# 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 jeu
  - `extension` : à rattacher à un parent existant (détection de conflits activée)
  - `advanced_rules` : variantes/modes avancés d'un parent
  - `faq` : FAQ officielle d'un parent
- **Langue des règles** : `fr` ou `en` (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 :

1. **Lecture** : pdfjs-dist extrait le texte
2. **Reconnaissance optique** (OCR — uniquement si PDF scanné, auto-détecté)
3. **Découpage** : chunking sémantique (paragraphes + overlap)
4. **Structuration** : Claude analyse l'arbre chapitre/section/sous-section
5. **Analyse contextuelle** : Claude génère 1-2 phrases de contexte par chunk (Contextual Retrieval B, 10 SSH parallèles, cache JSON)
6. **Compréhension** : embeddings TEI bge-m3 (batch de 32)
7. **Archivage** : push Qdrant
8. **Conflits** (extensions seulement) : compare aux chunks du parent, détecte replaces/modifies/extends
9. **PNG** : `pdftoppm` rend 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 :

1. Flush les caches JSON (contextual-llm + conflict-detect)
2. Passe la ligne en `ingestStatus='scheduled'` avec `ingestScheduledAt = resetAt + 2 min`
3. Émet un event SSE `quota_pause` → l'UI affiche un panneau dédié
4. Re-déclenche `runIngestion` automatiquement à l'heure de reset
5. 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

1. Le PDF est uploadé sur disque immédiatement (`/app/pdfs/...`)
2. La ligne `games` est créée avec `ingestStatus='scheduled'` + `ingestScheduledAt`
3. Un `setTimeout` est armé dans `src/cron/ingest-scheduler.ts` pour déclencher `startIngestJob(gameId)` à l'heure prévue
4. 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) :

1. Clear le timer
2. Supprime le PDF du disque
3. 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.