Add feature specs for booking platform requirements
CI / Coding Standards (push) Successful in 2m23s
CI / PHPStan (push) Successful in 59s
CI / Tests (PHP 8.1) (push) Successful in 50s
CI / Tests (PHP 8.2) (push) Successful in 51s
CI / Tests (PHP 8.3) (push) Successful in 48s
CI / No Debug Code (push) Successful in 3s
CI / Coding Standards (push) Successful in 2m23s
CI / PHPStan (push) Successful in 59s
CI / Tests (PHP 8.1) (push) Successful in 50s
CI / Tests (PHP 8.2) (push) Successful in 51s
CI / Tests (PHP 8.3) (push) Successful in 48s
CI / No Debug Code (push) Successful in 3s
Update availability, lesson-booking, and user-roles docs and add specs for offerings, group classes, registration questions, versioned policies, Stripe payments (with e-transfer/comp overrides and receipts), and monthly per-instructor payment reporting. Tracked in issues #1-#9. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,52 +1,72 @@
|
||||
# Feature: Lesson Booking
|
||||
|
||||
## Overview
|
||||
Students browse available slots and submit a booking. Instructors then confirm or cancel from wp-admin or via the REST API.
|
||||
Students register for a private lesson by choosing an offering, picking a time (or reserving a weekly slot for the term), answering the offering's intake questions, accepting current policies, and paying. Instructors confirm or cancel from wp-admin or via the REST API. A lesson becomes `confirmed` only once its payment is `paid` (or the student is comp'd).
|
||||
|
||||
## Data Model — `{prefix}us_lessons`
|
||||
|
||||
| Column | Type | Notes |
|
||||
|----------------|------------------|--------------------------------------------------|
|
||||
| `id` | BIGINT UNSIGNED | Primary key |
|
||||
| `slot_id` | BIGINT UNSIGNED | FK → `us_availability.id` |
|
||||
| `student_id` | BIGINT UNSIGNED | WordPress user ID |
|
||||
| `instructor_id`| BIGINT UNSIGNED | WordPress user ID (denormalised for fast queries) |
|
||||
| `status` | VARCHAR(20) | `pending` / `confirmed` / `cancelled` |
|
||||
| `notes` | TEXT | Optional student notes |
|
||||
| `created_at` | DATETIME | Insertion time |
|
||||
| Column | Type | Notes |
|
||||
|----------------|------------------|-------------------------------------------------------------|
|
||||
| `id` | BIGINT UNSIGNED | Primary key |
|
||||
| `slot_id` | BIGINT UNSIGNED | FK → `us_availability.id` |
|
||||
| `offering_id` | BIGINT UNSIGNED | FK → `us_offerings.id` (the private-lesson type booked) |
|
||||
| `student_id` | BIGINT UNSIGNED | WordPress user ID |
|
||||
| `instructor_id`| BIGINT UNSIGNED | WordPress user ID (denormalised for fast queries) |
|
||||
| `recurrence` | VARCHAR(10) | `single` or `weekly` |
|
||||
| `series_id` | BIGINT UNSIGNED | Nullable — groups the lesson rows of one weekly reservation |
|
||||
| `status` | VARCHAR(20) | `pending` / `confirmed` / `cancelled` |
|
||||
| `payment_id` | BIGINT UNSIGNED | Nullable FK → `us_payments.id` |
|
||||
| `notes` | TEXT | Optional student notes |
|
||||
| `created_at` | DATETIME | Insertion time |
|
||||
|
||||
## Booking Flow
|
||||
1. Student opens the page with `[us_booking]` shortcode.
|
||||
2. JS fetches `GET /availability` → renders available slots.
|
||||
3. Student clicks **Book** → `POST /bookings` with `slot_id`.
|
||||
4. Server creates the lesson row (`status = pending`) and sets `us_availability.is_booked = 1`.
|
||||
5. Instructor sees the booking under **My Lessons** in wp-admin.
|
||||
6. Instructor updates status via `PATCH /bookings/{id}/status`.
|
||||
## Registration Flow
|
||||
1. Student opens the page with the `[us_booking]` shortcode and browses the calendar.
|
||||
2. Student picks an **offering** (a 30 or 60-minute private-lesson type) and a slot.
|
||||
3. For a `weekly` reservation, the same weekday/time is held for the rest of the offering's term.
|
||||
4. Student answers the offering's questions (`GET /offerings/{id}/questions`).
|
||||
5. Student accepts the current published policy versions (`GET /policies`) — required to continue.
|
||||
6. Payment is taken per the student's billing method (card by default; `pending` for e-transfer; skipped for comp). See `payments.md`.
|
||||
7. `POST /bookings` creates the lesson row(s) (`status = pending`), records answers and policy acceptances, marks `us_availability.is_booked = 1`, and links the payment.
|
||||
8. On successful payment (or comp) the lesson is `confirmed` and a receipt is emailed.
|
||||
9. Instructor sees the booking under **My Lessons** and may update status via `PATCH /bookings/{id}/status`.
|
||||
|
||||
## Weekly Reservations
|
||||
A weekly reservation creates one `series_id` shared across N lesson rows (one per
|
||||
week in the term) and reserves the matching availability windows. It is billed
|
||||
**full-term upfront** as a single payment (`billing_mode = full_term` on the
|
||||
offering).
|
||||
|
||||
## REST API
|
||||
| Method | Endpoint | Permission |
|
||||
|-----------|------------------------------------------------|-------------------------------|
|
||||
| `GET` | `/wp-json/us-scheduler/v1/bookings` | Any logged-in user |
|
||||
| `POST` | `/wp-json/us-scheduler/v1/bookings` | `book_lesson` |
|
||||
| `PATCH` | `/wp-json/us-scheduler/v1/bookings/{id}/status`| `manage_availability` or admin |
|
||||
| Method | Endpoint | Permission |
|
||||
|-----------|-------------------------------------------------|--------------------------------|
|
||||
| `GET` | `/wp-json/us-scheduler/v1/bookings` | Any logged-in user |
|
||||
| `POST` | `/wp-json/us-scheduler/v1/bookings` | `book_lesson` |
|
||||
| `PATCH` | `/wp-json/us-scheduler/v1/bookings/{id}/status` | `manage_availability` or admin |
|
||||
|
||||
`POST /bookings` body: `offering_id`, `slot_id`, `recurrence`, `answers[]`
|
||||
(`question_id` → value), `accepted_policy_version_ids[]`, and payment data
|
||||
(see `payments.md`).
|
||||
|
||||
`GET /bookings` returns the caller's own lessons (student view) or upcoming lessons for the instructor if the caller has `manage_availability`.
|
||||
|
||||
Group classes follow the same registration flow but enrol against an offering of
|
||||
kind `group_class`; see `group-classes.md`.
|
||||
|
||||
## Admin Interface
|
||||
- **Scheduler** (`manage_options` only): all upcoming lessons across all instructors
|
||||
- **My Lessons** (`view_own_lessons`): upcoming lessons for the logged-in instructor
|
||||
|
||||
## Frontend Shortcodes
|
||||
- `[us_booking]` — student booking form; requires `book_lesson` capability
|
||||
- `[us_booking]` — student calendar + registration flow; requires `book_lesson` capability
|
||||
- `[us_student_login]` — front-end login form for students
|
||||
|
||||
## Implementation
|
||||
- Repository: `Unsupervised\Schedular\Data\BookingRepository`
|
||||
- Model: `Unsupervised\Schedular\Model\Lesson`
|
||||
- Admin controller: `Unsupervised\Schedular\Admin\LessonController`
|
||||
- REST endpoint: `Unsupervised\Schedular\Api\BookingEndpoint`
|
||||
- Frontend: `Unsupervised\Schedular\Frontend\BookingPage`, `LoginPage`
|
||||
- Repository: `Unsupervised\Schedular\Booking\BookingRepository`
|
||||
- Model: `Unsupervised\Schedular\Booking\Lesson`
|
||||
- Admin controller: `Unsupervised\Schedular\Booking\LessonController`
|
||||
- REST endpoint: `Unsupervised\Schedular\Booking\BookingEndpoint`
|
||||
- Frontend: `Unsupervised\Schedular\Booking\BookingPage`, `Unsupervised\Schedular\Auth\LoginPage`
|
||||
|
||||
## Tests
|
||||
- `tests/Unit/Data/BookingRepositoryTest.php`
|
||||
- `tests/Unit/Model/LessonTest.php`
|
||||
- `tests/Unit/Booking/BookingRepositoryTest.php`
|
||||
- `tests/Unit/Booking/LessonTest.php`
|
||||
|
||||
Reference in New Issue
Block a user