feat: admin/chef/player permission model + leaderless teams + setleader

Commands:
- Drop all short aliases (c/i/t/j/vis/disband/...) — long names only.
- Every /core team <action> now has a crcore.team.<action> permission.
- Three-tier model:
  * Admin (perm only): create, delete, setleader, score
  * Chef (perm + chef-check in execute): add, remove, transfer, visibility, setspawn
  * Player (perm): join, leave, info, list, top
- delete now takes <team> as argument (admin); no more chef-disband shortcut.

New /core team setleader <team> <player>:
- Admin assigns or replaces a team's leader.
- More permissive than transfer: target may not yet be a member (auto-add),
  and works on leaderless teams.

Leaderless teams:
- Team.leaderId is now nullable.
- getLeaderId() and getLeader() return Optional<...>.
- hasLeader() and isLeader(UUID) helpers added.
- New constructors Team(id, name, tag, color [, visibility]) for leaderless.
- TeamService.createTeam overloads without leaderId.
- TeamService.setLeader(teamId, playerId): assigns/replaces leader (auto-adds
  as member if needed). Fires TeamLeadershipTransferEvent with optional old.
- TeamLeadershipTransferEvent.getOldLeaderId() returns Optional<UUID>.
- SqliteTeamRepository: leader_id column no longer NOT NULL.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Antone Barbaud
2026-06-09 14:56:07 +02:00
parent 5bd6e227d3
commit 002fefdc02
24 changed files with 472 additions and 138 deletions
+60
View File
@@ -323,6 +323,66 @@ Format léger : une décision = un titre + contexte + choix + raison.
même fichier SQLite (par défaut `<dataFolder>/crcore.db`) ; le préfixe
isole proprement.
## 2026-06-09 — Refonte permissions + modèle admin/chef/joueur
- **Choix** : chaque sous-commande `/core team <action>` a sa propre permission
`crcore.team.<action>`. Trois niveaux fonctionnels :
- **Admin** (permission seule, cible une team par argument) : `create`,
`delete`, `setleader`, `score`.
- **Chef** (permission + check chef dans `execute()`) : `add`, `remove`,
`transfer`, `visibility`, `setspawn`.
- **Joueur** (permission seule, défaut « tout le monde » côté LuckPerms si
voulu) : `join`, `leave`, `info`, `list`, `top`.
- **Aliases courts supprimés** : `c` (create), `i` (info), `t` (team), `j`
(join), `vis` (visibility), `disband`/`dissolve` (delete), `kick`/`expel`
(remove), etc. Plus que les noms longs. Raison : réduire la friction
d'apprentissage et la confusion (les game plugins ont leurs propres noms,
l'aliasing devient un bruit).
- **`delete` devient admin** : `/core team delete <team>` (au lieu de
l'ancien `/core team delete` qui ciblait l'équipe du chef). Cohérent avec
`create` qui est aussi admin.
## 2026-06-09 — Team peut être leaderless
- **Choix** : `Team.leaderId` devient nullable. `getLeaderId()` renvoie
`Optional<UUID>`, `getLeader()` renvoie `Optional<TeamMember>`. Nouveau
`hasLeader()` et `isLeader(UUID)` pour les checks.
- **Raison** : le modèle admin requiert qu'on puisse créer une équipe sans
chef et l'assigner ensuite via {@code setLeader}. Avant, créer une équipe
imposait de connaître l'UUID du chef.
- **Constructeurs ajoutés** :
- `new Team(id, name, tag, color)` — leaderless, PRIVATE
- `new Team(id, name, tag, color, visibility)` — leaderless avec visibilité
- Les constructeurs avec leaderId acceptent maintenant `null`.
- **`Team.setLeader(playerId)`** : assigne un chef à n'importe quel moment.
Si la team a déjà un chef, il est démis en MEMBER. Si le nouveau n'est
pas membre, il est auto-ajouté.
- **`Team.transferLeadership(playerId)`** : conserve sa sémantique stricte
(chef→chef, membre déjà existant). Lève `IllegalStateException` si la team
est leaderless. Utilisé par la commande `/core team transfer` (chef).
- **`TeamLeadershipTransferEvent.getOldLeaderId()`** renvoie maintenant
`Optional<UUID>` (vide si la team était leaderless avant l'opération).
- **Schéma SQLite** : la colonne `crcore_teams.leader_id` n'a plus la
contrainte `NOT NULL`. Migration automatique sur nouvelle base — pour les
bases existantes, ALTER TABLE manuel ou suppression du fichier
(les bases d'event sont jetables).
## 2026-06-09 — Nouvelle commande `/core team setleader`
- **Choix** : ajout de `TeamSetLeaderSubCommand` (`/core team setleader
<team> <player>`). Permission `crcore.team.setleader`. Délègue à
`TeamService.setLeader(...)`.
- **Différence avec `/core team transfer`** :
- `transfer` : action **chef**, cible son équipe, le nouveau chef doit déjà
être membre.
- `setleader` : action **admin**, cible n'importe quelle équipe, le nouveau
chef peut être non-membre (auto-ajouté).
- **Use cases couverts** :
- Admin assigne un chef à une équipe leaderless fraîchement créée.
- Admin remplace le chef d'une équipe (le membre target est déjà dans
l'équipe ou pas — peu importe).
- Admin "promote member up to leader" (cas explicitement demandé).
## 2026-06-09 — Bascule Java 16 → Java 11 (révision)
- **Révision** de la décision "Java 16" du 2026-06-08.