# 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](../../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) + Telegram Bot | - | Multi-canal, pas de coût SMS |
| **Uptime monitoring** | Uptime Kuma | MIT | Self-hosted, SSL checks, incidents page |

### Architecture

```mermaid
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)"]
        Telegram["Telegram Bot"]
    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 --> Telegram

    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,Telegram notifStyle
    class Storage,PromStorage,LokiStorage,Backups storageStyle
```

### Métriques Clés

**API Performance** (requêtes PromQL) :
- Latency p99 : histogramme quantile 99e percentile sur durée requêtes HTTP (fenêtre 5 min)
- Error rate : ratio requêtes 5xx / total requêtes (fenêtre 5 min)
- Throughput : taux de requêtes par seconde (fenêtre 5 min)

**Infrastructure** :
- CPU usage : taux utilisation CPU (mode non-idle, fenêtre 5 min)
- Memory usage : ratio mémoire disponible / totale
- Disk I/O : temps I/O disque (fenêtre 5 min)

**Business** (compteurs custom) :
- Active users (DAU) : `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 |
| **Telegram Bot** | **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 + Telegram (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 (Telegram 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

**Alertes critiques** (Telegram + Email immédiat) :
- **API Down** : Job API indisponible pendant >1 min → Notification immédiate
- **High Error Rate** : Taux erreurs 5xx >1% pendant >5 min → Notification immédiate
- **Database Down** : PostgreSQL indisponible pendant >1 min → Notification immédiate

**Alertes warnings** (Email uniquement) :
- **High Latency** : Latency p99 >100ms pendant >10 min → Investigation requise
- **Disk Space Running Out** : Espace disque <10% pendant >30 min → Nettoyage requis

### Backup & Disaster Recovery

**PostgreSQL WAL-E** :
- Méthode : Backup continu Write-Ahead Log (WAL)
- Rétention : 7 jours full + WAL incrémentaux
- Stockage : S3 OVH région GRA (France)
- Chiffrement : AES-256 server-side

**RTO (Recovery Time Objective)** : 1h
- Restore depuis S3 : ~30 min (DB 10 GB)
- Validation + relance services : ~30 min

**RPO (Recovery Point Objective)** : 15 min
- Fréquence archivage WAL : 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** : Requête Loki filtrée sur app roadwave-api + niveau 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** : Utiliser 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** : Consulter 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

- [TECHNICAL.md](../../TECHNICAL.md) (SLO 99.9%, latency p99 <100ms)
- [ADR-001 : Langage Backend](001-langage-backend.md) (Go, Fiber)
- [ADR-005 : Base de données](005-base-de-donnees.md) (PostgreSQL)
- [ADR-015 : Hébergement](015-hebergement.md) (OVH France, self-hosted)
- [Prometheus Documentation](https://prometheus.io/docs/)
- [Grafana Loki](https://grafana.com/oss/loki/)
- [WAL-E PostgreSQL Archiving](https://github.com/wal-e/wal-e)
