# 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/<feature>/              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<ViewFoo>.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
```
