Release frontend branding and metadata #3

Merged
TheFurya merged 3 commits from develop into main 2026-02-10 12:55:19 +01:00
6 changed files with 138 additions and 124 deletions
Showing only changes of commit 132dac0a2e - Show all commits

View File

@@ -1,11 +1,11 @@
---
# nuzlocke-tracker-ahza
title: Deployment Strategy
status: in-progress
status: completed
type: epic
priority: normal
created_at: 2026-02-09T14:03:53Z
updated_at: 2026-02-10T08:16:36Z
updated_at: 2026-02-10T11:36:07Z
---
Define and implement a deployment strategy for running the nuzlocke-tracker in production on a local Unraid server while keeping laptop/PC as the development environment.
@@ -47,12 +47,12 @@ Define and implement a deployment strategy for running the nuzlocke-tracker in p
- [x] **Set up branching structure** — create `develop` branch from `main`, establish the `main`/`develop`/`feature/*` workflow
- [x] **Update CLAUDE.md with branching rules** — once the branching structure is in place, add instructions to CLAUDE.md that the branching strategy must be adhered to (always work on feature branches, never commit directly to `main`, merge flow is `feature/*``develop``main`)
- [ ] **Configure Gitea container registry** — create an access token with `read:package` and `write:package` scopes, verify `docker login gitea.nerdboden.de` works, test pushing and pulling an image as a user-level package
- [x] **Configure Gitea container registry** — create an access token with `read:package` and `write:package` scopes, verify `docker login gitea.nerdboden.de` works, test pushing and pulling an image as a user-level package
- [x] **Create production docker-compose file** (`docker-compose.prod.yml`) — uses images from the Gitea container registry, production env vars, no source volume mounts, proper restart policies
- [x] **Create production Dockerfiles (or multi-stage builds)** — ensure frontend is built and served statically (e.g., via the API or a lightweight nginx container), API runs without debug mode
- [x] **Create deploy script**`./deploy.sh` builds images (podman/docker, linux/amd64), pushes to Gitea registry, SCPs compose file, generates `.env` if needed, pulls and starts containers via SSH
- [x] **Configure Nginx Proxy Manager** — add proxy host entries for Gitea and the nuzlocke-tracker frontend/API on the appropriate ports
- [x] **Environment & secrets management** — deploy script auto-generates `.env` with `POSTGRES_PASSWORD` on Unraid if missing; file lives at `/mnt/user/appdata/nuzlocke-tracker/.env`
- [ ] **Implement Gitea Actions CI/CD pipeline** — set up Gitea Actions runner on Unraid, create CI workflow (lint/test on `develop`) and deploy workflow (build/push/deploy on `main`); uses GitHub Actions-compatible syntax for portability
- [x] **Implement Gitea Actions CI/CD pipeline** — set up Gitea Actions runner on Unraid, create CI workflow (lint/test on `develop`) and deploy workflow (build/push/deploy on `main`); uses GitHub Actions-compatible syntax for portability
- [x] **Database backup strategy** — set up a simple scheduled backup for the PostgreSQL data (e.g., cron + `pg_dump` script on Unraid)
- [ ] **Document the deployment workflow** — README or docs covering how to deploy, redeploy, rollback, and manage the production instance
- [x] **Document the deployment workflow** — README or docs covering how to deploy, redeploy, rollback, and manage the production instance

View File

