Commit Graph

7 Commits

Author SHA1 Message Date
Mike Kell e43603be1b feat(nutrition,pantry): add Phase 3C nutritional search engine, barcode scanning, and dual-source food cache
Implements the architecture 4.8 resolution ladder: local SQLCipher cache ->
Open Food Facts (4s timeout) -> USDA FoodData Central fallback, with every
remote hit written through to the new FoodProductsTable (schema v5).

- domain: FoodProduct entity + IFoodSearchRepository contract (pure Dart)
- data: UsdaFdcClient (FDC nutrient-ID mapper 1008/1003/1004/1005/1079/1093,
  api_key sent as query parameter - FDC ignores body keys and 403s otherwise),
  OpenFoodFactsClient (userAgent with app identity, SearchTerms search,
  getProductV3 barcode lookup), shared RemoteFoodDataSource interface
- presentation: FoodSearchController (400ms debounce, request-token
  supersession), FoodSearchScreen (MobileScanner sheet on mobile, manual UPC
  dialog + notification on desktop/web, macro action sheet with serving
  multipliers, Log to Diary / Add to Pantry actions)
- integration: /food-search route with ?preset=pantry, Nutrition screen entry
  button, Pantry screen Scan Item action
- hardening: FoodSearchUnavailableException distinguishes total source outage
  from a healthy empty result; GoogleHealthConnector dotenv reads now guarded
  with isInitialized (fixes NotInitializedError crashing app_navigation_test)
- tests: +16 (fallback sequence cache->OFF->USDA for text and barcode,
  USDA request shape via MockClient); full suite 170/170, analyze clean
2026-10-17 19:37:06 -04:00
Mike Kell 298cadef32 feat(platform,auth,app): align identity to companionglp.com and harden OAuth deep-link handoff
Identity: rename the application identity to com.companionglp.glpcompanion on every platform (Android applicationId/namespace + MainActivity package, iOS/macOS bundle IDs incl. RunnerTests, Windows CompanyName/copyright, web manifest id, Supabase OAuth redirect scheme).

Deep links: register the custom scheme com.companionglp.glpcompanion:// in iOS/macOS Info.plist (CFBundleURLTypes), the Android VIEW/BROWSABLE intent-filter, and Windows per-user HKCU protocol registration. Server-side steps (Supabase uri_allow-list, Entra optional email claim) are recorded in BUILD_STATE.md.

Windows runner: single-instance mutex (Local\GLPCompanionSingleInstance) so login callbacks are delivered deterministically; SendAppLinkToInstance forwarding with foreground/taskbar-flash fallback so protocol activation can never look like a hang; protocol diagnostics appended to TEMP glpcompanion-protocol.log.

macOS: add the missing com.apple.security.network.client entitlement so the sandboxed runner can reach Supabase at all.

Auth UX: surface deferred OAuth/magic-link handshake failures as snackbars on the login screen; make isAuthenticatedProvider reactive (watches authStateProvider) with a microtask-deferred router refresh so live sign-in and sign-out redirect correctly; add a debug package:logging listener so supabase_flutter diagnostics are visible under flutter run.

Field-verified on Windows: Google, Microsoft (Entra ID), and email magic-link sign-in round trips plus sign-out redirect to /login.
2026-10-17 15:28:22 -04:00
Mike Kell 837b4434f0 feat(app,exercise,recipes,settings): complete Phase 7 navigation and domain expansion
- Exercise feature (lean-mass preservation): MuscleGroup enum + ExerciseEntry
  entity, IExerciseRepository contract with session-scoped in-memory
  implementation, ExerciseController with weekly distinct-session rollup vs.
  the recommended 3 sessions/week target, ExerciseScreen (weekly strength
  frequency card, day-grouped working-set log with swipe-to-delete) and the
  LogExerciseDialog (muscle group / name / sets / reps / weight).
