Development
You need Node.js 22.13 or newer, and Docker.
npm install
cp .env.example .env
npm run dev:mail # a throwaway Dovecot + SMTP sink on localhost (any user, password "pass")
npm run seed # fill alice@example.test with realistic sample mail
npm run dev # http://127.0.0.1:5173: sign in as alice@example.test / passnpm run seed -- bob@example.test seeds a second mailbox. Mail sent between them is delivered for real, so you can watch live updates arrive.
npm run cli -- admin add alice@example.test makes alice an admin of your dev server (open /admin); npm run cli -- settings lists every setting. It's the viauna command, run from source.
npm run typecheck
npm test # unit tests, and that the docs match the code
npm run test:integration # end-to-end against the dev mail server
npm run build && npm start
npm run test:browser # every shortcut and the command menu, in Chromium (after a build)The browser tests need Chromium once: npx playwright-core install chromium-headless-shell.
npm test includes test/docs.test.ts, which fails when the docs and the code drift apart: an environment variable missing from Configuration, a shortcut that differs between the help panel and the shortcuts page, a server file missing from the layout in Architecture, or a page missing from the sidebar. A change to how something works, its timings or its limits also belongs in How it works.
On PostgreSQL, MySQL and MariaDB
npm test checks the state store on SQLite. To check it on every engine, as CI does, start throwaway databases and pass their URLs:
npm run dev:databases
export VIAUNA_TEST_PG=postgres://viauna:viauna@127.0.0.1:55432/viauna
export VIAUNA_TEST_MYSQL=mysql://viauna:viauna@127.0.0.1:53306/viauna
export VIAUNA_TEST_MARIADB=mariadb://viauna:viauna@127.0.0.1:53307/viauna
export VIAUNA_TEST_LDAP=ldap://127.0.0.1:53389 # password changes over LDAP
export VIAUNA_TEST_CARDDAV=http://127.0.0.1:55232 # contacts sync
npm test
VIAUNA_TEST_DATABASE_URL=$VIAUNA_TEST_PG npm run test:integration # end-to-end on one of themThe tests empty those databases, so don't point them at anything else.
How the pieces fit together is in Architecture. Before opening a pull request, read CONTRIBUTING.md.
Releasing
Changes land on main as they're ready, and every push publishes the edge image. Releases come in batches: one when a batch on the roadmap is done, or a patch release for fixes. Each change people will notice adds a line under Unreleased in CHANGELOG.md as it lands, so the notes are written by release time. To cut release X.Y.Z:
- In
CHANGELOG.md, rename## Unreleasedto## X.Y.Z - YYYY-MM-DDand put a new, empty## Unreleasedabove it. Edit the entries into release notes: that section becomes the GitHub Release text as written. - Set the version:
npm version X.Y.Z --no-git-tag-versionupdatespackage.jsonandpackage-lock.json. - Bring the docs up to date: image tags (
ghcr.io/bryanthomaschen/viauna:X.Y) and the tag table in Getting started; a "From … to X.Y" section in Upgrading if anything needs doing; and take the batch off the roadmap. npm run check:releasechecks that the version, the changelog and the docs agree. Commit as "Release X.Y.Z", push tomainand wait for CI.- Tag that commit and push the tag:
git tag vX.Y.Z && git push origin vX.Y.Z.
The Release workflow then builds the image for linux/amd64 and linux/arm64, publishes X.Y.Z, X.Y and latest to ghcr.io/bryanthomaschen/viauna, starts it on both, creates the GitHub Release from the changelog section, and last publishes these docs. It publishes nothing if the tag, package.json, the changelog and the docs disagree.
Patch releases
A fix for the current release can't wait for main, which already holds the next version's work, so a patch release X.Y.Z+1 is cut from a branch of the release itself:
- Land the fix on
mainfirst, as usual, with its changelog line. - On
release/X.Y(made from thevX.Y.0tag the first time:git branch release/X.Y vX.Y.0), cherry-pick the fix commits. Wheremainhas moved on, resolve towards the release: keep the release's code and take only the fix. Reword the changelog lines so they don't mention anything the release lacks. - Correct that branch's docs for anything the fix changes: the docs site is built from the tag, so it shows this branch's
docs/. - Test the branch yourself (CI runs on
mainonly):npm testandnpm run test:integrationon every state store, a build, and a look in the browser. - Make the release commit there (steps 1 to 4 above, as "Release X.Y.Z"), tag it, push the branch and the tag.
- Back on
main, "Record X.Y.Z": add the release's changelog section below Unreleased, take its entries out of Unreleased, and set the version and the image-tag table, somain's checks agree and the next release's notes don't repeat the fixes. Don't merge the release branch intomain: its cherry-picks were cut back to the release's code, and merging them would bring that back as conflicts.
These docs
The docs are the Markdown files in docs/, built with VitePress. The site describes the latest release, so it's published to GitHub Pages only when a release is tagged; on main, the docs describe the next release. Pushes and pull requests still build it, so a broken link fails the check. Link between pages with relative .md paths so they work on GitHub too. To preview your changes:
cd docs
npm install
npm run dev # http://127.0.0.1:5173/viauna/