Initial commit

This commit is contained in:
jpgiannetti
2026-01-31 11:45:11 +01:00
commit f99fb3c614
166 changed files with 115155 additions and 0 deletions

View File

@@ -0,0 +1,144 @@
# ADR-019 : Architecture des Notifications Géolocalisées
**Statut** : Accepté
**Date** : 2026-01-28
**Supersède** : Résout l'incohérence identifiée entre ADR-002 et Règle Métier 05 (Mode Piéton)
## Contexte
Le mode piéton exige des notifications push en temps réel lorsque l'utilisateur approche d'un point d'intérêt (rayon de 200m), **même si l'application est fermée ou en arrière-plan**.
ADR-002 spécifie HLS pour tout le streaming audio, mais HLS est un protocole unidirectionnel (serveur → client) qui ne permet pas au serveur d'envoyer des notifications push vers un client inactif.
## Décision
Architecture hybride en **2 phases** :
### Phase 1 (MVP) : WebSocket + Firebase Cloud Messaging
```
[App Mobile] → [WebSocket] → [Backend Go]
[PostGIS Worker]
[Firebase FCM / APNS]
[Push Notification]
```
**Fonctionnement** :
1. L'utilisateur ouvre l'app → connexion WebSocket établie
2. L'app envoie sa position GPS toutes les 30s via WebSocket
3. Un worker backend (goroutine) interroge PostGIS toutes les 30s :
```sql
SELECT poi.*, users.fcm_token
FROM points_of_interest poi
JOIN user_locations users ON ST_DWithin(
poi.geom,
users.last_position,
200 -- rayon en mètres
)
WHERE users.notifications_enabled = true
AND users.last_update > NOW() - INTERVAL '5 minutes'
```
4. Si proximité détectée → envoi de push notification via Firebase (Android) ou APNS (iOS)
5. Utilisateur clique → app s'ouvre → HLS démarre l'audio (ADR-002)
**Limitations MVP** :
- Fonctionne uniquement si l'utilisateur a envoyé sa position < 5 minutes
- En voiture rapide (>80 km/h), possible de "manquer" un POI si position pas mise à jour
### Phase 2 (Post-MVP) : Ajout du Geofencing Local
```
[Mode Connecté] → WebSocket + Push serveur (Phase 1)
[Mode Offline] → Geofencing natif iOS/Android
[Mode Économie] → Geofencing natif (batterie < 20%)
```
**Fonctionnement additionnel** :
1. Quand l'utilisateur télécharge du contenu pour mode offline → synchronisation des POI proches (rayon 10 km)
2. Configuration de **geofences locales** sur iOS/Android (limite : 20 sur iOS, 100 sur Android)
3. Sélection intelligente des 20 POI les plus pertinents selon les jauges d'intérêt
4. Système d'exploitation surveille les geofences même app fermée
5. Entrée dans geofence → notification locale (pas de serveur)
## Alternatives considérées
| Option | Fonctionne offline | Batterie | Complexité | Limite POI | Précision |
|--------|-------------------|----------|------------|------------|-----------|
| **WebSocket + FCM (Phase 1)** | ❌ Non | ⭐ Optimale | ⭐ Faible | ∞ | ⭐⭐ Bonne |
| Geofencing local seul | ⭐ Oui | ⚠️ Élevée | ⚠️ Moyenne | 20 (iOS) | ⭐⭐⭐ Excellente |
| Polling GPS continu | ⭐ Oui | ❌ Critique | ⭐ Faible | ∞ | ⭐⭐⭐ Excellente |
| **Hybride (Phase 1+2)** | ⭐ Oui | ⭐ Adaptative | ⚠️ Moyenne | ∞/20 | ⭐⭐⭐ Excellente |
## Justification
### Pourquoi WebSocket et pas HTTP long-polling ?
- **Efficacité** : 1 connexion TCP vs multiples requêtes HTTP
- **Batterie** : Connexion persistante optimisée par l'OS mobile
- **Bi-directionnel** : Backend peut envoyer des mises à jour instantanées (ex: "nouveau POI créé par un créateur que tu suis")
### Pourquoi Firebase FCM et pas implémentation custom ?
- **Gratuit** : 10M notifications/mois (largement suffisant jusqu'à 100K utilisateurs)
- **Fiabilité** : Infrastructure Google avec 99.95% uptime
- **Batterie** : Utilise les mécanismes système (Google Play Services)
- **Cross-platform** : API unifiée iOS/Android
### Pourquoi limiter le geofencing local à Phase 2 ?
- **Complexité** : Permissions "Always Location" difficiles à obtenir (taux d'acceptation ~30%)
- **ROI** : 80% des utilisateurs auront un réseau mobile disponible
- **Priorité** : Livrer le MVP rapidement avec la solution serveur
## Conséquences
### Positives
- ✅ Notifications temps réel en mode piéton (< 1 minute de latence)
- ✅ Fonctionne avec HLS pour l'audio (pas de conflit avec ADR-002)
- ✅ Scalable : Worker backend peut gérer 10K utilisateurs/seconde avec PostGIS indexé
- ✅ Mode offline disponible en Phase 2 sans refonte
### Négatives
- ❌ Dépendance à Firebase (vendor lock-in) - mitigée par l'utilisation de l'interface FCM standard
- ❌ WebSocket nécessite maintien de connexion (charge serveur +10-20%)
- ❌ Mode offline non disponible au MVP (déception possible des early adopters)
### Impact sur les autres ADR
- **ADR-002 (Streaming)** : Aucun conflit - HLS reste pour l'audio
- **ADR-005 (Base de données)** : Ajouter index PostGIS `GIST (geom)` sur `points_of_interest`
- **ADR-012 (Architecture Backend)** : Ajouter un module `geofencing` avec worker dédié
- **ADR-014 (Frontend Mobile)** : Intégrer `firebase_messaging` (Flutter) et gérer permissions
## Métriques de Succès
- Latence notification < 60s après entrée dans rayon 200m
- Taux de livraison > 95% (hors utilisateurs avec notifications désactivées)
- Consommation batterie < 5% / heure en mode piéton
- Coût serveur < 0.01€ / utilisateur / mois
## Migration et Rollout
### Phase 1 (MVP - Sprint 3-4)
1. Backend : Implémenter WebSocket endpoint `/ws/location`
2. Backend : Worker PostGIS avec requête ST_DWithin
3. Mobile : Intégrer Firebase SDK + gestion FCM token
4. Test : Validation en conditions réelles (Paris, 10 testeurs)
### Phase 2 (Post-MVP - Sprint 8-10)
1. Mobile : Implémenter geofencing avec `flutter_background_geolocation`
2. Backend : API `/sync/nearby-pois?lat=X&lon=Y&radius=10km`
3. Mobile : Algorithme de sélection des 20 POI prioritaires
4. Test : Validation mode avion (offline complet)
## Références
- [Firebase Cloud Messaging Documentation](https://firebase.google.com/docs/cloud-messaging)
- [PostGIS ST_DWithin Performance](https://postgis.net/docs/ST_DWithin.html)
- [iOS Geofencing Best Practices](https://developer.apple.com/documentation/corelocation/monitoring_the_user_s_proximity_to_geographic_regions)
- Règle Métier 05 : Section 5.1.2 (Mode Piéton, lignes 86-120)