diff --git a/.beans/nuzlocke-tracker-ahza--deployment-strategy.md b/.beans/nuzlocke-tracker-ahza--deployment-strategy.md index 49e2962..4b60a7a 100644 --- a/.beans/nuzlocke-tracker-ahza--deployment-strategy.md +++ b/.beans/nuzlocke-tracker-ahza--deployment-strategy.md @@ -1,11 +1,11 @@ --- # nuzlocke-tracker-ahza title: Deployment Strategy -status: todo +status: in-progress type: epic priority: normal created_at: 2026-02-09T14:03:53Z -updated_at: 2026-02-09T16:44:13Z +updated_at: 2026-02-09T16:53:58Z --- 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. @@ -51,7 +51,7 @@ Define and implement a deployment strategy for running the nuzlocke-tracker in p - [ ] **Configure Gitea container registry** — create an access token with `read:package` and `write:package` scopes, verify `docker login gitea.yourdomain.com` works, test pushing and pulling an image as a user-level package - [ ] **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 - [ ] **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 -- [ ] **Set up Portainer on Unraid** — install Portainer CE as a Docker container, configure the stack from the production compose file +- [x] **Set up Portainer on Unraid** — install Portainer CE as a Docker container, configure the stack from the production compose file - [ ] **Configure Portainer webhook for automated redeployment** — add a webhook trigger in Portainer that pulls latest images and restarts the stack - [ ] **Create deploy script** — a script (e.g., `./deploy.sh`) that builds images from `main`, tags them for the Gitea registry, pushes them, and triggers the Portainer webhook to redeploy - [ ] **Configure Nginx Proxy Manager** — add proxy host entries for Gitea and the nuzlocke-tracker frontend/API on the appropriate ports diff --git a/.beans/nuzlocke-tracker-hwyk--set-up-portainer-on-unraid.md b/.beans/nuzlocke-tracker-hwyk--set-up-portainer-on-unraid.md index 924ee4f..78ce31d 100644 --- a/.beans/nuzlocke-tracker-hwyk--set-up-portainer-on-unraid.md +++ b/.beans/nuzlocke-tracker-hwyk--set-up-portainer-on-unraid.md @@ -1,10 +1,11 @@ --- # nuzlocke-tracker-hwyk title: Set up Portainer on Unraid -status: todo +status: completed type: task +priority: normal created_at: 2026-02-09T15:30:44Z -updated_at: 2026-02-09T15:30:44Z +updated_at: 2026-02-09T16:53:41Z parent: nuzlocke-tracker-ahza --- diff --git a/.beans/nuzlocke-tracker-re0m--document-the-deployment-workflow.md b/.beans/nuzlocke-tracker-re0m--document-the-deployment-workflow.md index ed1c2cd..dc053ae 100644 --- a/.beans/nuzlocke-tracker-re0m--document-the-deployment-workflow.md +++ b/.beans/nuzlocke-tracker-re0m--document-the-deployment-workflow.md @@ -1,11 +1,11 @@ --- # nuzlocke-tracker-re0m title: Document the deployment workflow -status: todo +status: in-progress type: task priority: normal created_at: 2026-02-09T15:30:57Z -updated_at: 2026-02-09T15:31:15Z +updated_at: 2026-02-09T16:55:02Z parent: nuzlocke-tracker-ahza blocking: - nuzlocke-tracker-aiw6 diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 0000000..9259314 --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,152 @@ +# 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. + +## 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) | +| Container Registry | — | Gitea (user-level packages) | +| Container Management | — | Portainer CE | +| Reverse Proxy | — | Nginx Proxy Manager | + +### 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. +- **Nginx Proxy Manager** — reverse proxy with SSL termination for all services on the Unraid server. + +## 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//:`: + +``` +gitea.nerdboden.de/julian/nuzlocke-tracker-api:latest +gitea.nerdboden.de/julian/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. + +### Pushing images + +```bash +# Build and tag +docker build -t gitea.nerdboden.de/julian/nuzlocke-tracker-api:latest ./backend +docker build -t gitea.nerdboden.de/julian/nuzlocke-tracker-frontend:latest ./frontend + +# Push +docker push gitea.nerdboden.de/julian/nuzlocke-tracker-api:latest +docker push gitea.nerdboden.de/julian/nuzlocke-tracker-frontend:latest +``` + +Pushed images are visible under the **Packages** tab on your Gitea user profile. + +## 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/julian/nuzlocke-tracker-api:latest ./backend +docker build -t gitea.nerdboden.de/julian/nuzlocke-tracker-frontend:latest ./frontend +docker push gitea.nerdboden.de/julian/nuzlocke-tracker-api:latest +docker push gitea.nerdboden.de/julian/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 + +## Database + +PostgreSQL 16 with data stored in a named Docker volume. + +- Migrations run automatically on API container startup (Alembic) +- **TODO**: Set up scheduled backups (`pg_dump` cron job on Unraid) + +## Rollback + +> **TODO** — rollback procedure to be documented once image tagging strategy is finalized. + +General approach: tag images with version/commit hash in addition to `latest`, so rolling back means redeploying a previous tag.