Files
redefined-designs/docker-compose.qa.yml
T
bermudalambandClaude Opus 5 2a20c0e05b
SonarQube Analysis / sonarqube (pull_request) Successful in 2m34s
Tests / backend-unit (pull_request) Successful in 36s
Tests / backend-integration (pull_request) Failing after 3h3m42s
Tests / frontend-e2e (pull_request) Failing after 7m32s
ci: manual workflow to build and publish the QA image (#25)
Adds a workflow_dispatch job that builds a chosen ref, pushes it to the
Gitea container registry as :qa plus a commit-sha tag, and emails when it
is ready. It deliberately does not restart the QA stack — redeploying
stays a human action in Portainer.

The build runs against a Docker-in-Docker service rather than the NAS's
Docker socket. Mounting the host socket into the runner would give every
workflow on every branch root-equivalent control of the NAS, production
included; pushing to a registry means the image does not need to survive
in the build daemon.

The QA stack now pulls that image instead of requiring a local build. The
previous arrangement meant the image existed only if someone remembered
to build it, which produced two confusing failures already: a Docker Hub
"pull access denied" when the tag was missing, and a silent stale-image
deploy when the build had not been rerun.

Two runner capabilities cannot be verified from here — privileged service
containers for dind, and a docker CLI in the runner image. The workflow
checks both and fails with an explanation rather than a connection
refused, and validates all five required secrets and variables up front
rather than part-way through a build.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-17 19:10:04 -05:00

95 lines
4.2 KiB
YAML

# QA stack — a disposable copy of the app for reviewing merged-but-undeployed
# changes online. See issue #25.
#
# Deployed as its own Portainer stack, separate from production. Every value
# that could collide with production has been changed: container names, host
# port, volume paths, database name, and image tag. Do not copy a path or port
# back from the production stack — a shared Postgres data directory would mean
# QA writing into production's database files.
#
# Name the Portainer stack `redefined-designs-qa`, NOT `redefined-designs`.
# The stack name becomes the compose project name. Reusing production's name
# would make compose treat this as the same project and reconcile the two
# against each other — it would happily remove the production containers
# because they are not declared in this file.
#
# Required stack environment variable:
# QA_DB_PASSWORD — deliberately not named DB_PASSWORD, so pasting the
# production stack's variables here does nothing silently.
#
# The image comes from the Gitea container registry, built by the manual
# "Build QA Image" workflow. Redeploy this stack with Portainer's
# "Pull latest image" toggle ON, or it will keep running the image it already
# has and the redeploy will appear to do nothing.
#
# Portainer needs registry credentials for gitea.bermudalamb.synology.me once
# (Registries > Add registry, custom, with a Gitea token that has read:package).
#
# This replaced a locally-built `redefined-designs:qa` with `pull_policy: never`.
# That arrangement meant the image existed only if someone had remembered to
# build it, which produced two confusing deploy failures: a "pull access denied"
# from Docker Hub when the tag was missing entirely, and a silent stale-image
# deploy when the build had not been rerun.
services:
redefined-designs-qa:
image: gitea.bermudalamb.synology.me/bermudalamb/redefined-designs:qa
container_name: redefined-designs-qa-syn
environment:
- TZ=America/Chicago
- PORT=3000
- PGHOST=redefined-designs-qa-db-syn
- PGPORT=5432
- PGUSER=redefined_qa
- PGPASSWORD=${QA_DB_PASSWORD}
- PGDATABASE=redefined_qa
# No PayPal credentials at all. DEMO_MODE lets the full cart and checkout
# flow run without them, so QA can exercise the whole purchase path with
# no way to reach live PayPal. Never set PAYPAL_ENV=live here. To test a
# real PayPal integration change, add sandbox credentials and set
# PAYPAL_ENV=sandbox — never the live ones.
- DEMO_MODE=true
# No SMTP configuration either. The mailer degrades gracefully when
# unconfigured: it logs a warning and skips sending. That is the desired
# behaviour here — a QA run must not be able to email real customers if
# a fixture ever contains a real address.
- SITE_CURRENCY=USD
- RESERVATION_MINUTES=15
- PUBLIC_URL=https://qa-redefined-designs.bermudalamb.synology.me
volumes:
# Separate uploads directory. Sharing production's would let a QA run
# write into, and a QA teardown delete, real product images.
- /volume1/configs/redefined-designs-qa/uploads:/app/uploads
ports:
# 32751, not production's 32750.
- 32751:3000
depends_on:
redefined-designs-qa-db-syn:
condition: service_healthy
# Not `unless-stopped`: QA is meant to be up only while a review is
# happening. `unless-stopped` would silently bring it back after every NAS
# reboot and leave it running indefinitely.
restart: "no"
redefined-designs-qa-db-syn:
image: postgres:16
container_name: redefined-designs-qa-db-syn
environment:
- POSTGRES_USER=redefined_qa
- POSTGRES_PASSWORD=${QA_DB_PASSWORD}
- POSTGRES_DB=redefined_qa
- PGDATA=/var/lib/postgresql/data/pgdata
volumes:
# Distinct data directory from production's
# /volume1/configs/redefined-designs/postgres. This is the single most
# important difference in this file.
- /volume1/configs/redefined-designs-qa/postgres:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U redefined_qa -d redefined_qa"]
interval: 10s
timeout: 5s
retries: 10
restart: "no"