# dotnews-paas — working notes for Claude

Self-hosted, Docker-free deployment platform: Caddy → (Varnish) → app, driven by
one bash CLI (`bin/paas`, the ONLY writer of server state) and a Fastify/EJS
panel (`panel/`) that shells out to it. Full architecture: `docs/README.md`.

## Runtimes / flavours

- Per **app**: `RUNTIME=node|laravel` in `/srv/paas/apps.d/<app>.conf`, fixed at
  creation. Node = PM2 process on `127.0.0.1:PORT`; Laravel = PHP-FPM pool +
  Caddy `php_fastcgi` (+ loopback `http://127.0.0.1:PORT` site so health/monitoring
  keep the port contract). Varnish is refused for Laravel (VCL strips cookies).
- Per **server**: `bootstrap.sh` plain = Node-only (production today);
  `WITH_LARAVEL=1` adds PHP 8.3/8.4, composer, MariaDB and writes
  `RUNTIMES=node,laravel` to `/srv/paas/paas.conf` — the flag panel + CLI gate on.
  Never install PHP/MariaDB on node-only servers; keep every Laravel/DB feature
  capability-gated so existing servers see zero change.
- `paas db` (MariaDB per app, creds into `shared/.env`) is runtime-agnostic.

## Golden template policy (Proxmox, prox3.younex.de)

- There is **exactly one** golden template (`infra/golden-template.md` names the
  current VMID). It is generic — no instance state — and serves both flavours;
  the flavour is chosen on the clone by the wizard `sudo paas-init`
  (`bin/paas-init`), which asks panel domain, admin password, Node.js/Laravel,
  system-domain base, ACME e-mail, pulls the repo and runs `bootstrap.sh`.
- **Whenever a feature lands in production (committed + deployed), refresh the
  template**: clone current template → `git pull` → `bootstrap.sh` →
  `sudo PREINSTALL_LARAVEL=1 infra/generalize-golden.sh` → `qm template` →
  set the Notes from `infra/golden-template-notes.md` (Markdown only, no HTML —
  Proxmox shows HTML literally) → verify with one test clone → **destroy the
  previous template and the test clone**. Update the VMID/table in
  `infra/golden-template.md` and the r-number in the same commit.
- Each spawned instance needs its own panel domain (production: `deploy.younex.de`).

## Conventions

- `paas` runs as user `deploy`, never root; anything needing root goes through
  the exact-command sudoers allowlists (`/etc/sudoers.d/paas`, `paas-laravel`).
- Generated configs follow stage → validate → commit → reload
  (`regen_caddy`, `regen_vcl`, `regen_fpm`); never hand-edit generated files.
- Releases are immutable dirs + `current` symlink; deploys are health-gated on
  `PORT+1000` before the flip. Laravel deploys never reload php-fpm
  (`resolve_root_symlink` keys opcache per release).
- Registry keys are added to `reset_app_vars` in `bin/paas`; panel reads them via
  `paas info`. New project flags follow the `multi_label` precedent
  (`panel/lib/db.js` migration block, `server.js` route, `project.ejs` toggle).
- Lint before committing: `bash -n` + `shellcheck -S warning` for bash,
  `node --check` for the panel; EJS can be render-tested with mock data.
- Pushing `main` deploys the platform to production automatically (LAN
  Jenkins job `paas-platform` → `ci/Jenkinsfile.platform` → `paas-self-deploy`
  on the VM, `docs/ci-platform-deploy.md`). No manual rsync/bootstrap on
  production; verify with `sudo paas-self-deploy status|verify`, undo with
  `rollback`.
