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:
@@ -6,3 +6,27 @@ id = "x31gBYdQKnMGZriV7IJ1v"
|
|||||||
uri = "file://DEPLOIEMENT.md"
|
uri = "file://DEPLOIEMENT.md"
|
||||||
type = "text"
|
type = "text"
|
||||||
title = "Guide d'auto-hébergement RockyLinux"
|
title = "Guide d'auto-hébergement RockyLinux"
|
||||||
|
|
||||||
|
[[outputs]]
|
||||||
|
id = "QwHkF1SFkRpZFuyRMNI9h"
|
||||||
|
uri = "file://docs/GITEA_TUTO.md"
|
||||||
|
type = "text"
|
||||||
|
title = "Tutoriel — Récupérer le projet sur Gitea"
|
||||||
|
|
||||||
|
[[outputs]]
|
||||||
|
id = "wdBpdE1lSme8lM2xYd3oJ"
|
||||||
|
uri = "file://docs/DAT.md"
|
||||||
|
type = "text"
|
||||||
|
title = "DAT — Document d'Architecture Technique"
|
||||||
|
|
||||||
|
[[outputs]]
|
||||||
|
id = "NXFvDFOIzX862xNq15Mak"
|
||||||
|
uri = "file://docs/DEX.md"
|
||||||
|
type = "text"
|
||||||
|
title = "DEX — Document d'Exploitation"
|
||||||
|
|
||||||
|
[[outputs]]
|
||||||
|
id = "kJNXgVnYp_LQmPcWr6Osb"
|
||||||
|
uri = "file://docs/WIKI.md"
|
||||||
|
type = "text"
|
||||||
|
title = "Wiki — La Voix du Peuple"
|
||||||
|
|||||||
+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
|
||||||
|
```
|
||||||
+244
@@ -0,0 +1,244 @@
|
|||||||
|
# Document d'Exploitation — La Voix du Peuple
|
||||||
|
|
||||||
|
**Version** : 1.0
|
||||||
|
**Date** : Avril 2026
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Démarrage et arrêt des services
|
||||||
|
|
||||||
|
### Sur Replit
|
||||||
|
|
||||||
|
Les services sont gérés par les **Workflows** Replit. Ils démarrent automatiquement.
|
||||||
|
|
||||||
|
| Workflow | Commande | Port |
|
||||||
|
|----------|----------|------|
|
||||||
|
| API Server | `PORT=8080 sh artifacts/flask-api/start.sh` | 8080 |
|
||||||
|
| Frontend | `pnpm --filter @workspace/voix-du-peuple run dev` | auto |
|
||||||
|
|
||||||
|
Pour redémarrer manuellement : onglet **Workflows** → bouton restart.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### En auto-hébergement (RockyLinux / Debian)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Démarrer le backend
|
||||||
|
systemctl start voix-du-peuple-api
|
||||||
|
|
||||||
|
# Arrêter le backend
|
||||||
|
systemctl stop voix-du-peuple-api
|
||||||
|
|
||||||
|
# Redémarrer après mise à jour
|
||||||
|
systemctl restart voix-du-peuple-api
|
||||||
|
|
||||||
|
# Voir le statut
|
||||||
|
systemctl status voix-du-peuple-api
|
||||||
|
|
||||||
|
# Activer au démarrage
|
||||||
|
systemctl enable voix-du-peuple-api
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Redémarrer Nginx après modification de la config
|
||||||
|
nginx -t && systemctl reload nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Variables d'environnement
|
||||||
|
|
||||||
|
Fichier de référence : `.env.example` à la racine du projet.
|
||||||
|
|
||||||
|
En production, créer `/etc/voix-du-peuple/.env` :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Base de données
|
||||||
|
DATABASE_URL=postgresql://user:password@localhost:5432/voix_du_peuple
|
||||||
|
|
||||||
|
# IA — choisir l'un des deux
|
||||||
|
MISTRAL_API_KEY=sk-...
|
||||||
|
# OPENAI_API_KEY=sk-...
|
||||||
|
|
||||||
|
# Modèles (optionnel — valeurs par défaut ci-dessous)
|
||||||
|
FILTER_MODEL=mistral-small-latest
|
||||||
|
SYNTHESIS_MODEL=mistral-large-latest
|
||||||
|
|
||||||
|
# Sécurité Flask
|
||||||
|
SESSION_SECRET=une-longue-chaine-aleatoire-securisee
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Important** : Après toute modification du fichier `.env`, redémarrer le service API.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Mise à jour du code
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Depuis votre serveur, après un git pull
|
||||||
|
cd /opt/voix-du-peuple
|
||||||
|
|
||||||
|
git pull gitea main
|
||||||
|
|
||||||
|
# Mettre à jour les dépendances Python si requirements.txt a changé
|
||||||
|
pip install -r artifacts/flask-api/requirements.txt
|
||||||
|
|
||||||
|
# Reconstruire le frontend si le code frontend a changé
|
||||||
|
pnpm install
|
||||||
|
pnpm --filter @workspace/voix-du-peuple run build --config vite.config.selfhost.ts
|
||||||
|
|
||||||
|
# Redémarrer l'API
|
||||||
|
systemctl restart voix-du-peuple-api
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Consultation des logs
|
||||||
|
|
||||||
|
### Sur Replit
|
||||||
|
|
||||||
|
Voir les logs dans l'onglet **Workflows** → cliquer sur le workflow concerné.
|
||||||
|
|
||||||
|
### En auto-hébergement
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Logs du service systemd (temps réel)
|
||||||
|
journalctl -u voix-du-peuple-api -f
|
||||||
|
|
||||||
|
# 100 dernières lignes
|
||||||
|
journalctl -u voix-du-peuple-api -n 100
|
||||||
|
|
||||||
|
# Logs d'une journée spécifique
|
||||||
|
journalctl -u voix-du-peuple-api --since "2026-04-01" --until "2026-04-02"
|
||||||
|
|
||||||
|
# Logs Nginx
|
||||||
|
tail -f /var/log/nginx/access.log
|
||||||
|
tail -f /var/log/nginx/error.log
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Base de données
|
||||||
|
|
||||||
|
### Connexion directe
|
||||||
|
|
||||||
|
```bash
|
||||||
|
psql "$DATABASE_URL"
|
||||||
|
# ou
|
||||||
|
psql -U voix_user -d voix_du_peuple -h localhost
|
||||||
|
```
|
||||||
|
|
||||||
|
### Requêtes utiles
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Nombre de contributions par statut
|
||||||
|
SELECT accepted, COUNT(*) FROM ideas GROUP BY accepted;
|
||||||
|
|
||||||
|
-- Dernières contributions
|
||||||
|
SELECT id, author, left(content, 60), accepted, created_at
|
||||||
|
FROM ideas ORDER BY created_at DESC LIMIT 10;
|
||||||
|
|
||||||
|
-- Contributions refusées avec motif
|
||||||
|
SELECT id, left(content, 60), rejection_reason, created_at
|
||||||
|
FROM ideas WHERE accepted = false ORDER BY created_at DESC;
|
||||||
|
|
||||||
|
-- État de la synthèse
|
||||||
|
SELECT idea_count, left(text, 200), updated_at FROM synthesis;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Sauvegarde
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Dump complet
|
||||||
|
pg_dump "$DATABASE_URL" > backup_$(date +%Y%m%d_%H%M).sql
|
||||||
|
|
||||||
|
# Restauration
|
||||||
|
psql "$DATABASE_URL" < backup_20260401_0800.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Vérification du bon fonctionnement
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Health check API
|
||||||
|
curl http://localhost:8080/health
|
||||||
|
|
||||||
|
# Test de soumission
|
||||||
|
curl -X POST http://localhost:8080/api/ideas \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"content": "Test de fonctionnement de la plateforme.", "author": "Admin"}'
|
||||||
|
|
||||||
|
# Lecture de la synthèse
|
||||||
|
curl http://localhost:8080/api/synthesis | python3 -m json.tool
|
||||||
|
|
||||||
|
# Statistiques
|
||||||
|
curl http://localhost:8080/api/ideas/stats
|
||||||
|
```
|
||||||
|
|
||||||
|
Réponse attendue du health check :
|
||||||
|
```json
|
||||||
|
{"status": "ok"}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Changement de modèle IA
|
||||||
|
|
||||||
|
Pour basculer vers un modèle différent sans toucher au code :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Exemple : passer à mistral-medium
|
||||||
|
# Éditer le .env
|
||||||
|
FILTER_MODEL=mistral-medium-latest
|
||||||
|
SYNTHESIS_MODEL=mistral-medium-latest
|
||||||
|
|
||||||
|
# Redémarrer
|
||||||
|
systemctl restart voix-du-peuple-api
|
||||||
|
```
|
||||||
|
|
||||||
|
Modèles Mistral disponibles (avril 2026) :
|
||||||
|
- `mistral-small-latest` — Rapide, économique (filtre)
|
||||||
|
- `mistral-medium-latest` — Équilibré
|
||||||
|
- `mistral-large-latest` — Meilleure qualité (synthèse)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Purge des données
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Supprimer toutes les contributions (irréversible)
|
||||||
|
TRUNCATE ideas;
|
||||||
|
TRUNCATE synthesis;
|
||||||
|
|
||||||
|
-- Supprimer uniquement les contributions refusées
|
||||||
|
DELETE FROM ideas WHERE accepted = false;
|
||||||
|
|
||||||
|
-- Forcer une re-synthèse (supprimer le cache)
|
||||||
|
DELETE FROM synthesis;
|
||||||
|
```
|
||||||
|
|
||||||
|
Après une purge, la synthèse se régénère automatiquement à la prochaine contribution acceptée.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Dépannage courant
|
||||||
|
|
||||||
|
| Symptôme | Cause probable | Solution |
|
||||||
|
|----------|---------------|----------|
|
||||||
|
| `Service temporairement indisponible` sur soumission | Clé Mistral invalide ou quota dépassé | Vérifier `MISTRAL_API_KEY`, consulter console.mistral.ai |
|
||||||
|
| Synthèse non mise à jour | Erreur silencieuse en arrière-plan | Consulter les logs, vérifier la connexion à l'API IA |
|
||||||
|
| Erreur 500 sur toutes les routes | `DATABASE_URL` incorrect ou PostgreSQL arrêté | `systemctl status postgresql`, vérifier le `.env` |
|
||||||
|
| Frontend vide (page blanche) | Build manquant ou `BASE_URL` incorrect | Relancer le build Vite, vérifier la config Nginx |
|
||||||
|
| Rate limit atteint (429) | Trop de soumissions depuis la même IP | Normal — attendre 1 minute |
|
||||||
|
| Modèle IA introuvable (404) | Nom de modèle incorrect dans `FILTER_MODEL` | Corriger le nom, redémarrer le service |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Contacts et ressources
|
||||||
|
|
||||||
|
- Documentation Mistral : https://docs.mistral.ai
|
||||||
|
- PostgreSQL : https://www.postgresql.org/docs/
|
||||||
|
- Flask : https://flask.palletsprojects.com
|
||||||
|
- Guide de déploiement complet : `DEPLOIEMENT.md`
|
||||||
|
- Architecture : `docs/DAT.md`
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
# Récupérer le projet sur Gitea
|
||||||
|
|
||||||
|
Ce tutoriel explique comment pousser le code de **La Voix du Peuple** depuis Replit vers votre instance Gitea, et comment vous synchroniser ensuite à votre rythme.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prérequis
|
||||||
|
|
||||||
|
- Une instance Gitea accessible (ex. `https://git.mondomaine.fr`)
|
||||||
|
- Un compte avec les droits de création de dépôt
|
||||||
|
- Git installé localement (si vous travaillez aussi depuis votre poste)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Étape 1 — Créer le dépôt sur Gitea
|
||||||
|
|
||||||
|
1. Connectez-vous à votre Gitea
|
||||||
|
2. Cliquez sur **+ New Repository**
|
||||||
|
3. Nom suggéré : `voix-du-peuple`
|
||||||
|
4. Laissez-le **vide** (pas de README, pas de .gitignore)
|
||||||
|
5. Notez l'URL du dépôt — elle ressemble à :
|
||||||
|
- SSH : `git@git.mondomaine.fr:vous/voix-du-peuple.git`
|
||||||
|
- HTTPS : `https://git.mondomaine.fr/vous/voix-du-peuple.git`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Étape 2 — Ajouter Gitea comme remote depuis Replit
|
||||||
|
|
||||||
|
Dans le shell Replit (onglet **Shell**) :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Vérifier les remotes actuels
|
||||||
|
git remote -v
|
||||||
|
|
||||||
|
# Ajouter votre Gitea comme remote (choisissez SSH ou HTTPS)
|
||||||
|
git remote add gitea git@git.mondomaine.fr:vous/voix-du-peuple.git
|
||||||
|
# ou en HTTPS :
|
||||||
|
git remote add gitea https://git.mondomaine.fr/vous/voix-du-peuple.git
|
||||||
|
|
||||||
|
# Vérifier
|
||||||
|
git remote -v
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Étape 3 — Configurer l'authentification
|
||||||
|
|
||||||
|
### Option A — SSH (recommandé)
|
||||||
|
|
||||||
|
Générez une clé SSH dans le shell Replit si vous n'en avez pas :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh-keygen -t ed25519 -C "replit-voix-du-peuple"
|
||||||
|
cat ~/.ssh/id_ed25519.pub
|
||||||
|
```
|
||||||
|
|
||||||
|
Copiez la clé publique affichée et ajoutez-la dans Gitea :
|
||||||
|
**Paramètres → Clés SSH → Ajouter une clé**
|
||||||
|
|
||||||
|
Testez la connexion :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh -T git@git.mondomaine.fr
|
||||||
|
```
|
||||||
|
|
||||||
|
### Option B — HTTPS avec token
|
||||||
|
|
||||||
|
Dans Gitea : **Paramètres → Applications → Générer un token**
|
||||||
|
|
||||||
|
Utilisez l'URL avec token :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git remote set-url gitea https://VOTRE_TOKEN@git.mondomaine.fr/vous/voix-du-peuple.git
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Étape 4 — Pousser le code
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Premier push (établit le tracking)
|
||||||
|
git push -u gitea main
|
||||||
|
|
||||||
|
# Pour les push suivants
|
||||||
|
git push gitea main
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Étape 5 — Récupérer les mises à jour depuis Replit
|
||||||
|
|
||||||
|
Chaque fois que vous voulez synchroniser votre Gitea avec l'état actuel du projet Replit :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Depuis le shell Replit
|
||||||
|
git push gitea main
|
||||||
|
```
|
||||||
|
|
||||||
|
Si vous avez également modifié des fichiers directement sur Gitea :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git pull gitea main --rebase
|
||||||
|
git push gitea main
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Étape 6 — Cloner depuis Gitea sur votre serveur de production
|
||||||
|
|
||||||
|
Sur votre serveur RockyLinux / Debian :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone git@git.mondomaine.fr:vous/voix-du-peuple.git
|
||||||
|
cd voix-du-peuple
|
||||||
|
|
||||||
|
# Copier et adapter les variables d'environnement
|
||||||
|
cp .env.example .env
|
||||||
|
nano .env # Renseignez DATABASE_URL, MISTRAL_API_KEY, SESSION_SECRET
|
||||||
|
|
||||||
|
# Suivre ensuite le guide DEPLOIEMENT.md
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Résumé des commandes utiles
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Voir l'état du dépôt
|
||||||
|
git status
|
||||||
|
git log --oneline -10
|
||||||
|
|
||||||
|
# Synchroniser vers Gitea
|
||||||
|
git push gitea main
|
||||||
|
|
||||||
|
# Récupérer depuis Gitea
|
||||||
|
git pull gitea main
|
||||||
|
|
||||||
|
# Voir les remotes configurés
|
||||||
|
git remote -v
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Structure des branches
|
||||||
|
|
||||||
|
| Branche | Usage |
|
||||||
|
|---------|-------|
|
||||||
|
| `main` | Code de production, stable |
|
||||||
|
| `replit-agent` | Branche de travail de l'agent Replit (interne) |
|
||||||
|
|
||||||
|
> Il est conseillé de ne travailler que sur `main` et de ne jamais pousser `replit-agent` vers votre Gitea.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Pousser uniquement main
|
||||||
|
git push gitea main
|
||||||
|
```
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
# La Voix du Peuple — Page wiki
|
||||||
|
|
||||||
|
**Type** : Plateforme civique numérique
|
||||||
|
**Stack** : Python / Flask · React / Vite · PostgreSQL · Mistral AI
|
||||||
|
**Hébergement** : Replit (dev) / Auto-hébergeable (RockyLinux, Debian)
|
||||||
|
**Dépôt** : `voix-du-peuple` (Gitea)
|
||||||
|
**Statut** : Actif — avril 2026
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Qu'est-ce que c'est ?
|
||||||
|
|
||||||
|
Un outil permettant à des citoyens de soumettre des propositions politiques en texte libre. Ces propositions sont :
|
||||||
|
|
||||||
|
- **filtrées** automatiquement par une IA selon les textes internationaux des droits humains (DUDH, PIDCP, CEDH…)
|
||||||
|
- **synthétisées** en un résumé structuré par thèmes, destiné à des élus ou décideurs
|
||||||
|
- **affichées** en temps réel sur la page principale
|
||||||
|
|
||||||
|
L'objectif est de fournir aux représentants politiques un document clair et utilisable issu des préoccupations citoyennes, sans intermédiaire.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Fonctionnement en 5 points
|
||||||
|
|
||||||
|
1. Un citoyen saisit une proposition sur la page principale
|
||||||
|
2. L'IA (Mistral Small) vérifie que le contenu respecte les droits fondamentaux
|
||||||
|
3. Si la contribution est acceptée, elle s'ajoute à la base et déclenche une re-synthèse
|
||||||
|
4. L'IA (Mistral Large) relit toutes les contributions et produit un résumé thématique
|
||||||
|
5. Le résumé s'affiche en temps réel à droite de l'écran
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Pages de l'application
|
||||||
|
|
||||||
|
| URL | Contenu |
|
||||||
|
|-----|---------|
|
||||||
|
| `/` | Formulaire de soumission + contributions récentes + synthèse |
|
||||||
|
| `/about` | Description du projet et fondements juridiques |
|
||||||
|
| `/transparence` | Fonctionnement de l'IA, données collectées, limites |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Stack technique
|
||||||
|
|
||||||
|
| Couche | Technologie |
|
||||||
|
|--------|-------------|
|
||||||
|
| Frontend | React 18 + TypeScript + Vite 7 + Tailwind CSS |
|
||||||
|
| Backend | Python 3.11 + Flask 3 + Gunicorn |
|
||||||
|
| Base de données | PostgreSQL |
|
||||||
|
| IA | Mistral AI (API OpenAI-compatible) |
|
||||||
|
| Modération | `mistral-small-latest` |
|
||||||
|
| Synthèse | `mistral-large-latest` |
|
||||||
|
| Police | Bahnschrift (titres), Inter (corps) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Variables d'environnement clés
|
||||||
|
|
||||||
|
```
|
||||||
|
DATABASE_URL — URL PostgreSQL
|
||||||
|
MISTRAL_API_KEY — Clé API Mistral
|
||||||
|
SESSION_SECRET — Secret Flask
|
||||||
|
FILTER_MODEL — Modèle de modération (optionnel)
|
||||||
|
SYNTHESIS_MODEL — Modèle de synthèse (optionnel)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Données collectées
|
||||||
|
|
||||||
|
- Texte de la contribution
|
||||||
|
- Pseudonyme (facultatif, choisi par l'utilisateur)
|
||||||
|
- Horodatage
|
||||||
|
- Résultat du filtre IA (accepté / refusé + motif)
|
||||||
|
|
||||||
|
**Non collecté** : adresse IP, compte utilisateur, cookies de suivi.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Liens
|
||||||
|
|
||||||
|
- Tutoriel Gitea → [`docs/GITEA_TUTO.md`](./GITEA_TUTO.md)
|
||||||
|
- Architecture technique → [`docs/DAT.md`](./DAT.md)
|
||||||
|
- Exploitation → [`docs/DEX.md`](./DEX.md)
|
||||||
|
- Guide déploiement → [`DEPLOIEMENT.md`](../DEPLOIEMENT.md)
|
||||||
|
- Fonctionnement technique (in-app) → `/transparence`
|
||||||
Reference in New Issue
Block a user