No more shared instructor password env var — the api service now needs only PROVISIONER_SHARED_SECRET. First-run setup is npm run bootstrap-owner instead.
RootNode Academy — Platform
The full multi-student platform, layered on top of the unmodified Lab image at the repo root. Start here, then go to the component you need:
provisioner/— Postgres-backed environment registry and lifecycle. Design:docs/LAB_ARCHITECTURE.md,docs/PHASE1_PLATFORM_FOUNDATION.md. Operational reference:provisioner/README.md.api/— the lightweight Platform API: students, cohorts, enrollments, curriculum, progress, scenario attempts, student/admin sessions, and the instructor/admin control plane. No k3s, no--privileged— this replaced Phase 2A's "identity" instance, which was a full Lab image booting an unused k3s cluster just to serve these APIs. Design:docs/PHASE2B_ADMIN_AND_PLATFORM_DATA.md. Operational reference:api/README.md.gateway/— the only student-facing path to a Lab (HTTP + WebSocket proxy, environment-aware routing derived from a server-controlled session — not a client-suppliable header/param). Design:docs/PHASE2A_GATEWAY_AND_STUDENT_FLOW.md(routing),docs/PHASE2B_ADMIN_AND_PLATFORM_DATA.md§3 (session ownership).egress-proxy/— shared allowlisting proxy every Lab's outbound traffic passes through.docker-compose.dev.yml— the full stack (Postgres, egress proxy, Provisioner, Platform API, Gateway) on one machine. This is the Phase 1/2A/2B local dev exception — production is the two-VM Proxmox split described indocs/LAB_ARCHITECTURE.md§1.
Running the full stack locally
cd platform
echo "PROVISIONER_SHARED_SECRET=$(openssl rand -hex 32)" > .env
echo "ADMIN_PASSWORD=$(openssl rand -hex 12)" >> .env
docker compose -f docker-compose.dev.yml build
docker compose -f docker-compose.dev.yml up -d
No k3s boot to wait for at this layer anymore (Platform API starts instantly) — the whole
platform is reachable at http://localhost:4200 (the Gateway) right away: students at /,
instructors at /admin.
Tests
provisioner/test/run.js— fast, isolated Provisioner tests (network/container/firewall mechanics, no Gateway/Platform API involved). Run againstprovisioner/docker-compose.dev.yml.test/e2e-phase2a.js— student-flow regression through real session cookies: roster → login → curriculum → launch → Gateway routing → cross-student rejection → progress relay → reset.test/e2e-phase2b.js— the classroom acceptance workflow: instructor creates a cohort, adds students, assigns curriculum, Prepare Labs (concurrent), students complete different scenarios, instructor resets one, instructor destroys all cohort Labs after class — progress survives every step. NeedsADMIN_PASSWORDset (seeplatform/.env).
Both e2e suites are slow (real k3s boots) and need the full stack up. Neither substitutes for
the manual real-Lab-image checks (node-pty, terminal WebSocket, kubectl, scenario validation)
in docs/PHASE2A_GATEWAY_AND_STUDENT_FLOW.md §8 — those need a browser-equivalent client and
aren't automated here.
Known limitations
See provisioner/README.md (Phase 1), docs/PHASE2A_GATEWAY_AND_STUDENT_FLOW.md §9 (Phase
2A), and docs/PHASE2B_ADMIN_AND_PLATFORM_DATA.md §13 (Phase 2B) for the full, honest lists —
including in-memory sessions, the single shared admin credential, and exam mode's live
bookkeeping staying Lab-local.