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
11 KiB
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
- Utilisateur à pied (<5 km/h) passe à <100m d'un lieu avec audio-guides
- Notification push : "📍 Audio-guide disponible : [Musée du Louvre]"
- 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 :
- Créateur upload plusieurs fichiers audio (1 par séquence)
- Numérote les séquences : "Séquence 1", "Séquence 2", etc.
- Titre chaque séquence : "Introduction", "La Joconde", etc.
- Définit point GPS unique pour tout le guide (centre du lieu)
- Métadonnées : durée totale calculée automatiquement
Format stockage :
{
"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)
- 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