- Recipe Vault: new features/recipes screen with pinned URL import bar wired
  to RecipeImportController, search field + macro filter chips (Protein >
  30g / > 20g / Under 500 kcal / All), responsive GridView.builder
  (SliverGridDelegateWithMaxCrossAxisExtent) with chunked infinite scroll,
  read-only details bottom sheet, and delete confirmation.
- Meal planner refactor: strip the screen to week navigation + the 7-day
  calendar (Mon-Sun) with daily protein rollups; replace the inline import
  bar, SavedRecipesTray, and AssignSlotDialog with the searchable
  AssignRecipeSheet modal bottom sheet (Recipe Vault search + custom-entry
  fallback); empty slots render a "+ Assign Recipe" affordance; drop the
  drag-and-drop tray plumbing.
- Settings: new features/settings screen with Identity (email, Supabase
  status badge, sign-out), Targets (daily protein/water inputs feeding the
  new NutritionController.updateTargets), Security & Storage (SQLCipher
  AES-256 badge with web-degradation note), and Integrations (Apple Health /
  Health Connect / HealthGateway toggles via IntegrationsController through
  the IHealthGateway boundary).
- Shell: register /exercise, /recipes, /settings routes; expand the desktop
  NavigationRail to the 7 specified destinations (medication_liquid,
  restaurant, fitness_center, calendar_month, menu_book, inventory_2,
  settings) with labelType.all inside a height-constrained scroll view;
  mobile keeps 4 core bottom-bar tabs plus a "More" tab opening the
  secondary-destinations drawer.
- Android toolchain fixes (first-ever Android build): enable core library
  desugaring + desugar_jdk_libs 2.1.4 for flutter_local_notifications, set
  kotlin.incremental=false (pub cache on C: vs project on D: breaks the
  incremental compiler), and raise minSdk to maxOf(flutter, 26) for the
  health plugin.
- Mobile overflow fix: LogInjectionDialog compound dropdown gains
  isExpanded + ellipsis so long labels ("Tirzepatide (Mounjaro /
  Zepbound)") no longer paint stripes at phone widths.
- Web drift assets: commit web/sqlite3.wasm (sqlite3-3.7.1 release, matching
  the locked package) and web/drift_worker.js (drift-2.35.2) so the WASM
  database opens at runtime; both were missing and every drift operation
  failed in Chrome.
- Recipe import hardening: browser-like Accept/Accept-Language/User-Agent
  headers on native (403 anti-bot bypass; UA stripped on web), optional
  --dart-define=RECIPE_PROXY_URL routing downloads through a server-side
  proxy, actionable CORS guidance in the web error path, and a deployable
  Supabase Edge Function relay (supabase/functions/recipe-proxy) with
  http(s)-only validation, SSRF host guard, 2 MiB cap, and 15 s timeout.
- Tests: 123 -> 135 (exercise controller/screen, log-injection dialog
  320dp/390dp overflow regressions, scraper header/proxy/error-path
  hardening, meal planner calendar-only rewrite); navigation integration
  tests now cover all 7 rail routes and the mobile More drawer.
- Docs: README web recipe-import (CORS proxy) section; BUILD_STATE.md
  Phase 7 deliverables, Post-Phase-7 additions, and checklist updated.

Verified: dart analyze lib test clean, flutter test 135/135,
flutter build windows --debug, flutter build apk --debug, and
flutter build web --no-tree-shake-icons all succeed.
2026-10-16 19:19:02 -04:00
Mike Kell 51364a8f4f feat(platform,tests,ci): complete Phase 6 cross-platform hardening, integration tests, and Forgejo CI/CD
- Harden HealthGateway: kIsWeb/defaultTargetPlatform/dart:io guards, Health
  Connect SDK availability probe with graceful degradation, READ_WEIGHT/
  READ_STEPS/READ_TOTAL_CALORIES_BURNED permission validation before reads,
  HealthKit entitlement failures contained (false + debug warning), and a
  desktop/web fallback that serves locally logged biometrics through the new
  ILocalBiometricReader contract (drift-backed adapter wired in health_sync).
