Files
nuzlocke-tracker/DEPLOYMENT.md
Julian Tabel 66bd1a421f Update deployment docs, complete Deployment Strategy epic
Rewrite DEPLOYMENT.md to reflect current state (CI/CD, backups, merge
strategy). Expand CI paths-ignore to skip docs, license, gitignore,
and deploy workflow changes. Add merge strategy to CLAUDE.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 12:38:34 +01:00

5.3 KiB

Deployment

This document describes the deployment architecture and workflows for the nuzlocke-tracker.

Architecture Overview

Component Dev (Laptop/PC) Production (Unraid)
API docker-compose.yml (hot reload) docker-compose.prod.yml (built image)
Frontend docker-compose.yml (Vite dev server) docker-compose.prod.yml (nginx, static build)
Database PostgreSQL 16 (Docker volume) PostgreSQL 16 (bind mount)
Container Registry Gitea (user-level packages)
Reverse Proxy Nginx Proxy Manager
CI/CD Gitea Actions

Services

  • Gitea — self-hosted Git server, container registry, and CI/CD runner. Accessible at gitea.nerdboden.de via SSL.
  • Nginx Proxy Manager — reverse proxy with SSL termination for all services on the Unraid server.

Branching Strategy

Branch Purpose Merge strategy
main Always production-ready. Deploy workflow builds from here. Merge commit from develop
develop Integration branch for day-to-day work. CI runs on push. Squash merge from feature/*
feature/* Short-lived branches off develop for individual features/fixes.

Workflow

  1. Create feature/xyz from develop
  2. Work on the feature, commit, squash merge into develop
  3. CI runs automatically on develop (lint checks)
  4. When ready to deploy: merge develop into main (merge commit)
  5. Trigger the deploy workflow via workflow_dispatch in Gitea Actions

CI/CD (Gitea Actions)

The project uses two Gitea Actions workflows (GitHub Actions-compatible syntax):

CI (.github/workflows/ci.yml)

Triggers: Push to develop, PRs targeting develop (skips bean-only changes)

Jobs:

  • backend-lintruff check + ruff format --check
  • frontend-linteslint + tsc -b

Deploy (.github/workflows/deploy.yml)

Triggers: Manual via workflow_dispatch (must be on main)

Steps:

  1. Login to Gitea container registry
  2. Build Docker images (linux/amd64) for API and frontend
  3. Push images to the Gitea registry
  4. SCP compose file and backup script to Unraid
  5. SSH into Unraid and run docker compose pull && docker compose up -d

Secrets (configured in Gitea repo settings)

Secret Purpose
REGISTRY_USERNAME Gitea username for pushing images
REGISTRY_PASSWORD Gitea access token (read:package + write:package scopes)
DEPLOY_SSH_KEY SSH private key for root@192.168.1.10

Runner

An act_runner container runs on Unraid with the Docker socket mounted, registered with the Gitea instance.

Manual Deployment

The ./deploy.sh script can also be used to deploy from the dev machine:

# Ensure you're on main with latest changes
git checkout main
./deploy.sh

The script:

  1. Checks you're on main with no uncommitted changes
  2. Builds Docker images (podman or docker, linux/amd64)
  3. Pushes to the Gitea container registry
  4. SCPs docker-compose.prod.yml and backup.sh to Unraid
  5. Generates .env with a random POSTGRES_PASSWORD if missing
  6. Pulls images and restarts containers on Unraid via SSH

Container Registry

Images are hosted on Gitea's built-in container registry as user-level packages:

gitea.nerdboden.de/thefurya/nuzlocke-tracker-api:latest
gitea.nerdboden.de/thefurya/nuzlocke-tracker-frontend:latest

Authentication

  1. Create a Gitea access token at Settings > Applications with read:package and write:package scopes.
  2. Log in: docker login gitea.nerdboden.de (username + token as password).

Production Environment

File layout on Unraid

/mnt/user/appdata/nuzlocke-tracker/
├── docker-compose.yml    # production compose (synced from repo)
├── .env                  # POSTGRES_PASSWORD (auto-generated)
├── backup.sh             # database backup script (synced from repo)
├── backups/              # pg_dump backups (daily, 7-day retention)
│   └── cron.log
└── data/
    └── postgres/         # PostgreSQL data (bind mount)

Environment variables

The .env file is auto-generated on first deploy with a random POSTGRES_PASSWORD. The compose file references it for both the database and API connection string.

Database

PostgreSQL 16 with data persisted via bind mount at ./data/postgres/.

  • Migrations run automatically on API container startup (alembic upgrade head)
  • Daily backups via pg_dump scheduled through the Unraid User Scripts plugin (03:00, 7-day retention)

Backup

Backups are created by backup.sh and stored in /mnt/user/appdata/nuzlocke-tracker/backups/. The script is scheduled via the Unraid User Scripts plugin.

Restore

cd /mnt/user/appdata/nuzlocke-tracker
gunzip -c backups/nuzlocke-YYYYMMDD-HHMMSS.sql.gz | \
  docker compose exec -T db psql -U postgres nuzlocke

Rollback

Currently images are tagged as latest only. To roll back:

  1. Revert the merge commit on main
  2. Trigger the deploy workflow (or run ./deploy.sh) to rebuild and push

For more granular rollback, consider adding commit-hash tags to images in the future.

Nginx Proxy Manager

NPM runs on Unraid and handles SSL termination and routing:

  • nuzlocke.nerdboden.de → nuzlocke-tracker frontend (port 9080)
  • gitea.nerdboden.de → Gitea