Files
office_translator/_bmad-output/planning-artifacts/architecture.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

33 KiB

stepsCompleted, inputDocuments, workflowType, project_name, user_name, date, lastStep, status, completedAt
stepsCompleted inputDocuments workflowType project_name user_name date lastStep status completedAt
1
2
3
4
5
6
7
8
prd.md
prd-validation-report.md
product-brief-office_translator-2026-02-18.md
architecture office_translator Sepehr 2026-02-18 8 complete 2026-02-19

Architecture Decision Document

This document builds collaboratively through step-by-step discovery. Sections are appended as we work through each architectural decision together.

Project Context Analysis

Requirements Overview

Functional Requirements:

Catégorie Count Impact Architectural
Document Translation FR1-FR8 Cœur métier - module translation
Format Preservation FR9-FR16 Critique - différenciateur produit
User Management & Auth FR17-FR22 Module auth (JWT + API Keys)
Subscription & Billing FR23-FR28 Module payment à refactorer
API & Integration FR29-FR35 API REST versionnée /api/v1/
Webhooks FR36-FR38, FR65-FR66 Module webhooks (Fire & Forget)
Admin Dashboard FR39-FR45 Module admin
Web UI FR46-FR49 Frontend Next.js
File Management FR50-FR54 Stockage éphémère /tmp
Error Handling FR55-FR57 Cross-cutting concern
Glossaries & Prompts FR58-FR61 MVP Critique - Justification abonnement Pro
URL Ingestion FR62-FR64 Feature automation

Non-Functional Requirements:

Catégorie NFRs Décisions Architecturales Clés
Performance NFR1-NFR5 Async processing, progress feedback < 500ms
Security NFR6-NFR11 JWT + API Keys, HTTPS, secrets via env
Reliability NFR12-NFR14 0% HTTP 500, provider fallback, TTL cleanup
Data Retention NFR15-NFR17 Zero retention, 60 min TTL, RGPD by design
API Quality NFR18-NFR21 OpenAPI 3.0, JSON errors, rate limiting, versioning

Scale & Complexity:

  • Primary domain: Full-stack (Backend API + Frontend Web + Admin Dashboard)
  • Complexity level: Moyenne-Haute
  • Estimated architectural components: 5 modules

Technical Constraints & Dependencies

Contrainte Description Impact
Brownfield Refonte de l'existant Architecture monolithique modulaire
Solo Developer Une seule personne Pas de microservices, dette technique zéro
Payment Module Existant à refactorer Clean Architecture pour module payment
Stockage Local éphémère /tmp Pas de S3 pour MVP
Hébergement Préférence UE RGPD compliance
LLM Providers Multi-provider (Ollama, OpenAI, compatibles) Abstraction provider avec fallback

Cross-Cutting Concerns Identified

Concern Modules Affectés Stratégie
Rate Limiting API, Auth Par utilisateur/tier, réponse 429 avec Retry-After
Logging Tous Structuré, métadonnées uniquement (pas de contenu document)
Error Handling Tous 0% HTTP 500, erreurs JSON structurées
File Cleanup Translation TTL 60 min, hard delete après download
Auth API, Admin, Web JWT (Web/Admin) + API Keys (Automation)

Starter Template Evaluation

Primary Technology Domain

Full-stack Brownfield — Refonte de l'existant avec stack technologique validée.

Contexte Projet

Ce n'est pas un projet greenfield. L'objectif est de refactorer une codebase existante vers une architecture propre (Clean Architecture) plutôt que de partir d'un starter template.

Stack Technologique Confirmée

Couche Technologie Justification
Backend FastAPI (Python) Écosystème Python, async natif, excellent pour API REST
Frontend Next.js 15 (App Router) Déjà en place, Tailwind CSS inclus
Base de données PostgreSQL (prod) / SQLite (dev) SaaS-ready, données persistantes (users, subscriptions, API keys)
ORM SQLAlchemy / SQLModel Moderne, typé, compatible FastAPI
Rate Limiting Redis Robuste, distribué, performant
Déploiement Docker + VPS Reverse proxy (Traefik/Nginx), HTTPS/HSTS

