New docs/PHASE3B_LEARNING_AND_ASSESSMENT.md covers the attempt/learning-record model, progressive hints (including the Gateway response-rewrite mechanism), curriculum completion rules, the assessment/exam engine and its timer/draw integrity guarantees, the RootNode Capstone design, achievement records, the deliberately minimal versioning model, instructor analytics, the Phase 3B RBAC matrix, security/integrity assumptions, dev/test commands, known limitations, and the Phase 4 boundary. Updates ENGINEERING_SOP.md (roadmap items 2/7/8 now done, new section 12, corrects a stale capstone-placeholder description in section 4), LAB_ARCHITECTURE.md's status line, README.md (corrects the 'Lab image unmodified' claim now that its frontend bundle carries Phase 3B UX, plus new platform properties), platform/README.md, and platform/api/README.md.
91 lines
4.7 KiB
Markdown
91 lines
4.7 KiB
Markdown
# RootNode Academy — Platform API (Phase 3B)
|
|
|
|
Lightweight service: no k3s, no `--privileged`, no Lab terminal runtime. See
|
|
`docs/PHASE2B_ADMIN_AND_PLATFORM_DATA.md` for the original split/migration design,
|
|
`docs/PHASE3A_IDENTITY_AND_INSTRUCTOR_ACCESS.md` for persistent sessions, per-instructor
|
|
accounts, RBAC, and audit logging, and `docs/PHASE3B_LEARNING_AND_ASSESSMENT.md` for attempt
|
|
telemetry, progressive hints, curriculum rules, and the exam/capstone engine — this file is the
|
|
operational reference.
|
|
|
|
## Configuration reference
|
|
|
|
| Variable | Required | Meaning |
|
|
|---|---|---|
|
|
| `PLATFORM_DB_URL` | no (defaults to local dev Postgres) | Postgres connection string |
|
|
| `PROVISIONER_URL` | no | Provisioner base URL |
|
|
| `PROVISIONER_SHARED_SECRET` | **yes** | Internal Provisioner auth — process refuses to start without it |
|
|
| `PLATFORM_API_PORT` | no | Listen port, default 4300 |
|
|
| `FRONTEND_DIST_DIR` | no | Where the built frontend lives — set by the Dockerfile, override for local non-Docker dev |
|
|
| `SCENARIOS_DIR` / `BUNDLES_DIR` / `CURRICULUM_PATH_FILE` | no | Override the default `scenarios/` locations, mainly for local dev outside Docker |
|
|
| `STUDENT_SESSION_TTL_HOURS` / `STUDENT_SESSION_IDLE_HOURS` | no | Default 8h / 2h |
|
|
| `INSTRUCTOR_SESSION_TTL_HOURS` / `INSTRUCTOR_SESSION_IDLE_HOURS` | no | Default 12h / 2h |
|
|
| `COOKIE_SECURE` | no | Set to `1` once served over real HTTPS — adds `Secure` to every session/CSRF cookie |
|
|
| `TRUST_PROXY` | no | Set to `1` once fronted by a trusted reverse proxy — honors `X-Forwarded-For` for `req.ip` (audit `source_ip`, login rate limiting) |
|
|
|
|
There is no `ADMIN_PASSWORD` anymore — instructor accounts live in Postgres (`instructors`
|
|
table), created via `bootstrap-owner.js` for the first one and the admin portal after that.
|
|
|
|
## Local dev
|
|
|
|
```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
|
|
|
|
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"
|
|
```
|
|
|
|
Everything is reachable through the Gateway at `http://localhost:4200` — students at `/`,
|
|
instructors at `/admin` (sign in with the bootstrapped owner). Platform API itself isn't meant
|
|
to be hit directly by a browser (same boundary as the Provisioner relative to Platform API),
|
|
though nothing stops you from curling it directly at `:4300` for local debugging.
|
|
|
|
## Owner bootstrap
|
|
|
|
```bash
|
|
node bootstrap-owner.js <email> <display_name> [password]
|
|
```
|
|
|
|
Prefer `BOOTSTRAP_OWNER_PASSWORD` over the positional argument outside a throwaway local test —
|
|
CLI args can leak into shell history and `ps`. Refuses to run if an active owner already exists
|
|
unless the target email belongs to an existing instructor (the intended recovery path if a
|
|
platform is ever locked out with zero owners: point this at a known instructor account to
|
|
promote them).
|
|
|
|
## SQLite migration
|
|
|
|
One-time cutover, run against the real data volume:
|
|
|
|
```bash
|
|
docker run --rm -v <identity-data-volume>:/data \
|
|
-e SQLITE_PATH=/data/progress.db -e PLATFORM_DB_URL=postgres://postgres:postgres@<host>:5433/rootnode_platform \
|
|
<platform-api-image> node migrate-sqlite.js
|
|
```
|
|
|
|
Always backs up the SQLite file first, is safe to re-run, and writes a JSON report — see
|
|
`docs/PHASE2B_ADMIN_AND_PLATFORM_DATA.md` §2/§3 for the full guarantees and rollback
|
|
procedure. This step is about academic data (students/cohorts/progress) — it has nothing to do
|
|
with instructor accounts, which are Phase 3A-native and start empty until you bootstrap one.
|
|
|
|
## Tests
|
|
|
|
`platform/test/e2e-phase2a.js` (student-flow regression), `platform/test/e2e-phase2b.js` (the
|
|
classroom acceptance workflow), `platform/test/e2e-phase3a.js` (persistent sessions including a
|
|
real restart, instructor auth, RBAC, cohort scoping, CSRF, audit log), and
|
|
`platform/test/e2e-phase3b.js` (attempt telemetry, progressive hints, curriculum/Capstone
|
|
unlock rules, the exam engine including a real restart, two-student assessment isolation,
|
|
instructor analytics). All four need the full stack up and `OWNER_EMAIL` / `OWNER_PASSWORD` set
|
|
to a bootstrapped account — see `platform/README.md`.
|
|
|
|
## Known limitations
|
|
|
|
See `docs/PHASE3A_IDENTITY_AND_INSTRUCTOR_ACCESS.md` "Known limitations" (sessions are
|
|
Postgres-backed and survive a restart, but there's no distributed revocation channel to the
|
|
Gateway's short-lived whoami cache; OIDC/SSO is a documented adapter interface, not a working
|
|
integration yet) and `docs/PHASE3B_LEARNING_AND_ASSESSMENT.md` §20 (no automatic
|
|
abandoned-attempt detection, needs-attention thresholds are fixed constants, `pool_spec`
|
|
authoring is raw JSON in the admin UI).
|