docs: correct stale build, forge and layer facts

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.
This commit is contained in:
2026-07-30 10:13:48 +02:00
parent fbb14f9334
commit 048de67350
7 changed files with 92 additions and 26 deletions

View File

@@ -40,5 +40,9 @@ shows a stylized "1" on a slate squircle.
## Source ## Source
Hosted on self-hosted Gitea, released through self-hosted F-Droid repo on **Codeberg (`jlmakiola/calendula`) is canonical** — git, issues, PRs, tags and
Hetzner. Same infrastructure as `HouseHoldKeaper`. 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`.

View File

@@ -1,6 +1,6 @@
# Calendula — Requirements # 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) ## V1 Scope (Variant "B") — shipped in full (v1.0.0, 2026-06-11)

View File

@@ -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) ## v2.0 — Write Support (complete, shipped 2026-06-11)
Delivered in four releasable slices (plan: Delivered in four releasable slices. The V1 spec is a guide here, not a
`docs/superpowers/plans/2026-06-11-03-write-support.md`). The V1 spec is a contract — scope per slice is decided as we go.
guide here, not a contract — scope per slice is decided as we go.
| Version | Milestone | Status | | 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) sequential branches: `feat/ics-export` (write side + UID-on-create precursor)
then `feat/ics-import` (parser, restore, dedup by UID). Import is then `feat/ics-import` (parser, restore, dedup by UID). Import is
liberal-in/strict-out: skip-and-report foreign `VTIMEZONE` / `RECURRENCE-ID` liberal-in/strict-out: skip-and-report foreign `VTIMEZONE` / `RECURRENCE-ID`
/ guest lists it can't model. Plans: / guest lists it can't model.
`docs/superpowers/plans/2026-06-18-05-ics-export.md` + `…-06-ics-import.md`.
11. **Snooze / dismiss notification actions** *(merged into release/v2.8.0)* 11. **Snooze / dismiss notification actions** *(merged into release/v2.8.0)*
followed the `.ics` work; inherits v2.6's deferred exact-alarm/WorkManager followed the `.ics` work; inherits v2.6's deferred exact-alarm/WorkManager
decision (snooze must re-fire an alarm). decision (snooze must re-fire an alarm).

View File

@@ -25,7 +25,7 @@ release-cut.
## Progress ## 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] 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 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 - [x] Plan 02 written and executed — data layer + permission flow + debug screen

View File

@@ -62,9 +62,15 @@ flowchart TD
- **`data/prefs/`** — DataStore-backed settings (theme, week start, form - **`data/prefs/`** — DataStore-backed settings (theme, week start, form
field defaults, reminders toggle) and small state (last-used calendar). field defaults, reminders toggle) and small state (last-used calendar).
- **`ui/`** — one package per screen, each with Screen + ViewModel + - **`ui/`** — one package per screen, each with Screen + ViewModel +
UiState. Shared pieces in `ui/common/` (OptionCard — the app's only UiState. Shared pieces in `ui/common/` (recurrence humanizer, FAB column,
sanctioned selection-dialog style —, recurrence humanizer, FAB column, drawer, transitions). Selection pickers are full-screen and come from
drawer, transitions). 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 ## Navigation
@@ -81,7 +87,7 @@ exactly like an event tap.
## Recurring writes ## Recurring writes
The provider's invariants drive the design (learned the hard way, verified 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 - Recurring rows carry `RRULE` + `DURATION` (no `DTEND`); one-off rows
carry `DTEND`. 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), `CalendarDataSource` is faked (`FakeCalendarDataSource` records writes),
mappers parse `ColumnReader`/plain maps instead of cursors, domain logic mappers parse `ColumnReader`/plain maps instead of cursors, domain logic
(recurrence, validation, snapshots, write-value building) is pure. CI (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 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. F-Droid repo and then mints the `vX.Y.Z` tag + release. See docs/RELEASING.md.

View File

@@ -1,12 +1,35 @@
# Building from source # Building from source
Calendula builds with the standard Android Gradle toolchain — no extra setup 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 ## Requirements
- **Android SDK 36+** - **JDK 17** — not newer; the Android Gradle Plugin requires exactly 17. If your
- **JDK 17** — if your default JDK is not 17, set `JAVA_HOME` explicitly. 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. 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 ```bash
./gradlew assembleDebug # debug APK → app/build/outputs/apk/debug/ ./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 ./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 builds
Release signing and the publishing pipeline are documented separately in 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.

View File

@@ -4,19 +4,20 @@ Where to look for what:
| Document | What it is | | 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 | | [`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) | | [`../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/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/PROJECT.md`](../.planning/PROJECT.md) | What the project is, stack, naming, infrastructure |
| [`../.planning/REQUIREMENTS.md`](../.planning/REQUIREMENTS.md) | Requirement checklist per milestone | | [`../.planning/REQUIREMENTS.md`](../.planning/REQUIREMENTS.md) | Requirement checklist per milestone |
| [`../.planning/STATE.md`](../.planning/STATE.md) | Snapshot of where development currently stands | | [`../.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 | | [`design/`](design/) | Per-feature design notes kept for features whose provider behaviour is worth recording |
| [`superpowers/plans/`](superpowers/plans/) | Per-milestone implementation plans with task checklists — historical record of how each slice was built, including provider lessons learned |
| [`../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) | | [`../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-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 Conventions: the `.planning/` files are living documents and should stay current.
artifacts of the agentic workflow that built each milestone — they get `ARCHITECTURE.md` is the authoritative orientation tour — it is updated with the
status updates but are never rewritten. The `.planning/` files are living code, and is the right place for a lesson learned about the calendar provider.
documents and should stay current.