Refactoring Backend - Clean Architecture

Structure cible par domaine:

backend/
├── modules/
│   ├── translation/    # Cœur métier
│   │   ├── router.py
│   │   ├── service.py
│   │   └── schemas.py
│   ├── auth/           # JWT + API Keys
│   ├── payment/        # À refactorer
│   ├── admin/          # Dashboard
│   └── webhooks/       # Notifications
├── core/
│   ├── config.py       # Pydantic BaseSettings
│   ├── security.py
│   └── database.py
└── main.py             # Point d'entrée épuré

Refactoring Frontend - Focus UX

  • Suppression code mort
  • Amélioration Core Web Vitals (LCP < 2.5s, INP < 200ms, CLS < 0.1)
  • UX cohérente (textes unifiés, parcours clairs)

Décisions Architecturales Établies

Language & Runtime:

  • Backend: Python 3.11+ avec FastAPI
  • Frontend: TypeScript avec Next.js 15

Styling Solution:

  • Tailwind CSS (déjà configuré)

Build Tooling:

  • Backend: uv/pip avec pyproject.toml
  • Frontend: Next.js built-in (Turbopack)

Database & ORM:

  • PostgreSQL (prod) / SQLite (dev)
  • SQLAlchemy 2.0 ou SQLModel

Infrastructure:

  • Docker Compose pour orchestration locale
  • VPS avec reverse proxy pour production

Core Architectural Decisions

Decision Priority Analysis

Critical Decisions (Block Implementation):

  • Auth library (PyJWT)
  • Database migrations (Alembic)
  • Error format (JSON structuré)

Important Decisions (Shape Architecture):

  • State management frontend (TanStack Query)
  • Logging (structlog)
  • API documentation (Swagger + ReDoc)

Deferred Decisions (Post-MVP):

  • Prometheus/Grafana monitoring
  • Zustand pour state local complexe

Data Architecture

Décision Choix Version Rationale
Database PostgreSQL (prod) / SQLite (dev) 16+ / 3.x SaaS-ready, abonnements, API keys
ORM SQLAlchemy 2.0 / SQLModel 2.0+ Typé, compatible FastAPI, mature
Migrations Alembic Latest Standard absolu SQLAlchemy, évolutivité schéma
Validation Pydantic v2 2.x Natif FastAPI, validation automatique

Authentication & Security

Décision Choix Version Rationale
JWT Library PyJWT 2.x Moderne, bien maintenu, plus standard que python-jose
Password Hashing passlib[bcrypt] Latest Éprouvé, standard industrie, parfait MVP
API Key Generation secrets.token_urlsafe(32) Natif 256-bit, URL-safe, simple, sécurisé
Token Expiry Access: 15min, Refresh: 7 days PRD NFR6

Flux Auth:

Web/Admin → JWT (Access + Refresh Tokens)
API Automation → X-API-Key header (static key)

API & Communication Patterns

Décision Choix Rationale
REST Versioning /api/v1/ PRD requirement, préserve intégrations
Error Format {error, message, details?} Parsable par n8n, clair pour devs
Documentation Swagger UI + ReDoc FastAPI génère gratuitement, Swagger=test, ReDoc=lecture
Rate Limiting Redis + sliding window Par utilisateur/tier, réponse 429 + Retry-After

Endpoints Principaux:

Endpoint Méthode Description
/api/v1/translate POST Traduire un document
/api/v1/languages GET Langues supportées
/api/v1/health GET Santé du service
/api/v1/download/{id} GET Télécharger fichier traduit

Frontend Architecture

Décision Choix Rationale
State Management (Server) TanStack Query Standard pour appels API Next.js, cache, revalidation
State Management (Local) React useState Suffisant pour UI state, pas de Zustand nécessaire
Component Model Server Components default Next.js 15 best practice, 'use client' si besoin
Styling Tailwind CSS Déjà configuré

Pattern Data Fetching:

