From 213a67e61256ed6a3cbaf8c6fce684aca0a4e04f Mon Sep 17 00:00:00 2001 From: pironantoine <57062554-pironantoine@users.noreply.replit.com> Date: Sat, 4 Apr 2026 06:56:49 +0000 Subject: [PATCH] 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 --- .agents/agent_assets_metadata.toml | 24 +++ docs/DAT.md | 217 +++++++++++++++++++++++++ docs/DEX.md | 244 +++++++++++++++++++++++++++++ docs/GITEA_TUTO.md | 156 ++++++++++++++++++ docs/WIKI.md | 86 ++++++++++ 5 files changed, 727 insertions(+) create mode 100644 docs/DAT.md create mode 100644 docs/DEX.md create mode 100644 docs/GITEA_TUTO.md create mode 100644 docs/WIKI.md diff --git a/.agents/agent_assets_metadata.toml b/.agents/agent_assets_metadata.toml index 34fa4de..34a13af 100644 --- a/.agents/agent_assets_metadata.toml +++ b/.agents/agent_assets_metadata.toml @@ -6,3 +6,27 @@ id = "x31gBYdQKnMGZriV7IJ1v" uri = "file://DEPLOIEMENT.md" type = "text" 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" diff --git a/docs/DAT.md b/docs/DAT.md new file mode 100644 index 0000000..b096817 --- /dev/null +++ b/docs/DAT.md @@ -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 +``` diff --git a/docs/DEX.md b/docs/DEX.md new file mode 100644 index 0000000..1221b24 --- /dev/null +++ b/docs/DEX.md @@ -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` diff --git a/docs/GITEA_TUTO.md b/docs/GITEA_TUTO.md new file mode 100644 index 0000000..da9bc38 --- /dev/null +++ b/docs/GITEA_TUTO.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 +``` diff --git a/docs/WIKI.md b/docs/WIKI.md new file mode 100644 index 0000000..49e79a4 --- /dev/null +++ b/docs/WIKI.md @@ -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`