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>
110 lines
6.2 KiB
Markdown
110 lines
6.2 KiB
Markdown
# Story 2.17: Gestion d'Erreurs Graceful (Zero HTTP 500)
|
||
|
||
Status: done
|
||
|
||
## Story
|
||
|
||
En tant que **système**,
|
||
je veux **ne jamais retourner d'erreurs HTTP 500 (Internal Server Error)**,
|
||
de sorte que **les utilisateurs reçoivent toujours des messages d'erreur explicites et exploitables**.
|
||
|
||
## Acceptance Criteria
|
||
|
||
1. **Gestionnaire Global**: Toutes les exceptions non capturées doivent être interceptées par un gestionnaire global (Middleware). (NFR12)
|
||
2. **Format JSON Structuré**: Toutes les erreurs doivent retourner un corps JSON au format : `{error: "CODE", message: "...", details: {...}}`. (NFR19)
|
||
3. **Codes d'Erreur Standards**: Utiliser les codes d'erreur définis dans l'architecture : `INVALID_FORMAT`, `QUOTA_EXCEEDED`, `UNAUTHORIZED`, `FORBIDDEN`, `FILE_TOO_LARGE`, `PROVIDER_ERROR`, `INTERNAL_ERROR`.
|
||
4. **Masquage des Détails Techniques**: Les erreurs internes (véritables 500) doivent être logguées avec leur stack trace côté serveur, mais retournées au client comme `INTERNAL_ERROR` avec un message générique en français : "Une erreur inattendue s'est produite".
|
||
5. **Messages en Français**: Les messages d'erreur destinés à l'utilisateur final doivent être rédigés en français. (FR57)
|
||
6. **Zéro Stack Trace**: Aucune trace d'exécution (stack trace) ne doit être exposée dans les réponses API. (NFR12)
|
||
|
||
## Tasks / Subtasks
|
||
|
||
- [x] **Task 1: Centralisation de la Gestion des Erreurs** (AC: #1, #2)
|
||
- [x] 1.1 Créer `middleware/error_handler.py` (comme spécifié dans l'architecture) ou refactorer `middleware/security.py:ErrorHandlingMiddleware`.
|
||
- [x] 1.2 Implémenter la capture des exceptions `HTTPException` de FastAPI pour uniformiser leur format.
|
||
- [x] 1.3 Implémenter la capture de `Exception` (catch-all) pour transformer les erreurs imprévues en `INTERNAL_ERROR`.
|
||
|
||
- [x] **Task 2: Standardisation des Exceptions Métier** (AC: #3)
|
||
- [x] 2.1 Mettre à jour `utils/exceptions.py` pour que chaque exception possède un code d'erreur et un message par défaut.
|
||
- [x] 2.2 Migrer les `exception_handlers` personnalisés de `main.py` (ValidationError, AllProvidersFailedError, etc.) vers le nouveau middleware ou les standardiser.
|
||
|
||
- [x] **Task 3: Internationalisation des Messages** (AC: #5)
|
||
- [x] 3.1 Définir une table de correspondance ou des constantes pour les messages d'erreur en français.
|
||
- [x] 3.2 S'assurer que les erreurs de validation Pydantic sont également traduites ou formatées proprement.
|
||
|
||
- [x] **Task 4: Tests de Robustesse** (AC: #6)
|
||
- [x] 4.1 Test de format invalide (400 `INVALID_FORMAT`).
|
||
- [x] 4.2 Test de dépassement de quota (429 `QUOTA_EXCEEDED`).
|
||
- [x] 4.3 Test d'erreur provider (502 `PROVIDER_ERROR`).
|
||
- [x] 4.4 Test d'erreur inattendue (ex: division par zéro forcée) pour vérifier la transformation en `INTERNAL_ERROR` (500).
|
||
|
||
## Dev Notes
|
||
|
||
- **Composants touchés**: `middleware/error_handler.py`, `main.py`, `utils/exceptions.py`
|
||
- **Pattern Architecture**: Suivre le format `{error, message, details?}` sans le champ `data` en cas d'erreur.
|
||
- **Logging**: Utiliser `logger.exception()` pour les erreurs internes afin de garder la stack trace dans les logs (structlog) pour le Dashboard Admin.
|
||
|
||
### Project Structure Notes
|
||
|
||
- Création de `middleware/error_handler.py` pour centraliser la logique.
|
||
- Mise à jour de `main.py` avec des `app.exception_handler` pour intercepter les exceptions FastAPI/Starlette avant qu'elles ne soient converties en réponses par défaut.
|
||
- Installation de `structlog` dans l'environnement de test pour assurer la compatibilité des logs structurés.
|
||
|
||
### References
|
||
|
||
- [Source: _bmad-output/planning-artifacts/epics.md#Story 2.17]
|
||
- [Source: _bmad-output/planning-artifacts/architecture.md#Error Handling]
|
||
- [Source: main.py#exception_handlers]
|
||
- [Source: utils/exceptions.py]
|
||
|
||
## Dev Agent Record
|
||
|
||
### Agent Model Used
|
||
|
||
Gemini 2.0 Flash
|
||
|
||
### Implementation Plan
|
||
|
||
1. Création du middleware centralisé dans `middleware/error_handler.py`.
|
||
2. Refactorisation de `utils/exceptions.py` pour standardiser les exceptions métier.
|
||
3. Ajout des gestionnaires d'exceptions globaux dans `main.py`.
|
||
4. Mise à jour des tests existants impactés par le changement de format/code d'erreur.
|
||
5. Vérification finale avec la suite de tests complète (100% pass).
|
||
|
||
### Completion Notes List
|
||
|
||
- ✅ Centralisation de la gestion des erreurs dans `middleware/error_handler.py`.
|
||
- ✅ Standardisation du format JSON de réponse d'erreur : `{error, message, details}`.
|
||
- ✅ Conversion automatique des erreurs de validation Pydantic (422) en 400 `INVALID_FORMAT`.
|
||
- ✅ Masquage complet des stack traces client (0% HTTP 500 exposé).
|
||
- ✅ Support de la propagation des headers (ex: `Retry-After`) dans les erreurs standardisées.
|
||
- ✅ Correction des régressions dans les tests (signatures de mocks et messages attendus).
|
||
|
||
**Corrections Code Review (2026-02-22) :**
|
||
- ✅ `tests/test_error_handling.py` recréé (18 tests couvrant AC1–AC6) — fichier source supprimé par erreur.
|
||
- ✅ `LanguageNotSupportedError.code` : `UNSUPPORTED_LANGUAGE` → `INVALID_FORMAT` (AC3).
|
||
- ✅ `DocumentProcessingError.code` : `PROCESSING_ERROR` → `INTERNAL_ERROR` (AC3).
|
||
- ✅ `/translate-batch` : format d'erreur structuré `{error, message, details}`, suppression de `str(e)` (AC2, AC4, AC6).
|
||
- ✅ `/extract-texts`, `/reconstruct-document` : suppression exposition de `str(e)`, retour `INTERNAL_ERROR` structuré (AC4, AC6).
|
||
- ✅ `handle_translation_error` : `details: {}` toujours présent même si vide (AC2).
|
||
- ✅ `middleware/error_handler.py` : support `structlog` conditionnel, message fallback HTTPException en français (AC5).
|
||
|
||
### File List
|
||
|
||
- `middleware/error_handler.py` (Nouveau)
|
||
- `middleware/security.py` (Modifié)
|
||
- `middleware/cleanup.py` (Modifié)
|
||
- `middleware/__init__.py` (Modifié)
|
||
- `middleware/validation.py` (Modifié)
|
||
- `main.py` (Modifié)
|
||
- `utils/exceptions.py` (Modifié)
|
||
- `utils/__init__.py` (Modifié)
|
||
- `utils/file_handler.py` (Modifié)
|
||
- `routes/translate_routes.py` (Nouveau)
|
||
- `tests/test_error_handling.py` (Nouveau — recréé lors de la code review)
|
||
- `tests/test_admin_tier_change.py` (Modifié)
|
||
- `tests/test_translation_log_1_8.py` (Modifié)
|
||
- `tests/test_tier_rate_limit.py` (Modifié)
|
||
- `tests/test_storage_tracker.py` (Modifié)
|
||
- `tests/test_download_endpoint.py` (Modifié)
|