- 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]>