Files
roadwave/docs/adr/012-frontend-mobile.md
jpgiannetti 5e5fcf4714 refactor(docs): réorganiser la documentation selon principes DDD
Réorganise la documentation du projet selon les principes du Domain-Driven Design (DDD) pour améliorer la cohésion, la maintenabilité et l'alignement avec l'architecture modulaire du backend.

**Structure cible:**
```
docs/domains/
├── README.md (Context Map)
├── _shared/ (Core Domain)
├── recommendation/ (Supporting Subdomain)
├── content/ (Supporting Subdomain)
├── moderation/ (Supporting Subdomain)
├── advertising/ (Generic Subdomain)
├── premium/ (Generic Subdomain)
└── monetization/ (Generic Subdomain)
```

**Changements effectués:**

Phase 1: Création de l'arborescence des 7 bounded contexts
Phase 2: Déplacement des règles métier (01-19) vers domains/*/rules/
Phase 3: Déplacement des diagrammes d'entités vers domains/*/entities/
Phase 4: Déplacement des diagrammes flux/états/séquences vers domains/*/
Phase 5: Création des README.md pour chaque domaine
Phase 6: Déplacement des features Gherkin vers domains/*/features/
Phase 7: Création du Context Map (domains/README.md)
Phase 8: Mise à jour de mkdocs.yml pour la nouvelle navigation
Phase 9: Correction automatique des liens internes (script fix-markdown-links.sh)
Phase 10: Nettoyage de l'ancienne structure (regles-metier/, diagrammes/, features/)

