focus-flow/Codex Documentation/Completed Plans/Persistence Plan 1 - SQLite Runtime Persistence/PERSISTENCE_PLAN_1_SUMMARY.md

104 lines
4.2 KiB
Markdown

<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
# Persistence Plan 1 Summary — SQLite Runtime Persistence
**Status:** Complete on 2026-07-02.
**Scope level:** XHIGH implementation plan.
**Primary outcome:** The Flutter desktop app persists real task state to an
on-disk SQLite database instead of recreating arbitrary demo seed data at launch.
---
## Current repo facts this plan is based on
1. The project is SQLite-first and V1 has no MongoDB runtime.
2. `packages/scheduler_persistence_sqlite` already contains a Drift database and
repository implementations for task/project/locked-time/settings/snapshot
persistence.
3. The Flutter app still starts through `DemoSchedulerComposition.seeded()` and
an `InMemoryApplicationUnitOfWork`.
4. The dev runner already passes `SCHEDULER_SQLITE_PATH` into Flutter as a Dart
define, but the Flutter app does not yet consume that path.
5. `V1ApplicationCommandUseCases` and `GetTodayStateQuery` already operate
against the public `ApplicationUnitOfWork` boundary.
6. Existing command flows write more than tasks: completion can also write task
activities, project statistics, and operation records.
7. Current SQLite schema files do not yet expose all app-layer repository data
needed for durable application semantics across restarts.
---
## Definition of done
Persistence Plan 1 is complete when all of the following are true:
1. `main.dart` no longer boots the normal app through static seeded demo data.
2. App startup opens an on-disk SQLite database at the configured path.
3. The composition root builds scheduler queries/use cases with a SQLite-backed
`ApplicationUnitOfWork`.
4. The app creates or loads required owner bootstrap data, including owner
settings and a default Inbox/Home project, without inserting arbitrary demo
timeline tasks.
5. Quick capture persists a task to SQLite.
6. Scheduling a backlog task persists `status`, `durationMinutes`,
`scheduledStart`, and `scheduledEnd`.
7. Completing and uncompleting a task persist `status`, actual/completion
timestamps, and updated metadata.
8. Closing and reopening the app against the same database reloads the task,
schedule placement, and done/not-done state.
9. Widgets/controllers still consume read models/controllers and do not contain
scheduling, Drift, SQL, or OS path logic.
10. Temp-file lifecycle tests prove close/reopen persistence.
11. Existing backend gates and Flutter gates pass, or every unavailable command
is documented with the reason.
---
## Non-goals
1. No UI redesign beyond empty/loading/error text needed for real persisted data.
2. No new scheduling algorithm behavior.
3. No manual SQL in Flutter widgets.
4. No backup/restore UI.
5. No JSON/CSV export UI.
6. No calendar sync.
7. No notifications wiring.
8. No week/month views.
9. No Shield/Recovery UX beyond preserving existing backend recovery contracts.
---
## Architecture rule
The SQLite runtime must sit behind the existing application boundaries:
```text
Flutter widgets/controllers
-> app composition/root runtime object
-> V1ApplicationCommandUseCases / GetTodayStateQuery
-> ApplicationUnitOfWork
-> SQLite application repositories / Drift database
```
The UI may request capture/schedule/done actions. The scheduler core remains the
source of truth for schedule state and task transitions.
---
## Important implementation decision
The current `scheduler_persistence_sqlite` adapter package implements
repository-conformance contracts, but the app command layer needs the richer
`scheduler_core` application repository surface. This plan therefore adds a
SQLite-backed `ApplicationUnitOfWork` adapter and the missing app-layer rows it
requires instead of wiring Flutter directly to low-level persistence
repositories.
Recommended default: implement the application unit of work in
`packages/scheduler_persistence_sqlite` and expose it from `sqlite.dart`.
Optional stricter boundary: create a small pure-Dart runtime package that owns
SQLite file opening and depends on `scheduler_persistence_sqlite`; Flutter then
imports only that runtime package. Use this option only if keeping all SQLite
package imports out of `apps/focus_flow_flutter/lib/` remains a hard boundary.