Files
roadwave/docs/adr/024-monitoring-observabilite.md
jpgiannetti 5986286c3d feat(adr): créer 3 ADR P1 manquants + atteindre score 95%
Création des ADR critiques pour phase pré-implémentation :

- ADR-023 : Architecture de Modération
  * PostgreSQL LISTEN/NOTIFY + Redis cache priorisation
  * Whisper large-v3 (transcription) + NLP (distilbert, roberta)
  * Dashboard React + Wavesurfer.js + workflow automatisé
  * SLA 2h/24h/72h selon priorité, conformité DSA

- ADR-024 : Monitoring et Observabilité
  * Prometheus + Grafana + Loki (stack self-hosted)
  * Alerting multi-canal : Email (Brevo) + Webhook (Slack/Discord)
  * Backup PostgreSQL : WAL-E continuous (RTO 1h, RPO 15min)
  * Runbooks incidents + dashboards métriques + uptime monitoring

- ADR-025 : Secrets et Sécurité
  * HashiCorp Vault (self-hosted) pour secrets management
  * AES-256-GCM encryption PII (emails, GPS précis)
  * Let's Encrypt TLS 1.3 (wildcard certificate)
  * OWASP Top 10 mitigation complète + rate limiting

Impact INCONSISTENCIES.md :
- Score Modération : 20% → 95%
- Score Ops & Monitoring : 30% → 95%
- Score Sécurité : 40% → 95%
- Score global : 82% → 95%  OBJECTIF ATTEINT

Phase P0 + P1 TERMINÉES : documentation prête pour Sprint 3 !

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-01 16:44:21 +01:00

11 KiB

ADR-024 : Monitoring, Observabilité et Incident Response

Statut : Accepté Date : 2026-02-01

Contexte

RoadWave nécessite un système de monitoring pour garantir la disponibilité cible 99.9% (SLO) définie dans TECHNICAL.md :

  • Métriques : latency p99 < 100ms, throughput API, erreurs
  • Alerting : détection pannes, dégradations performance
  • Incident response : runbooks, escalation, post-mortems
  • Backup/Disaster Recovery : RTO 1h, RPO 15min

Contrainte : self-hosted pour souveraineté données (ADR-015).

Décision

Stack Prometheus + Grafana + Loki self-hosted avec alerting multi-canal.

Stack Technique

Composant Technologie Licence Justification
Métriques Prometheus Apache-2.0 Standard industrie, PromQL, TSDB performant
Visualisation Grafana AGPL-3.0 Dashboards riches, alerting intégré
Logs Grafana Loki AGPL-3.0 "Prometheus pour logs", compression efficace
Tracing Tempo (optionnel Phase 2) AGPL-3.0 Traces distribuées, compatible OpenTelemetry
Alerting Alertmanager Apache-2.0 Grouping, silencing, routing multi-canal
Canaux alerts Email (Brevo) + Webhook (Slack/Discord) - Multi-canal, pas de coût SMS
Uptime monitoring Uptime Kuma MIT Self-hosted, SSL checks, incidents page

Architecture

graph TB
    subgraph Services["Services RoadWave"]
        API["Backend Go API<br/>(Fiber metrics)"]
        DB["PostgreSQL<br/>(pg_exporter)"]
        Redis["Redis<br/>(redis_exporter)"]
        Zitadel["Zitadel<br/>(metrics endpoint)"]
    end

    subgraph Monitoring["Stack Monitoring"]
        Prom["Prometheus<br/>(scrape + TSDB)"]
        Grafana["Grafana<br/>(dashboards)"]
        Loki["Loki<br/>(logs aggregation)"]
        Alert["Alertmanager<br/>(routing)"]
        Uptime["Uptime Kuma<br/>(external checks)"]
    end

    subgraph Notifications["Alerting"]
        Email["Email (Brevo)"]
        Slack["Webhook Slack/Discord"]
    end

    subgraph Storage["Stockage"]
        PromStorage["Prometheus TSDB<br/>(15j retention)"]
        LokiStorage["Loki Chunks<br/>(7j retention)"]
        Backups["Backups PostgreSQL<br/>(S3 OVH)"]
    end

    API --> Prom
    DB --> Prom
    Redis --> Prom
    Zitadel --> Prom

    API -.->|logs stdout| Loki
    Prom --> Grafana
    Loki --> Grafana
    Prom --> Alert

    Alert --> Email
    Alert --> Slack

    Uptime -.->|external HTTP checks| API
    Uptime --> Alert

    Prom --> PromStorage
    Loki --> LokiStorage
    DB -.->|WAL-E continuous| Backups

    classDef serviceStyle fill:#e3f2fd,stroke:#1565c0
    classDef monitoringStyle fill:#fff3e0,stroke:#e65100
    classDef notifStyle fill:#f3e5f5,stroke:#6a1b9a
    classDef storageStyle fill:#e8f5e9,stroke:#2e7d32

    class Services,API,DB,Redis,Zitadel serviceStyle
    class Monitoring,Prom,Grafana,Loki,Alert,Uptime monitoringStyle
    class Notifications,Email,Slack notifStyle
    class Storage,PromStorage,LokiStorage,Backups storageStyle

