# Story 6.6: Environment Configuration Status: done ## Story En tant que **Developer**, je veux **toute la configuration via variables d'environnement**, afin que **les secrets ne soient jamais dans le code**. ## Acceptance Criteria 1. **Étant donné** .env.example documente toutes les variables requises **Quand** je déploie **Alors** tous les secrets proviennent de l'environnement : DATABASE_URL, JWT_SECRET_KEY (ou SECRET_KEY), GOOGLE_API_KEY (ou équivalent), DEEPL_API_KEY, OPENAI_API_KEY, OLLAMA_BASE_URL, REDIS_URL **Et** les variables requises manquantes provoquent un échec rapide avec un message d'erreur clair **Et** des valeurs par défaut sont fournies pour les variables optionnelles ## Tasks / Subtasks - [x] Task 1 (AC: #1) — Inventaire et .env.example - [x] 1.1 Vérifier que .env.example (racine ou backend) liste toutes les variables utilisées en production : base de données, auth (JWT, admin), Redis, providers (Google, DeepL, OpenAI, Ollama), Stripe si utilisé, CORS, log level, etc. - [x] 1.2 Pour chaque variable, indiquer si elle est requise ou optionnelle, un exemple de valeur (sans secret réel), et le comportement si absente (défaut ou fail-fast). - [x] 1.3 S'assurer qu'aucun secret n'apparaît en clair dans .env.example (placeholders du type `your_secret_here`, `sk_...`, `pk_...`). - [x] Task 2 (AC: #1) — Fail-fast pour variables requises - [x] 2.1 Au démarrage de l'application (main.py ou module config), valider la présence des variables requises pour l'environnement cible (ex. production : DATABASE_URL ou POSTGRES_*, JWT_SECRET_KEY, REDIS_URL, ADMIN_USERNAME + ADMIN_PASSWORD ou ADMIN_PASSWORD_HASH). - [x] 2.2 Si une variable requise est absente, lever une exception ou sortir avec un message explicite listant les variables manquantes (pas de stack trace générique). - [x] 2.3 En développement, autoriser des valeurs par défaut ou des avertissements au lieu de fail-fast pour certaines variables (ex. REDIS_URL optionnel si rate limiting désactivé), en documentant le comportement dans .env.example. - [x] Task 3 (AC: #1) — Défauts pour variables optionnelles - [x] 3.1 Pour les variables optionnelles (LOG_LEVEL, OLLAMA_BASE_URL, CORS_ORIGINS, timeouts, etc.), définir des valeurs par défaut dans le code ou dans un schéma Pydantic BaseSettings / config centralisée. - [x] 3.2 Documenter ces défauts dans .env.example pour que le déploiement soit reproductible sans deviner. - [x] Task 4 — Cohérence backend / frontend - [x] 4.1 Backend : une seule source de vérité pour la config (ex. core/config.py avec Pydantic BaseSettings chargé depuis os.environ et .env). Éviter les os.getenv dispersés pour les variables critiques. - [x] 4.2 Frontend : NEXT_PUBLIC_* et autres variables documentées dans .env.local.example ou la section frontend de .env.example ; pas de secrets côté client (NFR10). - [x] 4.3 Mettre à jour README ou DEPLOYMENT_GUIDE avec la procédure "copier .env.example vers .env et remplir les champs requis". ## Dev Notes - **Contexte** : Les stories 6-1 à 6-5 ont livré Docker, Redis, structlog, reverse proxy. L'architecture impose que **tous les secrets et la configuration sensible passent par l'environnement** (NFR10). Le projet dispose déjà d'un .env.example riche à la racine ; cette story vise à s'assurer qu'il est exhaustif, que le démarrage échoue clairement si des variables requises manquent, et que les optionnelles ont des défauts documentés. - **Architecture** : [Source: _bmad-output/planning-artifacts/architecture.md] — core/config.py Pydantic BaseSettings ; NFR10 (secrets via env, jamais dans le code). Product brief : centraliser la config dans un module Pydantic BaseSettings. - **NFR10** : Variables d'environnement pour tous les secrets ; jamais de clés ou mots de passe en dur dans le code ni dans le dépôt. - **Fichiers à toucher** : `.env.example` (racine), `config.py` (racine — actuellement classe Config + os.getenv, sans fail-fast), `main.py` (point d'entrée pour validation au démarrage), éventuellement `services/providers/config.py` si centralisation dans un seul module config, README/DEPLOYMENT_GUIDE. Pas de `core/config.py` existant ; créer ou étendre le config actuel selon choix d’architecture. ### Project Structure Notes - **Racine** : `office_translator/` avec `config.py` à la racine (classe `Config`, `os.getenv` partout — pas de Pydantic BaseSettings ni fail-fast actuellement). `main.py` fait `from config import config`. `.env.example` à la racine (partagé dev/Docker). - **Config actuelle** : `config.py` (racine) + `services/providers/config.py` (providers). Pas de `core/config.py` ; l’architecture cible peut être soit migrer vers `core/config.py` avec BaseSettings, soit ajouter validation fail-fast dans le `Config` existant au démarrage dans `main.py`. - **Frontend** : si présent, documenter `NEXT_PUBLIC_*` dans une section dédiée de `.env.example` ou `.env.local.example`. ### References - [Source: _bmad-output/planning-artifacts/architecture.md] — core/config.py, NFR10, Infrastructure & Deployment. - [Source: _bmad-output/planning-artifacts/epics.md] — Epic 6, Story 6.6, AC. - [Source: _bmad-output/planning-artifacts/product-brief-office_translator-2026-02-18.md] — Configuration centralisée Pydantic BaseSettings. - [Source: .env.example] — Variables existantes (Translation, Rate Limiting, Database, Redis, Admin, JWT, Stripe, Logging). S'en servir comme base pour l'exhaustivité et le fail-fast. ### Technical Requirements (Architecture Compliance) - **Variables requises (prod)** : Au minimum DATABASE_URL (ou POSTGRES_* pour construire l'URL), JWT_SECRET_KEY, REDIS_URL (si rate limiting/cache activés), ADMIN_USERNAME et ADMIN_PASSWORD ou ADMIN_PASSWORD_HASH. Autres secrets (provider keys, Stripe) peuvent être optionnels avec désactivation des features associées. - **Fail-fast** : Au tout début du démarrage (avant de monter les routes ou de lancer des workers), vérifier les variables requises et sortir avec un message lisible du type : "Missing required env: JWT_SECRET_KEY, REDIS_URL. Set them in .env or environment. See .env.example." - **Défauts** : LOG_LEVEL=INFO, OLLAMA_BASE_URL=http://localhost:11434, CORS_ORIGINS=http://localhost:3000, etc. Documenter dans .env.example ; implémenter dans BaseSettings avec Field(default=...) ou équivalent. - **Un seul point de chargement** : Éviter que chaque module fasse son propre os.getenv pour les variables critiques ; passer par un objet Settings chargé une fois (dependency injection ou global après validation). ### Architecture Compliance - Alignement avec architecture.md : config centralisée (Pydantic BaseSettings), secrets uniquement via env. - Pas de clé API ou mot de passe en dur ; pas de fichier .env commité (vérifier .gitignore). ### Library / Framework Requirements - **Pydantic BaseSettings** (pydantic-settings) : chargement depuis os.environ et .env, validation des types, optional avec default. Déjà utilisé dans beaucoup de projets FastAPI. - **python-dotenv** : optionnel si BaseSettings charge le .env ; sinon utiliser load_dotenv() avant de construire Settings. Pas de lib supplémentaire obligatoire si BaseSettings est déjà en place. - Côté frontend : Next.js charge automatiquement .env.local ; documenter NEXT_PUBLIC_API_URL et autres dans .env.example. ### File Structure Requirements - **.env.example** : à la racine du projet. Sections commentées par domaine (Database, Redis, Auth, Providers, etc.). Chaque variable avec commentaire "Required" ou "Optional" et exemple. Déjà présent ; s’assurer exhaustivité et clarté Required/Optional. - **Config centralisée** : soit migrer `config.py` (racine) vers Pydantic BaseSettings dans `config.py` ou `core/config.py`, soit conserver la classe Config actuelle et ajouter une fonction de validation au démarrage qui vérifie les variables requises et appelle `sys.exit(1)` avec message listant les variables manquantes. Éviter de laisser des `os.getenv` dispersés pour les variables critiques (JWT_SECRET_KEY, DATABASE_URL, etc.) sans validation. - **main.py** : au tout début du démarrage (avant montage des routes), appeler la validation des variables requises ; en cas d’échec, ne pas démarrer l’app et afficher un message lisible (ex. "Missing required env: JWT_SECRET_KEY, REDIS_URL. Set them in .env. See .env.example."). ### Testing Requirements - Test unitaire ou script : avec un environnement vide (ou sans les variables requises), le démarrage de l'app doit échouer et le message doit mentionner les noms des variables manquantes. - Test : avec .env complet (ou mock des env), l'app démarre et les endpoints répondent (ex. GET /health). - Vérifier que .env.example ne contient aucun secret réel (grep ou revue manuelle). ### Previous Story Intelligence (6-5 Reverse Proxy) - **Fichiers concernés** : Docker Compose prod, config Nginx/Traefik, README/DEPLOYMENT_GUIDE. Pas de changement des variables d'environnement applicatives ; le proxy utilise ses propres config (certificats, etc.). - **Pour 6-6** : les variables ENABLE_HSTS, CORS_ORIGINS, et les URLs (FRONTEND_URL, NEXT_PUBLIC_API_URL) sont déjà dans .env.example ; s'assurer qu'elles sont documentées comme requises/optionnelles et que l'app les charge depuis la config centralisée. Pas de duplication de logique entre 6-5 et 6-6 : 6-5 = infra proxy, 6-6 = config applicative via env. ### Git Intelligence Summary - Le dépôt contient déjà .env.example à la racine avec de nombreuses variables. Vérifier qu'aucun fichier .env (sans .example) n'est versionné et que .gitignore exclut bien .env et .env.local. ### Latest Tech Information - **pydantic-settings** (Pydantic v2) : SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="ignore"). Pour rendre un champ obligatoire : pas de default ; pour optionnel : Field(default=...). Validation au chargement ; MissingEnvVarError ou ValidationError avec détails des champs manquants. - **Fail-fast** : appeler Settings() dans main.py ou dans un lifespan ; en cas de ValidationError, logger l'erreur et sys.exit(1) avec message listant les variables manquantes (err.errors() contient les détails). ### Project Context Reference - Aucun fichier project-context.md trouvé. Contexte : architecture.md (config, NFR10), epics.md (Story 6.6), .env.example existant, product-brief (config centralisée). ### Story Completion Status - **Status** : ready-for-dev - **Completion note** : Contexte et guide développeur complets — prêt pour implémentation. ## Dev Agent Record ### Agent Model Used {{agent_model_name_version}} ### Debug Log References - Fail-fast testé en dev (validate_required_env retourne []) et en prod simulée (liste des variables manquantes). Tests dans tests/test_config_env.py. ### Completion Notes List - Task 1 : .env.example mis à jour avec légende Required/Optional, comportement si absent, TRANSLATION_SERVICE et section Frontend (NEXT_PUBLIC_API_URL). Placeholder ADMIN_PASSWORD=your_admin_password_here (plus de secret en clair). - Task 2 : config.validate_required_env() ajouté dans config.py ; appel au démarrage dans main.py avec sys.exit(1) et message listant les variables manquantes. Fail-fast uniquement en ENV=production ; en dev retourne []. - Task 3 : Défauts déjà présents dans config.py et services/providers/config.py ; documentés dans .env.example (Optional. Default: ...). - Task 4 : Procédure « copier .env.example → .env et remplir les champs requis » ajoutée dans README.md et DEPLOYMENT_GUIDE.md. Section Frontend dans .env.example. - Code review (AI): HIGH/MEDIUM corrigés — main.py une seule source de vérité (config.LOG_FORMAT, config.ENV, config.LOG_LEVEL, config.RATE_LIMIT_*, config.MAX_MEMORY_PERCENT, config.ENABLE_HSTS, config.CORS_ORIGINS_RAW) ; support POSTGRES_* dans config._get_database_url() et injection dans os.environ ; fail-fast déplacé en tête de main.py (avant tout autre import) ; test démarrage exit 1 + test POSTGRES_* ; table Required Variables complétée dans DEPLOYMENT_GUIDE ; .env.example CLEANUP_INTERVAL Default: 5 + doc POSTGRES_* ; README note CORS dev-only. File List complétée avec .env.production. ### File List - .env.example - .env.production - config.py - main.py - tests/test_config_env.py - README.md - DEPLOYMENT_GUIDE.md ## Change Log | Date | Author | Action | Notes | |------|--------|--------|-------| | 2026-03-14 | dev-story | Implement | Story 6.6: .env.example exhaustif + fail-fast (config + main), tests, README/DEPLOYMENT_GUIDE. Status → review. | | 2026-03-14 | code-review (AI) | Fix HIGH/MEDIUM | Single source of truth (main→config), POSTGRES_* support, fail-fast before imports, tests startup exit 1 + POSTGRES_*, DEPLOYMENT_GUIDE + .env.example + README. Status → done. |