---
stepsCompleted: [1, 2, 3, 4, 5, 6, 7, 8]
inputDocuments:
  - prd.md
  - prd-validation-report.md
  - product-brief-office_translator-2026-02-18.md
workflowType: 'architecture'
project_name: 'office_translator'
user_name: 'Sepehr'
date: '2026-02-18'
lastStep: 8
status: 'complete'
completedAt: '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:**
```tsx
// 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:**
```json
{
  "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

```json
{
  "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

```json
{
  "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:**
```python
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:**
```typescript
try {
  const result = await apiClient.translate(file);
} catch (error) {
  // error.response.data = { error, message, details }
  toast.error(error.response.data.message);
}
```

#### Loading States

```typescript
// 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:**

```typescript
// ❌ 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:**

```http
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:**
```json
{
  "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:**
```json
{
  "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):**

```python
# 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:**
```python
# 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:**
```bash
docker-compose -f docker-compose.dev.yml up -d
# Backend: http://localhost:8000
# Frontend: http://localhost:3000
# API Docs: http://localhost:8000/docs
```

**Migrations:**
```bash
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:**
- [x] Technologies avec versions documentées
- [x] Patterns de nommage complets
- [x] Formats API (succès + erreur)
- [x] Règles critiques (App Router, colocation)

**Structure Completeness:**
- [x] Arbre complet backend + frontend
- [x] Fichiers de configuration définis
- [x] Migrations Alembic nommées
- [x] Tests organisés

**Pattern Completeness:**
- [x] Naming conventions
- [x] API response formats
- [x] Error codes
- [x] 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**
- [x] Project context analysé
- [x] Scale et complexité évalués
- [x] Contraintes techniques identifiées
- [x] Cross-cutting concerns mappés

**✅ Architectural Decisions**
- [x] Décisions critiques documentées avec versions
- [x] Stack technologique complète
- [x] Patterns d'intégration définis
- [x] Considérations performance adressées

**✅ Implementation Patterns**
- [x] Naming conventions établies
- [x] Structure patterns définis
- [x] Communication patterns spécifiés
- [x] Process patterns documentés

**✅ Project Structure**
- [x] Directory structure complète
- [x] Component boundaries établies
- [x] Integration points mappés
- [x] 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*
