Files
SlabUploader/docs/DEPLOYMENT.md
T
Ty 6435199f08 docs(structure): govern .planning/ and register the ops runbook
- docs/STRUCTURE.md: add a .planning/ registry (vision/roadmap/history/breakdown
  roles), broaden the roadmap role, add enforcement items 8-10.
- tools/check_requirements.py: scan .planning/ too - every .planning/**.md must be
  registered, registered files must exist, requirement rows rejected there.
- .planning/: PROJECT.md, ROADMAP.md, MILESTONES.md, and milestones/v0.5/M3/
  {roadmap.md,task_breakdown.md}. M3 breakdown holds only the tasks; decisions live
  in the contracts.
- docs/DEPLOYMENT.md: add the ops runbook (registered as ops).
2026-09-19 10:12:32 -07:00

5.1 KiB
Raw Blame History

Deployment

Role: ops. This is the canonical runbook for getting a build from a working tree to a live dev/test host. deploy/INVENTORY.md is the only source for what runs where (hosts, ports, container names). docs/UAT-PRACTICE.md is the human walk once the app is up; this doc is what makes it up.

1. Topology

Node Role Reach
Ty dev box (Windows) code, git push to Gitea. No Docker CLI. LAN + Tailscale
Gitea (gitea.vps1.afterthedemo.com) source of truth for the repo. SSH port closed; HTTPS only. Tailscale
ubudual5060 (UAT host, LAN 192.168.1.202, Tailscale 100.64.0.9) builds and runs Docker images for UAT. LAN + Tailscale

The dev box never builds images. The UAT host pulls source from Gitea and builds locally. Do not install Docker on the dev box to work around this; the pull-build path is the plan.

2. Access (already provisioned; do not re-do)

  • Dev box → UAT host: ssh ubudual5060 (key ~/.ssh/ubudual5060, wired in ~/.ssh/config). Unattended, passphrase-less.
  • UAT host → Gitea: HTTPS with a read-only token named 5060-pull, stored in ~/.git-credentials on the host. The host clones/pulls with the plain HTTPS URL; no key material in the repo.
  • Deploy checkout on the UAT host: ~/slab-deploy (branch main). The pre-existing ~/SlabUploader on that host is a stale work clone — do not use it.

If access is broken, fix it here before touching compose. Do not commit credentials to the repo.

3. Build and deploy (M3)

Precondition: the M3 scaffold exists on the branch being deployed — frontend/Dockerfile, backend/Dockerfile, and deploy/.env on the host. main currently has frontend/Dockerfile only; backend/ lands with M3 implementation. Prompts live in SQLite (docs/contracts/PROMPTS.md); no prompt files ship with the image.

  1. Push the branch to Gitea from the dev box.

  2. On the UAT host:

    cd ~/slab-deploy
    git fetch origin && git checkout <branch> && git pull
    cp deploy/.env.example deploy/.env && chmod 600 deploy/.env   # first time only
    docker compose -f deploy/docker-compose.yml --env-file deploy/.env build
    docker compose -f deploy/docker-compose.yml --env-file deploy/.env up -d
    
  3. Verify with the smoke checks in §5.

.env values

Generate on the UAT host, never in the repo:

  • SLAB_AES_KEY — openssl rand -base64 32
  • WOO_BASE_URL — the store, https:// only. FastAPI refuses http:// at startup.
  • APP_HOSTNAME — from deploy/INVENTORY.md.
  • FRONTEND_PORT / FASTAPI_PORT — see the port override below.

Woo Application Password and inference keys are not in .env; they are entered in the app's Settings and stored AES-GCM encrypted in the app's SQLite.

Port binding for the dev-test environment

deploy/docker-compose.yml binds 127.0.0.1 only (Caddy is the TLS edge in the full stack). The dev-test environment is reached directly on a port from the project block 10880–10889 (per deploy/INVENTORY.md) and must be reachable from any machine on 192.168.1.0/24, so the deploy must override the port bindings to 0.0.0.0 (compose override file or ports: edit scoped to this deploy). Never bind :10880 (Ty's local Node/SvelteKit) or Ty's :18080.

M3 takes over port 10881 from the M2 container (slabuploader-m2-overnight), per the replace-prior-container rule in deploy/INVENTORY.md. Remove the M2 container when the M3 one is healthy.

4. Local loop (no UAT host needed)

  • Frontend: cd frontend && npm install && npm run dev (Vite).
  • Backend: uvicorn from backend/ once the M3 scaffold lands; needs the same env vars as §3.
  • Tests: frontend npm test (Playwright config in frontend/); backend tests land with M3.

Use the local loop for iteration; use §3 for anything Ty must see on a phone.

5. Smoke checks (after every deploy)

Run from the UAT host, then from a phone on the same network (LAN or Tailscale):

  1. curl -fsS http://127.0.0.1:<frontend-port>/api/health on the host returns ok.
  2. Phone browser opens the inventory URL (deploy/INVENTORY.md) and the app loads.
  3. docker compose -f deploy/docker-compose.yml --env-file deploy/.env ps shows both services up; docker logs for fastapi shows no startup refusal (WOO_BASE_URL is https://).
  4. test-woo in app Settings reports ok (store reachable, taxonomy synced).

If a check fails, the deploy is not live. Roll back per §6 before debugging on the live port.

6. Rollback

  1. docker compose -f deploy/docker-compose.yml --env-file deploy/.env down on the UAT host.
  2. Check out the last known-good ref in ~/slab-deploy and re-run §3 steps 2–3.
  3. Re-run §5. Volumes slab_db and slab_images persist across rollback; do not remove them unless the data itself is the problem.

Where each rule lives

Rule Source
Hosts, ports, container names deploy/INVENTORY.md
Compose shape, env contract deploy/docker-compose.yml, deploy/.env.example
UAT walk once the app is up docs/UAT-PRACTICE.md
M3 scope and exit docs/MILESTONES.md, docs/REQUIREMENTS.md
Woo auth model AGENTS.md, docs/contracts/CONTENT-WOO.md