From ae1bffeaa0a2c051377cd08cc7d5924f728d610b Mon Sep 17 00:00:00 2001 From: FragginWagon Date: Wed, 9 Sep 2026 16:25:01 -0400 Subject: [PATCH] feat: add tagged deployment rollback --- compose.production.yaml | 3 +++ docs/DEPLOYMENT.md | 25 +++++++++++++++++++++++++ scripts/deploy-production.sh | 13 +++++++++++++ scripts/rollback-production.sh | 8 ++++++++ 4 files changed, 49 insertions(+) create mode 100755 scripts/deploy-production.sh create mode 100755 scripts/rollback-production.sh diff --git a/compose.production.yaml b/compose.production.yaml index 21e561e..b89318d 100644 --- a/compose.production.yaml +++ b/compose.production.yaml @@ -27,6 +27,7 @@ services: retries: 10 api: + image: ${API_IMAGE:-pokemon-inventory-api}:${IMAGE_TAG:-latest} build: context: . dockerfile: Dockerfile.node @@ -50,6 +51,7 @@ services: retries: 5 worker: + image: ${WORKER_IMAGE:-pokemon-inventory-worker}:${IMAGE_TAG:-latest} build: context: . dockerfile: Dockerfile.node @@ -66,6 +68,7 @@ services: condition: service_healthy web: + image: ${WEB_IMAGE:-pokemon-inventory-web}:${IMAGE_TAG:-latest} build: context: . dockerfile: Dockerfile.web diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md index cce543d..5b429a2 100644 --- a/docs/DEPLOYMENT.md +++ b/docs/DEPLOYMENT.md @@ -45,6 +45,31 @@ worker images share the same Node workspace image; the web image builds the Vue application and serves it through Nginx with SPA fallback and internal `/api` proxying. +## Tagged Releases And Rollback + +Use an immutable release tag for every deployment. The production Compose file +uses `IMAGE_TAG` to select matching API, worker, and web images. Deploy with: + +```sh +RELEASE_TAG=2026-09-09-01 ./scripts/deploy-production.sh +``` + +The deploy script builds the three tagged images, starts healthy data services, +applies migrations with the tagged API image, and then switches the application +services. Keep the previous release tag and migration state with the deployment +record. + +Rollback application images with: + +```sh +RELEASE_TAG=2026-09-08-02 ./scripts/rollback-production.sh +``` + +Image rollback is safe only when the previous image understands the current +database schema. If the release included an incompatible schema change, restore +the matching PostgreSQL backup before starting the previous images. Always +verify the API and web health checks after a rollback. + ## Health Checks Production Compose waits for healthy PostgreSQL, Redis, and API services before diff --git a/scripts/deploy-production.sh b/scripts/deploy-production.sh new file mode 100755 index 0000000..438a1b8 --- /dev/null +++ b/scripts/deploy-production.sh @@ -0,0 +1,13 @@ +#!/bin/sh +set -eu + +: "${RELEASE_TAG:?Set RELEASE_TAG to an immutable image tag}" + +compose_args='-f compose.production.yaml' +export IMAGE_TAG="$RELEASE_TAG" + +docker compose $compose_args build api worker web +docker compose $compose_args up -d postgres redis +docker compose $compose_args run --rm api npm run db:migrate +docker compose $compose_args up -d api worker web +docker compose $compose_args ps \ No newline at end of file diff --git a/scripts/rollback-production.sh b/scripts/rollback-production.sh new file mode 100755 index 0000000..cdd4ae7 --- /dev/null +++ b/scripts/rollback-production.sh @@ -0,0 +1,8 @@ +#!/bin/sh +set -eu + +: "${RELEASE_TAG:?Set RELEASE_TAG to the previously deployed immutable image tag}" + +export IMAGE_TAG="$RELEASE_TAG" +docker compose -f compose.production.yaml up -d api worker web +docker compose -f compose.production.yaml ps \ No newline at end of file