# Feature: Instructor Booking Notifications ## Overview An instructor can ask to be emailed whenever someone books one of their private lessons or enrols in one of their group classes. It is **off by default** and set per instructor — the people it emails decide whether they want it. The notice fires whichever way the booking or enrolment was made: a student (or a guardian for their child) doing it themselves through the front-end, or the studio doing it on their behalf from wp-admin. There is no separate "the studio booked it" case to forget — every path funnels through one place per registration type, and the opt-in check lives in the mailer, not at each call site, so no path can drift on who gets mailed. ## Preference `us_notify_on_booking` (user meta) `'1'` or `'0'`, stored against the instructor's WordPress user. Absent — the default for every account — reads as off. Stored as `'0'` rather than deleted when an instructor turns it off, so a deliberate "no" is told apart from never having chosen. Default off because the notification is a new capability: turning it on for every instructor on an existing site the day it ships would mail people who never asked. ## Admin Interface **My Availability → Notifications** (`manage_availability` — every instructor sees their own availability page): - **Email me when someone books a lesson or enrols in one of my group classes** — a single checkbox, off by default, saved on its own form (`usc_action=save_notify`). The page an instructor sets availability on is the one they already visit to shape their teaching schedule, so the preference about that schedule lives beside it. ## What triggers a notice | Registration | Path | Where the notice fires | |---|---|---| | Private lesson | student/guardian REST **and** studio wp-admin form | `Booking\LessonBooker::settle()` — the single step both paths reach once a slot is claimed | | Group class | student/guardian REST | `GroupClass\EnrollmentEndpoint::enroll()`, after the roster row is written | | Group class | studio "Add students directly" (wp-admin) | `GroupClass\GroupClassController::addDirect()`, per student added | A weekly lesson reservation reports the number of occurrences claimed, so a single booking and a term booked at once each read correctly. The notice is an opt-in courtesy, never a step a booking or enrolment depends on: a missing or failed send can never fail a booking that otherwise succeeded, and the mailer returns false (without sending) when the instructor has not opted in, their account is gone, or it carries no email. ## Implementation - `Unsupervised\Schedular\Auth\InstructorNotificationPref` — the per-instructor user-meta preference (`wants()` / `set()`), default off - `Unsupervised\Schedular\Auth\InstructorNotificationMailer` — `notifyLessonBooked()` and `notifyEnrollment()`; the opt-in check and recipient resolution live here - `Unsupervised\Schedular\Booking\LessonBooker::settle()` — fires the lesson notice for both booking paths - `Unsupervised\Schedular\GroupClass\EnrollmentEndpoint::enroll()` — student/guardian enrolment notice - `Unsupervised\Schedular\GroupClass\GroupClassController::addDirect()` — studio enrolment notice - `Unsupervised\Schedular\Availability\AvailabilityController` — reads the preference for the page and saves the toggle (`save_notify`) - `templates/admin/availability.php` — the Notifications checkbox All three consumers take the mailer (and the controller its preference) as a constructor dependency defaulting to a fresh instance, so existing wiring in `Plugin`, `RestRegistrar` and `AdminMenu` is unchanged. ## Tests - `tests/Unit/Auth/InstructorNotificationPrefTest.php` — default-off, opt-in read, string-boolean write, non-user guards - `tests/Unit/Auth/InstructorNotificationMailerTest.php` — sends to an opted-in instructor, weekly occurrence count, and sends nothing when opted out / account gone / no email - `tests/Unit/GroupClass/EnrollmentEndpointTest.php` — a successful enrolment notifies the class instructor - `tests/Unit/Availability/AvailabilityControllerTest.php` — the toggle saves an opt-in and an opt-out - The booking-path tests (`BookingEndpointTest`, `AdminBookingTest`) inject a mock mailer, keeping them about booking ## Related - `lesson-booking.md` — the booking core the lesson notice hangs off - `group-classes.md` — the enrolment paths the class notice hangs off - `user-roles.md` — the instructor role and `manage_availability` capability