# Story 3.5: API Versioning /api/v1/ Status: done ## Story En tant que **Développeur**, Je veux **que tous les endpoints API soient préfixés avec /api/v1/**, de sorte que **les futures versions de l'API puissent coexister sans casser les clients existants**. ## Acceptance Criteria 1. **Préfixe Obligatoire**: Tous les endpoints API sont montés sous `/api/v1/` prefix. (FR33) 2. **Endpoints Non-Versionnés**: Les endpoints sans préfixe de version retournent 404 (sauf health check et documentation). 3. **Documentation OpenAPI**: La version est documentée dans la spécification OpenAPI (title, version, description). 4. **Rétrocompatibilité**: Les clients existants utilisant `/api/v1/*` ne sont pas affectés. 5. **Health Check Préservé**: `/health` et `/ready` restent accessibles sans préfixe pour les probes Kubernetes. 6. **Documentation Accessible**: `/docs` (Swagger UI) et `/redoc` restent accessibles sans préfixe. ## Tasks / Subtasks - [x] **Task 1: Auditer les Endpoints Non-Versionnés** (AC: #1, #2) - [x] 1.1 Lister tous les endpoints dans `main.py` qui ne sont pas sous `/api/v1/` - [x] 1.2 Identifier les endpoints à migrer vs à préserver (health, docs) - [x] 1.3 Documenter la liste des endpoints à déplacer - [x] **Task 2: Créer un Routeur Racine API v1** (AC: #1) - [x] 2.1 Créer `routes/api_v1_router.py` avec un routeur principal pour `/api/v1` - [x] 2.2 Inclure tous les sous-routeurs (translate, auth, api-keys, admin) - [x] 2.3 Configurer les tags OpenAPI pour la documentation - [x] **Task 3: Migrer les Endpoints de main.py** (AC: #1, #2) - [x] 3.1 Déplacer `/languages` vers `/api/v1/languages` - [x] 3.2 Déplacer `/translate` vers `/api/v1/translate` (déjà fait via translate_routes.py) - [x] 3.3 Déplacer `/translate-batch` vers `/api/v1/translate/batch` - [x] 3.4 Déplacer `/download/{filename}` vers `/api/v1/download/{filename}` - [x] 3.5 Déplacer `/extract-texts` vers `/api/v1/extract-texts` - [x] 3.6 Déplacer `/reconstruct-document` vers `/api/v1/reconstruct-document` - [x] 3.7 Déplacer `/ollama/models` vers `/api/v1/ollama/models` - [x] 3.8 Déplacer `/ollama/configure` vers `/api/v1/ollama/configure` - [x] 3.9 Déplacer `/rate-limit/status` vers `/api/v1/rate-limit/status` - [x] 3.10 Déplacer `/admin/*` vers `/api/v1/admin/*` - [x] 3.11 Déplacer `/metrics` vers `/api/v1/metrics` - [x] **Task 4: Configurer les Exceptions de Versioning** (AC: #5, #6) - [x] 4.1 Garder `/health` accessible sans préfixe (Kubernetes probe) - [x] 4.2 Garder `/ready` accessible sans préfixe (Kubernetes probe) - [x] 4.3 Garder `/docs` accessible sans préfixe (Swagger UI) - [x] 4.4 Garder `/redoc` accessible sans préfixe (ReDoc) - [x] 4.5 Garder `/openapi.json` accessible sans préfixe - [x] 4.6 Optionnel: Garder `/` comme endpoint info avec redirect vers `/docs` - [x] **Task 5: Mettre à jour la Documentation OpenAPI** (AC: #3) - [x] 5.1 Vérifier que `config.API_VERSION` est utilisé dans FastAPI app - [x] 5.2 Ajouter la description de versioning dans la description de l'API - [x] 5.3 Documenter les endpoints versionnés dans les tags OpenAPI - [x] **Task 6: Nettoyer main.py** (AC: #1, #2) - [x] 6.1 Supprimer les endpoints déplacés de main.py - [x] 6.2 Garder uniquement les endpoints exception (health, docs, root) - [x] 6.3 Inclure le routeur API v1 principal - [x] **Task 7: Ajouter les Tests** (AC: Tous) - [x] 7.1 Test endpoint versionné accessible (`/api/v1/health` ou `/api/v1/languages`) - [x] 7.2 Test endpoint non-versionné retourne 404 (sauf exceptions) - [x] 7.3 Test health check accessible sans préfixe - [x] 7.4 Test documentation accessible sans préfixe - [x] 7.5 Test tous les endpoints migrés fonctionnent ## Dev Notes ### État Actuel du Versioning **Endpoints DÉJÀ versionnés** (via routeurs): - `POST /api/v1/translate` - translate_routes.py ✅ - `GET /api/v1/translations/{id}` - translate_routes.py ✅ - `GET /api/v1/download/{job_id}` - translate_routes.py ✅ - `POST /api/v1/auth/register` - auth_routes.py ✅ - `POST /api/v1/auth/login` - auth_routes.py ✅ - `POST /api/v1/api-keys` - api_key_routes.py ✅ - `GET /api/v1/api-keys` - api_key_routes.py ✅ - `DELETE /api/v1/api-keys/{key_id}` - api_key_routes.py ✅ - `DELETE /api/v1/admin/api-keys/{key_id}` - admin_routes.py ✅ **Endpoints NON versionnés** (dans main.py à migrer): | Endpoint | Migration | |----------|-----------| | `/` | Garder ou redirect vers /docs | | `/health` | **GARDER** (K8s probe) | | `/ready` | **GARDER** (K8s probe) | | `/languages` | → `/api/v1/languages` | | `/translate` | → Supprimer (doublon avec /api/v1/translate) | | `/translate-batch` | → `/api/v1/translate/batch` | | `/download/{filename}` | → Supprimer (doublon avec /api/v1/download/{job_id}) | | `/extract-texts` | → `/api/v1/extract-texts` | | `/reconstruct-document` | → `/api/v1/reconstruct-document` | | `/ollama/models` | → `/api/v1/ollama/models` | | `/ollama/configure` | → `/api/v1/ollama/configure` | | `/metrics` | → `/api/v1/metrics` | | `/rate-limit/status` | → `/api/v1/rate-limit/status` | | `/admin/login` | → `/api/v1/admin/login` | | `/admin/logout` | → `/api/v1/admin/logout` | | `/admin/verify` | → `/api/v1/admin/verify` | | `/admin/dashboard` | → `/api/v1/admin/dashboard` | | `/admin/users` | → `/api/v1/admin/users` | | `/admin/users/{user_id}` | → `/api/v1/admin/users/{user_id}` | | `/admin/stats` | → `/api/v1/admin/stats` | | `/admin/cleanup/trigger` | → `/api/v1/admin/cleanup/trigger` | | `/admin/files/tracked` | → `/api/v1/admin/files/tracked` | | `/admin/config/provider` | → `/api/v1/admin/config/provider` | | `/cleanup/{filename}` | → `/api/v1/cleanup/{filename}` | ### Architecture Proposée ``` main.py ├── /health (exception - K8s probe) ├── /ready (exception - K8s probe) ├── /docs (exception - Swagger UI) ├── /redoc (exception - ReDoc) ├── /openapi.json (exception - OpenAPI spec) ├── / (optionnel: redirect vers /docs) └── include_router(api_v1_router) # Tout le reste sous /api/v1/ routes/ ├── api_v1_router.py # NOUVEAU - Routeur principal /api/v1 │ ├── include_router(translate_v1_router) │ ├── include_router(auth_v1_router) │ ├── include_router(api_key_router) │ ├── include_router(admin_v1_router) # NOUVEAU │ └── include_router(legacy_router) # NOUVEAU ├── admin_routes.py # NOUVEAU - Endpoints admin versionnés ├── legacy_routes.py # NOUVEAU - Endpoints legacy versionnés ├── translate_routes.py # Existant ├── auth_routes.py # Existant └── api_key_routes.py # Existant ``` ### Patterns à Suivre **Pattern de Routeur Principal**: ```python # routes/api_v1_router.py from fastapi import APIRouter router = APIRouter(tags=["API v1"]) # Inclure les sous-routeurs from routes.translate_routes import router_v1 as translate_router from routes.auth_routes import router_v1 as auth_router from routes.api_key_routes import router as api_key_router router.include_router(translate_router, tags=["Translation"]) router.include_router(auth_router, tags=["Authentication"]) router.include_router(api_key_router, tags=["API Keys"]) ``` **Pattern d'Endpoint Admin Versionné**: ```python # routes/admin_routes.py from fastapi import APIRouter router = APIRouter(prefix="/admin", tags=["Admin"]) @router.post("/login") async def admin_login(...): ... @router.get("/dashboard") async def get_admin_dashboard(...): ... ``` **Configuration FastAPI**: ```python # main.py from routes.api_v1_router import router as api_v1_router app = FastAPI( title="Office Translator API", version="1.0.0", description="API de traduction de documents Office. Tous les endpoints sont préfixés avec /api/v1/.", ) # Endpoints exception (sans préfixe) @app.get("/health") async def health_check(): ... # Inclure le routeur principal app.include_router(api_v1_router) ``` ### Structure de Fichiers ``` routes/ ├── __init__.py ├── api_v1_router.py # CRÉÉ - Routeur principal ├── admin_routes.py # CRÉÉ - Endpoints admin versionnés ├── legacy_routes.py # CRÉÉ - Endpoints migrés de main.py ├── translate_routes.py # Existant - Pas de changement ├── auth_routes.py # Existant - Pas de changement └── api_key_routes.py # Existant - Pas de changement main.py # MODIFIÉ - Nettoyer et inclure api_v1_router config.py # MODIFIÉ - Description mise à jour tests/ └── test_story_3_5_api_versioning.py # CRÉÉ ``` ### Project Structure Notes - Le projet suit une structure plate (pas de dossier `backend/app/`) - Les routeurs sont dans `routes/` - Les modèles sont dans `database/models.py` - Les services sont dans `services/` - Les tests sont dans `tests/` ### Références - [Source: _bmad-output/planning-artifacts/epics.md#Story 3.5] - [Source: _bmad-output/planning-artifacts/architecture.md#API & Communication Patterns] - [Source: main.py - Endpoints actuels] - [Source: routes/translate_routes.py - Pattern de routeur versionné] ## Intelligence des Stories Précédentes (Epic 3) ### Story 3.1 (API Key Generation) - Enseignements 1. **Routeur api_key_routes.py** utilise `prefix="/api/v1/api-keys"` ✅ 2. **Pattern de réponse** `{data: {...}, meta: {...}}` établi 3. **Tests complets** avec fixtures dans `tests/conftest.py` ### Story 3.2 (API Key Revocation User) - Enseignements 1. **Soft delete** avec `is_active=False` 2. **Fonction `get_user_by_api_key`** dans `services/auth_service.py` 3. **Format d'erreur structuré** `{error, message, details?}` ### Story 3.3 (Admin API Key Revocation) - Enseignements 1. **Routes admin dans main.py** - migré vers `routes/admin_routes.py` 2. **Dépendance `require_admin`** pour l'authentification admin 3. **Audit logging** avec `logger.info()` ### Story 3.4 (API Auth X-API-Key) - Enseignements 1. **Coexistence JWT + API Key** dans `get_authenticated_user` 2. **Middleware d'auth** dans `routes/translate_routes.py` 3. **Priorité API key sur JWT** si les deux présents ## Intelligence Git (Commits Récents) Derniers commits pertinents: - `3d37ce4`: PostgreSQL database infrastructure - `c4d6cae`: Redis sessions, security hardening - `dfd45d9`: Admin login endpoint **Patterns identifiés**: - Routeurs avec `APIRouter(prefix="/api/v1")` - Tests avec `pytest` dans `tests/` - Fixtures dans `tests/conftest.py` ## Contexte Métier ### Epic 3: API & Automation (Pro) Cette story est la **cinquième de l'Epic 3** qui permet aux utilisateurs Pro d'automatiser les traductions: 1. ~~API Keys - Génération~~ (Story 3.1 ✅) 2. ~~API Keys - Révocation User~~ (Story 3.2 ✅) 3. ~~API Keys - Révocation Admin~~ (Story 3.3 ✅) 4. ~~Authentification X-API-Key~~ (Story 3.4 ✅) 5. **API Versioning** (cette story - COMPLETE) 6. Documentation OpenAPI (Story 3.6 - ready-for-dev) 7. Webhooks (Stories 3.7-3.8 - backlog) 8. Glossaires (Stories 3.9-3.10 - backlog) 9. Custom Prompts (Stories 3.11-3.12 - backlog) ### Valeur Business Le versioning d'API est critique pour: - **Évolutivité**: Pouvoir faire évoluer l'API sans casser les clients existants - **Documentation**: Clarté sur la version utilisée - **Migration**: Permettre une transition douce lors de changements majeurs - **Professionalisme**: Standard de l'industrie pour les APIs REST ### Dépendances - **Stories 3.1-3.4** (prérequis): Endpoints déjà versionnés ✅ - **Story 3.6** (impact): Documentation OpenAPI à mettre à jour ## Guardrails Développeur ### ❌ À NE PAS FAIRE 1. **NE PAS** supprimer les endpoints health/ready (K8s probes) 2. **NE PAS** supprimer l'accès à /docs et /redoc 3. **NE PAS** casser les clients existants utilisant `/api/v1/*` 4. **NE PAS** dupliquer le code - utiliser `include_router` 5. **NE PAS** oublier de tester tous les endpoints migrés 6. **NE PAS** modifier les routeurs existants (translate_routes.py, auth_routes.py, api_key_routes.py) ### ✅ À FAIRE 1. **TOUJOURS** préfixer les nouveaux endpoints avec `/api/v1/` 2. **TOUJOURS** garder health/ready accessibles sans préfixe 3. **TOUJOURS** tester que les endpoints non-versionnés retournent 404 4. **TOUJOURS** documenter la version dans OpenAPI 5. **TOUJOURS** utiliser `include_router` pour composer les routeurs 6. **CRÉER** un routeur principal `api_v1_router.py` 7. **CRÉER** un routeur admin `admin_routes.py` ## Dev Agent Record ### Agent Model Used Claude Sonnet 4 ### Debug Log References - App import successful after refactoring - All 31 versioning tests pass - Updated existing tests to use versioned endpoints - Patch paths updated for translator mocks ### Completion Notes List - ✅ Analyse exhaustive du contexte terminée - guide complet créé pour le développeur - ✅ Endpoints existants analysés (versionnés et non-versionnés) - ✅ Architecture proposée avec routeur principal et sous-routeurs - ✅ Liste complète des endpoints à migrer documentée - ✅ Exceptions documentées (health, ready, docs, redoc) - ✅ Routes api_v1_router.py créé - agrège tous les sous-routeurs - ✅ Routes admin_routes.py créé - tous les endpoints admin sous /api/v1/admin/ - ✅ Routes legacy_routes.py créé - endpoints migrés (languages, ollama, metrics, etc.) - ✅ main.py nettoyé - ne contient plus que les exceptions (health, ready, root) - ✅ Config.py mis à jour avec description mentionnant /api/v1 - ✅ Tests complets créés dans tests/test_story_3_5_api_versioning.py - ✅ Tests existants mis à jour pour utiliser les endpoints versionnés - ✅ Ancien auth_router marqué DEPRECATED - non importé, conservé pour référence ### Code Review Fixes Applied (2026-02-22) - 🔧 Sécurité: Suppression du mot de passe admin par défaut "changeme123" - 🔧 Stripe webhook migré vers /api/v1/auth/webhook/stripe - 🔧 Valeurs hardcodées remplacées par config (metrics, rate-limit/status) - 🔧 Tests ajoutés pour endpoints manquants (extract-texts, reconstruct, batch, download, cleanup) - 🔧 Ancien router /api/auth marqué DEPRECATED avec documentation ### File List - `routes/api_v1_router.py` - CRÉÉ - Routeur principal /api/v1 - `routes/admin_routes.py` - CRÉÉ - Endpoints admin versionnés - `routes/legacy_routes.py` - CRÉÉ - Endpoints migrés de main.py - `main.py` - MODIFIÉ - Nettoyé et inclut api_v1_router uniquement - `config.py` - MODIFIÉ - Description mise à jour avec mention /api/v1 - `tests/test_story_3_5_api_versioning.py` - CRÉÉ - 31 tests complets - `tests/test_admin_tier_change.py` - MODIFIÉ - URLs et patches mis à jour - `tests/test_story_3_3_admin_api_key_revocation.py` - MODIFIÉ - URLs et patches mis à jour - `tests/test_auth_register.py` - MODIFIÉ - Test legacy path skipped ## Change Log - 2026-02-22: Story créée avec contexte complet (endpoints à migrer, architecture proposée, code suggéré) - 2026-02-22: Implémentation complète - tous les endpoints migrés sous /api/v1/, tests passants ## Checklist de Validation Avant de marquer cette story comme terminée, vérifier: - [x] Tous les endpoints API sont sous `/api/v1/` - [x] Les endpoints non-versionnés retournent 404 (sauf exceptions) - [x] `/health` et `/ready` sont accessibles sans préfixe - [x] `/docs` et `/redoc` sont accessibles sans préfixe - [x] La version est documentée dans OpenAPI - [x] Les clients existants utilisant `/api/v1/*` ne sont pas affectés - [x] Tous les tests passent - [x] Le routeur principal `api_v1_router.py` est créé - [x] Le routeur admin `admin_routes.py` est créé - [x] main.py est nettoyé et ne contient que les endpoints exception