**Configuration des tests:**
- Makefile: godog run docs/domains/*/features/
- scripts/generate-bdd-docs.py: features_dir → docs/domains

**Avantages:**
 Cohésion forte: toute la doc d'un domaine au même endroit
 Couplage faible: domaines indépendants, dépendances explicites
 Navigabilité améliorée: README par domaine = entrée claire
 Alignement code/docs: miroir de backend/internal/
 Onboarding facilité: exploration domaine par domaine
 Tests BDD intégrés: features au plus près des règles métier

Voir docs/REFACTOR-DDD.md pour le plan complet.
2026-02-07 17:15:02 +01:00

10 KiB

ADR-012 : Frontend Mobile

Statut : Accepté Date : 2025-01-20

Contexte

RoadWave nécessite applications iOS et Android avec support CarPlay/Android Auto, lecture audio HLS avancée, géolocalisation temps réel. Le choix du framework impacte vélocité développement et performances.

Décision

Flutter pour iOS et Android avec codebase unique.

Alternatives considérées

Framework Codebase Performance Audio/CarPlay Communauté
Flutter Unique Native Excellente Large
React Native Unique Bonne Modules natifs requis Très large
Native (Swift+Kotlin) Double Excellente Native Large
Ionic/Capacitor Unique Moyenne Limitée Moyenne

Justification

  • Codebase unique : iOS + Android maintenus ensemble, vélocité développement x2
  • Performance : Dart compilé en code natif (pas de bridge JS)
  • Audio HLS : Package just_audio mature avec support HLS, buffering adaptatif
  • CarPlay/Android Auto : Support via packages communautaires (flutter_carplay, android_auto_flutter)
  • Géolocalisation : geolocator robuste avec gestion permissions
  • Écosystème : Widgets riches (Material/Cupertino), state management mature (Bloc, Riverpod)

Packages Flutter

Voir ADR-020 - Librairies Flutter pour la liste complète des packages, licences, alternatives considérées et justifications détaillées.

Packages clés pour RoadWave :

  • State management : flutter_bloc (pattern BLoC, testable, reactive)
  • Audio HLS : just_audio (HLS natif, buffering adaptatif, background playback)
  • GPS temps réel : geolocator (mode voiture haute précision)
  • Geofencing : geofence_service (mode piéton, détection rayon 200m, économie batterie)
  • Notifications : flutter_local_notifications (compteur dynamique, conformité CarPlay/Android Auto)
  • HTTP : dio (client HTTP avec retry logic)
  • Stockage sécurisé : flutter_secure_storage (JWT tokens, Keychain iOS, KeyStore Android)
  • Cache images : cached_network_image (LRU cache)

Points d'attention :

  • ⚠️ Permissions progressives requises pour geofence_service et geolocator (voir section "Stratégie de Permissions")
  • ⚠️ Licences : 100% permissives (MIT, BSD-3) - voir ADR-020

Stratégie de Permissions (iOS/Android)

Contexte et Enjeux

Problème : La géolocalisation en arrière-plan (requise pour le mode piéton) est très scrutée par Apple et Google :

  • iOS App Store : Taux de rejet ~70% si permission "Always Location" mal justifiée
  • Android Play Store : ACCESS_BACKGROUND_LOCATION nécessite déclaration spéciale depuis Android 10
  • RGPD : Permissions doivent être optionnelles et l'app utilisable sans

Architecture de Permissions Progressive

Principe : Demander le minimum au départ, puis proposer upgrade contextuel uniquement si besoin.

Niveaux de Permissions

Trois niveaux de permissions doivent être gérés :

  • Denied : Aucune permission → app limitée (contenu national)
  • When In Use : "Quand l'app est ouverte" → mode voiture complet
  • Always : "Toujours" / Background → mode piéton

Étape 1 : Permission de Base (Onboarding)

Quand : Premier lancement de l'app

Demande : locationWhenInUse uniquement

  • iOS : "Allow While Using App"
  • Android : ACCESS_FINE_LOCATION

Justification affichée :

📍 RoadWave a besoin de votre position

Pour vous proposer du contenu audio adapté
à votre localisation en temps réel.

[Autoriser] [Non merci]

Si acceptée : Mode voiture entièrement fonctionnel

Si refusée : Mode dégradé (contenus nationaux/régionaux via GeoIP)

Étape 2 : Upgrade Optionnel (Contextuel)

Quand : Utilisateur active explicitement "Notifications audio-guides piéton" dans Settings

Flow :

  1. Écran d'éducation (requis pour validation stores) :
┌────────────────────────────────────────┐
│ 📍 Notifications audio-guides piéton   │
├────────────────────────────────────────┤
│ Pour vous alerter d'audio-guides à     │
│ proximité même quand vous marchez avec │
│ l'app fermée, RoadWave a besoin de     │
│ votre position en arrière-plan.        │
│                                        │
│ Votre position sera utilisée pour :   │
│ ✅ Détecter monuments à 200m           │
│ ✅ Vous envoyer une notification       │
│                                        │
│ Votre position ne sera jamais :        │
│ ❌ Vendue à des tiers                  │
│ ❌ Utilisée pour de la publicité       │
│                                        │
│ Cette fonctionnalité est optionnelle.  │
│ Vous pouvez utiliser RoadWave sans     │
│ cette permission.                      │
│                                        │
│ [Continuer] [Non merci]                │
│                                        │
│ Plus d'infos : Politique confidentialité│
└────────────────────────────────────────┘
  1. Demande permission OS : locationAlways / ACCESS_BACKGROUND_LOCATION

  2. Si refusée :

    • Toggle "Mode piéton" reste désactivé
    • Message : "Mode piéton non disponible sans permission arrière-plan"
    • App reste pleinement fonctionnelle en mode voiture

Implémentation

Le service de gestion des permissions (lib/core/services/location_permission_service.dart) doit implémenter :

Détection du niveau actuel :

  • Vérifier le statut de la permission location (when in use)
  • Vérifier le statut de la permission locationAlways (background)
  • Retourner le niveau le plus élevé accordé

Demande de permission de base (Étape 1) :

  • Demander uniquement la permission location (when in use)
  • Utilisée lors de l'onboarding
  • Aucun écran d'éducation requis

Demande de permission arrière-plan (Étape 2) :

  • Toujours afficher un écran d'éducation AVANT la demande OS
  • Demander la permission locationAlways (iOS) ou ACCESS_BACKGROUND_LOCATION (Android)
  • Si refusée de manière permanente, proposer l'ouverture des réglages système

Gestion des refus :

  • Détecter si la permission est refusée de manière permanente
  • Proposer l'ouverture des réglages de l'appareil avec un message clair
  • Permettre à l'utilisateur d'annuler

Configuration Platform-Specific

iOS (ios/Runner/Info.plist)

Clés requises :

  • NSLocationWhenInUseUsageDescription : Décrire l'usage pour le mode voiture (contenu géolocalisé en temps réel)
  • NSLocationAlwaysAndWhenInUseUsageDescription : Décrire l'usage optionnel pour le mode piéton (notifications audio-guides en arrière-plan), mentionner explicitement que c'est optionnel et désactivable
  • UIBackgroundModes : Activer les modes location et remote-notification

Exemple de texte pour NSLocationAlwaysAndWhenInUseUsageDescription :

"Si vous activez les notifications audio-guides piéton, RoadWave peut vous alerter lorsque vous passez près d'un monument ou musée, même quand l'app est en arrière-plan. Cette fonctionnalité est optionnelle et peut être désactivée à tout moment dans les réglages."

Android (android/app/src/main/AndroidManifest.xml)

Permissions requises :

  • ACCESS_FINE_LOCATION et ACCESS_COARSE_LOCATION : Permission de base (when in use)
  • ACCESS_BACKGROUND_LOCATION : Permission arrière-plan (Android 10+), nécessite justification Play Store
  • FOREGROUND_SERVICE et FOREGROUND_SERVICE_LOCATION : Service persistant pour mode piéton (Android 12+)

Android Play Store : Déclaration requise dans Play Console lors de la soumission :

  • Justification : "Notifications géolocalisées pour audio-guides touristiques en arrière-plan"
  • Vidéo démo obligatoire montrant le flow de demande de permission

Fallbacks et Dégradations Gracieuses

Niveau Permission Mode Voiture Mode Piéton Contenus Accessibles
Always Complet Complet Tous (national + hyperlocal)
When In Use Complet Désactivé Tous (si app ouverte)
Denied ⚠️ Limité Désactivé Nationaux/régionaux (GeoIP)

Garantie RGPD : App est pleinement utilisable même avec permission refusée (mode dégradé acceptable).

Tests de Validation Stores

Checklist App Store (iOS) :

  • Permission "Always" demandée uniquement si user active mode piéton
  • Écran d'éducation avant demande OS (requis iOS 13+)
  • App fonctionne sans permission "Always" (validation critique)
  • Texte Info.plist clair et honnête (pas de tracking publicitaire)

Checklist Play Store (Android) :

  • Déclaration ACCESS_BACKGROUND_LOCATION avec justification détaillée
  • Vidéo démo flow de permissions (< 30s, requis Play Console)
  • App fonctionne sans permission background (validation critique)
  • Foreground service notification visible en mode piéton (requis Android 12+)

Documentation Associée


Structure application

lib/
├── core/           # Config, DI, routes
│   └── services/   # LocationPermissionService, GeofencingService
├── data/           # Repositories, API clients
├── domain/         # Models, business logic
├── presentation/   # UI (screens, widgets, blocs)
│   └── dialogs/    # PedestrianModeEducationDialog
└── main.dart

Conséquences

  • Équipe doit apprendre Dart (syntaxe proche Java/TypeScript)
  • Taille binaire : 8-15 MB (acceptable)
  • Tests : flutter_test pour widgets, integration_test pour E2E
  • CI/CD : Fastlane pour déploiement stores
  • Permissions : Stratégie progressive critique pour validation stores (iOS/Android)
  • Validation stores : Tests requis avec TestFlight beta (iOS) et Internal Testing (Android)
  • Documentation : Justifications permissions détaillées requises pour soumission stores