# Full System Plan — Clinic Booking Module (Start to End)

One continuous, linear plan for building the whole multi-clinic booking system inside this ERP,
from the very first migration to a working mobile app with video consultations. The other 25
files in this folder hold the field-by-field/step-by-step detail; this file is the single
straight-through read that ties them together in build order, including the **Phase 0
foundations step that wasn't previously called out as its own checklist**.

Every decision here was made by exploring this actual codebase (not generic Laravel advice) and,
where it was a genuine fork, confirmed with the user — see `README.md` for the three confirmed
decisions (new `clinic_payments` table, Laravel Reverb for chat, Agora for video).

---

## The system in one paragraph

A multi-clinic booking platform inside the existing ERP. Five roles: **Super Admin** (platform
owner), **Clinic Admin** (runs one clinic/branch), **Receptionist** (optional, limited ops role),
**Doctor** (own portal, own patients), **Patient** (site customer + medical profile). A patient
searches by specialty and branch, books a clinic visit or online video consultation with a
doctor, pays online, gets diagnosed/prescribed, can chat with the doctor, and rates the doctor
and clinic afterwards. Full business rules: see the project-details PDF/artifact delivered
earlier in this conversation.

## The reuse principle (read `00-overview.md` for the full table)

This module is built by **extending existing ERP infrastructure wherever it already fits**, and
only adding new infrastructure where nothing comparable exists:

