Files
roadwave/docs/adr/023-architecture-moderation.md
jpgiannetti 5e5fcf4714 refactor(docs): réorganiser la documentation selon principes DDD
Réorganise la documentation du projet selon les principes du Domain-Driven Design (DDD) pour améliorer la cohésion, la maintenabilité et l'alignement avec l'architecture modulaire du backend.

**Structure cible:**
```
docs/domains/
├── README.md (Context Map)
├── _shared/ (Core Domain)
├── recommendation/ (Supporting Subdomain)
├── content/ (Supporting Subdomain)
├── moderation/ (Supporting Subdomain)
├── advertising/ (Generic Subdomain)
├── premium/ (Generic Subdomain)
└── monetization/ (Generic Subdomain)
```

**Changements effectués:**

Phase 1: Création de l'arborescence des 7 bounded contexts
Phase 2: Déplacement des règles métier (01-19) vers domains/*/rules/
Phase 3: Déplacement des diagrammes d'entités vers domains/*/entities/
Phase 4: Déplacement des diagrammes flux/états/séquences vers domains/*/
Phase 5: Création des README.md pour chaque domaine
Phase 6: Déplacement des features Gherkin vers domains/*/features/
Phase 7: Création du Context Map (domains/README.md)
Phase 8: Mise à jour de mkdocs.yml pour la nouvelle navigation
Phase 9: Correction automatique des liens internes (script fix-markdown-links.sh)
Phase 10: Nettoyage de l'ancienne structure (regles-metier/, diagrammes/, features/)

