The root AGENTS.md holds what applies to every app and package (how work is done, Serverpod, checks with Melos and the tools, CI); Learn's own is apps/learn/AGENTS.md, Todo's a note that it is still the scaffold. The root README introduces the project, Learn's moves to its folder; LICENSE.md says which licence covers which directory, Todo's packages unlicensed until decided; one CONTRIBUTING.md. ADR 0015 records the decision; ADR 0014 and 0003 note what moved. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
88 lines
6.2 KiB
Markdown
88 lines
6.2 KiB
Markdown
# ADR 0015: One repository for every app and the packages they share
|
|
|
|
- **Status:** accepted
|
|
- **Date:** 2026-10-19
|
|
- **Decided by:** the developer, after Melos in each repository was offered instead.
|
|
|
|
## Context
|
|
|
|
Until 19 Oct 2026 Halkyon lived in three repositories: Learn's (`halkyon_learn`), the
|
|
shared packages' (`halkyon_shared`: `halkyon_ui`, the `halkyon_base` module of ADR 0014,
|
|
`halkyon_app`, `halkyon_core`, `halkyon_interop`) and Todo's, a local scaffold. Learn took
|
|
the shared packages by git, pinned to signed commits of `halkyon_shared`'s main, as it pins
|
|
the offline sync fork. Every change to a shared package was a round trip: commit there,
|
|
the developer signs and pushes, sends the hash, Learn's pins move, Learn's checks run again.
|
|
On 18 and 19 Oct alone that took four rounds (the theme and widgets, the module,
|
|
`halkyon_app`, data locations as precise as a state), each change only complete across two
|
|
repositories. Todo, Train and Meditate are expected to grow like Learn, slightly smaller,
|
|
on the same shared packages, so the rounds would multiply. Asked whether Melos, which runs
|
|
scripts across a workspace's packages, was worth setting up, the developer chose one
|
|
repository for everything, with Melos on top.
|
|
|
|
## Decision
|
|
|
|
1. **One repository, `project-halkyon/halkyon` on code.halkyon.app: Learn's renamed.** It
|
|
keeps the CI runner's registration, the Actions, the tags and the releases, and Forgejo
|
|
redirects the old address, so the server's checkout and the F-Droid listing keep
|
|
working until they are pointed at the new one.
|
|
2. **The layout:** `apps/<app>/` with each app's packages (`apps/learn/`: server, client,
|
|
app, curator, and `tool/` with the scripts writing Learn's assets; `apps/todo/`),
|
|
`packages/` with the shared packages, `deploy/` at the root as the instance deploy (other
|
|
services' compose files are to join Learn's there, which settles how an operator adds a
|
|
second service), `snap/` at the root (Learn's snap needs the whole workspace to build),
|
|
`tool/` with the repository's tools, `docs/adr/` with one numbering for every app.
|
|
3. **One pub workspace:** the root `pubspec.yaml` lists every package; one `pubspec.lock`
|
|
holds one version of each dependency for every app; the apps take the shared packages by
|
|
path; the root's `dependency_overrides` hold for every app (the sync fork; `cli_util`,
|
|
below). Todo moved to Serverpod 4.0.4 and Dart 3.13 with the rest.
|
|
4. **History kept, nothing rewritten.** Learn's history is the repository's.
|
|
`halkyon_shared`'s is merged in as it was, its packages read into `packages/` by the
|
|
merge itself, so its four commits keep their signatures. Todo's scaffold came in as
|
|
files: its one commit held the scaffold alone and was unsigned, and the deploy refuses
|
|
every commit new to it that isn't signed by a key in `deploy/allowed-signers`. Learn
|
|
moved into `apps/learn/` by a commit of renames alone, so `git log --follow` and blame
|
|
follow every file.
|
|
5. **Signing** takes one rebase that re-signs only what isn't signed yet:
|
|
`git rebase -r --exec '[ "$(git log -1 --format=%G?)" = G ] || git commit --amend --no-edit -S' main`.
|
|
A merged commit whose parents don't change is kept as it is, signature and all; tested
|
|
in a scratch repository before the move.
|
|
6. **Melos 8.9**, a dev dependency of the root (`dart run melos …`), runs scripts across
|
|
the packages (`analyze`, `test:dart`, `test:flutter`, `generate`, `check`), each taking
|
|
Melos' filters (`--diff`, `--include-dependents`, `--scope`).
|
|
7. **Tools in Dart where they hold logic, Bash for glue and for the production host,
|
|
Python only for Python-only libraries.** `tool/check.dart` replaces `tool/check.sh`
|
|
(its file selection tested in the root's `test/`), with `--changed-since=<commit>` for
|
|
only what changed and what depends on it; `tool/pre-push` is the hook (the signature
|
|
check, then the checks). `deploy/redeploy.sh` and `deploy/backup.sh` stay Bash: the
|
|
production host has no Dart SDK and gets none. Learn's `tool/release.sh` stays Bash
|
|
until build 21 is out, so the release that goes with ADR 0014's breaking deploy uses the
|
|
script it was proven with; then a release tool in Dart, shared by the apps and tagging
|
|
per app (`learn-vX.Y.Z`), takes over.
|
|
8. **The move happens while deploys pause** (until 22 Oct, after the hackathon's judging):
|
|
the first deploy from the new layout comes with build 21.
|
|
|
|
## Consequences
|
|
|
|
- A change to a shared package and to every app using it is one commit, checked as one;
|
|
a shared package's change must keep every app's tests passing in the same commit.
|
|
- One version of each dependency across the apps: an app's upgrade moves every app.
|
|
Serverpod moves as one already (ADR 0014). Melos needs `cli_util` 0.5, which Learn's
|
|
`flutter_launcher_icons` (0.14.4, its latest) doesn't allow; the root overrides it to
|
|
0.5.2, as that package uses only `cli_util`'s logger, unchanged in 0.5. Drop the override
|
|
once it allows 0.5.
|
|
- CI checks every package on every push, and the generated-code check covers every
|
|
server package (`dart run melos run generate`); the four throwaway test passwords CI
|
|
gives cover the module's and Todo's server tests too.
|
|
- **Deploys:** `deploy/` stays at the root, so the command the runner's key is pinned to on
|
|
learn.halkyon.eu's server (`/home/deploy/halkyon-learn/deploy/redeploy.sh`) is unchanged,
|
|
and the server's checkout keeps its folder. Its images are built from the root with the
|
|
workspace narrowed to what they need (`tool/workspace_only.sh`: Learn's server and the
|
|
module; the curator), checked by building both images before the move. The first deploy
|
|
after the move starts the server once more than needed, as the deployed copy of
|
|
`redeploy.sh` looks for migrations at their old path.
|
|
- `halkyon_shared`'s repository is archived, not deleted: Learn's commits before the move
|
|
pin it. Its commit style gives way to the repository's typed commits.
|
|
- Todo's packages have no licence until the developer decides (`LICENSE.md`).
|
|
- References to the old repository address in code and listings (the source link Learn's
|
|
instances name, the snap's and the F-Droid listing's source, the curator's credits) work
|
|
through Forgejo's redirect until they are changed to `project-halkyon/halkyon`.
|