Files
narl-workspace/docs/wiki/Development.md
T
nvrl 0eabcb2333 keys: one table drives dispatch, help, footers, the rail and the wiki
keymap.ts lists every key with its context, action and help line.
actions.ts holds what each one does, typed against the table so a key
without an action, or an action without a key, does not compile.
modes.ts stacks the contexts (always > sheet > drawer > workspace >
writing > focused tile > special > global) and writes the two-key
pending logic once. App.svelte's 480-line onkeydown is now one call.

Help, the panel footers (a shared Keys component), the rail's keycaps
and Commands.md all read the table; the wiki gains the card and
scratchpad key tables.

One fix on the way: Ctrl-S in the editor no longer saves twice, which
could make the second save fail as "changed somewhere else".
2026-10-22 03:42:19 +02:00

111 lines
4.0 KiB
Markdown

# Development
## Running it from source
```sh
make dev-api # cargo run, serving the API on :4242
make dev-web # vite on :4243, proxying /api to :4242
```
Open <http://127.0.0.1:4243>. The release binary embeds `web/dist`, and a
debug build reads it from disk, so build the frontend once
(`cd web && bun install && bun run build`) for `cargo run` alone to serve the
app. Without it the Rust side still compiles and tests, and the pages answer
"frontend not built".
Point `WORKSPACE_DATA_DIR` at a throwaway directory while trying things, so the
real data stays out of it.
## The code
| where | what |
| --- | --- |
| `src/main.rs` | start-up, the router, security headers, background loops |
| `src/routes/` | one module per area of the API: `nodes`, `boards`, `trash`, `revisions`, `links`, `capture`, `diary`, `media`, `file_text`, `seal`, `share`, `import`, `export` … |
| `src/sftp/` | the SFTP mount |
| `src/backup/` | the Proton Drive mirror |
| `src/mail/`, `src/notify/` | the outbox, and what is worth a mail |
| `src/vault.rs` | the vault's keys and file format |
| `src/sweep.rs` | the daily clean-up: trash, old versions, unreferenced uploads |
| `migrations/` | the SQLite schema, one numbered file per change |
| `web/src/lib/keymap.ts` | every key: where it is heard, what it is called, its help line |
| `web/src/lib/actions.ts`, `modes.ts` | what each key does, and which contexts hear it first |
| `web/src/lib/store.svelte.ts` | the client's state, and every call to the API |
| `web/src/lib/commands.ts` | the `:` commands |
| `web/src/lib/Help.svelte` | the `?` screen |
The database is one SQLite file with FTS5 for search. Every migration is
applied at start, after a copy of the database is kept as
`diary.db.pre-<version>`. Many rules are enforced by triggers as well as in the
code, so no path can break them: a sealed file has no indexed text, a file in a
sealed folder is sealed, the diary cannot be deleted.
## Checks
```sh
make check
```
runs what CI runs:
- `cargo fmt --check`
- `cargo clippy --all-targets -- -D warnings`
- `cargo test`
- `bun run check` in `web/` (svelte-check)
The Rust tests run against an in-memory database; most modules have a test
block at the bottom.
## CI
`.github/workflows/ci.yml` runs on every push and pull request:
- **rust**: builds the frontend, so the tests see the app the binary ships,
then format, clippy and the tests;
- **web**: svelte-check;
- **docs**: checks that the generated wiki pages are up to date and that every
link between the pages resolves.
`.github/workflows/wiki.yml` publishes `docs/wiki` to the GitHub wiki on every
push to `main` that changes it, or changes a file the generated pages are read
from.
## The wiki
The pages live in `docs/wiki` and the pictures in `docs/images`. Edit them
there; an edit on GitHub's wiki page is overwritten by the next publish.
Three pages are generated by `scripts/wiki.ts`:
| page | read from |
| --- | --- |
| [Keys and commands](Commands.md) | `web/src/lib/keymap.ts` and `web/src/lib/commands.ts` |
| [Configuration](Configuration.md) | `.env.example` |
| [API](API.md) | the API section of `README.md` |
After changing one of those, run `make wiki` and commit the result. CI fails
when they are stale.
Links between pages are written as `Page-Name.md` so that they work when the
files are read in the repository; the publish step drops the `.md` for the
wiki.
## Screenshots
```sh
make screenshots
```
builds the app, starts it on a temporary data directory with a password made
up for the run, fills it with an example workspace, and drives a headless
Chromium through the views the docs show. The pictures are written to
`docs/images`. It needs `chromium` on the path (or `CHROMIUM=/path/to/chrome`),
and shrinks the pictures with ImageMagick when it is installed.
## Conventions
- One finished feature per commit, with the README, `:help` and the tests in
the same commit.
- Commit messages are `area: a sentence`, followed by prose about why.
- Comments explain why, not what.