Aller au contenu principal

Modèle de données

LeBoard partage la même base PostgreSQL que LeHub. Les modèles de Board ne touchent jamais aux entités du Hub (Workshop, Registration, Member, etc.), sauf pour la lecture de WorkshopModel (catalogue des plateaux) et Member (authentification animateur).

Le schéma Prisma pour LeBoard vit dans prisma/schema.prisma, au même endroit que les modèles LeHub. Les migrations spécifiques LeBoard (tâche 4) sont versionnées et appliquées au déploiement.

Modèles Board

Board

Représente un plateau collaboratif (une instance par atelier en ligne).

ChampTypeRôle
idString (CUID)Identifiant unique
workshopIdString (unique)Référence atelier LeHub (1-to-1)
workshopTitleStringTitre atelier copié (pour affichage sans req LeHub)
tokenString (unique)Token d'accès public (URL : /b/[token])
languageString"fr" (défaut) / "en" / "es" — langue des cartes
statusString"active" (défaut) / "closed"
isTrainingBooleanAtelier de test (formation) — affiche badge dans header
expiresAtDateTime?Expiration board (optionnel, utilisé pour les ateliers test)
modelIdString?Référence WorkshopModel (Hub) — définit les étapes/lots/matrices
placementsCardPlacement[]Cartes posées sur le board
connectionsConnection[]Flèches entre cartes
lotDistributionsBoardLotDistribution[]Historique distributions des lots
animatorSessionsAnimatorSession[]Sessions animateur actives
stickyNotesStickyNote[]Post-its
arrowsBoardArrow[]Flèches avec anchorpoints
activeStageIdStringÉtape active (persistée pour survivre aux déploiements)
createdAt, updatedAtDateTimeTimestamps

Relations : WorkshopModel (optionnel, peut être null si modèle supprimé), CardPlacement (cascade delete), Connection (cascade delete), StickyNote (cascade delete), BoardArrow (cascade delete), BoardLotDistribution (cascade delete), AnimatorSession (cascade delete).

CardPlacement

Représente la position d'une carte sur le plateau (placement temporaire).

ChampTypeRôle
idString (CUID)Identifiant unique
boardIdStringBoard (FK)
cardIdStringID métier de la carte (ex: "card-001") — pas une FK, juste une référence textuelle
x, yFloatPositionnement en pixels
rotationFloatRotation en degrés (défaut 0)
flippedBooleanRecto/verso (défaut false = recto)
zIndexIntOrdre de rendu (défaut 0)
fromConnectionsConnection[]Flèches partant de cette carte
toConnectionsConnection[]Flèches vers cette carte
updatedAtDateTimeTimestamp dernière modification

Cascade delete sur Board : si board est supprimé, toutes ses CardPlacements disparaissent.

Connection

Représente une flèche de causalité entre deux cartes.

ChampTypeRôle
idString (CUID)Identifiant unique
boardIdStringBoard (FK)
fromId, toIdStringCardPlacement IDs (FK) — relation CardPlacement.fromConnections / toConnections
labelString?Texte optionnel sur la flèche
createdAtDateTimeTimestamp création

Cascade delete sur fromId/toId : si une CardPlacement est supprimée, ses flèches disparaissent aussi.

BoardLotDistribution

Représente une distribution (historique) d'un lot à un board.

ChampTypeRôle
idString (CUID)Identifiant unique
boardIdStringBoard (FK)
lotIdStringLot ID (FK du Hub)
distributedAtDateTimeTimestamp distribution
modeString"distribute" ou "popcorn" — mode de lancement choisi par l'animateur
Unique[boardId, lotId]Un seul record par (board, lot) pair — prevent doublons

Piège : suppression en cascade — si un Lot est supprimé du Hub, les BoardLotDistribution liés disparaissent en cascade. Cela ne pose pas de problème en prod (les lots ne sont jamais supprimés, juste archivés), mais en dev peut causer des surprises. Voir la note de la tâche 3 pour plus de détails.

Cascade delete sur Board : si board supprimé, toutes ses distributions disparaissent.

StickyNote

Représente un post-it libre sur le plateau.

