- classroom.js: create/start/end/cancel (DB-level partial unique index guarantees at most one
live classroom per cohort; app layer catches 23505 and returns a clean ALREADY_LIVE), join/
leave/heartbeat, derivePresence (pure, derived from last_seen_at at read time — no stored
status to go stale), help-request create/acknowledge/resolve, announcements, current-activity
(guidance only, never redirects a browser or marks work complete), append-only event log.
- admin-classroom-routes.js: instructor-facing classroom API, RBAC via rbac.js's
requireClassroomAccess/requireClassroomWriteAccess/requireHelpRequestWriteAccess (resolves
through to the classroom's cohort, same owner/admin/instructor/viewer rules as everywhere
else cohort-scoped). The dashboard route (GET /api/admin/classroom-sessions/:id) combines
real Provisioner Lab state and real academic records with classroom.js's own data — no
second Lab-state or academic-state system.
- classroom-routes.js: student-facing API (live classroom, join/leave/heartbeat, help-request,
announcements), requireEnrolledClassroom middleware.
- prepare-labs.js: shared prepareLabsForCohort, extracted so the existing cohort-level and new
classroom-level Prepare Labs routes share one implementation; maps Phase 4.1 admission
control's CAPACITY_EXCEEDED into a capacity_waiting per-student result.