# CLAUDE.md — Instructions pour l'assistant ## Source de vérité **Le dossier `docs/` est la source unique de vérité du projet.** - Toute spécification, règle, décision technique, commande ou contrainte doit être lue depuis `docs/` et écrite dans `docs/`. - Avant d'implémenter, vérifier ce qui est consigné dans `docs/`. - Toute nouvelle information donnée par l'utilisateur va dans le fichier adapté : - `docs/features.md` — domaines fonctionnels (chaque feature a sa section numérotée : team, player, modération, broadcasts, messages, GUI, team-config, database, command framework, bootstrap) - `docs/decisions.md` — décisions techniques / architecturales (ADR léger, une décision = un titre + contexte + choix + raison) - `docs/setup.md` — build, intégration dans un plugin de jeu, arborescence, snippets d'usage, publication Maven (Gitea Packages) - `docs/README.md` — vue d'ensemble, index des features, index des diagrammes - `docs/diagrams/*.puml` — diagrammes PlantUML organisés en `util/` + `features//` + transverses à la racine - En cas de conflit code ↔ `docs/`, `docs/` fait foi. ## Nature du projet **CR-Core** est une **librairie Java/Maven** consommée par des plugins Bukkit ("plugins de jeu"). Pas de `plugin.yml` côté core — c'est le plugin de jeu qui en a un et qui instancie `CRCore` dans son `onEnable()`. - **Nom** : CR-Core (artifactId Maven : `CR-Core`) - **Type** : librairie (`jar`) - **Cible runtime** : serveur Paper/Spigot 1.16.5 - **Build** : Maven, **Java 11** (pas de records / pattern matching / switch expressions — déjà downgradé une fois, ne pas réintroduire) - **Package racine** : `fr.luc.crcore` - **SQLite** : `org.xerial:sqlite-jdbc` (compile scope) - **PlaceholderAPI** : `me.clip:placeholderapi` 2.11.6 (provided) - **Publication** : Gitea Packages Maven sur `https://gitea.luc-rival.fr/api/packages/admin/maven` (repo HTTPS `https://gitea.luc-rival.fr/admin/Cites_Plugins.git`) ## Architecture en couches Le code est séparé en trois couches qui se reflètent dans les packages : ``` fr.luc.crcore/ ├── CRCore + CRCoreConfig ← entrée + config builder ├── builtin/ ← commandes top-level │ ├── CoreCommand (/core) │ └── CoreReloadSubCommand (/core reload) ├── util/ ← TOUJOURS actif (infrastructure) │ ├── common/ (Identifiable, Named, ScoreHolder, …) │ ├── command/ (framework : BaseCommand, SubCommand, …) │ ├── database/ (wrapper SQLite : Database, TableBuilder) │ ├── message/ (MessagesService, YAML impl) │ ├── broadcast/ (BroadcastService, listener cross-feature) │ ├── gui/ (AbstractInventoryGui, GuiListener) │ └── placeholder/ (CRCorePlaceholderExpansion PAPI) └── features/ ← OPT-IN via CRCoreConfig.setupX() ├── team/ (setupTeams()) │ ├── event/ exception/ impl/ │ ├── config/ (TeamSetting, TeamConfigService + GUI) │ └── command/ (14 Team*SubCommand sous /core team) ├── player/ (setupPlayers()) │ └── event/ exception/ impl/ └── moderation/ (setupModeration() — skeleton) ├── event/ exception/ impl/ ├── command/ (/core admin) └── tool/ (5 ModeratorTool squelette) ``` **Règle d'or** : un util ne dépend jamais d'une feature. Une feature peut dépendre d'utils. Les features se référencent uniquement via leurs interfaces publiques (jamais via `impl/`). ## Setup modulaire (opt-in) Les features sont opt-in via `CRCoreConfig` : ```java new CRCore(this, new CRCoreConfig() .setupTeams() .setupPlayers() .setupPlaceholders() .setupModeration()) // ou setupAll() pour tout activer .enable(); ``` - Par défaut : **aucune feature** n'est active, seule la couche util. - Getter d'une feature désactivée → `IllegalStateException` avec message qui pointe sur le `setupX()` manquant. - Sous-commande d'une feature désactivée → simplement pas enregistrée (ex. `/core team` n'existe pas si `setupTeams()` non appelé). ## Modèle de fichiers générés au runtime Au premier `enable()`, CR-Core crée dans le dataFolder du plugin de jeu : | Fichier (`-…`) | Contenu | Couche | |---|---|---| | `messages.yml` | Templates des messages (commandes + broadcasts) | util | | `broadcasts.yml` | Routes : quel event → quelles audiences | util | | `team-config.yml` | Defaults globaux des paramètres d'équipe | feature team | Pattern commun : defaults bundlés dans le jar (`crcore-*.yml`), fichier user copié au premier boot (le plugin de jeu peut bundler son propre template sous le même nom pour le supplanter). Couches en mémoire = defaults + user. `/core reload` (perm `crcore.reload`) recharge les trois à chaud. ## Principe : simple par défaut, overridable partout Chaque service expose des **hooks `protected`** que les plugins de jeu peuvent overrider : - factories (`newTeam`, `newRanking`, `newProfile`) - validations (`validateName`, `validateJoinable`, …) - post-hooks (`onAfterCreate`, `onMemberAdded`, `onScoreChanged`, `onAfterEnter`, `onAfterExit`, …) Chaque commande built-in (`TeamCreateSubCommand`, etc.) est elle aussi substituable par nom via `replaceSubCommand(...)`. Sur `CRCore`, override les `buildX()` pour fournir une impl alternative (`buildTeamService`, `buildMessagesService`, `buildBroadcastService`, `buildTeamConfigService`, `buildModerationService`, `registerDefaultModeratorTools`). **Règles** : - Pas de `final` sur les classes du noyau. - Méthodes-clés en `protected` (pas `private`). - Hooks `onBefore...` / `onAfter...` partout où ça a du sens. - Factories pour permettre les sous-classes. ## Workflow attendu 1. Lire le contexte pertinent dans `docs/`. 2. Discuter / valider l'approche avec l'utilisateur si nécessaire. 3. Mettre à jour `docs/` (et le `.puml` concerné) avec la décision ou la spec. 4. Implémenter le code conformément à la doc. 5. Compiler (`mvn clean compile`) — BUILD SUCCESS obligatoire avant commit. 6. Déployer si la version le justifie (`mvn clean deploy` → Gitea Packages). 7. Commit + push (token Gitea fourni par l'utilisateur ; URL HTTPS). ## Conventions de code - Code (classes, méthodes, attributs, variables) en **anglais standard**. - Messages joueur et documentation en **français**. - JavaDoc en français sur les classes publiques et les méthodes non triviales. - Séparation stricte : - `interface`, `enum`, `abstract class`, `class` concrète, `exception` — chacun dans son fichier. - Au sein d'un domaine : contrats publics (interfaces, entités, enums) au top du package, `impl/` pour les implémentations swappables, `exception/` pour les exceptions, `event/` pour les events Bukkit. - Pas d'API Java 12+ (records, switch expressions, instanceof pattern matching). Cible compile = Java 11. - Pour les events Bukkit : `HandlerList` static, base abstraite par feature, `getHandlerList()` static obligatoire. ## Conventions Git - Commits descriptifs en anglais, message multi-lignes via heredoc. - Co-author trailer : `Co-Authored-By: Claude Opus 4.7 `. - Push sur `main` via URL HTTPS avec token (l'utilisateur fournit le token, warning donné si stocké en clair). - Le repo Gitea est `gitea.luc-rival.fr/admin/Cites_Plugins` (HTTPS). ## Build / Maven - **JAVA_HOME** : `C:\Program Files\JetBrains\IntelliJ IDEA 2026.1.3\jbr` (JetBrains Runtime utilisé comme JDK) - **mvn** : `C:\Program Files\JetBrains\IntelliJ IDEA 2026.1.3\plugins\maven\lib\maven3\bin\mvn.cmd` - Commande compile : `mvn clean compile -B` - Commande deploy : `mvn clean deploy -B` (publie sur Gitea Packages)