From 048de67350bbb0ccafb0ea31bbeefccb8eb6b17e Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Thu, 30 Jul 2026 10:13:48 +0200 Subject: [PATCH] docs: correct stale build, forge and layer facts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BUILDING.md never mentioned the floret-kit submodule, so its instructions could not produce a working build — a plain clone fails to configure. It also understated the SDK requirement: compileSdk is 37, not the "36+" it claimed. Both matter now that the Codeberg move is meant to make an outside clone viable. The docs map advertised superpowers/specs/ and superpowers/plans/, neither of which exists any more, while omitting BUILDING.md and RELEASING.md. Dropped the dead rows and listed what is actually there. Purged the remaining superpowers references in .planning/ and ARCHITECTURE.md's dangling "see plan 03" the same way — a pointer to a deleted file is worse than no pointer. ARCHITECTURE.md still called OptionCard "the app's only sanctioned selection-dialog style", which the 2026-07-07 flip to full-screen pickers reversed, and described no layer for floret-kit despite it being a compiled-from-source composite build. Its CI note credited Gitea Actions; contributor CI runs on Codeberg now. PROJECT.md's Source section described the old world outright ("hosted on self-hosted Gitea") and now records the split: Codeberg canonical, Gitea build infrastructure. --- .planning/PROJECT.md | 8 +++-- .planning/REQUIREMENTS.md | 2 +- .planning/ROADMAP.md | 8 ++--- .planning/STATE.md | 2 +- docs/ARCHITECTURE.md | 17 +++++++--- docs/BUILDING.md | 66 ++++++++++++++++++++++++++++++++++++--- docs/README.md | 15 ++++----- 7 files changed, 92 insertions(+), 26 deletions(-) diff --git a/.planning/PROJECT.md b/.planning/PROJECT.md index 04ce9d3..66e1cf8 100644 --- a/.planning/PROJECT.md +++ b/.planning/PROJECT.md @@ -40,5 +40,9 @@ shows a stylized "1" on a slate squircle. ## Source -Hosted on self-hosted Gitea, released through self-hosted F-Droid repo on -Hetzner. Same infrastructure as `HouseHoldKeaper`. +**Codeberg (`jlmakiola/calendula`) is canonical** — git, issues, PRs, tags and +releases, plus contributor CI. The self-hosted Gitea instance is build +infrastructure only: it holds the signing key, runs the release pipeline, and +publishes the self-hosted F-Droid repo on Hetzner. Codeberg push-mirrors `main` +and tags to Gitea, where a bumped `versionName` triggers the release. Also +published to the official F-Droid repo. See `docs/RELEASING.md`. diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index a6b970b..5ed4993 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -1,6 +1,6 @@ # Calendula — Requirements -See full design spec: `docs/superpowers/specs/2026-06-08-calendar-app-design.md` +Architecture reference: [`../docs/ARCHITECTURE.md`](../docs/ARCHITECTURE.md) ## V1 Scope (Variant "B") — shipped in full (v1.0.0, 2026-06-11) diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index a27a7dc..0f7c729 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -55,9 +55,8 @@ after v0.6 (full event read) plus the onboarding-screen polish pass. ## v2.0 — Write Support (complete, shipped 2026-06-11) -Delivered in four releasable slices (plan: -`docs/superpowers/plans/2026-06-11-03-write-support.md`). The V1 spec is a -guide here, not a contract — scope per slice is decided as we go. +Delivered in four releasable slices. The V1 spec is a guide here, not a +contract — scope per slice is decided as we go. | Version | Milestone | Status | |---|---|---| @@ -244,8 +243,7 @@ pass on the existing controls; new toggles ride in with their own features. sequential branches: `feat/ics-export` (write side + UID-on-create precursor) then `feat/ics-import` (parser, restore, dedup by UID). Import is liberal-in/strict-out: skip-and-report foreign `VTIMEZONE` / `RECURRENCE-ID` - / guest lists it can't model. Plans: - `docs/superpowers/plans/2026-06-18-05-ics-export.md` + `…-06-ics-import.md`. + / guest lists it can't model. 11. **Snooze / dismiss notification actions** *(merged into release/v2.8.0)* — followed the `.ics` work; inherits v2.6's deferred exact-alarm/WorkManager decision (snooze must re-fire an alarm). diff --git a/.planning/STATE.md b/.planning/STATE.md index a2c9e67..fbd5fb7 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -25,7 +25,7 @@ release-cut. ## Progress -- [x] Design spec written and committed (`docs/superpowers/specs/2026-06-08-calendar-app-design.md`) +- [x] Design spec written and committed (2026-06-08) - [x] V1 design decisions resolved (App name "Calendula", icon, seed color) - [x] Plan 01 written and executed — foundation lands (theme, icon, i18n, Hilt, DataStore, CI green) - [x] Plan 02 written and executed — data layer + permission flow + debug screen diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index a8c3600..2b4aabc 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -62,9 +62,15 @@ flowchart TD - **`data/prefs/`** — DataStore-backed settings (theme, week start, form field defaults, reminders toggle) and small state (last-used calendar). - **`ui/`** — one package per screen, each with Screen + ViewModel + - UiState. Shared pieces in `ui/common/` (OptionCard — the app's only - sanctioned selection-dialog style —, recurrence humanizer, FAB column, - drawer, transitions). + UiState. Shared pieces in `ui/common/` (recurrence humanizer, FAB column, + drawer, transitions). Selection pickers are full-screen and come from + floret-kit (`FullScreenPicker` / `OptionPicker`); `AlertDialog` is reserved + for plain confirmations and the compact recurring-scope choosers. +- **`floret-kit/`** — the shared Material 3 Expressive kit for the Floret app + family, wired in as a git submodule *and* a Gradle composite build + (`includeBuild`), so it is compiled from source rather than resolved as a + dependency. Pickers, crash plumbing, and locale/time helpers live there; + changing them is a pull request against that repository plus a submodule bump. ## Navigation @@ -81,7 +87,7 @@ exactly like an event tap. ## Recurring writes The provider's invariants drive the design (learned the hard way, verified -on-device — see plan 03): +on-device): - Recurring rows carry `RRULE` + `DURATION` (no `DTEND`); one-off rows carry `DTEND`. @@ -167,6 +173,7 @@ JUnit 5 + Truth + Turbine on the JVM. The seams that make it work: `CalendarDataSource` is faked (`FakeCalendarDataSource` records writes), mappers parse `ColumnReader`/plain maps instead of cursors, domain logic (recurrence, validation, snapshots, write-value building) is pure. CI -(Gitea Actions) runs `lint test assembleDebug` once per pull request; merging a +(Forgejo Actions on Codeberg) runs `lint test assembleDebug` once per pull +request; merging a bumped `versionName` to `main` builds, signs, and publishes to the self-hosted F-Droid repo and then mints the `vX.Y.Z` tag + release. See docs/RELEASING.md. diff --git a/docs/BUILDING.md b/docs/BUILDING.md index 6524e94..9577701 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -1,12 +1,35 @@ # Building from source Calendula builds with the standard Android Gradle toolchain — no extra setup -beyond the SDK and a JDK. +beyond the SDK, a JDK, and the submodule. + +## Clone + +```bash +git clone --recurse-submodules https://codeberg.org/jlmakiola/calendula.git +``` + +Calendula depends on **[floret-kit](https://codeberg.org/jlmakiola/floret-kit)**, +the shared Material 3 Expressive kit, as a git submodule wired in as a Gradle +composite build (`includeBuild("floret-kit")` in `settings.gradle.kts`) — it is +compiled from source, not resolved from a repository. A clone without the +submodule fails to configure. For an existing clone: + +```bash +git submodule update --init --recursive +``` ## Requirements -- **Android SDK 36+** -- **JDK 17** — if your default JDK is not 17, set `JAVA_HOME` explicitly. +- **JDK 17** — not newer; the Android Gradle Plugin requires exactly 17. If your + default JDK differs, set `JAVA_HOME` explicitly. +- **Android SDK** — platform **37** (`compileSdk`) and **build-tools 36.0.0**. + `minSdk` is 29, `targetSdk` 36. + +The SDK is located via `ANDROID_HOME` (or `ANDROID_SDK_ROOT`), or via a +gitignored `local.properties` with `sdk.dir`. If you use `local.properties`, note +that the composite build needs **its own** copy at `floret-kit/local.properties`; +setting `ANDROID_HOME` covers both builds at once and is the simpler route. The Gradle wrapper is checked in, so you don't need a system Gradle. @@ -14,11 +37,44 @@ The Gradle wrapper is checked in, so you don't need a system Gradle. ```bash ./gradlew assembleDebug # debug APK → app/build/outputs/apk/debug/ -./gradlew test # JVM unit tests +./gradlew test # JVM unit tests (JUnit 5 + Truth + Turbine) ./gradlew lint # Android lint ``` +A single test class, or a pattern: + +```bash +./gradlew testDebugUnitTest --tests "de.jeanlucmakiola.calendula.domain.SimpleRecurrenceTest" +./gradlew testDebugUnitTest --tests "*SimpleRecurrence*" +``` + +Translation-key invariants (stale and orphaned keys are fatal; missing ones are +not) are checked outside Gradle: + +```bash +python3 scripts/check_translations.py +``` + +## What CI runs + +`.forgejo/workflows/ci.yaml` reports a single `CI` check per pull request on +Codeberg: the reproducible-release guard, then `lintDebug`, +`testDebugUnitTest`, `assembleDebug` and a Trivy filesystem scan. Pull requests +that touch only docs, F-Droid metadata or the licence skip the Android build and +still report green. + ## Release builds Release signing and the publishing pipeline are documented separately in -[RELEASING.md](RELEASING.md). +[RELEASING.md](RELEASING.md). To smoke-test a release candidate locally, the +`releaseTest` build type is an R8-shrunk twin of `release`, debug-signed with its +own `applicationId` suffix so it installs alongside the real app: + +```bash +scripts/verify-release.sh +``` + +## Contributing + +See [`../CONTRIBUTING.md`](../CONTRIBUTING.md) for the issue-first workflow, +which branch to target, and the architectural rules a change is reviewed against. diff --git a/docs/README.md b/docs/README.md index dddbcf7..267d722 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,19 +4,20 @@ Where to look for what: | Document | What it is | |---|---| +| [`../CONTRIBUTING.md`](../CONTRIBUTING.md) | How to contribute: issue-first workflow, which branch to target, translations, the rules a change is reviewed against | +| [`BUILDING.md`](BUILDING.md) | Building from source: submodule, JDK/SDK requirements, Gradle tasks, what CI runs | | [`ARCHITECTURE.md`](ARCHITECTURE.md) | Orientation tour: principles, layers, navigation, recurring-write / conflict / reminder pipelines, testing | +| [`RELEASING.md`](RELEASING.md) | Release process: versioning, the merge-driven pipeline, the two-forge split, secrets, key custody | | [`../CHANGELOG.md`](../CHANGELOG.md) | Release history (Keep a Changelog, SemVer) | | [`../.planning/ROADMAP.md`](../.planning/ROADMAP.md) | Living roadmap: shipped milestones, current scope, idea backlog | | [`../.planning/PROJECT.md`](../.planning/PROJECT.md) | What the project is, stack, naming, infrastructure | | [`../.planning/REQUIREMENTS.md`](../.planning/REQUIREMENTS.md) | Requirement checklist per milestone | | [`../.planning/STATE.md`](../.planning/STATE.md) | Snapshot of where development currently stands | -| [`superpowers/specs/`](superpowers/specs/) | The original design spec (2026-06-08) — historical record, not updated | -| [`superpowers/plans/`](superpowers/plans/) | Per-milestone implementation plans with task checklists — historical record of how each slice was built, including provider lessons learned | +| [`design/`](design/) | Per-feature design notes kept for features whose provider behaviour is worth recording | | [`../fastlane/metadata/android/`](../fastlane/metadata/android/) | Store metadata (single source of truth): descriptions, title, icon, screenshots (DE + EN). Harvested directly by the official F-Droid repo; transformed into the self-hosted repo layout at release time by [`../scripts/fastlane_to_fdroid_localized.sh`](../scripts/fastlane_to_fdroid_localized.sh) | | [`../fdroid-metadata/`](../fdroid-metadata/) | App-level F-Droid control file (`*.yml`: Categories, License, links) for the self-hosted repo's `fdroid update` | -| [`fdroid-official/`](fdroid-official/) | Draft recipe + notes for publishing to the **official** F-Droid repo (reproducible build + developer-signed binary) | +| [`fdroid-official/`](fdroid-official/) | Recipe + notes for publishing to the **official** F-Droid repo (reproducible build + developer-signed binary) | -Conventions: plans and specs under `superpowers/` are point-in-time -artifacts of the agentic workflow that built each milestone — they get -status updates but are never rewritten. The `.planning/` files are living -documents and should stay current. +Conventions: the `.planning/` files are living documents and should stay current. +`ARCHITECTURE.md` is the authoritative orientation tour — it is updated with the +code, and is the right place for a lesson learned about the calendar provider.