# 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](020-librairies-flutter.md)** 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é│
└────────────────────────────────────────┘
```

2. **Demande permission OS** : `locationAlways` / `ACCESS_BACKGROUND_LOCATION`

3. **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

- **Guide détaillé** : [/docs/mobile/permissions-strategy.md](../mobile/permissions-strategy.md)
- **Règles métier** : [Règle 05 - Mode Piéton](../regles-metier/05-interactions-navigation.md#512-mode-piéton-audio-guides)
- **RGPD** : [Règle 02 - Conformité RGPD](../regles-metier/02-conformite-rgpd.md)

---

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