Files
code-vorlage/.claude/skills/deploy/SKILL.md
T
Florian Wilde b0c4e9e9b9 refactor: rebuild template — Tailwind v4, Docker self-hosting, passkey auth
Toolchain fixes (all previously broken):
- npm run lint: next lint was removed in Next 16 -> eslint with flat config
- .eslintrc.json was ignored by ESLint 9 -> eslint.config.mjs
- npm test / test:e2e exited 1 with no tests -> passWithNoTests
- Vitest scanned tests/ and would have run Playwright specs -> scoped to src/
- Playwright targeted Mobile Safari while docs installed only chromium
- reuseExistingServer silently tested a foreign server on :3000 -> E2E_PORT
- 11 high-severity vulns -> npm audit fix
- deny rule Read(**/.env*) also blocked .env.example -> precise patterns

Stack changes:
- Tailwind v3 -> v4 (CSS-first, no tailwind.config.ts, tw-animate-css)
- shadcn regenerated for v4; 33 components -> 6 core, bundled radix-ui
- Supabase removed entirely; data layer is now chosen per project
- Vercel removed; Docker Compose self-hosting with scripts/update.sh
- Better Auth + passkey plugin as the binding auth standard
- ThemeProvider and Sonner mounted; dark mode and toasts now actually work

Workflow system:
- Sub-agents wired: /frontend, /backend, /qa delegate to .claude/agents
- Checklists folded into their SKILL.md; one file per skill
- Rules rewritten: DB-agnostic backend, passkey security, v4 frontend
- Spec language settled as German, skill instructions English
2026-08-09 00:48:50 +02:00

3.9 KiB

name, description, argument-hint, user-invocable
name description argument-hint user-invocable
deploy Deploy the Docker Compose stack to a server, with pre-flight checks and rollback. PROJ-X or 'production' true

Deploy

Self-hosted Docker Compose. There is no Vercel, no managed platform. The stack runs one app container; TLS and routing are handled by a reverse proxy already present on the host.

1. Gate

  1. Read features/INDEX.md — what is being shipped
  2. Read the feature spec's QA section

No QA section: → "Für PROJ-X gibt es noch kein QA-Ergebnis. Führe erst /qa aus." → Stop. Critical or High bugs open: → name them and stop. Those get fixed first.

2. Pre-flight

Run and show the results — do not proceed on a failure:

npm run lint
npm run typecheck
npm test
npm run build

Then check:

  • Every env var used in code is in .env.example with a dummy value
  • No secrets in the diff (git diff --cached)
  • Pending migrations are committed
  • Everything committed and pushed to the remote the server pulls from

3. First deployment only

Walk the user through this once. It happens on the server, over SSH.

Prerequisites the user provides manually: a server with Docker and the Compose plugin, a reverse proxy (nginx, Caddy, Traefik) terminating TLS, and a DNS record pointing at it.

git clone <repo-url> /srv/<app-name> && cd /srv/<app-name>
cp .env.example .env

Then edit .env:

  • NEXT_PUBLIC_APP_URL — the real public URL. If auth is used, this must match the domain exactly: the WebAuthn relying-party ID comes from this hostname, and a mismatch makes every passkey fail without a useful error.
  • APP_PORT — the port the reverse proxy forwards to
  • APP_BIND — leave at 127.0.0.1 so the container is not exposed directly
  • BETTER_AUTH_SECRET — openssl rand -base64 32, unique per environment
docker compose up -d --build
curl -fsS http://127.0.0.1:${APP_PORT:-3000}/api/health

Point the reverse proxy at 127.0.0.1:$APP_PORT and make sure it forwards X-Forwarded-Proto and X-Forwarded-Host, otherwise redirects and WebAuthn origin checks break.

Passkeys need HTTPS in production — confirm TLS works before testing auth.

4. Subsequent deployments

On the server:

./scripts/update.sh

It pulls the branch, rebuilds, restarts, waits for the healthcheck, and rolls back to the previous commit if the new container never turns healthy. --force rebuilds without a new commit; --branch <name> deploys a different branch.

If a data layer exists, migrations run before the new container serves traffic — see docs/DEPLOYMENT.md.

5. Verify

  • Public URL loads over HTTPS
  • /api/health returns {"status":"ok"}
  • The deployed feature works end to end
  • Sign-in works and offers passkey first (if auth exists)
  • No console errors, no errors in docker compose logs app
  • Security headers survived the proxy (DevTools → Network → Response Headers)

6. Bookkeeping

  • Add a Deployment section to the spec: URL, date, commit SHA
  • features/INDEX.md → Deployed (write, then re-read to verify)
  • Tag: git tag -a v1.X.0-PROJ-X -m "Deploy PROJ-X: [name]" and push it

Rollback

scripts/update.sh rolls back automatically on an unhealthy container. Manually:

git reset --hard <previous-sha>
docker compose up -d --build

Common failures

Symptom Cause
Build works locally, fails in Docker A dependency sits in devDependencies but is needed at build time
Env var undefined at runtime Not in .env on the server, or missing NEXT_PUBLIC_ for client use
Container healthy, proxy returns 502 Proxy points at the wrong port, or APP_BIND is not reachable from it
Passkeys fail after deploy NEXT_PUBLIC_APP_URL does not match the real domain, or TLS is missing
Redirect loop Proxy not forwarding X-Forwarded-Proto

Commit

deploy(PROJ-X): Deploy [feature name] to production