doxa-maps/deployment/cloud
Doxa Maps c0487bb39d
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
Cloud container: Rudder's engine inside (RUDDER_ENGINE=1), fed by the browser's microphone
Go 1.22 in the image; on start, backend/rudder-engine/setup-runtime.sh fetches its pinned runtime and
model (SHA-256 checked, skipped when present) into RUDDER_HOME (default /data/rudder, meant for the
persistent volume) and builds the engine; RUDDER_AUDIO=browser. The pull loop rebuilds the untracked
engine binary when backend/rudder-engine changes. /api/rudder stays behind the sign-in: it is served
by Vite on the gated / route, and the only public routes remain /cdn/ and /api-prod/api/. README:
the flag, and 3.5 GB with it on.
2026-09-27 21:43:30 +00:00
..
admin.mjs Cloud container v1: PocketBase dev + prod, a public CDN of the last good build, and an admin-only build trigger 2026-09-27 21:32:46 +00:00
apply-exclusions.sh Cloud container v1: PocketBase dev + prod, a public CDN of the last good build, and an admin-only build trigger 2026-09-27 21:32:46 +00:00
build-cdn.sh Cloud container v1: PocketBase dev + prod, a public CDN of the last good build, and an admin-only build trigger 2026-09-27 21:32:46 +00:00
Dockerfile Cloud container: Rudder's engine inside (RUDDER_ENGINE=1), fed by the browser's microphone 2026-09-27 21:43:30 +00:00
entry.sh Cloud container: Rudder's engine inside (RUDDER_ENGINE=1), fed by the browser's microphone 2026-09-27 21:43:30 +00:00
public-exclusions.txt Cloud container v1: PocketBase dev + prod, a public CDN of the last good build, and an admin-only build trigger 2026-09-27 21:32:46 +00:00
README.md Cloud container: Rudder's engine inside (RUDDER_ENGINE=1), fed by the browser's microphone 2026-09-27 21:43:30 +00:00
vite.cloud.config.mjs Cloud dev server recipe in the repo, with an optional OIDC sign-in 2026-09-27 07:50:45 +00:00

Run dx-maps in the cloud: one shared dev server for a team

One container runs the Plugin Studio with hot reload for everyone. It clones the repo, pulls the branch every few seconds, and Vite hot-reloads whatever changed, so every change an agent lands on main shows up in everyone's browser within seconds. No rebuild; bun run build is only for publishing.

With no OIDC settings it runs open, like bun run dev on a laptop. With OIDC settings a sign-in page ("Sign in with your provider") sits in front of everything: the Studio, every map, and the hot-reload websocket. Only people in the allowed groups get in.

Deploy

  1. Build the image from Dockerfile. It's a small bootstrap (Bun, git, and the oauth2-proxy binary); at start it clones the repo and runs entry.sh from it, so the recipe updates with the repo. Paste it into any container host (Coolify's "Dockerfile" build pack, Railway, docker build).
  2. Set the environment below and expose the container's PORT over HTTPS.
  3. Give it about 2 GB of memory (Vite plus the dependency install).
Variable Needed Meaning
REPO_URL yes the dx-maps git URL to clone
BRANCH no (main) the branch to follow
PULL_INTERVAL no (15) seconds between pulls
GIT_TOKEN private repos a read token for the clone and pulls
PORT no (5173) the port the container serves on
HMR_CLIENT_PORT, HMR_PROTOCOL behind HTTPS 443 and wss, so browsers reach the hot-reload websocket

Sign-in (optional)

Set all of these to turn the gate on. Register a confidential client at your OIDC provider with the redirect URL https://<your-host>/oauth2/callback; PKCE (S256) is used as well.

Variable Meaning
OIDC_ISSUER the provider's issuer URL (its /.well-known/openid-configuration must resolve)
OIDC_CLIENT_ID, OIDC_CLIENT_SECRET the registered client
OIDC_REDIRECT_URL https://<your-host>/oauth2/callback
OIDC_ALLOWED_GROUPS comma-separated groups allowed in; required (the server refuses to start without it, because many providers allow open sign-up)
OIDC_DISPLAY_NAME the name on the button, e.g. "Sign in with Acme"
OIDC_GROUPS_CLAIM the token claim holding groups (default groups)
OIDC_COOKIE_SECRET 32 characters; keeps people signed in across restarts (random if unset)

Secrets reach oauth2-proxy through its environment, never its command line.

Backend and production (v1, experimental)

With the sign-in on, the container also runs PocketBase and can publish a production build:

Route Who What
/ signed-in the dev server (Plugin Studio, hot reload)
/pb/ signed-in (its /_/ dashboard: OIDC_ADMIN_GROUPS only) PocketBase dev
/api-prod/api/ public PocketBase prod's API; its dashboard is never exposed
/cdn/dx-maps/ public the last published build: manifest.json at a stable URL, CORS open for embeds
POST /admin/build · GET /admin/status OIDC_ADMIN_GROUPS only build and publish the pulled commit

A build runs one at a time (a second gets 409), on a snapshot of the pulled commit, with Node's heap capped. It removes everything in public-exclusions.txt before building, checks the output again afterwards, and refuses to publish if anything excluded is still there. Only then does it swap the new build in.

Variable Meaning
OIDC_ADMIN_GROUPS comma-separated groups allowed to build and to open PocketBase's dashboard
PB_SUPERUSER_EMAIL, PB_SUPERUSER_PASSWORD PocketBase's superuser, set on start in both instances
PUBLIC_API_BASE the public API URL written into the build's runtime-config.js (e.g. https://<host>/api-prod)
BUILD_MAX_OLD_SPACE_MB Node heap cap for a build (default 1536)
RUDDER_ENGINE 1 runs Rudder's voice-to-text engine here, fed by the browser's microphone (about 1 GB more; its model, ~742 MB, downloads once to RUDDER_HOME, default /data/rudder)

Mount a persistent volume at /data (PocketBase data and published builds). Memory measured on the running container: about 0.45 GB idle, up to about 1.5 GB more during a build, so give it 2.5 GB (3.5 GB with RUDDER_ENGINE=1).