Runbook: releasing
Both apps release the same way: green tests, commit, kamal deploy, verify, record.
Deploys build the Docker image locally and push it to Docker Hub; Kamal builds from a
clean git clone of HEAD, so uncommitted changes never ship.
Website (keferboeck.com)
- Verify on dev first: the site runs permanently via launchd on port 3002
(
com.georg.dev.keferboeck); restart withlaunchctl kickstart -k gui/$UID/com.georg.dev.keferboeck. - If articles or pages changed:
node scripts/generate-sitemap.js(also refreshes the AI advisor index) and commit the result. - Commit and push. Then
kamal deployfrom the repo root (~15–20 min; the builder uses the plaindockerdriver on purpose, see incidents). - Verify:
curl -s -o /dev/null -w "%{http_code}" https://keferboeck.com/en-gbplus the pages the release touched, in both locales.
Portal (hub.keferboeck.com)
bundle exec rspec— the full suite must be green; critical paths are contract.- Commit and push.
kamal deploy(~2 min; the entrypoint runsdb:prepare, so migrations apply on boot). - Verify:
https://hub.keferboeck.com/admin/...for the touched screens; watchkamal app logs -fif anything looks off. - New env secrets: add to
.kamal/secrets(reads from git-ignored files) and theenv.secretlist inconfig/deploy.ymlbefore deploying.
GitHub release notes (step by step)
Every verified production deploy ends with a tagged GitHub release, so the release
history lives where the code lives. Each app repo carries bin/release:
- Deploy and verify (steps above). Do not tag an unverified deploy.
- From the repo root run
bin/release. - Tags are CalVer:
v2026.09.11, with.2,.3appended for repeat releases on the same day. An explicit tag can be passed:bin/release v1.4.0. - The notes are generated from every commit subject since the previous tag (commit
messages are written to be readable for exactly this reason), under a
## Changesheading. - Edit on GitHub afterwards if a release deserves prose: highlights first, generated commit list underneath.
- The baseline is
v2026.09.11on each repo (websitekeferboeck-next-react, portalkeferboeck-portal, shopssolidus-demos): a hand-written summary of everything in production at the time tagging began.
Rules: one release per deploy, never batch days together; a rollback gets its own release tagged from the rolled-back SHA with a note saying why; releases are immutable like ADRs — correct with a new one.
Where else a change is recorded
- The ClickUp task is completed with the mandatory fields (problem, Solution, Automated Tests, QA Steps) — the canonical per-change record.
- Client-visible changes additionally get a portal Document (category
release) assigned to the affected company, written for humans. - Architecture-level changes update this knowledge base in the same PR (definition of done).
Rollback
kamal rollback <version> from the app repo (versions are git SHAs; kamal app images
lists what the droplet still holds). Portal migrations are additive by convention, so a
one-version rollback is safe without a schema down-step.