# 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 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 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)