Master overview (PHASE4_1_PREPRODUCTION_HARDENING.md) covering all 27 substantive items, plus REMOTE_AND_SELF_PACED_ARCHITECTURE.md (reviews what already works for remote/self-paced delivery - student-driven provisioning, cohort-less students, idle-reaper-destroy-then-continue - and the one real gap: student authentication, explicitly Phase 5 scope, not built here). Updated PRODUCTION_NETWORK_SECURITY.md (the Gateway-to-Lab gap is now RESOLVED, with the full design writeup and a new control-plane-vs-data-plane section), PRODUCTION_DEPLOYMENT.md (four-cert TLS bundle), PRODUCTION_VALIDATION_CHECKLIST.md (Router mTLS check, admission control checks), PHASE4_PRODUCTION_INFRASTRUCTURE.md and ENGINEERING_SOP.md and LAB_ARCHITECTURE.md (stale 'known gap' pointers updated to point at the resolution), BACKUP_DR.md (destructive drill), README.md and platform/README.md (Phase 4.1 pointers, lab-router component, updated known-limitations). Also fixes a real pre-existing bug found while auditing what gets committed: infra/.gitignore's patterns were written repo-root-relative (e.g. "infra/terraform/...") but the file lives in infra/, so git resolved them relative to THAT directory and none of them ever matched anything - a real .terraform/ provider cache showed up as untracked when it should have been ignored. Fixed by dropping the redundant leading "infra/" from every pattern. Status: PHASE 4.1 COMPLETE / PRE-PRODUCTION HARDENING COMPLETE / READY FOR HARDWARE DEPLOYMENT.
6.6 KiB
RootNode Academy — Platform
The full multi-student platform, layered on top of the Lab image at the repo root (backend/
entrypoint/Dockerfile unmodified; frontend bundle gained Phase 3B learning UX, see
docs/PHASE3B_LEARNING_AND_ASSESSMENT.md §10–11). 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, detailed scenario attempt telemetry, progressive hints, curriculum completion rules, the exam + capstone assessment engine, achievements, per-instructor accounts, persistent student/ instructor sessions, RBAC, audit logging, 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(split + Postgres migration),docs/PHASE3A_IDENTITY_AND_INSTRUCTOR_ACCESS.md(sessions, accounts, RBAC, audit),docs/PHASE3B_LEARNING_AND_ASSESSMENT.md(learning/assessment engine). 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 — and, as of Phase 3B, server-side gating of progressive hint reveal). Design:docs/PHASE2A_GATEWAY_AND_STUDENT_FLOW.md(routing),docs/PHASE3A_IDENTITY_AND_INSTRUCTOR_ACCESS.md(persistent sessions, CSRF),docs/PHASE3B_LEARNING_AND_ASSESSMENT.md§3 (hint gating).egress-proxy/— shared allowlisting proxy every Lab's outbound traffic passes through.lab-router/— Phase 4.1 addition. Runs on the Lab Host VM (ordev-local's stand-in in local dev, thoughdirectmode there never exercises it); resolves an opaque routing token to a local Lab container purely from Docker state, over mTLS, so the Gateway never needs a Docker-internal address. Design:docs/PHASE4_1_PREPRODUCTION_HARDENING.md§1-3.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
docker compose -f docker-compose.dev.yml build
docker compose -f docker-compose.dev.yml up -d
# First run only — create the owner account (no ADMIN_PASSWORD anymore, see
# docs/PHASE3A_IDENTITY_AND_INSTRUCTOR_ACCESS.md):
cd api
PLATFORM_DB_URL=postgres://postgres:postgres@localhost:5433/rootnode_platform \
node bootstrap-owner.js [email protected] "Your Name" "a-real-password-12-chars-plus"
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 (sign in with the owner account you just bootstrapped, then create
further instructor accounts from the Instructors tab).
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.test/e2e-phase3a.js— persistent sessions (including a real Platform API restart), instructor auth (no enumeration, rate limiting), RBAC across owner/admin/instructor, cohort-scoped instructor access, CSRF enforcement, password change, and audit logging.test/e2e-phase3b.js— attempt telemetry, progressive hint sequencing/persistence through a Lab reset, curriculum stage/Capstone lock-unlock, the exam engine (random draw, server timer, expiry, restart persistence), the Capstone workflow end to end, two-student assessment isolation, and instructor learning analytics/RBAC.
All four e2e suites need OWNER_EMAIL / OWNER_PASSWORD set to a real bootstrapped instructor
account (see "Running the full stack locally" above) — the old ADMIN_PASSWORD mechanism is
gone. They're slow (real k3s boots, e2e-phase3b.js also runs a real API restart) and need the
full stack up. None of them substitute 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), docs/PHASE3A_IDENTITY_AND_INSTRUCTOR_ACCESS.md (Phase 3A identity limitations), and
docs/PHASE3B_LEARNING_AND_ASSESSMENT.md §20 (Phase 3B learning/assessment limitations) for the
full, honest lists. Phase 3B's "no automatic abandoned-attempt detection" and "no per-cohort
needs-attention threshold configuration" limitations were both closed in Phase 4.1 (§13/§17 of
docs/PHASE4_1_PREPRODUCTION_HARDENING.md); its raw-JSON pool_spec limitation was replaced with
a structured editor (§18) with an owner-only raw-JSON fallback still available. Phase 4.1's own
known limitation: real remote/self-paced delivery needs student email/password authentication,
not built — see docs/REMOTE_AND_SELF_PACED_ARCHITECTURE.md.
Running this in production
../infra/ has the full production infrastructure package (Ansible, Terraform, firewall,
monitoring, backup, CI/CD) for deploying the Platform API/Gateway/Provisioner/Postgres onto a
dedicated rn-platform-01 VM, with student Labs — and a new lab-router service
(../platform/lab-router/) — on a separate rn-lab-host-01 VM. See
../docs/PHASE4_PRODUCTION_INFRASTRUCTURE.md for the overview and
../docs/PHASE4_1_PREPRODUCTION_HARDENING.md for how Gateway-to-Lab reachability across two
real VMs was closed (a Lab Host Router + mTLS data plane, simulation-tested in
../infra/scripts/simulate-two-host/) and for the rest of Phase 4.1's pre-production hardening.