| Reused as-is or extended | Genuinely new |
|---|---|
| `Core\Branch` → extended via new `ClinicProfile` (1:1) | `doctor` auth guard (mirrors `employee` guard exactly) |
| `Admin` model + Spatie roles/permissions (`admin` guard) | `admins.branch_id` column + branch-scoping logic (doesn't exist anywhere yet) |
| `User` model (`web` guard) → extended via new `PatientProfile` (1:1) | `clinic_payments` table (isolated from the `SalesOrder`-coupled `PaymentTransaction`) |
| `PaymentGatewayManager` + gateway adapters | Laravel Reverb (real-time chat) |
| `NotificationService` (`DatabaseNotification::create()` pattern) | Agora (video consultations) |
| `System\ActivityLog` (edit history for prescriptions) | Laravel Sanctum + `routes/api.php` (mobile app) |

---

## Phase 0 — Foundations (infrastructure only, no UI, do this first)

Nothing user-visible happens in this phase. It exists so every later phase can assume the
plumbing is already in place. Estimated as a single focused work session.

**Dependencies**
- [ ] `composer require laravel/sanctum` (needed by Phase 5, safe to install now)
- [ ] Confirm `spatie/laravel-permission` is present (it already is — no action)

**Config**
- [ ] `config/auth.php` — add the `doctor` guard (`driver: session, provider: clinic_doctors`) and
  the `clinic_doctors` provider (`driver: eloquent, model: App\Models\Clinic\Doctor`), copying the
  `employee`/`employees` block exactly.
- [ ] `bootstrap/app.php` — register the `doctor.active` middleware alias (copy of
  `'employee.active' => EnsureEmployeeActive::class`, pointing at a new `EnsureDoctorActive`).

**Middleware**
- [ ] `app/Http/Middleware/EnsureDoctorActive.php` — copy of `EnsureEmployeeActive.php`, swap the
  guard to `doctor`.
- [ ] `app/Models/Clinic/Scopes/ClinicBranchScope.php` + `app/Models/Clinic/Concerns/BelongsToClinicBranch.php`
  — new branch-scoping global scope, see `03-permissions-and-roles.md` for the exact design (no
  existing pattern to copy — this is new).

**Migrations** (run in this order — see `02-database-schema.md` for full column definitions of
every new table)

- [ ] `..._add_branch_id_to_admins_table.php` (alter `admins`)
- [ ] `..._create_clinic_profiles_table.php`
- [ ] `..._create_clinic_specialties_table.php`
- [ ] `..._create_clinic_doctors_table.php`
- [ ] `..._create_clinic_doctor_branch_table.php`
- [ ] `..._create_clinic_doctor_schedules_table.php`
- [ ] `..._create_clinic_patient_profiles_table.php`
- [ ] `..._create_clinic_bookings_table.php`
- [ ] `..._create_clinic_payments_table.php`
- [ ] `..._create_clinic_medical_records_table.php`
- [ ] `..._create_clinic_reviews_table.php`
- [ ] `..._create_clinic_chat_messages_table.php`
- [ ] `..._create_clinic_offers_table.php`

**Models** (empty/skeleton classes are fine at this point — full definitions land as each phase
that uses them is built, per `models/*.md`)
- [ ] `App\Models\Clinic\{ClinicProfile,Specialty,Doctor,DoctorClinic,DoctorSchedule,PatientProfile,Booking,Payment,MedicalRecord,Review,ChatMessage,Offer}`

**Permissions & roles**
- [ ] Add the full `clinic.*` permission block to `database/seeders/RolePermissionSeeder.php`
  (exact keys in `03-permissions-and-roles.md`), add Arabic titles to `arabicPermissionSegments()`.
- [ ] Add `Role::findOrCreate('Clinic Admin', 'admin')` and `Role::findOrCreate('Receptionist', 'admin')`
  with their permission subsets.
- [ ] Add the full `clinic.*` set to the existing `Super Admin` role's `givePermissionTo()` call.
- [ ] Re-run the seeder.

**Route files**
- [ ] Create `routes/doctor.php` (copy `routes/portal.php`'s structure, guard `employee`→`doctor`,
  prefix `portal`→`doctor`, controllers `Portal\*`→`Doctor\*`). Require it from `routes/web.php`
  next to `require __DIR__.'/portal.php';`.
- [ ] Add an empty `App\Http\Controllers\Doctor\Auth\AuthenticatedSessionController` (login/logout
  only) so the route file resolves — full controller in Phase 3.

**Sidebar**
- [ ] Add the "Clinic" section skeleton to `resources/views/dashboard/admin/layouts/main-sidebar.blade.php`
  (`$isClinic` flag + accordion block), even with placeholder links — fill in as each screen ships.

**Phase 0 definition of done**: `php artisan migrate` runs clean, the permission seeder adds the
new roles/permissions without errors, `config/auth.php` has a working `doctor` guard (even with
no doctors yet), and the sidebar shows an (empty) Clinic section to a Super Admin. Commit here.

---

## Phase 1 — Early Pages: Clinic & Doctor setup (Super Admin, Clinic Admin)

Full detail: **`04-early-pages.md`**. Pure internal setup, no patient/doctor-facing UI yet.

- [ ] Specialties CRUD (Super Admin) — build first, nothing else depends on data existing yet
      it's a dependency of everything else.
- [ ] Clinics CRUD (Super Admin) — creates a `Branch` + `ClinicProfile` + first `Clinic Admin`
      account together.
- [ ] Doctors CRUD (Clinic Admin, branch-scoped) — creates/links a `Doctor` + one `DoctorClinic`
      pivot row (price, slot duration) for the acting admin's branch.
- [ ] Doctor Schedules (Clinic Admin) — weekly recurring slots per `DoctorClinic` pairing.
- [ ] Sidebar entries wired to real routes, permission-gated.

**Phase 1 definition of done** (verbatim from `04-early-pages.md`): a Super Admin can create a
clinic (which also creates its Clinic Admin account), log in as that Clinic Admin (scoped to only
that branch), add a specialty-linked doctor, and configure that doctor's weekly schedule and
prices for that branch. Commit here.

---

## Phase 2 — Patient-facing booking & payment

Full detail: **`05-roadmap.md`** (Phase 2 section), **`flows/02-booking-flow.md`**,
**`flows/03-payment-flow.md`**, **`models/PatientProfile.md`**, **`models/Booking.md`**,
**`models/Payment.md`**.

- [ ] `PatientProfile` model + medical-profile form (`Site\Clinic\PatientProfileController`)
- [ ] `Booking` model + `BookingService::availableSlots()`
- [ ] Search (`Site\Clinic\SearchController`) + public doctor/clinic profile page
- [ ] Booking creation (`Site\Clinic\BookingController`) — visit or online, slot-availability enforced
- [ ] `Payment` model + `Site\Clinic\BookingPaymentController` wrapping `PaymentGatewayManager`
      (hosted checkout → return → webhook, mirroring the existing Site e-commerce checkout)
- [ ] My Bookings (`Site\Clinic\MyBookingController`) — cancel/reschedule within policy window
- [ ] Admin-side `Admin\Clinic\BookingController` + `PatientController` (branch-scoped, no medical fields)
- [ ] Cancellation/reschedule policy read from `clinic.policies.*` (Super Admin default)

**Phase 2 definition of done**: a patient completes their medical profile, searches a doctor by
specialty+branch, books a clinic visit, pays, and sees it in "My Bookings"; the right Clinic
Admin/Receptionist and the right Doctor can see the confirmed booking. Commit here.

---

## Phase 3 — Doctor portal

Full detail: **`05-roadmap.md`** (Phase 3 section), **`flows/04-visit-consultation-flow.md`**,
**`models/Doctor.md`**, **`models/MedicalRecord.md`**.

- [ ] `Doctor\Auth\AuthenticatedSessionController` (full login/logout, `guest:doctor`/`auth:doctor`+`doctor.active`)
- [ ] `resources/views/doctor/layouts/app.blade.php` + `auth/login.blade.php` (mirrors `resources/views/portal/`)
- [ ] `Doctor\DashboardController`, `Doctor\ScheduleController` — bookings across all their branches
- [ ] `Doctor\PatientController` — own patients: basic data + medical history (read)
- [ ] `MedicalRecord` model + `Doctor\VisitController` — diagnosis/prescription/report, editable
      later with an `ActivityLog` entry + patient notification on edit
- [ ] `Site\Clinic\MedicalRecordController` — patient reads their own prescriptions/reports

**Phase 3 definition of done**: a doctor logs into their own portal, sees only their own
bookings/patients, records a diagnosis+prescription+report for a completed visit, edits it later
(patient gets notified), and the patient can read it. Commit here.

---

## Phase 4 — Chat, Reviews, Reports, Offers

Full detail: **`05-roadmap.md`** (Phase 4 section), **`flows/05-chat-flow.md`**,
**`flows/06-rating-flow.md`**, **`flows/07-admin-monitoring-flow.md`**, **`models/ChatMessage.md`**,
**`models/Review.md`**, **`models/Offer.md`**.

- [ ] Install & configure **Laravel Reverb** (`BROADCAST_CONNECTION=reverb`)
- [ ] `ChatMessage` model + `ChatService` + `NewClinicChatMessage` broadcast event
- [ ] `Doctor\ChatController` + `Site\Clinic\ChatController` (with image/file attachments,
      reusing the existing upload trait(s))
- [ ] `Review` model + `Site\Clinic\ReviewController` — two-step rating, unlocked once a booking
      is `completed`
- [ ] `ReviewService` — recompute doctor average + `ClinicProfile.avg_rating` on new review
- [ ] `Admin\Clinic\Reports\ClinicReportController` — bookings/revenue/performance/ratings,
      filterable by branch+period (mirrors existing Finance/HR report controllers)
- [ ] `Offer` model + `Admin\Clinic\OfferController` (Super Admin platform-wide, Clinic Admin
      branch-local, same branch-scoping rule as everywhere else)

**Phase 4 definition of done**: doctor and patient message each other in near-real-time; a
patient rates the doctor then the clinic after a completed booking and both averages update;
Super Admin and Clinic Admin each see the reports/offers relevant to their scope. Commit here.

---

## Phase 5 — Mobile API + Video Consultations

Full detail: **`05-roadmap.md`** (Phase 5 section), **`flows/04-visit-consultation-flow.md`**
(online-consultation section).

- [ ] Publish Sanctum config, create `routes/api.php`, register it in `bootstrap/app.php`'s `withRouting()`
- [ ] `Api\Clinic\*` controllers mirroring `Site\Clinic\*` + `Doctor\*` as token-authenticated JSON endpoints
- [ ] Agora project set up (outside this codebase) + `AgoraTokenService` (join tokens keyed by
      `clinic-booking-{id}` channel, per role)
- [ ] `Doctor\ConsultationController` + `Api\Clinic\ConsultationController` — issue token,
      start/end the consultation, flip `Booking.status` to `completed` on end
- [ ] Push notifications (FCM) for booking confirmation + pre-appointment reminder — a new
      delivery channel layered on the existing `NotificationService`, not a replacement for it

**Phase 5 definition of done**: the mobile app authenticates, searches/books/pays, and both sides
can join a live Agora video consultation at the scheduled time; push notifications fire for
booking confirmation and a reminder. Commit here — **this completes the system**.

---

## Cross-cutting rules that apply in every phase

1. **Medical data firewall.** `clinic_medical_records` and the medical fields on
   `clinic_patient_profiles` are never selected, loaded, or exposed by any `Admin\Clinic\*`
   controller/service/view, regardless of role or branch scope — only `Doctor\*` and
   `Site\Clinic\*` (the patient's own data) ever touch them. Review this on every PR that touches
   either table.
2. **Branch scoping.** Every Clinic Admin/Receptionist-facing list/detail screen must go through
   the `ClinicBranchScope`/policy checks from `03-permissions-and-roles.md` — never a raw
   unscoped query, even "just for now."
3. **Price/duration snapshotting.** Anything that becomes part of a `Booking` (price, slot
   duration) is copied at booking time, never looked up live from `DoctorClinic` afterwards.
4. **Notifications.** Every new system event (booking confirmed, payment failed, new chat
   message, new review, medical record edited) goes through `NotificationService`'s existing
   `DatabaseNotification::create()` pattern — no new notification mechanism gets introduced.
5. **One phase, one commit (or a few focused commits).** Each phase above ends with a working,
   demonstrable slice of the system — don't start the next phase with the previous one half-done.

## Where to look things up while building

| Need | File |
|---|---|
| "What columns does table X have?" | `models/*.md` (matching model name) |
| "What does controller Y actually do, step by step?" | `flows/*.md` |
| "What permission key gates this route?" | `03-permissions-and-roles.md` |
| "What's the exact folder/namespace for a new controller/service/view?" | `01-module-structure.md` |
| "Is this the first thing to build, or later?" | This file, or `04-early-pages.md` / `05-roadmap.md` |
