Files
clockula/docs/ROADMAP.md
T
Jean-Luc MakiolaandClaude Opus 5 052c7b177d docs: lock the Clockula spec — PLAN, ROADMAP, docs index
Third floret after Calendula and Agendula: a Material 3 Expressive clock app
(alarms, timers, stopwatch, world clock).

The family thesis doesn't survive contact with a clock — there is no open
provider behind one — so PLAN opens by saying so plainly and relocates the
open-standards commitment to the three places it can actually live: the full
android.provider.AlarmClock intent contract, IANA tzdata, and a documented
JSON backup format.

Locked: four surfaces and no extras in v1, Room + DataStore + JSON export,
maximum alarm reliability including a self-check diagnostics screen, seed
#6B7A5C (completing the family's Calendula→Agendula colour rotation), four
tabs plus a live running-state pill, Codeberg-canonical from commit one, and
floret-kit from day one with core-prefs + core-di extracted up front.

ROADMAP carries M0–M11 as an ordered work queue with per-milestone done
criteria, written to be executed one milestone per loop iteration.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L94fydiJC37LtxVusNQBDy
2026-09-11 11:27:57 +02:00

165 lines
7.8 KiB
Markdown

# Clockula — roadmap
The **status** view, and the work queue. Design rationale for every decision here
lives in [`PLAN.md`](PLAN.md); the shape of the code as it stands will live in
[`ARCHITECTURE.md`](ARCHITECTURE.md) from M2 onward.
Status legend: ✅ done · 🚧 in progress · ⬜ not started
---
## Current state (one line)
**Nothing built yet.** The spec is locked (`PLAN.md`); M0 is next.
---
## How the loop works through this
One milestone per iteration, auto-continuing. Each iteration:
1. Pick the **first milestone not marked ✅**.
2. Implement it **completely** — every checklist item under it.
3. Build, and run the tests the milestone names. A milestone is not done until
they pass.
4. **Commit** (floret-kit submodule first where it changed, then Clockula's
pointer bump — separate commits, granular, lowercase area prefix).
5. Mark the milestone ✅ here, update **Current state**, and commit that too.
6. Continue to the next milestone.
Rules that hold across every iteration:
- **Never let a Room entity or `@Query` string leak above the data layer**
(`PLAN.md` §0).
- **Never** add a foojay toolchain resolver, anywhere, not even in a comment.
- Commit each finished unit of work; never accumulate a WIP pile.
- If a milestone turns out to be wrong, say so and amend `PLAN.md` — do not
silently build something else.
- `ARCHITECTURE.md` and `CHANGELOG.md` are updated as part of the milestone that
changes them, not in a later cleanup pass.
---
## v1 milestones
### ⬜ M0 — Skeleton & pipeline
The project exists, builds, is themed, and ships itself.
- Gradle project: `settings.gradle.kts`, version catalog copied from Agendula
(drop `:provider`, add Room + KSP), AGP 9.x conventions, `vcsInfo` off on
release, no foojay resolver.
- floret-kit as a git submodule + `includeBuild`, with the gitignored
`floret-kit/local.properties` arrangement documented.
- Hilt, Compose, `MainActivity`, `FloretExpressiveTheme` reseeded to `#6B7A5C`
(`ui/theme/Color.kt` + `Theme.kt`), hand-tuned light/dark schemes.
- `core-crash` wired; `core-locale` + `res/xml/locales_config.xml`.
- Codeberg repo, canonical from the first commit. Full pipeline per `PLAN.md` §10:
`ci.yaml`, `translations.yaml`, `release.yaml` (Agendula spine + Calendula `play`
job), `renovate.yml`, issue/PR templates, F-Droid metadata, fastlane tree.
- `README.md`, `LICENSE` (MIT), `CHANGELOG.md`, `.editorconfig`, `.gitattributes`,
`.gitignore`, `docs/README.md` index.
- **Done when:** it builds, installs, shows a themed placeholder, and CI is green.
### ⬜ M1 — floret-kit: `core-prefs` + `core-di`
Pay the extraction the kit's roadmap has been waiting for a third app to trigger.
- In the kit: `core-prefs` (`ThemeMode`, `dynamicColor`, typed DataStore wrapper,
`toEnum()`) and `core-di` (`@IoDispatcher` + provider), each with tests, module
docs, `CHANGELOG` and `ROADMAP`/`ARCHITECTURE` updates.
- Clockula consumes both. Migrating Calendula and Agendula is explicitly **out of
scope** — note it in the kit's roadmap as a follow-up.
- **Done when:** the kit's tests pass, Clockula builds against the new modules,
and both repos are committed (submodule first, then the pointer bump).
### ⬜ 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.
- Domain models (plain Kotlin) + mappers. Repositories exposing Flows.
- DataStore prefs (theme, dynamic colour, defaults, stopwatch running state).
- DI modules.
- **Tests:** mappers, repository behaviour, the elapsed-realtime vs wall-clock
distinction under a simulated clock change.
- Write the first `ARCHITECTURE.md`.
### ⬜ M3 — Alarm engine
The hard part (`PLAN.md` §4), still headless apart from the ring screen's
plumbing.
- Next-fire resolution: local time-of-day + repeat mask → next instant in the
device zone; `skipNextOccurrence`; snooze.
- `AlarmScheduler` over `setAlarmClock`, single-next-alarm registration,
`USE_EXACT_ALARM` with a `SCHEDULE_EXACT_ALARM` fallback path.
- Receivers: fire, `BOOT_COMPLETED`, `TIME_SET`, `TIMEZONE_CHANGED`,
`MY_PACKAGE_REPLACED`.
- Ringing foreground service: audio focus, `USAGE_ALARM`, volume ramp, vibration,
ringtone URIs; survives process death and reboot mid-ring.
- Full-screen-intent notification + `canUseFullScreenIntent()` handling, degrading
to a high-priority heads-up notification that still rings — never to silence.
- **Tests:** DST spring-forward and fall-back, every repeat configuration, skip,
snooze-vs-next-occurrence. These are the tests the app lives or dies on.
### ⬜ M4 — App shell
- Navigation host, four tabs, M3 navigation bar, adaptive rail on wide layouts.
- The **live pill** (`PLAN.md` §9) — shared running-state surface, pause + stop
from any tab.
- The ring screen UI: over-lockscreen, turn-screen-on, snooze/dismiss, optional
dismiss challenge that cannot strand the user.
- Motion from the kit's `identity` module; predictive back.
### ⬜ M5 — Alarms screen
List, create, edit, delete, enable/disable. Time picker, repeat-day selector,
label, ringtone picker, vibrate, snooze settings, per-alarm overrides. Next-fire
line ("in 9h 12m") on each row. Built on `GroupedSurface`/`GroupedRow`.
### ⬜ M6 — Timers
Multiple concurrent timers, presets, labels, add/pause/reset/+1min. Foreground
service with notification controls, expiry ringing reusing M3's audio path.
Elapsed-realtime anchored.
### ⬜ M7 — Stopwatch
Start/stop/reset, laps with splits and cumulative times, best/worst lap emphasis.
Foreground service so it survives backgrounding; laps persist across process
death. This is where the big-readout typography gets settled for the whole app.
### ⬜ M8 — World clock
IANA zone list with search, ICU-localised city and zone display names, offset and
day-difference relative to home, reorder, home-zone handling. The analog face
built from `MaterialShapes` / `androidx.graphics.shapes` — the app's one
deliberate showpiece.
### ⬜ M9 — System interop
The full `android.provider.AlarmClock` contract (`PLAN.md` §6): `SET_ALARM`,
`SET_TIMER`, `SHOW_ALARMS`, `SHOW_TIMERS`, `DISMISS_ALARM`, `SNOOZE_ALARM`, plus
next-alarm publishing. Hostile-input validation at the intent boundary.
- **Tests:** extra validation, including malformed and out-of-range input.
### ⬜ M10 — Settings, backup, and the self-check
- Settings composed from kit components: theme, dynamic colour, language,
alarm/timer/clock defaults, about + crash reporting.
- JSON backup export/import via SAF (`PLAN.md` §7), schema documented in the repo.
- The **"why might my alarm not ring?"** self-check screen (`PLAN.md` §4) —
real device state, deep links to the exact settings pages.
- **Tests:** backup round-trip and unknown-field tolerance.
### ⬜ M11 — Release readiness
Translations wired to Weblate, fastlane metadata and screenshots, F-Droid
reproducibility guard verified against the submodule, instrumentation smoke
tests, accessibility pass (TalkBack on the ring screen especially), on-device
reliability soak across a few real nights. Then 1.0.0.
---
## Post-v1
Deferred deliberately, in rough priority order:
- **Dock / screensaver mode** — a `DreamService` full-screen clock. Cheapest big
win, and the surface people look at most.
- **Glance home-screen widget** — next alarm and running timer.
- **Quick Settings tile** — timer control and next alarm from the shade.
- **Bedtime / sleep schedule** — wind-down and wake, with DND handoff. A feature
in its own right, realistically v2.
- **`core-notification` in floret-kit** — revisit once Clockula's real
notification surface is known (`PLAN.md` §3).
- **Migrate Calendula and Agendula onto `core-prefs` + `core-di`** — tracked in
the kit's roadmap, not here.
- **Wear OS companion** — unscoped.