// Server Component (default)
const data = await fetch('/api/v1/languages');

// Client Component avec TanStack Query
const { data, isLoading } = useQuery({ queryKey: ['translations'], ... });

Infrastructure & Deployment

Décision Choix Rationale
Logging structlog JSON structuré, lisible par Admin Dashboard
Monitoring Simple health checks GET /health existant, pas d'over-engineering
Containerization Docker Compose Backend + Frontend + Redis + DB
Reverse Proxy Traefik ou Nginx HTTPS/HSTS, termination SSL
Hosting VPS unique Solo dev, simple, coût maîtrisé

Health Check Format:

{
  "status": "healthy",
  "database": "connected",
  "redis": "connected",
  "providers": {"google": "ok", "deepl": "ok"}
}

Decision Impact Analysis

Séquence d'Implémentation:

  1. Setup Alembic migrations
  2. Core: Auth module (PyJWT + passlib)
  3. Core: Translation module (providers abstraction)
  4. API: REST endpoints + error format
  5. Frontend: TanStack Query setup
  6. Infra: structlog integration
  7. Admin: Dashboard health metrics

Cross-Component Dependencies:

  • Auth → DB (users, api_keys tables)
  • Translation → Redis (rate limiting, progress)
  • Admin → Logging (structlog consumption)
  • Webhooks → Translation (completion events)

Implementation Patterns & Consistency Rules

⚠️ Règles Critiques (Non-Négociables)

Ces règles DOIVENT être respectées par tous les agents AI pour éviter les conflits:

🚨 NEXT.JS APP ROUTER - FICHIERS SPÉCIAUX
   page.tsx, layout.tsx, route.ts, loading.tsx, error.tsx
   → TOUJOURS en minuscules strictes
   → JAMAIS PascalCase (le framework plantera avec 404)

Naming Patterns

Backend (Python/FastAPI)

Élément Convention Exemple
Tables DB snake_case, pluriel users, api_keys, translations
Colonnes DB snake_case user_id, created_at, file_name
Foreign keys {table}_id user_id, subscription_id
Index idx_{table}_{columns} idx_users_email, idx_translations_user_id
Fichiers Python snake_case translation_service.py, auth_router.py
Variables snake_case user_id, file_path, translation_result
Fonctions snake_case get_user_by_id(), translate_document()
Classes PascalCase TranslationService, UserRepository
Constantes UPPER_SNAKE MAX_FILE_SIZE, TTL_SECONDS, API_VERSION

Frontend (TypeScript/Next.js)

Élément Convention Exemple
Fichiers spéciaux App Router minuscules strictes page.tsx, layout.tsx, route.ts, loading.tsx, error.tsx
Composants réutilisables PascalCase UserCard.tsx, TranslationProgress.tsx
Utilitaires/lib camelCase apiClient.ts, formatters.ts
Variables camelCase userId, fileName, translationResult
Fonctions camelCase getUserById(), handleFileUpload()
Composants (nom) PascalCase <UserCard />, <TranslationProgress />
Hooks useCamelCase useTranslation(), useUser()
Types/Interfaces PascalCase User, TranslationResponse, ApiError

API (Communication Backend ↔ Frontend)

Élément Convention Exemple
Endpoints REST pluriel, kebab-case /api/v1/users, /api/v1/api-keys
Paramètres route snake_case /api/v1/translations/{translation_id}
Query params snake_case ?user_id=123&file_type=xlsx
Headers Pascal-Kebab X-API-Key, Content-Type, Authorization
JSON fields snake_case user_id, created_at, file_name
Dates ISO 8601 string "2024-01-15T10:30:00Z"

API Response Formats

Format Succès

{
  "data": {
    "id": "abc123",
    "file_name": "report.xlsx",
    "status": "completed"
  },
  "meta": {
    "rate_limit_remaining": 45,
    "provider_used": "google",
    "processing_time_ms": 2340
  }
}

Champ meta utilisé pour:

  • Rate limiting info (rate_limit_remaining, rate_limit_reset)
  • Pagination (page, per_page, total)
  • Provider info (provider_used)
  • Performance (processing_time_ms)

