Files
coach-ios/COWORK.md
Sylvain Bettinelli f480c36dab feat(deeplink): entitlement associated-domains pour coach.hypnotruck.ch
Aucun .widgetURL ne ramenait dans l'app : la Live Activity, les deux widgets
iPhone et les deux complications Watch pointent sur des URL https, mais sans
entitlement associated-domains ni fichier d'association servi, iOS ouvrait
Safari — où le cookie d'auth de la WKWebView n'existe pas.

Le versant serveur est déjà en prod (coach_sportif 8ec0047 : route AASA +
deeplink.js). Reste la capability à vérifier dans Xcode côté Mac, cf. COWORK.md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 09:28:21 +00:00

8.3 KiB
Raw Blame History

COWORK — coordination multi-Claude (coach-ios)

Ce repo est travaillé en parallèle par 2 instances de Claude :

  • Claude « dev » (serveur Linux, sans Xcode) : écrit le code (Swift des plugins, config projet) + le backend/web (repo coach_sportif). Ne peut PAS builder iOS (pas de Xcode).
  • Claude « Cowork » (app Claude sur le Mac mini de Sylvain) : fait les builds Xcode, la signature, les tests sur device. → C'est toi si tu lis ça depuis le Mac.

Les deux ne communiquent que via git + ce fichier. ⚠️ La mémoire de chaque Claude est locale à sa machine (non partagée) → l'état partagé, c'est CE fichier : tiens-le à jour.

🔑 Règles d'or (pour ne pas se bloquer)

  1. git pull AVANT de toucher au projet ; git push après chaque changement.
  2. ⚠️ Ne jamais laisser Xcode ouvert pendant un git pull — Xcode garde/réécrit le pbxproj en mémoire → fichiers Swift non compilés + conflits (ça nous a bloqués 2× le 2026-06-05). Quitter Xcode (Cmd+Q), pull, rouvrir.
  3. Après toute modif faite dans Xcode (package SPM, capability, signing) → commit + push project.pbxproj (+ Package.resolved) immédiatement, sinon le prochain git pull est bloqué par les modifs locales.
  4. Zone sensible = ios/App/App.xcodeproj/project.pbxproj : le Claude dev y ajoute les fichiers Swift (entrées manuelles), le Claude Mac y ajoute les packages SPM. → committer de suite limite les collisions.

🛠️ Workflow type « le dev a poussé du code natif, build-le »

  1. Quitter Xcode.
  2. git pull
  3. Nouveau *.swift ? vérifier qu'il est dans le projet : grep -c <Nom>.swift ios/App/App.xcodeproj/project.pbxproj (doit être ≠ 0). Si Xcode ne le voit pas après ouverture → clic droit dossier AppAdd Files to "App"… (décocher Copy items, cocher target App).
  4. Ouvrir Xcode → Clean Build Folder (Cmd+Shift+K) → Run (Cmd+R) sur l'iPhone.
  5. Erreurs → corriger, committer le fix, push.
  6. Diagnostic plugins : Safari → Développement → iPhone → coach.hypnotruck.ch → console → Object.keys(Capacitor.Plugins).filter(k=>k.indexOf('Coach')===0).

📍 État natif actuel (2026-06-05)

  • Capacitor 8 n'auto-découvre PAS les plugins in-app → tous enregistrés dans MainViewController.capacitorDidLoad() : CoachWorkoutKit, CoachHealthRoute, CoachWorkoutObserver, CoachLiveBridge, CoachAppleAuth, CoachGoogleAuth.
  • Login natif Apple + Google = OK, validé device. Apple via AuthenticationServices (intégré). Google via SDK GoogleSignIn (SPM, lié à la target App) + GIDClientID/URL scheme dans Info.plist. Les deux POSTent l'id_token sur /auth/apple|google/web (backend) → cookie de session.
  • watchOS CoachWatch + Live Activity en place (chantiers antérieurs, cf. HANDOFF-WATCHOS.md).
  • Widgets natifs iPhone + complication Watch (2026-06-29) : code écrit côté dev, reste le câblage Mac.
    • iPhone : plugin CoachWidgetBridge (enregistré dans capacitorDidLoad()), modèle partagé CoachWidgetSnapshot.swift, widgets CoachWidgets.swift (Séance du jour + Score de forme) dans l'extension CoachLiveActivity. App Group group.ch.hypnotruck.coach. Hook web déjà en prod (widget-bridge.js).
    • Watch : CoachWidgetBridge.pushToWatch (WCSession) → CoachWatch/ConnectivityManager reçoit → App Group montre + reload. Complications CoachWatchWidgets/CoachWatchComplications.swift (Forme circular/corner, Séance rectangular/inline). Nouvelle target widget watchOS à créer dans Xcode.
    • ⚠️ Étapes Mac obligatoires (App Group portail + capabilities + Target Membership + target Watch + build) : TOUT est détaillé dans docs/widgets-runbook-mac.md.

