The booking flow never asks the student to choose an offering. The front end (assets/js/booking.js) only reads slot.offering_id, and POST /bookings accepts offering_id defaulting to 0.
For any availability slot created without a tied offering ("Offering: none" in the availability form), this means:
the booking is created with no offering at all
no payment is created and the lesson is confirmed immediately, for free
no intake questions are asked
This contradicts docs/features/lesson-booking.md ("Student picks an offering… and a slot") and docs/features/availability-management.md (slot duration "is matched against the offering a student picks" — never enforced).
Fix
Server (Booking\BookingEndpoint):
Reject bookings with no resolvable offering (400 offering_required).
For student-chosen offerings on generic slots, require an activeprivate_lesson offering owned by the slot's instructor whose duration_minutes matches the slot.
Slot tied to an offering → shown locked with title/duration/price so the student sees exactly what they are booking.
Generic slot → required picker of the instructor's active private-lesson offerings that fit the slot length; intake questions load for the selected offering.
Generic slot with no fitting offering → "cannot be booked online" message.
## Problem
The booking flow never asks the student to choose an offering. The front end (`assets/js/booking.js`) only reads `slot.offering_id`, and `POST /bookings` accepts `offering_id` defaulting to `0`.
For any availability slot created **without** a tied offering ("Offering: none" in the availability form), this means:
- the booking is created with **no offering** at all
- **no payment** is created and the lesson is **confirmed immediately, for free**
- **no intake questions** are asked
This contradicts `docs/features/lesson-booking.md` ("Student picks an offering… and a slot") and `docs/features/availability-management.md` (slot duration "is matched against the offering a student picks" — never enforced).
## Fix
**Server (`Booking\BookingEndpoint`):**
- Reject bookings with no resolvable offering (`400 offering_required`).
- For student-chosen offerings on generic slots, require an **active** `private_lesson` offering owned by the slot's instructor whose `duration_minutes` matches the slot.
- Slot-tied offerings remain authoritative (existing anti-tamper behaviour).
**Front end (`assets/js/booking.js`):**
- Registration form gets a **Lesson type** field:
- Slot tied to an offering → shown **locked** with title/duration/price so the student sees exactly what they are booking.
- Generic slot → **required picker** of the instructor's active private-lesson offerings that fit the slot length; intake questions load for the selected offering.
- Generic slot with no fitting offering → "cannot be booked online" message.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
The booking flow never asks the student to choose an offering. The front end (
assets/js/booking.js) only readsslot.offering_id, andPOST /bookingsacceptsoffering_iddefaulting to0.For any availability slot created without a tied offering ("Offering: none" in the availability form), this means:
This contradicts
docs/features/lesson-booking.md("Student picks an offering… and a slot") anddocs/features/availability-management.md(slot duration "is matched against the offering a student picks" — never enforced).Fix
Server (
Booking\BookingEndpoint):400 offering_required).private_lessonoffering owned by the slot's instructor whoseduration_minutesmatches the slot.Front end (
assets/js/booking.js):