# Flow: Booking

**Actors**: Patient, Doctor (receives), Clinic Admin/Receptionist (receives)
**Phase**: 2 (`05-roadmap.md`)

## Steps

1. **Patient searches.** `Site\Clinic\SearchController::index()` — filters by specialty and/or
   branch. If both are given, results are doctors matching both (join across `clinic_doctor_branch`
   filtered by `doctor.specialty_id` AND `branch_id`). If only a branch is given, all doctors at
   that branch across all specialties.

2. **Patient views a doctor's profile.** `Site\Clinic\DoctorProfileController::show()` — shows
   bio, per-branch prices, ratings (`Review` aggregate), and available slots.

3. **Patient completes their medical profile, if not already done.**
   `Site\Clinic\PatientProfileController` — required before the first booking, per the brief
   ("rest of the data collected at first booking"). Skipped on subsequent bookings.

4. **Patient chooses visit type and a slot.** `type = visit` or `type = online`.
   `BookingService::availableSlots($doctorBranch, $date)` — reads `DoctorSchedule` rows for that
   `DoctorClinic` pairing, subtracts already-booked `clinic_bookings` slots for that doctor/branch/
   date, returns open slots at `slot_duration_minutes` intervals.

5. **Patient submits the booking.** `Site\Clinic\BookingController::store()` →
   `BookingService::create()` — creates a `Booking` row, `status = 'pending'`, `price` and
   `duration_minutes` snapshotted from `DoctorClinic` at this moment.

6. **Payment.** Redirects into `flows/03-payment-flow.md`. On success, `Booking.status` becomes
   `'confirmed'`.

7. **Booking becomes visible to staff.** Once `confirmed`, the booking appears automatically (no
   separate notification-only step — it's a live query) in:
   - `Doctor\ScheduleController::index()` for the assigned doctor, and
   - `Admin\Clinic\BookingController::index()` for the branch's Clinic Admin/Receptionist
     (branch-scoped per `03-permissions-and-roles.md`).
   Both also receive a `NotificationService`-dispatched notice.

## Cancellation / reschedule (patient-initiated, within policy)

- `Site\Clinic\MyBookingController::cancel()` — allowed only if `now() < scheduled_at - policy_window`
  (default 24h, from `clinic.policies.*`); sets `status='cancelled'`, `cancelled_at`, `cancel_reason`.
- `Site\Clinic\MyBookingController::reschedule()` — allowed only if `now() < scheduled_at - reschedule_window`
  (default 12h); creates a **new** `Booking` row with `rescheduled_from_id` pointing at the
  original, and cancels the original.

## Cancellation (staff-initiated)

- `Admin\Clinic\BookingController::cancel()` — Clinic Admin/Receptionist can cancel any booking
  in their branch regardless of the patient-facing time window (an operational override, e.g.
  doctor unavailability) — logged with the acting admin as `created_by`/an activity log entry.

## Business rules from the brief

- A booking can also be created **manually by a Receptionist** on the patient's behalf
  (`Admin\Clinic\BookingController::store()`, same `BookingService::create()`, `created_by` set
  to the acting admin) — the brief explicitly allows staff-entered bookings, not just
  self-service ones.
- Sending a chat inquiry to a doctor is explicitly **not** a booking — see `05-chat-flow.md`.