Format Erreur

{
  "error": "QUOTA_EXCEEDED",
  "message": "Limite quotidienne atteinte. Passez en Pro pour plus de traductions.",
  "details": {
    "current_usage": 5,
    "limit": 5,
    "reset_at": "2024-01-16T00:00:00Z"
  }
}

⚠️ Pas de champ data en cas d'erreur.

Codes Erreur Standards

Code HTTP Usage
INVALID_FORMAT 400 Format fichier non supporté
QUOTA_EXCEEDED 429 Limite tier atteinte
UNAUTHORIZED 401 Token/API key invalide
FORBIDDEN 403 Pas les droits
FILE_TOO_LARGE 413 Fichier > max size
PROVIDER_ERROR 502 Provider externe en erreur

Structure Patterns

Organisation Tests

Couche Emplacement Exemple
Backend (Python) tests/ centralisé tests/test_translation_service.py
Frontend (TS/React) Co-localisé components/UserCard.test.tsx

Organisation Frontend (Colocation Pattern)

frontend/src/
├── app/                      # Next.js App Router
│   ├── (auth)/              # Route group
│   │   └── login/
│   │       ├── page.tsx     # ⚠️ minuscule!
│   │       ├── LoginForm.tsx    # ⭐ Colocated component
│   │       └── types.ts         # ⭐ Colocated types
│   ├── dashboard/
│   │   └── translate/
│   │       ├── page.tsx
│   │       ├── FileUploader.tsx     # ⭐ Colocated
│   │       ├── useTranslation.ts    # ⭐ Colocated hook
│   │       └── types.ts
│   ├── layout.tsx
│   └── page.tsx
├── components/
│   └── ui/                  # ⭐ Seulement composants GLOBAUX
│       ├── Button.tsx
│       └── Input.tsx
├── lib/                     # ⭐ Seulement utilitaires GLOBAUX
│   └── apiClient.ts
└── providers/
    └── QueryProvider.tsx

Process Patterns

Error Handling

Backend:

from fastapi import HTTPException

raise HTTPException(
    status_code=400,
    detail={
        "error": "INVALID_FORMAT",
        "message": "Format PDF non supporté",
        "details": {"accepted_formats": [".xlsx", ".docx", ".pptx"]}
    }
)

Frontend:

try {
  const result = await apiClient.translate(file);
} catch (error) {
  // error.response.data = { error, message, details }
  toast.error(error.response.data.message);
}

Loading States

// TanStack Query pattern
const { data, isLoading, error } = useQuery({
  queryKey: ['translation', id],
  queryFn: () => apiClient.getTranslation(id),
});

if (isLoading) return <LoadingSpinner />;
if (error) return <ErrorMessage error={error} />;
return <TranslationResult data={data} />;

Enforcement Guidelines

Tous les agents AI DOIVENT:

  1. Respecter les conventions de nommage par langage
  2. Utiliser les formats API définis (succès avec data+meta, erreur sans data)
  3. Nommer les fichiers spéciaux Next.js en minuscules (page.tsx, pas Page.tsx)
  4. Utiliser snake_case pour les champs JSON API
  5. Retourner des erreurs structurées avec codes explicites
  6. Placer les tests selon les conventions (centralisé Python, co-localisé TS)

Anti-Patterns à ÉVITER:

// ❌ MAUVAIS - Fichier App Router en PascalCase
app/Dashboard/Page.tsx  // → 404 error!

// ❌ MAUVAIS - camelCase dans JSON API
{ "fileName": "report.xlsx" }

// ❌ MAUVAIS - data présent dans erreur
{ "data": null, "error": "..." }

// ✅ BON
app/dashboard/page.tsx
{ "file_name": "report.xlsx" }
{ "error": "...", "message": "..." }  // pas de data

Pattern Examples

Exemple Requête API Complète:

POST /api/v1/translate
X-API-Key: sk_live_abc123...
Content-Type: multipart/form-data

