(doc) : ajout et modification de docs après arbitrage

This commit is contained in:
jpgiannetti
2026-01-31 21:09:59 +01:00
parent f99fb3c614
commit 841028d1b2
24 changed files with 3081 additions and 301 deletions

View File

@@ -14,9 +14,9 @@ Cette analyse a identifié **15 incohérences** entre les décisions d'architect
| Sévérité | Nombre | % Total | Statut | Action Required |
|----------|--------|---------|--------|-----------------|
| 🔴 **CRITICAL** | 2 | 13% | ✅ **RÉSOLU** | ~~avant implémentation~~ |
| 🟠 **HIGH** | 4 | 27% | ⏳ 3 restants (1 résolu) | Résolution Sprint 1-2 |
| 🟡 **MODERATE** | 8 | 53% | ⏳ En cours | Résolution Sprint 3-5 |
| 🔴 **CRITICAL** | 2 | 14% | ✅ **RÉSOLU** | ~~avant implémentation~~ |
| 🟠 **HIGH** | 2 | 14% | **RÉSOLU** (2 résolus, 1 annulé) | ~~Résolution Sprint 1-2~~ |
| 🟡 **MODERATE** | 6 | 43% | ⏳ 4 restants (3 résolus) | Résolution Sprint 3-5 |
| 🟢 **LOW** | 1 | 7% | ⏳ En cours | À clarifier lors du développement |
### Impact par Domaine
@@ -24,7 +24,7 @@ Cette analyse a identifié **15 incohérences** entre les décisions d'architect
| Domaine | Nombre d'incohérences | Criticité maximale |
|---------|----------------------|-------------------|
| Streaming & Géolocalisation | 3 | 🔴 CRITICAL |
| Données & Infrastructure | 3 | 🟠 HIGH |
| Données & Infrastructure | 2 | 🟠 HIGH |
| Authentification & Sécurité | 2 | 🟠 HIGH |
| Tests & Qualité | 2 | 🟡 MODERATE |
| Coûts & Déploiement | 3 | 🟡 MODERATE |
@@ -134,106 +134,94 @@ Résultat: Audio démarre 200m APRÈS le point ❌
### #4 : ORM sqlc vs Types PostGIS
**Statut** : ✅ **RÉSOLU** (ADR-013 mis à jour)
| Élément | Détail |
|---------|--------|
| **ADR concernés** | ADR-013 (ORM, lignes 12, 33-40), ADR-005 (BDD, lignes 47-56) |
| **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 |
**Nature du problème** :
**Solution implémentée** :
sqlc génère du code Go depuis SQL, mais les types PostGIS (`geography`, `geometry`) ne sont pas mappés proprement en Go. Résultat : types opaques (`[]byte`, `interface{}`) qui perdent la **type safety** revendiquée dans ADR-013.
**Solution retenue** :
**Wrappers typés + fonctions de conversion PostGIS** :
1. **Wrapper types Go** avec méthodes `Scan/Value` pour conversion automatique
2. **Utiliser les fonctions PostGIS de conversion** :
- `ST_AsGeoJSON()` → struct GeoJSON typée
- `ST_AsText()` → string WKT
- `geography` brut → `pgtype.Point` (lib pgx)
3. **Documenter le pattern** dans ADR-013 section "Gestion des Types PostGIS"
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)
```
**Action** :
- [ ] Créer package `internal/geo` avec wrappers `GeoJSON`, `WKT`
- [ ] Mettre à jour ADR-013 section "Types PostGIS"
- [ ] Documenter pattern dans README backend
**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 |
| **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~~ |
**Analyse du flux** :
**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).
```
Mode connecté:
1. Requête POI proches → Redis (cache 5min)
2. Si miss → PostGIS → Cache Redis
3. ✅ Fonctionne
Mode offline (Règle 11):
1. Requête POI proches → Redis (expiré depuis 6 min)
2. Impossible de requêter PostGIS (pas de réseau) ❌
3. Aucun POI détecté
```
**Solution** :
Stratégie de **cache à 2 niveaux** :
| Cache | TTL | Usage | Invalidation |
|-------|-----|-------|--------------|
| **Redis (L1)** | 5 min | Mode connecté | Automatique |
| **SQLite local (L2)** | 30 jours | Mode offline | Manuelle lors sync |
**Architecture** :
```
[Mode Connecté]
→ Redis (L1) → PostGIS → Cache local SQLite (L2)
[Mode Offline]
→ SQLite local (L2) uniquement
```
**Action** :
- [ ] Backend : Ajouter endpoint `/sync/nearby-pois?lat=X&lon=Y&radius=10km`
- [ ] Mobile : Créer `OfflineCacheService` avec SQLite + index spatial
- [ ] Mettre à jour ADR-005 section "Cache" avec stratégie 2 niveaux
- [ ] Règle 11 : Clarifier sync automatique vs manuel
**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, ligne 48) |
| **Règle métier** | Règle 05 (lignes 86-134), Règle 11 (RGPD, lignes 51-86) |
| **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 |
| **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~~ |
**Problématiques** :
**Solution implémentée** :
1. **iOS** : Permission "Always Location" exige justification stricte (taux refus 70%)
2. **Android** : Background location nécessite déclaration spéciale (depuis Android 10)
3. **Règle métier** : Permissions optionnelles (app utilisable sans "Always Location")
**Package `geofence_service`** :
- ✅ Supporte iOS/Android
- ⚠️ Documentation peu claire sur permissions optionnelles
- ⚠️ Pas de fallback natif si permission refusée
**Solution** :
**Stratégie de permissions progressive** :
**Stratégie de permissions progressive en 2 étapes** :
```dart
enum LocationPermissionLevel {
@@ -263,10 +251,25 @@ class GeofencingService {
}
```
**Actions** :
- [ ] Mettre à jour ADR-014 avec stratégie permissions progressive
- [ ] Créer doc "Permissions Strategy" dans `/docs/mobile/`
- [ ] Tests : Validation rejet App Store (TestFlight beta)
**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)
---
@@ -274,89 +277,129 @@ class GeofencingService {
### #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, lignes 15-21) |
| **Règle métier** | Règle 03 (Centres d'intérêt, lignes 7-14) |
| **Conflit** | ADR dit "+2 **points**", Règle dit "+2**%**" pour même action |
| **Impact** | Ambiguïté sur calcul : +2 points absolus ou +2% relatifs ? |
| **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 ?~~ |
**Exemple du conflit** :
**Solution adoptée** : **Option A (points de pourcentage absolus)**
- **ADR-010 (ligne 18)** : "≥80% d'écoute = +2 **points**"
- **Règle 03 (ligne 9)** : "≥80% d'écoute = +2**%** à la jauge"
**Scénario** :
**Calcul confirmé** :
```
Jauge "Automobile" = 45%
Utilisateur écoute 85% d'un podcast voiture
→ Like renforcé : +2%
→ 45 + 2 = 47% ✅
Option A (points absolus): 45 + 2 = 47%
Option B (pourcentage relatif): 45 * 1.02 = 45.9%
NOT 45 × 1.02 = 45.9% ❌
```
**Recommandation** : **Option A (points absolus)** pour simplicité
**Justification** :
- Progression linéaire plus intuitive
- Évite effet "rich get richer" (jauges hautes progressent + vite)
- Cohérent avec système de gamification classique
- ✅ **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** :
- [ ] Clarifier ADR-010 : remplacer "points" par "points de pourcentage"
- [ ] Clarifier Règle 03 : uniformiser terminologie
- [ ] Backend : Documenter formule exacte dans code
**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, lignes 12, 52-68) |
| **Règle métier** | Règle 01 (Auth, lignes 5-10) |
| **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 |
| **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~~ |
**Analyse** :
**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**
- **ADR-008** : Architecture OAuth2 avec PKCE, refresh tokens, etc.
- **Règle 01** : "❌ Pas de Google, Apple, Facebook OAuth"
**Solution adoptée** :
**Zitadel supporte** :
- OAuth2 (pour intégrations tierces)
- Email/Password natif (ce dont on a besoin)
RoadWave utilise **Zitadel self-hosted** avec **email/password natif uniquement** :
**Question** : Pourquoi implémenter OAuth2 si pas de tiers ?
| 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) |
**Options** :
**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
| Option | Complexité | Justification |
|--------|------------|---------------|
| **A. Garder OAuth2** | Haute | Future-proof pour API partenaires |
| **B. Session simple** | Basse | Suffit pour MVP 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)
```
**Recommandation** : **Option A** (garder OAuth2) si :
- Vision long-terme : API pour partenaires (créateurs, annonceurs)
- Coût marginal : Zitadel gère OAuth2 nativement
**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
Sinon **Option B** (session simple) si MVP pur.
**Actions** :
- [ ] Décision : Confirmer besoin OAuth2 avec product owner
- [ ] Si A : Mettre à jour Règle 01 "OAuth tiers en Phase 2"
- [ ] Si B : Simplifier ADR-008 (session JWT classique)
**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-005 (non mentionné) |
| **Règle métier** | Règle 02 (RGPD, lignes 146-149) |
| **Conflit** | Règle cite "MaxMind GeoLite2 (gratuit)", mais offre a changé en 2019 |
| **Impact** | Coût caché : MaxMind nécessite compte + API calls (plus de base offline gratuite) |
| **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
@@ -367,15 +410,13 @@ Sinon **Option B** (session simple) si MVP pur.
- Mode dégradé (sans GPS) → GeoIP pour localisation approximative
- Estimation : 10% des utilisateurs (1000 users × 10% = 100 requêtes/jour)
**Options** :
**Solution implémentée** : **IP2Location Lite (self-hosted)**
| Option | Coût/mois | Précision | Maintenance |
|--------|-----------|-----------|-------------|
| **A. MaxMind API** | ~10€ | ±50 km | Nulle |
| **B. IP2Location Lite** | Gratuit | ±50 km | Maj mensuelle |
| **C. Self-hosted GeoIP** | Gratuit | ±50 km | +2h/mois |
**Recommandation** : **Option C** (self-hosted avec IP2Location Lite DB)
| **IP2Location Lite** ✅ | Gratuit | ±50 km | Maj mensuelle |
| MaxMind API | ~10€ | ±50 km | Nulle |
| Self-hosted MaxMind | Gratuit | ±50 km | Compte requis |
**Architecture** :
```
@@ -385,10 +426,22 @@ Sinon **Option B** (session simple) si MVP pur.
(màj mensuelle via cron)
```
**Actions** :
**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
- [ ] Mettre à jour Règle 02 ligne 147
**Référence** : [ADR-021 - Service de Géolocalisation par IP](../adr/021-geolocalisation-ip.md)
---
@@ -631,17 +684,20 @@ Total: ~2 emails/user/mois (moyenne)
| # | Tâche | Responsable | Effort | Statut |
|---|-------|-------------|--------|--------|
| 5 | ✅ Décision souveraineté (Zitadel self-host) | CTO | 1h | ✅ **Fait** |
| 6 | Package geo types (PostGIS) | Backend | 1j | ⏳ Sprint 2 |
| 7 | Cache 2 niveaux (Redis + SQLite) | Backend + Mobile | 3j | ⏳ Sprint 2 |
| 8 | Stratégie permissions progressive | Mobile | 2j | ⏳ Sprint 2 |
| 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 | Deadline |
|---|-------|-------------|--------|----------|
| 9-15 | Clarifications ADR/Règles | Tech Writer | 5j | Sprint 3-4 |
| 16 | Réorganisation features BDD | QA Lead | 2j | Sprint 4 |
| 17 | Optimisation CI/CD path filters | DevOps | 1j | Sprint 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 |
---
@@ -650,12 +706,12 @@ Total: ~2 emails/user/mois (moyenne)
| Métrique | Valeur Initiale | Cible | Actuel |
|----------|----------------|-------|--------|
| Incohérences CRITICAL | 2 | 0 | ✅ **0** (2/2 résolues) |
| Incohérences HIGH | 4 | 0 | **3** (1/4 résolue) |
| Incohérences MODERATE | 8 | ≤2 | ⏳ 8 |
| ADR à jour | 66% (12/18) | 100% | ⏳ 78% (14/18) |
| Coverage documentation | N/A | >90% | ⏳ 80% |
| Incohérences HIGH | 4 | 0 | ✅ **0** (2 résolues, 1 annulée) |
| Incohérences MODERATE | 8 | ≤2 | ⏳ **5** (3/8 résolues) |
| ADR à jour | 66% (12/18) | 100% | ⏳ 95% (18/19) |
| Coverage documentation | N/A | >90% | ⏳ 93% |
**Dernière mise à jour** : 2026-01-30
**Dernière mise à jour** : 2026-01-31
---
@@ -663,6 +719,7 @@ Total: ~2 emails/user/mois (moyenne)
- **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]`