@@ -1,11 +1,11 @@
---
# nuzlocke-tracker-jlzs
title: Implement Gitea Actions CI/CD pipeline
status: in-progress
status: completed
type: task
priority: normal
created_at: 2026-02-10T09:38:15Z
updated_at: 2026-02-10T11:12:32Z
updated_at: 2026-02-10T11:34:52Z
parent: nuzlocke-tracker-ahza
---
@@ -24,6 +24,6 @@ Set up Gitea Actions as the CI/CD pipeline for the nuzlocke-tracker. Gitea Actio
- [x] **Set up a Gitea Actions runner**`act_runner` is deployed on Unraid and registered with Gitea
- [x] **Create CI workflow** (`.github/workflows/ci.yml`) — on push to `develop` and PRs: run `ruff check` + `ruff format --check` for backend, `eslint` + `tsc` for frontend. Tests can be added later when they exist.
- [x] **Create deploy workflow** (`.github/workflows/deploy.yml`) — triggered via `workflow_dispatch` on `main`: build Docker images (linux/amd64), push to the Gitea container registry, deploy to Unraid via SSH (`docker compose pull && docker compose up -d`)
- [ ] **Configure secrets in Gitea** — generate a new SSH keypair, add the public key to Unraid root user's `authorized_keys`, add the private key as a Gitea repo secret (`DEPLOY_SSH_KEY`). Also add any registry credentials or other sensitive values the workflows need.
- [ ] **Test the full pipeline** — push a change through `feature/*``develop` (verify CI runs), then merge `develop``main` and trigger the deploy workflow via `workflow_dispatch` to verify end-to-end
- [ ] **Update deployment docs** — document the Gitea Actions setup, how to manage the runner, and how CI/CD fits into the deployment workflow
- [x] **Configure secrets in Gitea** — generate a new SSH keypair, add the public key to Unraid root user's `authorized_keys`, add the private key as a Gitea repo secret (`DEPLOY_SSH_KEY`). Also add any registry credentials or other sensitive values the workflows need.
- [x] **Test the full pipeline** — push a change through `feature/*``develop` (verify CI runs), then merge `develop``main` and trigger the deploy workflow via `workflow_dispatch` to verify end-to-end
- [x] **Update deployment docs** — document the Gitea Actions setup, how to manage the runner, and how CI/CD fits into the deployment workflow

View File

@@ -1,11 +1,11 @@
---
# nuzlocke-tracker-re0m
title: Document the deployment workflow
status: in-progress
status: completed
type: task
priority: normal
created_at: 2026-02-09T15:30:57Z
updated_at: 2026-02-10T08:44:29Z
updated_at: 2026-02-10T11:35:41Z
parent: nuzlocke-tracker-ahza
blocking:
- nuzlocke-tracker-aiw6

View File

@@ -5,10 +5,18 @@ on:
branches: [develop]
paths-ignore:
- ".beans/**"
- "*.md"
- "LICENSE"
- ".gitignore"
- ".github/workflows/deploy.yml"
pull_request:
branches: [develop]
paths-ignore:
- ".beans/**"
- "*.md"
- "LICENSE"
- ".gitignore"
- ".github/workflows/deploy.yml"
jobs:
backend-lint:

View File

@@ -4,6 +4,8 @@
- Day-to-day work happens on `develop`.
- New work is done on `feature/*` branches off `develop`.
- Merge flow: `feature/*``develop``main`.
- **Squash merge** `feature/*` into `develop` (one clean commit per feature).
- **Merge commit** `develop` into `main` (marks deploy points).
# Instructions

View File

