When running /release, include a documentation review step before shipping.
Steps
- Scan commits since last release for features, UI changes, new roles, or workflow changes
- Check affected docs — map changes to relevant pages in
docs/:
- New/changed user features →
docs/guider/ (deltaker, moteleder, sekretar, projektor)
- New concepts or domain model changes →
docs/konsepter.mdx
- Getting started flow changes →
docs/kom-i-gang.mdx
- Architecture or setup changes →
docs/utvikling/ (oppsett, arkitektur, bidra)
- Update docs if needed, following the Mintlify writing standards below
- Commit doc changes before creating the release tag
- Rehearse new migrations against the schema production runs before deploying. CI tests every migration against the final schema only, so a data migration that calls app models can pass CI and still fail on production: the models read columns that later migrations add. Load production’s
db/schema.rb (from the deployed commit) into a scratch database, add rows shaped like production’s, and run db:migrate with the release code. lib/migration_rehearsal.rb does this, one MigrationRehearsal::Scenario per deploy that needs it: bin/rails migration_rehearsal:meeting_lifecycle for the VOT-432 – VOT-437 migrations and bin/rails "migration_rehearsal:projector_screens[<ref>]" for the VOT-444 projector-screen layout migrations (<ref> = the commit production runs, default 25ac00b = v0.35.0; it runs every pending migration, so it covers the lifecycle migrations too when they ship in the same deploy). Both exit 1 on a failed check. Add a scenario for the next deploy whose migrations transform data. Read <ref> off production, never off the last tag: the running container is named voteringsapp-web-<sha> (kamal app version prints the same commit), and production can run an untagged deploy (it ran e0211d9, schema 20261006210000, from 2026-10-06 until v0.36.0)
- Tag: an annotated tag
vX.Y.Z on the release commit, then git push origin main and the tag
- Back up, then deploy outside a live meeting, from a clean checkout of the tag:
kamal deploy (secrets from Doppler prd through .kamal/secrets). While production has no Litestream replica, first copy its four SQLite databases with sqlite3 .backup inside the web container to storage/predeploy-<timestamp>/ and off the host. Afterwards check /up, the schema version (bin/rails runner in the new container) and the app logs
- Publish the GitHub release (
gh release create vX.Y.Z) with the release notes once production answers. Leave the included Linear issues In Review; the owner closes them
Mintlify documentation site
The docs/ directory contains a Mintlify documentation site with two tabs:
- Brukerveiledning (Norwegian) — User-facing guides: getting started, concepts, role guides (deltaker, møteleder, sekretær, projektor)
- Development (English) — Developer docs: setup, architecture, contributing
Configuration: docs/docs.json. Pages are MDX files. Mintlify components used: <Steps>, <Step>, <Info>, <Warning>, <Tip>, <Note>, <Card>, <CardGroup>, <Frame>. Mintlify parses every page as MDX, so a placeholder in prose goes in backticks (<page title>, never bare); mint broken-links, run in docs/, stops at a page it cannot parse and lists every broken internal link.
Guide images live in docs/images/<guide>/ (today docs/images/projektor/, 1280×720 PNGs) and are committed with the guide. A page references them site-absolute (/images/projektor/<name>.png) inside a <Frame> with a caption. They are captured by an opt-in system test, never by hand: when a release changes a screen the guide shows, regenerate them and commit the result with the doc changes:
Writing standards
- Norwegian pages: use Norwegian UI terms, keep sentences short, use
du-form
- English pages: standard technical writing
- No placeholder content or Lorem ipsum
Last modified on October 13, 2026