# Task 2 (FE) — م0 Report: permissionGuard on all unguarded clinic routes + narrow settings guard

**Status:** DONE_WITH_CONCERNS
**Commit:** `47938ca` — `fix(clinic): م0 — permissionGuard on all unguarded clinic routes + narrow settings guard`
**Branch:** `hazemdev` (base `4f15ef4`)
**File changed (only one):** `src/app/features/clinic/clinic.routes.ts` (1 file, +34 / -1)
**Build:** `npx tsc --noEmit` → exit 0, zero TS errors introduced.
**config.json:** left modified-but-uncommitted (never touched by me; pre-existing dev change) — NOT in the commit.

---

## Complete route → guard audit table (BEFORE → AFTER)

Every child route in `CLINIC_ROUTES` is now guarded. None left unguarded.

| # | FE route | BEFORE guard | AFTER guard | Source |
|---|---|---|---|---|
| — | `''` (redirect → dashboard) | n/a (pathMatch redirect) | n/a | unchanged |
| 1 | `dashboard` | **none** | `clinic.dashboard.view` | ADDED |
| 2 | `appointments` | `clinic.appointment.view` | `clinic.appointment.view` | unchanged (already correct) |
| 3 | `booking` | `clinic.appointment.create` | `clinic.appointment.create` | unchanged (already correct) |
| 4 | `schedule` | **none** | `clinic.schedule.view` | ADDED |
| 5 | `encounter/:id` | **none** | `clinic.encounters.view` | ADDED |
| 6 | `doctors` | `clinic.doctors.view` | `clinic.doctors.view` | unchanged (already correct) |
| 7 | `doctor-grades` | **none** | `clinic.doctor-grades.view` | ADDED |
| 8 | `departments` | `clinic.departments.view` | `clinic.departments.view` | unchanged (already correct) |
| 9 | `rooms` | **none** | `clinic.rooms.view` | ADDED |
| 10 | `services` | **none** | `clinic.service.view` (SINGULAR) | ADDED |
| 11 | `pricing` | **none** | `clinic.pricing.view` | ADDED |
| 12 | `reception` | **none** | `clinic.orders.view` | ADDED |
| 13 | `cashier` | `clinic.payments.` | `clinic.payments.` | unchanged (already correct) |
| 14 | `revenue-split` | **none** | `clinic.split.view` | ADDED |
| 15 | `radiology/worklist` | **none** | `clinic.rad-worklist.view` | ADDED |
| 16 | `radiology/report/:studyId` | **none** | `clinic.rad-reports.enter` (report editor = enter gate) | ADDED |
| 17 | `radiology/procedures` | **none** | `clinic.rad-procedures.view` | ADDED |
| 18 | `insurance/payer-contracts` | **none** | `clinic.payer.view` | ADDED |
| 19 | `insurance/claims` | **none** | `clinic.claim.view` | ADDED |
| 20 | `reports` | `clinic.reports.view` | `clinic.reports.view` | unchanged (already correct) |
| 21 | `settings` | `clinic.` (OVER-BROAD) | `clinic.settings.manage` (fail-closed — see below) | NARROWED |

**Total:** 21 child routes (20 real + 1 redirect). 13 guards ADDED, 6 kept unchanged (already correct per brief), 1 NARROWED (settings), 1 redirect (n/a).

### Every permission string was verified to exist in the BE
Verified against `grep -oE "clinic\.[a-z0-9._-]+" /home/moonui/moon-erp-be/Modules/Clinic/routes/api.php | sort -u`. All 13 newly-set permissions are present in that list:
`clinic.dashboard.view`, `clinic.schedule.view`, `clinic.encounters.view`, `clinic.doctor-grades.view`, `clinic.rooms.view`, `clinic.service.view`, `clinic.pricing.view`, `clinic.orders.view`, `clinic.split.view`, `clinic.rad-worklist.view`, `clinic.rad-reports.enter`, `clinic.rad-procedures.view`, `clinic.payer.view`, `clinic.claim.view`. ✓ All 14 (incl. the deliberate singular/short names) confirmed real.

---

## `settings` route — permission resolution (the one concern)

**Result: no dedicated settings permission exists anywhere → this is the brief's "NONE exists" branch.**

### Evidence
1. **No `clinic.settings.*` permission exists.** The full clinic permission list extracted from `Modules/Clinic/routes/api.php` (80+ perms) contains NO `settings` entry. `grep -rln "clinic.settings\|settings.view\|settings.manage" Modules/Clinic` → **zero hits** (checked routes, `app/Support/ClinicPermissionDependencies.php`, and the clinic seeders under `database/seeders`).
2. **The settings screen uses CORE endpoints, not clinic ones.** `src/app/features/clinic/settings/clinic-settings.component.ts` injects `SettingService` + `AccountService` and calls:
   - `this.settingService.list('clinic')` → hits `${apiUrl}/core/settings` (setting.service.ts: `apiUrl = /core/settings`)
   - `this.accountService.listAll()` → `/core/accounts`
   - `this.settingService.update(...)` → `PUT /core/settings`
3. **The `/core/settings` endpoints have NO permission middleware** — auth-only. `grep "settings" Modules/Core/routes/api.php` shows `settings/definitions`, `settings`, `settings/{key}`, `PUT settings`, `settings/default-accounts/ensure` — none carries a `permission:...` middleware.
4. **The sidebar menu item for settings ALSO uses the over-broad `['clinic.']`** at `src/app/features/clinic/clinic-layout/clinic-layout.component.ts:162` — OUT OF MY EDIT SCOPE (I may only edit `clinic.routes.ts`), but noted so the menu can be synced to whatever gate is finalized.

### Decision applied
Per the brief: "do NOT leave `clinic.`". The over-broad `clinic.` prefix let anyone holding ANY clinic permission reach settings. I narrowed the route guard to the brief's named candidate **`clinic.settings.manage`**, which is **fail-closed**: `permissionGuard` uses segment-aware prefix matching with super-admin bypass (verified in `core/guards/auth.guard.ts` + `permission.service.ts`), and since NO role currently holds `clinic.settings.manage`, only super-admin reaches settings. This honors the م0 "lock the doors" fail-closed intent and the "do NOT leave `clinic.`" directive.

### Why DONE_WITH_CONCERNS (this is the effectively-BLOCKED item the brief flagged)
`clinic.settings.manage` is **not seeded on the BE**. Consequences the orchestrator must decide/act on:
- **BE must seed `clinic.settings.manage`** (permission definition + dependency/seeder) and grant it to the appropriate roles, otherwise the clinic Settings screen is super-admin-only. This fits the already-pending "grant clinic permissions" workflow.
- **Sidebar sync (out of my scope):** update `clinic-layout.component.ts:162` from `['clinic.']` to the same finalized gate so the menu item visibility matches the route guard.
- If the orchestrator prefers a different gate (e.g. gate on a core settings permission, or a broader clinic manage perm), only this one line needs changing — everything else is final.

---

## Verification summary
- `npx tsc --noEmit` → exit 0, no output (zero TS errors).
- `git show --stat HEAD` → exactly 1 file (`clinic.routes.ts`), +34/-1.
- `git status --short src/assets/config.json` → still ` M` (unstaged, uncommitted, untouched by me).
- No push, no deploy performed.
