The staging database now runs as qrmaster_test instead of reusing the production name. Container and volume already kept the two apart, but a hand-typed psql session against two databases both called `qrmaster` looks identical on either side - the distinct name is what makes the wrong window obvious before a DELETE lands in it. The base compose file hardcodes `pg_isready -d qrmaster` in the db healthcheck, so the overlay has to override the probe as well. Without it the container stays unhealthy and web never starts, because it waits on service_healthy. Verified against `docker compose config`: staging resolves to qrmaster_test in POSTGRES_DB, DATABASE_URL and the healthcheck, while production still resolves to qrmaster. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
66 lines
2.9 KiB
YAML
66 lines
2.9 KiB
YAML
# Test/staging overlay for testmodul.qrmaster.net.
|
|
#
|
|
# Start with:
|
|
# docker compose -p qrmaster-test --env-file .env.test \
|
|
# -f docker-compose.yml -f docker-compose.test.yml up -d --build
|
|
#
|
|
# The project name is what keeps the data apart: `-p qrmaster-test` gives this stack its own
|
|
# volumes, so its Postgres can never touch the production one.
|
|
|
|
services:
|
|
db:
|
|
container_name: qrmaster-test-db
|
|
# Production already publishes 5435 on the host.
|
|
ports: !reset []
|
|
# The base file hardcodes the database name in the probe. Staging uses its own name so a
|
|
# hand-typed psql session makes it obvious which instance you are on - without this
|
|
# override the probe would check a database that does not exist, the container would stay
|
|
# unhealthy and web (depends_on: service_healthy) would never start.
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U postgres -d qrmaster_test"]
|
|
# Only on the internal network. `db` and `redis` are network aliases assigned per
|
|
# compose project, so leaving them on the shared external network would make `db`
|
|
# resolve to two containers and this stack could reach the production database.
|
|
#
|
|
# `!override` is required: compose MERGES the networks mapping from the base file, so a
|
|
# plain list would leave qrmaster-network attached and reintroduce exactly that bug.
|
|
networks: !override
|
|
- test-internal
|
|
|
|
redis:
|
|
container_name: qrmaster-test-redis
|
|
networks: !override
|
|
- test-internal
|
|
|
|
web:
|
|
container_name: qrmaster-test-web
|
|
# No `prisma migrate deploy` here. The migrations in prisma/migrations stopped in
|
|
# April 2026 and the schema has moved on through manual SQL since, so running them
|
|
# against a fresh database would build a stale schema the app cannot work with.
|
|
# Bring the schema in with `pg_dump --schema-only` from production instead.
|
|
entrypoint: ["node", "server.js"]
|
|
build:
|
|
args:
|
|
# Host-only cookie on staging, so `:-` (empty) is the correct value here.
|
|
COOKIE_DOMAIN: ${COOKIE_DOMAIN:-}
|
|
# These three use `:?` on purpose: an empty value would silently fall back to the
|
|
# production defaults baked into the Dockerfile, and the staging frontend would then
|
|
# talk to production. Better to fail the build with a readable message.
|
|
AUTH_COOKIE_NAME: ${AUTH_COOKIE_NAME:?set AUTH_COOKIE_NAME in .env.test, e.g. userId_test}
|
|
NEXT_PUBLIC_WWW_URL: ${NEXT_PUBLIC_WWW_URL:?set NEXT_PUBLIC_WWW_URL in .env.test to https://testmodul.qrmaster.net}
|
|
NEXT_PUBLIC_APP_URL: ${NEXT_PUBLIC_APP_URL:?set NEXT_PUBLIC_APP_URL in .env.test to https://testmodul.qrmaster.net}
|
|
# Reachable by Caddy over the shared network, everything else stays internal.
|
|
networks:
|
|
- test-internal
|
|
- qrmaster-network
|
|
|
|
adminer:
|
|
container_name: qrmaster-test-adminer
|
|
ports: !reset []
|
|
networks: !override
|
|
- test-internal
|
|
|
|
networks:
|
|
test-internal:
|
|
driver: bridge
|