Upgrading an instance
One version covers the whole project — the server, the admin UI and the website — so an upgrade moves all of them together. How it is done depends on how the instance was installed; the rule is the same everywhere: back up, switch to the new version, restart, check.
Importante
The server applies the database migrations of the new version when it starts. After that the
previous version is not expected to work against the database: the only supported way back is
the backup taken before the upgrade (operations.md).
Update notice
When a newer stable release exists, the admin UI says so: a notice at the top of every admin page names the available version and the running one, and the version in the footer carries the same mark. That is all it does — the instance never updates itself. An upgrade runs database migrations and binds the database to the new version, so it stays a deliberate step of the operator, with a backup taken first — the rest of this page.
How it works:
- Where the version comes from. The server asks GitHub for the latest release of the project
(
api.github.com/repos/Fristail27/vocab-bloom-hub/releases/latest). GitHub's "latest" skips drafts and prereleases, and versions are compared as semantic versions:1.10.0is newer than1.9.0, and an instance on1.1.0-beta.1is not offered1.0.0. - How often. A few times a day: the answer is kept for six hours, a failure for half an hour. No page view triggers a request of its own. When GitHub does not answer — no network, a rate limit — the result is "unknown" and nothing is shown; the server logs one warning per period.
- Who sees it. The signed-in admin only (
GET /api/settings/update-checkis behind the admin guard). Visitors of the website and of/api/v1learn nothing about the version's age. - What is sent. One anonymous
GETwith aUser-Agentofvocab-bloom-hub/<version>. Nothing about the instance or its data; GitHub sees the address the request comes from, as with any request. - Turning it off.
UPDATE_CHECK=false(environment.md): no outgoing request at all, no notice. The startup log names the setting. - The datasets have a notice of their own. The same switch covers the check for a newer file
of a source — Wiktionary, the Open English WordNet — shown on the card of the dataset
(
datasets.md).
Closing the notice hides it for that release in this browser; the next release shows it again. The two links of the notice lead to the release notes on GitHub and to this page.
Before you upgrade
-
Read the release notes — the changelog entry of every version between yours and the new one. It names the migrations a release ships and the settings that changed (
v1.0.0, for one, moved the default ports of docker compose). -
Know what you run. The admin footer shows the version; so does
GET /api/health({"status":"ok","version":"1.0.0"}). -
Back up the database. For the bundled Postgres of docker compose:
docker compose exec -T postgres pg_dump -U vocab vocab_bloom | gzip > backup-$(date +%F).sql.gzvocab/vocab_bloomarePOSTGRES_USER/POSTGRES_DBof.env. Any other database, and restoring:database.md.
Docker: the published images
The installation of the quick start: images pulled from
GHCR, the version picked by VBH_TAG in .env.
# .env: VBH_TAG=1.1.0
docker compose pull
docker compose up -d
up -d recreates only the services whose image changed; the database and its volume are not
touched. What VBH_TAG may hold:
VBH_TAG | What an upgrade is |
|---|---|
1.1.0 | Edit the line, then pull and up -d — nothing moves until you say so |
1.1 or 1 | pull and up -d fetch the newest patch (or minor) release of that line |
latest | The newest stable release, whatever its number — for trying things out |
main | The development build of every merge; may carry migrations of unreleased code |
Nota
With the observability overlay, or any second compose file, pass the same -f files to pull
and up -d as at the first start — or name them once in .env:
COMPOSE_FILE=docker-compose.yml:docker-compose.observability.yml
(deployment/docker.md).
Docker: built from a checkout
An instance built on the server with docker-compose.build.yml — the way to run the website
under a hostname of your own (deployment/docker.md).
git pull --ff-only # or: git fetch --tags && git checkout v1.1.0
docker compose -f docker-compose.yml -f docker-compose.build.yml build
docker compose -f docker-compose.yml -f docker-compose.build.yml up -d
docker image prune -f # the images of the previous build
The old containers keep serving while the new images build; the switch itself takes seconds.
A change to the documentation only rebuilds the website: build site, then up -d site. The
same steps with the backup and the checks around them, as an update.sh:
deployment/vps.md.
Without Docker
git pull --ff-only # or a release tag
yarn install --immutable
yarn build # the server and the admin UI
yarn site:build # the website, when you run it
# restart the processes: systemctl restart …, pm2 reload …
The admin UI and the website inline their NEXT_PUBLIC_* values when they are built, so the
rebuild is part of every upgrade. Process managers, probes and a restart without dropped
requests: deployment/README.md.
After the upgrade
curl -s localhost:3240/api/ready # {"status":"ok"}: the migrations ran, the database answers
curl -s localhost:3240/api/health # "version" is the new one
(3010 instead of 3240 without Docker.) A 503 on /api/ready that does not go away means
the server could not migrate or reach the database — docker compose logs server says which.
The update notice disappears by itself: it compares the running version on every request.
Rolling back
Restore the backup taken before the upgrade and start the previous version — VBH_TAG back to
the old number, or git checkout of the old tag and a rebuild. A release without migrations
rolls back by starting the previous build alone. Why a plain downgrade is not enough, and what
a failed migration leaves behind: operations.md.
Upgrading to a version with datasets
The first version that keeps several datasets (datasets.md) migrates the
database by itself, like any other, and changes nothing a reader can see:
- the dictionary tables stay where they are, in
public, and become the datasetdefault— the active one. Nothing is copied, the migration takes a moment whatever the size; - the registry (
datasets) is created with that one row: the project's dataset, CC BY 4.0, the version the instance had recorded; - the public API gains fields and loses none:
sourceon a word,dataset,sourceandattribution_urlin/api/v1/meta. The SDKs of 1.0 read the answers of the new server, the new SDKs read the answers of a 1.0 server.
Rolling back is the usual restore of the backup taken before the upgrade. An instance that already holds other datasets cannot be served by a version that does not know them: its tables are in schemas the old code never looks into.
Upgrading to a version with the history of edits
The first version that keeps a history of edits
(datasets.md) migrates every dataset
by itself:
- the table
en_changesis created in the schema of every dataset, empty: a dataset is taken to be what its source published, and the history holds what is changed from here on. The entries edited before keep theiruser_modifiedflag — they are kept through an update as they were — and are not shown as modified; - the public API gains fields and a route, and loses none:
modifiedon a word and on every part of one,license_textandmodified_entriesin/api/v1/meta,GET /api/v1/words/{word}/history,author_nameandauthor_consentof a suggestion. The SDKs of earlier versions read the answers of the new server; - the edits of the dictionary leave the audit journal: from this version on they are
written to the history of the dataset only. The rows the journal already holds stay on the
Events tab of the History page until
AUDIT_RETENTION_DAYSremoves them; a tool that read word edits fromGET /api/en/auditreads them fromGET /api/en/changesnow; - a dataset of a public source takes nothing marked as generated by a model any more
(
400 generated_not_allowed).
Upgrading to a version that reads every dataset
The version that reads a headword from every dataset at once
(datasets.md) needs no migration:
- the public API gains two routes and loses none:
GET /api/v1/words/{word}/datasetsandGET /api/v1/words/{word}/datasets/{dataset}/history. Every other route answers what it answered, from the active dataset; - an instance that holds several datasets opens up to four more database connections per
dataset that is not the active one, once such a read arrives — count them against the
connection limit of a managed Postgres, next to
DB_POOL_SIZE; - the settings gain a field the server writes,
dataset_removed_at: when a dataset was last deleted. It dates the answers of the new routes and is not meant to be edited.
Upgrading to a version that reads the versions from the files
The version that records a dataset of a public source by what its file says
(datasets.md) needs no migration:
- a dataset that is installed keeps the version it has — the day it was installed. Install it again from the file of its source, the one you have or a newer one, to record the version of the file; until then the card of a WordNet dataset says that its edition is not known and gives no notice of a newer one, and the one of Wiktionary counts its 30 days from the day of the installation;
- with
UPDATE_CHECKon, an instance that holds Wiktionary or the Open English WordNet asks kaikki.org and the GitHub API once a day. An instance that must make no outgoing request hasUPDATE_CHECK=falsealready, and asks nothing; dataset_versionof/api/v1/metachanges for such a dataset at its next installation, from a day to a day or an edition. It was never promised a format;- the import page offers the update of the published dataset for the dataset of the project only. It used to offer it for a dataset of another source too, and the server refused.
The dictionary is updated separately
A new version of the code does not change the dictionary data, and a new dataset revision does
not need a new version of the code. The import page of the admin UI says when a newer dataset
exists; what an update replaces and what it keeps:
operations.md.