# 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.