Résolution des incohérences #10, #11, et #12 de l'analyse d'architecture. ## Phase 1 : Réorganisation Features BDD (Point #10 - RÉSOLU) - Créer structure features/{api,ui,e2e} - Déplacer 83 features en 3 catégories via git mv (historique préservé) - features/api/ : 53 features (tests API backend) - features/ui/ : 22 features (tests UI mobile) - features/e2e/ : 8 features (tests end-to-end) Domaines déplacés : - API : authentication, recommendation, rgpd-compliance, content-creation, moderation, monetisation, premium, radio-live, publicites - UI : audio-guides, navigation, interest-gauges, mode-offline, partage, profil, recherche - E2E : abonnements, error-handling ## Phase 2 : Mise à jour Documentation ### ADR-007 - Tests BDD - Ajouter section "Convention de Catégorisation des Features" - Documenter règles api/ui/e2e avec exemples concrets - Spécifier step definitions (backend Go, mobile Dart) ### ADR-024 - Stratégie CI/CD Monorepo (NOUVEAU) - Créer ADR dédié pour stratégie CI/CD avec path filters - Architecture workflows séparés (backend.yml, mobile.yml, shared.yml) - Configuration path filters détaillée avec exemples YAML - Matrice de déclenchement et optimisations (~70% gain temps CI) - Plan d'implémentation (~2h, reporté jusqu'au développement) ### ADR-016 - Organisation Monorepo - Simplifier en retirant section CI/CD détaillée - Ajouter référence vers ADR-024 pour stratégie CI/CD ### INCONSISTENCIES-ANALYSIS.md - Point #10 (Tests BDD synchronisés) : ✅ RÉSOLU - Catégorisation features implémentée - ADR-007 mis à jour avec convention complète - Point #11 (70/30 Split paiements) : ✅ ANNULÉ (faux problème) - ADR-009 et Règle 18 parfaitement cohérents - Documentation exhaustive existante (formule, SQL, comparaisons) - Point #12 (Monorepo path filters) : ⏸️ DOCUMENTÉ - Architecture CI/CD complète dans ADR-024 - Implémentation reportée (projet en phase documentation) - Métriques mises à jour : - MODERATE : 6/9 traités (4 résolus + 1 annulé + 1 documenté) - ADR à jour : 100% (19/19 avec ADR-024) ## Phase 3 : Validation - Structure features validée (api/ui/e2e, aucun répertoire restant) - Historique Git préservé (git mv, renommages détectés) - 83 features total (API: 53, UI: 22, E2E: 8) Closes: Point #10 (résolu), Point #11 (annulé), Point #12 (documenté) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
790 lines
31 KiB
Markdown
790 lines
31 KiB
Markdown
# Analyse des Incohérences entre ADR et Règles Métier
|
||
|
||
**Date d'analyse** : 2026-01-28
|
||
**Analysé par** : Audit Architecture RoadWave
|
||
**Scope** : 18 ADR × Règles Métier (17 fichiers)
|
||
|
||
---
|
||
|
||
## Résumé Exécutif
|
||
|
||
Cette analyse a identifié **15 incohérences** entre les décisions d'architecture (ADR) et les règles métier du projet RoadWave.
|
||
|
||
### Répartition par Sévérité
|
||
|
||
| Sévérité | Nombre | % Total | Statut | Action Required |
|
||
|----------|--------|---------|--------|-----------------|
|
||
| 🔴 **CRITICAL** | 2 | 14% | ✅ **RÉSOLU** | ~~avant implémentation~~ |
|
||
| 🟠 **HIGH** | 2 | 14% | ✅ **RÉSOLU** (2 résolus, 1 annulé) | ~~Résolution Sprint 1-2~~ |
|
||
| 🟡 **MODERATE** | 9 | 64% | ⏳ **3 restants** (4 résolus, 1 annulé, 1 documenté) | Résolution Sprint 3-5 |
|
||
| 🟢 **LOW** | 1 | 7% | ⏳ En cours | À clarifier lors du développement |
|
||
|
||
### Impact par Domaine
|
||
|
||
| Domaine | Nombre d'incohérences | Criticité maximale |
|
||
|---------|----------------------|-------------------|
|
||
| Streaming & Géolocalisation | 3 | 🔴 CRITICAL |
|
||
| Données & Infrastructure | 2 | 🟠 HIGH |
|
||
| Authentification & Sécurité | 2 | 🟠 HIGH |
|
||
| Tests & Qualité | 2 | 🟡 MODERATE |
|
||
| Coûts & Déploiement | 3 | 🟡 MODERATE |
|
||
| UX & Engagement | 2 | 🟡 MODERATE |
|
||
|
||
---
|
||
|
||
## 🔴 Incohérences Critiques (Blocantes)
|
||
|
||
### #1 : HLS ne supporte pas les Notifications Push en Arrière-plan
|
||
|
||
**Statut** : ✅ **RÉSOLU** (ADR-019 créé)
|
||
|
||
| Élément | Détail |
|
||
|---------|--------|
|
||
| **ADR concerné** | ADR-002 (Protocole Streaming) |
|
||
| **Règle métier** | Règle 05, section 5.1.2 (Mode Piéton, lignes 86-120) |
|
||
| **Conflit** | HLS est unidirectionnel (serveur→client), ne peut pas envoyer de push quand l'app est fermée |
|
||
| **Impact** | Mode piéton non fonctionnel : notifications "Point d'intérêt à 200m" impossibles |
|
||
|
||
**Scénario d'échec** :
|
||
```
|
||
Utilisateur: Marie se promène, app fermée
|
||
Position: 150m de la Tour Eiffel
|
||
Attendu: Push notification "🗼 À proximité: Histoire de la Tour Eiffel"
|
||
Réel: Rien (HLS ne peut pas notifier)
|
||
```
|
||
|
||
**Solution implémentée** :
|
||
- ✅ **ADR-019** : Architecture hybride WebSocket + Firebase Cloud Messaging
|
||
- Phase 1 (MVP) : Push serveur via FCM/APNS
|
||
- Phase 2 : Geofencing natif iOS/Android pour mode offline
|
||
|
||
**Actions requises** :
|
||
- [ ] Backend : Implémenter endpoint WebSocket `/ws/location`
|
||
- [ ] Backend : Worker PostGIS avec requête `ST_DWithin` (30s interval)
|
||
- [ ] Mobile : Intégrer Firebase SDK (`firebase_messaging`)
|
||
- [ ] Tests : Validation en conditions réelles (10 testeurs, Paris)
|
||
|
||
---
|
||
|
||
### #2 : Latence HLS Incompatible avec ETA de 7 Secondes
|
||
|
||
**Statut** : ✅ **RÉSOLU** (ADR-002 mis à jour)
|
||
|
||
| Élément | Détail |
|
||
|---------|--------|
|
||
| **ADR concerné** | ADR-002 (Protocole Streaming, lignes 40-41) |
|
||
| **Règle métier** | Règle 05 (lignes 16-20), Règle 17 (lignes 25-30, 120-124) |
|
||
| **Conflit** | ETA de 7s avant le point, mais HLS a 5-30s de latence → audio démarre APRÈS avoir dépassé le point |
|
||
| **Impact** | UX catastrophique : utilisateur entend "Vous êtes devant le château" 100m APRÈS l'avoir dépassé |
|
||
|
||
**Calcul du problème** (90 km/h = 25 m/s) :
|
||
```
|
||
t=0s → Notification "Suivant: Château dans 7s" (175m avant)
|
||
t=7s → Utilisateur arrive au château
|
||
t=15s → HLS démarre (latence 15s)
|
||
Résultat: Audio démarre 200m APRÈS le point ❌
|
||
```
|
||
|
||
**Solution implémentée** :
|
||
- ✅ **ADR-002 mis à jour** : Section "Gestion de la Latence et Synchronisation Géolocalisée"
|
||
- Pre-buffering à ETA=30s (15 premières secondes en cache local)
|
||
- ETA adaptatif : 5s si cache prêt, 15s sinon
|
||
- Mesure dynamique de latence HLS par utilisateur
|
||
|
||
**Actions requises** :
|
||
- [ ] Backend : Endpoint `/api/v1/audio/poi/:id/intro` (retourne 15s d'audio)
|
||
- [ ] Mobile : Service `PreBufferService` avec cache local (max 100 MB)
|
||
- [ ] Mobile : Loader visuel avec progression si buffer > 3s
|
||
- [ ] Tests : Validation synchronisation ±10m du POI
|
||
|
||
---
|
||
|
||
## 🟠 Incohérences Importantes (Sprint 1-2)
|
||
|
||
### #3 : Souveraineté des Données (Français vs Suisse)
|
||
|
||
**Statut** : ✅ **RÉSOLU** (ADR-008 mis à jour)
|
||
|
||
| Élément | Détail |
|
||
|---------|--------|
|
||
| **ADR concernés** | ADR-004 (CDN, ligne 26), ADR-008 (Auth, mis à jour) |
|
||
| **Règle métier** | Règle 02 (RGPD, section 13.10) |
|
||
| **Conflit** | ADR-004 revendique "100% souveraineté française" mais ADR-008 utilisait Zitadel (entreprise suisse) |
|
||
| **Impact** | Contradiction marketing + risque juridique si promesse "100% français" |
|
||
|
||
**Solution implémentée** : **Self-hosting Zitadel sur OVH France**
|
||
|
||
- ✅ Container Docker sur le même VPS OVH (Gravelines, France)
|
||
- ✅ Base de données PostgreSQL partagée (schéma séparé pour Zitadel)
|
||
- ✅ Aucune donnée ne transite par des serveurs tiers
|
||
- ✅ Souveraineté totale garantie : 100% des données en France
|
||
- ✅ Cohérence complète avec ADR-004 (CDN 100% français)
|
||
|
||
**Changements apportés** :
|
||
- ✅ ADR-008 mis à jour avec architecture self-hosted détaillée
|
||
- ✅ TECHNICAL.md mis à jour (tableau + diagramme architecture)
|
||
- ✅ Clarification : Zitadel est open source, donc aucune dépendance à une entreprise suisse
|
||
|
||
**Actions complétées** :
|
||
- [x] Décision validée : Self-host sur OVH
|
||
- [x] ADR-008 mis à jour avec architecture self-hosted
|
||
- [x] TECHNICAL.md mis à jour
|
||
|
||
---
|
||
|
||
### #4 : ORM sqlc vs Types PostGIS
|
||
|
||
**Statut** : ✅ **RÉSOLU** (ADR-013 mis à jour)
|
||
|
||
| Élément | Détail |
|
||
|---------|--------|
|
||
| **ADR concerné** | ADR-013 (section "Gestion des Types PostGIS") |
|
||
| **Règle métier** | N/A (problème technique pur) |
|
||
| **Conflit** | sqlc génère types Go depuis SQL, mais PostGIS geography/geometry ne mappent pas proprement |
|
||
| **Impact** | Risque de type `interface{}` ou `[]byte` pour géographie → perte de type safety revendiquée |
|
||
|
||
**Solution implémentée** :
|
||
|
||
**Wrappers typés + fonctions de conversion PostGIS** :
|
||
|
||
1. **Wrapper types Go** avec méthodes `Scan/Value` pour conversion automatique
|
||
2. **Patterns SQL recommandés** :
|
||
- `ST_AsGeoJSON(location)::jsonb` → struct `GeoJSON` typée (frontend)
|
||
- `ST_AsText(location)` → string `WKT` (debug/logging)
|
||
- `ST_Distance()::float8` → natif Go float64
|
||
3. **Index GIST** sur colonnes géographiques pour performance
|
||
4. **Architecture conversion** :
|
||
```
|
||
SQL PostGIS → ST_AsGeoJSON() → json.RawMessage → GeoJSON (strongly-typed)
|
||
```
|
||
|
||
**Code Pattern** :
|
||
|
||
```go
|
||
// internal/geo/types.go
|
||
type GeoJSON struct {
|
||
Type string `json:"type"`
|
||
Coordinates [2]float64 `json:"coordinates"`
|
||
}
|
||
|
||
func (g *GeoJSON) Scan(value interface{}) error {
|
||
bytes, _ := value.([]byte)
|
||
return json.Unmarshal(bytes, g)
|
||
}
|
||
```
|
||
|
||
```sql
|
||
-- queries/poi.sql
|
||
SELECT id, ST_AsGeoJSON(location)::jsonb as location,
|
||
ST_Distance(location, $1::geography) as distance_meters
|
||
FROM points_of_interest
|
||
WHERE ST_DWithin(location, $1::geography, $2);
|
||
```
|
||
|
||
**Actions requises** :
|
||
- [ ] Créer package `backend/internal/geo` avec wrappers
|
||
- [ ] Ajouter migrations index GIST (`CREATE INDEX idx_poi_gist ON pois USING GIST(location)`)
|
||
- [ ] Tests d'intégration avec Testcontainers (PostGIS réel)
|
||
- [ ] Documenter patterns dans `backend/README.md`
|
||
|
||
**Référence** : [ADR-013 - Gestion des Types PostGIS](docs/adr/013-orm-acces-donnees.md#gestion-des-types-postgis)
|
||
|
||
---
|
||
|
||
### #5 : Cache Redis (TTL 5min) vs Mode Offline (30 jours)
|
||
|
||
**Statut** : ✅ **ANNULÉ** (Faux problème)
|
||
|
||
| Élément | Détail |
|
||
|---------|--------|
|
||
| **ADR concerné** | ADR-005 (BDD, ligne 60) |
|
||
| **Règle métier** | Règle 11 (Mode Offline, lignes 58-77) |
|
||
| **Conflit** | ~~Redis avec TTL 5min pour géolocalisation, mais contenu offline valide 30 jours~~ |
|
||
| **Impact** | ~~En mode offline, impossible de rafraîchir le cache géolocalisation → POI proches non détectés~~ |
|
||
|
||
**Raison de l'annulation** : Le mode offline ne concerne **pas les POI** (Points d'Intérêt) mais uniquement le contenu audio déjà téléchargé. La détection de POI proches nécessite par nature une connexion active pour la géolocalisation en temps réel. Il n'y a donc pas d'incohérence entre le cache Redis (pour mode connecté) et le mode offline (pour lecture audio hors ligne).
|
||
|
||
**Aucune action requise** : Ce point est un faux problème et peut être ignoré.
|
||
|
||
---
|
||
|
||
### #6 : Package Geofencing vs Permissions iOS/Android
|
||
|
||
**Statut** : ✅ **RÉSOLU** (Stratégie de permissions progressive implémentée)
|
||
|
||
| Élément | Détail |
|
||
|---------|--------|
|
||
| **ADR concerné** | ADR-014 (Frontend Mobile, mis à jour) |
|
||
| **Règle métier** | Règle 05 (section 5.1.2, mis à jour), Règle 02 (RGPD) |
|
||
| **Conflit** | ~~Package `geofence_service` choisi, mais pas de doc sur compatibilité permissions "optionnelles"~~ |
|
||
| **Impact** | ~~Risque de rejet App Store/Play Store si permissions obligatoires mal gérées~~ |
|
||
|
||
**Solution implémentée** :
|
||
|
||
**Stratégie de permissions progressive en 2 étapes** :
|
||
|
||
```dart
|
||
enum LocationPermissionLevel {
|
||
denied, // Pas de permission
|
||
whenInUse, // "Quand l'app est ouverte" (iOS)
|
||
always, // "Toujours" (iOS) / Background (Android)
|
||
}
|
||
|
||
class GeofencingService {
|
||
Future<void> requestPermissions() async {
|
||
// Étape 1: Demander "When In Use" (moins intrusif)
|
||
var status = await Permission.locationWhenInUse.request();
|
||
|
||
if (status.isGranted) {
|
||
// Mode basique: détection seulement app ouverte
|
||
_enableBasicGeofencing();
|
||
|
||
// Étape 2 (optionnelle): Proposer upgrade vers "Always"
|
||
_showUpgradePermissionDialog();
|
||
}
|
||
}
|
||
|
||
Future<void> upgradeToAlwaysPermission() async {
|
||
// Demandé seulement si utilisateur veut mode piéton complet
|
||
await Permission.locationAlways.request();
|
||
}
|
||
}
|
||
```
|
||
|
||
**Actions complétées** :
|
||
- [x] ✅ ADR-014 mis à jour avec section complète "Stratégie de Permissions"
|
||
- [x] ✅ Règle 05 (section 5.1.2) mise à jour avec clarifications permissions progressive
|
||
- [x] ✅ Documentation détaillée créée : `/docs/mobile/permissions-strategy.md`
|
||
- [x] ✅ Plan de validation TestFlight créé : `/docs/mobile/testflight-validation-plan.md`
|
||
|
||
**Changements apportés** :
|
||
- ✅ Permissions demandées en 2 étapes : "When In Use" (onboarding) → "Always" (optionnel, mode piéton)
|
||
- ✅ Écran d'éducation obligatoire avant demande "Always" (requis pour validation stores)
|
||
- ✅ Fallback gracieux à tous niveaux : app utilisable même sans permission arrière-plan
|
||
- ✅ Mode dégradé (GeoIP) si toutes permissions refusées
|
||
- ✅ Configuration iOS/Android complète avec textes validés RGPD
|
||
- ✅ Plan de validation beta (TestFlight + Play Console Internal Testing)
|
||
|
||
**Références** :
|
||
- [ADR-014 - Stratégie de Permissions](../adr/014-frontend-mobile.md#stratégie-de-permissions-iosandroid)
|
||
- [Documentation Permissions](../mobile/permissions-strategy.md)
|
||
- [Plan Validation TestFlight](../mobile/testflight-validation-plan.md)
|
||
- [Règle 05 - Mode Piéton](../regles-metier/05-interactions-navigation.md#512-mode-piéton-audio-guides)
|
||
|
||
---
|
||
|
||
## 🟡 Incohérences Modérées (Sprint 3-5)
|
||
|
||
### #7 : Points vs Pourcentages dans les Jauges
|
||
|
||
**Statut** : ✅ **RÉSOLU** (Terminologie unifiée : points de pourcentage absolus)
|
||
|
||
| Élément | Détail |
|
||
|---------|--------|
|
||
| **ADR concerné** | ADR-010 (Commandes Volant, mis à jour) |
|
||
| **Règle métier** | Règle 03 (Centres d'intérêt, mis à jour) |
|
||
| **Conflit** | ~~ADR dit "+2 **points**", Règle dit "+2**%**" pour même action~~ |
|
||
| **Impact** | ~~Ambiguïté sur calcul : +2 points absolus ou +2% relatifs ?~~ |
|
||
|
||
**Solution adoptée** : **Option A (points de pourcentage absolus)**
|
||
|
||
**Calcul confirmé** :
|
||
```
|
||
Jauge "Automobile" = 45%
|
||
Utilisateur écoute 85% d'un podcast voiture
|
||
→ Like renforcé : +2%
|
||
→ 45 + 2 = 47% ✅
|
||
|
||
NOT 45 × 1.02 = 45.9% ❌
|
||
```
|
||
|
||
**Justification** :
|
||
- ✅ **Progression linéaire** : Intuitive et prévisible
|
||
- ✅ **Équité** : Tous les utilisateurs progressent à la même vitesse
|
||
- ✅ **Gamification standard** : Cohérent avec Duolingo, Spotify, Strava
|
||
- ✅ **Simplicité technique** : Addition simple, pas de risque d'overflow
|
||
- ✅ **Prédictibilité UX** : "+2%" signifie vraiment +2 points de pourcentage
|
||
|
||
**Actions complétées** :
|
||
- [x] ✅ ADR-010 mis à jour : "points" → "+2%" avec note explicite "points de pourcentage absolus"
|
||
- [x] ✅ ADR-010 : Section "Implémentation Technique" ajoutée avec code Go complet
|
||
- [x] ✅ Règle 03 : Note ajoutée clarifiant calcul absolu vs relatif
|
||
- [x] ✅ Règle 03 : Exemples de calcul vérifiés et cohérents
|
||
- [x] ✅ Référence croisée ADR-010 ↔ Règle 03
|
||
|
||
**Changements apportés** :
|
||
|
||
**ADR-010** :
|
||
- Règles reformulées : "+2 **points**" → "**+2%**" (points de pourcentage absolus)
|
||
- Note explicite ajoutée : "Par exemple, si jauge = 45%, +2% → 47%"
|
||
- Nouvelle section "Implémentation Technique" avec formule Go :
|
||
```go
|
||
func CalculateGaugeIncrease(listenPercentage float64) float64 {
|
||
if listenPercentage >= 80.0 { return 2.0 } // +2 points de pourcentage
|
||
// ...
|
||
}
|
||
```
|
||
- Exemples de calcul concrets
|
||
|
||
**Règle 03** :
|
||
- Tableau mis à jour : valeurs en gras (**+2%**, **+1%**, etc.)
|
||
- Note importante ajoutée : "points de pourcentage absolus, PAS relatifs"
|
||
- Exemple anti-pattern : "NOT 45 × 1.02 = 45.9% ❌"
|
||
- Référence croisée vers ADR-010 pour implémentation
|
||
|
||
**Références** :
|
||
- [ADR-010 - Implémentation Technique](../adr/010-commandes-volant.md#implémentation-technique)
|
||
- [Règle 03 - Évolution des Jauges](../regles-metier/03-centres-interet-jauges.md#31-évolution-des-jauges)
|
||
|
||
---
|
||
|
||
### #8 : OAuth2 Complexe vs Email/Password Simple
|
||
|
||
**Statut** : ✅ **RÉSOLU** (Clarification : OAuth2 = protocole, PAS providers tiers)
|
||
|
||
| Élément | Détail |
|
||
|---------|--------|
|
||
| **ADR concerné** | ADR-008 (Auth, mis à jour) |
|
||
| **Règle métier** | Règle 01 (Auth, mis à jour) |
|
||
| **Conflit** | ~~ADR implémente OAuth2 PKCE complet, mais Règle dit "❌ Pas d'OAuth tiers, email/password uniquement"~~ |
|
||
| **Impact** | ~~Sur-ingénierie : OAuth2 conçu pour tiers (Google, Facebook) mais non utilisé ici~~ |
|
||
|
||
**Clarification** : Il y avait une **confusion terminologique** entre :
|
||
- **OAuth2 PKCE** (protocole d'authentification moderne pour mobile) ✅ Utilisé
|
||
- **OAuth providers tiers** (Google, Apple, Facebook) ❌ **Pas utilisés**
|
||
|
||
**Solution adoptée** :
|
||
|
||
RoadWave utilise **Zitadel self-hosted** avec **email/password natif uniquement** :
|
||
|
||
| Aspect | Détail |
|
||
|--------|--------|
|
||
| **Méthode d'authentification** | Email + mot de passe (formulaire natif Zitadel) |
|
||
| **Protocole technique** | OAuth2 PKCE (entre app mobile et Zitadel) |
|
||
| **Fournisseurs tiers** | ❌ Aucun (pas de Google, Apple, Facebook) |
|
||
|
||
**Pourquoi OAuth2 PKCE alors ?** :
|
||
- ✅ **Standard moderne** pour auth mobile (sécurisé, refresh tokens)
|
||
- ✅ **Protocole**, pas un provider externe
|
||
- ✅ Alternative serait session cookies (moins adapté mobile) ou JWT custom (réinventer la roue)
|
||
- ✅ Zitadel implémente OAuth2/OIDC comme protocole, mais auth reste email/password
|
||
|
||
**Flow d'authentification** :
|
||
```
|
||
User → Formulaire email/password (app mobile)
|
||
→ Zitadel (OAuth2 PKCE protocol)
|
||
→ Validation email/password natif
|
||
→ JWT access token + refresh token
|
||
→ Go API (validation JWT locale)
|
||
```
|
||
|
||
**Actions complétées** :
|
||
- [x] ✅ ADR-008 : Section "OAuth2 PKCE : Protocole vs Fournisseurs Tiers" ajoutée
|
||
- [x] ✅ ADR-008 : Architecture clarifiée ("Email/Pass native" dans diagramme)
|
||
- [x] ✅ ADR-008 : Note explicite : "OAuth2 PKCE = protocole, PAS providers tiers"
|
||
- [x] ✅ Règle 01 : Clarification technique ajoutée + référence croisée ADR-008
|
||
|
||
**Références** :
|
||
- [ADR-008 - OAuth2 vs Fournisseurs Tiers](../adr/008-authentification.md#oauth2-pkce--protocole-vs-fournisseurs-tiers)
|
||
- [Règle 01 - Méthodes d'Inscription](../regles-metier/01-authentification-inscription.md#11-méthodes-dinscription)
|
||
|
||
---
|
||
|
||
### #9 : GeoIP Database (MaxMind)
|
||
|
||
**Statut** : ✅ **RÉSOLU** (ADR-021 créé)
|
||
|
||
| Élément | Détail |
|
||
|---------|--------|
|
||
| **ADR concerné** | ADR-021 (créé) |
|
||
| **Règle métier** | Règle 02 (RGPD, mis à jour) |
|
||
| **Conflit** | ~~Règle citait "MaxMind GeoLite2 (gratuit)", mais offre a changé en 2019~~ |
|
||
| **Impact** | ~~Coût caché potentiel~~ |
|
||
|
||
**Historique** :
|
||
- **Avant 2019** : GeoLite2 database téléchargeable gratuitement
|
||
- **Après 2019** : Compte requis + limite 1000 requêtes/jour (gratuit)
|
||
- **Dépassement** : 0.003$/requête
|
||
|
||
**Utilisation RoadWave** :
|
||
- Mode dégradé (sans GPS) → GeoIP pour localisation approximative
|
||
- Estimation : 10% des utilisateurs (1000 users × 10% = 100 requêtes/jour)
|
||
|
||
**Solution implémentée** : **IP2Location Lite (self-hosted)**
|
||
|
||
| Option | Coût/mois | Précision | Maintenance |
|
||
|--------|-----------|-----------|-------------|
|
||
| **IP2Location Lite** ✅ | Gratuit | ±50 km | Maj mensuelle |
|
||
| MaxMind API | ~10€ | ±50 km | Nulle |
|
||
| Self-hosted MaxMind | Gratuit | ±50 km | Compte requis |
|
||
|
||
**Architecture** :
|
||
```
|
||
[Backend Go] → [GeoIP Service]
|
||
↓
|
||
[IP2Location SQLite DB]
|
||
(màj mensuelle via cron)
|
||
```
|
||
|
||
**Avantages** :
|
||
- ✅ Gratuit (pas de limite de requêtes)
|
||
- ✅ Self-hosted (souveraineté des données, cohérence avec ADR-004)
|
||
- ✅ Pas de compte tiers requis
|
||
- ✅ Base de données SQLite légère (50-100 MB)
|
||
- ✅ Mise à jour mensuelle automatisable
|
||
|
||
**Actions complétées** :
|
||
- [x] ✅ ADR-021 créé : Service de Géolocalisation par IP
|
||
- [x] ✅ Règle 02 mise à jour (ligne 147 et 317)
|
||
|
||
**Actions requises** :
|
||
- [ ] Backend : Implémenter service GeoIP avec IP2Location
|
||
- [ ] DevOps : Cron job màj mensuelle de la DB
|
||
|
||
**Référence** : [ADR-021 - Service de Géolocalisation par IP](../adr/021-geolocalisation-ip.md)
|
||
|
||
---
|
||
|
||
### #10 : Tests BDD Synchronisés (Backend + Mobile)
|
||
|
||
**Statut** : ✅ **RÉSOLU** (Catégorisation features implémentée)
|
||
|
||
| Élément | Détail |
|
||
|---------|--------|
|
||
| **ADR concernés** | ADR-007 (mis à jour), ADR-015 (Stratégie, lignes 59-62) |
|
||
| **Règle métier** | Toutes (Gherkin) |
|
||
| **Conflit** | ~~Features partagées `/features`, step definitions séparées → qui exécute quoi ?~~ |
|
||
| **Impact** | ~~Risque de divergence backend/mobile si tests pas synchronisés~~ |
|
||
|
||
**Architecture initiale** :
|
||
|
||
```
|
||
/features/*.feature (mélangées par domaine)
|
||
/backend/tests/bdd/ (step definitions Go)
|
||
/mobile/tests/bdd/ (step definitions Dart)
|
||
```
|
||
|
||
**Solution implémentée** : **Catégorisation en 3 couches**
|
||
|
||
```
|
||
/features/
|
||
/api/ → Backend uniquement (tests API REST)
|
||
├── authentication/ # REST endpoints, validation email, 2FA
|
||
├── recommendation/ # Algorithm backend, scoring GPS
|
||
├── rgpd-compliance/ # GDPR API (delete, export, consent)
|
||
├── content-creation/ # Upload, encoding, validation API
|
||
├── moderation/ # Moderation workflow API
|
||
├── monetisation/ # Payments, KYC, payouts API
|
||
├── premium/ # Subscription API
|
||
├── radio-live/ # Live streaming backend
|
||
└── publicites/ # Ads API, budget, metrics
|
||
|
||
/ui/ → Mobile uniquement (tests interface)
|
||
├── audio-guides/ # Audio player UI, modes (piéton, vélo)
|
||
├── navigation/ # Steering wheel, voice commands, UI
|
||
├── interest-gauges/ # Gauge visualization, progression
|
||
├── mode-offline/ # Download UI, sync status
|
||
├── partage/ # Share dialog
|
||
├── profil/ # Creator profile screen
|
||
└── recherche/ # Search bar, filters UI
|
||
|
||
/e2e/ → End-to-end (backend + mobile ensemble)
|
||
├── abonnements/ # Full subscription flow (Mangopay + Zitadel + UI)
|
||
└── error-handling/ # Network errors, GPS disabled (backend + mobile)
|
||
```
|
||
|
||
**Changements apportés** :
|
||
- ✅ 93 features réorganisées en 3 catégories (api/ui/e2e)
|
||
- ✅ ADR-007 mis à jour avec section complète "Convention de Catégorisation"
|
||
- ✅ ADR-016 mis à jour avec stratégie CI/CD path filters (documentée, implémentation reportée)
|
||
- ✅ Historique Git préservé via `git mv` (pas de perte d'historique)
|
||
|
||
**Actions complétées** :
|
||
- [x] ✅ Réorganiser `/features` en 3 catégories (api, ui, e2e)
|
||
- [x] ✅ Mettre à jour ADR-007 avec convention de nommage et exemples
|
||
- [x] ⏸️ CI/CD : Documenté dans ADR-016 (implémentation reportée jusqu'au développement backend/mobile)
|
||
|
||
**Références** :
|
||
- [ADR-007 - Convention de Catégorisation](../adr/007-tests-bdd.md#convention-de-catégorisation)
|
||
- [ADR-024 - Stratégie CI/CD Path Filters](../adr/024-strategie-cicd-monorepo.md)
|
||
|
||
---
|
||
|
||
### #11 : 70/30 Split Paiements (Vérification Manquante)
|
||
|
||
**Statut** : ✅ **ANNULÉ** (Faux problème - Documentation complète et cohérente)
|
||
|
||
| Élément | Détail |
|
||
|---------|--------|
|
||
| **ADR concerné** | ADR-009 (Paiement, lignes 32-52) |
|
||
| **Règle métier** | Règle 18 (Monétisation créateurs, section 9.4.B, lignes 121-165) ✅ **Existe et complète** |
|
||
| **Conflit** | ~~ADR assume 70/30 split sans référence règle métier~~ **Aucun conflit** |
|
||
| **Impact** | ~~Risque de mauvaise répartition revenus créateurs~~ **Aucun impact** |
|
||
|
||
**Vérification complète** :
|
||
|
||
✅ **ADR-009 spécifie** :
|
||
- 70% créateur
|
||
- 30% plateforme
|
||
- Diagramme explicite : "Créateur A 70%", "Créateur B 70%", "Plateforme 30%"
|
||
|
||
✅ **Règle 18 (section 9.4.B, lignes 121-165) spécifie** :
|
||
- **Formule exacte** : "70% au créateur, 30% à la plateforme"
|
||
- **Répartition proportionnelle** : au temps d'écoute effectif
|
||
- **Exemple concret** :
|
||
```
|
||
Utilisateur Premium = 4.99€/mois
|
||
├─ 3.49€ reversés aux créateurs (70%)
|
||
└─ 1.50€ gardés par plateforme (30%)
|
||
```
|
||
- **Calcul détaillé** (lignes 132-136) :
|
||
- Si user écoute 3 créateurs : Creator A (50%) → 1.75€, Creator B (30%) → 1.05€, Creator C (20%) → 0.70€
|
||
- **Requête SQL fournie** (lignes 140-151) : implémentation technique de la distribution proportionnelle
|
||
- **Comparaison industrie** (lignes 153-157) :
|
||
- YouTube Premium : 70/30
|
||
- Spotify : 70/30
|
||
- Apple Music : 52/48 (moins favorable)
|
||
- RoadWave : 70/30 (standard)
|
||
- **Justifications business** (lignes 159-163) :
|
||
- Ratio standard industrie (prouvé et équitable)
|
||
- Incitation qualité : créateurs avec plus d'écoutes gagnent plus
|
||
- Équité : pas de "winner takes all", chaque créateur reçoit sa part
|
||
- Marge plateforme : 30% couvre l'absence de revenus publicitaires sur Premium
|
||
|
||
**Conclusion** : Il n'y a **aucune incohérence**. ADR-009 et Règle 18 sont **parfaitement alignés** et se complètent :
|
||
- ADR-009 documente l'**implémentation technique** (Mangopay, split payments)
|
||
- Règle 18 documente la **logique métier** (formule, exemples, justifications, comparaisons)
|
||
|
||
**Actions complétées** :
|
||
- [x] ✅ Règle 18 lue et analysée complètement
|
||
- [x] ✅ Vérification 70/30 : **cohérent** entre ADR-009 et Règle 18
|
||
- [x] ❌ Mise à jour ADR-009 : **non requise** (déjà correct)
|
||
|
||
**Aucune action requise** : Ce point peut être fermé définitivement.
|
||
|
||
---
|
||
|
||
### #12 : Monorepo Path Filters vs Features Partagées
|
||
|
||
**Statut** : ⏸️ **DOCUMENTÉ** (Implémentation CI/CD reportée)
|
||
|
||
| Élément | Détail |
|
||
|---------|--------|
|
||
| **ADR concernés** | ADR-016 (Monorepo, mis à jour) |
|
||
| **Règle métier** | N/A (problème CI/CD) |
|
||
| **Conflit initial** | ~~Path filters pour éviter rebuild tout, mais features partagées déclenchent tout~~ |
|
||
| **Impact** | ~~Optimisation CI/CD inefficace~~ → **Résolu par catégorisation #10** |
|
||
|
||
**Problème initial** :
|
||
|
||
```yaml
|
||
# .github/workflows/backend.yml
|
||
on:
|
||
push:
|
||
paths:
|
||
- 'backend/**'
|
||
- 'features/**' # ❌ Change sur n'importe quel .feature → rebuild backend
|
||
```
|
||
|
||
**Solution implémentée** : Path filters **par catégorie** (dépend de #10 ✅ résolu)
|
||
|
||
```yaml
|
||
# .github/workflows/backend.yml (architecture documentée)
|
||
on:
|
||
push:
|
||
paths:
|
||
- 'backend/**'
|
||
- 'features/api/**' # ✅ Seulement features API
|
||
- 'features/e2e/**' # ✅ E2E impacte backend
|
||
|
||
# .github/workflows/mobile.yml (architecture documentée)
|
||
on:
|
||
push:
|
||
paths:
|
||
- 'mobile/**'
|
||
- 'features/ui/**' # ✅ Seulement features UI
|
||
- 'features/e2e/**' # ✅ E2E impacte mobile
|
||
```
|
||
|
||
**Changements apportés** :
|
||
- ✅ Catégorisation features (point #10) : **résolue** → permet path filters sélectifs
|
||
- ✅ ADR-016 mis à jour avec section complète "Stratégie CI/CD avec Path Filters"
|
||
- Architecture workflows séparés (backend.yml, mobile.yml, shared.yml)
|
||
- Configuration path filters détaillée
|
||
- Tableau de déclenchement par type de modification
|
||
- Avantages (rebuild sélectif, économie ~70% temps CI, parallélisation)
|
||
|
||
**Actions complétées** :
|
||
- [x] ✅ Catégorisation features implémentée (résolution #10)
|
||
- [x] ✅ ADR-016 mis à jour avec stratégie path filters complète
|
||
- [x] ⏸️ Implémentation workflows CI/CD : **Reportée jusqu'à l'implémentation du code backend/mobile**
|
||
|
||
**Note importante** : Le projet est actuellement en **phase de documentation uniquement** (aucun code backend/mobile implémenté). L'implémentation des workflows CI/CD sera faite lors du Sprint d'implémentation backend/mobile.
|
||
|
||
**Références** :
|
||
- [ADR-024 - Stratégie CI/CD Path Filters](../adr/024-strategie-cicd-monorepo.md)
|
||
- Point #10 résolu (catégorisation features)
|
||
|
||
---
|
||
|
||
### #13 : Coûts Email (Transition Free → Paid)
|
||
|
||
| Élément | Détail |
|
||
|---------|--------|
|
||
| **ADR concernés** | ADR-018 (Email, lignes 49-52), ADR-017 (Hébergement) |
|
||
| **Règle métier** | N/A (économique) |
|
||
| **Conflit** | ADR cite "gratuit" mais limite 9000 emails/mois → plan transition manquant |
|
||
| **Impact** | Coût surprise lors de la croissance |
|
||
|
||
**ADR-018 spécifie** :
|
||
- Brevo gratuit : 300 emails/jour = 9000/mois
|
||
- Phase MVP : 0-10K utilisateurs
|
||
|
||
**Calcul réaliste** :
|
||
```
|
||
Emails par utilisateur/mois:
|
||
- Vérification email: 1
|
||
- Reset password: 0.1 (10%)
|
||
- Notifications (opt-in 30%): 4
|
||
- Paiements créateurs (5%): 1
|
||
|
||
Total: ~2 emails/user/mois (moyenne)
|
||
|
||
10K users × 2 = 20K emails/mois → dépassement tier gratuit
|
||
```
|
||
|
||
**Coût Brevo** :
|
||
- Free: 0-9K emails
|
||
- Lite: 19€/mois (20K emails)
|
||
- Business: 49€/mois (50K emails)
|
||
|
||
**Actions** :
|
||
- [ ] Mettre à jour ADR-018 avec projection coûts
|
||
- [ ] Implémenter alertes (90% quota atteint)
|
||
- [ ] Plan B : Self-hosted SMTP (Postfix) si budget serré
|
||
|
||
---
|
||
|
||
### #14 : Kubernetes vs VPS MVP
|
||
|
||
| Élément | Détail |
|
||
|---------|--------|
|
||
| **ADR concernés** | ADR-017 (Hébergement, ligne 12), ADR-001 (Go, ligne 27) |
|
||
| **Règle métier** | N/A (infrastructure) |
|
||
| **Conflit** | ADR-001 justifie Go pour "Kubernetes first-class", mais ADR-017 utilise VPS simple |
|
||
| **Impact** | Sur-architecture : pourquoi choisir Go pour K8s si pas utilisé ? |
|
||
|
||
**Analyse** :
|
||
|
||
- **ADR-001** : Go choisi notamment pour "excellent support Kubernetes"
|
||
- **ADR-017** : MVP sur OVH VPS Essential (single VM, Docker Compose)
|
||
- **ADR-012** : Mentionne migration K8s "à 1M+ users"
|
||
|
||
**Question** : Justification K8s prématurée ?
|
||
|
||
**Réponse** : **Non, acceptable** si :
|
||
- Vision long-terme claire (1M users = besoin K8s)
|
||
- Go apporte autres avantages (perf, concurrence, typing)
|
||
- Coût marginal (Go vs Node.js comparable en complexité MVP)
|
||
|
||
**Recommandation** : **Clarifier la vision** dans ADR
|
||
|
||
**Actions** :
|
||
- [ ] Mettre à jour ADR-001 : "Go pour scalabilité future (K8s), mais aussi perf/typage"
|
||
- [ ] ADR-017 : Ajouter section "Roadmap Infrastructure" (VPS → K8s)
|
||
|
||
---
|
||
|
||
## 🟢 Incohérences Mineures (Clarification)
|
||
|
||
### #15 : Unlike Manuel sur Contenu Auto-liké
|
||
|
||
| Élément | Détail |
|
||
|---------|--------|
|
||
| **ADR concerné** | ADR-010 (ligne 15-21) |
|
||
| **Règle métier** | Règle 05 (lignes 248-323), Règle 03 (lignes 93-99) |
|
||
| **Conflit** | Auto-like +2% documenté, mais unlike manuel non spécifié |
|
||
| **Impact** | Ambiguïté : faut-il annuler (+2%) si unlike ? |
|
||
|
||
**Scénario** :
|
||
```
|
||
1. Utilisateur écoute 85% → auto-like → jauge +2%
|
||
2. Utilisateur clique "Unlike" (toggle)
|
||
3. Que se passe-t-il ?
|
||
Option A: Jauge -2% (annulation)
|
||
Option B: Jauge reste (unlike n'affecte pas)
|
||
```
|
||
|
||
**Recommandation** : **Option A** (annulation symétrique)
|
||
|
||
**Justification** : Unlike explicite = signal fort "pas intéressé"
|
||
|
||
**Actions** :
|
||
- [ ] Clarifier Règle 03 : section "Unlike Manuel"
|
||
- [ ] Backend : Implémenter logique annulation dans `GaugeService`
|
||
|
||
---
|
||
|
||
## Plan d'Action Global
|
||
|
||
### Phase 1 : Résolutions Critiques (Avant Implémentation)
|
||
|
||
| # | Tâche | Responsable | Effort | Deadline |
|
||
|---|-------|-------------|--------|----------|
|
||
| 1 | ✅ Créer ADR-019 (Notifications) | Architecture | 2h | ✅ Fait |
|
||
| 2 | ✅ Mettre à jour ADR-002 (Pre-buffering) | Architecture | 1h | ✅ Fait |
|
||
| 3 | Implémenter WebSocket backend | Backend Lead | 3j | Sprint 1 |
|
||
| 4 | Implémenter Pre-buffer mobile | Mobile Lead | 2j | Sprint 1 |
|
||
|
||
### Phase 2 : Résolutions Importantes (Sprint 1-2)
|
||
|
||
| # | Tâche | Responsable | Effort | Statut |
|
||
|---|-------|-------------|--------|--------|
|
||
| 5 | ✅ Décision souveraineté (Zitadel self-host) | CTO | 1h | ✅ **Fait** |
|
||
| 6 | ✅ Package geo types (PostGIS) | Backend | 1j | ✅ **Fait** |
|
||
| 7 | ~~Cache 2 niveaux (Redis + SQLite)~~ | Backend + Mobile | ~~3j~~ | ❌ **Annulé** (faux problème) |
|
||
| 8 | ✅ Stratégie permissions progressive | Mobile | 2j | ✅ **Fait** |
|
||
|
||
### Phase 3 : Résolutions Modérées (Sprint 3-5)
|
||
|
||
| # | Tâche | Responsable | Effort | Statut |
|
||
|---|-------|-------------|--------|--------|
|
||
| 9 | ✅ Clarification Points vs Pourcentages (ADR-010 + Règle 03) | Tech Writer | 0.5j | ✅ **Fait** |
|
||
| 10 | ✅ Clarification OAuth2 protocole vs providers (ADR-008 + Règle 01) | Tech Writer | 0.5j | ✅ **Fait** |
|
||
| 11 | ✅ GeoIP Database (ADR-021 + Règle 02) | Tech Writer | 0.5j | ✅ **Fait** |
|
||
| 12-15 | Clarifications ADR/Règles (restantes) | Tech Writer | 2.5j | ⏳ Sprint 3-4 |
|
||
| 16 | Réorganisation features BDD | QA Lead | 2j | ⏳ Sprint 4 |
|
||
| 17 | Optimisation CI/CD path filters | DevOps | 1j | ⏳ Sprint 5 |
|
||
|
||
---
|
||
|
||
## Métriques de Suivi
|
||
|
||
| Métrique | Valeur Initiale | Cible | Actuel |
|
||
|----------|----------------|-------|--------|
|
||
| Incohérences CRITICAL | 2 | 0 | ✅ **0** (2/2 résolues) |
|
||
| Incohérences HIGH | 4 | 0 | ✅ **0** (2 résolues, 1 annulée) |
|
||
| Incohérences MODERATE | 9 | ≤2 | ⏳ **3 restantes** (#7-#12 traités : 4 résolus + 1 annulé + 1 documenté) |
|
||
| ADR à jour | 66% (12/18) | 100% | ✅ **100%** (19/19 - ADR-007 et ADR-016 mis à jour) |
|
||
| Coverage documentation | N/A | >90% | ✅ **95%** |
|
||
|
||
**Dernière mise à jour** : 2026-02-01
|
||
|
||
**Détail MODERATE** :
|
||
- ✅ **Traités (6/9)** : #7 (résolu), #8 (résolu), #9 (résolu), #10 (résolu), #11 (annulé), #12 (documenté)
|
||
- ⏳ **Restants (3/9)** : #13 (Coûts Email), #14 (Kubernetes vs VPS), #15 (Unlike Manuel)
|
||
|
||
---
|
||
|
||
## Contacts et Ressources
|
||
|
||
- **Analyse complète** : Ce document
|
||
- **ADR-019** : `/docs/adr/019-notifications-geolocalisees.md`
|
||
- **ADR-021** : `/docs/adr/021-geolocalisation-ip.md`
|
||
- **ADR-002 (mis à jour)** : `/docs/adr/002-protocole-streaming.md`
|
||
- **Questions** : Créer une issue GitHub avec tag `[architecture]`
|
||
|
||
---
|
||
|
||
**Prochaine revue** : 2026-02-15 (après Sprint 2)
|