---
issueRef: "#156"
version: 5
updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"}
updatedAt: 1785248859161
---
## Entrée architecture utilisateur — Main (2026-07-27)

Architect doit cadrer une architecture permettant :
- collecte **live** fréquence cardiaque, distance, calories depuis montre compatible ;
- affichage live téléphone + montre ;
- persistance pour après-séance et historique ;
- **fréquence cardiaque min / moyenne / max** avec détail **par étape, série et exercice** ;
- fallback totalement silencieux si un capteur ou une donnée manque ;
- alimentation future de graphiques historiques.

Point important : le chantier doit être découpé en plusieurs tickets exécutables à la suite, avec dépendances claires, sans polluer les carnets des tickets non concernés.

---

## Cadrage initial Architect (2026-07-27)

### Décision d’architecture
Traiter ce lot comme un sous-système `telemetry` séparé de la projection de séance. La projection continue de porter le contrôle de la séance, tandis que la télémétrie devient un flux orthogonal, plus fréquent, avec sa propre persistance et ses propres agrégats.

### Base existante
- Le watch bridge a déjà un pipeline capteur cœur: `WatchHeartRateCollector` côté watch et ingestion sur le téléphone via `WatchWearDataLayerAdapter`.
- Le téléphone a déjà un état actif in-memory pour la FC et une écriture d’historique `averageHeartRateBpm` / `maxHeartRateBpm`.
- La projection montre `WatchSessionProjection` ne doit pas être le réceptacle des mesures live; elle est trop liée aux commandes et à la révision.
- Les écrans historique et exécution consomment déjà un `sensorUseCases`.

### Principes figés
- ne pas mélanger la télémétrie live avec la projection de commande ;
- ne pas réutiliser `estimatedCaloriesKcal` comme substitut de calories réelles si le watch compatible ne fournit pas la mesure ;
- ne pas faire dépendre l’agrégation historique du temps d’arrivée des messages ;
- ne pas surcharger le moteur de progression existant ;
- fallback silencieux si métrique absente.

### Contrats nécessaires
- évolution du contrat watch bridge capteur vers un payload v2 ou nouveaux types `WatchTelemetrySample` / `WatchTelemetrySummary` ;
- `WatchTelemetrySample` doit porter au minimum :
  - `sampleId` unique par session pour l’idempotence ;
  - `sessionId` ;
  - `capturedAtEpochMs` ;
  - le contexte d’exécution au moment de la capture ;
  - `programIndex`, `exerciseIndex`, `setIndex` ;
  - `passageIndex` et `stepIndex` si disponibles ;
  - ids snapshot si disponibles ;
  - `heartRateBpm?`, `distanceMeters?`, `caloriesKcal?`.
- `WatchTelemetrySummary` doit porter au minimum :
  - `sessionId` ;
  - `sampleCount` ;
  - FC `min/avg/max` ;
  - distance totale ;
  - calories totales.
- côté application, introduire un port de type `WorkoutTelemetryRepository` ou `ActiveWorkoutTelemetryRepository`.
- côté application, introduire un use case dédié `ActiveWorkoutTelemetryUseCases` ou équivalent.
- côté historique, ajouter des tables/agrégats dédiés pour les mesures brutes et les agrégats par scope.
- les scopes à supporter doivent être stables sur les coordonnées de séance : session, exercice, série, étape.
- pour la FC, stocker `min/avg/max` à chaque scope.
- pour distance et calories, stocker le total et la dernière valeur connue ; ne pas fabriquer des min/max si le capteur ne les fournit pas.

### Modèle de persistance recommandé
- une table de samples bruts pour la session active et l’historique ;
- une table d’agrégats matérialisés par scope ;
- `WorkoutHistory` peut conserver un résumé rapide de session pour la liste et l’en-tête ;
- les vues détail historique doivent lire les agrégats de scope, pas recalculer en widget.

### Flux cible
- Watch compatible : collecteur natif démarre si session active et source dispo ; publie des samples live vers le téléphone ; alimente aussi l’UI watch locale.
- Téléphone : l’adapter ingère les samples ; le use case met à jour un état live de télémétrie ; l’état live alimente l’écran séance ; les samples sont persistés.
- Clôture de séance : figer le résumé live ; matérialiser les agrégats session / exercice / série / étape ; écrire le résumé dans l’historique.
- Reprise de séance : la télémétrie continue à partir de nouveaux samples ; les scopes sont recalculés sans mélanger les périodes de pause.

### Fallback silencieux
- watch non compatible ou permission refusée : métrique absente = valeur nulle, pas de bannière, pas d’erreur bloquante ;
- si un seul metric est disponible, on affiche seulement celui-là ;
- si aucune donnée n’est disponible, l’UI reste vide sur cette zone ;
- aucune métrique ne doit être synthétisée par heuristique pour masquer un manque de source.

### Dépendance UX
Aucune dépendance bloquante sur le contenu métier des contrats. Les seuls points pilotés par le rendu final sont :
- composition exacte de la zone live téléphone ;
- composition exacte de l’écran principal et de l’écran secondaire watch ;
- forme des graphiques historiques et hiérarchie visuelle.

### Découpage recommandé
- Lot 1: contrat watch telemetry v2 + collecteur watch multi-métriques.
- Lot 2: ingestion téléphone + état live persistant + écriture des samples.
- Lot 3: matérialisation historique + agrégats FC par scope + repository de séries pour graphes.
- Lot 4: branchements UI téléphone/watch et historique.
- Lot 5: QA des cas silencieux et des transitions de scope.

### Points de test
- watch compatible avec FC seule ;
- watch compatible avec FC + distance + calories ;
- watch non compatible ou permission refusée ;
- sample reçu en retard rattaché au bon scope via son horodatage ;
- pause / reprise ;
- fin d’étape, fin de série, fin d’exercice ;
- historique récupérable sans recalcul coûteux.
