feat(platform): business/product architecture — organizations, guardians, offerings, registrations

- organizations, locations, guardians, student_guardians (033) — additive, no existing
  table's meaning changes. Widens programs.family to accept 'bootcamp'.
- curriculum_packages/curriculum_package_items, offerings, instructor_offerings,
  offering_registrations, agreement_definitions/agreement_acceptances (034) — the full
  purchasable-delivery model. Server-defined status transitions only (no client-controlled
  offering/registration status). Capacity uses a single atomic UPDATE (reserved_seats),
  never a SELECT-count-then-INSERT race.
- offerings.js — business logic: reserveSeat/releaseSeat, transitionOffering/
  transitionRegistration (fixed transition tables), convertRegistrationToEnrollment
  (reuses enrollment.js's existing resolveOrCreateStudent/createManualEnrollment rather
  than duplicating student-matching logic).
- enrollment.js — resolveOrCreateStudent gains an optional, default-off returnToken param
  (used only by offerings.js's admin-only conversion route; the public website integration
  endpoint's contract is completely unchanged, per docs/WEBSITE_ENROLLMENT_INTEGRATION.md).
- admin-offerings-routes.js — the full admin/owner API surface. Registration/guardian
  detail is admin/owner only; offering/location listing is any instructor (access_notes
  stripped for a plain instructor).
- A real bug found and fixed during this phase's own smoke testing before any commit: the
  registration route originally reserved a seat BEFORE validating the registration's own
  fields, letting a validation failure consume a real seat and get masked behind a false
  OFFERING_FULL under a full offering. Fixed: validate (create) first, reserve second, roll
  back the registration row if reservation then genuinely fails.

See docs/ROOTNODE_ACADEMY_BUSINESS_AND_PRODUCT_ARCHITECTURE.md and
docs/OFFERING_AND_REGISTRATION_MODEL.md.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
2026-08-26 22:43:52 -05:00
co-authored by Claude Sonnet 5
parent d066410451
commit 3510979196
6 changed files with 747 additions and 3 deletions
+8
View File
@@ -413,6 +413,14 @@ require('./notification-routes')(app, {
instructorSession: wrap(instructorSession), rbac, getPool, recordAudit,
});
// Phase 7 — the business/product architecture: organizations, locations, guardians,
// curriculum packages, offerings, registrations, and agreements. Admin/owner surface only —
// no student-facing routes yet (registration is admin-entered this phase; a future public
// registration flow is a Phase 8+ decision, see docs/OFFERING_AND_REGISTRATION_MODEL.md).
require('./admin-offerings-routes')(app, {
instructorSession: wrap(instructorSession), rbac, getPool, recordAudit,
});
// Fallback to the platform-shell SPA for any unmatched non-API route
app.get('*', (req, res) => {
res.sendFile(path.join(FRONTEND_DIST, 'index.html'));