file: report.xlsx
source_lang: en
target_lang: fr
webhook_url: https://example.com/webhook

Réponse Succès:

{
  "data": {
    "id": "tr_abc123",
    "status": "processing",
    "file_name": "report.xlsx",
    "source_lang": "en",
    "target_lang": "fr"
  },
  "meta": {
    "rate_limit_remaining": 49,
    "estimated_time_seconds": 12
  }
}

Réponse Erreur:

{
  "error": "QUOTA_EXCEEDED",
  "message": "Limite quotidienne atteinte (5/5 fichiers)",
  "details": {
    "current_usage": 5,
    "limit": 5,
    "tier": "free",
    "reset_at": "2024-01-16T00:00:00Z"
  }
}

Project Structure & Boundaries

⚠️ Règle de Colocation (Frontend)

🚨 NEXT.JS APP ROUTER - COLOCATION
   Les composants, hooks et types spécifiques à une page
   doivent vivre DANS le dossier de la route correspondante.
   
   → Un seul dossier par feature = tous les fichiers proches
   → Seuls les composants GLOBAUX vont dans src/components/ui/

Complete Project Directory Structure

office_translator/
├── docker-compose.yml
├── docker-compose.dev.yml
├── .env.example
├── .gitignore
├── README.md
│
├── backend/
│   ├── pyproject.toml
│   ├── requirements.txt
│   ├── alembic.ini
│   ├── .env.example
│   ├── Dockerfile
│   │
│   ├── alembic/
│   │   ├── env.py
│   │   ├── versions/
│   │   │   ├── 001_initial_users.py      # User + tier field
│   │   │   ├── 002_api_keys.py
│   │   │   ├── 003_translations.py
│   │   │   └── 004_glossaries.py
│   │   └── script.py.mako
│   │
│   ├── app/
│   │   ├── main.py
│   │   ├── __init__.py
│   │   │
│   │   ├── core/
│   │   │   ├── __init__.py
│   │   │   ├── config.py           # Pydantic BaseSettings
│   │   │   ├── database.py         # SQLAlchemy async engine
│   │   │   ├── security.py         # JWT, password hashing
│   │   │   ├── logging.py          # structlog setup
│   │   │   └── exceptions.py       # Custom exceptions
│   │   │
│   │   ├── modules/
│   │   │   ├── __init__.py
│   │   │   │
│   │   │   ├── auth/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── router.py       # /api/v1/auth/*
│   │   │   │   ├── service.py
│   │   │   │   ├── schemas.py
│   │   │   │   └── dependencies.py # get_current_user
│   │   │   │
│   │   │   ├── translation/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── router.py       # /api/v1/translate
│   │   │   │   ├── service.py      # Translation orchestration
│   │   │   │   ├── ingest.py       # ⭐ URL ingestion (FR62-FR64)
│   │   │   │   ├── schemas.py
│   │   │   │   ├── providers/
│   │   │   │   │   ├── __init__.py
│   │   │   │   │   ├── base.py     # Abstract provider
│   │   │   │   │   ├── google.py
│   │   │   │   │   ├── deepl.py
│   │   │   │   │   ├── ollama.py
│   │   │   │   │   └── openai.py
│   │   │   │   └── processors/
│   │   │   │       ├── __init__.py
│   │   │   │       ├── excel.py
│   │   │   │       ├── word.py
│   │   │   │       └── powerpoint.py
│   │   │   │
│   │   │   ├── glossaries/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── router.py       # /api/v1/glossaries
│   │   │   │   ├── service.py
│   │   │   │   └── schemas.py
│   │   │   │
│   │   │   ├── webhooks/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── router.py
│   │   │   │   ├── service.py      # ⭐ Fire & Forget (FR36-FR38)
│   │   │   │   └── schemas.py
│   │   │   │
│   │   │   ├── admin/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── router.py       # /api/v1/admin/*
│   │   │   │   ├── service.py
│   │   │   │   └── schemas.py
│   │   │   │
│   │   │   └── payment/
│   │   │       ├── __init__.py
│   │   │       ├── router.py       # /api/v1/payments
│   │   │       ├── service.py
│   │   │       └── schemas.py
│   │   │
│   │   ├── models/
│   │   │   ├── __init__.py
│   │   │   ├── user.py             # ⭐ user.tier (free/pro) direct
│   │   │   ├── api_key.py
│   │   │   ├── translation.py
│   │   │   └── glossary.py
│   │   │
│   │   └── middleware/
│   │       ├── __init__.py
│   │       ├── rate_limit.py       # Redis + user.tier check
│   │       └── error_handler.py
│   │
│   └── tests/
│       ├── __init__.py
│       ├── conftest.py
│       ├── test_translation_service.py
│       ├── test_ingest.py           # ⭐ URL ingestion tests
│       ├── test_auth_router.py
│       ├── test_rate_limit.py
│       └── test_providers/
│           ├── test_google_provider.py
│           └── test_deepl_provider.py
│
├── frontend/
│   ├── package.json
│   ├── next.config.js
│   ├── tailwind.config.ts
│   ├── tsconfig.json
│   ├── .env.local.example
│   ├── Dockerfile
│   │
│   ├── src/
│   │   ├── app/
│   │   │   ├── layout.tsx          # Root layout
│   │   │   ├── page.tsx            # Landing page
│   │   │   ├── globals.css
│   │   │   │
│   │   │   ├── (auth)/
│   │   │   │   ├── layout.tsx
│   │   │   │   ├── login/
│   │   │   │   │   ├── page.tsx
│   │   │   │   │   ├── LoginForm.tsx    # ⭐ Colocated
│   │   │   │   │   └── types.ts         # ⭐ Colocated
│   │   │   │   └── register/
│   │   │   │       ├── page.tsx
│   │   │   │       ├── RegisterForm.tsx # ⭐ Colocated
│   │   │   │       └── types.ts
│   │   │   │
│   │   │   ├── dashboard/
│   │   │   │   ├── layout.tsx
│   │   │   │   ├── page.tsx
│   │   │   │   ├── translate/
│   │   │   │   │   ├── page.tsx
│   │   │   │   │   ├── FileUploader.tsx    # ⭐ Colocated
│   │   │   │   │   ├── TranslationProgress.tsx
│   │   │   │   │   ├── LanguageSelector.tsx
│   │   │   │   │   ├── useTranslation.ts    # ⭐ Colocated hook
│   │   │   │   │   └── types.ts             # ⭐ Colocated types
│   │   │   │   ├── api-keys/
│   │   │   │   │   ├── page.tsx
│   │   │   │   │   ├── ApiKeyManager.tsx    # ⭐ Colocated
│   │   │   │   │   ├── useApiKeys.ts
│   │   │   │   │   └── types.ts
│   │   │   │   └── glossaries/
│   │   │   │       ├── page.tsx
│   │   │   │       ├── GlossaryEditor.tsx   # ⭐ Colocated
│   │   │   │       ├── useGlossaries.ts
│   │   │   │       └── types.ts
│   │   │   │
│   │   │   └── admin/
│   │   │       ├── layout.tsx
│   │   │       ├── page.tsx
│   │   │       ├── users/
│   │   │       │   ├── page.tsx
│   │   │       │   ├── UserTable.tsx        # ⭐ Colocated
│   │   │       │   ├── TierBadge.tsx
│   │   │       │   └── types.ts
│   │   │       └── system/
│   │   │           ├── page.tsx
│   │   │           ├── HealthStatus.tsx      # ⭐ Colocated
│   │   │           └── types.ts
│   │   │
│   │   ├── components/
│   │   │   └── ui/                # ⭐ Seulement composants GLOBAUX
│   │   │       ├── Button.tsx
│   │   │       ├── Input.tsx
│   │   │       ├── Card.tsx
│   │   │       ├── Modal.tsx
│   │   │       ├── LoadingSpinner.tsx
│   │   │       └── ErrorMessage.tsx
│   │   │
│   │   ├── lib/                   # ⭐ Seulement utilitaires GLOBAUX
│   │   │   ├── apiClient.ts       # Fetch wrapper, error handling
│   │   │   ├── auth.ts            # Token management
│   │   │   └── constants.ts       # App-wide constants
│   │   │
│   │   └── providers/
│   │       └── QueryProvider.tsx  # TanStack Query setup
│   │
│   ├── __tests__/
│   │   └── lib/
│   │       └── apiClient.test.ts
│   │
│   └── public/
│       ├── favicon.ico
│       └── logo.svg
│
└── scripts/
    ├── deploy.sh
    └── backup-db.sh

