# Halkyon Learn A spaced-repetition learning app: studysets of flashcards with rich text, studied offline on every device and synced between a person's devices. Anyone can run an instance. - **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 | |---|---|---| | `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 | ## Running it locally You need Flutter (Dart v3.13 or later) and the Serverpod CLI v4.0.3 (`dart install serverpod_cli@4.0.3`). Linux builds also need `libwebkit2gtk-4.1-dev` and `libsecret-1-dev`. The rich-text editor comes from a fork that is expected at `../appflowy-editor`, next to this repository, until the fork is hosted. 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: ```sh cd 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 `halkyon_learn_flutter/assets/config.json` (`http://localhost:8080`). Without `--no-analytics`, the Serverpod CLI reports usage to Serverpod. ## Tests ```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`. 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. ## 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.