Prime's directive via pewpew-dev. Images are built on nh3-dev from a clean archive of vh/pewpewstudio (26bba3c; hamr over gitea SSH via BuildKit --ssh) and loaded on nh3-docker. Caddy serves the SPA and strips /api/ in front of the backend. It refuses foreign Host headers inside a route block, because the Host rewrite would otherwise bypass the backend's TrustedHost. The DB, assets and the app-edited shop config live on named volumes inside nh3-docker's nightly vzdump. Verified: SPA, /api/machines and /api/generate/workflows 200; foreign Host 400.
52 lines
3.6 KiB
Markdown
52 lines
3.6 KiB
Markdown
# pewpewstudio
|
|
|
|
Laser job studio (FastAPI backend + React SPA, gitea `vh/pewpewstudio`). It composes Thunder Aurora marking jobs and
|
|
returns LightBurn `.lbrn` files as browser downloads, and never touches hardware. Deployed 2026-10-13 on Prime's directive
|
|
via pewpew-dev (thread `01M4WATRFQX3V7TSJ4XPGABWMN`).
|
|
|
|
| | |
|
|
|---|---|
|
|
| **URL** | `http://10.100.50.40:8185/` (= `http://nh3-docker.nh3.internal:8185/`). Homepage tile in *AI - Studios*. |
|
|
| **Host** | nh3-docker: fast local disk for SQLite WAL (fsync ~2.7 ms, unlike ana-docker's HDD pool), and it reaches arbo `100.64.0.6:8201` and Worldtree DEMO `10.250.50.152:8080`. |
|
|
| **Auth** | NONE in v1. LAN/mesh only: published on the host's LAN address, with no public ingress. |
|
|
| **Images** | `pewpewstudio:<rev>` (api) and `pewpewstudio-web:<rev>` (Caddy + `web/dist`), built on nh3-dev and loaded here; `PEWPEW_REV` in `.env` picks the pair. |
|
|
| **State** | volume `pewpewstudio_state` (`/state`: `shop.db` + `assets/`) and volume `pewpewstudio_config` (`/config`: machine profiles, lenses, denylist, sizing, fonts, which **the app edits from the browser**). Both are covered by nh3-pve's nightly 21:00 whole-VM vzdump of VM 100. |
|
|
| **Secrets** | `.env` (0600, infra-ops): `WORLDTREE_API_KEY` = vault `nh3-dev/.config/worldtree/pewpewstudio-demo-key`. |
|
|
|
|
## Topology
|
|
|
|
`web` (Caddy, published `10.100.50.40:8185 → :80`) serves the SPA at `/`. It sends `/api/*` to `api:8000` with the
|
|
prefix **stripped** (the backend has no `/api` routes and no CORS, so both must be one origin) and Host rewritten to
|
|
`localhost`, which the backend's TrustedHost accepts. Because of that rewrite, **Caddy refuses any Host other than
|
|
`10.100.50.40` / `nh3-docker.nh3.internal` with 400**, to keep the backend's DNS-rebinding defence. Add a name to
|
|
`conf/Caddyfile` before publishing one. Verified 2026-10-13: foreign Host → 400; IP and name → 200.
|
|
⚠ That check must stay inside `route { }`. Outside it, Caddy orders `respond` after `handle_path`, and the check
|
|
silently never runs: a foreign Host got 200 until it was wrapped.
|
|
⚠ The Caddy config is mounted as the DIRECTORY `/opt/docker/conf/pewpewstudio → /etc/caddy`. deploy-stack replaces the
|
|
file, and a single-file bind mount keeps showing the old inode.
|
|
|
|
## Build and deploy (from nh3-dev)
|
|
|
|
```bash
|
|
REV=<short sha>; C=$(mktemp -d)
|
|
git -C ~/development/pewpewstudio archive $REV | tar -x -C $C
|
|
cp stacks/pewpewstudio/build/Dockerfile $C/Dockerfile.eshpfi
|
|
# hamr is a git dependency over gitea SSH (10.250.50.70:222); BuildKit forwards lkraven's gitea key:
|
|
(cd $C && docker build -f Dockerfile.eshpfi --ssh default=$HOME/.ssh/id_rsa --target api -t pewpewstudio:$REV . \
|
|
&& docker build -f Dockerfile.eshpfi --target web -t pewpewstudio-web:$REV .)
|
|
docker save pewpewstudio:$REV pewpewstudio-web:$REV | ssh infra-ops@10.100.50.40 docker load
|
|
scripts/deploy-stack.sh nh3-docker pewpewstudio # compose + conf/Caddyfile; never .env
|
|
# on nh3-docker: set PEWPEW_REV=$REV in .env (in place, keep 0600), then
|
|
cd /opt/docker/compose/pewpewstudio && docker compose up -d
|
|
```
|
|
|
|
**First deploy only:** the config volume was seeded once from the repo's `config/` plus the gitignored
|
|
`config/machine.local.toml` from nh3-dev's checkout (machine parameters, no secrets). Without a `machine.*.toml` (the
|
|
registry skips `machine.example.toml`), startup fails "no machine.*.toml files". **Never reseed a populated volume**:
|
|
it holds the shop's own edits. The database started fresh; the dev `shop.db` was smoke-test data.
|
|
|
|
## Checks
|
|
|
|
- `GET /` 200 (the SPA); `GET /api/machines` 200 (one machine, `aurora-mopa-100w-f160`); `GET /api/generate/workflows` 200.
|
|
- The api healthcheck is `GET /machines` on loopback.
|