Améliorations: - Orientation LR (Left-Right) au lieu de TB pour meilleur flux - Ajout icônes émojis pour identification visuelle rapide - Simplification des connexions (api --> services au lieu de connexions multiples) - Labels plus courts dans les boîtes - Styles améliorés avec bordures colorées - Meilleure organisation des sous-graphes Le diagramme est maintenant beaucoup plus lisible et professionnel.
7.5 KiB
7.5 KiB
RoadWave - Architecture Technique
Les décisions techniques sont documentées dans adr/
Stack Technologique
| Composant | Technologie | ADR |
|---|---|---|
| Backend | Go + Fiber | ADR-001 |
| Architecture Backend | Monolithe Modulaire | ADR-010 |
| Authentification | Zitadel (self-hosted OVH) | ADR-008 |
| Streaming | HLS | ADR-002 |
| Codec | Opus | ADR-003 |
| CDN | NGINX Cache (OVH VPS) | ADR-004 |
| Storage | OVH Object Storage | ADR-004 |
| Hébergement MVP | OVH VPS Essential | ADR-015 |
| Organisation | Monorepo | ADR-014 |
| Base de données | PostgreSQL + PostGIS | ADR-005 |
| ORM/Accès données | sqlc | ADR-011 |
| Cache | Redis Cluster | ADR-021 |
| Chiffrement | TLS 1.3 | ADR-006 |
| Live | WebRTC | ADR-002 |
| Frontend Mobile | Flutter | ADR-012 |
| Tests | Testify + Godog (Gherkin) | ADR-013, ADR-007 |
| Paiements | Mangopay | ADR-009 |
| Emailing | Brevo | ADR-016 |
| Géolocalisation IP | IP2Location (fallback) | ADR-019 |
| Librairies Mobile | Flutter packages | ADR-020 |
| CI/CD | GitHub Actions (monorepo) | ADR-022 |
| Modération | Architecture modération | ADR-023 |
| Monitoring | Prometheus + Grafana | ADR-024 |
| Secrets | Vault + sealed secrets | ADR-025 |
| Notifications géo | Push + geofencing | ADR-017 |
| Notifications push | FCM + APNS | ADR-018 |
Streaming Audio
Protocole : HLS (HTTP Live Streaming)
- Fonctionne à travers firewalls et réseaux mobiles instables
- Cache CDN natif (réduction des coûts)
- Bitrate adaptatif automatique (tunnels, zones rurales)
- Support natif iOS/Android
Codec : Opus
Optimisé pour la voix en environnement bruyant (voiture).
| Qualité | Bitrate | Usage |
|---|---|---|
| Basse | 24 kbps | 2G/Edge |
| Standard | 48 kbps | 3G |
| Haute | 64 kbps | 4G/5G |
Fallback AAC-LC pour appareils legacy.
Buffering Adaptatif
| Réseau | Buffer min | Buffer cible | Buffer max |
|---|---|---|---|
| WiFi | 5s | 30s | 120s |
| 4G/5G | 10s | 45s | 120s |
| 3G | 30s | 90s | 300s |
Sécurité
Chiffrement
- TLS 1.3 sur tous les endpoints (overhead ~1-2%)
- DTLS-SRTP pour WebRTC (radio live)
- Pas de DRM initialement (ajout si licences l'exigent)
Authentification
- Zitadel self-hosted sur OVH France (Gravelines) pour IAM
- Souveraineté totale : 100% données en France (cohérent avec ADR-004)
- JWT validation locale (zitadel-go SDK)
- OAuth2 PKCE pour mobile (iOS/Android)
- MFA et passkeys disponibles
- Rate limiting par IP et par utilisateur (Nginx + Zitadel)
- PostgreSQL schema partagé avec RoadWave (séparation logique)
Base de Données
PostgreSQL + PostGIS
-- Requête géolocalisée typique
SELECT id, ST_Distance(location::geography, ST_MakePoint($lon, $lat)::geography) as distance
FROM contents
WHERE ST_DWithin(location::geography, ST_MakePoint($lon, $lat)::geography, 50000)
ORDER BY distance
LIMIT 20;
Redis Geospatial (Cache)
GEOADD contents:geo longitude latitude content_id
GEORADIUS contents:geo user_lon user_lat 50 km WITHDIST COUNT 20 ASC
TTL cache : 5 minutes (le contenu ne bouge pas).
Architecture Services
flowchart LR
subgraph clients["📱 Clients"]
direction TB
mobile["Mobile Apps<br/>iOS/Android<br/>Flutter"]
carplay["CarPlay /<br/>Android Auto"]
end
subgraph ovh["🇫🇷 OVH VPS Essential (Gravelines, France)"]
direction TB
nginx["🌐 NGINX<br/>Cache + TLS 1.3<br/>Rate Limiting"]
api["🚪 API Gateway<br/>Go + Fiber<br/>:8080"]
subgraph services["Backend (Monolithe Modulaire)"]
direction LR
auth["🔐 Auth"]
user["👤 User"]
content["🎙️ Content/Geo"]
streaming["📡 Streaming"]
payment["💳 Payment"]
notif["🔔 Notif"]
end
zitadel["🔑 Zitadel<br/>OAuth2 PKCE<br/>:8081"]
ip2loc["🌍 IP2Location<br/>SQLite 50MB"]
subgraph data["💾 Données"]
direction TB
pgbouncer["PgBouncer<br/>:6432"]
postgres["PostgreSQL 16<br/>+ PostGIS 3.4"]
redis["Redis 7<br/>Cache + Geo"]
end
end
subgraph external["☁️ Services Externes"]
direction TB
storage["OVH Object Storage<br/>(Fichiers HLS)"]
mangopay["Mangopay<br/>(Paiements/KYC)"]
brevo["Brevo<br/>(Emails)"]
fcm["FCM/APNS<br/>(Push)"]
end
%% Flux clients
clients --> nginx
nginx --> api
%% API vers services
api --> services
api --> ip2loc
%% Services vers infra
auth --> zitadel
user --> data
content --> data
streaming --> storage
payment --> mangopay
notif --> fcm
%% Infra interne
zitadel --> pgbouncer
pgbouncer --> postgres
%% Retours vers clients
brevo -.email.-> clients
fcm -.push.-> clients
style ovh fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
style external fill:#fff3e0,stroke:#f57c00,stroke-width:2px
style clients fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
style data fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
style services fill:#fff,stroke:#666,stroke-width:1px
Souveraineté : 100% données en France (RGPD compliant)
Scaling 10M Utilisateurs
Stratégie par phase
| Phase | Utilisateurs | Infra | Coût estimé |
|---|---|---|---|
| MVP | 0-20K | OVH VPS Essential + PostgreSQL + Zitadel + NGINX Cache | ~14€/mois |
| Growth | 20K-500K | Scaleway Instances (multi-replicas), OVH Object Storage | 150-500€/mois |
| Scale | 500K+ | Multi-région, Kubernetes managé, NGINX origin shield | 2-10K€/mois |
Métriques cibles
| Métrique | Objectif |
|---|---|
| Latence API p99 | < 100ms |
| Temps de démarrage audio | < 3s |
| Disponibilité | 99.9% |
| Connexions/serveur | 100K+ |
Points de vigilance
- Buffering mobile : Pré-chargement agressif avant tunnels (détection GPS)
- Handoff réseau : Buffer suffisant pour survivre aux changements de cellule
- Mode offline : Téléchargement complet sur WiFi
- Bande passante : 48 kbps Opus = ~20 MB/heure (faible consommation data)
Pourquoi pas UDP brut ?
| UDP | HLS/TCP |
|---|---|
| Latence minimale | Latence acceptable (5-30s) |
| Problèmes NAT/firewall | Passe partout |
| Perte de paquets = artefacts | Retransmission automatique |
| Pas de cache CDN | Cache CDN = économies |
| Complexité++ | Standard de l'industrie |
Pour du contenu non-interactif (podcasts, audio-guides), la latence HLS est acceptable. WebRTC réservé à la radio live uniquement.