Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .backlog/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
project_name: "OpenGlucose"
default_status: "To Do"
statuses: ["To Do", "In Progress", "Done"]
labels: []
definition_of_done: []
date_format: yyyy-mm-dd
max_column_width: 20
default_editor: "vim"
auto_open_browser: false
default_port: 6420
remote_operations: true
auto_commit: false
filesystem_only: false
zero_padded_ids: 3
bypass_git_hooks: true
check_active_branches: true
active_branch_days: 10
task_prefix: "task"
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
id: TASK-001
title: Rename openhealth to openglucose across codebase
status: To Do
assignee: []
labels:
- 'epic:core'
- 'phase:1-foundation'
dependencies: []
priority: high
ordinal: 1000
---

## Description

<!-- SECTION:DESCRIPTION:BEGIN -->
The product is now OpenGlucose, but the app module directory is still `openhealth/` and several identifiers still use the legacy `openhealth` / `aidex_flutter` / `com.aidex.aidex_flutter` names. Do a clean, repo-wide rename so naming is consistent with the OpenGlucose brand.

Scope of the rename:
- App module directory `openhealth/` -> `openglucose/` (the Flutter reference app).
- Android `namespace` `com.aidex.aidex_flutter` and the Java package path `com/aidex/aidex_flutter` (MainActivity, GlucoseLiveUpdateService) -> a consistent `com.openglucose.app` package.
- Any lingering `aidex_flutter` references in `openhealth/README.md` (currently the default "A new Flutter project" template) and the iOS project where they do not refer to the Aidex *driver* (the `cgm_aidex` package and Aidex protocol stay named Aidex — that is the sensor vendor, not the app).
- Update workspace references, import paths, melos/pubspec workspace globs, CI paths, and docs that point at `openhealth/`.

Honesty/scope note: do NOT rename the `cgm_aidex` package or Aidex protocol symbols — "Aidex" is the real sensor vendor and must stay. This task only retires the legacy *app* name.

**Fleet: NOT parallelizable — run ALONE.** Touches nearly everything: `openhealth/` (entire dir, becomes `openglucose/`), `openhealth/android/app/build.gradle.kts`, `openhealth/android/app/src/main/java/com/aidex/aidex_flutter/*`, `openhealth/pubspec.yaml`, `openhealth/ios/Runner.xcodeproj/project.pbxproj`, root `pubspec.yaml`/workspace config, CI configs, and docs. Must be sequenced so no other branch is mid-flight in `openhealth/`.
<!-- SECTION:DESCRIPTION:END -->

## Acceptance Criteria
<!-- AC:BEGIN -->
- [ ] #1 App module directory renamed to `openglucose/` with all workspace/import/CI references updated
- [ ] #2 Android namespace and Java package renamed off `com.aidex.aidex_flutter` to a consistent `com.openglucose.*`; app builds and runs
- [ ] #3 No remaining `openhealth` or `aidex_flutter` app-name references (excluding the legitimate `cgm_aidex` driver package and Aidex protocol/vendor names)
- [ ] #4 `flutter build` (android + ios) and the existing test suite pass after the rename
- [ ] #5 README(s) and docs updated to the new module path
<!-- AC:END -->

## Implementation Notes

<!-- SECTION:NOTES:BEGIN -->
Bundle id `com.openglucose.app` is already set in `build.gradle.kts` and iOS `PRODUCT_BUNDLE_IDENTIFIER`; the mismatch to fix is the Android `namespace`/Java package and the module directory name.
<!-- SECTION:NOTES:END -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
id: TASK-002
title: Normalized event and health-data domain models
status: To Do
assignee: []
labels:
- 'epic:health-data'
- 'phase:1-foundation'
dependencies: []
priority: high
ordinal: 2000
---

## Description

<!-- SECTION:DESCRIPTION:BEGIN -->
Foundation data layer for everything beyond raw glucose. Add vendor-agnostic, pure-Dart domain models for user-logged events and imported health signals, living in the reusable packages (e.g. `packages/cgm_core` or a new `packages/health_core`) — NOT in Flutter UI code, per the workspace's protocol/UI separation.

