77 lines
3.6 KiB
Markdown
77 lines
3.6 KiB
Markdown
|
|
# 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.
|