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

7.8 KiB

Clockula — roadmap

The status view, and the work queue. Design rationale for every decision here lives in PLAN.md; the shape of the code as it stands will live in 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.