Métriques Clés

API Performance (Prometheus PromQL) :

# Latency p99
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))

# Error rate
rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m])

# Throughput
rate(http_requests_total[5m])

Infrastructure :

  • CPU usage : rate(node_cpu_seconds_total{mode!="idle"}[5m])
  • Memory usage : node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes
  • Disk I/O : rate(node_disk_io_time_seconds_total[5m])

Business :

  • Active users (DAU) : compteur custom roadwave_active_users_total
  • Audio streams actifs : roadwave_hls_streams_active
  • Signalements modération : roadwave_moderation_reports_total

Alternatives considérées

Stack Monitoring

Option Coût Hébergement Complexité Verdict
Prometheus + Grafana 0€ Self-hosted Moyenne Choisi
Datadog 15-31$/host/mois SaaS US Faible Coût + souveraineté
New Relic 99-349$/user/mois SaaS US Faible Coût prohibitif
Elastic Stack (ELK) 0€ (open) Self-hosted Complexe Overhead JVM
VictoriaMetrics 0€ Self-hosted Moyenne ⚠️ Moins mature

Alerting Canaux

Canal Coût Disponibilité Intrusivité Verdict
Email (Brevo) 0€ (300/j) Asynchrone Basse Standard
Webhook Slack/Discord 0€ Temps réel Moyenne On-call
SMS (Twilio) 0.04€/SMS Immédiat Haute ⚠️ Phase 2 (critique)
PagerDuty 21$/user/mois Immédiat + escalation Haute Coût
OpsGenie 29$/user/mois Immédiat + escalation Haute Coût

Backup Strategy

Option RPO RTO Coût Verdict
WAL-E continuous archiving 15 min 1h 5-15€/mois (S3) Choisi
pg_dump quotidien 24h 2-4h 0€ (local) RPO trop élevé
pgBackRest 5 min 30 min 10-20€/mois ⚠️ Complexe MVP
Managed backup (Scaleway) 5 min 15 min 50€/mois Phase 2

Justification

Prometheus + Grafana

  • Standard industrie : adopté par CNCF, documentation riche
  • Performance : TSDB optimisé, compression >10x vs PostgreSQL
  • Écosystème : 150+ exporters officiels (PostgreSQL, Redis, Go, Nginx)
  • PromQL : langage requête puissant pour alerting complexe
  • Coût 0€ : self-hosted, licences permissives

Loki pour Logs

  • Compression : 10-50x vs Elasticsearch (stockage chunks)
  • Simplicité : pas de schéma, logs = labels + timestamp
  • Intégration Grafana : requêtes logs + métriques unifiées
  • Performance : grep distribué sur labels indexés

Uptime Kuma

  • Self-hosted : alternative à UptimeRobot (SaaS)
  • Fonctionnalités : HTTP/HTTPS checks, SSL expiry, status page public
  • Alerting : intégration Webhook, Email
  • Coût 0€ : open source MIT

Conséquences

Positives

  • Coût infrastructure : 5-20€/mois (stockage S3 backups uniquement)
  • Souveraineté : 100% self-hosted OVH France
  • Alerting multi-canal : Email + Slack/Discord (extensible SMS Phase 2)
  • Observabilité complète : métriques + logs + uptime externe
  • Conformité RGPD : logs anonymisés, rétention 7-15j

Négatives

  • ⚠️ Maintenance : Stack à gérer (mises à jour Prometheus, Grafana, Loki)
  • ⚠️ Stockage : Prometheus TSDB consomme ~1-2 GB/mois @ 1000 RPS
  • Pas d'on-call automatique au MVP (Slack manual, SMS Phase 2)
  • Courbe d'apprentissage : PromQL à maîtriser

