Upgrading
Upgrades follow the same tag-based flow you used to install, whether you build from source or run the published image.
Back up first
Section titled “Back up first”Two things hold your durable state: the PostgreSQL database (all messages,
teams, and users) and the storage-app volume (uploaded files). The
Meilisearch index is derived data — it is rebuilt from Postgres on boot, so it
needs no backup — and Redis holds only cache, sessions, and transient queued
jobs.
Take a logical database dump (portable across Postgres versions) and an archive of the uploaded files:
# Database — logical dump, gzippeddocker compose -f docker-compose.prod.yml exec -T pgsql \ pg_dump -U "${DB_USERNAME:-laravel}" "${DB_DATABASE:-laravel}" \ | gzip > db-backup-$(date +%F).sql.gz
# Uploaded files — stream a tar out of the running app containerdocker compose -f docker-compose.prod.yml exec -T app \ tar czf - -C /app/storage/app . > storage-app-$(date +%F).tar.gzStore both files off the host. To restore into a freshly created, empty database and a running stack:
# Databasegunzip -c db-backup-YYYY-MM-DD.sql.gz | docker compose -f docker-compose.prod.yml exec -T pgsql \ psql -U "${DB_USERNAME:-laravel}" "${DB_DATABASE:-laravel}"
# Uploaded filesdocker compose -f docker-compose.prod.yml exec -T app \ tar xzf - -C /app/storage/app < storage-app-YYYY-MM-DD.tar.gzBuild-from-source
Section titled “Build-from-source”Check out the newer release tag and rebuild:
git fetch --tagsgit checkout v1.4.0 # the desired release tagdocker compose -f docker-compose.prod.yml downdocker compose -f docker-compose.prod.yml up -d --build# migrations run automatically via the entrypointPublished image
Section titled “Published image”Point APP_IMAGE at the new tag, then pull and restart:
sed -i 's|^APP_IMAGE=.*|APP_IMAGE=ghcr.io/emmpaul/the-desk:1.4.0|' .envdocker compose -f docker-compose.prod.yml pulldocker compose -f docker-compose.prod.yml up -dMigrations run automatically on start — the app container’s entrypoint runs
php artisan migrate --force.
Your data persists
Section titled “Your data persists”Data survives down/up in named volumes:
pgsql-data— the PostgreSQL databasethe-desk-meili-<version>— the Meilisearch index (version-scoped, see below)redis-data— cache, session, and queued jobsstorage-app— uploaded files
Search reindexing
Section titled “Search reindexing”The Meilisearch on-disk format is version-specific — it refuses to boot against a
data directory written by a different version. MEILISEARCH_VERSION pins both
the image tag and the data volume name, so bumping it starts the new Meilisearch
on a fresh volume, and the app rebuilds the index from Postgres on boot
(php artisan search:sync). No manual dump or migration is needed — the search
index is derived data.
The old volume is left behind; prune it once the new version is healthy:
docker volume rm the-desk-meili-<old-version>