Matchs, reports, résultats et compositions
Cette page documente uniquement les règles vérifiées dans le backend Convex de CEL.
Sources principales :
convex/schema.ts
convex/competition/match_result_mutations.ts
convex/competition/match_postponement_mutations.ts
convex/competition/match_postponement_shared.ts
convex/competition/match_admin_mutations.ts
convex/admin/disputes.ts
convex/competition/match_lineups.ts
convex/competition/match_scheduling_mutations.ts
matches.status vs match_reports.status
matches.status est une chaîne métier utilisée par les flux Convex de match : planification, paris, validation, etc.
match_reports.status est un enum optionnel (PENDING, ACCEPTED, COUNTER_PROPOSED, CANCELLED, REJECTED) ; undefined reste possible en legacy.
Conséquence vérifiée : une ligne de report legacy bloque la création d’un nouveau report tant que assertNoLegacyMatchReportsForMatch n’est pas passée.
matches et données liées
matches contient notamment : leagueId, homeClubId, awayClubId, matchday, scheduledAt, originalScheduledAt, postponedAt, postponedById, status, isActive.
Des index techniques existent par ligue, statut, clubs, journée, date planifiée et états de synchronisation EA.
Cycle de vie des résultats de match
Statuts observés
scheduled
pending_validation
disputed
validated
completed (état final historique/importé reconnu par les lectures, les
classements, les récompenses et les interfaces)
Les mutations actuelles de résultat finalisent un match en validated. Aucun
chemin d’écriture actif audité ne crée completed ; ce statut est conservé
comme compatibilité de lecture.
Soumission GM (submitMatchResult)
- En premier passage (match en
scheduled), une soumission côté club crée homeScoreBy* / awayScoreBy* et met match.status = pending_validation.
- En second passage, si les deux scores concordent :
- scores finaux posés,
validatedAt,
match.status = validated,
- settlement paris (vague courante) + mise à jour classement.
- Si les soumissions divergent :
match_results.isDisputed = true,
match.status = disputed.
Actions admin avancées
adminSetMatchResult (admin) :
- écrit un score explicite,
- cible
validated (défaut) ou pending_validation,
- inverse la précédente contribution au classement si nécessaire,
- peut nettoyer les sous-soumissions,
- relance settlement/standings en
validated,
- réouvre paris si retour en
pending_validation.
adminResetMatchResult (admin) :
- supprime le résultat,
- inverse classement si nécessaire,
- remet en
scheduled ou pending_validation,
- réouvre les paris.
contestResult suit le flux de gestion de litige côté module (admin ou staff selon règles d’accès applicables), puis réévalue statut/paris selon la phase de résolution.
Report de match (postponement)
Les match_reports peuvent avoir les statuts vérifiés : PENDING, ACCEPTED, COUNTER_PROPOSED, CANCELLED, REJECTED.
isReportQuotaConsumed compte uniquement les ACCEPTED.
Le quota métier de base utilise league.reportsPerClubTotal avec un bonus premium PREMIUM_REPORTS_BONUS = 2 côté mutation.
requestPostponement
Conditions confirmées :
- match existant en
scheduled ou provisional,
- acteur côté l’un des clubs,
- quota disponible,
scheduledAt conforme, pas de conflit de calendrier,
- pas de report legacy,
- pas de
PENDING / COUNTER_PROPOSED,
- pas d’
ACCEPTED existant.
Effet : création PENDING + audit.
acceptPostponement
Entrées : report PENDING ou COUNTER_PROPOSED.
- Côté adverse si
PENDING, côté demandeur si COUNTER_PROPOSED.
- revalidation date + conflit + quota.
Effets :
- status report
ACCEPTED,
matches.scheduledAt déplacé,
- conservation de
originalScheduledAt si déjà présent,
postponedAt, postponedById mis à jour,
match.status = scheduled.
counterProposePostponement
Sur PENDING, côté adverse, avec nouvelle date valide.
Statut -> COUNTER_PROPOSED.
cancelPostponement
Sur PENDING ou COUNTER_PROPOSED, acteur du club demandeur selon la logique du module.
rejectPostponement
Exclusif admin sur PENDING ou COUNTER_PROPOSED.
adminDirectPostponement
Parcours admin qui valide quotas/date/conflits et crée directement un report ACCEPTED en impactant le match.
Snapshots calendrier
Chaque match_report conserve scheduledAtBefore et scheduledAtAfter. Le
match conserve aussi originalScheduledAt lors de la première acceptation.
acceptPostponement met à jour scheduledAt du match.
cancelPostponement et rejectPostponement n’acceptent que les états
PENDING ou COUNTER_PROPOSED. Un report ACCEPTED est terminal dans ce
module : aucune mutation de report ne restaure ensuite scheduledAtBefore.
Une restauration de calendrier relève du mécanisme séparé de snapshot de ligue,
pas de l’annulation/rejet d’un report accepté.
Litiges
reportDispute (module résultat) :
- crée une entrée
disputes en OPEN si aucun litige ouvert,
- met
match.status = disputed.
Le contrôle d’accès côté invocation n’est pas exclusivement admin-only : côté club actif et admin peuvent initier la déclaration selon helpers.
resolveDispute (admin) :
APPROVED : validation du match,
REJECTED : match.status = pending_validation,
CUSTOM + score : enregistrement score, sortie litige, validatedAt.
convex/admin/disputes.ts expose la même palette de statuts de décision.
Compositions d’avant-match
match_lineups couvre les statuts draft et submitted.
Règles vérifiées :
- deadline :
LINEUP_DEADLINE_MS = 20 * 60 * 1000,
- soumission seulement si match
scheduled et avant deadline,
- minimum 7 joueurs à la soumission,
ADMIN et MODERATOR peuvent bypasser statut/deadline (auditées).
Précautions
- Traiter
completed comme un état final de compatibilité ; les nouveaux flux
applicatifs doivent écrire validated.
- Ne pas présenter l’annulation ou le rejet comme un mécanisme d’annulation
d’un report déjà accepté : ces actions sont volontairement refusées par le
backend.
Last modified on July 16, 2026