feat(qa): add the QA environment stack definition (#25)
A disposable stack for reviewing merged-but-undeployed changes online, running alongside production on the same NAS. Every value that could collide with production is changed: container names, host port (32751), volume paths, database name, and image tag. The Postgres data directory is the critical one — sharing production's would mean QA writing into production's database files. QA deliberately differs from production in three ways. DEMO_MODE=true with no PayPal credentials, so the full cart and checkout path is exercisable with no route to live PayPal. No SMTP configuration, so a QA run cannot email anyone; the mailer already degrades gracefully when unset. And restart: "no", so a NAS reboot does not quietly bring QA back up and leave it running. The stack must be named redefined-designs-qa in Portainer: the stack name becomes the compose project name, and reusing production's would make compose reconcile the two against each other and remove the production containers. README covers the one-time NAS directory setup, the review workflow, and how to reset QA data. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -162,4 +162,64 @@ Gitea Actions runs two workflows on every push to `main` and on pull requests:
|
||||
|
||||
Production runs as a single Docker image (multi-stage build — the frontend is built to static files and served directly by the backend), deployed via Portainer behind Nginx Proxy Manager, with authentik forward-auth gating `/admin`. That infrastructure is homelab-specific and documented separately outside this repo.
|
||||
|
||||
The container applies pending migrations before starting the server, so deployed code can never be ahead of the database schema. A failed migration stops the container rather than letting it serve against a schema it doesn't match — check `docker logs` on the app container if it doesn't come up.
|
||||
The container applies pending migrations before starting the server, so deployed code can never be ahead of the database schema. A failed migration stops the container rather than letting it serve against a schema it doesn't match — check `docker logs` on the app container if it doesn't come up.
|
||||
|
||||
## QA environment
|
||||
|
||||
`docker-compose.qa.yml` defines a disposable QA stack for reviewing merged-but-undeployed changes online. It runs alongside production on the same NAS with its own containers, database, volumes, and host port, and is started only when a review is needed.
|
||||
|
||||
It differs from production deliberately: `DEMO_MODE=true` with no PayPal credentials (so checkout is exercisable but cannot reach live PayPal), no SMTP configuration (so it cannot email anyone), and `restart: "no"` (so a NAS reboot doesn't quietly bring it back up).
|
||||
|
||||
### One-time setup on the NAS
|
||||
|
||||
Create the directory structure. These paths are deliberately **not** under `/volume1/configs/redefined-designs` — sharing production's Postgres directory would mean QA writing into production's database files.
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /volume1/configs/redefined-designs-qa/postgres
|
||||
sudo mkdir -p /volume1/configs/redefined-designs-qa/uploads
|
||||
|
||||
# The official postgres image runs as uid/gid 999. Without this the DB
|
||||
# container exits immediately with a data-directory permissions error.
|
||||
sudo chown -R 999:999 /volume1/configs/redefined-designs-qa/postgres
|
||||
sudo chmod 700 /volume1/configs/redefined-designs-qa/postgres
|
||||
|
||||
# Uploads are written by the app container, which runs as root.
|
||||
sudo chown -R root:root /volume1/configs/redefined-designs-qa/uploads
|
||||
sudo chmod 755 /volume1/configs/redefined-designs-qa/uploads
|
||||
|
||||
# Confirm the two environments are separate before going further.
|
||||
ls -la /volume1/configs/redefined-designs-qa/
|
||||
ls -la /volume1/configs/redefined-designs/
|
||||
```
|
||||
|
||||
Then, in Portainer, create a stack **named `redefined-designs-qa`** from `docker-compose.qa.yml`, with one environment variable `QA_DB_PASSWORD`. The stack name matters: it becomes the compose project name, and reusing production's name would make compose reconcile the two stacks against each other and remove the production containers.
|
||||
|
||||
Finally, add an Nginx Proxy Manager host for `qa-redefined-designs` pointing at the NAS on port `32751`, with authentik forward-auth on `location /` — the whole site, not just `/admin`, so nothing unreleased is publicly reachable.
|
||||
|
||||
### Reviewing a change
|
||||
|
||||
```bash
|
||||
cd /volume1/docker/redefined-designs
|
||||
gitc() { sudo docker run --rm -it -v /volume1/docker/redefined-designs:/repo -v ~/.gitconfig-docker/.gitconfig:/root/.gitconfig -w /repo alpine/git "$@"; }
|
||||
gitc pull origin main
|
||||
gitc log --oneline -3
|
||||
|
||||
sudo docker build --no-cache -t redefined-designs:qa /volume1/docker/redefined-designs
|
||||
# start the redefined-designs-qa stack in Portainer
|
||||
|
||||
# Migrations run as the container starts — confirm before reviewing.
|
||||
sudo docker logs redefined-designs-qa-syn | head -30
|
||||
```
|
||||
|
||||
Stop the stack in Portainer when finished.
|
||||
|
||||
### Resetting QA data
|
||||
|
||||
QA data is disposable. To start from an empty database, stop the stack first, then:
|
||||
|
||||
```bash
|
||||
# Check the path before running this. It must contain -qa.
|
||||
sudo rm -rf /volume1/configs/redefined-designs-qa/postgres/pgdata
|
||||
```
|
||||
|
||||
Restarting the stack recreates the database and re-runs every migration from scratch.
|
||||
Reference in New Issue
Block a user