**Configuration des tests:**
- Makefile: godog run docs/domains/*/features/
- scripts/generate-bdd-docs.py: features_dir → docs/domains

**Avantages:**
 Cohésion forte: toute la doc d'un domaine au même endroit
 Couplage faible: domaines indépendants, dépendances explicites
 Navigabilité améliorée: README par domaine = entrée claire
 Alignement code/docs: miroir de backend/internal/
 Onboarding facilité: exploration domaine par domaine
 Tests BDD intégrés: features au plus près des règles métier

Voir docs/REFACTOR-DDD.md pour le plan complet.
2026-02-07 17:15:02 +01:00

207 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR-023 : Architecture de Modération
**Statut** : Accepté
**Date** : 2026-02-01
## Contexte
Le système de modération RoadWave doit traiter des signalements de contenu audio problématique (haine, spam, droits d'auteur, etc.) avec :
- **SLA stricts** : 2h (critique), 24h (haute), 72h (standard) définis dans [Règle 14](../domains/moderation/rules/moderation-flows.md)
- **Scalabilité** : 0-10K+ signalements/mois
- **Conformité DSA** : transparence, traçabilité, délais garantis
- **Efficacité** : pré-filtrage IA pour priorisation automatique
## Décision
Architecture hybride **humain + IA** avec file d'attente intelligente.
### Stack Technique
| Composant | Technologie | Justification |
|-----------|-------------|---------------|
| **Queue signalements** | PostgreSQL LISTEN/NOTIFY | Pas de dépendance externe, transactions ACID |
| **Transcription audio** | Whisper large-v3 (self-hosted) | Open source, qualité production, 0€ |
| **Analyse NLP** | distilbert + roberta-hate-speech | Modèles open source, self-hosted |
| **Dashboard modérateurs** | React + Fiber API | Stack cohérent avec ADR-001, ADR-010 |
| **Player audio** | Wavesurfer.js | Waveform visuel, annotations temporelles |
| **Cache priorisation** | Redis Sorted Sets | Ranking temps réel, TTL automatique |
### Architecture
```mermaid
graph TB
subgraph Client["App Mobile/Web"]
Report["Signalement utilisateur"]
end
subgraph Backend["Backend Go"]
API["API Fiber<br/>/moderation/report"]
Queue["PostgreSQL Queue<br/>LISTEN/NOTIFY"]
Worker["Worker Go<br/>(transcription + NLP)"]
end
subgraph AI["IA Self-hosted"]
Whisper["Whisper large-v3<br/>(transcription)"]
NLP["distilbert<br/>(sentiment + haine)"]
end
subgraph Moderation["Modération Dashboard"]
Dashboard["React Dashboard"]
Player["Wavesurfer.js<br/>(lecture audio)"]
end
subgraph Storage["Stockage"]
DB["PostgreSQL<br/>(signalements + logs)"]
Redis["Redis<br/>(priorisation + cache)"]
end
Report --> API
API --> Queue
Queue --> Worker
Worker --> Whisper
Whisper --> NLP
NLP --> Redis
Worker --> DB
Dashboard --> Player
Dashboard --> Redis
Dashboard --> DB
classDef clientStyle fill:#e3f2fd,stroke:#1565c0
classDef backendStyle fill:#fff3e0,stroke:#e65100
classDef aiStyle fill:#f3e5f5,stroke:#6a1b9a
classDef storageStyle fill:#e8f5e9,stroke:#2e7d32
class Client,Report clientStyle
class Backend,API,Queue,Worker backendStyle
class AI,Whisper,NLP aiStyle
class Storage,DB,Redis storageStyle
```
### Workflow de Traitement
1. **Réception signalement** :
- Insertion en base PostgreSQL (table `moderation_reports`)
- Notification asynchrone via PostgreSQL NOTIFY
2. **Worker asynchrone** (goroutine) :
- Écoute queue PostgreSQL (LISTEN/NOTIFY)
- Téléchargement audio depuis stockage S3/local
- Transcription audio via Whisper large-v3 (1-10 min selon durée)
- Analyse NLP : score confiance 0-100% (distilbert + roberta)
- Calcul priorité selon formule : `(score_IA × 0.7) + (nb_signalements × 0.2) + (fiabilité_signaleur × 0.1)`
- Insertion dans Redis Sorted Set pour priorisation
3. **Dashboard modérateurs** :
- Récupération signalements priorisés depuis Redis (top 20 par page)
- Affichage : transcription, waveform audio, historique créateur
- Actions disponibles : Approuver, Rejeter, Escalade (shortcuts clavier A/R/E)
- Logs audit PostgreSQL pour traçabilité (conformité DSA)
## Alternatives considérées
### Queue de signalements
| Option | Avantages | Inconvénients | Verdict |
|--------|-----------|---------------|---------|
| **PostgreSQL LISTEN/NOTIFY** | ✅ Pas de dépendance, ACID | ⚠️ Performance limitée >10K/min | ✅ Choisi MVP |
| RabbitMQ | Scalable, dead letter queues | ❌ Nouvelle dépendance, complexité | ❌ Overkill MVP |
| Redis Streams | Performant, simple | ⚠️ Pas de garantie persistance | ⚠️ Phase 2 |
| SQS/Cloud | Managed, scalable | ❌ Dépendance cloud, coût | ❌ Souveraineté |
### Transcription audio
| Option | Coût | Qualité | Hébergement | Verdict |
|--------|------|---------|-------------|---------|
| **Whisper large-v3** | **0€** (self-hosted) | ⭐⭐⭐ Excellente | Self-hosted | ✅ Choisi |
| AssemblyAI API | 0.37$/h audio | ⭐⭐⭐ Excellente | Cloud US | ❌ Coût + souveraineté |
| Google Speech-to-Text | 0.024$/min | ⭐⭐ Bonne | Cloud Google | ❌ Dépendance Google |
| Whisper tiny/base | 0€ | ⭐ Moyenne | Self-hosted | ❌ Qualité insuffisante |
### NLP Analyse
| Option | Coût | Performance | Hébergement | Verdict |
|--------|------|-------------|-------------|---------|
| **distilbert + roberta** | **0€** | CPU OK (1-3s/audio) | Self-hosted | ✅ Choisi |
| OpenAI Moderation API | 0.002$/1K tokens | Excellente | Cloud OpenAI | ❌ Dépendance + coût |
| Perspective API (Google) | Gratuit | Bonne | Cloud Google | ❌ Dépendance Google |
## Justification
### PostgreSQL LISTEN/NOTIFY
- **Performance MVP** : Suffisant jusqu'à 1000 signalements/jour (~0.7/min)
- **Simplicité** : Pas de broker externe, transactions ACID
- **Migration facile** : Abstraction via interface `ModerationQueue` → swap vers Redis Streams si besoin (méthodes : Enqueue, Listen)
### Whisper large-v3 self-hosted
- **Coût 0€** vs AssemblyAI (3700€/an @ 10K heures audio)
- **Souveraineté** : données sensibles restent en France
- **Qualité production** : WER (Word Error Rate) <5% français
- **Scaling** : CPU MVP (1 core), GPU Phase 2 si >1000 signalements/jour
### Dashboard React
- **Cohérence stack** : Même techno que admin panel (si React adopté)
- **Performance** : TanStack Table pour listes >1000 éléments
- **Wavesurfer.js** : Standard industrie (SoundCloud, Audacity web)
## Conséquences
### Positives
-**0€ infrastructure IA** au MVP (CPU standard)
-**100% self-hosted** : conformité souveraineté (ADR-008, ADR-015)
-**Scalable progressif** : PostgreSQL → Redis Streams si besoin
-**Conformité DSA** : logs audit, traçabilité complète
-**Productivité ×3-5** : pré-filtrage IA réduit charge modérateurs
### Négatives
- ⚠️ **Latence transcription** : 1-10 min selon durée audio (acceptable, traitement asynchrone)
- ⚠️ **Performance limite** : PostgreSQL LISTEN/NOTIFY saturé >10K signalements/jour (migration Redis Streams nécessaire)
-**Ressources CPU** : Whisper consomme 1-4 CPU cores selon charge (migration GPU si >1000 signalements/jour)
### Dépendances
**Backend Go** :
- `gofiber/fiber/v3` : API Dashboard
- `jackc/pgx/v5` : PostgreSQL + LISTEN/NOTIFY
- `redis/rueidis` : Cache priorisation
- Whisper : via Python subprocess ou go-whisper bindings
**Frontend Dashboard** :
- `react` : Framework UI
- `@tanstack/react-table` : Tables performantes
- `wavesurfer.js` : Player audio avec waveform
## Métriques de Succès
- Latence traitement < 10 min (P95) après réception signalement
- Précision IA pré-filtre > 80% (validation humaine)
- SLA respectés > 95% des cas (2h/24h/72h selon priorité)
- Coût infrastructure < 50€/mois jusqu'à 1000 signalements/mois
## Migration et Rollout
### Phase 1 (MVP - Sprint 3-4)
1. Backend : API `/moderation/report` + PostgreSQL queue
2. Worker : Whisper large-v3 CPU + NLP basique (liste noire mots-clés)
3. Dashboard : React basique (liste + player audio)
### Phase 2 (Post-MVP - Sprint 8-10)
1. Migration Redis Streams si >1000 signalements/jour
2. GPU pour Whisper si latence >15 min P95
3. NLP avancé (distilbert + roberta)
4. Modération communautaire (badges, [Règle 15](../domains/moderation/rules/moderation-communautaire.md))
## Références
- [Règle 14 : Modération - Flows opérationnels](../domains/moderation/rules/moderation-flows.md)
- [Règle 15 : Modération Communautaire](../domains/moderation/rules/moderation-communautaire.md)
- [ADR-001 : Langage Backend](001-langage-backend.md) (Go, Fiber)
- [ADR-005 : Base de données](005-base-de-donnees.md) (PostgreSQL)
- [ADR-010 : Architecture Backend](010-architecture-backend.md) (Modular monolith)
- [Whisper large-v3 documentation](https://github.com/openai/whisper)
- [PostgreSQL LISTEN/NOTIFY](https://www.postgresql.org/docs/current/sql-notify.html)