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>
383 lines
16 KiB
Markdown
383 lines
16 KiB
Markdown
# 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
|