ChampTypeRôle
idStringID custom (UUID v4) — pas CUID, pour contourner un bug Konva
boardIdStringBoard (FK)
textStringContenu texte (défaut "")
x, yFloatPosition en pixels
colorString"yellow" / "pink" / "blue" / "green" / "white" (défaut "yellow")
zIndexIntOrdre rendu (défaut 0)
width, heightFloatDimensions en pixels (défaut 180×150)
fontSizeIntTaille police (défaut 12)
createdAt, updatedAtDateTimeTimestamps

Cascade delete sur Board.

BoardArrow

Représente une flèche entre anchorpoints (variante plus riche que Connection).

ChampTypeRôle
idString (CUID)Identifiant unique
boardIdStringBoard (FK)
fromType, toTypeString"card" / "sticky" — type source/cible
fromId, toIdStringID carte ou post-it
fromAnchor, toAnchorStringAnchorpoint ("tl", "tc", "tr", "ml", "mr", "bl", "bc", "br")
directionString"forward" / "both" (défaut "forward")
colorStringCouleur flèche (défaut "gray")
strokeWidthIntÉpaisseur trait (défaut 2)
createdAt, updatedAtDateTimeTimestamps

Cascade delete sur Board.

AnimatorSession

Représente une session animateur active (pour tracking connexion).

ChampTypeRôle
idString (CUID)Identifiant unique
boardIdStringBoard (FK)
memberIdStringID animateur (Hub Member)
pseudoStringPseudo affiché (défaut "")
expiresAtDateTimeExpiration session (défaut +24h)
createdAtDateTimeTimestamp création

Cascade delete sur Board. Utilisé pour tracer les connexions animateur et implémenter le timeout (logout après 24h ou fermeture browser).

Modèles de référence (LeHub, lecture seule)

WorkshopModel

Catalogue des modèles d'atelier (étapes, lots, matrices). Créé et géré exclusivement par LeHub via /admin/cards/.

ChampTypeRôle
idString (CUID)Identifiant unique
nameStringNom du modèle (ex: "Fresque Systémique v1")
languageString"fr" (défaut)
plateauIdString?ID plateau (maps à src/lib/plateaux.ts)
lotsLot[]Les lots du modèle
boardsBoard[]Les boards utilisant ce modèle
createdAt, updatedAtDateTimeTimestamps

Lot

Ensemble de cartes ou diapositives à lancer ensemble. Créé via LeHub.

ChampTypeRôle
idString (CUID)Identifiant unique
modelIdStringWorkshopModel (FK)
nameStringNom du lot (ex: "Actions")
orderIntPosition dans la séquence
stageIdString?Étape liée (ex: "stage-2")
kindString?"normal" (défaut) / "emergence" / null
cardIdsStringJSON stringifié : [{"cardId":"card-001","col":0,"row":0},...]
contentTypeString"cards" (défaut) / "slides"
slidesDataString?JSON stringifié si diaporama (images + notes)
distributionsBoardLotDistribution[]Historique distributions pour ce lot

Cascade delete si WorkshopModel supprimé.

Member

Utilisateur du Hub (animateurs, admins). Lecture seule pour LeBoard.

Champ clésTypeRôle
idStringID unique
emailStringEmail
roleStringRôle pédagogique ("animateur", "formateur", etc.)
isAdminBooleanAccès admin

Utilisé uniquement pour valider le JWT de l'animateur et tracer les sessions.

Diagramme relations Board

WorkshopModel (Hub admin)

├─ plateauId (ref → src/lib/plateaux.ts)
└─ Lot[] (lots du modèle)

└─ BoardLotDistribution (historique distribution)

└─ Board (plusieurs boards par lot)
├─ CardPlacement[] (cartes posées)
│ └─ Connection[] (flèches vers d'autres cartes)
├─ StickyNote[] (post-its)
├─ BoardArrow[] (flèches avancées)
├─ AnimatorSession[] (sessions animateurs)
└─ activeStageId (étape actuelle)

Member (Hub auth)

└─ AnimatorSession (liaison animateur → board)

Remarques opérationnelles

  • Pas de soft delete sur Board et dérivés (contrairement au Hub). Les boards sont créés à la volée et expirés via expiresAt.
  • Pas de relation directe Workshop : Board référence juste workshopId textuel, pas une FK vers Workshop. Cela permet une indépendance légère (Board peut exister si Workshop est supprimé).
  • Partage DB : toute migration Board doit être versionnée dans ce repo (prisma/migrations/) et appliquée au déploiement.