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:
+217
@@ -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 10–1000 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
|
||||
```
|
||||
Reference in New Issue
Block a user