ページ · Health Debug
Phase 4 — Native Apple Suite Plan (iOS, macOS, watchOS, CarPlay, Widgets)
Purpose
This document plans Phase 4 of the Health Debug build: the native Apple client suite, written in Swift/SwiftUI, covering iOS, macOS, watchOS, CarPlay, and WidgetKit widgets. It defines the multi-platform project layout, the HealthKit sensor bridge, the watchOS Kinetic Pomodoro validation loop, the macOS menu bar experience, CarPlay audio-first alerting, widget surfaces, rendering/theming, and Arabic RTL behavior. It is a planning artifact only — no production code. Phase 4 begins only after Phase 1 (ToGO backend + PostgreSQL + auth), Phase 2 (React web dashboard + theme/i18n engine), and Phase 3 (Chrome extension) are complete, and it precedes Phase 5 (native Android suite) and Phase 6 (Electron desktop).
Anything dependent on the visual/UI design being finalized separately (Figma / Claude design) is flagged inline as PENDING DESIGN.
1. Non-Negotiable Constraints (inherited, restated for this phase)
These are project-wide rules. Phase 4 must not weaken any of them:
- Clients never compute or hardcode protocol business logic. The Apple apps are a presentation and sensor-collection layer only. Every timer state, cooldown, window, categorization, prediction, and validation is decided by the central ToGO REST API — the Single Source of Truth (SSOT) for all temporal and state logic. The iOS/macOS/watchOS apps render server state and forward sensor/user input; they never locally decide "the break counted," "the cooldown elapsed," or "this food is a trigger."
- The Protocol is Categorical, Not Quantitative. Client UI presents food as strictly
SafeorTrigger-bearingper the backend's Trigger Families engine. No client screen may introduce quantitative food deduction UI. - The App NEVER Invents Medical Certainty. No Apple surface (including Siri/CarPlay audio, watch haptic descriptions, widget copy) may phrase output as diagnosis, prescription, or drug-category guessing. AI-derived text is behavioral pattern analysis only and must always defer to: "Consult your doctor."
- AI BYOK keys never reach the client. All AI calls are proxied server-side by ToGO; keys are encrypted in the backend. The Apple apps hold no provider API keys, ever — not in Keychain, not in memory, not in entitlements. (How the "Apple Intelligence" BYOK provider option reconciles with strict server-side proxying is undefined — see Open Questions.)
- Identity is TOGO auth. The Apple suite authenticates against the Phase 1 TOGO auth identity system; it does not introduce a parallel identity store.
- No hybrid frameworks. Native Swift/SwiftUI only.
2. Scope of Phase 4
| Deliverable | Platform | Summary |
|---|---|---|
| iOS app | iPhone | Full protocol client: dashboard, logging, HealthKit bridge, notifications, Meds & Cycle tracking (closes Divergence #1) |
| watchOS app | Apple Watch | CoreMotion Kinetic Pomodoro break validation, custom haptics, complications |
| macOS app | Mac | Menu bar status item (Pomodoro timer + one-click water logging), optional Workstation Guard full-screen break overlay |
| CarPlay | Car head units | Audio-first protocol alerts |
| Widgets | iOS Lock Screen + Home Screen | Human Node visual (PENDING DESIGN) + progress rings, full Arabic RTL mirroring |
Out of scope for Phase 4: Android/WearOS/Android Auto/ChromeOS (Phase 5), Electron (Phase 6), Doctor & B2B dashboards, gamification badges, marketplace APIs (all Future State).
3. Swift/SwiftUI Multi-Platform Project Layout
One Xcode workspace, shared logic extracted into local Swift Packages so every target consumes the identical API client, DTOs, theme tokens, and i18n plumbing. Shared packages contain zero protocol business logic — only transport, decoding, rendering primitives, and sensor plumbing.
Layout notes:
- App Group shared container: widgets and complications cannot make arbitrary long-running network calls, so the host apps write the latest server-provided state snapshots into
HDSharedState; extensions render those snapshots. The snapshot is a cache of backend output, never a locally computed state. - HDAPIClient is the only module allowed to talk to the network. All targets depend on it; no target embeds its own HTTP layer.
- Minimum OS versions per target: undefined in the spec — to be decided against required APIs (WidgetKit accessory families, MenuBarExtra, CoreMotion availability). See Open Questions.
3.1 Where the line sits: "sensor collection" vs "protocol logic"
| Allowed on client | Forbidden on client (backend-only) |
|---|---|
| Reading HealthKit samples, packaging them as JSON | Interpreting biometrics into protocol decisions |
| Detecting raw motion via CoreMotion and reporting it | Deciding whether a Pomodoro break "counts" |
| Rendering countdowns from server-issued timestamps/state | Computing whether a cooldown/window has elapsed and changing state on that basis |
Showing Safe / Trigger-bearing labels from API | Categorizing any food locally |
| Displaying cycle predictions returned by API | Any cycle math, prediction, or irregularity handling |
| Scheduling local notifications at server-provided fire times | Deriving those fire times from local rules |
Client-side countdown rendering (a ticking timer UI between two server-issued timestamps) is presentation. State transitions on expiry are confirmed with the API, not assumed.
4. API Consumption Model
The Apple suite consumes the ToGO REST API defined in Phase 1. The table below is the client's consumption map, to be reconciled against the Phase 1 API contract — paths are placeholders if Phase 1 named them differently; the client conforms to Phase 1, not vice versa.
| Concern | Direction | Purpose (client view) |
|---|---|---|
| Auth (TOGO auth) | client → API | Sign-in, session/token refresh |
| Hydration Engine | client → API | Log one 250 ml unit; server enforces 5000 ml daily max and 30-second cooldown; response returns accepted/rejected + current total |
| Hydration Engine | API → client | Current hydration state for rings/menu bar/widgets |
| Caffeine Block | API → client | Whether the 90-minute post-wakeup block is active; block-end timestamp for countdown rendering |
| GERD Window | API → client | Window state; during the 4-hour pre-sleep window only water, chamomile, anise are permitted — client renders the permitted set exactly as returned |
| Trigger Families | API → client | Food catalog with categorical labels (Gout, IBS-GERD, Fatty Liver triggers vs Safe) |
| Medication Grace | both | Log medication intake; server applies the 60-minute flexible window; client shows grace status |
| Cycle Engine | both | Log cycle events; server requires 3 consecutive logged cycles before predicting and fails safe on irregularity; client renders "insufficient data" states verbatim |
| Contraceptive Security | both | Log/read contraceptive regimen (daily pills vs monthly injections vs implants, as differentiated by the server) |
| Kinetic Pomodoro | both | Start/stop focus sessions; stream/report movement evidence; server decides break completion |
| Biometrics ingest | client → API | Push HealthKit-read biometrics as JSON (see §5) |
| HealthKit write-back feed | API → client | Which burned-active-calories and completed-hydration entries to write into HealthKit (see §5.3) |
| Notifications/alert schedule | API → client | Server-computed alert times (hydration reminders, GERD window start, caffeine block end) that the client schedules locally and voices in CarPlay |
| AI (BYOK, proxied) | client → API only | Behavioral-pattern-analysis requests; server proxies to the user's configured provider; responses always defer to "Consult your doctor." |
Error/limit behaviors (e.g., what the API returns when the 30-second hydration cooldown rejects an entry) are Phase 1 contract details; the client's only job is to surface them faithfully.
Offline behavior is undefined in the spec. Since the server is SSOT for temporal logic, naive client-side queuing of timestamped logs is a correctness risk (e.g., replayed hydration entries vs the 30-second cooldown). Whether the Apple clients queue-with-original-timestamps, reject offline logging, or something else must be decided with the backend team before implementation. See Open Questions.
5. HealthKit Integration (iOS)
There is no cloud API for HealthKit — all reads happen on-device. The iOS app requests explicit, granular user permissions and acts as the bridge between the device's health store and ToGO.
5.1 Read scope (biometrics pulled from HealthKit → pushed to ToGO)
| Biometric (spec) | Candidate HealthKit type | Mapping status |
|---|---|---|
| Weight | bodyMass | Direct |
| Body Fat % | bodyFatPercentage | Direct |
| Water % | — | No first-party HealthKit quantity type exists for body water percentage. Source is undefined (some smart-scale vendors keep it in their own silo). Must be resolved before implementation — see Open Questions. |
| Heart Rate | heartRate | Direct |
| Skin Temp | appleSleepingWristTemperature and/or bodyTemperature | Which type(s) satisfy "Skin Temp" is undefined in the spec — decide with backend on ingest semantics. |
Collection mechanics (planning level):
- Observer + anchored queries per type with HealthKit background delivery, so new samples (e.g., a smart-scale weigh-in synced via the vendor's HealthKit integration) are picked up without the app foregrounded.
- Each new sample batch is serialized to JSON and pushed to the ToGO biometrics ingest endpoint. Sketch of the push payload (planning artifact, field names to be finalized in the Phase 1 contract):
- The app performs no interpretation of these values (no trend detection, no thresholds, no "your weight is concerning" copy). Interpretation, if any, is backend behavioral pattern analysis, and its output always defers to "Consult your doctor."
5.2 Permission UX
- Explicit HealthKit permission prompts, requested per data type, with plain-language purpose strings (final copy PENDING DESIGN / localization).
- The app must remain functional (logging, timers, protocol display) when the user denies any or all HealthKit permissions; denied types are simply not bridged.
- HealthKit read authorization status is intentionally opaque on Apple platforms (the API hides "denied" for reads); the bridge must be built to tolerate silently-empty types without error states that guess at the reason.
5.3 Write-back scope (ToGO → HealthKit)
The iOS app writes exactly two things back into HealthKit:
- Burned active calories — active energy values as provided by the backend feed.
- Completed hydration entries — each server-accepted 250 ml water log written as a dietary water sample.
Write-back rules:
- Only server-confirmed entries are written (never optimistic local writes), preserving SSOT.
- Idempotency: the client must tag written samples (HealthKit sample metadata carrying the backend entry ID) so retries do not duplicate samples. Exact metadata key naming: implementation detail for the build phase.
- Where the backend's burned-active-calories figures originate is a backend concern defined outside this document; this phase only plans the write path.
6. watchOS App
6.1 Kinetic Pomodoro break validation via CoreMotion
The Kinetic Pomodoro Engine (backend state machine) rules that a desk-timer break only registers if wearables detect physical movement away from the screen. The watch's role:
- Collect accelerometer/gyroscope data via CoreMotion during a server-declared break window.
- Report movement evidence to the ToGO API (via the paired iPhone or directly, transport decision at build time).
- Render whatever state the backend returns. The watch never marks a break complete on its own.
The precise movement signature that qualifies as "physical movement away from the workstation" (thresholds, duration, features extracted from accelerometer/gyroscope) is a backend engine definition and is not specified here. The client plan reserves an evidence-reporting payload (raw or minimally featurized motion summary — to be defined jointly with the Phase 1 Kinetic Pomodoro contract). See Open Questions.
6.2 Custom haptics
Custom haptic taps for exactly the two spec'd events:
- Hydration reminders — fired at server-provided reminder times.
- GERD window start — fired when the backend declares the 4-hour pre-sleep window has begun.
Planning notes: watchOS haptic customization is constrained (a fixed set of system haptic types; fully custom CoreHaptics patterns have limited watch support). The plan is distinct, consistent tap patterns per event within platform constraints; the exact patterns are PENDING DESIGN (haptic identity is part of the product's sensory design language). Haptic timing always originates from the server's alert schedule (§4), never from watch-local rule computation.
6.3 Complications
- Families: rectangular (
accessoryRectangular) and circular (accessoryCircular) — the two families named in the spec; no others planned. - Content candidates: hydration progress ring, Pomodoro state, GERD window status — final selection and visual treatment PENDING DESIGN.
- Implementation via WidgetKit complications sharing timeline/rendering code with the iOS widget extension where practical; data comes from the
HDSharedStateApp Group snapshot of server state. - Full RTL mirroring for Arabic, including ring/progress direction (§10).
7. macOS App
7.1 Menu bar status item
- A persistent menu bar item (SwiftUI
MenuBarExtra) showing the Pomodoro timer (state + countdown rendered from server-issued timestamps). - One-click water logging: a single click sends one 250 ml hydration entry to the API. The server enforces the 30-second cooldown and 5000 ml daily max; the menu bar UI surfaces acceptance or rejection (e.g., cooldown rejection feedback) exactly as returned. No client-side pre-blocking based on locally-tracked cooldowns — at most, the UI may reflect the server's last-known cooldown-until timestamp for affordance (disabled state), which is presentation of server state, not local logic.
- Menu content beyond timer + water logging: PENDING DESIGN.
7.2 Workstation Guard (optional full-screen break overlay)
- An optional (user-opt-in) full-screen overlay that appears when the backend declares a Pomodoro break, encouraging the user to physically leave the screen.
- Because break completion requires wearable-detected movement (§6.1), the overlay's dismissal semantics matter: the overlay reflects the backend break state and lifts when the backend reports the break registered (or the break window ends unfulfilled). Whether the user may manually dismiss the overlay early — and what that does to the (server-side) break outcome — is a product decision, PENDING DESIGN; the engine rule itself (movement-validated completion) is not negotiable.
- Multi-display behavior, focus-stealing etiquette, and overlay visuals: PENDING DESIGN.
8. CarPlay
- Audio-first alerts: protocol alerts voiced while driving, e.g. "GERD Window starting in 30 minutes; finish eating before driving." (spec example; the 30-minute pre-alert lead time here is taken from that example — whether pre-alerts at that offset are a general backend rule is an Open Question).
- Alert content and timing come from the server's alert schedule (§4); CarPlay is a delivery surface only.
- Localized audio in all supported languages including Arabic; text-to-speech vs pre-rendered audio is an implementation decision for the build phase.
- Minimal-to-no visual interaction is planned for the driving context (audio-first per spec); any on-screen CarPlay UI beyond alert delivery is PENDING DESIGN and subject to the entitlement constraint below.
- Risk / dependency: CarPlay app functionality requires an Apple-granted CarPlay entitlement tied to approved app categories. A health/protocol app's path to CarPlay (dedicated CarPlay app category vs CarPlay-surfaced notifications/Siri audio) is not yet determined and must be validated with Apple's program requirements early in Phase 4 — this is the highest external-approval risk in the phase. See Open Questions.
- Safety/compliance framing: CarPlay copy is behavioral-protocol phrasing only; per the medical-certainty rule, no alert may imply diagnosis or urgency of a medical nature beyond protocol adherence.
9. WidgetKit — Lock Screen and Home Screen Widgets
- Surfaces: iOS Lock Screen widgets (accessory families) and Home Screen widgets (system families). Exact family/size matrix: PENDING DESIGN.
- Content: the Human Node visual — PENDING DESIGN (the visual is being finalized in the separate design effort; the widget architecture must not hard-bake assumptions about its geometry) — plus progress rings (hydration is the obvious ring candidate; final ring set PENDING DESIGN).
- Data flow: widget timelines render
HDSharedStatesnapshots of backend state written by the host app; background refresh cadence is bounded by WidgetKit's system budget, so timelines are built from the last server sync with server-provided future timestamps (e.g., countdown text interpolated by the system between reloads). Widgets perform no protocol computation; a stale widget shows stale server truth with a staleness affordance (PENDING DESIGN) rather than locally-advanced state. - Interactions: tapping deep-links into the app. Whether any widget offers an interactive one-tap water log (App Intents) is PENDING DESIGN; if adopted, the intent posts to the API exactly like the macOS one-click log (server-enforced cooldown/max).
- RTL: fully mirrored for Arabic — layout, the Human Node composition (mirroring rules PENDING DESIGN with the design team), and progress ring/bar direction all follow the RTL rules in §10.
10. Rendering, Theming, and RTL
10.1 Color spec (strict — applies to every Apple surface)
| Token | Dark Mode | Light Mode |
|---|---|---|
| Background | #1A1A1A charcoal | #FFFFFF |
| Primary accent (active timers) | #00FF33 neon green with glow | #20A060 saturated teal, flat |
| Active buttons / secondary accent | #00CCFF cyan with glow | #0070A0 deep cyan blue, flat |
| Alerts | #FF3333 red | (light-mode alert color not specified — undefined, confirm with design) |
- Dark Mode uses glowing effects; Light Mode is strictly flat.
- Tokens live once in
HDDesignSystemand are consumed by all targets; no target redefines hex values.
10.2 Glow rendering
- Baseline: SwiftUI
.shadow-based glow (layered soft shadows in the accent color) for#00FF33and#00CCFFelements on#1A1A1A— sufficient for most static/low-frequency UI. - Escalation path: Metal (custom SwiftUI shaders / Metal-backed views) for high-fidelity or animated glow (e.g., the active Pomodoro timer's live glow) where stacked shadows are visually or computationally inadequate. Decision per component during build, guided by the finalized design (PENDING DESIGN for exact glow radii/intensities).
- Constrained surfaces: widgets are statically rendered and Lock Screen accessory widgets are subject to system tinting/vibrancy; watch complications and always-on display have strict rendering budgets. Glow treatment on these surfaces will be a pre-baked/approximated variant — specifics PENDING DESIGN.
10.3 i18n and Arabic RTL
- Full RTL support for Arabic: achieved via SwiftUI's native layout-direction handling (environment layout direction, leading/trailing-only layout, no hardcoded left/right), so the entire hierarchy mirrors automatically. This includes progress bars and rings — progress direction mirrors in RTL per the project-wide rule that progress visuals mirror for Arabic.
- No string concatenation anywhere; every user-facing string is a complete localized message with placeholders.
- ICU Message Format is the project's mandated message format. Apple's native tooling (String Catalogs / stringsdict) is not natively ICU MessageFormat; the plan is a shared localization pipeline in
HDLocalizationthat keeps ICU as the source-of-truth format (shared with the Phase 2 web i18n engine) and bridges into the Apple runtime. The exact tooling for that bridge is an implementation decision — see Open Questions. - Numerals, dates, and units render through locale-aware formatters only (no manual formatting), consistent with the no-concatenation rule.
- Mirroring exceptions (assets that must not mirror, if any, within the Human Node visual): PENDING DESIGN.
11. Closing Divergence #1 — Meds & Cycle Tracking on iOS
Divergence #1 in the project's divergence register (Meds & Cycle Tracking availability on iOS) is closed in this phase purely by consuming the backend API — no client-side logic is introduced:
- Medication Grace: iOS surfaces medication logging and renders the server's 60-minute flexible grace window state. The window's evaluation lives entirely in the backend engine.
- Cycle Engine (Fertility): iOS provides cycle event logging UI and renders server output, including the pre-prediction state — the backend requires 3 consecutive logged cycles before predicting and fails safe on irregularity; the iOS app must render those "not predicting yet / irregular — no prediction" states verbatim, with no local estimation, ever.
- Contraceptive Security: iOS renders the server's differentiation of daily pills, monthly injections, and implants and logs adherence events against it.
Explicitly not planned: any use of Apple's own HealthKit cycle-tracking data as an input or output for the Cycle Engine. The spec's HealthKit scope (§5) is limited to the five listed biometrics in and calories/hydration out; cycle data flows only through the ToGO API. All screens carry the medical-certainty rule (§1.3): behavioral tracking only, "Consult your doctor."
Per-engine client responsibility summary for the Apple suite:
| Engine | Apple clients collect/present | Backend decides |
|---|---|---|
| 1. Hydration | One-tap 250 ml logs (iOS/macOS/watch/widget-TBD); rings | 30 s cooldown, 5000 ml max, totals |
| 2. Caffeine Block | Countdown + block state display | 90-min post-wakeup window |
| 3. GERD Window | Window state, permitted list (water, chamomile, anise), watch haptic at start, CarPlay audio | 4-hour pre-sleep window logic |
| 4. Trigger Families | Safe / Trigger-bearing labels (Gout, IBS-GERD, Fatty Liver) | All categorization |
| 5. Medication Grace | Med logging UI, grace status | 60-min flexible window |
| 6. Cycle Engine | Cycle logging UI, prediction display incl. fail-safe states | 3-cycle minimum, predictions, irregularity fail-safe |
| 7. Contraceptive Security | Regimen display/logging (pills / injections / implants) | Regimen differentiation logic |
| 8. Kinetic Pomodoro | Timer display (iOS/macOS menu bar/watch), CoreMotion evidence, Workstation Guard overlay | Break registration on movement evidence |
12. Phase 4 Internal Sequencing (proposed)
- Workspace + packages scaffold — targets, App Group,
HDAPIClientagainst the Phase 1 contract, TOGO auth session, theme tokens, ICU/RTL pipeline (reusing Phase 2 message catalogs). - iOS core app — auth, dashboard rendering of all 8 engine states, logging flows (hydration, food with categorical labels, meds, cycle, contraceptive), notification scheduling from server alert times. Closes Divergence #1.
- HealthKit bridge — permissions UX, read observers + JSON push, write-back (active calories + hydration) with idempotency tags.
- watchOS — app + CoreMotion evidence reporting for Kinetic Pomodoro, haptics, rectangular + circular complications.
- Widgets — Lock Screen + Home Screen with Human Node (blocks on PENDING DESIGN) + rings, RTL verification.
- macOS — MenuBarExtra timer + one-click water log; Workstation Guard overlay.
- CarPlay — entitlement pursuit starts at step 1 (long lead time); audio alert delivery built once the entitlement path is confirmed.
Steps 3–6 can partially parallelize after step 2; CarPlay is gated on external approval.
13. Testing & Acceptance (planning level)
- SSOT conformance audit: a checklist/lint pass asserting no client module contains protocol constants (no
250,5000,30,90,240,60,3as embedded rule values — such numbers may appear only as rendered server data or design-system dimensions). - HealthKit bridge: simulated health store fixtures per biometric type; duplicate-write-back prevention verified; denied-permission paths verified non-fatal.
- Kinetic Pomodoro: recorded CoreMotion traces (movement vs stationary) replayed against a mock API to verify the client reports evidence and renders both outcomes — and never self-completes a break.
- RTL: snapshot tests of every screen, widget family, and complication in Arabic, verifying mirroring including progress direction; pseudo-locale checks for concatenation regressions.
- Theming: snapshot tests for both modes verifying exact hex tokens and glow-vs-flat treatment.
- Copy audit: automated scan + review gate ensuring no diagnostic/prescriptive phrasing and that AI-surface copy includes the "Consult your doctor." deferral.
14. Open Questions
- Human Node visual — geometry, states, mirroring rules, widget/complication adaptations: PENDING DESIGN (blocks widget and complication build).
- Water % biometric source — no first-party HealthKit body-water type exists. Where does "Water %" come from on iOS (vendor-specific HealthKit writes? unsupported on Apple? backend-only via other clients)? Needs a product + backend decision.
- Skin Temp mapping —
appleSleepingWristTemperature,bodyTemperature, or both, and how the backend wants them labeled on ingest. - Kinetic Pomodoro evidence contract — what the watch sends (raw samples vs summarized features), transport (via iPhone vs direct), and the backend's qualifying-movement definition. Backend-owned; client blocked on the contract.
- Offline behavior — queue with original timestamps, reject, or hybrid? Unresolved tension with server-enforced temporal rules (cooldowns/windows); must be decided project-wide, not per-client.
- CarPlay entitlement path — which Apple CarPlay category (if any) admits this app, vs delivering audio through CarPlay-surfaced notifications; external approval risk.
- ICU MessageFormat bridge on Apple — tooling to keep ICU catalogs (shared with web) as source of truth while playing well with Xcode localization workflows.
- Apple Intelligence under BYOK — spec lists it as a BYOK provider while also mandating all AI calls be server-side proxied with no keys on device; how Apple Intelligence (an on-device/platform capability, not a key-based cloud API in the same sense) fits this model is undefined.
- Workstation Guard dismissal semantics — can the user manually dismiss, and how is that reflected (server-side) in the break outcome? PENDING DESIGN + backend.
- Alert pre-lead times — is the CarPlay example's "30 minutes before GERD window" a general server-side alerting rule or CarPlay-specific? Backend alert-schedule contract question.
- Light Mode alert color — the strict color spec defines
#FF3333for Dark Mode alerts only; the Light Mode alert color is unspecified. Confirm with design. - Minimum OS versions per target — undefined; to be set against required API availability.
- Interactive widgets — whether one-tap water logging is offered from the widget itself (App Intents) or widgets remain deep-link-only: PENDING DESIGN.
- Divergence register cross-reference — confirm the canonical numbering/wording of "Divergence #1 (Meds & Cycle Tracking on iOS)" in the project's divergence document so this plan links to it precisely.