Dashboards Grafana

Dashboard principal :

  • Latency p50/p95/p99 API (5 min, 1h, 24h)
  • Error rate 5xx/4xx (seuil alerte >1%)
  • Throughput requests/sec
  • Infra : CPU, RAM, Disk I/O
  • Business : DAU, streams actifs, signalements modération

Dashboard PostgreSQL :

  • Slow queries (>100ms)
  • Connections actives vs max
  • Cache hit ratio (cible >95%)
  • Deadlocks count

Dashboard Redis :

  • Memory usage
  • Evictions count
  • Commands/sec
  • Keyspace hits/misses ratio

Alerting Rules

Critiques (Slack + Email immédiat) :

- alert: APIDown
  expr: up{job="roadwave-api"} == 0
  for: 1m
  severity: critical
  message: "API indisponible depuis 1 min"

- alert: HighErrorRate
  expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.01
  for: 5m
  severity: critical
  message: "Error rate >1% depuis 5 min"

- alert: DatabaseDown
  expr: up{job="postgresql"} == 0
  for: 1m
  severity: critical
  message: "PostgreSQL indisponible"

Warnings (Email uniquement) :

- alert: HighLatency
  expr: histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])) > 0.1
  for: 10m
  severity: warning
  message: "Latency p99 >100ms depuis 10 min"

- alert: DiskSpaceRunningOut
  expr: node_filesystem_avail_bytes / node_filesystem_size_bytes < 0.1
  for: 30m
  severity: warning
  message: "Espace disque <10%"

Backup & Disaster Recovery

PostgreSQL WAL-E :

# Backup continu WAL (Write-Ahead Log)
wal-e backup-push /var/lib/postgresql/data

# Rétention : 7 jours full + WAL
# Stockage : S3 OVH (région GRA, France)
# Chiffrement : AES-256 server-side

RTO (Recovery Time Objective) : 1h

  • Temps de restore depuis S3 : ~30 min (DB 10 GB)
  • Temps validation + relance services : ~30 min

RPO (Recovery Point Objective) : 15 min

  • WAL archivage toutes les 15 min
  • Perte maximale : 15 min de transactions

Tests DR : Mensuel (restore backup sur environnement staging)

Runbooks Incidents

API Down (5xx errors spike)

  1. Vérifier : Grafana dashboard → onglet Errors
  2. Logs : Loki query {app="roadwave-api"} |= "error"
  3. Actions :
    • Si OOM : restart container + augmenter RAM
    • Si DB connexions saturées : vérifier slow queries
    • Si réseau : vérifier OVH status page
  4. Escalade : Si non résolu en 15 min → appel admin senior

Database Slow Queries

  1. Identifier : Grafana → PostgreSQL dashboard → Top slow queries
  2. Analyser : EXPLAIN ANALYZE sur query problématique
  3. Actions :
    • Index manquant : créer index (migration rapide)
    • Lock contention : identifier transaction longue et kill si bloquante
  4. Prevention : Ajouter alerte Grafana si query >100ms P95

High Load (CPU >80%)

  1. Vérifier : Grafana → Node Exporter → CPU usage
  2. Top processus : htop ou docker stats
  3. Actions :
    • Si Whisper (modération) : réduire concurrence workers
    • Si API : scale horizontal (ajouter instance)
  4. Prévention : Auto-scaling (Phase 2)

Métriques de Succès

  • Uptime > 99.9% (8.76h downtime/an max)
  • MTTD (Mean Time To Detect) < 5 min
  • MTTR (Mean Time To Recover) < 30 min
  • Alerts faux positifs < 5%

Migration et Rollout

Phase 1 (MVP - Sprint 2-3)

  1. Deploy Prometheus + Grafana + Loki (Docker Compose)
  2. Instrumenter API Go (Fiber middleware metrics)
  3. Configure exporters : PostgreSQL, Redis, Node
  4. Dashboard principal + 5 alertes critiques
  5. Setup WAL-E backup PostgreSQL

Phase 2 (Post-MVP - Sprint 6-8)

  1. Ajouter Tempo (tracing distribué)
  2. SMS alerting (Twilio) pour incidents critiques
  3. Auto-scaling basé métriques Prometheus
  4. Post-mortem process (template Notion)

Références