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>
16 KiB
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
- Préfixe Obligatoire: Tous les endpoints API sont montés sous
/api/v1/prefix. (FR33) - Endpoints Non-Versionnés: Les endpoints sans préfixe de version retournent 404 (sauf health check et documentation).
- Documentation OpenAPI: La version est documentée dans la spécification OpenAPI (title, version, description).
- Rétrocompatibilité: Les clients existants utilisant
/api/v1/*ne sont pas affectés. - Health Check Préservé:
/healthet/readyrestent accessibles sans préfixe pour les probes Kubernetes. - Documentation Accessible:
/docs(Swagger UI) et/redocrestent accessibles sans préfixe.
Tasks / Subtasks
-
Task 1: Auditer les Endpoints Non-Versionnés (AC: #1, #2)
- 1.1 Lister tous les endpoints dans
main.pyqui ne sont pas sous/api/v1/ - 1.2 Identifier les endpoints à migrer vs à préserver (health, docs)
- 1.3 Documenter la liste des endpoints à déplacer
- 1.1 Lister tous les endpoints dans
-
Task 2: Créer un Routeur Racine API v1 (AC: #1)
- 2.1 Créer
routes/api_v1_router.pyavec un routeur principal pour/api/v1 - 2.2 Inclure tous les sous-routeurs (translate, auth, api-keys, admin)
- 2.3 Configurer les tags OpenAPI pour la documentation
- 2.1 Créer
-
Task 3: Migrer les Endpoints de main.py (AC: #1, #2)
- 3.1 Déplacer
/languagesvers/api/v1/languages - 3.2 Déplacer
/translatevers/api/v1/translate(déjà fait via translate_routes.py) - 3.3 Déplacer
/translate-batchvers/api/v1/translate/batch - 3.4 Déplacer
/download/{filename}vers/api/v1/download/{filename} - 3.5 Déplacer
/extract-textsvers/api/v1/extract-texts - 3.6 Déplacer
/reconstruct-documentvers/api/v1/reconstruct-document - 3.7 Déplacer
/ollama/modelsvers/api/v1/ollama/models - 3.8 Déplacer
/ollama/configurevers/api/v1/ollama/configure - 3.9 Déplacer
/rate-limit/statusvers/api/v1/rate-limit/status - 3.10 Déplacer
/admin/*vers/api/v1/admin/* - 3.11 Déplacer
/metricsvers/api/v1/metrics
- 3.1 Déplacer
-
Task 4: Configurer les Exceptions de Versioning (AC: #5, #6)
- 4.1 Garder
/healthaccessible sans préfixe (Kubernetes probe) - 4.2 Garder
/readyaccessible sans préfixe (Kubernetes probe) - 4.3 Garder
/docsaccessible sans préfixe (Swagger UI) - 4.4 Garder
/redocaccessible sans préfixe (ReDoc) - 4.5 Garder
/openapi.jsonaccessible sans préfixe - 4.6 Optionnel: Garder
/comme endpoint info avec redirect vers/docs
- 4.1 Garder
-
Task 5: Mettre à jour la Documentation OpenAPI (AC: #3)
- 5.1 Vérifier que
config.API_VERSIONest utilisé dans FastAPI app - 5.2 Ajouter la description de versioning dans la description de l'API
- 5.3 Documenter les endpoints versionnés dans les tags OpenAPI
- 5.1 Vérifier que
-
Task 6: Nettoyer main.py (AC: #1, #2)
- 6.1 Supprimer les endpoints déplacés de main.py
- 6.2 Garder uniquement les endpoints exception (health, docs, root)
- 6.3 Inclure le routeur API v1 principal
-
Task 7: Ajouter les Tests (AC: Tous)
- 7.1 Test endpoint versionné accessible (
/api/v1/healthou/api/v1/languages) - 7.2 Test endpoint non-versionné retourne 404 (sauf exceptions)
- 7.3 Test health check accessible sans préfixe
- 7.4 Test documentation accessible sans préfixe
- 7.5 Test tous les endpoints migrés fonctionnent
- 7.1 Test endpoint versionné accessible (
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:
# 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é:
# 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:
# 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
- Routeur api_key_routes.py utilise
prefix="/api/v1/api-keys"✅ - Pattern de réponse
{data: {...}, meta: {...}}établi - Tests complets avec fixtures dans
tests/conftest.py
Story 3.2 (API Key Revocation User) - Enseignements
- Soft delete avec
is_active=False - Fonction
get_user_by_api_keydansservices/auth_service.py - Format d'erreur structuré
{error, message, details?}
Story 3.3 (Admin API Key Revocation) - Enseignements
- Routes admin dans main.py - migré vers
routes/admin_routes.py - Dépendance
require_adminpour l'authentification admin - Audit logging avec
logger.info()
Story 3.4 (API Auth X-API-Key) - Enseignements
- Coexistence JWT + API Key dans
get_authenticated_user - Middleware d'auth dans
routes/translate_routes.py - Priorité API key sur JWT si les deux présents
Intelligence Git (Commits Récents)
Derniers commits pertinents:
3d37ce4: PostgreSQL database infrastructurec4d6cae: Redis sessions, security hardeningdfd45d9: Admin login endpoint
Patterns identifiés:
- Routeurs avec
APIRouter(prefix="/api/v1") - Tests avec
pytestdanstests/ - 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:
API Keys - Génération(Story 3.1 ✅)API Keys - Révocation User(Story 3.2 ✅)API Keys - Révocation Admin(Story 3.3 ✅)Authentification X-API-Key(Story 3.4 ✅)- API Versioning (cette story - COMPLETE)
- Documentation OpenAPI (Story 3.6 - ready-for-dev)
- Webhooks (Stories 3.7-3.8 - backlog)
- Glossaires (Stories 3.9-3.10 - backlog)
- 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
- NE PAS supprimer les endpoints health/ready (K8s probes)
- NE PAS supprimer l'accès à /docs et /redoc
- NE PAS casser les clients existants utilisant
/api/v1/* - NE PAS dupliquer le code - utiliser
include_router - NE PAS oublier de tester tous les endpoints migrés
- NE PAS modifier les routeurs existants (translate_routes.py, auth_routes.py, api_key_routes.py)
✅ À FAIRE
- TOUJOURS préfixer les nouveaux endpoints avec
/api/v1/ - TOUJOURS garder health/ready accessibles sans préfixe
- TOUJOURS tester que les endpoints non-versionnés retournent 404
- TOUJOURS documenter la version dans OpenAPI
- TOUJOURS utiliser
include_routerpour composer les routeurs - CRÉER un routeur principal
api_v1_router.py - 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/v1routes/admin_routes.py- CRÉÉ - Endpoints admin versionnésroutes/legacy_routes.py- CRÉÉ - Endpoints migrés de main.pymain.py- MODIFIÉ - Nettoyé et inclut api_v1_router uniquementconfig.py- MODIFIÉ - Description mise à jour avec mention /api/v1tests/test_story_3_5_api_versioning.py- CRÉÉ - 31 tests completstests/test_admin_tier_change.py- MODIFIÉ - URLs et patches mis à jourtests/test_story_3_3_admin_api_key_revocation.py- MODIFIÉ - URLs et patches mis à jourtests/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:
- Tous les endpoints API sont sous
/api/v1/ - Les endpoints non-versionnés retournent 404 (sauf exceptions)
/healthet/readysont accessibles sans préfixe/docset/redocsont accessibles sans préfixe- La version est documentée dans OpenAPI
- Les clients existants utilisant
/api/v1/*ne sont pas affectés - Tous les tests passent
- Le routeur principal
api_v1_router.pyest créé - Le routeur admin
admin_routes.pyest créé - main.py est nettoyé et ne contient que les endpoints exception