docs: one repository for every app and shared package (ADR 0015)
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>
This commit is contained in:
parent
af1dbee509
commit
1b62c8098c
16 changed files with 542 additions and 393 deletions
201
AGENTS.md
201
AGENTS.md
File diff suppressed because one or more lines are too long
|
|
@ -1,10 +1,12 @@
|
|||
# Contributing to Halkyon Learn
|
||||
# Contributing to Halkyon
|
||||
|
||||
## Licences
|
||||
|
||||
Contributions are accepted under the licence of the package they change (see
|
||||
`LICENSE.md`): `AGPL-3.0-or-later` for the app and the client, `SSPL-1.0` for the
|
||||
server. There is no copyright assignment and no contributor licence agreement: every
|
||||
`LICENSE.md`): `AGPL-3.0-or-later` for the apps, the client packages and the shared
|
||||
Flutter and Dart packages, `SSPL-1.0` for the servers and the server module. Halkyon
|
||||
Todo's packages have no licence yet; contributions to them wait until they have one.
|
||||
There is no copyright assignment and no contributor licence agreement: every
|
||||
contributor keeps the copyright of their work.
|
||||
|
||||
## Sign-off
|
||||
|
|
@ -12,14 +14,15 @@ contributor keeps the copyright of their work.
|
|||
Every commit carries a `Signed-off-by` line with your name and email address. With it
|
||||
you certify the Developer Certificate of Origin below: that you wrote the change, or
|
||||
otherwise have the right to submit it under the package's licence. `git commit -s` adds
|
||||
the line.
|
||||
the line, or `git config format.signoff true` for every commit.
|
||||
|
||||
## Before you push
|
||||
|
||||
`tool/check.sh` runs the format check, the analyzer and every test that doesn't need a
|
||||
running server. In a fresh clone, `ln -s ../../tool/check.sh .git/hooks/pre-push` makes
|
||||
every push run it. How the code is organised, and the rules it follows, are in
|
||||
`AGENTS.md`.
|
||||
`dart run tool/check.dart` runs the format check, the analyzer and every package's tests
|
||||
that don't need a running server. In a fresh clone,
|
||||
`ln -s ../../tool/pre-push .git/hooks/pre-push` makes every push run it. Keep a change
|
||||
focused, with its tests. How the code is organised, and the rules it follows, are in
|
||||
`AGENTS.md` and each app's own `AGENTS.md`.
|
||||
|
||||
## Developer Certificate of Origin
|
||||
|
||||
|
|
|
|||
26
LICENSE.md
26
LICENSE.md
|
|
@ -1,19 +1,25 @@
|
|||
# Licences
|
||||
|
||||
Halkyon Learn's packages carry different licences:
|
||||
The repository's packages carry different licences, each package's full text in its
|
||||
`LICENSE` file:
|
||||
|
||||
| Package | Licence | SPDX |
|
||||
|---|---|---|
|
||||
| `halkyon_learn_flutter`, the app | GNU Affero General Public License, version 3 or any later version | `AGPL-3.0-or-later` |
|
||||
| `halkyon_learn_client`, generated from our models | GNU Affero General Public License, version 3 or any later version | `AGPL-3.0-or-later` |
|
||||
| `halkyon_learn_server` | Server Side Public License, version 1 | `SSPL-1.0` |
|
||||
| `halkyon_learn_curator`, turning dictionary downloads into dictionary files | GNU Affero General Public License, version 3 or any later version | `AGPL-3.0-or-later` |
|
||||
| `apps/learn/halkyon_learn_flutter`, Learn's app | GNU Affero General Public License, version 3 or any later version | `AGPL-3.0-or-later` |
|
||||
| `apps/learn/halkyon_learn_client`, generated from Learn's models | GNU Affero General Public License, version 3 or any later version | `AGPL-3.0-or-later` |
|
||||
| `apps/learn/halkyon_learn_server` | Server Side Public License, version 1 | `SSPL-1.0` |
|
||||
| `apps/learn/halkyon_learn_curator`, turning dictionary downloads into dictionary files | GNU Affero General Public License, version 3 or any later version | `AGPL-3.0-or-later` |
|
||||
| `packages/halkyon_base_server`, the Serverpod module every Halkyon server includes | Server Side Public License, version 1 | `SSPL-1.0` |
|
||||
| `packages/halkyon_base_client`, generated from the module's models | GNU Affero General Public License, version 3 or any later version | `AGPL-3.0-or-later` |
|
||||
| `packages/halkyon_app`, `packages/halkyon_ui` | GNU Affero General Public License, version 3 or any later version | `AGPL-3.0-or-later` |
|
||||
| `packages/halkyon_core`, `packages/halkyon_interop` | GNU Affero General Public License, version 3 or any later version, as halkyon_shared, where they began, licensed them; their `LICENSE` files are still placeholders to be replaced with its text | `AGPL-3.0-or-later` |
|
||||
| `apps/todo/*`, Halkyon Todo's scaffold | None yet: unlicensed until the developer decides | — |
|
||||
|
||||
Each package holds the full text in its `LICENSE` file. The server builds on
|
||||
Serverpod's core, which is under the SSPL. The app links only BSD-3 packages, and the
|
||||
client package is generated from our own model definitions, so both are under the AGPL.
|
||||
The curator depends on neither the server nor Serverpod: the server reads the files it
|
||||
writes, never its code.
|
||||
The servers and the module build on Serverpod's core, which is under the SSPL, and so are
|
||||
under it too. The apps and the shared Flutter packages link only permissively licensed
|
||||
packages, and the client packages are generated from our own model definitions, so all of
|
||||
them are under the AGPL. The curator depends on neither a server nor Serverpod: Learn's
|
||||
server reads the files it writes, never its code.
|
||||
|
||||
Everything else in this repository (tooling, documentation, deployment files) is under
|
||||
`AGPL-3.0-or-later` unless a file says otherwise.
|
||||
|
|
|
|||
198
README.md
198
README.md
|
|
@ -1,158 +1,64 @@
|
|||
# Halkyon Learn
|
||||
# Halkyon
|
||||
|
||||
Halkyon Learn is for creating, sharing and collaborating on study material. It schedules
|
||||
flashcards with [FSRS](https://github.com/open-spaced-repetition) to strengthen
|
||||
retention, and organises study material together with the external references it draws
|
||||
on. It is offline-first: everything works on the device, without a connection. And the
|
||||
whole stack is transparent: the app, the server and everything needed to host an
|
||||
instance are published, so anyone can see how an instance works and run their own.
|
||||
Halkyon's apps and the packages they share, in one repository. Each app is a Flutter app
|
||||
for Linux, Windows, macOS, Android and iOS with a [Serverpod](https://serverpod.dev)
|
||||
server of its own, offline-first, and anyone may run an instance of it: the apps, the
|
||||
servers and everything needed to host an instance are published.
|
||||
|
||||
- **Offline first.** Each device keeps its own database and syncs in the background
|
||||
(`serverpod_offline_sync`). Edits made on two devices while offline are never lost:
|
||||
card content is stored as append-only revisions, and a side changed differently on two
|
||||
devices is shown as a conflict until the person picks a version
|
||||
([ADR 0001](docs/adr/0001-offline-sync.md), [ADR 0003](docs/adr/0003-card-revisions.md)).
|
||||
- **No sign-up needed.** The app starts with an anonymous account; signing in with GitHub
|
||||
later keeps everything. A GitHub sign-in stores only the numeric GitHub ID.
|
||||
- **No end-to-end encryption.** Content is readable by the operator of the instance, as on
|
||||
Mastodon; whoever trusts no operator can run their own
|
||||
([ADR 0002](docs/adr/0002-no-end-to-end-encryption.md)).
|
||||
|
||||
Targets: Linux, Windows, macOS, Android and iOS. There is no web build.
|
||||
|
||||
## Packages
|
||||
|
||||
| Package | What it is | Licence |
|
||||
| App | What it is | Where |
|
||||
|---|---|---|
|
||||
| `halkyon_learn_server` | The [Serverpod](https://serverpod.dev) server: endpoints, models, migrations | SSPL-1.0 |
|
||||
| `halkyon_learn_client` | The client, generated from the server's models | AGPL-3.0-or-later |
|
||||
| `halkyon_learn_flutter` | The app (`app.halkyon.learn`) | AGPL-3.0-or-later |
|
||||
| Halkyon Learn | Creating, sharing and studying study material, flashcards scheduled with FSRS | [`apps/learn/`](apps/learn/README.md), at learn.halkyon.eu |
|
||||
| Halkyon Todo | To-dos; still Serverpod's scaffold | [`apps/todo/`](apps/todo/) |
|
||||
|
||||
## Setting up
|
||||
Halkyon Train and Halkyon Meditate are to follow.
|
||||
|
||||
## Layout
|
||||
|
||||
- `apps/<app>/`: each app's server, generated client and Flutter app.
|
||||
- `packages/`: what the apps share, taken by path:
|
||||
[`halkyon_ui`](packages/halkyon_ui/README.md) (the look: theme, bundled Noto Sans,
|
||||
layout, shared widgets), [`halkyon_app`](packages/halkyon_app/README.md) (instances,
|
||||
signing in, each person's data and its sync),
|
||||
[`halkyon_base`](packages/halkyon_base_server/README.md) (what every server has, as a
|
||||
Serverpod module with its generated client `halkyon_base_client`: signing in, the
|
||||
account and its deletion, the pruning, the instance's basics),
|
||||
[`halkyon_core`](packages/halkyon_core/README.md) (low-level primitives) and
|
||||
[`halkyon_interop`](packages/halkyon_interop/README.md) (contracts between apps).
|
||||
- `deploy/`: what runs an instance (Docker Compose: Caddy, the server, PostgreSQL),
|
||||
learn.halkyon.eu's today.
|
||||
- `tool/`: the checks, the pre-push hook and the release scripts. `docs/adr/`: the
|
||||
decisions and their reasons.
|
||||
|
||||
One pub workspace holds every package: one `pubspec.lock`, one version of each dependency.
|
||||
[Melos](https://melos.invertase.dev) runs scripts across them.
|
||||
|
||||
## Getting started
|
||||
|
||||
- **Flutter v3.47.5**, the version CI uses (`FLUTTER_VERSION` in
|
||||
`.forgejo/workflows/ci.yaml`). Set up each platform you build for with Flutter's own
|
||||
guides: [Linux](https://docs.flutter.dev/platform-integration/linux/setup),
|
||||
[Windows](https://docs.flutter.dev/platform-integration/windows/setup),
|
||||
[Android](https://docs.flutter.dev/platform-integration/android/setup),
|
||||
[macOS](https://docs.flutter.dev/platform-integration/macos/setup),
|
||||
[iOS](https://docs.flutter.dev/platform-integration/ios/setup).
|
||||
- **The Serverpod CLI v4.0.4**: `dart install serverpod_cli@4.0.4`. Pass `--no-analytics`
|
||||
to every call; otherwise it reports the commands run to Serverpod.
|
||||
- **Linux**, on top of Flutter's packages, the libraries of four plugins: WebKitGTK
|
||||
(pulled in by the sign-in package), libsecret (keeps the session), GStreamer (plays
|
||||
sounds) and libmpv (plays videos from Jellyfin; the app doesn't start without it).
|
||||
On Debian or Ubuntu, Flutter's and these together:
|
||||
|
||||
```sh
|
||||
sudo apt-get install clang cmake ninja-build pkg-config libgtk-3-dev libstdc++-12-dev \
|
||||
libwebkit2gtk-4.1-dev libsecret-1-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
|
||||
libmpv-dev
|
||||
```
|
||||
|
||||
- **Windows** needs Developer Mode (Settings › System › For developers): building makes
|
||||
symbolic links, as Flutter links each plugin's native code into the build and the PDF
|
||||
engine's build does too, and Windows lets ordinary users make them only in Developer
|
||||
Mode.
|
||||
- **No Docker** for development: `serverpod start` and the server's tests run an embedded
|
||||
PostgreSQL. Docker Compose is only for running an instance (below).
|
||||
- **For the scripts in `tool/`**: Python 3 (`tool/app_icons.py` also needs Pillow,
|
||||
`python3-pil`), and for releases what [Releases](#releases) lists.
|
||||
|
||||
The rich-text editor comes from our fork of AppFlowy Editor
|
||||
([project-halkyon/appflowy-editor](https://code.halkyon.app/project-halkyon/appflowy-editor)),
|
||||
which `flutter pub get` fetches by itself.
|
||||
|
||||
## Running it locally
|
||||
|
||||
The server's secrets live in `halkyon_learn_server/config/passwords.yaml`, which is never
|
||||
committed. In a fresh clone, create it with a `development` and a `test` section, each
|
||||
holding `database`, `serverSideSessionKeyHashPepper` and `serviceSecret` (for example from
|
||||
`openssl rand -base64 32`). GitHub sign-in is optional: add `githubClientId` and
|
||||
`githubClientSecret` of your own GitHub OAuth app to `development`, registered with the
|
||||
callback URLs `app.halkyon.learn://github-callback` and `http://127.0.0.1/github-callback`.
|
||||
|
||||
Then start the server, its embedded database and the app:
|
||||
`.forgejo/workflows/ci.yaml`), with each platform you build for set up by Flutter's own
|
||||
guides; what an app needs beyond that is in its README.
|
||||
- **The Serverpod CLI v4.0.4**: `dart install serverpod_cli@4.0.4`. Pass
|
||||
`--no-analytics` to every call; otherwise it reports the commands run to Serverpod.
|
||||
- **A C++ compiler**, for `flutter test` too: a dependency of Learn's compiles MeCab as
|
||||
it builds.
|
||||
|
||||
```sh
|
||||
cd halkyon_learn_server
|
||||
serverpod --no-analytics start
|
||||
flutter pub get # every package of the workspace
|
||||
dart run melos list # the packages
|
||||
ln -s ../../tool/pre-push .git/hooks/pre-push # the checks before every push
|
||||
dart run tool/check.dart # format, analysis, every package's tests
|
||||
```
|
||||
|
||||
`serverpod start` applies pending migrations and reloads on changes. The app talks to the
|
||||
server named by `--dart-define=SERVER_URL=…`, or else to the one in
|
||||
`halkyon_learn_flutter/assets/config.json` (`http://localhost:8080`). Without
|
||||
`--no-analytics`, the Serverpod CLI reports usage to Serverpod.
|
||||
`dart run tool/check.dart --changed-since=origin/main` tests only what changed since
|
||||
`main` and what depends on it; `dart run melos run test:flutter --scope=<package>` one
|
||||
package's Flutter tests. Each server's tests start an embedded PostgreSQL (no Docker) and
|
||||
need test passwords in the server's git-ignored `config/passwords.yaml` (the module's
|
||||
README and each app's say which). How the code is organised and the rules it follows are
|
||||
in [`AGENTS.md`](AGENTS.md) and each app's own.
|
||||
|
||||
## Tests
|
||||
## Licences
|
||||
|
||||
```sh
|
||||
tool/check.sh
|
||||
```
|
||||
|
||||
runs the format check, the analyzer with the strict lints of `leancode_lint`, the server's
|
||||
tests (against an embedded PostgreSQL, no Docker needed) and the app's tests. To run it
|
||||
before every push: `ln -s ../../tool/check.sh .git/hooks/pre-push`. CI runs it on every
|
||||
push too (`.forgejo/workflows/ci.yaml`).
|
||||
|
||||
The sync tests need a running server (`serverpod start`); run them in
|
||||
`halkyon_learn_flutter` with `flutter test -t requires-server`.
|
||||
|
||||
## Running an instance
|
||||
|
||||
`deploy/` holds a Docker Compose setup: Caddy (HTTPS), the server and PostgreSQL. Copy
|
||||
`deploy/.env.example` to `deploy/.env` and fill it in; it explains every value. The
|
||||
licences require offering the source of what the instance runs to the people who use it.
|
||||
Assistants such as Claude read people's studysets through the instance's MCP connector at
|
||||
`/mcp` ([ADR 0006](docs/adr/0006-assistant-connector.md)): `webServer` in
|
||||
`halkyon_learn_server/config/production.yaml` names its public address, as `apiServer`
|
||||
does for the app.
|
||||
|
||||
learn.halkyon.eu itself deploys from `main` once CI is green: `deploy/redeploy.sh`, run by
|
||||
the CI runner described in `deploy/runner/`, deploys only commits signed by a key in
|
||||
`deploy/allowed-signers`. It backs up its database every hour, off-site and encrypted;
|
||||
[`deploy/backups.md`](deploy/backups.md) says how to set that up and how to restore.
|
||||
|
||||
## Releases
|
||||
|
||||
Releases are published on [code.halkyon.app](https://code.halkyon.app/project-halkyon/halkyon_learn/releases),
|
||||
with the APK and the snap, and the APK also in the project's F-Droid repository
|
||||
(`https://halkyon.app/fdroid/repo?fingerprint=E8082788756F6B7E682AA22FCEAD24B53E2A8B0912AD66D65E8C2D4F07BB94B0`,
|
||||
added in the F-Droid app as a repository). The Snap Store (`halkyon-learn`) follows.
|
||||
Their builds offer learn.halkyon.eu, the project's instance, at first start; people
|
||||
may choose another there, and keep accounts on several.
|
||||
|
||||
- **Checking a download:** `SHA256SUMS` lists the checksum of every file, signed with the
|
||||
maintainer's GPG key (`SHA256SUMS.asc`). The APK is signed with the app's key, whose
|
||||
certificate has the SHA-256
|
||||
`27:E2:43:FC:BD:C8:26:FF:98:AB:7D:BB:10:43:6C:98:C3:BE:A2:4B:2A:01:5E:94:E4:CF:C7:D1:FC:2A:00:6C`
|
||||
(`apksigner verify --print-certs` shows it).
|
||||
- **Versions** follow [semantic versioning](https://semver.org): `version` in
|
||||
`halkyon_learn_flutter/pubspec.yaml`, `<major>.<minor>.<patch>+<build>`. Since the last
|
||||
release, a commit typed `feat` raises the minor number, `fix` or `perf` the patch
|
||||
number, and a breaking one (`feat!:` or a `BREAKING CHANGE:` line) the major number from
|
||||
1.0 on, the minor one before; other commits release nothing by themselves. Every
|
||||
release raises the build number: Android only installs a higher one over an older, and
|
||||
the server tells apps below the build it supports to update.
|
||||
- **Making one** is for maintainers, on their own machine and never in CI:
|
||||
`tool/release.sh`, or `tool/release.sh minor` (or `major`, `patch`) to choose. It needs
|
||||
`main` clean, pushed and green in CI, the app's key, the F-Droid repository's key and
|
||||
a Forgejo token; its header says more. It shows the version and its commits and asks
|
||||
first, then writes the version into the pubspec in a signed release commit with a
|
||||
signed tag, builds the APK and the snap (`snap/snapcraft.yaml`, built in LXD; its icon
|
||||
comes from `tool/app_icons.py`), checks both, signs the checksums, pushes, and
|
||||
publishes on code.halkyon.app and in the F-Droid repository; the Snap Store once it is
|
||||
switched on in the script. Besides Flutter and the Android SDK, it uses snapcraft with
|
||||
LXD, a JDK (keytool), GnuPG, curl, jq, unzip, squashfs-tools, rsync and fdroidserver.
|
||||
Release builds made without the app's key are signed with the debug key and can't
|
||||
update a released app.
|
||||
- **The F-Droid repository** is kept by `tool/fdroid_repo.sh` (fdroidserver v2.4.5,
|
||||
e.g. `pipx install fdroidserver==2.4.5`); its settings and the app's listing are in
|
||||
`tool/release/fdroid/`.
|
||||
|
||||
## More
|
||||
|
||||
- [`AGENTS.md`](AGENTS.md): how the code is organised and the rules it follows.
|
||||
- [`docs/adr/`](docs/adr/): the architecture decisions and their reasons.
|
||||
- [`CONTRIBUTING.md`](CONTRIBUTING.md): licences of contributions and the sign-off.
|
||||
- [`LICENSE.md`](LICENSE.md): which licence covers what.
|
||||
The servers and the server module are under the Server Side Public License 1.0, the apps,
|
||||
the client packages and the other shared packages under the GNU Affero General Public
|
||||
License 3.0 or later; Todo's packages have none yet. [`LICENSE.md`](LICENSE.md) says
|
||||
which covers what, [`CONTRIBUTING.md`](CONTRIBUTING.md) how to contribute.
|
||||
|
|
|
|||
124
apps/learn/AGENTS.md
Normal file
124
apps/learn/AGENTS.md
Normal file
File diff suppressed because one or more lines are too long
1
apps/learn/CLAUDE.md
Normal file
1
apps/learn/CLAUDE.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
@AGENTS.md
|
||||
175
apps/learn/README.md
Normal file
175
apps/learn/README.md
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
# Halkyon Learn
|
||||
|
||||
Halkyon Learn is for creating, sharing and collaborating on study material. It schedules
|
||||
flashcards with [FSRS](https://github.com/open-spaced-repetition) to strengthen
|
||||
retention, and organises study material together with the external references it draws
|
||||
on. It is offline-first: everything works on the device, without a connection. And the
|
||||
whole stack is transparent: the app, the server and everything needed to host an
|
||||
instance are published, so anyone can see how an instance works and run their own.
|
||||
|
||||
- **Offline first.** Each device keeps its own database and syncs in the background
|
||||
(`serverpod_offline_sync`). Edits made on two devices while offline are never lost:
|
||||
card content is stored as append-only revisions, and a side changed differently on two
|
||||
devices is shown as a conflict until the person picks a version
|
||||
([ADR 0001](../../docs/adr/0001-offline-sync.md), [ADR 0003](../../docs/adr/0003-card-revisions.md)).
|
||||
- **No sign-up needed.** The app starts with an anonymous account; signing in with GitHub
|
||||
later keeps everything. A GitHub sign-in stores only the numeric GitHub ID.
|
||||
- **No end-to-end encryption.** Content is readable by the operator of the instance, as on
|
||||
Mastodon; whoever trusts no operator can run their own
|
||||
([ADR 0002](../../docs/adr/0002-no-end-to-end-encryption.md)).
|
||||
|
||||
Targets: Linux, Windows, macOS, Android and iOS. There is no web build.
|
||||
|
||||
## Packages
|
||||
|
||||
Learn lives in `apps/learn/` of the Halkyon repository, one workspace with Halkyon's
|
||||
other apps and the packages they share ([the repository's README](../../README.md)).
|
||||
|
||||
| Package | What it is | Licence |
|
||||
|---|---|---|
|
||||
| `halkyon_learn_server` | The [Serverpod](https://serverpod.dev) server: endpoints, models, migrations | SSPL-1.0 |
|
||||
| `halkyon_learn_client` | The client, generated from the server's models | AGPL-3.0-or-later |
|
||||
| `halkyon_learn_flutter` | The app (`app.halkyon.learn`) | AGPL-3.0-or-later |
|
||||
| `halkyon_learn_curator` | Turns dictionary sources into the files the server loads | AGPL-3.0-or-later |
|
||||
|
||||
It builds on the shared packages in `packages/`: `halkyon_base` (sign-in, accounts, the
|
||||
instance's basics; a Serverpod module), `halkyon_app` (instances, sign-in, sync) and
|
||||
`halkyon_ui` (the look).
|
||||
|
||||
## Setting up
|
||||
|
||||
- **Flutter v3.47.5**, the version CI uses (`FLUTTER_VERSION` in
|
||||
`.forgejo/workflows/ci.yaml`). Set up each platform you build for with Flutter's own
|
||||
guides: [Linux](https://docs.flutter.dev/platform-integration/linux/setup),
|
||||
[Windows](https://docs.flutter.dev/platform-integration/windows/setup),
|
||||
[Android](https://docs.flutter.dev/platform-integration/android/setup),
|
||||
[macOS](https://docs.flutter.dev/platform-integration/macos/setup),
|
||||
[iOS](https://docs.flutter.dev/platform-integration/ios/setup).
|
||||
- **The Serverpod CLI v4.0.4**: `dart install serverpod_cli@4.0.4`. Pass `--no-analytics`
|
||||
to every call; otherwise it reports the commands run to Serverpod.
|
||||
- **Linux**, on top of Flutter's packages, the libraries of four plugins: WebKitGTK
|
||||
(pulled in by the sign-in package), libsecret (keeps the session), GStreamer (plays
|
||||
sounds) and libmpv (plays videos from Jellyfin; the app doesn't start without it).
|
||||
On Debian or Ubuntu, Flutter's and these together:
|
||||
|
||||
```sh
|
||||
sudo apt-get install clang cmake ninja-build pkg-config libgtk-3-dev libstdc++-12-dev \
|
||||
libwebkit2gtk-4.1-dev libsecret-1-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
|
||||
libmpv-dev
|
||||
```
|
||||
|
||||
- **Windows** needs Developer Mode (Settings › System › For developers): building makes
|
||||
symbolic links, as Flutter links each plugin's native code into the build and the PDF
|
||||
engine's build does too, and Windows lets ordinary users make them only in Developer
|
||||
Mode.
|
||||
- **No Docker** for development: `serverpod start` and the server's tests run an embedded
|
||||
PostgreSQL. Docker Compose is only for running an instance (below).
|
||||
- **For Learn's scripts in `apps/learn/tool/`**, run from `apps/learn`: Python 3
|
||||
(`tool/app_icons.py` also needs Pillow, `python3-pil`); for releases what
|
||||
[Releases](#releases) lists.
|
||||
|
||||
The rich-text editor comes from our fork of AppFlowy Editor
|
||||
([project-halkyon/appflowy-editor](https://code.halkyon.app/project-halkyon/appflowy-editor)),
|
||||
which `flutter pub get` fetches by itself.
|
||||
|
||||
## Running it locally
|
||||
|
||||
The server's secrets live in `apps/learn/halkyon_learn_server/config/passwords.yaml`,
|
||||
which is never committed. In a fresh clone, create it with a `development` and a `test`
|
||||
section, each holding `database`, `serverSideSessionKeyHashPepper` and `serviceSecret`
|
||||
(for example from `openssl rand -base64 32`). GitHub sign-in is optional: add
|
||||
`githubClientId` and `githubClientSecret` of your own GitHub OAuth app to `development`,
|
||||
registered with the callback URLs `app.halkyon.learn://github-callback` and
|
||||
`http://127.0.0.1/github-callback`.
|
||||
|
||||
Then start the server, its embedded database and the app:
|
||||
|
||||
```sh
|
||||
cd apps/learn/halkyon_learn_server
|
||||
serverpod --no-analytics start
|
||||
```
|
||||
|
||||
`serverpod start` applies pending migrations and reloads on changes. The app talks to the
|
||||
server named by `--dart-define=SERVER_URL=…`, or else to the one in
|
||||
`apps/learn/halkyon_learn_flutter/assets/config.json` (`http://localhost:8080`). Without
|
||||
`--no-analytics`, the Serverpod CLI reports usage to Serverpod.
|
||||
|
||||
## Tests
|
||||
|
||||
From the repository's root,
|
||||
|
||||
```sh
|
||||
dart run tool/check.dart
|
||||
```
|
||||
|
||||
runs the format check, the analyzer with the strict lints of `leancode_lint` and every
|
||||
package's tests, Learn's server's (against an embedded PostgreSQL, no Docker needed), its
|
||||
curator's and its app's among them; `dart run melos run test:flutter
|
||||
--scope=halkyon_learn_flutter` runs the app's alone. To run the checks before every push:
|
||||
`ln -s ../../tool/pre-push .git/hooks/pre-push`. CI runs them on every push too
|
||||
(`.forgejo/workflows/ci.yaml`).
|
||||
|
||||
The sync tests need a running server (`serverpod start`); run them in
|
||||
`apps/learn/halkyon_learn_flutter` with `flutter test -t requires-server`.
|
||||
|
||||
## Running an instance
|
||||
|
||||
`deploy/`, at the repository's root, holds a Docker Compose setup: Caddy (HTTPS), the
|
||||
server and PostgreSQL. Copy `deploy/.env.example` to `deploy/.env` and fill it in; it
|
||||
explains every value. The licences require offering the source of what the instance runs
|
||||
to the people who use it. Assistants such as Claude read people's studysets through the
|
||||
instance's MCP connector at `/mcp`
|
||||
([ADR 0006](../../docs/adr/0006-assistant-connector.md)): `webServer` in
|
||||
`apps/learn/halkyon_learn_server/config/production.yaml` names its public address, as
|
||||
`apiServer` does for the app.
|
||||
|
||||
learn.halkyon.eu itself deploys from `main` once CI is green: `deploy/redeploy.sh`, run by
|
||||
the CI runner described in `deploy/runner/`, deploys only commits signed by a key in
|
||||
`deploy/allowed-signers`. It backs up its database every hour, off-site and encrypted;
|
||||
[`deploy/backups.md`](../../deploy/backups.md) says how to set that up and how to restore.
|
||||
|
||||
## Releases
|
||||
|
||||
Releases are published on [code.halkyon.app](https://code.halkyon.app/project-halkyon/halkyon/releases),
|
||||
with the APK and the snap, and the APK also in the project's F-Droid repository
|
||||
(`https://halkyon.app/fdroid/repo?fingerprint=E8082788756F6B7E682AA22FCEAD24B53E2A8B0912AD66D65E8C2D4F07BB94B0`,
|
||||
added in the F-Droid app as a repository). The Snap Store (`halkyon-learn`) follows.
|
||||
Their builds offer learn.halkyon.eu, the project's instance, at first start; people
|
||||
may choose another there, and keep accounts on several.
|
||||
|
||||
- **Checking a download:** `SHA256SUMS` lists the checksum of every file, signed with the
|
||||
maintainer's GPG key (`SHA256SUMS.asc`). The APK is signed with the app's key, whose
|
||||
certificate has the SHA-256
|
||||
`27:E2:43:FC:BD:C8:26:FF:98:AB:7D:BB:10:43:6C:98:C3:BE:A2:4B:2A:01:5E:94:E4:CF:C7:D1:FC:2A:00:6C`
|
||||
(`apksigner verify --print-certs` shows it).
|
||||
- **Versions** follow [semantic versioning](https://semver.org): `version` in
|
||||
`apps/learn/halkyon_learn_flutter/pubspec.yaml`, `<major>.<minor>.<patch>+<build>`.
|
||||
Since the last release, a commit typed `feat` raises the minor number, `fix` or `perf` the patch
|
||||
number, and a breaking one (`feat!:` or a `BREAKING CHANGE:` line) the major number from
|
||||
1.0 on, the minor one before; other commits release nothing by themselves. Every
|
||||
release raises the build number: Android only installs a higher one over an older, and
|
||||
the server tells apps below the build it supports to update.
|
||||
- **Making one** is for maintainers, on their own machine and never in CI, from the
|
||||
repository's root: `tool/release.sh`, or `tool/release.sh minor` (or `major`, `patch`)
|
||||
to choose (until build 21 is out; then a release tool in Dart, shared by the apps,
|
||||
takes over, [ADR 0015](../../docs/adr/0015-one-repository.md)). It needs `main` clean, pushed and green in CI, the app's key, the F-Droid repository's key and
|
||||
a Forgejo token; its header says more. It shows the version and its commits and asks
|
||||
first, then writes the version into the pubspec in a signed release commit with a
|
||||
signed tag, builds the APK and the snap (`snap/snapcraft.yaml`, built in LXD; its icon
|
||||
comes from `apps/learn/tool/app_icons.py`), checks both, signs the checksums, pushes, and
|
||||
publishes on code.halkyon.app and in the F-Droid repository; the Snap Store once it is
|
||||
switched on in the script. Besides Flutter and the Android SDK, it uses snapcraft with
|
||||
LXD, a JDK (keytool), GnuPG, curl, jq, unzip, squashfs-tools, rsync and fdroidserver.
|
||||
Release builds made without the app's key are signed with the debug key and can't
|
||||
update a released app.
|
||||
- **The F-Droid repository** is kept by `tool/fdroid_repo.sh` (fdroidserver v2.4.5,
|
||||
e.g. `pipx install fdroidserver==2.4.5`); its settings and the app's listing are in
|
||||
`tool/release/fdroid/`.
|
||||
|
||||
## More
|
||||
|
||||
- [`AGENTS.md`](AGENTS.md): how Learn's code is organised and the rules it follows; the
|
||||
[repository's](../../AGENTS.md) for what holds for every app.
|
||||
- [`docs/adr/`](../../docs/adr/): the architecture decisions and their reasons.
|
||||
- [`CONTRIBUTING.md`](../../CONTRIBUTING.md): licences of contributions and the sign-off.
|
||||
- [`LICENSE.md`](../../LICENSE.md): which licence covers what.
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
The app brings its fonts with it and never fetches any: text looks the same on
|
||||
every device, whatever fonts it has. Noto Sans, its font, comes with halkyon_ui
|
||||
(halkyon_shared), which bundles it with its licence and registers it; the fonts
|
||||
(`packages/halkyon_ui`), which bundles it with its licence and registers it; the fonts
|
||||
for Japanese, Chinese and Korean are the app's own, here.
|
||||
|
||||
| File | Font | Source | Licence |
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ release v5.1.2. Natural Earth's map data is in the public domain:
|
|||
## Japan's prefectures
|
||||
|
||||
`japan_prefectures.geojson` derives from *Admin 1 – States, Provinces*, 1:10m
|
||||
cultural vectors. `tool/maps/japan_prefectures.py` builds the file: it keeps
|
||||
cultural vectors. `apps/learn/tool/maps/japan_prefectures.py` builds the file: it keeps
|
||||
Japan's 47 prefectures, simplifies their outlines (Douglas–Peucker, 0.006°),
|
||||
drops islands too small to see (each prefecture keeps its largest), and rounds
|
||||
coordinates to 4 decimals. The outlines are an approximation for display, not
|
||||
|
|
@ -22,7 +22,7 @@ survey-accurate data. Regions are named by their ISO 3166-2 codes (`JP-01` …
|
|||
|
||||
`world_countries.geojson` derives from *Admin 0 – Countries*, 1:50m cultural
|
||||
vectors (Gibraltar and the US Outlying Islands, which it leaves out, from the
|
||||
1:10m layer). `tool/maps/world_countries.py` builds the file: one region per
|
||||
1:10m layer). `apps/learn/tool/maps/world_countries.py` builds the file: one region per
|
||||
ISO 3166-1 code (239), areas without a code of their own joined to the country
|
||||
ISO counts them under, outlines kept as Natural Earth generalised them (islands
|
||||
under 0.001 square degrees dropped), coordinates rounded to 3 decimals. Borders
|
||||
|
|
|
|||
|
|
@ -1,50 +1,7 @@
|
|||
# Flutter & Serverpod project
|
||||
# Halkyon Todo
|
||||
|
||||
This project is a Flutter app (frontend) backed by a Serverpod server (backend). Always build the app's backend with Serverpod.
|
||||
Build for multiple users, use Serverpod's built-in authentication, which is already set up in `lib/server.dart`.
|
||||
What holds for every app and package of this repository is in the [root AGENTS.md](../../AGENTS.md); it applies here in full.
|
||||
|
||||
The user starts the server and Flutter app with `serverpod start`. There is no need to check if the server is running: make the changes and call the `serverpod` MCP tools as needed. If the server is not running, an informative error message will be received from the MCP server. Then STOP and ask the user to start it. NEVER start the server yourself. The Flutter app is started along with it, or can be launched from the MCP tool `spawn_flutter_app`.
|
||||
|
||||
While running, `serverpod start` watches for file changes to run incremental code generation and hot reload both the server and the Flutter app.
|
||||
|
||||
Calling `serverpod generate` directly is not needed, but might be useful to troubleshoot when an incremental generation fails.
|
||||
|
||||
ALWAYS use the MCP server instead of the command line. Use the MCP server to:
|
||||
|
||||
- `create_migration` and `apply_migrations` for database (after you change data models).
|
||||
- `create_repair_migration` if the database has drifted out of sync with the migrations.
|
||||
- `tail_server_logs` to read logs from the server.
|
||||
- `tail_flutter_logs` to read the raw stdout/stderr of the Flutter app.
|
||||
- `hot_reload` / `hot_restart` to reload or restart the server and the Flutter app. ALWAYS call `hot_restart` after doing changes in the Flutter app that may not work with normal hot reload (which is automatically applied).
|
||||
- `spawn_flutter_app` to start a Flutter app declared under `serverpod: flutter_apps:` in the server `pubspec.yaml`.
|
||||
- `get_flutter_app_dtd` (Dart tooling daemon) for connecting to the app through the `dart` MCP.
|
||||
|
||||
NEVER edit generated code. The server's `lib/src/generated/` directory and the whole `halkyon_todo_client` package are rewritten by the code generator. Change the `.spy.yaml` models, the endpoints, or `lib/server.dart` instead.
|
||||
|
||||
Migrations are a narrow exception: the `migration.sql` of a generated migration MAY be edited by hand when the generated SQL would lose data — to add a data transformation, or to reach a destructive change through non-destructive steps. Never touch the other files in the migration directory, and keep the schema the SQL ends up with identical to `definition.sql` — new databases are created from that file and never run `migration.sql`.
|
||||
|
||||
Only when the server cannot be started at all, fall back to the CLI in the server package:
|
||||
|
||||
- `serverpod generate` to regenerate the client and the generated server code.
|
||||
- `serverpod create-migration` after changing a model with a `table` (add `--force` for destructive changes). It only writes the migration; `serverpod start` applies pending migrations when it boots the server.
|
||||
|
||||
Tests need no Docker. `config/test.yaml` sets `database.dataPath`, so Serverpod starts and manages the test database (an embedded PostgreSQL) itself, and the project's `docker-compose.yaml` is not used for it. Just run `dart test` in the server package.
|
||||
|
||||
Checklist after doing changes, in this order:
|
||||
|
||||
- `dart analyze` (CLI)
|
||||
- `dart format` (CLI)
|
||||
- `create_migration` and `apply_migrations` (MCP - only if necessary)
|
||||
- Do `serverpod` MCP `hot_restart` if required (hot reload is done automatically). Will also hot restart Flutter app
|
||||
- Run tests, if applicable (`dart test` in the server package)
|
||||
- Check `serverpod` MCP `tail_server_logs` and `tail_flutter_logs` for any issues.
|
||||
|
||||
If the user asks you to test the app:
|
||||
|
||||
1. Use `get_flutter_app_dtd` (`serverpod` MCP) to get the Flutter app's DTD
|
||||
2. Pass the DTD to `connect_dart_tooling_daemon` (`dart` MCP) to connect to the app
|
||||
3. Use `flutter_driver` (`dart` MCP) to navigate through the app
|
||||
|
||||
The app is launched from `halkyon_todo_flutter/lib/driver.dart`, which starts the Flutter driver extension with text entry emulation turned off so the app stays usable by hand. To let the driver type, set `enableTextEntryEmulation: true` there and `hot_restart` the app.
|
||||
|
||||
IMPORTANT: After building the first version of the app, update this AGENTS.md file with information about the app we're building. KEEP the info about the MCP server and the checklist. Remove this paragraph.
|
||||
- **Still Serverpod's scaffold** (`serverpod create`, joined the repository on 2026-10-19, ADR 0015): `halkyon_todo_server`, `halkyon_todo_client` (generated, never edited) and `halkyon_todo_flutter`, with the template's greeting endpoint and screens. Since joining: Serverpod 4.0.4 and Dart 3.13 like every package, server-side sessions (`ServerSideSessionsConfigFromPasswords`, 90 days unused), Serverpod's own email-and-password sign-in still, `google_fonts` gone (it fetches fonts, which Halkyon never does), and the scaffold's lints (`lints`, `flutter_lints`) rather than the root's.
|
||||
- **To be built on the shared packages**, as Learn is: `halkyon_base` for signing in, the account and the instance's basics (its server configured with `HalkyonBase.configure` and an app id of its own, which never changes once apps use it), `halkyon_app` for the instances, sign-in, the gates and sync, `halkyon_ui` for the look (`packages/*/README.md`). What it keeps and syncs, and which of Learn's rules it adopts, the developer decides first.
|
||||
- **`serverpod start`** runs in `apps/todo/halkyon_todo_server`; `.mcp.json`'s `--server-dir` names it when a session works on Todo. Its tests need throwaway passwords in its git-ignored `config/passwords.yaml` (`database`, `serviceSecret`, `serverSideSessionKeyHashPepper`) or from the environment, as CI gives them.
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@ conflict: "big" changed to "large" on one device and to "huge" on another become
|
|||
conflict, and a side changed differently is a conflict that the app shows with every
|
||||
version until the person keeps one. Merging happens when reading; nothing is written
|
||||
until the person saves. The code is
|
||||
`halkyon_learn_flutter/lib/src/feature/card/model/card_merge.dart`.
|
||||
`halkyon_learn_flutter/lib/src/feature/card/model/card_merge.dart` (under `apps/learn/`
|
||||
since 2026-10-19, ADR 0015).
|
||||
**Amended 2026-10-01, card types:** a card now has a type (front/back, multiple
|
||||
choice, vocabulary, matching) and the fields of that type, and the merge runs per
|
||||
field instead of per side: the type itself, the front, the back, the answers, the
|
||||
|
|
|
|||
|
|
@ -2,6 +2,11 @@
|
|||
|
||||
- **Status:** accepted
|
||||
- **Date:** 2026-10-19
|
||||
- **Amended by:** [ADR 0015](0015-one-repository.md) (2026-10-19): halkyon_shared's packages
|
||||
now live in this repository's `packages/`, which the apps take by path. Where this record
|
||||
says the module, `halkyon_ui` and `halkyon_app` are pinned by git to signed commits of
|
||||
halkyon_shared's main, read: taken by path, a change to the module and its hosts one
|
||||
commit.
|
||||
|
||||
## Context
|
||||
|
||||
|
|
|
|||
88
docs/adr/0015-one-repository.md
Normal file
88
docs/adr/0015-one-repository.md
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
# 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`.
|
||||
|
|
@ -28,7 +28,7 @@ Written as the apps are: Dart 3.13's primary constructors, Material from
|
|||
have their own, such as Scotland; else the country's). Countries are named
|
||||
by the app's `CountryNames`, subdivisions by Unicode CLDR's names in English
|
||||
and German, which come with the package (`AssetSubdivisionNames`; the
|
||||
workspace's `tool/subdivision_names.py` writes them).
|
||||
package's `tool/subdivision_names.py` writes them).
|
||||
- **Gates** (`lib/src/app/`): `InstanceGate` opens the app's dependencies on
|
||||
the instance in use (`AppDependencies`, handed down by `AppScope`), anew on
|
||||
a switch, the previous ones closed first; `SessionGate` keeps a person
|
||||
|
|
@ -57,17 +57,13 @@ Written as the apps are: Dart 3.13's primary constructors, Material from
|
|||
|
||||
1. **The server** includes `halkyon_base` with the nickname `base` (its
|
||||
README), so the app's generated client has `client.modules.base`.
|
||||
2. **Depend on it** by git, pinned to a signed commit of halkyon_shared's
|
||||
main, as `halkyon_ui` (whose README shows the `pubspec_overrides.yaml` for
|
||||
working on both at once):
|
||||
2. **Depend on it** by path, within the repository's workspace, as on
|
||||
`halkyon_ui`:
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
halkyon_app:
|
||||
git:
|
||||
url: https://code.halkyon.app/project-halkyon/halkyon_shared.git
|
||||
path: packages/halkyon_app
|
||||
ref: <signed commit>
|
||||
path: ../../../packages/halkyon_app
|
||||
```
|
||||
|
||||
3. **Texts**: add `HalkyonAppLocalizations.delegate` to every `MaterialApp`'s
|
||||
|
|
|
|||
|
|
@ -33,15 +33,13 @@ Endpoints, under the nickname `base` in a host's client (`client.base.emailCode`
|
|||
|
||||
## Taking it into a host
|
||||
|
||||
1. Depend on both packages, pinned to a signed commit of `halkyon_shared`:
|
||||
1. Depend on both packages by path, within the repository's workspace (an app's
|
||||
packages sit in `apps/<app>/`):
|
||||
|
||||
```yaml
|
||||
# the server's pubspec.yaml
|
||||
halkyon_base_server:
|
||||
git:
|
||||
url: https://code.halkyon.app/project-halkyon/halkyon_shared.git
|
||||
path: packages/halkyon_base_server
|
||||
ref: <signed commit>
|
||||
path: ../../../packages/halkyon_base_server
|
||||
# the client's pubspec.yaml: the same with halkyon_base_client
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -42,29 +42,15 @@ What belongs to one app stays in it: its own colours (an extension passed to
|
|||
|
||||
## Using it in an app
|
||||
|
||||
Depend on it by git, pinned to a signed commit, as the apps pin their forks:
|
||||
Depend on it by path, within the repository's workspace (an app's packages sit in
|
||||
`apps/<app>/`), so a change to the package and to the apps using it is one commit:
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
halkyon_ui:
|
||||
git:
|
||||
url: https://code.halkyon.app/project-halkyon/halkyon_shared.git
|
||||
path: packages/halkyon_ui
|
||||
ref: <signed commit>
|
||||
path: ../../../packages/halkyon_ui
|
||||
```
|
||||
|
||||
While changing both at once, point the app at a local checkout with a
|
||||
git-ignored `pubspec_overrides.yaml` beside the app's workspace root:
|
||||
|
||||
```yaml
|
||||
dependency_overrides:
|
||||
halkyon_ui:
|
||||
path: ../halkyon_shared/packages/halkyon_ui
|
||||
```
|
||||
|
||||
The lockfile then records the path: never commit it so, as CI has no such
|
||||
folder.
|
||||
|
||||
Then set the app up as `example/lib/main.dart` does:
|
||||
|
||||
```dart
|
||||
|
|
@ -95,7 +81,7 @@ fallback); `halkyon_ui_de.arb` German, informal "du"; `halkyon_ui_en_US.arb`
|
|||
only what American English spells differently; `halkyon_ui_en_GB.arb` empty. A
|
||||
new text goes into the template and German together (`test/l10n/` fails
|
||||
otherwise). `flutter pub get` writes `lib/l10n/halkyon_ui_localizations*.dart`,
|
||||
which are committed (apps take the package by git) and never edited or
|
||||
which are committed and never edited or
|
||||
formatted by hand.
|
||||
|
||||
## Checks
|
||||
|
|
|
|||
Loading…
Reference in a new issue