docs: améliorer rendu markdown et navigation mkdocs

- Ajouter ADR-018 (librairies Go) dans TECHNICAL.md
- Transformer Shared en menu dépliable dans mkdocs (cohérence avec autres domaines)
- Corriger listes markdown (ajout lignes vides avant listes)
- Corriger line breaks dans génération BDD (étapes "Et" sur nouvelles lignes)
- Ajouter script fix-markdown-lists.sh pour corrections futures

Impacte 86 fichiers de documentation et 164 fichiers BDD générés.
This commit is contained in:
jpgiannetti
2026-02-09 20:49:52 +01:00
parent 95c65b8be1
commit 35aaa105d0
87 changed files with 1044 additions and 91 deletions

View File

@@ -5,6 +5,7 @@
**Objectif** : Proposer des contenus audio au moment précis où l'utilisateur passe devant un point d'intérêt géographique, pour enrichir son trajet avec des informations contextuelles liées au paysage.
**Contrainte principale** : **Sécurité routière**
- Aucune distraction visuelle (pas de texte à lire)
- Notification sonore uniquement + icône minimale
- Validation par un seul bouton physique au volant ("Suivant")
@@ -26,6 +27,7 @@
**Méthode** : API GPS native iOS/Android
**Principe** :
- Calcul temps d'arrivée au point GPS basé sur vitesse actuelle et distance
- Notification déclenchée **7 secondes avant** d'atteindre le point
- Permet au conducteur d'avoir le temps de réagir (2s) + décompte (5s)
@@ -118,11 +120,13 @@ class GeoContentDetector(private val fusedLocationClient: FusedLocationProviderC
```
**Cas particulier : vitesse nulle ou très faible** :
- Si vitesse < 5 km/h (1.4 m/s) ET distance < 50m → notification immédiate
- Exemple : user arrêté à un feu rouge à 30m du point
- Évite notification trop tardive quand user redémarre
**Fréquence de vérification** :
- GPS updates : toutes les 1 seconde (balance batterie/précision)
- Calcul ETA : à chaque update GPS
- Notification : déclenchée immédiatement quand ETA ≤ 7s
@@ -134,6 +138,7 @@ class GeoContentDetector(private val fusedLocationClient: FusedLocationProviderC
**Philosophie** : **Minimalisme absolu** pour sécurité routière
**Pas de** :
- Titre texte à lire
- Description longue
- Bouton "Annuler" ou "Plus tard"
@@ -141,6 +146,7 @@ class GeoContentDetector(private val fusedLocationClient: FusedLocationProviderC
- Image/cover du contenu
**Uniquement** :
- Son bref (notification)
- Icône selon tag du contenu
- Compteur chiffres (7→1)
@@ -179,12 +185,14 @@ class GeoContentDetector(private val fusedLocationClient: FusedLocationProviderC
```
**Évolution du compteur** :
- Affichage pendant 7 secondes
- Compteur décrémente : 7 → 6 → 5 → 4 → 3 → 2 → 1 → disparaît
- Police grande (72pt), bold, couleur blanche
- Background semi-transparent (noir 50% opacity)
**Notification sonore** :
- **Son** : bip court (0.5s) ou "ding" doux personnalisé RoadWave
- **Volume** : suit le volume système notification (indépendant du volume media)
- **Pas de vibration** : inutile en voiture (téléphone sur support)
@@ -200,6 +208,7 @@ class GeoContentDetector(private val fusedLocationClient: FusedLocationProviderC
**Décision** : Notification sonore uniquement en mode CarPlay/Android Auto
**Contexte** :
- [CarPlay Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/carplay) interdisent les overlays qui "takeover" l'écran
- [Android Auto Media Apps Guidelines](https://developer.android.com/training/cars/media) imposent des interactions minimales
- Sécurité routière maximale = pas de distraction visuelle
@@ -207,11 +216,13 @@ class GeoContentDetector(private val fusedLocationClient: FusedLocationProviderC
**Comportement en mode CarPlay/Android Auto** :
**Désactivé** :
- Icône overlay
- Compteur visuel (7...6...5...)
- Tout élément graphique supplémentaire
**Activé uniquement** :
- Notification sonore (bip ou ding)
- Bouton "Suivant" standard (déjà présent)
@@ -280,12 +291,14 @@ class NotificationManager(private val context: Context) {
6. Contenu géolocalisé démarre après 5s
**Justification** :
- ✅ Conformité maximale CarPlay/Android Auto guidelines
- ✅ Sécurité routière (pas de distraction visuelle)
- ✅ User peut toujours valider via bouton "Suivant" standard
- ✅ Apps comparables (Waze, Apple Maps) utilisent alertes sonores similaires
**Alternative envisagée** : Mini-badge sur bouton "Suivant"
- Moins invasif qu'un compteur
- Mais toujours considéré comme overlay (zone grise)
- **Décision** : Privilégier conformité maximale (sonore uniquement)
@@ -297,15 +310,18 @@ class NotificationManager(private val context: Context) {
**User appuie sur "Suivant"** :
**Étape 1 : Transition visuelle (0.3s)**
- Icône + compteur "7" disparaissent avec fade out
- Nouveau compteur "5" apparaît (plus grand, centré)
**Étape 2 : Décompte 5 secondes**
- Compteur décrémente : 5 → 4 → 3 → 2 → 1
- Contenu actuel continue de jouer **normalement** (pas de baisse volume)
- User entend le contenu en cours pendant le décompte
**Étape 3 : Fin du décompte**
- Compteur atteint "0"
- Fade out 0.3s du contenu actuel
- Fade in 0.3s du contenu géolocalisé
@@ -327,6 +343,7 @@ T+5s : Décompte atteint 0
```
**Justification** :
- Évite silence inconfortable pendant décompte
- User continue d'écouter du contenu intéressant
- Transition naturelle
@@ -353,6 +370,7 @@ T+5s : Décompte atteint 0
### 17.3 Limitation anti-spam
**Problème identifié** :
- Routes riches en points d'intérêt (parcours touristiques)
- Risque de notifier toutes les 30 secondes
- Fatigue utilisateur + distraction conducteur
@@ -362,6 +380,7 @@ T+5s : Décompte atteint 0
#### 17.3.1 Quota : 6 contenus géolocalisés par heure
**Règle** :
- Maximum **6 contenus géolocalisés** notifiés par heure
- Fenêtre glissante : calcul sur les 60 dernières minutes (pas réinitialisation à 0h)
- Si quota atteint : notifications suivantes ignorées silencieusement
@@ -380,6 +399,7 @@ T+5s : Décompte atteint 0
```
**Exception : audio-guides multi-séquences** :
- Un audio-guide avec N séquences compte comme **1 seul contenu** dans le quota
- Une fois démarré, toutes ses séquences sont jouables (pas de limite)
- Exemple : audio-guide 8 séquences = 1 quota, contenus simples restants = 5
@@ -422,12 +442,14 @@ func RecordNotification(userID string, contentID string) {
#### 17.3.2 Cooldown : 10 minutes après notification ignorée
**Règle** :
- Si user ne clique pas sur "Suivant" pendant les 7 secondes
- → Cooldown de **10 minutes** activé
- → Aucune nouvelle notification pendant ce délai
- → Même si quota non atteint
**Justification** :
- User a probablement une raison de ne pas vouloir de contenu géolocalisé maintenant
- Évite harcèlement (notifications répétées ignorées)
- Respecte choix implicite de l'utilisateur
@@ -458,6 +480,7 @@ func ActivateCooldown(userID string) {
```
**Exception : notification validée (user a cliqué)** :
- Pas de cooldown si user a cliqué sur "Suivant"
- Même si user skip le contenu ensuite (pendant le décompte ou après)
- Cooldown = pénalité uniquement pour notification complètement ignorée
@@ -503,6 +526,7 @@ Timeline :
6. User appuie "Précédent" → **retour au contenu géolocalisé à 42s**
**Règle** : Comme décrit dans [../../recommendation/rules/interactions-navigation.md](../../recommendation/rules/interactions-navigation.md#52-commande-précédent) :
- Si temps écouté ≥ 10 secondes → replay contenu actuel depuis début
- Si temps écouté < 10 secondes → retour contenu précédent (position exacte)
@@ -567,6 +591,7 @@ if (avgSpeedKmh < 5) {
```
**Hysteresis (éviter basculements intempestifs)** :
- Nouvelle vitesse doit être stable pendant **10 secondes** avant basculement
- Exemple : user passe de 20 km/h à 3 km/h (arrêt feu rouge)
- Si vitesse remonte à 20 km/h après 8s → pas de basculement
@@ -595,6 +620,7 @@ if (avgSpeedKmh < 5) {
| **Type contenu** | Audio-guides uniquement | Tous contenus géolocalisés |
**Transition fluide** :
- Pas de popup ou message à l'utilisateur
- Basculement invisible et automatique
- Permissions ajustées automatiquement (si déjà accordées)
@@ -608,6 +634,7 @@ if (avgSpeedKmh < 5) {
**Scénario** : Autoroute A6, vitesse 130 km/h, contenu géolocalisé détecté.
**Calcul** :
- Vitesse : 130 km/h = 36.1 m/s
- ETA 7s → distance notification : 7 × 36.1 = **252 mètres** avant le point
- User a 7s pour cliquer "Suivant"
@@ -618,6 +645,7 @@ if (avgSpeedKmh < 5) {
**Conclusion** : Le système fonctionne même à très haute vitesse ✅
**Cas extrême : 180 km/h** (illégal mais théoriquement possible) :
- Vitesse : 180 km/h = 50 m/s
- ETA 7s → distance notification : 350m avant le point
- Décompte 5s : user parcourt 250m
@@ -655,6 +683,7 @@ T+57s : User clique "Suivant" → contenu Château B démarre
**Solution proposée** : **Ajuster le cooldown selon validation précédente**
Nouvelle règle :
- Notification validée (user a cliqué) : pas de cooldown
- Notification ignorée (user n'a pas cliqué) : cooldown 10 min
- Exception : si 2+ notifications validées consécutives, cooldown réduit à 5 min
@@ -687,18 +716,21 @@ func CalculateCooldown(userID string) time.Duration {
**Scénario** : User se gare à 30m d'un château, sort de voiture, visite 1h, revient.
**Problème** :
- Vitesse < 5 km/h + distance < 50m → notification immédiate
- Mais user en mode "stationnement", pas en mode "conduite"
**Solution** : **Détection mode stationnement**
Règle :
- Si vitesse < 1 km/h pendant **2 minutes** consécutives
- → Mode "stationnement" activé
- → Pas de notification de contenus géolocalisés
- → Basculement automatique en mode piéton (push arrière-plan)
**Reprise conduite** :
- Vitesse > 5 km/h pendant 10s
- → Mode "voiture" réactivé
- → Notifications reprennent (si quota non atteint)