# 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é)
