Master overview (PHASE4_PRODUCTION_INFRASTRUCTURE.md) plus five detail docs (PRODUCTION_DEPLOYMENT, PRODUCTION_NETWORK_SECURITY, BACKUP_DR, OBSERVABILITY, CAPACITY_PLANNING), a master PRODUCTION_VALIDATION_CHECKLIST, and 12 runbooks (first deployment, normal deploy, rollback, Postgres restore, VM rebuild for both hosts, Docker TLS rotation, TLS renewal, owner recovery, stuck Lab cleanup, failed migration, backup failure, disk failure, Lab Host resource pressure). PRODUCTION_NETWORK_SECURITY.md prominently documents the one genuine architectural gap this phase surfaced: the Gateway's existing env.internal_ip mechanism for reaching a Lab container assumes Gateway and Lab share a Docker daemon, which breaks once Labs run on a genuinely separate rn-lab-host-01 VM. The network-policy half is built (a firewall allowance for Gateway->Lab-Host on a published port range); the application half (Provisioner/Gateway address handling) is an explicit, reviewed, NOT-YET-BUILT follow-up flagged there rather than silently decided. Updated LAB_ARCHITECTURE.md, ENGINEERING_SOP.md, README.md, and platform/README.md with Phase 4 pointers, consistent with how every prior phase updated these. Status: PHASE 4 BUILD COMPLETE / PRODUCTION DEPLOYMENT PENDING HARDWARE.
90 lines
5.6 KiB
Markdown
90 lines
5.6 KiB
Markdown
# 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.
|
||
- `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 in `docs/LAB_ARCHITECTURE.md` §1.
|
||
|
||
## Running the full stack locally
|
||
|
||
```bash
|
||
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 against `provisioner/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.
|
||
|
||
## 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 on a separate `rn-lab-host-01` VM. See
|
||
`../docs/PHASE4_PRODUCTION_INFRASTRUCTURE.md` for the overview and
|
||
`../docs/PRODUCTION_NETWORK_SECURITY.md` for a known gap in Gateway-to-Lab reachability across
|
||
two real VMs that must be closed before production go-live.
|