Skip to content

Upgrading

Verified against v0.21.0 · internal/db/migrate.go, internal/db/migrations/0052_poker_splits.sql, internal/db/migrations/0053_poker_dependencies.sql, internal/db/migrations/0054_poker_estimate_scope.sql, internal/db/migrations/0058_poker_parked_drafts.sql, internal/db/migrations/0059_poker_parent_estimate.sql, internal/poker/splits.go, internal/poker/rounds.go, internal/poker/dependencies.go

Pull the new tag and docker compose up -d. Migrations run automatically at boot.

On Kubernetes it is helm upgrade with the new --version and --reuse-values — the procedure, and the checks that prove the pods actually rolled, are on Kubernetes. Under ArgoCD or Flux there is no --reuse-values and no helm test; see GitOps.

After upgrading a multi-replica install, confirm the replicas are still on different nodes — kubectl get pods -o wide. The chart makes a rollout much less likely to collapse them onto one, but the constraint is a preference rather than a guarantee, and on Kubernetes older than 1.27 the mitigation is absent entirely; see Rollouts.

Rolling back an image is only safe if the newer version didn’t add migrations. If it did, Parley refuses to start and says so, rather than running against a schema it doesn’t understand. Restore from a backup instead.

Upgrading to the release that adds Poker splits

Section titled “Upgrading to the release that adds Poker splits”

Take and restore-check a database backup before the upgrade. The additive split, dependency, estimate-scope, parked-drafts and parent-estimate migrations preserve historical flat stories and ended rooms (the parked-drafts column defaults to false, which is how every existing split already behaves), but additive schema compatibility does not make old writers safe. Older binaries and previously loaded browser pages do not enforce the new identity, round, scope and graph revision contracts.

Setting an estimate on the story that is on the table while its round is hidden now needs endRound: true with the reviewed round identity, in flat rooms as well as splits; a request without them is refused 409 and the round, whose votes would be discarded, is left alone. A browser page loaded before the upgrade therefore cannot set an estimate over a live hidden round until it is reloaded. undo-split likewise needs the children revision map.

Finish existing meetings or pause writes during the rollout. Upgrade every serving replica, confirm its build with /version, and reload participant, facilitator and meeting-client pages before allowing split edits. Do not use splits while an older replica can receive requests. There is no split feature flag or per-space enablement setting; bound initial use operationally to a small set of rooms after all writers have upgraded.

Check one historical flat room and one split room before widening use. In the split room, a previous parent 13 is context; child 3, 5 and blank remain three independent planning units. Verify hidden votes, facilitator-only editing, reconnect, close/reopen and grouped export. Local Blocked by links do not check completion or confirm tracker delivery. Core splitting requires no provider credentials; provider enablement and live capability proof are separate gates.

If checks fail, pause further split writes and retain the new database for investigation. Do not send older writers back to the migrated store. To return to the previous binary, stop every replica and restore its matching pre-upgrade backup using the recovery procedure, including revocation and deletion reconciliation. Writes made after that backup are lost; there is no down migration, child merge-back, or automatic remote rollback.

v0.5.0 puts every space inside an organization. The migrations that do it (0021–0023) are forward-only — there is no down path and no rollback. Take a backup first and check that you can restore it; if the upgrade goes wrong, restoring that backup is the only way back.

If you run one team on one instance, nothing visible changes

Section titled “If you run one team on one instance, nothing visible changes”

The migration creates one org, called default, and puts every existing space and every existing account in it. You do not have to create anything, configure anything, or tell anybody. Concretely:

  • Your links keep working. A /s/{slug} address redirects to the space’s new /o/{org}/s/{slug} home, resolved against the caller’s own memberships. Someone who is not signed in — or a guest holding a signed session link — is served the app exactly as before. A signed-in caller who has no matching membership, or more than one, gets a 404 rather than a redirect: the address names one space and Parley will not guess which org you meant.
  • Signed session links are untouched. They address a session, not a space, and they never carried an org segment.
  • Existing spaces become “unlisted”. This is a change in discoverability only. Nothing about who can open a space or what they see changes: a stranger who opens a link to an existing space still gets its name and whether a room code is set, exactly as they did the day before the upgrade. Being unlisted only means the space is not in the org directory, a screen that did not exist yesterday.
  • Room codes still do the same job. Visibility governs discovery; the room code governs entry, including for members of your org.

New spaces you make after the upgrade are listed in the directory by default, and their owner can unlist them at any time. In open mode every space is unlisted and the directory stays empty.

Read Organizations and claim mapping before you upgrade. It covers creating a second org, pointing it at one of your provider’s groups, and bootstrapping the first admin — and Organizations covers what the person administering an org can then see, which is worth being able to answer before somebody asks.

Upgrading to the release that adds session lifetimes

Section titled “Upgrading to the release that adds session lifetimes”

This release introduces SESSION_MAX_TTL, an absolute cap on how long a session may live measured from the moment it was issued, and nothing renews it. Before it, expiry was purely idle: a token that kept being used never died.

Some people will be signed out by the upgrade. Every existing token whose created_at is older than SESSION_MAX_TTL — 90 days by default — stops resolving at the next request, however recently it was used, and the new hourly sweep deletes the row. On an instance that has been running for more than 90 days that is everyone who has not signed in since. They sign in again; nothing is lost. It is still worth saying so in advance, because to the person it happens to it looks like the upgrade broke their login.

If you would rather not do that in the same change as the version bump, set SESSION_MAX_TTL to something longer than the instance has existed for the first rollout, then lower it once people have been told. Both lifetimes are documented under Configuration.

Parley supports PostgreSQL 13 and newer, with no upper bound — the compose file pins postgres:16-alpine because a compose file has to pin something. Major Postgres upgrades (16 → 17) are not automatic:

  1. pg_dump with the old version
  2. start fresh with the new one
  3. restore

Never just change the tag on an existing volume — the data directory is not readable across major versions.