diff --git a/.gitea/workflows/qa-build.yml b/.gitea/workflows/qa-build.yml
deleted file mode 100644
index 690fa1c..0000000
--- a/.gitea/workflows/qa-build.yml
+++ /dev/null
@@ -1,175 +0,0 @@
-name: Build QA Image
-
-# Manual only. Builds the QA image from a chosen ref, pushes it to the Gitea
-# container registry, and emails when it is ready to redeploy.
-#
-# It deliberately does NOT restart the QA stack. Redeploying stays a human
-# action in Portainer, so nothing changes what is running without someone
-# deciding it should.
-on:
- workflow_dispatch:
- inputs:
- ref:
- description: Branch, tag, or commit to build
- required: true
- default: main
-
-env:
- IMAGE: gitea.bermudalamb.synology.me/bermudalamb/redefined-designs
- # The build runs against a Docker-in-Docker service rather than the host
- # daemon. Mounting the host socket into the runner would give every workflow
- # on every branch root-equivalent control of the NAS, production included.
- # Because the image is pushed to a registry, it does not need to survive in
- # the build daemon.
- DOCKER_HOST: tcp://docker:2375
-
-jobs:
- build:
- runs-on: ubuntu-latest
-
- services:
- docker:
- image: docker:27-dind
- options: --privileged
- env:
- DOCKER_TLS_CERTDIR: ""
-
- steps:
- - name: Check required configuration
- run: |
- missing=""
- [ -n "${{ secrets.REGISTRY_TOKEN }}" ] || missing="$missing REGISTRY_TOKEN"
- [ -n "${{ secrets.BREVO_API_KEY }}" ] || missing="$missing BREVO_API_KEY"
- missingVars=""
- [ -n "${{ vars.REGISTRY_USER }}" ] || missing="$missing REGISTRY_USER"
- [ -n "${{ vars.QA_NOTIFY_TO }}" ] || missing="$missing QA_NOTIFY_TO"
- [ -n "${{ vars.QA_NOTIFY_FROM }}" ] || missing="$missing QA_NOTIFY_FROM"
- if [ -n "$missing" || -n "$missingVars" ]; then
- if [ -n "$missing" ]; then
- echo "::error::Missing configuration secrets:$missing"
- echo "Secrets go in Settings > Actions > Secrets"
- fi
- if [ -n "$missingVars" ]; then
- echo "::error::Missing configuration variables:$missingVars"
- echo "Variables go in Settings > Actions > Variables."
- fi
- exit 1
- fi
- echo "All required secrets and variables are present."
-
- - name: Checkout ${{ inputs.ref }}
- uses: actions/checkout@v4
- with:
- ref: ${{ inputs.ref }}
- fetch-depth: 0
-
- - name: Ensure a docker CLI is available
- run: |
- if command -v docker >/dev/null 2>&1; then
- echo "docker CLI already present: $(docker --version)"
- exit 0
- fi
- echo "docker CLI missing from the runner image; installing the static binary."
- curl -fsSL https://download.docker.com/linux/static/stable/x86_64/docker-27.3.1.tgz -o /tmp/docker.tgz
- tar -xzf /tmp/docker.tgz -C /tmp
- install -m 0755 /tmp/docker/docker /usr/local/bin/docker
- docker --version
-
- - name: Wait for the build daemon
- run: |
- # dind needs a privileged service container, which is a runner-wide
- # setting this workflow cannot check in advance. The NAS is also slow
- # to start one, so allow well over the observed time before giving up.
- for i in $(seq 1 90); do
- if docker info >/dev/null 2>&1; then
- echo "Build daemon reachable after ${i}s."
- exit 0
- fi
- sleep 1
- done
-
- echo "::error::No Docker daemon at $DOCKER_HOST after 90s."
- echo ""
- # These two cases look identical from the failing step but have
- # completely different fixes, so name which one it is.
- if getent hosts docker >/dev/null 2>&1; then
- echo "The 'docker' service host resolves, so the container exists but"
- echo "dockerd is not accepting connections on 2375. Check that"
- echo "DOCKER_TLS_CERTDIR is empty, so dind serves plain TCP rather"
- echo "than TLS on 2376."
- else
- echo "The 'docker' service host does not resolve, so the service"
- echo "container never started. This is what act_runner does when it"
- echo "refuses a privileged container: it allocates an ID, creation"
- echo "fails, and the job continues with nothing listening."
- echo ""
- echo "Set 'container.privileged: true' in the act_runner config.yaml"
- echo "and restart the runner. Check the runner's own logs to confirm."
- fi
- exit 1
-
- - name: Record what is being built
- id: meta
- run: |
- echo "sha=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
- echo "full_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
- {
- echo "subject<
To deploy it: open the redefined-designs-qa stack in Portainer and redeploy with Pull latest image enabled.
Migrations run automatically as the container starts — check docker logs redefined-designs-qa-syn shows the migration output before listening on 3000, and that it appears only once.