<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->

# Persistence Plan 1 Block 05 — Retire Demo Seed and Wire Persistent Commands

**Status:** Complete on 2026-07-02.
**Goal:** Make normal app startup use persisted SQLite state and prove the
current capture/schedule/done controls mutate durable state.

---

## Block outcome

After this block, launching the app normally should no longer recreate arbitrary
demo tasks. The app should load real persisted tasks, allow the current command
paths to change them, and refresh Today from SQLite-backed read models.

---

## Chunk 5.1 — Introduce an app composition protocol if needed

### Context

`FocusFlowApp` currently depends on `DemoSchedulerComposition`. To switch normal
runtime to SQLite without throwing away deterministic widget tests, the app
should depend on a small composition surface instead of one concrete demo class.

### Tasks

1. Define a protocol/interface for the composition used by the app shell if the
   current class shape makes that useful. It should expose only:
   - owner/date label data needed by UI,
   - Today screen controller factory,
   - command controller factory,
   - operation context factory if still needed externally,
   - dispose/close if the runtime owns resources.
2. Make the demo composition implement the protocol or adapt it behind a wrapper.
3. Make the persistent composition implement the protocol.
4. Keep the protocol free of Drift, SQL, and row types.

### Acceptance criteria

- `FocusFlowApp` can be given either demo or persistent composition.
- Widget tests can still use deterministic demo/fake state where visual coverage
  needs it.
- Normal `main()` can switch to persistent composition without altering widgets.

---

## Chunk 5.2 — Change normal app startup to persistent SQLite

### Tasks

1. Update `apps/focus_flow_flutter/lib/main.dart` so normal startup opens the
   persistent SQLite composition.
2. Keep an explicit demo entry point only if needed, for example:
   - `main_demo.dart`,
   - test-only factory,
   - `--dart-define=FOCUS_FLOW_DEMO_SEED=true` if an opt-in demo mode is useful.
3. Do not keep static demo task insertion on the normal code path.
4. Show a calm failure state if the DB cannot open instead of silently falling
   back to fake data.
5. Keep startup asynchronous if required, using a small loading shell before the
   persistent composition is ready.

### Acceptance criteria

- Running the app with no demo flags starts from the SQLite file.
- A database-open failure is visible and diagnosable.
- No arbitrary UI mockup tasks are inserted into user data.

BREAKPOINT: Stop if the app cannot initialize asynchronous composition without a
small root-shell refactor. Keep the refactor minimal and do not redesign the UI.

---

## Chunk 5.3 — Remove hardcoded demo assumptions from command wiring

### Tasks

1. Replace hardcoded quick-capture project id `'home'` in
   `SchedulerCommandController` with a composition-provided/default project id.
2. Keep owner id/timezone id in the operation context factory, not widgets.
3. Ensure scheduled commands pass the expected updated timestamp/revision-related
   metadata currently available from read models.
4. If read models do not expose enough information for stale-write protection,
   add the smallest read-model field needed rather than bypassing stale checks.
5. Keep command labels/messages calm and stable.

### Acceptance criteria

- Quick capture works on a fresh SQLite DB with bootstrapped project defaults.
- Scheduling from Backlog does not depend on demo project ids.
- Completion/uncompletion commands target real persisted task ids.

---

## Chunk 5.4 — Ensure Today and Backlog refresh from SQLite after commands

### Tasks

1. Verify the current refresh callback reloads all read controllers that should
   reflect command changes.
2. If the compact Today screen currently only refreshes one controller, ensure
   Backlog/TODAY surfaces used in this slice refresh together or derive from a
   shared reload boundary.
3. After quick capture, Backlog reflects the new row.
4. After scheduling, Today reflects the planned placement and Backlog no longer
   shows the task.
5. After done/uncomplete, Today reflects the new status.
6. Avoid optimistic UI as canonical state for this plan. It may show command
   running/success, but the rendered task state must come from SQLite-backed
   read models after refresh.

### Acceptance criteria

- UI state after every command is read back from SQLite-backed application state.
- No widget directly mutates task status or schedule placement as durable truth.

---

## Chunk 5.5 — Preserve demo composition only where useful

### Tasks

1. Keep deterministic seeded demo data only for:
   - visual/widget tests,
   - mockup comparison tests,
   - explicit demo mode if retained.
2. Rename files/classes if needed to clarify they are not normal runtime, for
   example `SeededDemoSchedulerComposition`.
3. Update comments and README text that still say all controls are no-op if the
   current code now supports command flows.
4. Do not delete tests that protect UI Plan 1 visuals unless they are replaced
   with equal coverage.

### Acceptance criteria

- Normal runtime and demo/test runtime are visibly separate in code.
- Future contributors cannot accidentally reintroduce demo seed into user data.
- README status matches actual command wiring.

---

## Chunk 5.6 — Add focused Flutter tests for persistent command wiring

### Required tests

1. Fresh persistent app starts empty or with only bootstrapped non-task state.
2. Quick capture through the UI writes a backlog task to temp-file SQLite.
3. Reopening the app against the same temp file still shows the captured backlog
   task.
4. Scheduling through the UI writes planned schedule placement.
5. Reopening shows the scheduled task in Today.
6. Tapping done writes completed state.
7. Reopening shows the task as completed/done.
8. Tapping done/status again uncompletes if that interaction is currently wired.
9. Reopening shows planned/not-done state.
10. Demo visual tests still run with deterministic seeded data.

### Test constraints

- Use temporary SQLite files.
- Close/dispose every persistent composition before reopening.
- Avoid relying on wall-clock current date; inject fixed clock/date where the
  app composition allows it.
- Keep tests resilient to UI text changes by using existing value keys where
  practical.

### Acceptance criteria

- Flutter tests prove the exact user lifecycle requested by the plan.
- Failures identify whether the bug is read, write, scheduling, or lifecycle.

---

## Block acceptance criteria

- Normal app startup uses SQLite-backed persisted state.
- Static demo task insertion is removed from normal runtime.
- Existing quick capture/schedule/done/uncomplete commands operate on persisted
  application state.
- Today/Backlog render from post-command SQLite reads.
- Persistent Flutter tests cover close/reopen task state.
- Demo/test seed remains isolated if retained.

## Validation after block

```sh
cd apps/focus_flow_flutter
flutter analyze
flutter test
cd ../..
scripts/test.sh
```
