Uniform stock management for healthcare linen rooms: the coordinator app, the phone counter and the staff app, for your own server. Built from 794bab5 on 2026-09-16. Licensed under the Functional Source License (FSL-1.1-ALv2).
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
---
|
||||
title: Update to a new release
|
||||
section: selfhost
|
||||
order: 3
|
||||
summary: Back up, fetch the release, rebuild, and let the migration run before the new app starts. Why a plain git pull does not work.
|
||||
role: Self-hosting admin
|
||||
keywords: update, upgrade, release, new version, git pull, fetch, reset, rebuild, migrations, schema, changelog, version
|
||||
---
|
||||
|
||||
## How releases are published
|
||||
|
||||
Releases go out about once a week. Each one is a tag named after the date it was cut, such as `v2026.09.17`, with `.2` added for a second release that day. Every release is listed with its notes on the repository's Releases page, and the same notes are in `CHANGELOG.md`. To hear about new ones on GitHub, choose Watch, then Custom, then Releases.
|
||||
|
||||
A release is one commit with no history behind it. It is exported from ThreadCount's own code with the parts that belong only to threadcount.tech removed, and it must type-check, build with `EDITION=community` and pass a smoke test before it is tagged. `main` points at the newest build. Every tag stays downloadable after `main` moves on, which is what makes going back possible.
|
||||
|
||||
The tag and the source commit are written to the `COMMUNITY_VERSION` file in the checkout:
|
||||
|
||||
```
|
||||
community v2026.09.17 b36d739
|
||||
```
|
||||
|
||||
A running server reports that line as `version` at `/api/app-info`.
|
||||
|
||||
## Back up first
|
||||
|
||||
Before every update, take a database dump and a copy of the photos, as in [backups](/docs/selfhost/backups):
|
||||
|
||||
```sh
|
||||
docker/backup.sh /srv/backups/threadcount
|
||||
```
|
||||
|
||||
Migrations only go forwards. `prisma migrate deploy` applies new migrations and has no step that undoes one, so the way back to an older release is to restore the dump you took before updating.
|
||||
|
||||
## Fetch the release
|
||||
|
||||
Because each release replaces the last commit rather than adding to it, `git pull` refuses to merge the two. Fetch the tags, then move your checkout to the newest release:
|
||||
|
||||
```sh
|
||||
cd /srv/threadcount
|
||||
git fetch --tags --force origin
|
||||
git reset --hard "$(git tag --sort=-v:refname | head -1)"
|
||||
cat COMMUNITY_VERSION
|
||||
```
|
||||
|
||||
To move to a particular release instead, name its tag: `git reset --hard v2026.09.17`.
|
||||
|
||||
`.env` is ignored by git, so `git reset --hard` leaves it alone.
|
||||
|
||||
> **Careful** `git reset --hard` throws away any change you made to a file in the repository, `docker-compose.yml` included. Keep local settings in `.env`, or copy your changes somewhere before you reset.
|
||||
|
||||
## Rebuild and start
|
||||
|
||||
```sh
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
What happens, in order:
|
||||
|
||||
1. **The images are rebuilt.** The build takes `NEXT_PUBLIC_SITE_URL` and `NEXT_PUBLIC_TURNSTILE_SITEKEY` from `.env` again.
|
||||
2. **`db` is checked.** Compose waits until Postgres answers `pg_isready`.
|
||||
3. **`migrate` runs.** It runs `npx prisma migrate deploy` against the bundled database and applies any migration the database does not have yet.
|
||||
4. **`app` starts.** Compose starts the new app only if `migrate` exited successfully.
|
||||
|
||||
If a migration fails, `app` is not started. Read what went wrong with:
|
||||
|
||||
```sh
|
||||
docker compose logs migrate
|
||||
```
|
||||
|
||||
Then check the app is healthy:
|
||||
|
||||
```sh
|
||||
docker compose ps
|
||||
curl -fsS https://uniforms.example.health/api/health
|
||||
```
|
||||
|
||||
## Go back to an older release
|
||||
|
||||
Migrations only go forwards, so going back needs the database dump you took before updating.
|
||||
|
||||
1. **Stop the app.** Run `docker compose down`.
|
||||
2. **Restore the dump.** Follow [backups](/docs/selfhost/backups).
|
||||
3. **Move to the older tag.** Run `git reset --hard v2026.09.17`, naming the release you were on.
|
||||
4. **Rebuild.** Run `docker compose up -d --build`.
|
||||
|
||||
## What changed
|
||||
|
||||
Each release's notes are on the repository's Releases page and in `CHANGELOG.md` in your checkout, newest first. They describe the Community edition only.
|
||||
|
||||
## Phones after an update
|
||||
|
||||
The Android apps ask your server at `/api/app-info` for the oldest app version it still works with, given in `minApp`. A phone running an older app is told to update rather than failing. Phones using `/m` or `/my` in a browser get the new version the next time the page loads.
|
||||
Reference in New Issue
Block a user