Metrics Research
Research supporting (a) the proposed Metrics chapter of The Uvilo Method (Metrics_Method_Chapter.md) and (b) the upcoming implementation plan for uvilo-ai. Sources: the legacy Meteor implementation (/Users/erik/Dev/Uvilo), the uvilo-mono codebase, and web research. All prices, coverage claims, and URLs were verified 2026-07-29 unless noted; wearable-ecosystem facts move fast (several changed May–July 2026), so re-verify before contract signatures.
Headline decisions (settled by Erik, 2026-07-29)
- Wearable sync: phone-as-hub, no aggregator. Read Apple Health (iOS) and Health Connect (Android) through the
@capgo/capacitor-healthplugin in the existing Capacitor 8 shells — $0 per user, covers Apple Watch, Oura, Whoop, Garmin, Withings, Polar, Amazfit, Coros. Native background sync ships in the initial build (iOS HealthKit background-delivery observer + Android WorkManager), not deferred. If an aggregator is ever adopted it is ROOK ($399/mo), not Terra (~$499/mo entry, ~$5,000/mo at 5k users). - Charts: Apache ECharts 6 — chosen after an interactive side-by-side demo against MUI X Charts Pro (same data, same gestures). Free (Apache-2.0), best-in-class mobile touch and canvas performance, and its mini-map slider is the closest analog to the Highstock navigator. MUI X Charts Pro (already licensed) remains the documented fallback. Highcharts is not re-licensed.
- Data model: port the legacy three-collection shape (metric catalog / per-user subscription / values) into ZenStack, fixing the legacy defects listed in §2.4 (no unique keys, string dates, client-side writes,
vmcode execution). - Connections: one surface for every source. The Composio integration plan ships before Metrics and delivers the Connections tab in user settings. Apple Health, Google Health (Health Connect), and later other health connectors are listed alongside Composio connectors on that same surface — the user never sees which mechanism a connection uses. Oura is the first direct cloud connector, implemented now to scope the effort and the value of direct integrations.
- Legacy data: migrate Erik’s own history. Metric data belonging to legacy user
hTsXvc9x8eyNNyNfEin the legacy MongoDB is migrated into Neon for botherik@erikdakoda.com(usr_cmflhqg0500009s8obw6jtucx) anderikschannen@gmail.com(usr_cmms0rurm000041uybelkx2bd). The legacy repo itself is not modified in any way.
1. Corrections to the brief
Two features on the keep-list turn out to be aspirations rather than legacy features — both are worth building, but they are net-new designs, not ports:
- Habit auto-complete was never implemented. The legacy habit editor renders a placeholder: “Auto-complete will allow you to automatically set a task as done, partial or skipped based on metric values… This is not yet implemented.” (
packages/uvilo-habits-ui/views/habitEditor.html:262-273). No rule schema, no evaluation code exists. The Uvilo Method §11.3 describes the intended behavior; §6 below proposes the engine. - Custom units were never supported. Units are a hard-coded code table (a vendored
convert-unitsfork); the only per-user choice is metric vs US display. What legacy did support is custom metrics (user-authored metric definitions withuserIdset). The new design should support both (§7).
2. Legacy implementation inventory
Packages: uvilo-metrics (model + server), uvilo-metrics-ui (values table + chart), uvilo-metrics-setup-ui (catalog/setup/editor), uvilo-metric-goal (goal band + slider), plus uvilo-apps (provider framework), uvilo-apps-fitbit, uvilo-apps-jawbone, uvilo-apps-health-kit, convert-units, highstock, uvilo-dashboard (gauges). Last substantive metrics work: 2023-05-26.
2.1 Data model (the part worth porting)
Three Mongo collections (packages/uvilo-metrics/modules/uviloMetrics.js:28-32):
| Collection | Role | Key fields |
|---|---|---|
metrics | Catalog — metric definitions, global (seeded) or user-authored. Slug _ids (bodyWeight, hkDailySteps). | measure (dimension), unit (canonical storage unit), unitUs (US display default), betterValues (higher/lower), goalLow/goalMid (goal band defaults), chartType, decimals, min/max/valueStep, source (manual | calculated | appId), baseMetricId, dependencies + calculation (calculated metrics), group (co-entry list), sourceInfo (per-provider mapping bag), dashboardTimePeriod |
userMetrics | Subscription + per-user overrides — which metrics a user tracks. | userId, metricId, unit (user’s display unit), per-user copies of goal band/bounds, synced (per-user-per-metric sync watermark) |
metricValues | Samples. | userId, metricId, date (ISO string), value (always stored in the canonical unit), source, sourceId (provider UUID), origin/originName |
Design ideas that proved out and should carry forward:
- Catalog / subscription / values split — cleanly separates “what a step count is” from “Erik tracks steps with goal 8–10k, last synced at T” from the samples.
- Canonical storage unit + display-only conversion (
formatMetricValue/parseMetricValueat the edges). All values stored inmetric.unit(metric system); user unit preference applied on render/parse only. baseMetricIdprovider→canonical mirroring —fitbitDailyStepsandhkDailyStepsboth feeddailySteps, so charts/goals/programs target the canonical metric regardless of device. Rare in this category and genuinely good.sourceInfomapping bags — adding a provider metric is a data change, not a code change.- Source-scoped re-sync (
replaceMetricValues: delete{source, date range}then bulk insert) — manual entries survive provider re-syncs. Plus thesyncedwatermark for resumable sync. hasData()probe on connect (HealthKit) — only onboard metrics the device actually has data for.- Sync transparency — per-user audit log (
UviloLog) + live per-metric value counts in the connect modal. Cheap, high trust payoff. - Metric groups as co-entry — chest/abdomen/thigh skinfolds entered on one row, derived body-fat % computes in the same row. A real workflow, not just taxonomy.
- Two-threshold goal band (
goalLow/goalMid+betterValues) — maps to red/amber/green gauges and “8k steps is OK, 10k is the goal”. - User-visible backfill horizon (
profiles.syncStartMonths, default 3). - Seeded catalog of ~30 metrics: body composition (weight, body fat + 3-point skinfold formulas), 11 girth measurements, steps, energy (basal/active/total), sleep, mindful minutes, back pain, plank test — a ready-made starting library.
- A Nightwatch E2E (
tests/nightwatch/metrics/enter_calculated_metric.js) that doubles as an acceptance spec: addbodyFat3PointMale, enter weight + three skinfolds, assert the derived value.
2.2 Sync: what legacy actually had
Three providers via a plugin framework (uvilo-apps): Fitbit (OAuth 1.0a — broken as committed: webhook handler references an undefined variable, wrong-arity delete call, missing imports), Jawbone (company died 2017), and Apple HealthKit (Cordova plugin, device-local, the only one that worked). Withings/Endomondo/MyFitnessPal/Wahoo were “vote for this” placeholders. No aggregator was ever used. The working HealthKit path — permission sheet, per-metric day-bucketed sync, change monitoring, watermarks — is precedent for the phone-as-hub strategy in §4.
2.3 Charts: what “pan/zoom” actually was
Vendored Highstock 2.1.5 (2015) StockCharts: the range-selector button bar + navigator brush (no zoomType, no panning config). All values shipped to the client (publication had no date window or bucketing) and re-rendered on any change; app code manually stripped Highstock’s touch handlers so pages could scroll. The feature to preserve is explorable time-series (range presets + brush/zoom + touch pan); the implementation is fully replaceable.
2.4 Explicitly avoid (legacy defects)
vm.runInNewContext(metric.calculation, …)— user-editable JS from the DB executed server-side. An RCE; replace with a whitelisted expression evaluator (§6.3).- Live OAuth secrets committed in
config/settings*.json(Fitbit key/secret, Jawbone id/secret). Rotate/retire; never repeat. - No unique constraint on
(userId, metricId, date, source)— idempotency by upsert-selector only. - ISO date strings with mixed day/instant granularity, lexicographic range queries, and a
date + '+'sentinel hack. Usetimestamptz+ a separate local-day column. - Client-side Mongo writes via allow-rules (goal slider, unit select, value edits).
- Publish-everything charts — no windowing, no rollups; will not survive years of step data.
- Zero vs missing conflated (
!valuedrops legit zeros; missing coerced to 0) and minus signs stripped in parsing (negative metrics impossible). - Dead fields (
goalStart/goalEnd/goalDays— declared, never used), dead publications, broken setup-UI handlers, the 428-line jQuery goal slider (which also displayed storage units instead of the user’s units).
3. Wearable-sync landscape (aggregators)
No mainstream aggregator has a free production tier in 2026. Verified pricing:
| Vendor | Entry | ~500 users | ~5,000 users | Capacitor SDK | Viability notes |
|---|---|---|---|---|---|
| ROOK (pricing) | $399/mo (≤750 active users) | $399/mo | $999/mo (Core+, ≤5k) | Yes — official, current (docs) | Pre-seed ($1.7M, 2023); webhook delivery with retries + pending buckets; some providers (Whoop, Strava, Dexcom, Samsung) need your own dev accounts |
| Junction (ex-Vital; pricing) | $0.50/user/mo, $300/mo min; free sandbox ≤50 users | $300/mo | ≲$2,500/mo (sales-gated rate) | No (iOS/Android/RN/Flutter) | Best-funded: $18M Series A 2025 (TechCrunch); strategic center shifting to lab testing |
| Terra (pricing, credits) | $499/mo ($399 annual), 100k credits; 200 credits/active user/mo | ~$499/mo | ~$5,000/mo (overage $0.005/credit) | No (iOS/Android/RN/Flutter/Expo) | YC W21, only ~$3.3M raised, ~25 staff; high product velocity; priciest at scale |
| Spike (pricing) | “from $450/mo”, rest sales-gated | ~$450+ | sales-gated | No | $4.2M seed 2024 |
| Thryve (pricing) | €499/mo (≤500 users) | €499/mo | €1,000/mo | No | EU/insurer-focused; Scale tier caps backfill at 14 days |
| Open Wearables (GitHub) | $0 — MIT, self-hosted (~$20–50/mo VPS) | ~$0 | ~$0 | No (OSS native/RN/Flutter SDKs) | Pre-1.0 (Dec 2025 launch, 2.2k stars); no Withings, no CGMs; you own provider apps + breakage |
| Validic | sales-gated enterprise | — | — | — | Incumbent, enterprise motion; wrong fit |
| Human API | — | — | — | — | Exited: acquired by LexisNexis 2023, now insurance underwriting |
| Metriport devices | — | — | — | — | Discontinued; pivoted to medical records. Do not build on it |
| WeFitter | sales-gated | — | — | — | Development reportedly ceased ~2023; too risky |
Independent market survey corroborating the above: Health API Guy, 2026-05-21.
Key structural fact: every aggregator still requires embedding their mobile SDK to get Apple Health / Health Connect data — an aggregator does not spare us mobile-side work; it spares us cloud-provider OAuth plumbing and normalization. Apple Health has no cloud API at all; the phone is the only exit.
4. Phone-as-hub: the no-aggregator path
4.1 Coverage (2026)
Most wearable vendors sync into the platform health stores:
| Brand | → Apple Health (iOS) | → Health Connect (Android) | Own free cloud API |
|---|---|---|---|
| Apple Watch | native | — (can’t pair) | none (no cloud exit) |
| Oura | ✅ | ✅ | ✅ free, webhooks |
| Whoop | ✅ (sleep/workouts/HR/energy; not its 5-stage sleep or Recovery score) | ✅ | ✅ free (needs a membership to register) |
| Garmin | ✅ one-way push | ✅ since 2025-07 | ✅ free, business-only program |
| Fitbit / Google Health | ❌ today — write-back promised “later in 2026” after the 2026-05 Google Health rebrand (Google) | ✅ | Google Health API: free ≤100 users, then CASA assessment $500–$4,500 (verification); legacy Fitbit API shuts Sept 2026 |
| Withings (scales) | ✅ (weight, fat %; not segmented masses) | ✅ | ✅ free, webhooks |
| Polar | ✅ | ✅ | ✅ free, self-serve (no pre-link backfill) |
| Samsung / Galaxy Watch | ❌ | ✅ | none (Health Connect is the sanctioned route) |
| Amazfit/Zepp, Coros | ✅ | ✅ | partner-gated |
| Suunto, Renpho scale | ✅ | shaky/undocumented | — |
So: iOS hub reaches everything except Fitbit (temporarily) and Samsung; Android hub reaches everything except Apple Watch. The branded scores (Whoop Recovery, Garmin Body Battery, Oura Readiness) mostly do not land in the hubs — you get raw metrics.
4.2 Capacitor plugin
Recommended: @capgo/capacitor-health — v8.10.0 published 2026-07-24, requires Capacitor ≥8 (matches our 8.4.2 shells), covers both HealthKit and Health Connect in one API, read+write, 25+ data types including steps, sleep sessions+stages, HR, HRV, weight, body fat, workouts, calories; queryAggregated day-bucketing; MPL-2.0; ~19.8k weekly downloads — an order of magnitude above alternatives. Alternatives checked and rejected: capacitor-health (mley — read-only, no sleep/HRV/weight), @perfood/capacitor-healthkit (pinned to Capacitor 4, dormant), Ubie capacitor-health-connect (stale, Cap 5).
Already in place in uvilo-mono: apps/uvilo-ai/ios/App/App/App.entitlements already carries HealthKit entitlements including background delivery (dormant — added with the Capacitor work). Missing: NSHealthShareUsageDescription/NSHealthUpdateUsageDescription in Info.plist, the plugin itself, and (to review) the health-records access entry, which we do not need and should remove — clinical records trigger extra App Review scrutiny.
4.3 Background-sync reality (design the product around this)
- iOS:
HKObserverQuery+enableBackgroundDelivery(entitlement already provisioned). Cumulative types (steps) are capped at hourly; delivery is best-effort and stops entirely if the user force-quits the app. Wiring observers must happen in native Swift at app launch — a small custom local plugin/AppDelegate addition; no off-the-shelf Capacitor plugin ships it. - Android: foreground reads simple; background reads need the
READ_HEALTH_DATA_IN_BACKGROUNDpermission + a WorkManager periodic worker (15–60 min realistic). Backfill defaults to 30 days pre-grant; older data needsREAD_HEALTH_DATA_HISTORY(Android 15+). - Practical baseline: sync on app open/foreground + opportunistic background delivery. “Eventually fresh,” not real-time. This matches how the legacy HealthKit integration behaved and is fine for daily coaching (habit auto-complete evaluates end-of-day anyway; see §6).
4.4 Compliance (must-do, small)
- Apple 5.1.3: HealthKit data may not be used for advertising/data-mining; must disclose collection; usage-description strings required. Sending data to our own backend for the user’s own coaching is permitted use.
- Google Play: Health Connect permissions require an approved health apps declaration (per-permission justifications, approved use case — “fitness and wellness” fits, privacy policy). Unapproved apps get blocked at runtime. Background + history permissions need their own justification. Budget review latency into the release plan.
- Worth a separate legal pass eventually: US state consumer-health-data laws (e.g., Washington My Health My Data) once health data is stored server-side.
4.5 Direct cloud APIs (for web-only users, later)
Best coverage per unit effort, all free: Oura (self-serve, OAuth2 + webhooks, full history — PATs were retired Dec 2025), Withings (self-serve, webhooks — fills body-composition detail), Garmin Health API (free, webhook-first, business-only application, ~2 business days). Whoop is a cheap fourth. Fitbit/Google Health only if demand justifies CASA cost — and native Apple Health write-back “later in 2026” may make it moot. Avoid Strava: since June 2026 API access requires an active subscription, new apps are capped to single-digit athletes, and the API agreement bans using its data to train AI models — a legal dead end for an AI coaching product (Strava).
Structural limit no vendor removes: web-only Apple Watch and Samsung users cannot be served — those ecosystems have no cloud API.
4.6 Cost comparison
| Path | Entry | ~500 users | ~5,000 users | Recurring vendor risk |
|---|---|---|---|---|
| Phone-as-hub (capgo plugin) | $0 | $0 | $0 | plugin maintenance (healthy), OS policy churn |
| + Oura/Withings/Polar/Garmin direct | $0 | $0 | $0 | per-provider API churn (real: 5 breaking ecosystem changes in the last 14 months) |
| + Fitbit/Google Health API | $0 (≤100 users) | CASA $500–$4,500 | same | Google program changes |
| ROOK | $399/mo | $399/mo | $999/mo | pre-seed vendor; keep our normalized store + abstract ingestion |
| Junction | $300/mo | $300/mo | ~$2,500/mo | strongest company; no Capacitor SDK |
| Terra | $499/mo | ~$499/mo | ~$5,000/mo | thin funding; priciest at scale |
DIY-vs-buy sanity check from a (vendor-biased but directionally useful) analysis: multi-provider DIY runs $63k–138k in year-one engineering; the crossover vs SaaS sits around 10–20k active users (The Momentum). Our situation inverts this: the phone-as-hub path is not multi-provider DIY — it is two integrations (HealthKit + Health Connect) that cover most devices, which is exactly the part aggregators can’t do for us anyway (their SDK would sit in our app just the same).
5. Charting
| Option | Cost | Zoom+pan incl. touch | Large series | Notes |
|---|---|---|---|---|
| MUI X Charts Pro v9 | $0 incremental — Pro license already held (NEXT_PUBLIC_MUI_X_PRO_LICENSE, @mui/x-data-grid-pro@9.7.0 in 16 packages) | ✅ wheel/pinch/drag/pan (zoomInteractionConfig) (docs) | Weakest of three (SVG); Pro sampling (lttb) mitigates; WebGL is Premium-only | Native MUI theming; touch gestures are the newest of the three — prototype in the WebView first |
| Apache ECharts 6 | $0 (Apache-2.0) | ✅ dataZoom inside (pinch/drag) + slider; best mobile record | Best (canvas, progressive, lttb) | ~368 KB gz full, tree-shakeable via echarts/core; manual MUI theme |
| Highcharts Core v13 | $366/yr/seat (SaaS annual; pan/zoom is in Core, Stock not needed) (shop) | ✅ mature, but open mobile pinch bugs (#19217, #19785) | Very good (Boost/WebGL in Core) | License scope: one external app per SaaS seat (uvilo-ai + forgentic could count as two) |
| Recharts / Observable Plot / visx / lightweight-charts | $0 | ❌ or DIY pinch; lightweight-charts requires TradingView attribution | — | Rejected |
Decision (Erik, 2026-07-29): Apache ECharts 6. An interactive side-by-side demo (both libraries, identical weight/steps series, zoom/pan/pinch, goal lines, range presets) was built and evaluated; Erik chose ECharts. It is free, has the strongest mobile-touch and large-series record, and its mini-map slider mirrors the Highstock navigator users already knew. MUI X Charts Pro remains the documented fallback; Highcharts is not re-licensed.
6. Net-new designs
6.1 Habit auto-complete engine (Method §11.3)
- Link: habit ↔ metric with
doneThreshold, optionalpartialThreshold, and a comparator implied by the metric’sbetterValues(at-least for higher-is-better like steps; at-most for lower-is-better like screen time). - Evaluation: immediate on ingest. The moment values land — manual entry and coach-recorded values evaluate in the same request; sync batches emit an evaluation event per affected user-day — linked habits update right away, so the checkmark appears as soon as the step count crosses the threshold. The one exception is lower-is-better habits (screen time under 2 h): “stayed under” is only provable once the day is over, so those confirm at the user’s local day close (grace-period aware). Auto-set only upward transitions on
emptytasks (empty→partial→done); never overwrite a user’s manual state. - Prerequisite: a server-side
completeHabitForDate(ownerId, habitId, isoDate, completion)primitive — does not exist today; habit completion is currently a client-side generated-hook update onEvent.completed(packages/@erikdakoda/habit-ui/components/HabitToggleEvent.tsx).
6.2 Goals: band + SMART target
Keep the legacy two-threshold band (partial/done thresholds, red-amber-green gauges — it doubles as the auto-complete config) and add what legacy declared but never built: baseline, target value, target date per user-metric, aligning with Method §10 (SMART framing) and §2.11 (periodic reevaluation). Progress = position between baseline and target; trajectory = recent trend extrapolated to the target date.
6.3 Calculated metrics without the RCE
Replace vm.runInNewContext with a sandboxed expression grammar (arithmetic, dependency variables, age/gender/height pseudo-variables) — e.g. expr-eval-style parser with a whitelist, no property access, no function calls beyond an approved math set. Seeded formulas (body-fat 3-point, lean mass) become data; user-authored formulas become safe.
6.4 Custom units (new)
Ship a seeded units table (port the legacy 11 measures, fixing its defects: money no-op conversions, scale off-by-one on 1-N scales, volume anchor typo) and add user-defined units (name, plural, abbreviation, optional conversion to a canonical unit of an existing measure, or standalone count-like units: pomodoros, chapters, glasses). Canonical-unit storage + display conversion stays exactly as legacy did it. Scale metrics (1–N) support per-value labels (1 = Terrible … 5 = Great) and render as a labeled slider or a dropdown, so subjective metrics read as words while storing as numbers.
7. Fit with uvilo-mono (readiness facts)
- Greenfield with footholds: zero metric/wearable/chart code exists; a commented-out Metrics nav entry is already reserved (
apps/uvilo-ai/src/config/navigation.ts:71-77); iOS HealthKit entitlements already provisioned (apps/uvilo-ai/ios/App/App/App.entitlements, incl. background delivery; Info.plist usage strings still missing). - Schema conventions: new
Metric-domain models slot into the established pattern —.zmodelper domain package, registered inpackages/@erikdakoda/database/schema.zmodel+ModelConfig.ts;NamedItem/OwnedItemdelegates give owner scoping and policies for free;ExecutionLogis the precedent for a high-volume child table with parent-delegated policies (check(...)). Global catalog rows will follow the Taxonomy/Resource publish pattern rather than boot-time reseeding. - Jobs: Inngest + ExecutionRun framework is mature (cron triggers, non-admin owner-scoped events, abort/checkpoint discipline) — sync jobs and the nightly auto-complete sweep have reference implementations to copy (
packages/@erikdakoda/habit/server/*,docs/execution-jobs.md). - Connections ride the Composio surface. The Composio plan (
.cursor/plans/composio_integration_7b9dc656.plan.md) ships before Metrics; its three pre-existing security fixes are already completed todos, and it delivers the Connections tab in user settings (TabConnections.tsx→ConnectionsPanelincomposio-ui, both still pending todos there). Metrics extends that panel with health connector cards — Apple Health and Google Health (Health Connect) on native platforms, Oura for everyone — using the same card anatomy (logo, status chip, connect/disconnect, last-synced) so the user never sees which mechanism a connection uses. Oura’s OAuth tokens are held by us in a dedicated model following the Composio plan’s column-secrecy conventions (@omit, precedentAccount.zmodel:30) and its authorize-helper and callback-hardening patterns. - Packaging:
@erikdakoda/metric+@erikdakoda/metric-uiclone thehabit/habit-uitemplate (scaffolding, tsconfig sync scripts, AI-tool five-tier layout, i18n, page re-export + nav entry). - Caution from recent history: generic ZenStack
updatecalls with runtime-built selects have caused multi-GB TS type instantiations — metric CRUD code must use concrete, non-generic query signatures.
8. Decision summary — all settled (Erik, 2026-07-29)
| # | Decision | Settled outcome |
|---|---|---|
| D1 | Wearable-sync strategy | Phone-as-hub, no aggregator (capgo plugin); native background sync (iOS observer + Android WorkManager) included up front |
| D2 | Aggregator, if ever needed | ROOK first (price + Capacitor SDK), Junction second; not Terra — documented fallback only |
| D3 | Direct cloud connections | Oura now, to scope the work and value of direct integrations; Withings/Garmin later on demand; skip Strava; Fitbit only if demand funds CASA |
| D4 | Chart library | Apache ECharts 6 (Erik’s preference after the interactive demo); MUI X Charts Pro documented fallback; Highcharts not re-licensed |
| D5 | Data model | Port catalog/subscription/values shape to ZenStack; timestamptz + local-day; unique (user, metric, time, source); publish-workflow catalog |
| D6 | Calculated metrics | Whitelisted expression evaluator; never vm |
| D7 | Units | Seeded units table + user-defined custom units; canonical storage; 1–N scales carry per-value labels rendered as labeled slider or dropdown |
| D8 | Goal model | Keep band (drives gauges + auto-complete) and add baseline/target/date (SMART) |
| D9 | Auto-complete engine | Immediate evaluation on ingest (manual/AI in-request; sync via per-day events); day-close confirmation only for lower-is-better habits; upward-only transitions; new completeHabitForDate primitive |
| — | Connections surface | Health connectors listed alongside Composio connectors in the one Connections tab; Composio plan ships first |
| — | Legacy data | Migrate legacy user hTsXvc9x8eyNNyNfE → both usr_cmflhqg0500009s8obw6jtucx and usr_cmms0rurm000041uybelkx2bd; no changes to the legacy repo |
9. Build phases (reflected in the implementation plan)
- Core domain: models (Metric, UserMetric, MetricValue, Unit incl. custom units + scale labels), versioned seeds, manual entry UI, metrics page + nav, safe calculation engine, AI tools, ECharts 6 charts.
- Goals & auto-complete: goal band + SMART fields, gauges/dashboard widgets, habit↔metric link,
completeHabitForDate, immediate-on-ingest evaluation engine. - Phone sync: capgo plugin, iOS usage strings + entitlement cleanup, connect UX with
hasDataprobes + live counts, watermark/idempotent ingestion, Play health declaration, and native background delivery (iOS Swift observer + Android WorkManager) in the same phase. - Connections & Oura: extend the Composio-plan Connections panel with health connector cards; implement the Oura OAuth connector (webhooks + backfill).
- Legacy migration: one-off script copying legacy user
hTsXvc9x8eyNNyNfE’s metric data into both of Erik’s accounts; idempotent, dry-run first, read-only against the legacy MongoDB.
10. Key sources
Aggregators: ROOK pricing · ROOK Capacitor SDK · Junction pricing · Junction providers · Junction Series A · Terra pricing + credits · Spike · Thryve · Human API → LexisNexis · Open Wearables · Health API Guy market analysis
Native path: @capgo/capacitor-health · Apple background-delivery entitlement · Apple review guidelines 5.1.3 · Health Connect background/history reads · Play health declaration · Google Health API + verification · Garmin program FAQ · Oura auth · Withings API · Polar AccessLink · Whoop dev · Strava API changes · Google Health rebrand / Apple Health write-back · Garmin → Health Connect
Charts: MUI X zoom/pan docs · MUI pricing · Highcharts shop · Highcharts zooming · ECharts features · ECharts modular import