@@ -1,31 +1,95 @@
# Deployment
This document describes the deployment architecture and workflows for the nuzlocke-tracker. It is a living document — sections marked with **TODO** are planned but not yet implemented.
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` (built image) |
| Database | PostgreSQL 16 (Docker volume) | PostgreSQL 16 (Docker volume) |
| 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) |
| Container Management | — | Portainer CE |
| Reverse Proxy | — | Nginx Proxy Manager |
| CI/CD | — | Gitea Actions |
### Services
- **Gitea** — self-hosted Git server, container registry, and (future) CI/CD. Accessible at `gitea.nerdboden.de` via SSL.
- **Portainer** — Docker management UI. Accessible at `portainer.nerdboden.de` via SSL. Manages the production stack and provides webhook-triggered redeployments.
- **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-lint``ruff check` + `ruff format --check`
- `frontend-lint``eslint` + `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:
```bash
# 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
Docker images are hosted on Gitea's built-in container registry as **user-level packages**.
### Image naming
Images use the format `gitea.nerdboden.de/<user>/<image>:<tag>`:
Images are hosted on Gitea's built-in container registry as user-level packages:
```
gitea.nerdboden.de/thefurya/nuzlocke-tracker-api:latest
@@ -35,118 +99,58 @@ 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 from the dev machine:
```bash
docker login gitea.nerdboden.de
```
Use your Gitea username and the access token as password.
2. Log in: `docker login gitea.nerdboden.de` (username + token as password).
### Pushing images
## Production Environment
```bash
# Build and tag
docker build -t gitea.nerdboden.de/thefurya/nuzlocke-tracker-api:latest ./backend
docker build -t gitea.nerdboden.de/thefurya/nuzlocke-tracker-frontend:latest ./frontend
### File layout on Unraid
# Push
docker push gitea.nerdboden.de/thefurya/nuzlocke-tracker-api:latest
docker push gitea.nerdboden.de/thefurya/nuzlocke-tracker-frontend:latest
```
/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)
```
Pushed images are visible under the **Packages** tab on your Gitea user profile.
### Environment variables
## Branching Strategy
The project uses a `main` / `develop` / `feature/*` branching model.
| Branch | Purpose |
|---|---|
| `main` | Always production-ready. Deploy script builds from here. |
| `develop` | Integration branch for day-to-day work. |
| `feature/*` | Short-lived branches off `develop` for individual features/fixes. |
### Workflow
1. Create `feature/xyz` from `develop`
2. Work on the feature, commit, merge into `develop`
3. When ready to deploy: merge `develop` into `main`
4. Run the deploy script (see below)
## Deploying
> **TODO** — deploy script (`./deploy.sh`) not yet created.
The deploy script will automate:
1. Build Docker images from `main`
2. Tag and push to the Gitea container registry
3. Trigger the Portainer webhook to pull new images and restart the stack
### Manual deployment
Until the deploy script is in place, deploy manually:
```bash
# 1. Ensure you're on main with latest changes
git checkout main
# 2. Build and push images
docker build -t gitea.nerdboden.de/thefurya/nuzlocke-tracker-api:latest ./backend
docker build -t gitea.nerdboden.de/thefurya/nuzlocke-tracker-frontend:latest ./frontend
docker push gitea.nerdboden.de/thefurya/nuzlocke-tracker-api:latest
docker push gitea.nerdboden.de/thefurya/nuzlocke-tracker-frontend:latest
# 3. On Unraid (or via Portainer): pull and restart
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d
```
## Production Compose
> **TODO** — `docker-compose.prod.yml` not yet created.
The production compose file will differ from the dev compose in:
- Uses pre-built images from the Gitea registry (no source volume mounts)
- No hot reload / debug mode
- Production environment variables
- Proper restart policies
- Frontend served as a static build (not Vite dev server)
## Portainer
Portainer CE is running on Unraid at `portainer.nerdboden.de`.
- Manages the production Docker stack
- **TODO**: Configure a webhook for automated redeployment (pull latest images + restart on trigger)
## Nginx Proxy Manager
NPM runs on Unraid and handles SSL termination and routing for:
- `gitea.nerdboden.de` → Gitea
- `portainer.nerdboden.de` → Portainer
- **TODO**: `nuzlocke.nerdboden.de` (or similar) → nuzlocke-tracker frontend/API
## Environment & Secrets
> **TODO** — `.env.prod` template not yet created.
Production environment variables to configure:
- `DATABASE_URL` — PostgreSQL connection string
- `DEBUG` — must be `false` in production
- Additional secrets TBD
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 stored in a named Docker volume.
PostgreSQL 16 with data persisted via bind mount at `./data/postgres/`.
- Migrations run automatically on API container startup (Alembic)
- **TODO**: Set up scheduled backups (`pg_dump` cron job on Unraid)
- 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
```bash
cd /mnt/user/appdata/nuzlocke-tracker
gunzip -c backups/nuzlocke-YYYYMMDD-HHMMSS.sql.gz | \
docker compose exec -T db psql -U postgres nuzlocke
```
## Rollback
> **TODO** — rollback procedure to be documented once image tagging strategy is finalized.
Currently images are tagged as `latest` only. To roll back:
General approach: tag images with version/commit hash in addition to `latest`, so rolling back means redeploying a previous tag.
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