diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 62a773c..16e1546 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -10,10 +10,12 @@ Status legend: โœ… done ยท ๐Ÿšง in progress ยท โฌœ not started ## Current state (one line) -โœ… **M1 done.** floret-kit 0.4.0 ships `core-prefs` and `core-di`, and Clockula's -theme now follows its own stored preference over a typed DataStore. **M2** (the -whole storage stack โ€” Room, domain models, repositories, and the first -`ARCHITECTURE.md`) is next. +โœ… **M2 done.** Clockula owns its storage: a Room database of four tables with +the schema exported and committed, plain-Kotlin domain models behind four +Flow-based repository interfaces, DataStore preferences, Hilt wiring, and the +first `ARCHITECTURE.md`. **M3** (the alarm engine โ€” next-fire resolution over +repeat masks and DST, `AlarmScheduler`, the receivers, and the ringing service) +is next, and is the hard one. --- @@ -90,7 +92,7 @@ Pay the extraction the kit's roadmap has been waiting for a third app to trigger reads the stored preference, with the DataStore built on a corruption handler so an unreadable prefs file cannot brick startup. -### โฌœ M2 โ€” Data layer +### โœ… M2 โ€” Data layer The whole storage stack, headless. No UI. - Room: `alarms`, `timers`, `world_clocks`, `stopwatch_laps` (`PLAN.md` ยง5), schema exported and committed, DAOs. @@ -100,6 +102,24 @@ The whole storage stack, headless. No UI. - **Tests:** mappers, repository behaviour, the elapsed-realtime vs wall-clock distinction under a simulated clock change. - Write the first `ARCHITECTURE.md`. +- **Done when:** the schema is exported and committed, no Room type or query + string appears above `data/`, and the build, lint and unit tests pass. + + โœ… Four tables (`alarms`, `timers`, `world_clocks`, `stopwatch_laps`), schema + v1 exported to `app/schemas` so migrations can be tested from the beginning. + The seam that matters: the app talks to four repository interfaces speaking + domain types and Flows, and `ArchitectureRulesTest` fails the build if Room, an + entity or a query string ever appears above `data/`. Time is a parameter rather + than an ambient read โ€” `WallClock` and `ElapsedRealtimeClock` are distinct + types, so a running timer anchors on the monotonic clock and keeps a wall-clock + value only as a post-reboot fallback, and the stopwatch keeps none at all. That + leaves one honest gap, written down rather than glossed: once a new boot's + uptime climbs past a stored anchor the reboot goes unnoticed, so closing it + needs a persisted boot id and M3's `BOOT_COMPLETED` receiver. Every + read-modify-write runs inside a DAO transaction, and the stopwatch run record + is written whole in one DataStore edit, so concurrent writers cannot swallow + each other's edits or persist a torn record. 151 JVM tests over fake DAOs and + injected fake clocks; the migration test is the only thing needing a device. ### โฌœ M3 โ€” Alarm engine The hard part (`PLAN.md` ยง4), still headless apart from the ring screen's