2026-02-01 09:31:38 +01:00

970 lines
32 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.

---
stepsCompleted: ['step-01-init', 'step-02-context', 'step-03-starter', 'step-04-decisions', 'step-05-patterns', 'step-06-structure']
inputDocuments:
- prd.md
workflowType: 'architecture'
project_name: 'chartbastan'
user_name: 'Ramez'
date: '2026-01-15T21:00:00.000Z'
lastStep: 8
status: 'complete'
completedAt: '2026-01-15T22:00:00.000Z'
---
# 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:**
Le projet chartbastan est une application web de prédiction de résultats de football basée sur l'analyse de l'énergie collective des supporters via les réseaux sociaux. Les exigences fonctionnelles principales incluent :
- **Collecte de données multi-sources** : Scraping Twitter (60%), Reddit (25%), RSS (15%) avec pondération intelligente
- **Analyse de sentiment en temps réel** : Utilisation de VADER/textblob pour analyser 1000+ tweets en < 1 seconde
- **Calcul d'énergie collective** : Formule Score = (Positif - Négatif) × Volume × Viralité avec pondération temporelle
- **Système de backtesting** : Validation sur 100+ matchs historiques avec seuil de précision 60%
- **Dashboard temps réel** : Visualisations interactives (D3.js) avec Confidence Meter (0-100%)
- **Gamification** : Système de classement, badges, parrainage (invite 3 amis = 1 mois premium gratuit)
- **Modèle freemium** : Version gratuite (1-2 prédictions/jour) + Premium (19.99€/mois) avec métriques avancées
- **API publique** : Documentation et accès pour développeurs tiers (Phase 2+)
- **Notifications push** : Alertes pour changements majeurs d'énergie collective
**Non-Functional Requirements:**
Les NFRs critiques qui façonneront l'architecture :
- **Performance** : Dashboard mis à jour en < 3 secondes, analyse de 1000+ tweets en < 1 seconde
- **Disponibilité** : Uptime > 99.5% pour l'API FastAPI principale
- **Scalabilité** : Système de queue asynchrone (RabbitMQ) pour gérer les pics de charge
- **Précision** : Taux de précision ≥ 60% (seuil de validation, < 55% = révision requise)
- **Rate limiting** : Gestion robuste des limites API Twitter (1000 req/heure gratuit)
- **Qualité frontend** : Next.js 16 responsive avec Lighthouse score > 90
- **Fiabilité** : Scraping Twitter stable sur 24h sans interruption
- **Transparence** : Confidence Meter précis à ±5% du taux de réussite réel
**Scale & Complexity:**
- **Primary domain** : Full-stack web application (Next.js 16 frontend + FastAPI backend)
- **Complexity level** : High (classification PRD)
- **Estimated architectural components** : ~11 composants majeurs
- Service de scraping multi-sources
- Service d'analyse de sentiment
- Service de calcul d'énergie
- API backend (FastAPI)
- API frontend (Next.js API routes)
- Dashboard frontend (Next.js + D3.js)
- Système de queue (RabbitMQ)
- Base de données (SQLite Phase 1)
- Service de notifications
- Système d'authentification/autorisation
- Service de backtesting
### Technical Constraints & Dependencies
**Contraintes budgétaires Phase 1 :**
- Budget minimal : 10-20€/mois
- SQLite (gratuit) suffisant pour Phase 1
- API Twitter gratuite (1000 req/heure)
- Pas d'app mobile complexe (web responsive suffisant)
**Stack technique imposé :**
- Frontend : Next.js 16 + Tailwind 4 + shadcn/ui
- Backend primaire : Python FastAPI (analytics, ML, sentiment analysis)
- Backend secondaire : Node.js (Next.js API routes pour API légère, authentification)
- Base de données : SQLite (Phase 1) → migration future prévue
- Queue : RabbitMQ pour traitement asynchrone
**Dépendances externes critiques :**
- Twitter API (rate limit : 1000 req/heure)
- Reddit API (généreuse, pas de rate limiting strict)
- RSS Feeds (diverses sources)
- Mailchimp (gratuit pour capture emails Phase 1)
**Contraintes de domaine :**
- Focus unique sur Football pour Phase 1
- Domaine gambling/betting (implications compliance potentielles)
- Projet greenfield (nouveau développement)
### Cross-Cutting Concerns Identified
**Gestion des API externes :**
- Rate limiting et priorisation dynamique (matchs VIP vs autres)
- Gestion des pannes (modes dégradés : Reddit + RSS uniquement)
- Monitoring et alertes prédictives (> 90% utilisation)
- Optimisation intelligente (scraper tweets avec engagement élevé)
**Traitement asynchrone :**
- Queue RabbitMQ pour découpler scraping et analyse
- Gestion des pics de charge (événements majeurs)
- Traitement batch pour backtesting
**Temps réel :**
- Dashboard avec mises à jour en temps réel
- Notifications push pour changements majeurs
- Visualisations dynamiques (D3.js)
**Multi-tenant :**
- Différenciation gratuit/premium (features, SLA, rate limiting)
- Système d'authentification/autorisation
- Métriques et analytics différenciés
**Compliance & Transparence :**
- Domaine gambling/betting (réglementations potentielles)
- Transparence algorithmique (explication des prédictions)
- Documentation publique des résultats (Medium, Reddit)
## Starter Template Evaluation
### Primary Technology Domain
Full-stack web application basé sur l'analyse du contexte projet et des exigences.
### Starter Options Considered
**Option 1 : create-next-app (officiel Next.js)**
- Starter officiel Next.js 16 avec support App Router, TypeScript, Tailwind CSS, ESLint/Biome
- Turbopack activé par défaut pour un bundling rapide
- Structure modulaire avec `src/` directory
- Intégration shadcn/ui via CLI séparé
**Option 2 : shadcn/ui CLI (canary pour Tailwind v4)**
- Compatible Tailwind v4 + React 19
- Intégration native avec Next.js 16
- Style "new-york" par défaut
- Composants copiés dans le projet (pas de dépendance externe)
### Selected Starter: create-next-app + shadcn/ui
**Rationale for Selection:**
Approche en deux étapes recommandée :
1. `create-next-app` pour établir la base Next.js 16 avec toutes les configurations essentielles
2. `shadcn@canary` pour intégrer l'UI avec Tailwind v4, aligné avec les préférences techniques du PRD
Cette approche offre :
- Base solide et officielle avec Next.js 16
- Flexibilité pour intégrer shadcn/ui avec Tailwind v4
- Alignement avec les contraintes techniques du projet (Next.js 16 + Tailwind 4 + shadcn/ui)
**Initialization Command:**
```bash
# 1. Créer le projet Next.js 16 avec TypeScript, Tailwind, ESLint
npx create-next-app@latest chartbastan --typescript --eslint --tailwind --app --src-dir --turbopack
cd chartbastan
# 2. Initialiser shadcn/ui avec Tailwind v4 (canary pour v4)
npx shadcn@canary init
```
**Architectural Decisions Provided by Starter:**
**Language & Runtime:**
- TypeScript avec configuration stricte activée
- Node.js 20.9+ requis (minimum pour Next.js 16)
- App Router (Next.js 16) par défaut avec Server Components
**Styling Solution:**
- Tailwind CSS v4 configuré via shadcn CLI
- shadcn/ui avec style "new-york" par défaut
- CSS Variables pour theming (dark mode support)
- Configuration via `components.json`
**Build Tooling:**
- Turbopack activé par défaut (bundler rapide de Next.js)
- Optimisations automatiques (Server Components, code splitting par route)
- Alias `@/*` configuré pour imports simplifiés
**Code Organization:**
- Structure `src/` directory pour séparation claire
- App Router avec `/app` directory pour routing
- Composants UI dans `components/ui/` (copiés localement)
- Utilitaires dans `lib/utils.ts` (helper `cn()` pour classnames)
**Development Experience:**
- Hot reloading avec Turbopack pour développement rapide
- ESLint configuré avec règles Next.js
- TypeScript strict mode pour sécurité de types
- Support Server Components par défaut (réduction bundle client)
**Note:** L'initialisation du projet avec cette commande devrait être la première story d'implémentation.
## Core Architectural Decisions
### Decision Priority Analysis
**Critical Decisions (Block Implementation):**
- Architecture des données (ORM, migrations)
- Authentification et autorisation
- Patterns API et communication
- Gestion d'état frontend
- Infrastructure de déploiement
**Important Decisions (Shape Architecture):**
- Stratégie de cache
- Monitoring et logging
- Gestion d'erreurs standardisée
- Rate limiting
**Deferred Decisions (Post-MVP):**
- Migration SQLite → PostgreSQL/MySQL (Phase 2+)
- Optimisations avancées de performance
- Multi-région deployment
- CDN et edge caching
### Data Architecture
**ORM Selection:**
**FastAPI Backend:**
- **Choice:** SQLAlchemy 2.0.45 (latest stable)
- **Rationale:**
- Mature, bien intégré avec FastAPI
- Support async natif pour performance
- Compatible avec Pydantic pour validation
- Migration facile vers PostgreSQL/MySQL en Phase 2
- **Migration Tool:** Alembic pour migrations de schéma
- **Affects:** Service FastAPI (analytics, ML, sentiment analysis)
**Next.js API Routes:**
- **Choice:** Drizzle ORM v0.44.7 (stable) avec `better-sqlite3`
- **Rationale:**
- TypeScript-first, excellent DX
- Léger et performant
- Support SQLite natif avec `better-sqlite3`
- Migrations via Drizzle Kit
- Compatible avec Server Components Next.js
- **Migration Tool:** Drizzle Kit pour migrations
- **Affects:** Next.js API routes (authentification, API légère)
**Data Modeling Approach:**
- **Schema Design:** Modélisation relationnelle classique avec normalisation
- **Validation:**
- FastAPI: Pydantic models pour validation des entrées/sorties
- Next.js: Zod pour validation côté API routes (cohérence TypeScript)
- **Migration Strategy:**
- Migrations versionnées (Alembic + Drizzle Kit)
- Scripts de migration pour Phase 1 → Phase 2 (SQLite → PostgreSQL)
**Caching Strategy:**
- **Phase 1:** Pas de cache distribué (SQLite suffisant)
- **Phase 2+:** Redis pour cache de prédictions et données fréquemment accédées
- **Frontend:** React Query (TanStack Query) pour cache côté client avec invalidation intelligente
### Authentication & Security
**Authentication Method:**
- **Choice:** Better Auth v1.4.4 (compatible Next.js 16)
- **Rationale:**
- Compatible officiellement avec Next.js 16 (contrairement à NextAuth.js v4)
- Support stateless auth (JWT)
- Migration path depuis NextAuth.js documentée
- Support OAuth (Google, Twitter) pour Phase 2
- **Version:** v1.4.4 (production-ready)
- **Affects:** Next.js API routes, système d'authentification
**Authorization Patterns:**
- **Role-Based Access Control (RBAC):** Gratuit vs Premium
- **Permissions:**
- Gratuit: 1-2 prédictions/jour, accès limité
- Premium: Accès illimité, métriques avancées, API prioritaire
- **Implementation:** Middleware Next.js pour protection des routes API
**Security Middleware:**
- **FastAPI:**
- CORS configuré pour domaines autorisés
- Rate limiting via `slowapi` ou middleware custom
- Validation Pydantic pour toutes les entrées
- **Next.js:**
- CSRF protection via middleware
- Secure cookies (HttpOnly, Secure, SameSite)
- Headers de sécurité (CSP, X-Frame-Options, etc.)
**Data Encryption:**
- **At Rest:** SQLite avec chiffrement optionnel (Phase 2+)
- **In Transit:** HTTPS obligatoire (TLS 1.3)
- **Secrets:** Variables d'environnement, jamais en code
- **Passwords:** Hashing avec bcrypt (via Better Auth)
### API & Communication Patterns
**API Design Pattern:**
- **Choice:** RESTful API avec OpenAPI 3.1
- **Rationale:**
- Standard, bien compris
- Documentation automatique avec FastAPI
- Compatible avec génération de clients TypeScript
- **Version:** OpenAPI 3.1 (supporté nativement par FastAPI 0.128.0+)
**API Documentation:**
- **FastAPI:**
- Swagger UI intégré (`/docs`)
- Redoc alternatif (`/redoc`)
- OpenAPI schema exportable (`/openapi.json`)
- Pydantic models pour schémas automatiques
- **Best Practices:**
- Docstrings Markdown pour chaque endpoint
- Tags pour groupement logique
- Exemples dans les schémas
- Documentation des erreurs (400, 401, 404, 500)
- **Production:** Désactiver `/docs` et `/redoc` ou les protéger par authentification
**Error Handling Standards:**
- **Format Standardisé:**
```json
{
"error": {
"code": "ERROR_CODE",
"message": "Human-readable message",
"details": {}
}
}
```
- **HTTP Status Codes:**
- 200: Success
- 400: Bad Request (validation)
- 401: Unauthorized
- 403: Forbidden (premium required)
- 404: Not Found
- 429: Too Many Requests (rate limit)
- 500: Internal Server Error
- **Logging:** Tous les erreurs 4xx/5xx loggés avec contexte
**Rate Limiting Strategy:**
- **FastAPI:**
- `slowapi` ou middleware custom
- Limites différenciées: Gratuit (10 req/min), Premium (100 req/min)
- Headers `X-RateLimit-*` pour transparence
- **Next.js API Routes:**
- Rate limiting par utilisateur (Better Auth)
- Protection contre abuse
- **External APIs:**
- Gestion proactive des limites Twitter (1000 req/heure)
- Priorisation dynamique (matchs VIP)
- Modes dégradés (Reddit + RSS si Twitter down)
**Communication Between Services:**
- **FastAPI ↔ Next.js:**
- HTTP REST pour communication synchrone
- RabbitMQ pour communication asynchrone (scraping, analyse)
- **Message Queue:** RabbitMQ pour découplage scraping/analyse
- **Service Discovery:** URLs configurées via variables d'environnement (Phase 1)
### Frontend Architecture
**State Management:**
- **Choice:** Zustand v5.0.9 + React Query (TanStack Query)
- **Rationale:**
- Zustand: Léger, pas de provider, SSR-safe avec `unstable_ssrSafe`
- React Query: Cache intelligent, synchronisation serveur, invalidation automatique
- Complémentaire: Zustand pour état UI local, React Query pour données serveur
- **Version:** Zustand v5.0.9 (latest stable)
- **Affects:** Composants React, gestion d'état global
**Component Architecture:**
- **Pattern:** Feature-based organization avec co-location
- **Structure:**
```
src/
app/ # Routes (App Router)
components/
ui/ # shadcn/ui components
features/ # Feature-specific components
predictions/
dashboard/
lib/ # Utilities, hooks
stores/ # Zustand stores
```
- **Server Components:** Par défaut, `use client` uniquement si nécessaire
**Routing Strategy:**
- **Choice:** Next.js App Router (déjà décidé par starter)
- **File-based routing** avec layouts et loading states
- **Protected Routes:** Middleware pour authentification
**Performance Optimization:**
- **Code Splitting:** Automatique par route (App Router)
- **Image Optimization:** Next.js Image component
- **Bundle Analysis:** `@next/bundle-analyzer` pour monitoring
- **Lazy Loading:** Dynamic imports pour composants lourds (D3.js)
- **Server Components:** Maximiser pour réduire bundle client
### Infrastructure & Deployment
**Hosting Strategy:**
- **Frontend (Next.js):**
- **Phase 1:** Vercel (gratuit, optimisé Next.js, déploiement automatique)
- **Rationale:** Zero-config, excellent DX, CDN intégré
- **Backend (FastAPI):**
- **Phase 1:** Railway ou Render (budget 10-20€/mois)
- **Rationale:** Support Python, déploiement simple, scaling facile
- **Database:**
- **Phase 1:** SQLite (fichier local, backup manuel)
- **Phase 2+:** PostgreSQL sur Railway/Render ou Supabase
**CI/CD Pipeline:**
- **Choice:** GitHub Actions
- **Workflow:**
- Lint + Type check sur PR
- Tests unitaires (si implémentés Phase 2+)
- Build et déploiement automatique sur merge main
- **Environments:**
- `development`: Local
- `staging`: Vercel Preview (auto)
- `production`: Vercel Production + Railway/Render
**Environment Configuration:**
- **Management:** `.env.local` (dev), `.env.production` (prod)
- **Secrets:** Variables d'environnement dans Vercel/Railway
- **Validation:** Zod pour validation des env vars au runtime
**Monitoring and Logging:**
- **Phase 1:**
- **Logging:** Console logs structurés (JSON)
- **Errors:** Sentry (plan gratuit) pour tracking erreurs
- **Uptime:** UptimeRobot (gratuit) pour monitoring basique
- **Phase 2+:**
- **APM:** Datadog ou New Relic (si budget)
- **Analytics:** Vercel Analytics intégré
- **Performance:** Web Vitals monitoring
**Scaling Strategy:**
- **Phase 1:** Vertical scaling (upgrade instance)
- **Phase 2+:**
- Horizontal scaling (multiple instances FastAPI)
- Load balancer (Railway/Render)
- Database: Migration PostgreSQL avec connection pooling
- CDN: Vercel Edge Network (automatique)
### Decision Impact Analysis
**Implementation Sequence:**
1. **Foundation:**
- Initialiser Next.js 16 avec create-next-app
- Configurer shadcn/ui avec Tailwind v4
- Setup FastAPI avec SQLAlchemy
- Configurer SQLite (FastAPI + Next.js)
2. **Core Services:**
- Implémenter Better Auth (authentification)
- Setup Drizzle ORM (Next.js)
- Setup SQLAlchemy + Alembic (FastAPI)
- Configurer RabbitMQ pour queue
3. **API Layer:**
- Définir schémas OpenAPI (FastAPI)
- Implémenter endpoints REST
- Setup rate limiting
- Documentation API
4. **Frontend:**
- Configurer Zustand + React Query
- Implémenter composants UI (shadcn)
- Setup routing et protection
- Intégration D3.js pour visualisations
5. **Infrastructure:**
- Setup Vercel (frontend)
- Setup Railway/Render (backend)
- Configurer CI/CD (GitHub Actions)
- Setup monitoring (Sentry, UptimeRobot)
**Cross-Component Dependencies:**
- **Authentication → API:** Better Auth protège toutes les routes API
- **Database → Services:** SQLAlchemy (FastAPI) et Drizzle (Next.js) partagent le même SQLite (Phase 1)
- **Queue → Scraping:** RabbitMQ découple scraping Twitter/Reddit de l'analyse
- **Frontend → Backend:** React Query synchronise état avec API FastAPI
- **Monitoring → All:** Sentry track erreurs dans tous les services
## Implementation Patterns & Consistency Rules
### Pattern Categories Defined
**Critical Conflict Points Identified:**
15+ zones où les agents AI pourraient faire des choix différents, nécessitant des patterns stricts pour garantir la cohérence.
### Naming Patterns
**Database Naming Conventions:**
**FastAPI (SQLAlchemy):**
- **Tables:** `snake_case`, pluriel : `users`, `predictions`, `matches`, `energy_scores`
- **Columns:** `snake_case` : `user_id`, `created_at`, `is_premium`, `energy_score`
- **Foreign Keys:** `{table}_id` : `user_id`, `match_id`, `prediction_id`
- **Indexes:** `idx_{table}_{column}` : `idx_users_email`, `idx_predictions_match_id`
- **Constraints:** `{table}_{column}_{constraint}` : `users_email_unique`, `predictions_user_id_fk`
**Next.js (Drizzle ORM):**
- **Tables:** Même convention que SQLAlchemy (`snake_case`, pluriel)
- **Schema Definition:** Utiliser `snake_case` dans les schémas Drizzle pour correspondre à SQLite
- **TypeScript Types:** Générer types TypeScript avec `snake_case` → `camelCase` via Drizzle
**Rationale:** Cohérence entre les deux ORMs partageant la même base SQLite. SQLAlchemy utilise traditionnellement `snake_case`, donc Drizzle doit suivre.
**API Naming Conventions:**
**REST Endpoints:**
- **Base URLs:** Pluriel, `snake_case` : `/api/v1/users`, `/api/v1/predictions`, `/api/v1/matches`
- **Route Parameters:** `{id}` format : `/api/v1/users/{id}`, `/api/v1/matches/{match_id}`
- **Query Parameters:** `snake_case` : `?user_id=123&limit=10&offset=0`
- **Nested Resources:** `/api/v1/users/{user_id}/predictions`
- **Actions:** `/api/v1/predictions/{id}/validate`, `/api/v1/matches/{id}/analyze`
**Headers:**
- **Custom Headers:** `X-` prefix : `X-API-Key`, `X-User-Id`, `X-RateLimit-Remaining`
- **Standard Headers:** Respecter conventions HTTP standard
**Code Naming Conventions:**
**Python (FastAPI):**
- **Files:** `snake_case.py` : `user_service.py`, `prediction_service.py`, `energy_calculator.py`
- **Classes:** `PascalCase` : `UserService`, `PredictionService`, `EnergyCalculator`
- **Functions:** `snake_case` : `get_user_by_id()`, `calculate_energy_score()`, `create_prediction()`
- **Variables:** `snake_case` : `user_id`, `energy_score`, `is_premium`
- **Constants:** `UPPER_SNAKE_CASE` : `MAX_PREDICTIONS_FREE`, `API_RATE_LIMIT`
**TypeScript/JavaScript (Next.js):**
- **Files:** `kebab-case.tsx` ou `PascalCase.tsx` pour composants : `user-card.tsx`, `UserCard.tsx`, `prediction-service.ts`
- **Components:** `PascalCase` : `UserCard`, `PredictionDashboard`, `EnergyMeter`
- **Functions:** `camelCase` : `getUserById()`, `calculateEnergyScore()`, `createPrediction()`
- **Variables:** `camelCase` : `userId`, `energyScore`, `isPremium`
- **Constants:** `UPPER_SNAKE_CASE` : `MAX_PREDICTIONS_FREE`, `API_RATE_LIMIT`
- **Types/Interfaces:** `PascalCase` : `User`, `Prediction`, `EnergyScore`
**Hooks:** `camelCase` avec préfixe `use` : `useUser()`, `usePredictions()`, `useEnergyScore()`
### Structure Patterns
**Project Organization:**
**FastAPI Backend Structure:**
```
backend/
├── app/
│ ├── __init__.py
│ ├── main.py # FastAPI app entry
│ ├── config.py # Configuration
│ ├── database.py # SQLAlchemy setup
│ ├── models/ # SQLAlchemy models
│ │ ├── __init__.py
│ │ ├── user.py
│ │ ├── prediction.py
│ │ └── match.py
│ ├── schemas/ # Pydantic schemas
│ │ ├── __init__.py
│ │ ├── user.py
│ │ └── prediction.py
│ ├── api/ # API routes
│ │ ├── __init__.py
│ │ ├── v1/
│ │ │ ├── __init__.py
│ │ │ ├── users.py
│ │ │ └── predictions.py
│ ├── services/ # Business logic
│ │ ├── __init__.py
│ │ ├── user_service.py
│ │ ├── prediction_service.py
│ │ └── energy_calculator.py
│ ├── repositories/ # Data access layer
│ │ ├── __init__.py
│ │ ├── user_repository.py
│ │ └── prediction_repository.py
│ └── utils/ # Utilities
│ ├── __init__.py
│ ├── logger.py
│ └── validators.py
├── alembic/ # Migrations
│ ├── versions/
│ └── env.py
├── tests/ # Tests (co-located or separate)
│ ├── __init__.py
│ ├── test_users.py
│ └── test_predictions.py
├── requirements.txt
└── .env
```
**Next.js Frontend Structure:**
```
frontend/
├── src/
│ ├── app/ # App Router routes
│ │ ├── layout.tsx
│ │ ├── page.tsx
│ │ ├── (auth)/
│ │ │ ├── login/
│ │ │ └── register/
│ │ ├── dashboard/
│ │ │ └── page.tsx
│ │ └── api/ # Next.js API routes
│ │ └── v1/
│ │ ├── users/
│ │ └── predictions/
│ ├── components/
│ │ ├── ui/ # shadcn/ui components
│ │ │ ├── button.tsx
│ │ │ └── card.tsx
│ │ └── features/ # Feature components
│ │ ├── predictions/
│ │ │ ├── PredictionCard.tsx
│ │ │ └── PredictionList.tsx
│ │ └── dashboard/
│ │ └── Dashboard.tsx
│ ├── lib/
│ │ ├── utils.ts # Utilities (cn helper, etc.)
│ │ ├── api.ts # API client
│ │ └── validations.ts # Zod schemas
│ ├── stores/ # Zustand stores
│ │ ├── user-store.ts
│ │ └── prediction-store.ts
│ ├── hooks/ # Custom React hooks
│ │ ├── use-user.ts
│ │ └── use-predictions.ts
│ └── types/ # TypeScript types
│ ├── user.ts
│ └── prediction.ts
├── public/ # Static assets
├── drizzle/ # Drizzle migrations
│ └── migrations/
├── tests/ # Tests (co-located or separate)
│ └── components/
└── .env.local
```
**File Structure Patterns:**
- **Tests:** Co-locés avec les fichiers (`*.test.ts`, `test_*.py`) OU dans dossier `tests/` séparé
- **Config Files:** `.env`, `.env.local`, `config.py`, `next.config.js` à la racine
- **Static Assets:** `public/` pour Next.js, `static/` pour FastAPI
- **Documentation:** `docs/` à la racine du projet
### Format Patterns
**API Response Formats:**
**Success Response:**
```json
{
"data": {
"id": 1,
"user_id": 123,
"energy_score": 0.75,
"created_at": "2026-01-15T10:30:00Z"
},
"meta": {
"timestamp": "2026-01-15T10:30:00Z",
"version": "v1"
}
}
```
**Error Response:**
```json
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid user_id provided",
"details": {
"field": "user_id",
"reason": "Must be a positive integer"
}
},
"meta": {
"timestamp": "2026-01-15T10:30:00Z",
"request_id": "req_abc123"
}
}
```
**List Response:**
```json
{
"data": [
{"id": 1, "user_id": 123},
{"id": 2, "user_id": 456}
],
"meta": {
"total": 2,
"page": 1,
"per_page": 10,
"timestamp": "2026-01-15T10:30:00Z"
}
}
```
**Data Exchange Formats:**
- **JSON Field Naming:** `snake_case` dans les réponses API (cohérence avec database)
- **Date Format:** ISO 8601 strings : `"2026-01-15T10:30:00Z"` (UTC)
- **Boolean:** `true`/`false` (pas de 1/0)
- **Null:** `null` (pas de `undefined` en JSON)
- **Arrays:** Toujours des arrays, jamais d'objets pour listes
**Type Conversions:**
- **Frontend:** Convertir `snake_case` API → `camelCase` TypeScript via transformation layer
- **Backend:** Accepter `camelCase` dans les requêtes, convertir en `snake_case` pour DB
### Communication Patterns
**Event System Patterns (RabbitMQ):**
**Event Naming:**
- Format: `{entity}.{action}` : `user.created`, `prediction.updated`, `match.analyzed`
- Lowercase avec points comme séparateurs
- Actions: `created`, `updated`, `deleted`, `analyzed`, `scraped`
**Event Payload Structure:**
```json
{
"event": "prediction.created",
"version": "1.0",
"timestamp": "2026-01-15T10:30:00Z",
"data": {
"prediction_id": 123,
"user_id": 456,
"match_id": 789
},
"metadata": {
"source": "api",
"user_id": 456
}
}
```
**State Management Patterns:**
**Zustand Store Structure:**
```typescript
interface UserState {
user: User | null;
isLoading: boolean;
error: string | null;
setUser: (user: User) => void;
clearUser: () => void;
}
const useUserStore = create<UserState>((set) => ({
user: null,
isLoading: false,
error: null,
setUser: (user) => set({ user, error: null }),
clearUser: () => set({ user: null, error: null }),
}));
```
**React Query Patterns:**
- **Query Keys:** Array format : `['users', userId]`, `['predictions', { matchId }]`
- **Mutations:** Utiliser `useMutation` avec `onSuccess`/`onError`
- **Cache Invalidation:** `queryClient.invalidateQueries(['predictions'])`
**State Update Rules:**
- **Immutable Updates:** Toujours créer de nouveaux objets/arrays
- **Action Naming:** `set{Entity}`, `update{Entity}`, `clear{Entity}`, `fetch{Entity}`
### Process Patterns
**Error Handling Patterns:**
**FastAPI:**
```python
from fastapi import HTTPException
# Standard error raising
raise HTTPException(
status_code=400,
detail={
"code": "VALIDATION_ERROR",
"message": "Invalid input",
"details": {"field": "user_id"}
}
)
```
**Next.js:**
```typescript
// API Routes
if (!user) {
return NextResponse.json(
{
error: {
code: "NOT_FOUND",
message: "User not found",
},
},
{ status: 404 }
);
}
// Components
try {
const data = await fetchUser();
} catch (error) {
// Log to Sentry
console.error("Failed to fetch user:", error);
// Show user-friendly message
setError("Unable to load user. Please try again.");
}
```
**Error Boundary:**
- Utiliser React Error Boundaries pour erreurs de rendu
- Logger toutes les erreurs à Sentry avec contexte
**Loading State Patterns:**
**Naming:**
- `isLoading` pour état de chargement principal
- `isFetching` pour refetch en arrière-plan (React Query)
- `isSubmitting` pour formulaires
**Implementation:**
```typescript
// Zustand
const useStore = create((set) => ({
isLoading: false,
setLoading: (loading) => set({ isLoading: loading }),
}));
// React Query
const { data, isLoading, isFetching } = useQuery(['users'], fetchUsers);
```
**Loading UI:**
- Skeleton loaders pour contenu principal
- Spinners pour actions rapides
- Désactiver les boutons pendant `isSubmitting`
### Enforcement Guidelines
**All AI Agents MUST:**
1. **Respecter les conventions de nommage:**
- Python: `snake_case` pour fichiers, fonctions, variables
- TypeScript: `camelCase` pour fonctions/variables, `PascalCase` pour composants/types
- Database: `snake_case` pour tables/colonnes (cohérence entre SQLAlchemy et Drizzle)
2. **Suivre la structure de projet définie:**
- Ne pas créer de fichiers en dehors des dossiers définis
- Co-locater les tests avec les fichiers OU utiliser `tests/`
- Respecter la séparation `services/`, `repositories/`, `api/`
3. **Utiliser les formats API standardisés:**
- Toujours wrapper les réponses dans `{data, meta}` ou `{error, meta}`
- Utiliser les codes d'erreur définis
- Dates en ISO 8601 UTC
4. **Implémenter la gestion d'erreurs cohérente:**
- Logger toutes les erreurs avec contexte
- Retourner des messages utilisateur-friendly
- Utiliser les patterns d'erreur définis
5. **Respecter les patterns de state management:**
- Zustand pour état UI local
- React Query pour données serveur
- Immutable updates uniquement
**Pattern Enforcement:**
- **Code Review:** Vérifier la conformité aux patterns dans chaque PR
- **Linting:** Configurer ESLint (Next.js) et flake8/black (Python) avec règles strictes
- **Type Safety:** TypeScript strict mode + Pydantic pour validation
- **Documentation:** Documenter toute exception aux patterns avec justification
**Process for Updating Patterns:**
1. Identifier le besoin de changement
2. Discuter l'impact sur l'existant
3. Mettre à jour ce document d'architecture
4. Communiquer le changement à l'équipe
5. Migrer le code existant si nécessaire
### Pattern Examples
**Good Examples:**
**Database Model (SQLAlchemy):**
```python
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
email = Column(String, unique=True, index=True, nullable=False)
is_premium = Column(Boolean, default=False)
created_at = Column(DateTime, default=datetime.utcnow)
```
**API Endpoint (FastAPI):**
```python
@router.get("/api/v1/users/{user_id}", response_model=UserResponse)
async def get_user(user_id: int):
user = await user_service.get_by_id(user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")
return {"data": user, "meta": {"timestamp": datetime.utcnow().isoformat()}}
```
**React Component:**
```typescript
export function UserCard({ userId }: { userId: number }) {
const { data: user, isLoading, error } = useQuery(
['users', userId],
() => fetchUser(userId)
);
if (isLoading) return <UserCardSkeleton />;
if (error) return <ErrorMessage error={error} />;
return <Card>{user.name}</Card>;
}
```
**Anti-Patterns:**
❌ **Mixing Naming Conventions:**
```python
# BAD
class userService: # Should be UserService
def getUserData(self): # Should be get_user_data
userId = 123 # Should be user_id
```
❌ **Inconsistent API Responses:**
```json
// BAD - Direct response
{"id": 1, "name": "John"}
// GOOD - Wrapped response
{"data": {"id": 1, "name": "John"}, "meta": {...}}
```
❌ **Mutable State Updates:**
```typescript
// BAD
state.users.push(newUser);
// GOOD
setUsers([...users, newUser]);
```
❌ **Inconsistent Error Handling:**
```python
# BAD - Different error formats
raise ValueError("Error")
return {"error": "Error"}
raise HTTPException(status_code=500)
# GOOD - Consistent format
raise HTTPException(
status_code=400,
detail={"code": "ERROR_CODE", "message": "Error"}
)
```