# Variables d'environnement

# Variables d'environnement

> _Dernière mise à jour : 2026-05-10_

Toutes les variables sont déclarées dans `src/config.ts` (Zod schema avec validation au boot). Le fichier `.env.example` les documente avec commentaires. **Aucune variable ne doit apparaître ailleurs que dans `config.ts`** (sauf `drizzle.config.ts` qui s'exécute hors du build TS).

⚠️ Quand tu ajoutes une variable, mets à jour **3 fichiers en parallèle** : `src/config.ts`, `.env.example`, `unraid/boardgame-referee.xml`. Sans le XML, l'admin Unraid ne pourra pas la setter via l'UI.

## Légende

- 🔐 = secret (jamais versionné, jamais loggé)
- ⚠️ = critique (requis ou blocage au boot)
- 🌐 = service URL externe

## Serveur

| Variable | Type | Défaut | Rôle |
|---|---|---|---|
| `PORT` | number | `3000` | Port d'écoute Hono |
| `LOG_LEVEL` | enum | `info` (prod) / `debug` (dev) | Filtrage logs (debug/info/warn/error) |
| `TRUST_PROXY` ⚠️ | bool | `false` | Active la confiance dans `X-Forwarded-*` (mettre `true` derrière NPM) |
| `CORS_ORIGIN` ⚠️ | string | `*` | Whitelist origines, virgule-séparées. Supporte CIDR IPv4 (`192.168.10.0/24`) |
| `COOKIE_SECRET` 🔐⚠️ | string | (requis, ≥16 chars hex) | Secret de signature des cookies session |

## Base de données / fichiers

| Variable | Type | Défaut | Rôle |
|---|---|---|---|
| `DB_PATH` | string | `/app/data/database.db` | Chemin SQLite |
| `PDF_DIR` | string | `/app/pdfs` | Dossier PDFs uploadés + PNG rendus |
| `CARD_IMAGE_CACHE_DIR` | string | `/app/data/card-images-cache` | Cache des images cartes resize sharp |

## Sources de cartes (data dirs)

| Variable | Type | Défaut |
|---|---|---|
| `MAGIC_CARDS_DATA_DIR` | string | `/app/data/magic-cards` |
| `LORCANA_CARDS_DATA_DIR` | string | `/app/data/lorcana-cards` |
| `TM_CARDS_DATA_DIR` | string | `/app/data/terraforming-mars-cards` |
| `ARK_NOVA_CARDS_DATA_DIR` | string | `/app/data/ark-nova-cards` |

(FAB est bundlé via `@flesh-and-blood/cards` npm — pas de data dir.)

## Embeddings et Vector DB

| Variable | Type | Défaut | Rôle |
|---|---|---|---|
| `TEI_URL` 🌐⚠️ | URL | `http://localhost:8099` | TEI bge-m3 (embeddings) |
| `TEI_RERANKER_URL` 🌐⚠️ | URL | `http://localhost:8990` | TEI reranker bge-v2-m3 |
| `QDRANT_URL` 🌐⚠️ | URL | `http://localhost:6333` | Qdrant vector DB |
| `CARD_WARM_TIMEOUT_MS` | number | `30000` | Timeout préchargement collections cartes au boot |

## Claude (génération)

| Variable | Type | Défaut | Rôle |
|---|---|---|---|
| `CLAUDE_USE_LOCAL` | bool | `false` | Mode dev local (bypass SSH) |
| `CLAUDE_LOCAL_BIN` | string | `claude` | Binaire CLI (mode local) |
| `CLAUDE_LOCAL_WORKDIR` | string | `(optionnel)` | Workdir CLI (mode local) |
| `CLAUDE_SSH_HOST` ⚠️ | string | (requis prod) | Host SSH VM oracle |
| `CLAUDE_SSH_USER` ⚠️ | string | `oracle` | User SSH (toujours `oracle`) |
| `CLAUDE_SSH_KEY_PATH` 🔐 | string | `/app/ssh/id_ed25519` | Clé privée ed25519 dédiée |
| `CLAUDE_SSH_WORKDIR` | string | `/home/oracle/work` | Workdir VM (préfixe ForceCommand) |

## RAG (HyDE, decompose, fusion)

| Variable | Type | Défaut | Rôle |
|---|---|---|---|
| `HYDE_ENABLED` | bool | `true` | Active HyDE (passage hypothétique) |
| `HYDE_MODEL` | string | `claude-haiku-4-5-20251001` | Modèle HyDE |
| `HYDE_TIMEOUT_MS` | number | `25000` | Timeout HyDE (tunnel SSH baseline ~5s, marge confortable) |
| `DECOMPOSE_TIMEOUT_MS` | number | `25000` | Timeout decompose-query Haiku |
| `HAIKU_RETRY_ENABLED` | bool | `true` | Retry 1× sur timeout/parse fail |
| `RAG_FUSION_V2_ENABLED` | bool | `true` | Active fusion RRF v2 + blending position-aware |
| `CONTEXTUAL_MODEL` | string | `claude-haiku-4-5-20251001` | Modèle Contextual Retrieval B (1 appel/chunk) |
| `CONTEXTUAL_CACHE_DIR` | string | `/app/data` | Dossier cache JSON contextes |
| `CONFLICT_MODEL` | string | (fallback `CONTEXTUAL_MODEL`) | Modèle détection conflits extension |
| `CONFLICT_SIMILARITY_THRESHOLD` | number | `0.65` | Seuil similarité cosine pour déclencher l'analyse de conflit |

## OCR

| Variable | Type | Défaut | Rôle |
|---|---|---|---|
| `OCR_ENABLED` | bool | `true` | Active l'auto-détection PDFs scannés |
| `OCR_ENGINE` | enum | `tesseract` | (Phase 1 : tesseract uniquement) |
| `OCR_LANGUAGES` | string | `fra+eng` | Concat tesseract |
| `OCR_CACHE_DIR` | string | `/app/data` | Cache JSON ocr-v1-`<slug>`.json |
| `OCR_AUTO_THRESHOLD_CHARS_PER_PAGE` | number | `50` | Seuil sous lequel on déclenche l'OCR |
| `OCR_CONCURRENCY` | number | `2` | Pool workers tesseract |
| `OCR_MIN_CONFIDENCE` | number | `40` | Confiance tesseract (0-100, log warn si en-dessous) |

## Premier admin (boot)

| Variable | Type | Défaut | Rôle |
|---|---|---|---|
| `FIRST_ADMIN_USERNAME` ⚠️ | string | `admin` | Username créé/réinitialisé au boot |
| `FIRST_ADMIN_PASSWORD` 🔐⚠️ | string | (requis, ≥8 chars) | Password initial (hashé argon2) |

## SMTP (optionnel)

| Variable | Type | Défaut | Rôle |
|---|---|---|---|
| `SMTP_HOST` | string | (vide = désactivé) | Host SMTP |
| `SMTP_PORT` | number | `587` | |
| `SMTP_USER` 🔐 | string | | |
| `SMTP_PASS` 🔐 | string | | |
| `SMTP_FROM` | string | | Header From |
| `SMTP_SECURE` | bool | `false` | TLS |

## Méta-game

(Tous désactivés par défaut. Activer à la carte selon les TCG suivis.)

| Variable | Type | Défaut |
|---|---|---|
| `META_SYNC_ENABLED` | bool | `false` |
| `META_SYNC_HOUR` | number | `4` |
| `META_SYNC_INTERVAL_HOURS` | number | `168` (hebdo) |
| `META_RETENTION_DAYS` | number | `90` |
| `META_MTG_SET` | string | (vide = skip) |
| `META_MTG_FORMATS` | string | (vide = skip) |
| `META_TOURNAMENT_ENABLED` | bool | `false` |
| `META_TOURNAMENT_FORMATS` | string | `standard,modern,pioneer,...` |
| `META_TOURNAMENT_ARCHIVE_HTML` | bool | `true` |
| `META_TOURNAMENT_RATE_LIMIT_MS` | number | `1500` |
| `META_RIFTBOUND_ENABLED` | bool | `false` |
| `META_RIFTBOUND_TOURNAMENT_ENABLED` | bool | `false` |
| `META_RIFTBOUND_TOURNAMENT_MAX_PLACEMENT` | number | `4` |
| `META_RIFTBOUND_TOURNAMENT_FORMAT_ID` | number | `2` (Spiritforged) |
| `META_RIFTBOUND_RATE_LIMIT_MS` | number | `300` |
| `META_FAB_TOURNAMENT_ENABLED` | bool | `false` |
| `META_FAB_TOURNAMENT_FORMATS` | string | `classic-constructed,blitz,living-legend,silver-age` |
| `META_FAB_TOURNAMENT_MAX_DECKS` | number | `50` |
| `META_FAB_TOURNAMENT_MAX_AGE_DAYS` | number | `60` |
| `META_FAB_RATE_LIMIT_MS` | number | `1500` |
| `META_FAB_USER_AGENT` | string | `Mozilla/5.0 (compatible; boardgame-referee/1.0; +https://referee.thymon.fr)` |

## Forums BGG

| Variable | Type | Défaut |
|---|---|---|
| `BGG_API_TOKEN` 🔐 | string | (vide, optionnel) |
| `BGG_FORUM_SYNC_ENABLED` | bool | `false` |
| `BGG_FORUM_SYNC_HOUR` | number | `3` |
| `BGG_FORUM_SYNC_INTERVAL_HOURS` | number | `72` |

## Vision

| Variable | Type | Défaut | Rôle |
|---|---|---|---|
| `VISION_SSH_IMAGES_PATH` | string | `/projet/boardgame-pdfs` | Chemin côté VM oracle des PNG (Read tool) |