# 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 : 1. **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. 2. **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 `updateApplicationContext` convient : le système n'en garde que le dernier, ce qui est la sémantique voulue. 3. **`CoachRoutineBridge` n'est PAS `WCSession.delegate`.** `CoachLiveBridge` l'est déjà et le délégué est unique. `CoachLiveBridge.routeIfNotLiveSample()` aiguille les messages `routineDone` vers `NotificationCenter` — c'est le seul endroit où j'ai touché au flux live workout (validé E2E sur device le 31/05), et il retourne `true` sans rien émettre, donc `LiveStore` n'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 ```bash # 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 : ```bash 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 1. Ouvrir l'app iPhone sur `/routine` — ça pousse les blocs vers la Watch. 2. Sur la Watch : app Coach → **Routine du jour** → la liste des 6 blocs doit apparaître avec la progression. 3. Cocher un bloc sur la Watch → retour à l'iPhone, la page `/routine` doit se mettre à jour **sans rechargement** (event `routineUpdated`). 4. Cocher un bloc sur l'iPhone → rouvrir la vue Watch, l'état doit suivre. 5. Vérifier côté serveur : ```bash 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) : ```js await Capacitor.Plugins.CoachRoutineBridge.getStatus() ``` → `paired` et `watchAppInstalled` doivent être `true`. - Xcode console, filtre `subsystem:ch.hypnotruck.coach category:routine`. - `updateApplicationContext` échoue silencieusement si la session n'est pas activée : vérifier que `CoachLiveBridge.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** : `transferUserInfo` garantit 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/day` côté Xcode (le plugin logue le code HTTP en cas d'échec — un 401 signifie un `CoachAuth.kCoachWebToken` périmé). ## Séance guidée au poignet (2026-08-03) `CoachWatch/RoutineGuidedView.swift` — bouton **Démarrer** sur chaque bloc : un exercice à la fois, décompte en anneau, passage automatique, haptique à chaque transition, pause / précédent / suivant. Chaque exercice écoulé est coché via `RoutineStore.toggle`, donc renvoyé à l'iPhone puis au serveur : à la fin, le bloc est déjà à jour sur les trois surfaces sans un geste de plus. Le fichier est **déjà référencé dans le pbxproj** (target CoachWatch), aucun « Add Files » à faire. Backup : `project.pbxproj.bak-guided`. À tester au build : démarrer le bloc 1 sur la montre, laisser tourner deux exercices, vérifier que la page `/routine` de l'iPhone se coche toute seule. ## Reste à faire (hors périmètre de ce chantier) - Complication watchOS « Routine » : la target `CoachWatchWidgets` n'existe toujours pas (cf. `docs/widgets-runbook-mac.md`). - Notification de rappel sur la montre si la routine n'est pas faite à 20 h.