Skip to main content

Sanctions et modération

Cette page documente le modèle de sanctions réellement présent dans le repo. Sources principales :
  • README.md
  • convex/schema.ts
  • convex/lib/person_sanctions.ts
  • convex/admin/sanctions.ts
  • convex/messaging/events.ts
  • convex/messaging/bus.ts

Modèle canonique personne

Une sanction personne est stockée dans sanctions avec :
targetType: "PERSON"
Types canoniques vérifiés :
  • PERSON_BAN
  • PERSON_SUSPENSION
  • PERSON_DISCIPLINARY_REVIEW
Effets canoniques vérifiés :
  • APP_ACCESS
  • SPORT_ELIGIBILITY
  • VISIBILITY
  • CONTACT

Cycle de vie

États vérifiés :
  • ACTIVE
  • ENDED_MANUAL
  • ENDED_EXPIRED
  • ENDED_REPLACED
Sources de fin vérifiées :
  • MANUAL
  • AUTO_EXPIRED
  • REPLACED
Une sanction active doit cibler PERSON, avoir isActive = true, ne pas avoir endedAt, et ne pas être expirée.

État de restriction utilisateur

getPersonRestrictionState retourne un état agrégé :
  • hasActiveRestriction
  • activeSanctionIds
  • activeEffects
  • reasonSummary
  • nextExpiryAt
  • blockingMessage
Le message bloquant est produit quand l’effet APP_ACCESS est actif.

Sanctions expirées

Une sanction active avec expiresAt <= now est considérée comme expirée dans les vues effectives. Elle peut apparaître comme :
  • isActive = false
  • lifecycleState = ENDED_EXPIRED
  • endSource = AUTO_EXPIRED

Historique

listPersonSanctionHistoryFromRecords supporte les vues :
  • ALL
  • ACTIVE
  • HISTORICAL
La liste est triée par createdAt décroissant. Il existe aussi une vue near-expiry avec fenêtre configurable.

Création d’une sanction personne

Inputs validés :
  • actorUserId
  • personUserId
  • sanctionType
  • reason
  • expiresAt
  • effectScopes
Règles vérifiées :
  • raison non vide ;
  • au moins un effet canonique ;
  • date d’expiration future si fournie ;
  • acteur admin ou moderator ;
  • un moderator ne peut pas sanctionner un admin ;
  • un acteur ne peut pas appliquer une sanction à lui-même.
Effets :
  • insertion dans sanctions ;
  • targetType = PERSON ;
  • lifecycleState = ACTIVE ;
  • isActive = true ;
  • audit personne ;
  • notification si transition de restriction ;
  • invalidation de sessions si APP_ACCESS ;
  • sync Algolia sanction.

Remplacement d’une sanction

replacePersonSanctionCommand crée une nouvelle sanction et termine l’ancienne. Règles vérifiées :
  • ancienne sanction existante ;
  • ancienne sanction cible PERSON ;
  • ancienne sanction active ;
  • même targetId ;
  • nouvelle sanction normalisée comme une création.
Effets sur l’ancienne sanction :
  • isActive = false ;
  • lifecycleState = ENDED_REPLACED ;
  • endSource = REPLACED ;
  • replacedBySanctionId ;
  • endedAt ;
  • endedByUserId.
Effets sur la nouvelle sanction :
  • replacementOfSanctionId ;
  • audit de création ;
  • audit de remplacement ;
  • notification selon transition ;
  • sync Algolia des deux sanctions.

Fin manuelle d’une sanction

endPersonSanctionCommand termine une sanction active. Règles vérifiées :
  • sanction existante ;
  • cible PERSON ;
  • sanction active ;
  • acteur autorisé ;
  • raison de fin optionnelle mais non vide si fournie.
Effets :
  • isActive = false ;
  • lifecycleState = ENDED_MANUAL ;
  • endSource = MANUAL ;
  • endedAt ;
  • endedByUserId ;
  • audit ;
  • notification si restriction levée ;
  • sync Algolia.

Notifications de sanction

Événements de messagerie liés :
  • person_sanction.activated
  • person_sanction.ended
  • user.banned
  • user.unbanned
  • user.reactivated
  • user.deleted
APP_ACCESS déclenche les notifications de type ban/unban en plus des notifications de sanction personne.

Legacy

Le README indique que le runtime ne lit plus :
  • users.banned
  • users.banReason
  • users.banExpires
Le backfill legacy est disponible dans convex/migration/person_sanctions.ts.

Sanctions club et compétition

Le schéma contient aussi des types historiques ou club/compétition :
  • BAN_PLAYER
  • SUSPENSION
  • BAN_CLUB
  • PENDING_DISCIPLINARY
  • POINTS_DEDUCTION
  • FINE
  • FORFAIT
  • COMPETITION_BAN
La documentation détaillée de ces sanctions doit rester alignée avec les modules métier qui les créent, notamment les forfaits club et l’éligibilité compétition.
Last modified on June 24, 2026