# Grounded — Flutter Frontend *A to-do app that doesn't believe you.* Architecture ported from `Documents/Autoreceptives/Frontend/Receptive`. Same structure, conventions and infrastructure; the business logic is the debt and enforcement engine. --- ## 1. Stack Flutter (Dart `^3.6.2`), **stacked** MVVM, **dio**, **flutter_secure_storage**, **flutter_dotenv**, **fl_chart**, **flutter_local_notifications**. Package name and `lib/` root are both `Grounded`, so imports read `package:Grounded/Grounded/...`. Org is `nya` (`nya.grounded`). Codegen is via **Mason** — screens, endpoints and storage fields are generated, never hand-scaffolded. --- ## 2. Layout (`lib/Grounded/`) ``` about/external/data/ responses & domain models (+ pages/ for pagination) about/external/initial/ request bodies about/internal/application/ enums and app-internal models about/internal/file/ FileStorage comms/ CommsDirections · ConnectComms · Comms informatics/ DataManager · AppDataManager memory/ ConnectInternalMemory · InternalMemory configs/ Navigator · Env · NotificationServiceConfig designs/ Component · Shell · Responsive · buttons/ input/ text/ see// screens, 4 files each utils/ Colors · CommonUtils · engines · validators ``` --- ## 3. The 4-file screen pattern (mandatory) | File | Role | |---|---| | `Foo.dart` | `StatefulWidget` shell — creates `FooState` only. | | `FooState.dart` | All UI + local state; implements `ConnectFoo`. | | `ViewFoo.dart` | `extends ParentViewModel` — business logic, calls `DataManager`, pushes results back through `ConnectFoo`. | | `ConnectFoo.dart` | Abstract callbacks so the ViewModel never touches widgets. | `ViewModelBuilder.reactive` wires them. `onViewModelReady` assigns `_model` and calls one named `_initiate()`. **No logic in `builder:` before the `return`.** Generate with: `mason make mvvc_template --project Grounded --screen Foo` --- ## 4. ParentViewModel Constructs the single `AppDataManager` and owns everything cross-cutting: `showLoading` / `closeLoading`, `hasNetwork(retry)`, `showError`, `showApplicationNotification`, and `handleError` — whose decision tree routes `401 → sessionExpired()` and error code `5000.901 → updateMe()`. Guard every network call: ```dart void loadThing(ThingRequest request) async { if (!await hasNetwork(() => loadThing(request))) return; showLoading('Loading…'); try { final response = await getDataManager().getThing(request); closeLoading(); connection.onThingLoaded(Thing.fromJson(response.data)); } catch (e) { handleError(e, () => loadThing(request), () => dismissError(), 'Retry'); } } ``` --- ## 5. Domain — the enforcement engine Three primitives: **Commitment** (what you said you'd do), **Debt** (weighted, decaying score), **Standing** (`Good → Warned → Grounded → Lockdown`). **Goals** contain commitments via `Commitment.parentId` — "Workout" holds "Monday shoulders". Goals never carry debt; the tasks inside them do. Engines in `utils/`, each mapping 1:1 to the spec's formulas: | Engine | Owns | |---|---| | `DebtEngine` | `w(class) × severity(d) × decay(t)`; abandonment 2×, no decay 30d; late complete retains 30% | | `StandingEngine` | tier derivation; what each tier permits | | `CapacityEngine` | blocks over-scheduling against p50 of historical completed minutes × 0.85 | | `IntegrityEngine` | session integrity, weekly volume, plyo contact ceiling, recovery gate | | `ExcuseAnalyser` | on-device excuse clustering + the confrontation copy | | `GuardrailEngine` | distress detection, amnesty tokens | | `ToneEngine` | **all** enforcement copy — the one place the tone cap is enforced | Thresholds live in `Thresholds.dart`. Never inline a limit. `CommitmentEvent` is append-only and is the source of truth — **not** the status field. That's what makes honest history and excuse analysis possible. --- ## 6. Design language See `design.md`. In short: black chrome → white sheet with a 28 radius → oversized **Light** display title → tiny grey all-caps labels above values. - Every screen is built from `Sheet` (`designs/Shell.dart`). - Display titles are `TextType.Light`. Bold is for labels and metrics only. - Never raw `Text`/`TextStyle` — use `text()` from `designs/text/Text.dart`. - Never inline hex — use `utils/Colors.dart`. - Standing owns a colour used consistently everywhere (chrome, chip, meter). - One primary button per screen; everything else outlined or text. Font: **General Sans** (Fontshare, FFL — see `fonts/LICENSE-GeneralSans.txt`), wrapped as `TextType.{Bold,Medium,Regular,Light}`. --- ## 7. Live task runner `see/live/` is the full-screen runner: a task being run takes over the screen. Elapsed time is derived from **wall-clock**, not counted by the ticker, so a screen-off period cannot lose time. Backgrounding pauses the clock and increments `backgroundedCount` — that's what makes Timer proof mean anything. `LocalNotificationEngine` mirrors it into an ongoing notification and fires alarm-class **full-screen intents** for non-negotiables. Android manifest carries `USE_FULL_SCREEN_INTENT`, `SCHEDULE_EXACT_ALARM`, and the activity is `showWhenLocked` + `turnScreenOn`. --- ## 8. Hard conventions 1. Named event handlers only — `onPressed: _onSave`, never `() => _save()`. 2. `selectField` loads on tap; never pre-load picker options. 3. List parsing via `utils/ObjectConvertors.dart` — never inline `.map(...fromJson)`. 4. Pagination: `HistoryRequest { PageAndSort }`; responses are `*Page`; `last == true` stops loading. 5. Reload-on-return: child `Navigator.pop(context, true)`, parent refreshes on the result. 6. New endpoint → `mason make api_endpoint` (injects into all four HTTP files). 7. New secure field → `mason make internal_memory`. 8. One class per file, named after the class. --- ## 9. Environment `.env` is a bundled asset, loaded in `main()` before `runApp`: ``` GROUNDED_PRODUCTION_PATH · GROUNDED_LOCAL_PATH · LOCALISED_APP_VERSION ``` `isProd` in `CommsDirections.dart` flips local↔production. Requests carry the three identity headers: `what`, `whom`, `version`. --- ## 10. Commands ```bash flutter pub get flutter analyze lib/ # bricks/ are excluded — templates aren't valid Dart flutter run mason get mason make mvvc_template --project Grounded --screen MyScreen dart run flutter_launcher_icons dart run flutter_native_splash:create ```