Files
roadwave/docs/regles-metier/09-abonnements-notifications.md
jpgiannetti 6ba0688f87 refactor(adr): remplacer Firebase par implémentation directe APNS/FCM
Remplace toutes les références au SDK Firebase par une implémentation
directe des APIs APNS (iOS) et FCM (Android) pour éliminer le vendor
lock-in et assurer la cohérence avec la stratégie self-hosted.

Modifications :
- ADR-017 : Architecture notifications avec APNS/FCM direct
- ADR-018 : Remplacement firebase.google.com/go par sideshow/apns2 + oauth2
- ADR-020 : Remplacement firebase_messaging par flutter_apns + flutter_fcm
- Règles métier 09 & 14 : Mise à jour références coûts notifications

Avantages :
- Aucun vendor lock-in (code 100% maîtrisé)
- Cohérence avec ADR-008 (self-hosted) et ADR-015 (souveraineté)
- Gratuit sans limite (APNS/FCM natifs)
- APIs standard HTTP/2 et OAuth2
2026-02-02 21:36:59 +01:00

320 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 8. Abonnements et notifications
### 8.1 Impact sur l'algorithme
**Décision** : Boost +30% au score + reste dans le mix
**Boost de score abonnements** :
- **+30% au score final** pour contenus d'un créateur suivi
- Application : multiplicateur sur le score calculé
```
score_final_avec_boost = score_final × 1.3
```
**Reste dans le mix** :
-**Pas de priorité absolue** (pas de file dédiée abonnements)
- ✅ Contenu suivi entre en **compétition avec autres contenus**
- ✅ Si créateur suivi publie contenu faible engagement → peut être battu par contenu viral non-suivi
**Exemple concret** :
```
Utilisateur à Paris, 2 contenus disponibles :
Contenu A (créateur NON suivi) :
- Score géo : 0.9 (très proche)
- Score intérêts : 0.8
- Score engagement : 0.7
→ Score final : 0.80
Contenu B (créateur suivi) :
- Score géo : 0.5 (moyennement proche)
- Score intérêts : 0.6
- Score engagement : 0.5
→ Score final : 0.53
→ Score avec boost : 0.53 × 1.3 = 0.69
→ Contenu A proposé en premier (0.80 > 0.69)
```
**Cas où abonnement fait la différence** :
```
Contenu A (non suivi) : score 0.70
Contenu B (suivi) : score 0.60 → avec boost 0.78
→ Contenu B proposé (boost fait pencher la balance)
```
**Justification** :
- **Équilibre** : valorise abonnements sans enfermer utilisateur
- **Découverte** : contenus viraux/locaux peuvent toujours émerger
- **Prévisible** : boost fixe, pas de logique opaque
- **Coût 0** : multiplicateur simple dans l'algo
---
### 8.2 Notifications contextuelles
**Décision** : Push adapté selon contexte (voiture vs à pied) + limite 10/jour
**Détection contexte utilisateur** :
| Contexte | Détection | Comportement |
|----------|-----------|--------------|
| **En voiture** | Vitesse GPS >10 km/h | Notifications silencieuses (in-app uniquement) + commandes volant |
| **À pied** | Vitesse GPS <5 km/h | Notifications push actives + interface tactile/vocale |
**Notifications activées** :
#### En voiture (mode conduite)
| Événement | Notification | Comportement |
|-----------|--------------|--------------|
| **Nouveau contenu créateur suivi** | In-app uniquement | Badge compteur, pas de push (sécurité) |
| **Live créateur suivi** | In-app uniquement | Badge compteur, pas de push |
| **Point d'intérêt proche** | Audio notification | Bip + annonce vocale : "Audio-guide disponible" |
#### À pied (mode piéton)
| Événement | Notification | Comportement |
|-----------|--------------|--------------|
| **Nouveau contenu créateur suivi** | ✅ Push | Si utilisateur dans zone géo du contenu |
| **Live créateur suivi** | ✅ Push | Si utilisateur dans zone géo |
| **Audio-guide disponible** | ✅ Push | "📍 Audio-guide disponible : [Lieu]" |
| **Séquence suivante suggérée** | Audio notification | Annonce vocale : "Pièce suivante disponible" |
**Format notifications** :
**Nouveau contenu** :
```
🎧 [Nom créateur] a publié : "[Titre contenu]"
Tap pour écouter
```
**Live en direct** :
```
🔴 [Nom créateur] est en direct : "[Titre live]"
Tap pour rejoindre
```
**Audio-guide à pied** :
```
📍 Audio-guide disponible : [Nom du lieu]
Choisissez parmi 3 guides pour [Musée du Louvre]
Tap pour explorer
```
**Filtrage géographique** :
- Si contenu/live hors zone utilisateur → **pas de notification**
- Évite frustration : "notification pour contenu que je ne peux pas écouter"
- Exception : contenu national → notifie tous les abonnés
**Fréquence maximale** :
- **Maximum 10 notifications push/jour** par utilisateur (tous types confondus)
- Si dépassement : notifications regroupées
- Message groupé : "🎧 3 nouveaux contenus de créateurs suivis"
**Plages horaires** :
- **Mode silencieux** : 22h-8h (pas de push, sauf live)
- Paramétrable utilisateur (désactivation totale possible)
- Option "Notifications importantes uniquement" (lives uniquement)
**Gestion préférences** :
| Préférence | Défaut | Description |
|------------|--------|-------------|
| **Nouveaux contenus** | ✅ Activé | Push à chaque nouveau contenu (à pied uniquement) |
| **Lives** | ✅ Activé | Push au démarrage live (à pied uniquement) |
| **Audio-guides proximité** | ✅ Activé | Push quand audio-guide détecté à <100m |
| **Mode silencieux** | ✅ Activé (22h-8h) | Pas de push nocturne |
| **Limite quotidienne** | 10 | Modifiable 5-20 |
**Justification** :
- **Sécurité routière** : pas de push en conduite (distraction)
- **Engagement piéton** : push actifs pour audio-guides (valeur ajoutée tourisme)
- **Pas de spam** : limite 10/jour + mode silencieux
- **Filtrage géo** : pertinence maximale (pas de notif inutiles)
- **Coût** : APNS/FCM natifs (gratuit, aucune limite)
---
### 8.3 Mode Audio-guide (piéton)
**Décision** : Navigation manuelle multiséquence + choix parmi plusieurs guides
**Fonctionnement** :
#### Détection et proposition
1. Utilisateur à pied (<5 km/h) passe à <**100m** d'un lieu avec audio-guides
2. **Notification push** : "📍 Audio-guide disponible : [Musée du Louvre]"
3. Tap notification → **Page de sélection** audio-guides
#### Page de sélection
**Affichage** :
```
📍 Musée du Louvre
Choisissez votre guide :
┌─────────────────────────────────┐
│ 🎨 Visite complète (45 min) │
│ Par [Créateur A] • 12 séquences│
│ ⭐ 4.8 • 1.2K écoutes │
└─────────────────────────────────┘
┌─────────────────────────────────┐
│ 🏛️ Œuvres majeures (20 min) │
│ Par [Créateur B] • 5 séquences │
│ ⭐ 4.9 • 3.5K écoutes │
└─────────────────────────────────┘
┌─────────────────────────────────┐
│ 👶 Visite famille (30 min) │
│ Par [Créateur C] • 8 séquences │
│ ⭐ 4.7 • 850 écoutes │
└─────────────────────────────────┘
```
#### Interface audio-guide
**Après sélection** :
```
🎨 Visite complète • Musée du Louvre
Piste actuelle : 2/12
"La Joconde - Histoire et mystères"
[████████────────────] 3:24 / 6:50
Liste des séquences :
✅ 1. Introduction et architecture
▶️ 2. La Joconde - Histoire et mystères
⏸️ 3. Vénus de Milo
⏸️ 4. Victoire de Samothrace
⏸️ 5. Peintures Renaissance
...
⏸️ 12. Conclusion et boutique
```
**Navigation** :
| Action | Geste | Effet |
|--------|-------|-------|
| **Séquence suivante** | Tap "Suivant" ou commande vocale "Suivant" | Passe à séquence N+1 |
| **Séquence précédente** | Tap "Précédent" ou commande vocale "Précédent" | Revient à séquence N-1 |
| **Saut direct** | Tap séquence dans liste | Lecture séquence choisie |
| **Pause** | Tap bouton pause | Met en pause, reprise position exacte |
| **Quitter** | Tap "×" | Sauvegarde progression, sortie guide |
**Guidage vocal automatique** :
- Entre 2 séquences : "Vous avez terminé la séquence 2. Dirigez-vous vers la Vénus de Milo pour la séquence 3."
- Si utilisateur s'éloigne (>50m de la prochaine pièce) : "Vous vous éloignez de la prochaine étape. Consultez le plan."
**Sauvegarde progression** :
- Position dans guide sauvegardée automatiquement
- Retour ultérieur : "Reprendre à la séquence 5 ?" ou "Recommencer depuis le début"
- Historique : guide marqué "Terminé" si toutes séquences écoutées
**Création audio-guide multiséquence** :
**Processus créateur** :
1. Créateur upload **plusieurs fichiers audio** (1 par séquence)
2. Numérote les séquences : "Séquence 1", "Séquence 2", etc.
3. Titre chaque séquence : "Introduction", "La Joconde", etc.
4. Définit **point GPS unique** pour tout le guide (centre du lieu)
5. Métadonnées : durée totale calculée automatiquement
**Format stockage** :
```json
{
"guide_id": "abc123",
"title": "Visite complète Musée du Louvre",
"location": {"lat": 48.8606, "lon": 2.3376, "radius": 200},
"sequences": [
{
"sequence_number": 1,
"title": "Introduction et architecture",
"audio_url": "https://cdn.../seq1.mp3",
"duration_seconds": 180
},
{
"sequence_number": 2,
"title": "La Joconde - Histoire et mystères",
"audio_url": "https://cdn.../seq2.mp3",
"duration_seconds": 410
},
...
],
"total_duration_seconds": 2700,
"creator_id": "creator_xyz"
}
```
**Justification** :
- **UX piéton** : navigation tactile adaptée (pas de commandes volant)
- **Autonomie** : utilisateur maître de son rythme (pas d'enchaînement forcé)
- **Choix** : plusieurs guides = diversité styles (famille, expert, rapide)
- **Engagement** : sauvegarde progression = incitation terminer
- **Coût** : réutilise infra contenu standard (juste métadonnées séquences)
---
### 8.4 Limites et désabonnement
**Décision** : 200 abonnements max + désabonnement -5% jauges
**Nombre maximum d'abonnements** :
- **200 créateurs maximum** par utilisateur
- Raisons :
- **Évite spam** : au-delà de 200, notifications ingérables
- **Usage réaliste** : 200 créateurs = déjà énorme (vs 100-150 sur YouTube/Twitter)
- **Performance** : requêtes SQL optimisées (index sur 200 max)
**Si limite atteinte** :
- Message : "Vous suivez déjà 200 créateurs. Désabonnez-vous d'un créateur pour en suivre un nouveau."
- Liste triable : par date abonnement, nb contenus écoutés, dernière activité
- Suggestion : "Vous n'avez pas écouté [Créateur X] depuis 6 mois, le désabonner ?"
**Abonnement initial** :
- Impact : **+5% toutes jauges tags du créateur** (voir [Règle 05 - Section 5.3](05-interactions-navigation.md#actions-complémentaires-mode-piéton-uniquement))
- Action : Bouton "S'abonner" dans profil créateur (interface mobile)
- Immédiat à l'action
**Désabonnement** :
- Impact : **-5% toutes jauges tags du créateur** (symétrique)
- Action : Bouton "Se désabonner" dans profil créateur
- Immédiat à l'action
- Pas de confirmation (action réversible)
**Exemple** :
```
Créateur tague ses contenus : Automobile, Voyage
Abonnement :
→ Jauge Automobile : 60% → 65% (+5%)
→ Jauge Voyage : 55% → 60% (+5%)
3 mois plus tard, désabonnement :
→ Jauge Automobile : 65% → 60% (-5%)
→ Jauge Voyage : 60% → 55% (-5%)
```
**Gestion multi-tags** :
- Si créateur a 3 tags → **+5% sur chacun des 3 tags**
- Logique : abonnement = signal fort d'affinité à TOUS les sujets du créateur
**Abonnements réciproques** :
-**Pas d'abonnement mutuel visible**
- Créateur ne voit pas qui est abonné (privacy)
- Créateur voit uniquement : nombre total abonnés (métrique globale)
**Justification** :
- **Limite 200** : équilibre entre liberté et gestion spam
- **Symétrie +5%/-5%** : cohérence mathématique, prévisibilité
- **Privacy** : pas de liste publique abonnés (évite stalking)
- **Coût** : table abonnements PostgreSQL standard
---
## Récapitulatif Section 8