Clubs et effectifs
Cette page décrit les règles vérifiées côté backend (Convex) concernant les clubs et la gestion d’effectif.
Sources principales :
convex/social/_shared.ts
convex/social/clubs.ts
convex/social/memberships.ts
convex/competition/match_lineups.ts
convex/social/announcements.ts
Modèle club (données de base)
La table clubs contient notamment :
gmUserId, name, isPremium, eaClubId, eaPlatform, logoUrl, premiumLogoUrl, bannerUrl, primaryColor, secondaryColor, description, abbreviation, isActive, ownerId, country, searchText, createdAt, updatedAt.
Le module normalise les couleurs et nettoie les URLs optionnelles : une chaîne vide est transformée en valeur absente.
Rôles d’effectif
Les rôles valides côté membership sont :
MANAGER
CO_MANAGER
COACH
MEMBER
Un membership actif est défini par status = IN_CLUB et leftAt absent (isMembershipActive).
La création/mise à jour d’un membership passe par des helpers qui :
- empêchent qu’un même club ait déjà un
MANAGER, CO_MANAGER ou COACH actif (assertSingletonRoleAvailable),
- vérifient les autorisations d’acteur pour les actions de management.
Matrice d’autorisation (club / effectif)
assertActorCanManageClub et canActorCanManageClub encapsulent les règles :
- GM du club : toujours autorisé.
- Rôles de gestion (
MANAGER, CO_MANAGER) : autorisés pour les actions management par défaut.
COACH : autorisé uniquement quand le call backend passe includeCoach: true.
ADMIN : autorisé par défaut.
- Anonyme : refusé, sauf si l’appel explicite
allowAnonymous: true (rare, dépend du flux).
Matrice (résumé d’usage) :
- Gestion club classique (
clubs / recrutement / annonces) : MANAGER, CO_MANAGER, GM, ADMIN.
- Actions demandant explicitement recrutement élargi :
COACH inclus via includeCoach: true.
- Consultations non sensibles selon flux : peuvent être plus permissives (selon les fonctions appelantes), non couvertes ici.
Règles de cap effectif (roster)
Le calcul de cap effectif est centralisé dans _shared.ts :
resolveLeagueRosterLimit(league, club) :
- cap base =
league.maxActiveRoster,
- +10 si
club.isPremium === true.
assertClubRosterCapacityAllowsJoin vérifie que, avant invitation ou acceptation, le nombre de membres actifs existants (hors joueur en cours d’acceptation, via exclusion sur playerProfileId) reste en dessous du cap.
Quand la limite est atteinte :
- code :
CLUB_ROSTER_LIMIT_REACHED
- message avec
(activeRosterCount/rosterLimit)
- surcharge premium exposée dans
premiumBonus (10 pour club premium, 0 sinon).
Cas non vérifiés / à confirmer (non vérifié)
- Le cycle exact de mise à jour côté UI de
rosterLimit dans toutes les vues de club n’est pas décrit ici (verrouillé par le code métier existant, non audité dans un plan produit).
- Les effets visuels d’un changement de
logoUrl/premiumLogoUrl dans l’ensemble des composants front ne sont pas documentés par une spécification produit centralisée (non vérifié).
Effets connexes (effet de recrutement)
Dans le flux de transfert premium/open-to-offers :
- un joueur actif dans un autre club peut encore être traité via invitation si le joueur est premium +
openToOffers,
- l’arrivée déclenche la fermeture de ses memberships actifs précédents et la création d’un membership
IN_CLUB dans le club cible après acceptation.
Ces règles sont détaillées côté transferts dans docs/transferts-mercato-premium.md.
Invariants d’ops
- Un membership actif doit rester cohérent (
status=IN_CLUB + leftAt absent).
- Les autorisations sensibles passent par les helpers
_shared.
- Les modifications de membership à fort impact déclenchent audits, événements et/ou annonces selon le flux.
Last modified on June 24, 2026