213a67e612
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
8.5 KiB
8.5 KiB
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 :
- Filtrées par un agent IA selon le droit international des droits humains
- Synthétisées automatiquement en un résumé clair par thème
- 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 viaFILTER_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 viaSYNTHESIS_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 :
MISTRAL_API_KEY→https://api.mistral.ai/v1OPENAI_API_KEY→ API OpenAI standardAI_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 supportdeploy/voix-du-peuple-api.service— Unité systemd pour Gunicornartifacts/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