Files
unsupervised-scheduler/docs/features/student-administration.md
T
thatguygriffandClaude Opus 5 76caf178f0
CI / Tests (PHP 8.1) (pull_request) Successful in 41s
CI / Tests (PHP 8.2) (pull_request) Successful in 40s
CI / No Debug Code (pull_request) Successful in 2s
CI / Coding Standards (pull_request) Successful in 2m55s
CI / PHPStan (pull_request) Successful in 3m1s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m43s
CI / Build Plugin Zip (pull_request) Skipped
Say "student" and "profile" in the UI, not "child" and "family"
Sweep the translatable strings across the frontend templates, the admin
screens, the editor previews and the block inserter entry. Nothing else
moves: the database columns, request parameters, form field names, CSS
classes, the us_family shortcode and the us-scheduler/family block name are
contracts with existing installs and with post content people have already
saved, so renaming them would break sites for no user-visible gain.

Two strings are reworded rather than swapped, because the direct
substitution reads wrong:

- The students list said "Child of Jane" and now says "Managed by Jane".
  "Student of Jane" would read as a teacher's pupil, which is exactly the
  wrong idea in a music studio.
- A managed account is now "a managed student account" rather than "a
  student account", which would not distinguish it from the account holder.

The guardian feature doc gains a short section on the split, so the next
person to work on it does not read the mismatch as drift and "fix" it.

Closes #144

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-07-29 20:34:55 -03:00

96 lines
5.1 KiB
Markdown

# 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 **Profile** column — a child links to their guardian,
a guardian lists their children — and the student screen a **Profile** 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`.