Models to define:
- `HealthEvent` base with typed variants: meal, exercise/workout, sleep, medication/supplement, note, mood/energy, stress, illness, fasting, caffeine, alcohol.
- Each event carries: timestamp(s) (point or interval), free-text note, tags, and optional structured payload (e.g. carbs/protein/fat for meals; duration/intensity/HR for workouts; quality/stages for sleep).
- Imported health-signal models: activity/steps, workouts, sleep sessions, heart rate samples, calories — normalized so they are source-agnostic (HealthKit vs Health Connect vs manual).
- Stable ids, source provenance (manual / healthkit / health-connect / derived), and serialization (JSON) for local persistence and export.

This is the schema that journaling, analytics, chart overlays, imports, AI, and export all build on. Keep it pure Dart and well-tested.

**Fleet: parallelizable (foundation, blocks many). Touches `packages/cgm_core` (or new `packages/health_core`) models + tests only — no app UI. Should land EARLY; downstream tasks (journaling, analytics, imports, AI, export) depend on it.**
<!-- SECTION:DESCRIPTION:END -->

## Acceptance Criteria
<!-- AC:BEGIN -->
- [ ] #1 Pure-Dart `HealthEvent` model with all listed variants and a normalized imported-signal model set
- [ ] #2 Source provenance + stable ids + JSON (de)serialization round-trip covered by tests
- [ ] #3 Models live in a reusable package, not in `openhealth/lib`, and have no Flutter dependency
- [ ] #4 Unit tests for serialization and variant construction pass
<!-- AC:END -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
id: TASK-003
title: Local persistence for events and insights
status: To Do
assignee: []
labels:
- 'epic:core'
- 'phase:1-foundation'
dependencies:
- TASK-002
priority: high
ordinal: 3000
---

## Description

<!-- SECTION:DESCRIPTION:BEGIN -->
Persist user events, imported health signals, and derived insights on-device so journaling and summaries are available fully offline — consistent with OpenGlucose's local-first, user-owned-data positioning.

Build a local store (e.g. SQLite/Drift, Isar, or sembast — pick and record an ADR) for `HealthEvent`s and imported signals from TASK-002, plus a cache for derived analytics. Provide a clean repository interface so UI and analytics read/write through it without knowing the backend. No cloud dependency.

Requirements:
- Insert/update/delete/query events by time range and type.
- Store imported health signals with dedup by source + external id.
- Cache derived insights (e.g. daily metrics) with invalidation when underlying data changes.
- Migration story for schema evolution.

**Fleet: parallelizable after TASK-002. Touches a new persistence package (e.g. `packages/health_store`) + repository interfaces; minimal app wiring. Record an ADR for the chosen storage engine in `docs/decisions/`.**
<!-- SECTION:DESCRIPTION:END -->

## Acceptance Criteria
<!-- AC:BEGIN -->
- [ ] #1 Local store persists events and imported signals across app restarts
- [ ] #2 Query by time range and type; dedup imported signals by source + external id
- [ ] #3 Repository interface abstracts the storage engine from UI/analytics
- [ ] #4 ADR recorded for the storage choice; migration path documented
- [ ] #5 Tests cover CRUD, dedup, and a migration
<!-- AC:END -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
id: TASK-004
title: Contextual messaging subsystem foundation
status: To Do
assignee: []
labels:
- 'epic:ux'
- 'phase:1-foundation'
dependencies: []
priority: high
ordinal: 4000
---

## Description

<!-- SECTION:DESCRIPTION:BEGIN -->
Foundation for surfacing in-app contextual messages — short Tips and occasional temporary info boxes — driven by app/user state, without becoming nagware. This is the shared engine that TASK-005 (Tips) and TASK-006 (temporary info boxes) build on.

