Ajouter un jeu
Ajouter un jeu
Ajouter un jeu
Dernière mise à jour : 2026-05-10
Réservé aux users avec canAddGames = true (admins par défaut, autres comptes : à toi de toggler dans /admin → Users).
Wizard /add-game (3 étapes)
Étape 1 — BGG search
Tu cherches le jeu sur BoardGameGeek (API XML v2). Tu sélectionnes le résultat → ses metadata (image, méchaniques, catégories, type) sont rapatriées et stockées dans la ligne games.
Si le jeu n'existe pas sur BGG (rare), tu peux skip cette étape et entrer le nom à la main.
Étape 2 — Upload PDF + métadonnées
- Le PDF : drag & drop ou file picker. Stocké sur disque dans
/app/pdfs/<slug>-<timestamp>.pdf, jamais dans git. - Type de contenu :
base: règles principales du jeuextension: à rattacher à un parent existant (détection de conflits activée)advanced_rules: variantes/modes avancés d'un parentfaq: FAQ officielle d'un parent
- Langue des règles :
frouen(impacte HyDE — le passage hypothétique sera généré dans la bonne langue + traduit côté backend). - Démarrer plus tard (optionnel) : champ datetime, max +7 jours. Cf. page suivante.
Étape 3 — Ingest ritual
Si tu démarres tout de suite, tu vois un suivi SSE en temps réel des actes :
- Lecture : pdfjs-dist extrait le texte
- Reconnaissance optique (OCR — uniquement si PDF scanné, auto-détecté)
- Découpage : chunking sémantique (paragraphes + overlap)
- Structuration : Claude analyse l'arbre chapitre/section/sous-section
- Analyse contextuelle : Claude génère 1-2 phrases de contexte par chunk (Contextual Retrieval B, 10 SSH parallèles, cache JSON)
- Compréhension : embeddings TEI bge-m3 (batch de 32)
- Archivage : push Qdrant
- Conflits (extensions seulement) : compare aux chunks du parent, détecte replaces/modifies/extends
- PNG :
pdftoppmrend chaque page en image 300 DPI dans/app/pdfs/images/<slug>/page-XX.png
Durée typique : 5-15 min selon taille du PDF + utilisation Claude (quota).
Pause quota Claude
Si pendant l'ingestion le CLI Claude renvoie son message « Usage limit reached, reset at HH:MM », l'app :
- Flush les caches JSON (contextual-llm + conflict-detect)
- Passe la ligne en
ingestStatus='scheduled'avecingestScheduledAt = resetAt + 2 min - Émet un event SSE
quota_pause→ l'UI affiche un panneau dédié - Re-déclenche
runIngestionautomatiquement à l'heure de reset - La reprise re-utilise les caches JSON → aucun chunk n'est retraité, zéro perte
Tu n'as rien à faire — laisse tourner.
Si l'ingestion plante
ingestStatus='error'en BDD- Logs serveur :
tail -f /app/data/logs/server.log(docker exec boardgame-referee tail -f /app/data/logs/server.log) - Possible relancer en supprimant le jeu (
/admin→ Games → bouton Retirer) puis le re-uploadant
Ingestion planifiée
Ingestion planifiée
Dernière mise à jour : 2026-05-10
Pourquoi
- Lancer une grosse ingestion la nuit pour ne pas bouffer ton quota Claude pendant la journée
- Étaler 3 jeux à ingérer sans tous les lancer en parallèle
- Programmer une ingestion d'extension pour quand le jeu de base sera lui-même fini
Comment
Dans le wizard /add-game étape 2, coche "Démarrer plus tard" et choisis une date/heure.
Contraintes : doit être dans le futur, max +7 jours.
Que se passe-t-il en interne
- Le PDF est uploadé sur disque immédiatement (
/app/pdfs/...) - La ligne
gamesest créée avecingestStatus='scheduled'+ingestScheduledAt - Un
setTimeoutest armé danssrc/cron/ingest-scheduler.tspour déclencherstartIngestJob(gameId)à l'heure prévue - Le PDF n'est PAS analysé tant que l'heure n'est pas atteinte
Si tu redémarres le container avant l'heure
Au boot, restoreScheduledOnBoot() relit la BDD et re-programme tous les timers en attente. Si une date est déjà passée pendant le redémarrage, le job démarre immédiatement avec une grace de 1 seconde.
Annuler une ingestion planifiée
DELETE /api/games/:id/scheduled (via /admin → Games → bouton Annuler) :
- Clear le timer
- Supprime le PDF du disque
- Supprime la ligne SQLite
Renvoie 409 si le jeu est déjà passé en running ou done.
Distinction reprise après quota
Le même mécanisme (scheduleIngestStart) est réutilisé pour la pause auto en cas de quota Claude. Côté UI, le motif est différencié (reason: 'quota' vs 'user') pour afficher la bonne copie. Pour l'utilisateur c'est transparent : laisse tourner, ça reprendra tout seul.