Files
unsupervised-scheduler/docs/features/student-administration.md
T
thatguygriffandClaude Opus 5 b772e1811e Let parents register once and book for their children
A parent registers once and manages lessons for one or more children, who
need no login of their own. A child is a real wp_users row with the student
role but no usable login — so student_id keeps meaning "a WordPress user"
on every table, and booking, credits, policies and enrolments work unchanged.
A us_guardians link table maps guardian to child.

The signup form gains a parent/guardian tick that reveals a block per child,
with the account-signup questions asked per child rather than per guardian
— they describe the student, not the account holder. Signup policies are
recorded once per child with the guardian as the acceptor, which is the
record that actually means something. A family that half-creates is rolled
back entirely rather than leaving a guardian who cannot re-register.

The booking and enrolment forms gain a "Who is this for?" picker listing
children first, so the default selection is never the parent — booking for
the wrong child is correctable, quietly billing a parent for their kid's
lesson is not. POST /bookings and POST /enrollments take an optional
student_id honoured only for that child's guardian; anything else is a 403.
That check is the authorisation boundary of the feature.

Payments and credits gain a payer: the charge names the child it was for and
the guardian who owes it, so per-child reporting is unchanged while notices,
receipts and the payment step reach the parent. Credit is held by the payer,
so one child's cancellation can settle a sibling's charge, and the daily
billing scan sends a guardian one notice covering every child.

Closes #132

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-07-29 16:07:52 -03:00

5.1 KiB

Feature: Student Administration

Overview

A studio-admin area to browse students, drill into one student's history and upcoming activity — lessons and group-class enrolments — and act on their behalf: cancel a lesson, withdraw them from a group class, or fix their account details.

Data Model

No new tables. The views are composed from existing data:

  • Students are WordPress users with the us_student role (get_users, get_userdata).
  • Lessons come from {prefix}us_lessons (with {prefix}us_availability for slot times).
  • Group-class enrolments come from {prefix}us_group_enrollments.
  • Policy acceptances come from {prefix}us_policy_acceptances (with the policy and version tables for titles/numbers).
  • Intake answers come from {prefix}us_question_answers (with {prefix}us_questions for labels).
  • Payments come from {prefix}us_payments.

Admin Interface

Students in wp-admin (manage_students, studio admin only):

  • List — every us_student user: display name, email, registered date, and quick counts (upcoming lessons, active group enrolments). Each row links to the detail view.
  • Detail (?student_id=):
    • Account — display name, email, registered date.
    • Upcoming lessons and Past lessons — split by the linked availability slot's start_dt; each shows date/time, offering, instructor, and status.
    • Group-class enrolments — active/past, with offering title and status.
    • Policy acceptances — every acceptance the student has recorded, newest first: policy title, version, context (account signup / lesson / enrolment), and when it was accepted.
    • Intake answers — every registration-question answer, newest first: question label, answer, and the registration it was given for.
    • Account credit (manage_billing only) — the student's available credit balance plus every credit (date, reason, amount, remaining, status). Credit comes from cancelled paid lessons and is applied automatically to upcoming scheduled billing. See credits.md.
    • Payment history (manage_billing only) — every payment, newest first: date, context, method, status, subtotal, HST, total, and receipt number.

Admin actions (detail view)

All actions are nonce-protected POSTs handled on the detail page:

  • Edit account — display name and email. The email must be valid and not in use by another account.
  • Cancel lesson — on any non-cancelled upcoming lesson. Uses the same path as student-initiated cancellation: the lesson is marked cancelled, the availability slot is freed for rebooking, and a still-pending payment is voided. A paid lesson is credited back to the student's account (see credits.md) rather than refunded.
  • Withdraw — on an active group-class enrolment: marked cancelled (freeing its capacity seat), with the same pending-payment voiding.

Capabilities

  • manage_students — studio admin (administrators inherit it via the user_has_cap filter). No new capabilities or tables.

Implementation

  • Admin controller: Unsupervised\Schedular\Auth\StudentController (list + detail)
  • Templates: templates/admin/students.php, templates/admin/student-detail.php
  • Reuses Booking\BookingRepository::findByStudent + countUpcomingForStudent, Availability\AvailabilityRepository::findById, Offering\OfferingRepository::findById, GroupClass\EnrollmentRepository::findByStudent + countActiveForStudent
  • History sections: Auth\StudentHistory builds the display rows from Policy\AcceptanceRepository::findByStudent, Registration\AnswerRepository::findByStudent, and Payment\PaymentRepository::findByStudent, resolving policy/version titles and question labels (unit-tested with mocked repositories).
  • Actions: Auth\StudentActions — cancel lesson / withdraw enrolment (both refuse records that don't belong to the student, and reuse Payment\PaymentService::voidPending) and account updates via wp_update_user (unit-tested with mocked repositories).
  • Upcoming/past split: Auth\StudentSchedule::partition() (pure, unit-tested)
  • The upcoming/past split is extracted into a small pure helper so it is unit-testable (the controller itself follows the repo convention of not being unit-tested).

Tests

  • tests/Unit/Auth/StudentScheduleTest.php (the pure upcoming/past split helper)
  • tests/Unit/Auth/StudentHistoryTest.php (history display rows + fallbacks)
  • tests/Unit/Auth/StudentActionsTest.php (cancel/withdraw guards + side effects, account validation)
  • findByStudent coverage in tests/Unit/Policy/AcceptanceRepositoryTest.php, tests/Unit/Registration/AnswerRepositoryTest.php, and tests/Unit/Payment/PaymentRepositoryTest.php

Family Relationships

The students list gains a Family column — a child links to their guardian, a guardian lists their children — and the student screen a Family panel. A child's listed email is their guardian's, since a child's own address is an undeliverable placeholder, and the credit balance shown is the payer's, labelled with whose account holds it. See parent-guardian-accounts.md.