# Flow: Rating (two-step review)

**Actors**: Patient
**Phase**: 4 (`05-roadmap.md`)
**Trigger**: `Booking.status` becomes `'completed'` (see `04-visit-consultation-flow.md` step 4/8)

## Steps

1. Once a booking is `completed`, `Site\Clinic\ReviewController::create(Booking $booking)` becomes
   reachable (guarded: only the booking's own patient, only once — `Review` is 1:1 with `Booking`).
2. **Step one of the UI**: rate the doctor — stars (1–5) + optional comment.
3. **Step two of the UI**: rate the clinic — stars (1–5) + optional comment.
   (Both captured in a single form submission server-side — `ReviewController::store()` writes
   one `Review` row with all four fields at once; the "two steps" are a front-end UX sequence, not
   two separate backend writes, per the brief's screenshot-described two-step *screen*, not two
   separate submissions.)
4. `ReviewService::store()`:
   - Creates the `Review` row.
   - Recomputes the doctor's average rating (aggregate over all `Review.doctor_rating` for that
     doctor's bookings) — surfaced wherever the doctor's rating is displayed.
   - Recomputes `ClinicProfile.avg_rating` (aggregate over all `Review.clinic_rating` for that
     branch's bookings) and persists it on the `ClinicProfile` row (denormalized for fast display
     on clinic listing pages, rather than aggregating on every page load).

## Where each rating is shown

| Rating | Shown on |
|---|---|
| Doctor rating + comments | `Site\Clinic\DoctorProfileController::show()` — the doctor's public profile page, for new patients deciding whether to book |
| Clinic rating + comments | `Site\Clinic\SearchController`/clinic detail page — the clinic's main page |

## Decisions

- No edit/delete of a submitted review in v1 — the brief doesn't call for it. If needed later,
  treat it the same way as `MedicalRecord` edits: allowed, logged, patient-visible edit trail is
  not needed here (the patient *is* the author), but recompute the averages again on any change.
