Major changes across backend, frontend, infrastructure: - Provider system with model selection (Google, DeepL, OpenAI, Ollama, Google Cloud) - Admin panel: user management, pricing, settings - Glossary system with CSV import/export - Subscription and tier quota management - Security hardening (rate limiting, API key auth, path traversal fixes) - Docker compose for dev, prod, and IONOS deployment - Alembic migrations for new tables - Frontend: dashboard, pricing page, landing page, i18n (en/fr) - Test suite and verification scripts Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
146 lines
13 KiB
Markdown
146 lines
13 KiB
Markdown
# Story 6.6: Environment Configuration
|
||
|
||
Status: done
|
||
|
||
<!-- Note: Validation is optional. Run validate-create-story for quality check before dev-story. -->
|
||
|
||
## 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. |
|