🆕 Routine quotidienne sur la Watch (2026-08-03, dev — non compilé)

Nouveau chantier, code complet côté dev, build Mac requis. Tout est détaillé dans docs/routine-watch-runbook-mac.md (archi, étapes, débogage).

  • Nouveaux fichiers, DÉJÀ référencés dans project.pbxproj (aucun « Add Files » à faire) : App/CoachRoutineBridge.swift (target App), CoachWatch/RoutineStore.swift + CoachWatch/RoutineView.swift (target CoachWatch). Backup : project.pbxproj.bak-routine.
  • Modifs : MainViewController.capacitorDidLoad() enregistre CoachRoutineBridgePlugin ; CoachWatch/ContentView ouvre RoutineView en sheet ; ConnectivityManager (watch) gagne sendRoutine() + réception du routineSnapshot.
  • ⚠️ CoachLiveBridge touché — un seul ajout : routeIfNotLiveSample() aiguille les messages routineDone vers NotificationCenter au lieu de les émettre comme samples. Le délégué WCSession est unique côté iPhone, on ne pouvait pas en ajouter un second. À re-vérifier au build que le live workout (validé E2E le 31/05) fonctionne toujours.
  • Côté backend coach_sportif : déjà en prod (/api/routine, /api/routine/check, /api/routine/day, data/routine_log.json).

Constat : aucun .widgetURL ne ramenait dans l'app. La Live Activity (CoachLiveActivityWidget), les deux widgets iPhone (CoachWidgets/calendar et /forme) et les deux complications Watch pointent tous sur des URL https://coach.hypnotruck.ch/…, mais l'entitlement associated-domains était absent et /.well-known/apple-app-site-association renvoyait 404 → un tap ouvrait Safari, où le cookie d'auth injecté dans la WKWebView n'existe pas : écran de login.

  • Backend — déjà en prod (commit 8ec0047) : route AASA publique déclarant TZ2PVTRKNY.ch.hypnotruck.coach sur /live, /routine, /forme, /calendar (chemins énumérés un par un pour ne pas détourner /calendar.ics), et static/deeplink.js qui écoute appUrlOpen et amène la WebView sur le bon chemin — Capacitor ne le fait pas tout seul.
  • Côté ce repo : App.entitlements gagne com.apple.developer.associated-domains = applinks:coach.hypnotruck.ch.
  • ⚠️ Étape Mac : ouvrir la cible AppSigning & Capabilities → vérifier qu'Associated Domains apparaît avec applinks:coach.hypnotruck.ch (l'entitlement est là, Xcode doit régénérer le profil ; si erreur de signing, décocher/recocher Automatically manage signing). Puis rebuild.
  • Effet attendu : tap sur la Live Activity → app → /live → la vue Liquid Glass CoachLiveView s'ouvre d'elle-même (le JS de /live appelle openNativeLive). C'est le point d'entrée qui manquait.

👉 À reprendre

  • Phase 4 login — FAIT & DÉPLOYÉ (révocation Apple à la suppression de compte) : code complet côté backend coach_sportif (commit 5ae6e2d) + clé .p8 déployée sur le VPS prod (vérifié 2026-06-26). Rien à coder. Détails : coach_sportif/COWORK.md.
  • iOS — bloqué Mac : builder + uploader TestFlight le natif accumulé (login Apple+Google natif, watchOS live, HeartRateRangeAlert). Sur le Mac : cd ~/coach-ios && git pull && npm install && npx cap sync ios && open ios/App/App.xcworkspace → Clean Build Folder → Archive → Upload.
    • ⚠️ Fixes robustesse 2026-07-01 (dev, non compilés) à valider au prochain build : CoachWidgetBridge (score lu en NSNumber.intValue → corrige un score float perdu ; save renvoie Bool → call.reject si App Group KO), CoachAppleAuth (double-tap : rejette l'ancien pendingCall ; erreur testée par domaine ASAuthorizationError). Swift pur, aucun nouveau fichier ni capability.
    • ⚠️ Checklist pré-App-Store (audit sécu 2026-07-01) : ios/App/App/App.entitlements a aps-environment = development. Pour la soumission App Store/TestFlight, l'APNs prod exige production. NON changé côté dev (casserait le push en dev device — arbitrage de signing à faire sur Mac : soit basculer production avant l'archive de distribution, soit laisser Xcode le gérer via le profil de distribution auto). À trancher/tester au moment du build release.
  • watchOS — bloqué Mac : test device + TestFlight de la cible CoachWatch (Phases 1-3 réalisées, build vert sim). Cf. HANDOFF-WATCHOS.md.
  • Android — bloqué externe : Play Console ($25 validé), upload AAB + Internal Testing depuis machine avec Android SDK.
  • Backend/web : voir coach_sportif/COWORK.md.