Pendant natif du backend coach_sportif (commit 772385b, déjà en prod). - CoachRoutineBridge (target App) : pousse blocs + état du jour vers la Watch via updateApplicationContext, relaie les coches Watch vers /api/routine/day puis notifie la WebView (event routineUpdated) - CoachWatch/RoutineStore : état persisté en UserDefaults, reset au changement de jour. Les blocs viennent de l'iPhone — rien codé en dur côté watchOS, donc modifier la routine côté web ne demande aucun rebuild - CoachWatch/RoutineView : liste cochable, progression, haptique, bouton de renvoi si la synchro a échoué - ConnectivityManager (watch) : sendRoutine() en sendMessage avec repli transferUserInfo (coche faite iPhone hors de portée -> livraison différée) ⚠️ CoachLiveBridge touché : routeIfNotLiveSample() aiguille les messages routineDone vers NotificationCenter. WCSession.delegate est unique côté iPhone, impossible d'en ajouter un second. Le flux live workout n'est pas modifié mais doit être re-vérifié au build. Les 3 nouveaux fichiers sont référencés dans project.pbxproj (bonne target) : aucun "Add Files" à faire sur le Mac. Runbook : docs/routine-watch-runbook-mac.md NON COMPILÉ — nécessite une session Xcode sur le Mac mini. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
5.5 KiB
Runbook Mac — Routine quotidienne sur l'Apple Watch
Écrit côté dev (Linux) le 2026-08-03. Rien n'est compilé. Ce document dit quoi faire sur le Mac pour activer la fonctionnalité, et comment la tester.
Ce que ça fait
La routine anti-douleurs (6 blocs) apparaît sur la montre, cochable au doigt.
Une coche faite sur la Watch remonte à l'iPhone, qui la POSTe au serveur — donc
la page /routine et le widget de la home reflètent immédiatement l'état, et
inversement.
Architecture (à connaître avant de débugger)
page /routine (web) Apple Watch (RoutineView)
│ coche │ coche
▼ ▼
POST /api/routine/check ConnectivityManager.sendRoutine
│ │ sendMessage / transferUserInfo
▼ ▼
data/routine_log.json ◄────────── CoachLiveBridge (délégué WCSession)
▲ POST /api/routine/day │ routeIfNotLiveSample()
│ ▼
└─────────────────────── CoachRoutineBridge (NotificationCenter)
│ notifyListeners
▼
routine.js re-render
Trois décisions structurantes, à ne pas défaire sans raison :
- L'état est serveur, plus en localStorage. La Watch n'a aucun accès au localStorage du WKWebView : il fallait un arbitre commun aux trois surfaces.
- On transmet l'état COMPLET du jour, jamais un delta. Si un message
WatchConnectivity se perd, le suivant recale tout au lieu de laisser les deux
côtés diverger. C'est aussi pour ça que
updateApplicationContextconvient : le système n'en garde que le dernier, ce qui est la sémantique voulue. CoachRoutineBridgen'est PASWCSession.delegate.CoachLiveBridgel'est déjà et le délégué est unique.CoachLiveBridge.routeIfNotLiveSample()aiguille les messagesroutineDoneversNotificationCenter— c'est le seul endroit où j'ai touché au flux live workout (validé E2E sur device le 31/05), et il retournetruesans rien émettre, doncLiveStoren'est pas pollué.
Les blocs eux-mêmes voyagent avec l'état : rien n'est codé en dur côté watchOS. Modifier la routine côté web ne demande donc aucun rebuild.
Étapes Mac
1. Récupérer le code
# Xcode FERMÉ (règle COWORK)
cd ~/coach-ios && git pull
npm install && npx cap sync ios
open ios/App/App.xcworkspace
2. Rien à ajouter dans Xcode
Les trois nouveaux fichiers sont déjà référencés dans project.pbxproj,
dans la bonne target :
| Fichier | Target |
|---|---|
App/CoachRoutineBridge.swift |
App |
CoachWatch/RoutineStore.swift |
CoachWatch |
CoachWatch/RoutineView.swift |
CoachWatch |
Vérification rapide si un doute :
grep -c "RoutineView.swift" ios/App/App.xcodeproj/project.pbxproj # doit valoir 4
(4 = PBXBuildFile + PBXFileReference + children du groupe + Sources phase.)
Backup du pbxproj avant modification : project.pbxproj.bak-routine.
3. Build
Clean Build Folder (Cmd+Shift+K) → Run sur l'iPhone, avec la Watch appairée.
⚠️ CoachAuth.swift doit exister (gitignored) : le plugin s'en sert pour
authentifier son POST vers /api/routine/day. Sans lui, ça ne compile pas.
4. Tester le cycle complet
- Ouvrir l'app iPhone sur
/routine— ça pousse les blocs vers la Watch. - Sur la Watch : app Coach → Routine du jour → la liste des 6 blocs doit apparaître avec la progression.
- Cocher un bloc sur la Watch → retour à l'iPhone, la page
/routinedoit se mettre à jour sans rechargement (eventroutineUpdated). - Cocher un bloc sur l'iPhone → rouvrir la vue Watch, l'état doit suivre.
- Vérifier côté serveur :
ssh ubuntu@83.228.246.229 'cat /home/ubuntu/coach_sportif/data/routine_log.json'
5. Si la Watch affiche « Ouvre l'app Coach sur l'iPhone »
C'est l'état vide normal au premier lancement : la montre n'a pas encore reçu de
blocs. Si ça persiste après avoir ouvert /routine sur l'iPhone :
- console Safari (Développement → iPhone → coach.hypnotruck.ch) :
→
await Capacitor.Plugins.CoachRoutineBridge.getStatus()pairedetwatchAppInstalleddoivent êtretrue. - Xcode console, filtre
subsystem:ch.hypnotruck.coach category:routine. updateApplicationContextéchoue silencieusement si la session n'est pas activée : vérifier queCoachLiveBridge.load()a bien tourné (c'est lui qui active la session).
6. Si une coche Watch ne remonte pas
- Hors de portée de l'iPhone, c'est normal et attendu :
transferUserInfogarantit la livraison différée, la coche partira au prochain rapprochement. La vue affiche un bouton « Renvoyer vers l'iPhone » si l'envoi a échoué net. - Sinon : vérifier le log
POST /api/routine/daycôté Xcode (le plugin logue le code HTTP en cas d'échec — un 401 signifie unCoachAuth.kCoachWebTokenpérimé).
Reste à faire (hors périmètre de ce chantier)
- Complication watchOS « Routine » : la target
CoachWatchWidgetsn'existe toujours pas (cf.docs/widgets-runbook-mac.md). - Notification de rappel sur la montre si la routine n'est pas faite à 20 h.