public/download/ holds a dev-server copy of apess-onboard.zip (baked cloud
token) so the "Download the board app" button works against the Vite dev
server. Never commit it.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Turnkey hosting for the distributable app: both web containers now mount
deploy/download/ read-only and nginx serves it at /download/<file>
(autoindex off, no-store). Drop dist/apess-onboard.zip into deploy/download/
and students fetch https://apess.redclaw.dev/download/apess-onboard.zip →
App Lab "Import an app" → Run. No image rebuild to update the artifact.
The zip carries a baked cloud token, so deploy/download/*.zip is gitignored
and the URL should be treated as a secret (workshop network / access-gated,
not a public link).
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Commits the workshop inference pool (LiteLLM → boards: pooled coding plans,
per-attendee virtual keys, failover) — config + docs only, no secrets. Ignores
the vendored Uno-QClaw reference repo and the generated qr-sheet.html.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Fixes the reachability gap: a cloud-hosted API can't reach boards behind the
workshop NAT, so live board features (claim status, Build & flash, module
feeds) fail. This stack runs web + API on one box on the workshop WiFi, where
the API CAN reach each board's LAN IP.
- deploy/lan/: docker-compose (web + internal API), nginx.lan.conf (SPA +
same-origin /api reverse-proxy with WS/SSE support), .env.example, README
(launch, point the fleet's APESS_URL at the box, run the room).
- Web is IP-agnostic: nginx serves the SPA and proxies /api on the same origin,
so no box IP is baked into the build.
- api.ts: API_BASE now supports a relative same-origin base ("/api"); wsUrl()
derives ws scheme+host from the page for it (absolute prod base unchanged).
- Dockerfile.web: VITE_API_BASE build arg (empty=prod default, "/api"=LAN).
Verified E2E with a real `docker compose up`: SPA 200, /api/healthz ok,
self-register→unclaimed round-trip through the proxy, /api/ws → 101 Switching
Protocols, and 0 hosted-URL refs in the /api build. Web 220 + api 56 green.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Two host-side helpers that close the operational gap between minting kit
codes and boards-in-hand.
- provision-fleet.sh: provision a whole fleet from fleet.csv (kit,serial).
Per board it pushes the per-kit apess-node.env + apess-selfregister.sh
over adb and enables the boot/refresh systemd timer (MODE=systemd, root)
or an equivalent cron (@reboot + every 5 min; the no-root default).
fleet.csv.example is the assignment template.
- gen-qr-sheet.sh: render the sticker CSV into a self-contained, printable
QR sheet (A4, ~9/page). QRs are baked in as inline SVG via qrencode, so
the HTML has zero external refs — prints offline. Each sticker: kit id,
QR of the claim URL (/workshop?kit=..&code=..), and the 6-digit code.
- .gitignore: never commit kit-codes/ (env files hold FLEET_SECRET +
claim codes) or fleet.csv.
- README: documents both, plus the one-command fleet path.
Verified: provision-fleet loop logic (header/comment/missing skips) and a
4-kit end-to-end sheet build (4 inline SVGs, 0 external refs).
Co-Authored-By: Claude Opus 4.8 <[email protected]>