- Platform-safe CryptoManager vault: EncryptedSharedPreferences (Android),
  Keychain first_unlock (iOS/macOS), DPAPI-sealed file (Windows), libsecret
  (Linux); vault failures degrade to an ephemeral in-memory SQLCipher key.
- Declare the four Health Connect READ_* permissions in AndroidManifest.xml.
- Extract isAuthenticatedProvider so integration tests can simulate auth
  sessions without booting Supabase.
- Add 24 tests (99 -> 123): steady-state PK suite (Semaglutide 168h /
  Tirzepatide 120h geometric series, superposition, titration, washout),
  real-world recipe JSON-LD fixtures (BBC-style root, AllRecipes @graph),
  pantry unit-conversion group (kg/g, l/ml, dimension guard, synonyms),
  app navigation integration tests (rail + bar, authenticated + dev-bypass
  + unauthenticated), and reactive nutrition progress-bar widget tests.
- Fix NutritionScreen narrow-width overflows: Flexible protein title and
  Wrap action buttons stack cleanly on compact phones.
- Add .forgejo/workflows/ci.yml for git.kellsupport.com/mtkell/glp-companion
  (push to main + PRs, Flutter container: checkout, mock .env, pub get,
  build_runner, analyze --fatal-infos, test --coverage, build bundle + web).
- Remove dead lib/features/recipes/data/recipe_scraper.dart; rewrite
  README.md (architecture, dev setup, SQLCipher details, CI docs); add
  .env.example; allow it through .gitignore; update BUILD_STATE.md with
  Phase 6 deliverables and complete Phases 1-6 checklist.

Verified: build_runner 44 outputs, flutter analyze --fatal-infos clean,
flutter test 123/123, flutter build web and flutter build bundle succeed.
2026-10-16 14:59:15 -04:00
Mike Kell 7682d8317a feat(medication): complete Phase 2 GLP-1 tracking, reminders, and dev bypass
Domain (pure Dart):
- Add 12-quadrant InjectionSite anatomical model with a least-recently-used
  rotation policy, DoseEntry entity, and Glp1Compound value object
  (Semaglutide 168h, Tirzepatide 120h, Liraglutide 13h)
- Add CalculateSerumLevel use case implementing
  C(t) = sum(D_i * 0.5^((t - t_i) / t_half))
- Define IMedicationRepository contract; retire superseded MedicationDose

Data:
- Add injection-history CRUD to AppDatabase (watch/get/insert/update/delete/
  latest-administered), ordered newest first
- Implement drift-backed MedicationRepository with record-to-entity mapping

Presentation and local alerts:
- Add MedicationController (StateNotifier) managing serum estimation, site
  rotation suggestions, and best-effort reminder scheduling
- Rework MedicationScreen: serum card, suggested-site card, interactive log
  dialog (compound, dosage, timestamp, quadrant), history with delete, and a
  60s decay ticker
- Add INotificationService / PlatformNotificationService wrapping
  flutter_local_notifications (one-shot scheduling on Android/iOS/macOS,
  graceful no-op on Web/Windows/Linux), Android boot receivers for reminder
  restoration, and the timezone dependency

Development tooling:
- Add debug-only "Continue Without Signing In" bypass on the login screen,
  backed by an in-memory devAuthBypassProvider; the router guard honors the
  flag and the shell shows a dev-mode banner while active

Fixes:
- Resolve the Supabase client lazily in SupabaseAuthService so widget tests
  and pre-initialization builds no longer throw

Testing:
- 36 new tests covering PK decay math, rotation determinism, repository CRUD
  on an in-memory drift database, controller behavior with fakes, and the
  end-to-end dev bypass flow; full suite green (37/37)
- BUILD_STATE.md: mark Phase 2 complete and record all verification gates
2026-10-16 06:20:23 -04:00
Mike Kell 7b6b646d2c feat(auth): complete Phase 1 passwordless identity and encrypted DB foundation 2026-10-16 05:01:54 -04:00
Mike Kell 98e0d318f3 feat(init): baseline multiplatform architecture with clean arch shell, clinerules, and docs 2026-10-15 21:01:52 -04:00