Clean successor to V3 (forge: lilith/atlilith). Seeded from local Mac working tree at ~/Code/@projects/@cocottetech/. node_modules and build artifacts excluded via .gitignore. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4.8 KiB
4.8 KiB
Flow — cross-device handoff (iPhone ⇄ laptop / web)
Goal
Quinn does most of her work on iPhone (chat-driven), but bulk operations and calendar work feel better on a laptop. The handoff between CocotteAI on iOS and the web FEs on ai.cocotte.maison (brief G) must feel like one continuous session, not two apps to keep in sync.
Constraints
- Same auth on both surfaces (SSO device-link → shared session).
- platform.api is the single source of truth; both clients read from it.
- Cache invalidation arrives via Redis pub/sub on vps-0 → SSE / WebSocket to clients (brief G open question; resolve here as: WebSocket from vps-0 cache layer).
- No conflict-resolution UI for P0 — last-write-wins via platform.api row
updated_at. Concurrent edits to the same resource are extremely unlikely (single Quinn).
Three handoff modes
Mode 1 — Pick-up-where-you-left-off
Quinn is editing a caption draft on iPhone; her phone dies / she switches to laptop.
- Web companion at
ai.cocotte.maisonopens → ai-copilot greets her. - A subtle banner at the top of chat: "Picking up — last edit on iPhone 2 min ago: caption for OF post #abc..."
- Tap → opens the same edit drawer the iPhone was showing.
- Pending mutations from iPhone (queued in SyncEngine if offline) reconcile in the background; if any failed, a notification surfaces in chat.
Mode 2 — Sidekick-on-laptop
Quinn is on iPhone but wants the bigger screen for a specific task (calendar review, asset library batch operation).
- In iPhone chat, she types: "Open the calendar on my laptop."
- ai-copilot returns a card: "Calendar opened on Desktop · transquinnftw-MBP."
- (Detected by: device-link list shows active web sessions.)
- The card on iPhone shows what the laptop is doing in real time (current month, scroll position).
- Laptop opens to the calendar drawer directly (deeplink).
- Mutations on either device propagate via cache.invalidate → both UIs update.
Mode 3 — Notification chase
Push lands on iPhone; Quinn is mid-something on laptop and doesn't want to switch.
- iOS notification arrives normally (brief C / notification-rich-preview).
- Quinn presses ⌘+T on laptop (or clicks the notification badge in
ai.cocotte.maison) → the same approval card appears in the web companion's chat. - Action taken on laptop → push notification on iPhone auto-clears.
- Audit row records which device approved (in
outcome_json.device_id).
State sync model
- Authoritative state: platform.api on black. Both clients always defer to it.
- Optimistic state: each client's local cache. Mutations are committed locally + queued for platform.api.
- Sync channel: WebSocket from vps-0 (subscribing to Redis cache.invalidate); each connected client gets push notifications of every change. iOS uses APNs for backgrounded delivery; web uses native WebSocket while tab is open.
- Reconciliation: on reconnect, client fetches
updated_at > last_seendeltas from platform.api. - Conflict policy (rare): last-write-wins by
updated_at. If a mutation'sif-matchfails, show a non-blocking toast "Refreshed from server — your version overwrote a newer one. View diff?" — tapping opens diff card.
Visible affordances
On iPhone chat
- "Send to laptop" action on any drawer (sheet header overflow menu). Opens the same drawer on the laptop session.
- Active sessions indicator in settings: which devices are currently connected, last seen, "sign out everywhere else" affordance.
- Banner when iPhone resumes from background and detects activity from another device.
On web companion
- "Send to phone" action on any drawer — pushes a notification to iPhone with deeplink.
- Device list dropdown in the top-right (mirrors iOS settings session list).
States to design
- Pick-up banner (iPhone → web).
- Pick-up banner dismissable / persistent.
- Sidekick-on-laptop card (iPhone view of laptop activity).
- Notification cleared cross-device confirmation (subtle toast on iPhone after web takes action).
- Conflict toast + diff card.
- Active sessions list (settings).
- Offline-on-one-device-online-on-other state (e.g. iPhone offline, laptop edits) — laptop edits succeed, iPhone catches up on reconnect.
Out of scope
- iPad as a third active device (P5+).
- Concurrent collaboration with another operator (still single-Quinn P0).
- macOS Catalyst (the web companion is the laptop story for P0).
Open questions
- WebSocket vs Server-Sent Events from vps-0? WebSocket is bidirectional but heavier; SSE is one-way and fine for cache invalidation but needs a second channel for client→server pings.
- "Send to laptop" — should it always open the same drawer, or open at the parent feature (e.g. calendar root, not specific tour edit)?
- Audit log device attribution — show always or only on demand?