Build a rule-driven messaging engine:
- A `ContextualMessage` model: id, type (tip / info-box), title/body, trigger condition, priority, dismissibility, frequency cap, and an optional CTA.
- A trigger evaluator that reads app/sensor/data state (e.g. "no events logged yet", "sensor warming up", "first full day of data", "wide glucose swings today") and decides which messages are eligible.
- Persistence of dismissals and shown-counts (so a tip isn't repeated forever) — reuse the local store from TASK-003 or a lightweight prefs store.
- A simple presentation API the UI layer can subscribe to, so surfaces (banners, cards) render from local state.

Honesty/UX guardrails: messages are observations and guidance, never medical advice; respect frequency caps; everything is dismissible.

**Fleet: parallelizable (foundation). Touches a new `packages/messaging` (engine + models) and a thin app subscription point. TASK-005 and TASK-006 depend on this and should NOT start until the engine API is stable.**
<!-- SECTION:DESCRIPTION:END -->

## Acceptance Criteria
<!-- AC:BEGIN -->
- [ ] #1 `ContextualMessage` model + rule/trigger evaluator implemented in a reusable package
- [ ] #2 Dismissals and shown-counts persisted; frequency caps enforced
- [ ] #3 Presentation API exposes eligible messages as local state for the UI to render
- [ ] #4 No medical-advice phrasing; all messages dismissible
- [ ] #5 Tests cover trigger evaluation, frequency capping, and dismissal persistence
<!-- AC:END -->
34 changes: 34 additions & 0 deletions .backlog/tasks/task-005 - Contextual-tips-feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
id: TASK-005
title: Contextual tips feature
status: To Do
assignee: []
labels:
- 'epic:ux'
- 'phase:2-build'
dependencies:
- TASK-004
priority: medium
ordinal: 5000
---

## Description

<!-- SECTION:DESCRIPTION:BEGIN -->
Ship the Tips experience on top of the contextual-messaging engine (TASK-004). Tips are short, helpful, dismissible nudges that help users get more from the app and understand their glucose patterns — framed as observations/guidance, never medical advice.

Includes:
- An initial library of tip content (onboarding tips, "log your first meal", "your glucose was stable overnight", "try tagging caffeine", metric explainers).
- Tip surfaces in the UI (e.g. a dismissible card on the dashboard / contextual inline hints).
- Wiring tip triggers to real app/data state via the engine.

**Fleet: parallelizable after TASK-004. Touches app UI (dashboard/tip card widgets) + a tips content file. Shares the messaging engine with TASK-006 but the UI surfaces differ; coordinate on shared widgets if any.**
<!-- SECTION:DESCRIPTION:END -->

## Acceptance Criteria
<!-- AC:BEGIN -->
- [ ] #1 Tip content library defined and wired to engine triggers
- [ ] #2 Dismissible tip surface renders from messaging state
- [ ] #3 Tips respect frequency caps and never repeat after dismissal
- [ ] #4 Copy reviewed for wellness (non-medical) framing
<!-- AC:END -->
34 changes: 34 additions & 0 deletions .backlog/tasks/task-006 - Temporary-contextual-info-boxes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
id: TASK-006
title: Temporary contextual info boxes
status: To Do
assignee: []
labels:
- 'epic:ux'
- 'phase:2-build'
dependencies:
- TASK-004
priority: medium
ordinal: 6000
---

## Description

<!-- SECTION:DESCRIPTION:BEGIN -->
Ship occasional, temporary info boxes on top of the contextual-messaging engine (TASK-004). Unlike persistent tips, these are time- or state-bounded notices (e.g. "Sensor warming up — readings stabilize in ~1h", "New: you can now export your data", "Heads up: your last sync was 40 min ago") that appear when relevant and then go away.

Includes:
- Info-box UI surface (banner/inline card) distinct from tips, with clear dismiss + auto-expiry.
- Trigger wiring for transient states (warmup, stale data, new-feature announcements, data-import completion).
- Expiry/auto-hide behavior so boxes don't linger after the condition clears.

**Fleet: parallelizable after TASK-004. Touches app UI (info-box/banner widget) + trigger wiring. Shares the messaging engine with TASK-005; serialize if the same banner widget is edited by both.**
<!-- SECTION:DESCRIPTION:END -->

## Acceptance Criteria
<!-- AC:BEGIN -->
- [ ] #1 Temporary info-box surface with dismiss + auto-expiry
- [ ] #2 Triggers wired for warmup, stale-data, and announcement-style states
- [ ] #3 Boxes auto-hide once the underlying condition clears
- [ ] #4 Non-medical, observation-only framing
<!-- AC:END -->
37 changes: 37 additions & 0 deletions .backlog/tasks/task-007 - First-run-onboarding-flow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
id: TASK-007
title: First-run onboarding flow
status: To Do
assignee: []
labels:
- 'epic:onboarding'
- 'phase:1-foundation'
dependencies: []
priority: high
ordinal: 7000
---

## Description

<!-- SECTION:DESCRIPTION:BEGIN -->
A light, honest first-run onboarding that gets a new user from install to a working sensor with the right expectations. Inspired by Stelo/Lingo's emphasis on guided setup, but kept minimal and privacy-forward.

Steps (keep it short — skippable where reasonable):
1. Welcome + one-line value prop (open-source, local-first, wellness — not a medical device).
2. Connect sensor: scan, select, pair, activate, warmup expectation (~1h) — hand off to the sensor lifecycle UX (TASK-008) for the heavy lifting.
3. Set target/display range (the user's preferred glucose range and units).
4. Privacy explainer: data stays on device, nothing goes to the manufacturer, BYO-key for any optional AI.
5. Wellness disclaimer acknowledgment (self-experimentation framing; not for diabetes management/medical decisions).

Persist that onboarding is complete so it only shows on first run (re-runnable from settings).

**Fleet: parallelizable, but depends conceptually on TASK-008 (sensor lifecycle) for the pairing step — can be built in parallel against a stubbed pairing handoff, then wired. Touches new onboarding screens in `openhealth/lib` + a "first run complete" flag in prefs. Foundation: blocks nothing hard but should land early for new-user quality.**
<!-- SECTION:DESCRIPTION:END -->

## Acceptance Criteria
<!-- AC:BEGIN -->
- [ ] #1 First-run flow: welcome, connect-sensor handoff, set range, privacy explainer, wellness disclaimer
- [ ] #2 Onboarding completion persisted; not shown again on subsequent launches; re-runnable from settings
- [ ] #3 Privacy + non-medical wellness framing stated plainly
- [ ] #4 Steps are skippable where sensible and the app is usable after completion
<!-- AC:END -->
36 changes: 36 additions & 0 deletions .backlog/tasks/task-008 - Sensor-lifecycle-center.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
id: TASK-008
title: Sensor lifecycle center
status: To Do
assignee: []
labels:
- 'epic:core'
- 'phase:1-foundation'
dependencies: []
priority: high
ordinal: 8000
---

## Description

<!-- SECTION:DESCRIPTION:BEGIN -->
Make sensor state legible at all times. Today the app scans/connects/syncs but does not give a clear, always-available picture of where the sensor is in its lifecycle. Add explicit, user-facing states: scanning, pairing, warming up (with countdown), ready/active, reconnecting, expiring (sensor age + remaining life), expired, and failed.

Includes:
- A sensor lifecycle/status surface (card or dedicated screen) showing current state, sensor age, remaining-life, and last successful sync time.
- A warmup countdown (~1h) and a background-freshness indicator.
- An explicit reconnect button and a documented auto-retry policy.
- State machine that derives these from driver/session signals (build on existing `session_presentation.dart` / `app_controller.dart`).

Strongest common denominator across Stelo, GS3, Lingo, Supersapiens — the #1 gap to "daily driver".

**Fleet: parallelizable, but it is the central sensor-state surface — TASK-009 (alerts) and TASK-007 (onboarding pairing step) depend on its state model. Touches `openhealth/lib/src/session_presentation.dart`, `app_controller.dart`, and a new lifecycle widget. Coordinate with TASK-009 since both read sensor state.**
<!-- SECTION:DESCRIPTION:END -->

## Acceptance Criteria
<!-- AC:BEGIN -->
- [ ] #1 Explicit states surfaced: scanning, pairing, warming-up (countdown), ready, reconnecting, expiring, expired, failed
- [ ] #2 Sensor age, remaining-life, and last-successful-sync time displayed
- [ ] #3 Manual reconnect action + documented auto-retry policy
- [ ] #4 State derived from driver/session signals via a tested state machine
<!-- AC:END -->
37 changes: 37 additions & 0 deletions .backlog/tasks/task-009 - High-low-and-data-freshness-alerts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
id: TASK-009
title: High/low and data-freshness alerts
status: To Do
assignee: []
labels:
- 'epic:core'
- 'phase:1-foundation'
dependencies:
- TASK-008
priority: high
ordinal: 9000
---

## Description

<!-- SECTION:DESCRIPTION:BEGIN -->
Turn the app from passive viewer into something operational. Add user-configurable alerts:
- High and low glucose thresholds (custom values + units), with a wellness-framed (non-diagnostic) presentation.
- Stale-data alert (no fresh reading for N minutes).
- Disconnect alert (sensor connection lost).
- Local notifications (foreground + background) + an in-app alert history.

Honesty guardrail: these are user-configured wellness alerts, NOT clinical hypo/hyper safety alarms; copy must avoid implying medical-grade urgent-low protection. State the wellness/self-experimentation framing where thresholds are set.

Build alert evaluation in pure Dart over normalized readings; deliver via platform notifications. Reuse sensor state from TASK-008 for disconnect/stale detection.

**Fleet: parallelizable after TASK-008. Touches a new alerts package (pure-Dart evaluation) + platform notification wiring in `openhealth/lib` (android/ios notification channels). Reads sensor state from TASK-008 — coordinate, don't edit the same lifecycle widget simultaneously.**
<!-- SECTION:DESCRIPTION:END -->

## Acceptance Criteria
<!-- AC:BEGIN -->
- [ ] #1 User-configurable high/low thresholds with units; stale-data and disconnect alerts
- [ ] #2 Local notifications fire foreground and background; in-app alert history kept
- [ ] #3 Alert evaluation is pure-Dart over normalized readings and unit-tested
- [ ] #4 Copy reviewed: wellness alerts, explicitly NOT clinical hypo/hyper safety alarms
<!-- AC:END -->
39 changes: 39 additions & 0 deletions .backlog/tasks/task-010 - Event-journal-UI.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
id: TASK-010
title: Event journal UI (meals, notes, events)
status: To Do
assignee: []
labels:
- 'epic:health-data'
- 'phase:2-build'
dependencies:
- TASK-002
- TASK-003
priority: high
ordinal: 10000
---

## Description

<!-- SECTION:DESCRIPTION:BEGIN -->
The journaling UI on top of the event model (TASK-002) and local store (TASK-003). Lets users log and review meals, notes, and events tagged to a time so glucose can be reasoned about in context.

Includes:
- Fast-add flows: meal, workout, sleep note, medication/supplement, generic note, mood/energy.
- Quick tags (caffeine, alcohol, stress, illness, fasting) and free-text.
- Optional structured fields per type (e.g. carbs for meals; duration/intensity for workouts).
- A chronological timeline/list view to browse, edit, and delete events.
- Convenience: duplicate-previous-meal, event templates.

Keep it search-free and low-friction for v1 (manual entry); food database / AI capture come later (TASK-019/020).

**Fleet: parallelizable after TASK-002 + TASK-003. Touches new journaling screens/widgets in `openhealth/lib` + repository calls. Shares the dashboard navigation shell with the UX-polish tasks (TASK-013/014) — coordinate on nav/shared widgets.**
<!-- SECTION:DESCRIPTION:END -->

## Acceptance Criteria
<!-- AC:BEGIN -->
- [ ] #1 Fast-add for meal, workout, sleep, medication, note, mood with quick tags and free-text
- [ ] #2 Chronological timeline to browse/edit/delete events, persisted via the local store
- [ ] #3 Duplicate-previous and templates for repeat entries
- [ ] #4 Works fully offline; no medical-advice framing
<!-- AC:END -->
Loading