Palmarès
Cette page couvre le palmarès CEL au sens large: récompenses de saison, honneurs joueurs, TOTS, MVP/Ballon d’Or, TOTW et MVP de match. Elle documente l’état actuellement implémenté dans le code.Sources principales
convex/schema.tsconvex/competition/season_awards.tsconvex/lib/season_mvp.tsconvex/competition/totw.tsconvex/awards/recipients.tsweb/src/app/admin/season-awardsweb/src/app/(app)/palmares/[awardId]/page.tsxweb/src/components/club/ClubPalmaresTab.tsxweb/src/components/player/PlayerHonoursPanel.tsx
Modèle de publication
Le palmarès de fin de saison est publié depuis l’adminseason-awards.
La publication crée:
- une ligne
season_awards, qui porte le snapshot global publié; - des lignes
season_award_entries, qui portent les entrées visibles du palmarès de saison; - des lignes
award_recipients, qui normalisent les honneurs par joueur.
award_recipients sert de table commune pour les honneurs publics joueur:
Catégories de saison
Les catégories deseason_award_entries sont:
La page publique
/palmares/[awardId] expose les trophées de saison et la TOTS
publiée. Les onglets de club et de joueur réutilisent les entrées normalisées
pour afficher les honneurs dans les profils.
Sortie publique /palmares/[awardId] (contrat)
La query publique getPublishedSeasonAwards retourne désormais:
finalists.mvp: les 5 meilleurs nommés MVP depuisseason_awards.mvpNomineesSnapshot;finalists.bestGk: les 5 meilleurs nommés meilleur gardien depuisseason_awards.bestGkNomineesSnapshot;
finalists contient au minimum:
playerProfileId,name,avatarUrl,clubName,clubLogoUrl,position,rank,goals,assists,matchesPlayed,score(les champs peuvent êtrenullsi le snapshot source est incomplet).
tots.players expose aussi une sous-structure stats limitée aux
champs:
goals,assists,matchesPlayed,performanceScore,ratingAverage,totwCount,matchMvpCount,teamRank.
SEASON_MVP et BEST_GK, le snapshot persisté par
publishSeasonAwards inclut aussi ratingAverage dans entry.stats; la valeur
peut être null si elle n’est pas calculable.
Pour BEST_GK, entry.stats inclut aussi:
saves,cleanSheets.
Règles de publication
Règles vérifiées danspublishSeasonAwards:
- publication réservée aux admins;
- ligue requise en statut
COMPLETEDouARCHIVED; - sélection MVP requise;
- sélection meilleur gardien requise;
- sélection TOTS optionnelle si aucune formation complète n’est disponible;
- remplacement d’un palmarès existant possible;
- notifications et emails activés par défaut.
Réactions B4 sur les palmarès
La query publiquegetAwardCongratulations est disponible côté social:
getAwardCongratulations({ awardId, actorUserId? })- Retourne
{ byEntryId: Record<entryId, { count, byReaction, mine }> }pour toutes les entrées de l’award. count: total des réactions de l’entrée.byReaction: compte par réaction (MERITE,QUELLE_SAISON,FIER,RENDEZVOUS).mine: réaction de l’utilisateur courant ounull.
- Retourne
congratulate({ awardId, entryId, reaction, actorUserId? })- Ajoute/remplace la réaction d’un utilisateur connecté pour une entrée.
uncongratulate({ awardId, entryId, actorUserId? })- Supprime la réaction de l’utilisateur connecté si elle existe.
- une seule réaction active par (
entryId, utilisateur). - pas d’usage de
collect().lengthpour les compteurs; lecture via table dénormaliséeaward_congratulation_counts.
Statut personnel du palmarès (B5)
La querygetMyPalmaresStatus({ awardId, actorUserId? }) retourne, pour
l’utilisateur connecté:
awardedEntries: lesentryIdpublics du palmarès où l’utilisateur est lauréat;totsSlots: les slots TOTS publics associés à cet utilisateur;isAwarded:truedès qu’au moins une entrée du palmarès lui correspond.
season_award_entries.recipientUserId, utile pour les entrées joueur et les destinataires directs;award_recipients, utile pour les récompenses de club qui sont normalisées vers les joueurs actifs au moment de la publication.
Requêtes de sélection de saison
La couche publique expose désormais deux queries pour trouver des publications:listPublishedSeasonAwards({ leagueId? })→{ awardId, leagueId, leagueName, season, publishedAt }[], triées enpublishedAtdécroissant.getLatestPublishedSeasonAwards({ leagueId? })→ le même format pour la publication la plus récente, ounullsi aucune.
leagueId est fourni, ces queries restreignent à une ligue précise.
Modèle de comparaison par poste
TOTS et MVP partagent le même principe: un joueur n’est jamais comparé à toute la ligue en vrac, mais aux autres joueurs de son poste. La chaîne de résolution du poste se fait en trois temps.1. Normalisation du poste détaillé
Les libellés bruts sont d’abord ramenés à un code détaillé canonique (normalizePositionDetailedForStats). Exemples d’alias:
On obtient ~13 postes détaillés:
GK, DG, DC, DD, MDC, MC, MOC,
MG, MD, AG, AD, BU.
2. Famille de comparaison
Après normalisation, le poste détaillé est rattaché à une famille de scoring (resolveScorePositionFamily). C’est cette famille qui sert au calcul des
barèmes de performance.
Conséquence: un
DG et un DD partagent le benchmark FULLBACK; un MG,
un MD, un AG et un AD partagent le benchmark WIDE. Les barèmes de
performance (meilleur total, moyenne des 10 meilleurs) sont calculés par
famille de poste, pas par poste détaillé isolé.
Le poste détaillé reste conservé pour l’affichage, l’éligibilité aux cases de
formation et la sélection du slot TOTS. Il évite par exemple de traiter un
MD comme un latéral DD, même si les deux jouent dans un couloir.
3. Agrégation multi-postes d’un même joueur
Un joueur joué à plusieurs libellés qui retombent sur la même famille de comparaison voit ses lignes fusionnées (aggregateTotsPositionStats): matchs
dédoublonnés par matchId, buts/passes/points cumulés. Le poste représentatif
est celui où il a le plus de matchs.
Formule TOTS (tots-v3)
La TOTS désigne les meilleurs joueurs à chaque poste. La comparaison statistique
se fait au sein de la famille de poste du joueur.
Pour être candidat à un poste, un joueur doit franchir deux seuils:
- un seuil de saison: avoir joué au moins
min(10, matchs max de la saison)matchs au total; - un seuil de poste: avoir joué au moins
max(15, plafond(20% de ses matchs de saison))matchs dans la famille de comparaison considérée.
15 n’est donc qu’un plancher: un joueur qui a disputé 100 matchs doit en
avoir joué au moins 20 au poste pour y être candidat. La régularité ne doit pas
ajouter de points séparés: elle est portée par ces seuils d’éligibilité.
Performance /70
La performance utilise le total de points cumulés dans la famille, pas une moyenne par match.- meilleur total de la famille: 500 points;
- total du joueur: 450 points;
- performance:
450 / 500 x 70 = 63.
Distinctions /10
Collectif /20
Total TOTS
Formule MVP / Ballon d’Or (mvp-v2)
Le MVP/Ballon d’Or doit comparer toute la ligue sans favoriser automatiquement
les postes offensifs. Il utilise donc un Performance Index basé sur la famille
de poste.
Famille retenue et éligibilité (changement v3)
Avant la v3, le MVP notait chaque joueur sur ses totaux globaux de saison (tous postes confondus) et son poste principal. La v3 change cela (selectMvpScoringPosition + toSeasonMvpCandidate):
- on regroupe les stats du joueur par famille de comparaison (même
chaîne que la TOTS), on agrège, puis on ne garde que les postes franchissant
le seuil d’éligibilité
max(15, plafond(20% des matchs de saison)); - parmi ces postes éligibles, on retient le meilleur (plus haut total de points, puis plus de matchs);
- les
matchs,buts,passesetpointsdu candidat MVP proviennent de ce seul poste, pas de ses totaux globaux; - un joueur qui ne franchit le seuil à aucun poste est exclu du classement.
GK.
Performance Index /70
- meilleur total du poste: 500;
- moyenne des 10 meilleurs du poste: 476;
- total du joueur: 500;
A = 500 / 500 = 1;B = 500 / 476 = 1,05;Performance Index = 0,7 x 1 + 0,3 x 1,05 = 1,015.
Distinctions /10
Le MVP utilise le même système de distinctions que la TOTS:Collectif /20
Le MVP utilise le même bonus collectif que la TOTS.Total MVP
Versioning
- TOTS:
tots-v3; - MVP/Ballon d’Or:
mvp-v2.