Builder: a separate service that claims work
Parent: structure
Microsite builds (the surface was called "custom pages" until the rename, e7fe80e91, 2026-09-05) run in a separate builder service, not the main app — so the API process never needs docker.sock or vite. The builder (builder/runner.mjs) long-polls /internal/builds/claim and grabs a job atomically with SELECT … FOR UPDATE SKIP LOCKED (backend/db/queries/owner/microsites.sql), runs vite build in its own container, writes the output to a shared volume, then PATCHes status back (routes/sys/builds.go).
Microsites carry a triple-state live / staging / previous_live build pointer (live_build_id / staging_build_id / previous_live_build_id in schema.sql), so going live and rolling back are just pointer swaps — no build cloning. Served at /p/<slug>/ (routes/public/microsites.go) with an injected <base href> so Vite's relative asset paths resolve.
On the admin side the editor now auto-compiles on edit (0140bbbac / bf5ffaa82, 2026-09-06/07) and the long-poll that follows a build moved into a generic worker (5ca6055aa, 2026-09-07) — the builder's claim protocol did not change.