Files
office_translator/_bmad-output/implementation-artifacts/6-3-redis-configuration.md
Sepehr Ramezani 26bd096a06 feat: production deployment - full update with providers, admin, glossaries, pricing, tests
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>
2026-04-25 15:01:47 +02:00

152 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Story 6.3: Redis Configuration
Status: done
<!-- Note: Validation is optional. Run validate-create-story for quality check before dev-story. -->
## Story
As a **system**,
I want **Redis configured for rate limiting and caching**,
so that **the application scales**.
## Acceptance Criteria
1. **Given** Redis container is running
**When** the application starts
**Then** Redis connection is established
**And** rate limiting middleware uses Redis
**And** translation progress is cached in Redis
**And** Redis data is persisted to volume
## Tasks / Subtasks
- [x] Task 1 (AC: #1) — Connexion Redis au démarrage
- [x] 1.1 Vérifier que REDIS_URL est lu depuis l'environnement et qu'un client Redis (sync ou async) est initialisé au démarrage de l'app.
- [x] 1.2 S'assurer que l'échec de connexion Redis est géré proprement (démarrage sans Redis en dev optionnel, ou fail-fast en prod selon convention projet).
- [x] Task 2 (AC: #1) — Rate limiting via Redis
- [x] 2.1 Le middleware de rate limiting (par IP et/ou par utilisateur) utilise Redis pour les compteurs (sliding window ou équivalent) afin que la limite soit partagée entre instances.
- [x] 2.2 Documenter ou adapter le middleware existant (rate_limiting.py et tier_quota) pour qu'au moins le quota par tier (daily) et idéalement les limites par fenêtre utilisent Redis.
- [x] Task 3 (AC: #1) — Cache de progression traduction
- [x] 3.1 La progression des traductions (status, progress_percent, current_step) est lue/écrite via Redis pour permettre le polling multi-instance et la persistance courte durée.
- [x] 3.2 Vérifier que le storage_tracker / métadonnées jobs utilisent bien Redis (déjà le cas) et que l'endpoint GET /api/v1/translations/{id} s'appuie sur ce stockage.
- [x] Task 4 (AC: #1) — Persistance Redis
- [x] 4.1 En environnement Docker (dev et prod), Redis est lancé avec persistance (appendonly yes) et volume dédié (déjà en place dans docker-compose.dev.yml et docker-compose.yml).
- [x] 4.2 Documenter dans .env.example ou README que REDIS_URL est requis pour le rate limiting et le cache de progression en production.
## Dev Notes
- **Contexte** : Les stories 6-1 et 6-2 ont livré Docker Compose dev et prod avec un service Redis (redis:7-alpine, volume, healthcheck). Le backend utilise déjà REDIS_URL à plusieurs endroits : tier_quota (quota quotidien par user), storage_tracker (métadonnées fichiers/jobs), auth blocklist (JWT révoqués), admin sessions, health check. Le middleware `rate_limiting.py` (limites par IP) est actuellement **en mémoire** (SlidingWindowCounter, TokenBucket) ; les AC exigent que le rate limiting middleware utilise Redis pour la scalabilité.
- **Architecture** : [Source: _bmad-output/planning-artifacts/architecture.md] — Rate Limiting Redis + sliding window ; Translation → Redis (rate limiting, progress). Health check format : `redis: connected` dans GET /health.
- **NFR10** : REDIS_URL via variables d'environnement uniquement.
- **Fichiers à toucher** : configuration Redis centralisée (core/config ou équivalent), `middleware/rate_limiting.py` (option Redis backend), `middleware/tier_quota.py` (déjà Redis), `services/storage_tracker.py` (déjà Redis), `main.py` (health check Redis), `.env.example` / README.
### Project Structure Notes
- Racine : `office_translator/` avec `main.py`, `middleware/`, `services/`, `routes/`. Redis utilisé depuis plusieurs modules ; viser un client partagé (singleton) pour éviter trop de connexions.
- Docker : `docker-compose.yml` et `docker-compose.dev.yml` définissent déjà le service `redis` avec volume et `redis-server --appendonly yes`.
### References
- [Source: _bmad-output/planning-artifacts/architecture.md] — Infrastructure & Deployment, Rate Limiting, Health Check Format.
- [Source: _bmad-output/planning-artifacts/epics.md] — Epic 6, Story 6.3, AC BDD.
- [Source: _bmad-output/implementation-artifacts/6-2-docker-compose-production.md] — Redis service prod, REDIS_URL, healthcheck.
### Technical Requirements (Architecture Compliance)
- **Connexion** : Un seul client Redis async partagé (ou sync selon usage) recommandé pour tier_quota, storage_tracker, et si possible rate_limiting ; initialisation au démarrage ou lazy avec gestion d'erreur claire.
- **Rate limiting** : Utiliser Redis pour stocker les fenêtres (sliding window) par clé (ex. `rate_limit:ip:{ip}:minute`). Si le middleware actuel est en mémoire, ajouter un backend Redis optionnel et l'activer quand REDIS_URL est défini (comportement existant dans tier_quota et storage_tracker).
- **Progress** : Les métadonnées de job (id, status, progress_percent, current_step) doivent être lisibles via Redis pour GET /api/v1/translations/{id} (déjà le cas si storage_tracker est utilisé pour ces infos).
- **Persistance** : Redis avec `appendonly yes` et volume monté (déjà en place dans Compose) ; pas de changement nécessaire si déjà configuré.
- **Health check** : GET /health doit inclure un champ `redis` avec status "healthy" / "unhealthy" / "not_configured" (déjà présent dans main.py).
### Architecture Compliance
- Alignement avec architecture.md : Redis pour rate limiting distribué et cache (progress). Pas de nouveau service ; configuration et usage cohérents.
- Respect de la structure projet : middleware/, services/, core/ si config centralisée.
### Library / Framework Requirements
- **redis** (Python) : utiliser `redis` (sync) et `redis.asyncio` (async) selon le module. Version compatible Python 3.11+ (redis >= 4.5 pour asyncio). Déjà présent dans le projet (tier_quota, storage_tracker, auth_service, admin_routes, main.py).
- Pas de nouvelle dépendance si redis est déjà dans requirements.txt ou pyproject.toml ; sinon lajouter.
### File Structure Requirements
- Ne pas dupliquer la logique de connexion Redis : centraliser dans un module (ex. `core/redis.py` ou réutiliser le pattern `_get_async_redis()` depuis un seul module importé par les autres).
- `.env.example` : REDIS_URL documenté (ex. `redis://redis:6379/0` pour Docker, `redis://localhost:6379/0` pour dev local).
### Testing Requirements
- Vérifier que lorsque REDIS_URL est défini, lapplication se connecte à Redis et que GET /health renvoie `redis: healthy`.
- Vérifier que le rate limiting (par user/tier ou par IP si migré) utilise Redis : deux requêtes depuis deux processus/instances différentes partagent la même limite.
- Vérifier que la progression dune traduction (GET /api/v1/translations/{id}) est bien lue depuis Redis après un enregistrement par le worker.
- Vérifier quen Docker, le volume Redis persiste les données après redémarrage du conteneur redis.
### Previous Story Intelligence (6-2 Docker Compose Production)
- **Fichiers créés/modifiés** : `docker-compose.yml`, `.env.example`, `scripts/verify-prod-compose.sh`. Redis service déjà défini avec healthcheck, volume `redis_data`, command `redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru`.
- **Patterns établis** : backend dépend de redis avec `condition: service_healthy` ; REDIS_URL=redis://redis:6379/0 dans environment backend.
- **Différence clé pour 6-3** : pas de changement Compose nécessaire pour Redis ; focus sur lapplication (connexion, middleware, cache progress, documentation).
### Git Intelligence Summary
- Codebase existante utilise déjà Redis dans plusieurs services (tier_quota, storage_tracker, auth blocklist, admin sessions, health). La story 6-3 formalise et complète la configuration : sassurer que le rate limiting (middleware IP) utilise Redis si pas déjà le cas, et que toute la doc/config est cohérente.
### Latest Tech Information
- redis-py 5.x : API stable, redis.asyncio recommandé pour FastAPI. Compatible Redis 6/7. Pas de breaking change majeur pour from_url, ping(), setex, get, etc.
- Redis 7 : appendonly yes et volume suffisent pour la persistance ; allkeys-lru avec maxmemory pour éviter saturation.
### Project Context Reference
- Aucun fichier `project-context.md` trouvé. Contexte métier et stack : architecture.md et epics.md.
## Dev Agent Record
### Agent Model Used
(dev-story workflow)
### Debug Log References
-
### Completion Notes List
- **Task 1**: Added `core/redis.py` with get_redis_url(), get_async_redis(), get_sync_redis(), ping_sync(). Refactored storage_tracker, tier_quota, main.py health/ready, admin_routes, auth_service to use shared clients. Connection failure handled gracefully (None when REDIS_URL missing or connection fails).
- **Task 2**: Rate limiting middleware uses Redis when REDIS_URL is set: sliding-window counters (minute/hour/day, trans_minute/trans_hour) stored in Redis (key pattern rate_limit:ip:{client_id}:{window}). Fallback to in-memory when Redis unavailable. tier_quota already used Redis.
- **Task 3**: Translation job status cached in Redis: core.redis set_job_status_async/get_job_status_async (key translation:job:{job_id}). Job created/updated in translate_routes triggers Redis write; background task syncs job to Redis every 0.5s until completed/failed. GET /api/v1/translations/{id} reads from Redis first, then falls back to _translation_jobs.
- **Task 4**: Docker Compose dev/prod already use Redis with appendonly yes and volume. .env.example updated with Redis section stating REDIS_URL required for rate limiting and translation progress cache in production.
- **Code Review (AI)** : GET /download/{id} résout le job via Redis (get_job_status_async) puis _translation_jobs pour cohérence multi-instance. Rate limiting Redis : application de max_total_size_per_hour_mb (clé rate_limit:size_hour:{client_id}:{hour_ts}). core/redis : socket_connect_timeout=5 pour le client sync, logs sur set_job_status_async/get_job_status_async. Test ping_sync succès ajouté. File List complétée avec fichiers modifiés non listés initialement.
### File List
- core/__init__.py (créé)
- core/redis.py (créé — timeout sync, logs job status)
- services/storage_tracker.py (modifié — utilise core.redis.get_async_redis)
- middleware/tier_quota.py (modifié — utilise core.redis.get_async_redis)
- main.py (modifié — health/ready utilisent core.redis.ping_sync)
- routes/admin_routes.py (modifié — get_redis_client utilise core.redis.get_sync_redis)
- services/auth_service.py (modifié — _get_blocklist_redis utilise core.redis.get_sync_redis)
- middleware/rate_limiting.py (modifié — backend Redis sliding window + size_hour; quand REDIS_URL défini)
- routes/translate_routes.py (modifié — set_job_status_async/get_job_status_async, GET status from Redis, GET download résout job via Redis)
- .env.example (modifié — section Redis)
- tests/test_core_redis.py (créé — tests unitaires core.redis + ping_sync success)
- _bmad-output/implementation-artifacts/6-3-redis-configuration.md (modifié — statut, tâches, Dev Agent Record)
- _bmad-output/implementation-artifacts/sprint-status.yaml (modifié — 6-3 → done)
- alembic/env.py (modifié — non listé initialement, ajouté en revue)
- docker-compose.yml (modifié — non listé initialement, ajouté en revue)
- docker-compose.dev.yml (modifié — non listé initialement, ajouté en revue)
- .env.production (modifié — non listé initialement, ajouté en revue)
- scripts/verify-dev-compose.sh (créé — non listé initialement, ajouté en revue)
### Senior Developer Review (AI)
- **Date** : 2026-03-10. **Issues trouvés** : 2 critiques, 3 haute, 3 moyenne, 2 basse. **Écarts Git vs File List** : 5.
- **Correctifs appliqués** : GET /download/{id} résout le job via Redis puis mémoire ; rate limiting Redis applique max_total_size_per_hour_mb ; core/redis timeout + logs ; test ping_sync success ; File List complétée.
- **Statut** : done (tous les correctifs HIGH/MEDIUM appliqués).
### Change Log
- 2026-03-10 — Code review (AI) : correctifs appliqués, story passée en done, sprint-status synced.