Opérations de paris
Cette page documente le cycle de vie des paris et la formule de points confirmée côté Convex.
Sources principales :
convex/competition/betting.ts
convex/competition/betting_rules.ts
convex/competition/bet_settlement.ts
convex/competition/betting_reasons.ts
convex/competition/betting_waves.ts
convex/admin/bets.ts
convex/admin/cron_runners.ts
États de pari
bets.status observé :
PENDING
WON
LOST
CANCELLED
Cycle de vie du pari
Création / update
createOrUpdateBet positionne/actualise en PENDING.
Settlement d’un match
settleBetsForMatch traite les statuts PENDING/WON/LOST, écrit WON/LOST + settledAt, et nettoie cancelReason.
Le traitement parcourt toutes les pages de paris du match par lots bornés. Il
ne s’arrête pas à 500 lignes : seuls les paris de la vague courante et du match
concerné sont modifiés, les autres matchs, autres vagues et statuts non
éligibles restent inchangés.
Réouverture
reopenBetsForMatch repasse PENDING/WON/LOST vers PENDING et remet pointsWon = 0.
La réouverture utilise le même parcours paginé complet que le settlement.
Annulation
cancelBetsForMatch : annule PENDING/WON/LOST, écrit CANCELLED, remet pointsWon = 0, avec option advanceWave.
cancelPendingBetsForMatch : annule PENDING seulement.
Les deux chemins annulent toutes les pages de paris éligibles de la vague
courante. advanceWave n’avance pas une deuxième fois quand un retry rejoue la
même annulation horodatée.
La valeur de reason utilisée par les flux de match dépend de la cause (ex. MATCH_FORFEITED, MATCH_CANCELLED, MATCH_RESCHEDULED, BETTING_DISABLED, ADMIN_INVALIDATION, ADMIN_ERROR).
Éligibilité paris / listing
Un match listable doit être en statut paris :
scheduled (minuscule) ou SCHEDULED (legacy),
bettable === true,
- fenêtre de coupe à
BETTING_CUTOFF_MINUTES = 60,
- pas de signal de progression de résultat (
hasMatchProgressSignal) déjà posé.
hasMatchProgressSignal couvre notamment scores finalisés partiels/finaux et timestamps associés.
settleSingleBet applique :
EXACT_SCORE : 3 points en cas de score identique exact.
- autres types (HOME/DRAW/AWAY) :
1 point si l’issue est correcte.
Résultat match → paris (points de couplage)
Depuis le flux Convex, les événements impactant les paris sont :
- résultat validé : settlement de la vague courante (
settleBetsForMatch),
- contestation / réouverture (
contestResult, adminResetMatchResult, adminSetMatchResult en retour pending_validation) : reopenBetsForMatch,
- annulations/indisponibilités match (ex. cancellation, reschedule, forfeit) :
cancel... selon contexte.
Forfaits et paris
applyClubForfeit (forfait club-compétition) et declareMatchForfeit
(forfait ponctuel de match) annulent les paris via cancelPendingBetsForMatch
avec raison MATCH_FORFEITED :
- seuls les paris
PENDING de la vague courante sont affectés,
- les paris déjà gagnants/perdants ne sont pas modifiés,
- si l’annulation est paginée, le forfait ponctuel garde un état
betCancellationInProgress puis synchronise pendingBetsCancelled avec le
total final du job,
- les paris annulés par forfait ne sont pas réouverts par une réversion ou une annulation de forfait.
Admin bet bulk settlement
requestBulkSettleBets (admin / modérateur) crée une exécution Cron admin-bets-bulk-settlement.
La demande refuse les listes vides, les IDs introuvables et les conflits de job
en cours avec des erreurs typées côté client.
runBetBulkSettlement :
- filtre et dédoublonne les IDs,
- applique patch par patch,
- écrit un audit par pari,
- envoie
notifyBetStatusChange,
- maintient
requested/updated/skipped/failed, requestedStatus et
actorUserId dans cron_executions.details,
- notifie en in-app l’admin/modérateur demandeur à la fin ou en cas d’échec.
En cas d’échec partiel, admin.bet_bulk_job.partial_failure_alerted envoie un
email au groupe ADMINS, dédupliqué par exécution.
Export et notifications
exportBets n’est pas paginé : il lit au maximum 5 000 paris, applique les
filtres, puis retourne { exportedAt, total, filters, columns, rows }.
bet.status_changed crée toujours une notification in-app ciblée vers
/betting, dédupliquée par eventKey.
- Les statuts exceptionnels
CANCELLED et PENDING déclenchent aussi un email
au parieur ; WON et LOST restent in-app uniquement.
- Le suivi opérationnel du bulk repose sur
cron_executions, les notifications
ADMIN_BET_BULK_JOB et le reporting d’erreurs PostHog.
Last modified on July 18, 2026