Create documentation for project architecture, deployment, and usage

Add DAT, DEX, GITEA_TUTO, and WIKI markdown files to the docs directory, and update agent_assets_metadata.toml to include these new documents.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 923ae0e3-a363-4db8-b04a-e8baca2a1330
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 4bb1a658-d577-451e-965c-fa15e2c21ca9
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8af7d2ec-2cc3-4ece-8af3-9f071488d072/923ae0e3-a363-4db8-b04a-e8baca2a1330/RusmVRz
Replit-Helium-Checkpoint-Created: true
This commit is contained in:
pironantoine
2026-04-04 06:56:49 +00:00
parent e2a0b6401d
commit 213a67e612
5 changed files with 727 additions and 0 deletions
+217
View File
@@ -0,0 +1,217 @@
# Document d'Architecture Technique — La Voix du Peuple
**Version** : 1.0
**Date** : Avril 2026
**Statut** : En production (Replit), prêt pour auto-hébergement
---
## 1. Présentation générale
**La Voix du Peuple** est une plateforme civique permettant à des citoyens de soumettre des propositions politiques. Ces contributions sont :
1. Filtrées par un agent IA selon le droit international des droits humains
2. Synthétisées automatiquement en un résumé clair par thème
3. Affichées en temps réel à destination d'élus ou de décideurs
---
## 2. Architecture globale
```
┌─────────────────────────────────────────────────────────┐
│ Navigateur client │
│ React + Vite (TypeScript) │
└────────────────────────┬────────────────────────────────┘
│ HTTP/REST (JSON)
┌─────────────────────────────────────────────────────────┐
│ Reverse Proxy — Nginx / HAProxy │
│ (rate limiting, TLS, X-Forwarded-For) │
└────────────────────────┬────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ Backend API — Flask (Python) │
│ Port 8080 │
│ │
│ ┌──────────────┐ ┌─────────────┐ ┌──────────────┐ │
│ │ app.py │ │ ai_agent.py │ │ database.py │ │
│ │ (routes) │──▶│ (filtre + │ │ (PostgreSQL) │ │
│ │ │ │ synthèse) │ │ │ │
│ └──────────────┘ └──────┬──────┘ └──────┬───────┘ │
└─────────────────────────────┼───────────────┼──────────┘
│ │
▼ ▼
┌──────────────────┐ ┌──────────────┐
│ Mistral AI API │ │ PostgreSQL │
│ api.mistral.ai │ │ (base DB) │
└──────────────────┘ └──────────────┘
```
---
## 3. Composants
### 3.1 Frontend — React + Vite
| Élément | Détail |
|---------|--------|
| Framework | React 18 + TypeScript |
| Build | Vite 7 |
| Styles | Tailwind CSS + shadcn/ui |
| Routing | Wouter |
| État serveur | TanStack Query |
| Client API | `@workspace/api-client-react` (généré depuis OpenAPI) |
| Police | Bahnschrift (titres), Inter (corps) |
**Pages** :
- `/` — Page principale (formulaire + fil + synthèse)
- `/about` — À propos et fondements juridiques
- `/transparence` — Fonctionnement technique et données collectées
**Variables d'environnement** :
- `BASE_URL` — Préfixe de chemin (injecté par Vite)
- `PORT` — Port du serveur de développement (assigné par Replit)
---
### 3.2 Backend — Flask
| Élément | Détail |
|---------|--------|
| Framework | Flask 3 (Python 3.11+) |
| Serveur WSGI | Gunicorn (production) |
| CORS | flask-cors |
| Rate limiting | flask-limiter (5 req/min par IP sur POST /api/ideas) |
| ORM | psycopg2-binary (requêtes SQL directes) |
**Endpoints** :
| Méthode | Route | Description |
|---------|-------|-------------|
| `GET` | `/api/ideas` | Liste des contributions acceptées |
| `POST` | `/api/ideas` | Soumet une nouvelle contribution |
| `GET` | `/api/ideas/stats` | Statistiques (acceptées/refusées) |
| `GET` | `/api/synthesis` | Texte de synthèse actuel |
| `GET` | `/health` | Health check |
**Réponses** : JSON camelCase, statuts HTTP standard.
---
### 3.3 Agent IA
Deux appels distincts à l'API Mistral (compatible OpenAI SDK) :
#### Filtre de modération
- **Modèle** : `mistral-small-latest` (configurable via `FILTER_MODEL`)
- **Entrée** : Texte brut de la contribution
- **Sortie** : JSON `{"accepted": bool, "reason"?: string, "legal_basis"?: string}`
- **Référentiel** : DUDH, PIDCP, CEDH, Charte UE, CERD, Statut de Rome
- **Max tokens** : 300
#### Synthèse collective
- **Modèle** : `mistral-large-latest` (configurable via `SYNTHESIS_MODEL`)
- **Entrée** : Liste de toutes les contributions acceptées
- **Sortie** : Texte libre structuré par thèmes, destiné aux élus
- **Max tokens** : 1200
- **Déclencheur** : À chaque nouvelle contribution acceptée (asynchrone)
**Priorité de configuration du client IA** :
1. `MISTRAL_API_KEY``https://api.mistral.ai/v1`
2. `OPENAI_API_KEY` → API OpenAI standard
3. `AI_INTEGRATIONS_OPENAI_*` → Proxy Replit (intégration native)
---
### 3.4 Base de données — PostgreSQL
**Table `ideas`** :
| Colonne | Type | Description |
|---------|------|-------------|
| `id` | SERIAL PK | Identifiant |
| `content` | TEXT | Texte de la contribution |
| `author` | VARCHAR(100) | Pseudonyme (nullable) |
| `accepted` | BOOLEAN | Résultat du filtre |
| `rejection_reason` | TEXT | Motif de refus (nullable) |
| `legal_basis` | TEXT | Base légale du refus (nullable) |
| `created_at` | TIMESTAMPTZ | Horodatage de soumission |
**Table `synthesis`** :
| Colonne | Type | Description |
|---------|------|-------------|
| `id` | SERIAL PK | (toujours 1 — ligne unique) |
| `text` | TEXT | Dernier texte de synthèse |
| `idea_count` | INTEGER | Nombre de contributions intégrées |
| `updated_at` | TIMESTAMPTZ | Dernière mise à jour |
---
## 4. Variables d'environnement
| Variable | Obligatoire | Description |
|----------|-------------|-------------|
| `DATABASE_URL` | ✅ | URL PostgreSQL complète |
| `MISTRAL_API_KEY` | ✅ (ou OpenAI) | Clé API Mistral |
| `SESSION_SECRET` | ✅ | Secret Flask (sessions) |
| `FILTER_MODEL` | — | Modèle de filtrage (défaut : `mistral-small-latest`) |
| `SYNTHESIS_MODEL` | — | Modèle de synthèse (défaut : `mistral-large-latest`) |
| `OPENAI_API_KEY` | — | Alternative à Mistral |
| `MISTRAL_BASE_URL` | — | URL custom Mistral (défaut : `https://api.mistral.ai/v1`) |
---
## 5. Infrastructure de déploiement (auto-hébergement)
```
Internet ──▶ HAProxy (TLS, load balancing)
└──▶ Nginx (reverse proxy, rate limiting IP)
└──▶ Gunicorn × N workers (Flask)
└──▶ Fichiers statiques Vite (build)
PostgreSQL (local ou RDS)
```
**Fichiers fournis** :
- `deploy/nginx.conf` — Configuration Nginx avec HAProxy support
- `deploy/voix-du-peuple-api.service` — Unité systemd pour Gunicorn
- `artifacts/voix-du-peuple/vite.config.selfhost.ts` — Build sans plugins Replit
---
## 6. Sécurité
| Mesure | Implémentation |
|--------|----------------|
| Rate limiting | 5 POST/min par IP (flask-limiter) |
| Sanitisation | bleach sur le contenu avant stockage |
| CORS | Origines configurées explicitement |
| SQL injection | Requêtes paramétrées (psycopg2) |
| Secrets | Variables d'environnement uniquement, jamais dans le code |
| Données personnelles | Aucune IP stockée, pseudonyme facultatif |
---
## 7. Flux de traitement d'une contribution
```
POST /api/ideas
├─ Validation (longueur 101000 chars)
├─ Sanitisation (bleach)
├─ INSERT en base (statut pending)
├─ Appel Mistral (filtre)
│ ├─ accepted=true → UPDATE idea, déclenche synthèse async
│ └─ accepted=false → UPDATE idea avec motif
├─ [async] Appel Mistral (synthèse) sur toutes contributions acceptées
│ └─ UPSERT table synthesis
└─ Réponse JSON 201
```