From 2beb2d5d43f890256d5c2bca875bfd0c8a1fab4a Mon Sep 17 00:00:00 2001 From: JP Date: Sat, 8 Aug 2026 17:02:51 +0000 Subject: [PATCH] Version the deploy skill with the repo .claude/ was ignored wholesale, which meant the deploy skill lived only on one machine. Narrow the rule so .claude/skills/ is tracked while settings.local.json stays local. Co-Authored-By: Claude Opus 5 (1M context) --- .claude/skills/deploy-drinktracker/SKILL.md | 69 +++++++++++++++++++++ .gitignore | 4 +- 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 .claude/skills/deploy-drinktracker/SKILL.md diff --git a/.claude/skills/deploy-drinktracker/SKILL.md b/.claude/skills/deploy-drinktracker/SKILL.md new file mode 100644 index 0000000..f529690 --- /dev/null +++ b/.claude/skills/deploy-drinktracker/SKILL.md @@ -0,0 +1,69 @@ +--- +name: deploy-drinktracker +description: Deploy drinktracker to the production LXC and verify it came back healthy. Use when asked to deploy, ship, release, push to prod, or update the running app - and after merging changes that need to go live. Also covers rollback and diagnosing a deploy that did not take effect. +--- + +# Deploying drinktracker + +Run `./deploy/deploy.sh` from the repo root. It typechecks, pushes to Gitea, rebuilds the +image on the LXC, restarts the stack and polls until the app answers. Use `--yes` to skip +the confirmation prompt when the user has already approved the deploy. + +`deploy/README.md` has the full topology table, the one-time sudoers setup, and rollback +commands. Read it before improvising — the layout is unusual in ways that waste time. + +## Facts that are not discoverable from the repo + +- **The LXC is `192.168.2.169`.** `drinktracker.tenseconddelay.net` (and `NEXTAUTH_URL`) + resolve to the reverse proxy at `192.168.2.172`. SSHing there fails with what looks like + a rejected key but is simply the wrong machine. +- **The live stack is `/root/drinktracker`.** The checkouts under `/home/drinkadmin/` + (`drinktracker`, `drinktracker-latest`) are stale June copies. Confirm with + `docker inspect drinktracker-app-1 --format '{{index .Config.Labels "com.docker.compose.project.working_dir"}}'`. +- **There is no CI.** No Gitea Actions, no GitHub workflows. `git push` updates the repo + and nothing else; the image must be built and the stack restarted separately. If someone + reports "I pushed but nothing changed", this is why. +- **Access:** `ssh -i ~/.ssh/drinktracker_ed25519 drinkadmin@192.168.2.169`. Root SSH is + disabled. `drinkadmin` needs the sudoers drop-in from `deploy/README.md` for the script + to work unattended. + +## Verifying + +An unauthenticated request to port 3000 returns **307** (redirect to `/login`) — that is a +healthy response, not a failure. The script accepts 200, 302 and 307. + +Each AI call emits one line: + +``` +sudo docker logs drinktracker-app-1 2>&1 | grep '\[switchboard\]' +``` + +`FAILOVER` lines are expected and harmless: the gateway's `:batch` model variants fail on +every request and fall back. `CONTEXT OVERFLOW` is worth investigating — it means a request +was too large for any model's window and may have been truncated. + +## Before deploying schema changes + +The `migrate` service runs `prisma db push --skip-generate --accept-data-loss` on every +start. Removing a field from `schema.prisma` therefore **drops the column and its data** on +the next deploy, in both directions — so a rollback past a schema change is destructive too. +Dump the database first when the schema changed: + +``` +sudo docker exec drinktracker-db-1 pg_dump -U drinktracker drinktracker > ~/dt-$(date +%F).sql +``` + +This is also why `UserPreference.defaultProvider` is still in the schema despite being +unused: deleting it would drop the column and break restoring older backups. + +## If the app does not come back + +``` +sudo docker compose -f /root/drinktracker/docker-compose.prod.yml ps +sudo docker logs drinktracker-app-1 --tail 100 +``` + +Most likely causes, in order: the build failed and compose restarted the previous image; +`.env.production` is missing a variable the new code reads (compare against `.env.example`); +or the `migrate` service exited non-zero and `app` never started, which `ps` will show as +`migrate` in a non-zero exited state. diff --git a/.gitignore b/.gitignore index d1caaf8..20b37e4 100644 --- a/.gitignore +++ b/.gitignore @@ -32,7 +32,9 @@ yarn-error.log* .env*.local # claude -.claude/ +.claude/* +# Skills are project documentation and worth versioning; local settings are not. +!.claude/skills/ # vercel .vercel