From 92d6495cc9b07f34f8625d70c7b4bae3308e6961 Mon Sep 17 00:00:00 2001 From: neodk2004 Date: Mon, 7 Sep 2026 19:32:44 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20update=20deploy=20workflow=20=E2=80=94?= =?UTF-8?q?=20NAS=20now=20git=20pull,=20not=20manual=20FTP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Confirmed 2026-09-07 while deploying the Child Safety Standards page: /Dockers/PawFeed on the NAS is its own git checkout tracking the self-hosted Gitea remote, kept up to date via git pull rather than the manual FTP upload this file previously described. Documents the actual deploy steps (ssh daniel@192.168.1.222 on the standard port, git pull, then rolling-deploy.sh) so this doesn't need rediscovering next time. --- CLAUDE.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index fab13f0..275cc23 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -96,7 +96,9 @@ Vitest + `jsdom`. Prisma is fully mocked per-model via `createMockPrisma()` in ` ### Deployment — self-hosted Docker, not Vercel -Despite `next.config.ts`'s `output: "standalone"` and the original stack research recommending Vercel, this app is deployed to a self-hosted OpenMediaVault NAS via Docker (`docker/Dockerfile`, `docker/docker-compose.yml`, `docker/start.sh`). **There is no `git pull` on the server** — deploys are manual FTP uploads of changed files followed by `./start.sh`. Don't suggest Vercel-specific features (ISR revalidation webhooks, Vercel KV, edge config) without checking this still holds. +Despite `next.config.ts`'s `output: "standalone"` and the original stack research recommending Vercel, this app is deployed to a self-hosted OpenMediaVault NAS via Docker (`docker/Dockerfile`, `docker/docker-compose.yml`, `docker/start.sh`). Don't suggest Vercel-specific features (ISR revalidation webhooks, Vercel KV, edge config) without checking this still holds. + +**Deploy sync is now `git pull` on the server, not manual FTP** (confirmed 2026-09-07 — supersedes the old FTP-based process; update this note again if it changes further). The NAS at `/Dockers/PawFeed` is its own git checkout with `origin` pointing at the self-hosted Gitea instance (`http://192.168.1.222:3666/admin/petfeed.git`, same repo `git push` in this dev environment goes to over SSH on port 2222). To deploy: `ssh daniel@192.168.1.222` (standard port 22, key-based — a *different* credential from the port-2222 Gitea git-shell key used for `git push`/`git pull` from a dev machine), then on the NAS: `cd /Dockers/PawFeed && git pull origin main`, then `cd docker && ./rolling-deploy.sh` (or `sh ./rolling-deploy.sh` if it's not executable). `mobile/` changes land in this same working tree too (it's one repo) but don't need a deploy — `.dockerignore` excludes it from the image build. **Runs as 3 load-balanced replicas, not a single container (since 2026-08-16, Gitea #26).** `docker/docker-compose.yml` defines `pawfeed-1`/`pawfeed-2`/`pawfeed-3` (via the `x-pawfeed-common` YAML anchor) instead of one `pawfeed` service — Next.js standalone output is single-process (`node server.js`), so one container only ever used one CPU core regardless of how many the NAS has. A load test on 2026-08-15 hit a hard ceiling at ~60–65 req/sec with one core pegged at 133% while 3 cores sat idle; splitting into 3 replicas fixed it (confirmed via a follow-up load test showing ~100% CPU spread evenly across all three). Nginx Proxy Manager (container `nginx-app-1` on this NAS, admin UI at `192.168.1.222:81`) load-balances across them via a `least_conn` upstream block — that block lives in `/Docker-Data/nginxproxymanager/data/nginx/custom/http_top.conf` on the NAS host (an nginx `upstream {}` is only valid in the `http{}` context, which NPM's per-host "Custom Nginx Configuration" field can't reach — that field only writes into the `server{}`/`location{}` context, and holds the `proxy_pass http://pawfeed_upstream;` override for the `pawfeed.org` Proxy Host instead). Full runbook, decisions, and risk notes: `docker/SCALING-ROADMAP.md`. **Deploying a config or code change means rebuilding all 3 replicas** — there is no separate single-container path anymore, and NPM's proxy target is `pawfeed_upstream`, not a bare `pawfeed:3000` hostname. Use `./docker/rolling-deploy.sh` for deploys against the live site — it rebuilds the shared `pawfeed:latest` image once, then restarts `pawfeed-1`/`2`/`3` one at a time, gated on each becoming `healthy` per the Docker `healthcheck` (`GET /api/health`, a dependency-free liveness check — see `src/app/api/health/route.ts`) before moving to the next, so at least 2 replicas always serve traffic. Verified zero-downtime on 2026-08-16 (continuous curl monitoring showed unbroken HTTP 200 through a full rolling deploy). `docker compose up -d --build` (`start.sh`) still works but restarts all 3 at once — only use it for first-time setup or when a brief outage is acceptable. `src/lib/prisma.ts`'s Prisma pg pool size is capped per-replica via `DB_POOL_MAX` (compose sets `10`) so 3 replicas stay well under the Supabase pooler's client-connection limit.