Files
narl-workspace/docs/wiki/Development.md
T
nvrl a59ba4af1b build: a clone compiles before the frontend is built
rust-embed refused to derive without `web/dist`, so on a fresh clone
`cargo check`, `cargo test` and rust-analyzer failed with a derive error that
did not say what was missing. With `allow_missing` the embed is empty until
the frontend is built, and the handler gives the answer it already had for
that case, "frontend not built". The release build is unchanged once
`web/dist` is there, which `make build`, the Dockerfile and CI all see to.
2026-10-21 12:35:59 +02:00

3.8 KiB

Development

Running it from source

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/App.svelte the keys
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

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 web/src/lib/Help.svelte and web/src/lib/commands.ts
Configuration .env.example
API 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

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.