Architectural Boundaries

API Boundaries

Frontière Description
/api/v1/translate Public endpoint (auth required)
/api/v1/admin/* Admin-only (role check)
/api/v1/glossaries Pro-only (tier check)
Rate Limiting Middleware → Redis → user.tier

Data Boundaries

Modèle User (simplifié pour Rate Limiting):

# models/user.py
class User(Base):
    __tablename__ = "users"
    
    id: Mapped[UUID]
    email: Mapped[str]
    hashed_password: Mapped[str]
    tier: Mapped[str] = mapped_column(default="free")  # ⭐ "free" | "pro"
    daily_translation_count: Mapped[int] = mapped_column(default=0)
    # ... timestamps

Rate Limiting Logic:

# middleware/rate_limit.py
FREE_TIER_LIMIT = 5  # files per day
PRO_TIER_LIMIT = None  # unlimited

if user.tier == "free" and user.daily_translation_count >= FREE_TIER_LIMIT:
    raise QuotaExceededError()

Requirements to Structure Mapping

Module PRD Backend Frontend
Translation (FR1-FR8) modules/translation/ app/dashboard/translate/
Format Preservation (FR9-FR16) modules/translation/processors/
URL Ingestion (FR62-FR64) modules/translation/ingest.py
Auth (FR17-FR22) modules/auth/ app/(auth)/
Payment (FR23-FR28) modules/payment/ app/dashboard/
API Keys (FR29-FR31) models/api_key.py app/dashboard/api-keys/
Webhooks (FR36-FR38) modules/webhooks/
Admin (FR39-FR45) modules/admin/ app/admin/
Glossaries (FR58-FR61) modules/glossaries/ app/dashboard/glossaries/

Integration Points

Internal Communication

Frontend (Next.js)
    ↓ fetch /api/v1/*
Backend (FastAPI)
    ↓ SQLAlchemy
Database (PostgreSQL)
    ↓ 
Redis (Rate Limiting + Cache)

External Integrations

Service Module Usage
Google Translate providers/google.py Classic translation
DeepL providers/deepl.py Classic translation
Ollama providers/ollama.py LLM translation
OpenAI providers/openai.py LLM translation
Webhooks (User) webhooks/service.py POST to user URL

Development Workflow

Démarrage Local:

docker-compose -f docker-compose.dev.yml up -d
# Backend: http://localhost:8000
# Frontend: http://localhost:3000
# API Docs: http://localhost:8000/docs

Migrations:

cd backend
alembic revision --autogenerate -m "description"
alembic upgrade head

Architecture Validation Results

Coherence Validation

Decision Compatibility:

Stack Compatibilité
FastAPI + Pydantic v2 Natif, parfait
SQLAlchemy 2.0 + Alembic Standard, éprouvé
PyJWT + passlib[bcrypt] Stack auth standard
Next.js 15 + TanStack Query Moderne, best practice
PostgreSQL + Redis Combo classique SaaS
structlog + JSON logs Cohérent avec Admin Dashboard

Pattern Consistency:

  • snake_case DB/API ↔ camelCase Frontend (convention par langage)
  • App Router fichiers minuscules ↔ Colocation components/hooks
  • Response wrapper {data, meta} ↔ Error format {error, message}

Structure Alignment:

  • Backend: Clean Architecture modulaire → 5 modules métier
  • Frontend: Colocation par feature → fichiers proches de leur usage
  • Mapping FRs → Emplacements documenté

Requirements Coverage Validation

Functional Requirements Coverage (66 FRs):

Catégorie FRs Status
Document Translation FR1-FR8 Couvert
Format Preservation FR9-FR16 Couvert
User Management & Auth FR17-FR22 Couvert
Subscription & Billing FR23-FR28 Couvert
API & Integration FR29-FR35 Couvert
Webhooks FR36-FR38, FR65-FR66 Couvert
Admin Dashboard FR39-FR45 Couvert
Web UI FR46-FR49 Couvert
File Management FR50-FR54 Couvert
Error Handling FR55-FR57 Couvert
Glossaries & Prompts FR58-FR61 Couvert (MVP)
URL Ingestion FR62-FR64 Couvert

Non-Functional Requirements Coverage (21 NFRs):

Catégorie NFRs Status
Performance NFR1-NFR5 Async + TanStack Query
Security NFR6-NFR11 JWT + API Keys + HTTPS
Reliability NFR12-NFR14 Error handler + fallback
Data Retention NFR15-NFR17 TTL 60min + zero retention
API Quality NFR18-NFR21 OpenAPI + JSON errors + versioning

Implementation Readiness Validation

Decision Completeness:

  • Technologies avec versions documentées
  • Patterns de nommage complets
  • Formats API (succès + erreur)
  • Règles critiques (App Router, colocation)

Structure Completeness:

  • Arbre complet backend + frontend
  • Fichiers de configuration définis
  • Migrations Alembic nommées
  • Tests organisés

Pattern Completeness:

  • Naming conventions
  • API response formats
  • Error codes
  • Rate limiting logic

Gap Analysis

Critical Gaps: Aucun

Important Gaps: Aucun

Nice-to-Have (Post-MVP):

  • CI/CD pipeline (peut être défini lors implémentation)
  • PDF support (PRD: future feature)
  • Prometheus/Grafana (health checks suffisent)

Architecture Completeness Checklist

Requirements Analysis

  • Project context analysé
  • Scale et complexité évalués
  • Contraintes techniques identifiées
  • Cross-cutting concerns mappés

Architectural Decisions

  • Décisions critiques documentées avec versions
  • Stack technologique complète
  • Patterns d'intégration définis
  • Considérations performance adressées

Implementation Patterns

  • Naming conventions établies
  • Structure patterns définis
  • Communication patterns spécifiés
  • Process patterns documentés

Project Structure

  • Directory structure complète
  • Component boundaries établies
  • Integration points mappés
  • Requirements → Structure mapping

Architecture Readiness Assessment

Overall Status: 🟢 READY FOR IMPLEMENTATION

Confidence Level: HIGH

Key Strengths:

  • Stack technologique cohérente et moderne
  • Clean Architecture modulaire (maintenabilité)
  • Colocation frontend (DX excellent pour solo dev)
  • 100% FRs/NFRs couverts
  • Patterns anti-conflit documentés

Areas for Future Enhancement:

  • CI/CD pipeline automation
  • Advanced monitoring (Prometheus/Grafana)
  • PDF format support
  • Team collaboration features

Implementation Handoff

AI Agent Guidelines:

  1. Suivre toutes les décisions architecturales exactement
  2. Utiliser les patterns d'implémentation de manière cohérente
  3. Respecter la structure projet et les boundaries
  4. Se référer à ce document pour toute question architecturale

⚠️ Règles Critiques à Respecter:

🚨 NEXT.JS: page.tsx, layout.tsx TOUJOURS minuscules
🚨 COLOCATION: Components/hooks/types dans le dossier de leur page
🚨 API JSON: snake_case (pas camelCase)
🚨 RESPONSE: {data, meta} succès / {error, message} erreur

First Implementation Priority:

  1. Setup Alembic migrations (001_initial_users.py)
  2. Core: Auth module (PyJWT + passlib)
  3. Core: Translation module (providers abstraction)
  4. API: REST endpoints /api/v1/*
  5. Frontend: TanStack Query + colocation structure

Document généré via workflow BMAD create-architecture — 2026-02-18