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

12 KiB
Raw Blame History

Story 6.3: Redis Configuration

Status: done

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

  • Task 1 (AC: #1) — Connexion Redis au démarrage
    • 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.
    • 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).
  • Task 2 (AC: #1) — Rate limiting via Redis
    • 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.
    • 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.
  • Task 3 (AC: #1) — Cache de progression traduction
    • 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.
    • 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.
  • Task 4 (AC: #1) — Persistance Redis
    • 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).
    • 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.