glp-companion/BUILD_STATE.md

52 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Build Execution Ledger
## Active Target
- **Current Milestone:** Phase 4: Recipe Web Scraper Engine & Meal Planning Calendar — COMPLETE
- **Status:** Phase 4 Complete (next: Phase 5)
## Phase Checklist
- [x] Phase 1: Foundation & Identity (Passwordless SSO & Encrypted Drift DB)
- [x] Phase 2: Medication Domain, Injection Rotation, Serum Modeling
- [x] Phase 3: Nutrition, Protein Target Tracking, HealthGateway Sync
- [x] Phase 4: Recipe Web Scraper Engine & Meal Planning Calendar
- [ ] Phase 5: Pantry Delta Engine & Auto-Shopping Generator
- [ ] Phase 6: Hardening, Native Desktop/Web Polish, CI/CD
## Phase 2 Deliverables (2026-10-16)
- [x] Domain: `DoseEntry` entity, 12-quadrant `InjectionSite` rotation model, `Glp1Compound` value object (Sema 168h / Tirze 120h / Lira 13h), `IMedicationRepository` contract.
- [x] Domain: `CalculateSerumLevel` use case implementing `C(t) = Σ D_i · 0.5^((t − t_i)/t_half)`.
- [x] Data: injection-history CRUD on `AppDatabase` + drift-backed `MedicationRepository` (record ↔ entity mapping).
- [x] Presentation: `MedicationController` (Riverpod StateNotifier) with serum estimation, least-recently-used site rotation, and reminder scheduling; refactored `MedicationScreen` (serum card, rotation suggestion, interactive log dialog, history with delete).
- [x] Platform: `INotificationService` / `PlatformNotificationService` (flutter_local_notifications 17.x; Android/iOS/macOS scheduled reminders, graceful no-op on Web/Windows/Linux); Android boot-receiver manifest entries; `timezone` dependency added.
- [x] Regression fix: `SupabaseAuthService` now resolves its client lazily (baseline widget test no longer throws when Supabase is uninitialized).
- [x] Tests: 33 new unit/widget-fake tests (PK calculator, rotation policy, repository w/ in-memory drift, controller); baseline smoke test green.
## Post-Phase-2 Additions
- [x] Development auth bypass (2026-10-16): debug-only "Continue Without Signing In" button on the login screen (`kDebugMode`-gated, in-memory `devAuthBypassProvider`) lets reviewers enter the app without a Supabase session; the router guard honors the flag and the shell shows an orange "Development mode - not signed in" banner while active. Covered by `test/features/auth/dev_auth_bypass_test.dart` (3 tests).
## Phase 3 Deliverables (2026-10-16)
- [x] Domain: `FoodLogEntry` (+ `MealType` enum), `HydrationLogEntry`, `BiometricEntry` (+ `BiometricSource` enum), `INutritionRepository`, `IHealthSyncRepository` — all pure Dart.
- [x] Data: `AppDatabase` schema v2 (+ migration for v1 installs) with `FoodLogsTable`, `HydrationLogsTable`, `BiometricLogsTable`, range-filtered watch/get/CRUD helpers, `clearSyncedRange` for idempotent re-syncs; drift-backed `NutritionRepository` and `HealthSyncRepository` (record ↔ entity mapping).
- [x] Platform: `HealthGateway` rewrite — `IHealthGateway` + conditional-import factory; mobile impl (`health_gateway_mobile.dart`) wraps `package:health` for `WEIGHT` (kg→lb normalization) and `ACTIVE_ENERGY_BURNED` (joule→kcal) with double-guarded try/catch; fallback impl (`health_gateway_fallback.dart`) for Web/Windows/macOS never touches platform channels (reads served from the drift cache, writes via manual entry).
- [x] Presentation: `NutritionController` (Riverpod `AsyncNotifier`; today's logs, 100 g protein / 96 oz water targets, meal grouping, quick-add water) and `BiometricController` (weight history, 7/30-day deltas, manual entry, native sync with per-day active-energy aggregation); `LogFoodDialog` and `LogWeightDialog`.
- [x] Presentation: `NutritionScreen` upgraded — interactive protein/hydration progress meters, +8/+16/+24 oz quick-add buttons, meal-grouped food diary with delete, weight tracker card (latest weight, 7/30-day trend chips, latest active burn) whose "Log Weight / Sync" button runs `HealthGateway` sync on Android/iOS and opens the manual dialog on Windows/Web; status snackbars via `ref.listen`.
- [x] Tests: 23 new tests — nutrition repository (in-memory drift: CRUD, day-range filter, watch, `MealType` round-trip), nutrition controller (targets, grouping, validation, quick-add, delete, failure retention), biometric controller (manual entry, deltas, fallback short-circuit, permission denial, weight+energy sync idempotency).
- [x] Regression fix: none required — existing 37 tests untouched and green.
## Phase 4 Deliverables (2026-10-16)
- [x] Domain: `Recipe` (+ `MacroProfile`), `RecipeIngredient` (quantity/unit/item parsing: decimals, ASCII + unicode + mixed fractions, known-unit vocabulary), `MealPlanSlot` (reuses nutrition `MealType`), `IRecipeRepository`, `IMealPlanRepository` — all pure Dart; `core/utils/uuid.dart` v4 generator (no new dependency).
- [x] Domain: `ScrapeRecipeFromUrl` use case — `package:http` download (injectable `RecipeHtmlFetcher` for tests), `package:html` DOM parse, JSON-LD `@graph`/root/array/`@type`-list navigation, `HowToStep`/`HowToSection` instruction flattening, ISO-8601 `prepTime`/`cookTime`, `recipeYield`, regex nutrition parsing (`calories`, `proteinContent`, `carbohydrateContent`, `fatContent`), image list/object unwrap, OpenGraph fallback (`og:title`/`og:image`/`og:description`), typed `RecipeScrapeException`.
- [x] Data: `AppDatabase` schema v3 (migration for v1/v2 installs) with `RecipesTable` (UUID PK, JSON ingredient/instruction columns, macros, `createdAt`) and `MealPlanSlotsTable` (UUID PK, plannedDate, mealType, nullable `recipeId` FK with `ON DELETE SET NULL`, customNotes, isCompleted); drift-backed `DriftRecipeRepository` (URL-deduplicated `importRecipe`, `createdAt` preserved on re-import) and `DriftMealPlanRepository` (half-open `[from, to)` window, upsert-by-id).
- [x] Presentation: `RecipeImportController` (Riverpod `Notifier`; URL submit → loading → preview modal state, live catalog watch stream, confirm-save/dismiss/delete) and `MealPlanCalendarController` (Monday–Sunday window, next/previous/today navigation, slot assign/upsert/clear, prepared toggle, per-day protein rollup against the nutrition 100 g target, deleted-recipe slot normalization, stale-window refresh guard).
- [x] Presentation: `MealPlannerScreen` refactor — URL import bar with spinner, `RecipePreviewDialog` (image, meta chips, macro tiles, ingredients, steps, save with error surface), `SavedRecipesTray` (draggable cards with thumbnail + protein badge + quick-assign), `WeeklyCalendarView` (≥900 dp: 7-column grid; below: tabbed pager) with `DragTarget` meal slots, prepared checkboxes, clear menu, per-day protein indicator (progress bar vs. target), `AssignSlotDialog` (saved-recipe dropdown or custom description), week navigation header.
- [x] Tests: 25 new tests — `recipe_scraper_test.dart` (JSON-LD `@graph`/root/array/list-`@type` extraction, macro/ingredient/instruction/duration/yield parsing, malformed-JSON fallthrough, OpenGraph fallback, `execute()` URL validation & error mapping) and `meal_plan_repository_test.dart` (`startOfWeek`, recipe CRUD/URL-dedup/watch, slot window filter/upsert/delete, calendar rollup/assignment/navigation/custom entries/prepared toggles/recipe-deletion normalization, import-controller empty-URL guard).
- [x] Regression fix: HowToSection flattening now recurses into `itemListElement` before using the section `name` (parser ordering bug caught by the new test).
## Post-Phase-4 Additions
- [x] Desktop resize overflow fix (2026-10-16): the hatched yellow/black stripes (RenderFlex overflow) shown when shrinking the Windows window are gone — wide-mode day columns now scroll vertically (matching the compact pager), and a `LayoutBuilder` in `MealPlannerScreen` collapses the page into a single scrollable column (with a fixed-height calendar) whenever the body is shorter than ~520 dp. Covered by `test/features/meal_planner/meal_planner_screen_test.dart` (4 widget tests pumping the screen at short-compact, short-wide, tall, and extremely-short window sizes; overflow errors fail widget tests, so green proves no stripes).
## Active Verification Gates
- [x] `flutter pub run build_runner build --delete-conflicting-outputs`
- [x] `flutter analyze` (Zero issues — `No issues found!`)
- [x] `flutter test` (89/89 passing)
- [x] `flutter build web --no-tree-shake-icons` (conditional import keeps `package:health`/`dart:io` out of the web bundle)