Seiten · Health Debug
Phase 5 — Native Android Suite Plan (Android, WearOS, Android Auto, ChromeOS)
Purpose
This document plans Phase 5 of the Health Debug execution sequence: the native Google-platform client suite, written in Kotlin with Jetpack Compose, spanning handheld Android, WearOS, Android Auto, ChromeOS, and Jetpack Glance home-screen widgets. It defines the project layout, the strict thin-client boundary against the ToGO backend (the Single Source of Truth), the Health Connect biometric bridge, the WearOS Tile and sensor surfaces, the Android Auto notification surface, theming and full Arabic RTL localization — and it explicitly maps how this phase closes divergences #2, #3, #4, and #5 from the project divergence register. This is a planning artifact only; no production code is included. Implementation does not begin until the UI design (in progress separately) is finalized — all design-dependent items are flagged inline as PENDING DESIGN.
1. Scope and Position in the Execution Sequence
| Phase | Deliverable | Status relative to this plan |
|---|---|---|
| 1 | ToGO backend + PostgreSQL + TOGO auth | Prerequisite — API contract must be frozen before Phase 5 coding |
| 2 | React web dashboard + theme/i18n engine | Prerequisite — theme tokens and ICU message catalogs are reused as the reference |
| 3 | Chrome extension (Manifest V3) | Independent |
| 4 | Native Apple suite (Swift) | Sibling — Phase 5 mirrors its parity targets on Google platforms |
| 5 | Native Android suite (this document) | Android, WearOS, Android Auto, ChromeOS, Glance widgets |
| 6 | Electron desktop (Windows, Linux) | Downstream |
Out of scope for Phase 5: Doctor/B2B dashboards, gamification badges, marketplace APIs (future state); any hybrid/webview framework (explicitly prohibited — native Kotlin only).
2. Governing Rules (Non-Negotiable)
These constrain every section below:
- Categorical, not quantitative. The Android clients present foods strictly as
SafeorTrigger-bearing(Gout / IBS-GERD / Fatty Liver trigger families). No client screen, widget, or Tile may display or compute quantitative food deduction. - No invented medical certainty. No Android surface (notification, Auto voice prompt, Tile, widget) may phrase output as diagnosis, prescription, or drug-category guessing. All AI-derived text is behavioral pattern analysis served by the backend, and terminal advice always defers to "Consult your doctor."
- Strict thin client. All 8 Protocol Engines (Hydration, Caffeine Block, GERD Window, Trigger Families, Medication Grace, Cycle, Contraceptive Security, Kinetic Pomodoro) are backend state machines. Android code NEVER re-implements, caches-as-authoritative, or hardcodes engine rules — not the 250ml unit, not the 5000ml cap, not the 30-second cooldown, not the 90-minute caffeine block, not the 4-hour GERD window, not the 60-minute medication grace, not the 3-cycle fertility minimum. Clients collect sensor data and user intents, POST them to the ToGO REST API, and render the state the API returns.
- AI BYOK proxy. No AI provider key (OpenAI, Anthropic, Google, Apple Intelligence) ever reaches the Kotlin client. All AI calls go through the server-side proxy; keys stay encrypted in the backend.
2.1 Thin-Client Enforcement Matrix
| Concern | Client responsibility | Backend (ToGO SSOT) responsibility |
|---|---|---|
| Hydration logging | Send "log 250ml unit" intent + timestamp | Enforce 250ml unit, 5000ml daily max, 30s cooldown; return accepted/rejected state |
| Caffeine Block | Render countdown state from API; push wake event from Health Connect sleep data | Compute the 90-minute post-wakeup block window |
| GERD Window | Render window status; surface allowed items (water, chamomile, anise) as returned by API | Compute 4-hour pre-sleep window and the allowed-items list |
| Trigger Families | Display category verdict | Categorize food into Gout / IBS-GERD / Fatty Liver trigger families |
| Medication Grace | Fire local reminder at server-scheduled time; send log intent | Compute the 60-minute flexible window; accept/reject the log |
| Cycle Engine | Collect cycle logs | Require 3 consecutive logged cycles before predicting; fail safe on irregularity |
| Contraceptive Security | Collect method + log intents | Differentiate daily pills, monthly injections, implants |
| Kinetic Pomodoro | Stream wearable movement signals during break windows | Decide whether the break "registers" (movement away from screen detected) |
| Countdown timers shown on-device | Interpolate display between API syncs for smooth UI only | Own the authoritative deadline timestamps; client interpolation is presentational and is reconciled on every sync |
Note on offline behavior: how much read-only cached state the client may display while offline, and the queue/replay semantics for logs made offline, are not defined in the current spec. This must be decided with the backend team before implementation (see Open Questions). The rule that clients never compute engine outcomes holds regardless.
3. Kotlin + Jetpack Compose Project Layout
Multi-module Gradle project, one repository area for the whole Google suite so that Wear, Auto, widgets, and handheld share networking, models, and design tokens without duplicating logic.
Layout principles:
core/modelcontains data shapes only. Any function that would answer "is this allowed?" or "how long remains?" belongs to the backend; the module lints against business-logic creep (custom lint rule or Konsist/Detekt architecture test — tooling choice open).core/designsystemis the single home for the color spec (§7); no hex literal appears anywhere else in the suite.wear,auto, andwidgetsdepend oncore/*but never onapp, and never on each other.- Minimum SDK levels for handheld, Wear, and Auto are not defined in the current spec — to be fixed by the constraint that Health Connect and Glance must be supported (Open Questions).
4. Health Connect Integration
Health Connect is the Google-side IoT bridge (mirroring HealthKit on Apple). The client reads on-device and pushes securely to ToGO; it also writes Health Debug's own logs back into Health Connect for ecosystem parity.
4.1 Read path (biometrics → ToGO)
| Health Connect record | Read purpose | Pushed to backend for |
|---|---|---|
| Weight | Biometric baseline | Behavioral pattern analysis (backend AI) |
| Body Fat % | Biometric baseline | Behavioral pattern analysis (backend AI) |
| Heart Rate | Biometric stream | Behavioral pattern analysis; wearable context |
| Sleep patterns | Sleep sessions / wake time | Caffeine Block (90-min post-wakeup anchor) and GERD Window (4-hour pre-sleep anchor) computed by the backend from pushed sleep data |
Design points:
- Reads happen on-device via the Health Connect SDK; raw records are pushed to the ToGO REST API over the authenticated (TOGO auth) channel. No third-party relay.
- Sync strategy: periodic background sync via WorkManager plus Health Connect changes-token differential reads, so we push deltas, not full history. Exact sync cadence is not defined in the spec — proposed as a backend-negotiated setting, to be confirmed.
- Permission UX (rationale screens, denied-permission fallbacks) is PENDING DESIGN.
- The client performs no interpretation of biometrics — no thresholds, no "your heart rate is high" judgments. Records are transported verbatim; all analysis is server-side (Core Opinion #2).
4.2 Write path (ToGO → Health Connect, ecosystem parity)
Hydration and nutrition logs accepted by the backend are written back into Health Connect so other health apps in the user's ecosystem see them:
| Health Debug event (backend-confirmed) | Health Connect record written |
|---|---|
| Hydration entry accepted (one 250ml unit) | Hydration record (volume as confirmed by API response) |
| Nutrition/food log accepted | Nutrition record. Note: Health Debug's data model is categorical (Safe / Trigger-bearing), while Health Connect nutrition records are quantitative fields. What we write beyond the food name/timestamp (and whether we write nutrient quantities at all — we hold none) must be resolved; the categorical verdict itself has no native Health Connect field. See Open Questions. |
Write-back rule: only backend-accepted logs are mirrored to Health Connect. A hydration tap rejected by the 30-second cooldown or 5000ml cap is never written — Health Connect must not diverge from the SSOT.
4.3 Client ↔ Backend endpoint sketch
The authoritative API contract belongs to Phase 1. The table below is the Phase 5 consumption plan — names are illustrative and must be reconciled with the frozen Phase 1 contract before coding:
| Interaction | Method + path (illustrative) | Client sends | Client receives |
|---|---|---|---|
| Push biometric batch | POST /v1/biometrics/batch | Health Connect records (weight, body fat %, heart rate, sleep) | Ack + server sync cursor |
| Log hydration unit | POST /v1/engines/hydration/log | Intent + client timestamp | Accepted/rejected + current total, cooldown state |
| Engine status snapshot | GET /v1/engines/status | — | State of all 8 engines for rendering (Tiles, widgets, Auto) |
| Log food item | POST /v1/engines/food/log | Food identity | Categorical verdict (Safe / trigger family) |
| Log medication | POST /v1/engines/medication/log | Intent + timestamp | Within/outside 60-min grace, as decided by backend |
| Pomodoro break movement evidence | POST /v1/engines/pomodoro/movement | Wearable sensor evidence stream/summary | Break registered: yes/no (backend decision) |
| Notification schedule | GET /v1/notifications/schedule | — | Upcoming constraint events (Caffeine Block end, GERD Window start, medication grace opening) for local scheduling |
| AI interaction | POST /v1/ai/chat (proxied) | User prompt/context reference | Backend-proxied AI response (behavioral analysis only, "Consult your doctor" framing enforced server-side) |
5. WearOS
5.1 Tiles
Two Tiles, both strictly render-and-intent surfaces:
- Instant Hydration Tile — one-tap logging of a single 250ml unit. The tap fires the log intent to the backend (via the paired-phone data layer or direct network — transport decision in Open Questions); the Tile then renders whatever the API returns: updated total, or the rejected state when inside the 30-second cooldown or at the 5000ml cap. The Tile never pre-computes whether the tap will succeed.
- Engine Status Tile — compact status of the currently relevant engines (e.g., Caffeine Block countdown, GERD Window state, hydration progress) as returned by the engine-status endpoint. Which engines appear and in what visual arrangement is PENDING DESIGN.
Tile freshness: Tiles refresh on a platform-scheduled cadence plus push-triggered refresh when the backend state changes. Exact refresh policy to be tuned during implementation.
5.2 Sensors — Kinetic Pomodoro movement detection
The Kinetic Pomodoro Engine's defining rule: a break only registers if wearables detect physical movement away from the screen. On WearOS the client's job is evidence collection only:
- During a backend-declared break window, the Wear app samples the device's motion-related sensor APIs (step/motion signals available on the watch) and transmits the evidence to the backend.
- The backend decides whether the evidence constitutes "movement away from the screen." The threshold (steps, distance, duration, sensor fusion recipe) is not defined in the current spec and must be specified as a backend engine rule — the Kotlin client must not embed it.
- Battery posture: sensing is active only inside break windows announced by the backend, never continuously.
- Fallback when no wearable is paired/worn during a break: per the spec, the break simply does not register (the engine's rule is wearable-detected movement). Any softer fallback would be a spec change — flagged in Open Questions.
(All transitions are backend state-machine transitions; the diagram shows what the Wear client observes and feeds, not logic it owns.)
6. Android Auto
Auto is a constraint-awareness surface, deliberately minimal:
- Context-aware notifications for upcoming constraints, rendered through Auto's notification/voice surface:
- Caffeine Block: warning that the block is active / about to matter (e.g., user driving shortly after waking — the block window itself is computed by the backend from pushed sleep data).
- GERD Window: warning that the 4-hour pre-sleep window is approaching or active, with the allowed-items framing (only water, chamomile, anise) exactly as delivered by the backend.
- Voice readout uses Auto's standard notification voice affordances; wording comes from backend-served, ICU-formatted strings (Arabic included) — the Auto layer does not compose sentences by concatenation.
- Lead time for "upcoming" (how many minutes before a window the driver is warned) is not defined in the spec — proposed as a backend-configured value delivered via the notification schedule endpoint.
- No logging-while-driving interactions are in scope from the current spec; whether Auto offers any tap/voice action (vs. display-only) is PENDING DESIGN and a product decision.
- Safety/medical framing rules (§2) apply verbatim: Auto messages are behavioral reminders, never medical directives.
7. Jetpack Glance Home-Screen Widgets
Glance widgets give at-a-glance engine state on the launcher. Widget set (exact composition PENDING DESIGN), with hydration progress and engine countdowns as the expected core, mirroring the Engine Status Tile.
7.1 Theming (strict color spec)
| Token | Dark Mode | Light Mode |
|---|---|---|
| Background | #1A1A1A charcoal | #FFFFFF |
| Active timers / primary accent | #00FF33 neon green with glow effect | #20A060 saturated teal, flat |
| Active buttons / secondary accent | #00CCFF cyan | #0070A0 deep cyan blue, flat |
| Alerts | #FF3333 red | (light-mode alert color not defined in spec — needs design decision) |
- The brief's widget pairing is explicit: Light =
#FFFFFFbackground /#0070A0accent; Dark =#1A1A1Abackground /#00FF33accent. Widgets follow the system dark/light setting via Glance's color-scheme support. - Glow effects are a dark-mode-only treatment; Glance's rendering model constrains true glow — the acceptable approximation for widgets (vs. full Compose screens) is PENDING DESIGN.
- All four surfaces (app, Wear, Auto, widgets) consume the same
core/designsystemtokens; no per-surface hex values.
7.2 Behavior
- Widgets are read-and-deep-link surfaces by default; whether any widget carries a direct log action (like the hydration Tile) is PENDING DESIGN.
- Widget data comes from the engine-status endpoint via WorkManager refresh + push-triggered updates; countdowns render from backend deadline timestamps (client interpolates for smoothness only, per §2.1).
8. Notification Infrastructure (Divergence #3)
Phase 5 builds the Kotlin notification layer in core/notifications, serving all four surfaces:
- Channels (Android notification channels) partitioned by engine concern — hydration nudges, Caffeine Block, GERD Window, Medication Grace reminders, Pomodoro break signals, cycle/contraceptive reminders. Exact channel taxonomy and user-facing names PENDING DESIGN.
- Scheduling model: the backend owns when things matter (it computes all windows); the client fetches the notification schedule and arms exact local alarms so reminders fire even offline/dozing. Push messages (delivery mechanism to be confirmed — the spec names no push provider; see Open Questions) trigger immediate state-change notifications and Tile/widget refreshes.
- Medication Grace: reminder timing must respect the backend-computed 60-minute flexible window — the client fires at server-provided instants, it does not compute the window.
- Content rules: every notification string is ICU-formatted, localized (including Arabic), and constrained by Core Opinion #2 — reminders and behavioral observations only, terminal medical advice always "Consult your doctor."
- Wear bridging (which notifications bridge to the watch vs. render as native Wear notifications) and Auto projection both consume this same layer — one scheduling source, three render targets.
9. Localization and RTL (Arabic)
- Resource structure: all user-visible strings in
values/with full mirrors invalues-ar/. No string concatenation anywhere; all variable strings use ICU Message Format (plurals, gender, ordering all inside the message, matching the Phase 2 web i18n engine's catalogs so translations are shared, not forked). How catalogs are shared between web and Android (single source exported to Android resources vs. runtime delivery) is an Open Question for the i18n pipeline. - Layout: full
LayoutDirection.Rtlsupport in Compose. Every screen, Tile, widget, and Auto template must render correctly mirrored — start/end semantics only, never left/right absolutes. - Progress bars, charts, node graphs: per spec, these must reverse smoothly under RTL — hydration progress fills right-to-left, countdown arcs mirror, chart axes and node-graph flow direction mirror. This is a first-class acceptance criterion, not a best-effort: RTL rendering of every progress/graph component is part of the Phase 5 test matrix (§11). Exact chart/graph visual specs are PENDING DESIGN.
- Numerals and locale formatting: digit shaping and date/number formatting follow the locale via standard formatting APIs (no hand-formatting). Whether Arabic UI uses Eastern Arabic numerals is not defined in the spec — flag for the design/i18n decision.
- Glance widgets and Wear Tiles are included in the RTL matrix (both support RTL layout, but each needs explicit verification — mirroring bugs in remote-rendered surfaces are common).
10. Divergence Closure Map
This phase explicitly closes the following items from the project divergence register:
| # | Divergence | How Phase 5 closes it |
|---|---|---|
| #2 | Dark/light themes not activated and tested | core/designsystem implements both palettes exactly per the color spec (§7.1): Dark #1A1A1A/#00FF33/#00CCFF/#FF3333 with glow effects; Light #FFFFFF/#20A060/#0070A0 flat. Both themes are activated (system-following + in-app override, override behavior PENDING DESIGN) and tested: screenshot tests of every screen, Tile, and widget in both themes are a release gate. |
| #3 | No notification infrastructure in Kotlin | §8 delivers the full Kotlin notification layer — channels, backend-driven scheduling, exact local alarms, localized ICU content, and fan-out to handheld, Wear, and Auto from one source. |
| #4 | AI key-proxy not integrated on this platform | The Kotlin suite integrates the BYOK server-side proxy: the client calls only the ToGO AI proxy endpoint over the TOGO-authenticated channel. No provider key (OpenAI, Anthropic, Google, Apple Intelligence) is ever stored, transported, or configurable on the client; key entry/management UX, if surfaced on Android at all, submits keys directly to the backend for encryption (key-entry screen PENDING DESIGN). A static check (dependency + string scan) asserts no AI-provider SDK or endpoint appears in the Android codebase. |
| #5 | No Wear/Auto/Widget parity | §5 (Tiles + Pomodoro sensing), §6 (Auto constraint notifications), and §7 (Glance widgets in both themes) bring the Google platform to parity across all companion surfaces, all as thin clients of the same engine-status and notification-schedule endpoints. |
Divergence #1 is not assigned to this phase in the brief and is therefore not addressed here; its closure lives in its owning phase's plan.
11. Testing and Acceptance Plan
| Area | Acceptance criteria |
|---|---|
| Thin-client integrity | Architecture tests prove no module outside core/network calls the API and no module anywhere computes engine outcomes; contract tests exercise every endpoint in §4.3 against the Phase 1 API |
| Theme (divergence #2) | Screenshot tests for every screen/Tile/widget in dark and light; hex values asserted against the spec tokens |
| Health Connect | Read/push round-trip for Weight, Body Fat %, Heart Rate, Sleep; write-back only on backend-accepted logs; rejected hydration taps produce no Health Connect record |
| Hydration flow | Tap → API → render loop verified for accepted, cooldown-rejected (30s), and cap-rejected (5000ml) responses — all three states rendered from API responses, none computed locally |
| Kinetic Pomodoro | Sensor evidence transmitted only during backend break windows; registered/not-registered verdicts rendered as received |
| Notifications (divergence #3) | Scheduled reminders fire at server-provided instants including under Doze; Auto and Wear projections carry identical, correctly localized content |
| AI proxy (divergence #4) | Static scan: zero AI-provider SDKs/keys/endpoints in the client; runtime: AI features function through the ToGO proxy only |
| RTL | Full Arabic pass: layout mirroring on every surface; progress bars, charts, and node graphs verified to reverse smoothly (screenshot tests under LayoutDirection.Rtl) |
| ChromeOS/foldables | Window Size Class matrix (compact/medium/expanded) verified on foldable postures and ChromeOS resizable windows; keyboard/mouse input sanity on ChromeOS |
12. ChromeOS and Foldables
- Adaptive layout via Compose Window Size Classes — compact (phone), medium (foldable inner display / small tablet window), expanded (tablet / ChromeOS desktop window). Screen-level adaptive layouts (list-detail vs. single pane, etc.) are PENDING DESIGN.
- ChromeOS runs the same handheld
appmodule in a resizable, keyboard-and-mouse environment: free-form window resize must re-evaluate size classes live; hover/right-click/keyboard focus get a functional (not necessarily bespoke) pass. - Foldable posture changes (fold/unfold mid-session) must preserve state and re-layout without losing in-progress input.
- No ChromeOS-specific feature beyond adaptive layout is in the current spec.
13. Dependencies and Sequencing Within Phase 5
Suggested internal milestones: (1) core modules + auth + Health Connect read/push, (2) handheld screens with both themes activated, (3) notification infrastructure, (4) Wear Tiles + Pomodoro sensing, (5) Glance widgets, (6) Android Auto, (7) ChromeOS/foldable adaptive pass, (8) full Arabic RTL certification, (9) divergence closure sign-off (#2–#5).
14. Open Questions
- Phase 1 API contract: endpoint names/shapes in §4.3 are illustrative — the frozen ToGO contract must be published before
core/networkwork starts. - Offline policy: how much cached engine state may be displayed offline, and whether log intents queue and replay — undefined in spec; needs a backend-owned decision.
- Wear transport: do Tiles/watch log directly to the ToGO API or relay through the paired phone? (Battery, standalone-watch support implications.)
- Pomodoro movement threshold: the backend rule defining "physical movement away from the screen" (sensors, thresholds, durations) is unspecified; must be defined server-side before the Wear evidence format can be fixed.
- Nutrition write-back mapping: Health Connect nutrition records are quantitative; Health Debug is categorical. What exactly is written back for food logs?
- Push delivery mechanism: the spec names no push provider for state-change notifications; needs an infrastructure decision consistent with the security posture.
- Notification lead times: how far ahead Auto/handheld warn about upcoming Caffeine Block / GERD Window constraints — proposed backend-configured, unconfirmed.
- Light-mode alert color: dark mode specifies
#FF3333; light mode's alert color is not in the color spec. - Minimum SDK levels for handheld, Wear, Auto — constrained by Health Connect and Glance support, to be fixed at kickoff.
- i18n catalog pipeline: how ICU catalogs are shared between the Phase 2 web engine and Android
values-arresources (build-time export vs. other); Eastern Arabic numeral policy. - Auto interactivity: display-only vs. any voice/tap action in the car — product + design decision.
- All visual specs (screen layouts, Tile/widget composition, glow treatment in Glance, theme-override UX, permission UX, key-entry UX, channel names): PENDING DESIGN — blocked on the Figma work finishing.