Add group-class enrolment (year commitment, capacity, registration gate) #21

Merged
thatguygriff merged 1 commits from feature/group-classes into main 2026-06-07 14:49:41 +00:00
Owner

Implements #4 (Group classes) — year-commitment enrolment reusing the registration gate built in #3.

Backend

  • Schema: us_group_enrollments table.
  • Enrollment value object (active/cancelled/completed) + EnrollmentRepositorycountActiveForOffering + hasActiveEnrollment (capacity + duplicate guards), per-student/per-instructor/all-active queries, updateStatus.
  • EnrollmentEndpoint: GET /enrollments (student / instructor / studio-admin scoped) and POST /enrollments — validates the offering is a group_class, enforces capacity and no-duplicate, runs the reused RegistrationGate (intake questions + booking-scoped policies), creates the enrolment (status = active), records answers/acceptances (type enrollment).

Admin & front end

  • Group Classes admin page (view_all_lessons) listing active enrolments.
  • [us_group_classes] shortcode (GroupClassPage) + group-classes.js: lists open group classes → questions + policies enrol form → POST /enrollments.

Payment seam

Deferred to #7: an enrolment lands status = active, payment_id = null. The pay→confirm + receipt step plugs in later.

Notes

  • JS left untested, keeping parity with the repo's no-build vanilla-JS posture (business rules are enforced and tested server-side in RegistrationGate/endpoints). Adding Jest is a good fit alongside #7 (Stripe JS).
  • Instructor-specific enrolment view (the spec's "under My Lessons") is a follow-up; per-instructor data is already exposed via GET /enrollments.

Tests

  • tests/Unit/GroupClass/Enrollment, EnrollmentRepository.
  • composer test (121 tests), composer cs, PHPStan level 6, and no-debug all pass.

Refs #4

🤖 Generated with Claude Code

Implements **#4 (Group classes)** — year-commitment enrolment reusing the registration gate built in #3. ## Backend - **Schema**: `us_group_enrollments` table. - **`Enrollment`** value object (`active`/`cancelled`/`completed`) + **`EnrollmentRepository`** — `countActiveForOffering` + `hasActiveEnrollment` (capacity + duplicate guards), per-student/per-instructor/all-active queries, `updateStatus`. - **`EnrollmentEndpoint`**: `GET /enrollments` (student / instructor / studio-admin scoped) and `POST /enrollments` — validates the offering is a `group_class`, enforces capacity and no-duplicate, runs the reused **`RegistrationGate`** (intake questions + booking-scoped policies), creates the enrolment (`status = active`), records answers/acceptances (type `enrollment`). ## Admin & front end - **Group Classes** admin page (`view_all_lessons`) listing active enrolments. - `[us_group_classes]` shortcode (`GroupClassPage`) + `group-classes.js`: lists open group classes → questions + policies enrol form → `POST /enrollments`. ## Payment seam Deferred to #7: an enrolment lands `status = active`, `payment_id = null`. The pay→confirm + receipt step plugs in later. ## Notes - **JS left untested**, keeping parity with the repo's no-build vanilla-JS posture (business rules are enforced and tested server-side in `RegistrationGate`/endpoints). Adding Jest is a good fit alongside #7 (Stripe JS). - Instructor-specific enrolment view (the spec's "under My Lessons") is a follow-up; per-instructor data is already exposed via `GET /enrollments`. ## Tests - `tests/Unit/GroupClass/` — `Enrollment`, `EnrollmentRepository`. - `composer test` (121 tests), `composer cs`, PHPStan level 6, and no-debug all pass. Refs #4 🤖 Generated with [Claude Code](https://claude.com/claude-code)
thatguygriff added 1 commit 2026-06-07 14:44:02 +00:00
Add group-class enrolment (year commitment, capacity, registration gate)
CI / Tests (PHP 8.1) (pull_request) Successful in 45s
CI / Coding Standards (pull_request) Successful in 50s
CI / PHPStan (pull_request) Successful in 1m4s
CI / No Debug Code (pull_request) Successful in 2s
CI / Tests (PHP 8.2) (pull_request) Successful in 42s
CI / Tests (PHP 8.3) (pull_request) Successful in 42s
CI / Build Plugin Zip (pull_request) Has been skipped
9cb5207dcd
Implements #4: students enrol in a group_class offering via the same
registration gate as private lessons (intake questions + booking-scoped
policy acceptance). Enrolment is capacity-enforced and prevents duplicates.

- Schema: us_group_enrollments table.
- Enrollment value object + EnrollmentRepository (countActiveForOffering,
  hasActiveEnrollment, per-student/instructor/all-active queries, status).
- EnrollmentEndpoint: GET /enrollments (scoped) and POST /enrollments
  (validates group_class, capacity, no-duplicate; reuses RegistrationGate;
  records answers/acceptances type enrollment).
- GroupClassController + admin page (view_all_lessons): all active enrolments.
- Front-end: [us_group_classes] shortcode (GroupClassPage) + group-classes.js
  enrol flow (list classes -> questions + policies -> POST /enrollments).
- Wiring in Plugin, RestRegistrar, AdminMenu, ShortcodeRegistrar.

Payment is the deferred seam (#7): enrolment lands active, payment_id null.
JS left untested for parity with the repo's no-build vanilla-JS posture.

Tests: tests/Unit/GroupClass/ (Enrollment, EnrollmentRepository).
composer test (121), cs, and PHPStan level 6 all pass.

Refs #4

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
thatguygriff merged commit 9799f7c1e2 into main 2026-06-07 14:49:41 +00:00
thatguygriff deleted branch feature/group-classes 2026-06-07 14:49:41 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Unsupervised/unsupervised-scheduler#21