# G4 — GYN operations: the procedure template (one structure for every operation — TLH / myomectomy / MUS / Burch / POP repair / vNOTES / fistula / CS…) on C1's `clinical_procedures`, findings · complications (Clavien-Dindo) · EBL / products · specimens + histology · media, discharge with ready meds, automatic follow-ups, the operative summary, and centre / hospital mode (link `hospital_surgeries`)

Read `_COMMON.md` first. G4 is **two serial WPs**: G4a (BE: install the 3 p3d modules from the committed schema JSON, the operation fields as **record-scope answers of a `clinical_procedures` row**, the PROC_LIB catalog as `hospital_operations` rows, the Gyn operation facade over C1's `ProcedureService`, discharge presets, the 3 summary templates) → G4b (FE: the operation screen — one card per procedure, procedure-specific sections by show_if, sign, link surgery in centre/hospital mode, the discharge card with presets → the P1 discharge Rx + the P5 discharge document, the follow-up visit card). Like G2/G3, the modules are **definitions in the G1 engine — no table, no component per module**; only the operation card (a C1 entity) gets bespoke UI.

**Depends on:** C1a ✅ (`clinical_procedures` + record-scope answers `record_type=clinical_procedure`, `PUT clinic/records/{type}/{id}/fields`, `ProcedureService` record / update / sign / link-surgery / cancel + `clinic.procedures.mode` external|center|hospital, `ClinicalProcedureSigned` → `GenerateFollowUpsOnProcedureSigned` → `ClinicalTypeRegistry` `gyn_ob.followup_rules.post_procedure` 7d/1m/3m/6m, `hospital_operations.clinical_template_id`), C1b ✅ (`operative` + `discharge` summary types declared for `gyn_ob`; `ClinicalSummaryService::records()` already folds the encounter's procedures' record answers), P5 ✅ (`discharge_summary` authored doc type, `CreateClinicalDocument`, the print engine), P1/P2 ✅ (`PrescriptionKind::Discharge`, `IssuePrescription` — catalog drugs only), G1a/G2a/G3a ✅ (`Modules/Gyn`, `gyn_schema.json` — `operation` / `discharge` / `followup` and `proc_lib` already exported, `GynFieldPackSeeder`, `GynModuleRegistry`, `GynModuleValues`, `GynFieldWriteGuard`, `GynFeatures` `operations`, the JS-fixture approach `export-g3a-fixtures.mjs`). G4b needs G4a ✅, G1b ✅, S1 ✅.

## Spec (read before coding)
- `/home/moonui3/public_html/knowledge-base/plans/gyn-obstetrics-module-src/p3d-schema-op.js` — **the whole file** (PROC_LIB 58 items · `operation` 6 sections ~80 fields with per-procedure show_if · `discharge` · `followup` and their `sum`). `Modules/Gyn/database/data/gyn_schema.json` is its committed machine form (`proc_lib`, `gyn.operation.*`, `gyn.discharge.*`, `gyn.followup.*` lookups — do not hand-edit it). Note: the `media` field is not in the JSON (media = AF3 attachments of the procedure).
- `p4c-scenarios.js` scenario 3 «POP + SUI → Urodynamics → MUS + Anterior repair» (operation · discharge · followup = the only operative fixture; hand-made TLH / myomectomy / endometriosis / vNOTES / Burch / bulking / fistula / complication + Clavien cases); `p4a-engine-calc.js` FLOWS «Operation» + «Discharge & follow-up», SUM_TYPES `operative` / `discharge`, `fmtD`.
- `../design-gyn-integration.md` §2 rows `operations + operation_procedures` (→ core `clinical_procedures` + record-scope template answers, «مفيش جدول بنود»), `follow_up_tasks`, Summary generator; §3 (`operation` = the procedure screen; `PROC_LIB` → `hospital_operations` rows); §7 decisions G4 (default follow-up schedule) / G9 (mode external first, G4 adds centre).
- `../design-data-layers.md` §3 (one answers store; record scope); `../visit-shell-prototype.html` `GYN_SUM` (`operative` / `discharge` = profile, alerts, dx, operation, discharge, followup).
- `../master-plan.md` G4 row (acceptance: **an operation report from the template · the 1 w / 1 m / 3 m / 6 m follow-ups were generated · the same screen when the mode becomes centre**).
- `../legacy-obgy-options-analysis.md` — read-only reference (the old sheet's dated «Operations» table, the clinic/hospital switch). Never connect to the legacy system, never persist its credentials.
- `G1-gyn-foundation.md` decisions 2–8, `G2-gyn-core-modules.md` 7–8, `G3-fertility.md` 3–4 / 9 (record-scope modules, one home per value, templates query their entity) — binding here too.

## Decisions (do not re-litigate)
1. **An operation IS a C1 `clinical_procedures` row** (`clinical_type='gyn_ob'` — mandatory: the C1 listener falls back to `general`, which has no follow-up rule). **The `operation` module fields are record-scope answers** (`record_type='clinical_procedure'`, `record_id=<procedure>`), seeded `scope='record'` (the encounter path refuses them), written through the shared `PUT api/clinic/records/clinical_procedure/{id}/fields`. No new table (deviation from the prototype's per-visit `operation` values; same pattern as G3a cycles).
2. **One home per value — the entity owns its header.** p3 keys with a `clinical_procedures` column are **not seeded** as fields: `date` → `performed_at` (else `scheduled_at`), `surgeon` → `surgeon_name` (`surgeon_id` optional), `place` → `place_name`, `indication` → `indication`, `status` → `signed_at` (Draft / Signed). `procs` → `procedure_codes` (catalog snapshot) **and** a read-only mirror answer `gyn_operation_procs` (`source='derived'`, PROC_LIB codes) written by the facade only — 30+ show_if rules key on it; `GynFieldWriteGuard` refuses any write to it (422 `operation_entity_field`). `approach` / `anesth` stay answers (multi-select / codes longer than the `string(32)`/`string(16)` columns); at **sign** the facade snapshots single-valued `approach` / `anesth` (when they fit), `complications` (`[{code, label, clavien}]`), `specimens` (labels) and `findings` (the Findings line) into the columns — the record is frozen from then on.
3. **PROC_LIB = `hospital_operations` rows** (design §3): `Modules/Gyn/app/Support/GynProcedureCatalog.php` seeds the 58 items per company, create-only by `(company_id, code)` incl. soft-deleted rows (query builder, guarded `hasTable`), `code` = `gyn_` + PROC_LIB code with an alias map for the ones over `varchar(30)` (`gyn_bowel_shaving_disc`, `gyn_mus_retropubic`, `gyn_mus_transobturator`, `gyn_vag_hyst_repair`), `name_en` = the PROC_LIB English string (the summary prints it), `name_ar` = same (the clinic translates), `specialty='gyn_ob'`, `category`/`anesthesia`/`needs_admission` defaults, `clinical_template_id` NULL — **the template of a gyn_ob procedure is the `operation` module** (per-procedure sections via show_if on `procs`); no `clinical_templates` kind is invented. `Operation` model `$fillable` gains `clinical_template_id` (C1a gap). The facade takes `procs` (PROC_LIB codes) → catalog rows → `procedure_codes`; `procedure_codes` items (catalog id / external free text) are also accepted as is.
4. **Lifecycle through C1** (`Modules/Gyn/app/Services/GynOperationService.php`, never a direct column write except the sign snapshot + mirror): record (patient · encounter? · episode? · place · place_name · hospital_surgery_id · performed_at/scheduled_at · procs · surgeon · indication · initial `fields` by code) · update · **sign** (snapshot → `ProcedureService::sign` → `ClinicalProcedureSigned` → the 4 tasks; non-blocking `warnings`: `clavien_missing` when a complication other than None has no Clavien grade) · cancel · link a `hospital_surgeries` row (centre/hospital mode, `ProcedureService::linkSurgery`; the surgery's catalog op becomes `procedure_codes` → the mirror is refreshed) · candidate surgeries of the patient. Mode rules stay C1's (external ⇒ place external, no surgery; hospital ⇒ in-house needs the surgery). **Feature** `gyn.feature.operations` off ⇒ every operation endpoint 422 `gyn_feature_off` and the module fields 422 (existing guard); writing operation fields needs `clinic.procedures.edit` (guard, 403).
5. **Histology after sign = an addendum.** Sign freezes the record (C1a) but the pathology result comes days later: `POST operations/{id}/histology {histo_result[], histo_date}` writes those two record answers on a signed (not cancelled) procedure — needs `clinic.procedures.edit`, logged with activity — the only post-sign write.
6. **Discharge + follow-up stay encounter-scope** (`always:true`, feature null — also used after medical / fertility treatment and by G5's delivery summary). Discharge = answers of the visit that discharges her (usually the procedure's encounter). **Ready meds** = `Modules/Gyn/app/Support/GynDischargePresets.php`: per instruction sheet (`instr_template`) the standard categories + drug rows (drug, dose, route, freq, days) + wound / activity / warning chips — code defaults (doctor to confirm, KB Open) overridable per company in the existing S1 store `clinic.visit_layouts['gyn_ob'].discharge_presets` (no new setting). `POST encounters/{e}/discharge/apply {template, replace?}` writes them as the visit's discharge answers (rows only when empty unless `replace`). The read model returns `rx_draft` (sentence + `route`/`frequency_code` mapped to P1's enums, PV → `other`) for the FE to compose the **P1 discharge Rx** (`POST clinic/encounters/{e}/prescriptions kind=discharge` — catalog drugs are P1's rule; no Gyn Rx endpoint). The **P5 discharge document**: `POST operations/{id}/discharge-document` → `CreateClinicalDocument` draft `discharge_summary` on the procedure's encounter, body = the C1b `discharge` summary of that encounter (needs `clinic.documents.create`; 422 without an encounter).
7. **Follow-ups:** the schedule IS `follow_up_tasks` (C1 rule `post_procedure` 7d/1m/3m/6m on sign) — `gyn_followup_source/schedule/custom_date/status` are **not seeded** (one home). The follow-up visit rows (`followup.visit`, encounter-scope repeat) stay as the JSON: the doctor records the post-op assessment on the follow-up visit. Urogyn 6 w/3/6/12 m (G6) and pregnancy schedules (G5) are theirs.
8. **Summaries** = `Modules/Gyn/app/Summary/{Operation,Discharge,Followup}Template.php`, ported **line by line** from the p3d `sum` (English, identical to the JS). **Operation** renders every non-cancelled gyn_ob procedure of the encounter (p3 shape = record answers + the entity header: `date` = performed_at‖scheduled_at, `procs` = `procedure_codes` names, `surgeon`) joined by a space — it queries the entity like G3a's OI. **Discharge** = the visit's answers (p3 `sum`). **Followup** = the visit's `visit` rows, else «Follow-up scheduled: 1 week, 1 month, 3 months, 6 months (after operation).» from the tasks of the encounter's procedures (offset → the schedule option label). The `operative` / `discharge` types already exist (C1b); `GET operations/{id}/summary` returns the three lines for a procedure without needing the encounter summary.
9. **Permissions:** no new `gyn.*` — the shared `clinic.procedures.view/edit/sign`, `clinic.history.record` (fields), `clinic.documents.create`, `clinic.prescriptions.create`, `clinic.followups.*` (already granted to the doctor set the GYN roles inherit).

## Shared-file rules
- Orchestrator-owned — REPORT: `Modules/Clinic/routes/api.php`, `RolePermissionSeeder.php`, `StandardRolesSeeder.php`, `ClinicPermissionDependencies`, setting seeders, permission-labels, `config/moonstack.php`. You own `Modules/Gyn/routes/api.php`.
- Hot file (one line): `Modules/Hospital/app/Models/Operation.php` `$fillable` + `clinical_template_id`. No Clinic edit is needed in G4a.
- FE i18n (G4b): targeted keys under `GYN.*` only, ar + en; **no `I18N_VERSION` bump**.

---

## G4a — BE (migrations `2026_11_03_400000`–`400099`, in `Modules/Gyn/database/migrations`)

### Files
- `Modules/Gyn/app/Support/GynSchema.php` (+`G4_MODULES`, `PROCEDURE_MODULES`, `PROCEDURE_RECORD_TYPE`, `ENTITY_FIELDS`, `PROCEDURE_MIRRORS`, `G4_SKIP`), `GynFieldWriteGuard.php` (operation permission + entity / mirror fields), `GynExtensions.php` (3 templates), `Services/GynPackInstaller.php` (default set + catalog), `database/seeders/GynFieldPackSeeder.php` (record scope for `operation`, skip list), `Http/Controllers/GynSchemaController.php` (module scope / storage / entity fields), `routes/api.php`, `lang/{ar,en}/gyn.php`.
- New: `Services/GynOperationService.php`, `Support/GynProcedureCatalog.php`, `Support/GynDischargePresets.php`, `Http/Controllers/GynOperationController.php`, `Summary/{Operation,Discharge,Followup}Template.php`, `database/data/tools/export-g4a-fixtures.mjs` → `tests/Fixtures/g4a_expected.json`.
- Migration: `400000_install_gyn_operation_modules` (data, pattern 390000: fields + the PROC_LIB catalog on every gyn_ob company).
- Hospital: `app/Models/Operation.php` fillable.

### Interfaces (`api/gyn`, company-scoped, patient data scope through `Patient::query()`)
| Method | Path | Permission | Body / result |
|---|---|---|---|
| GET | `patients/{patient}/operations?status=` | `clinic.procedures.view` | read models (newest first) |
| POST | `patients/{patient}/operations` | `clinic.procedures.edit` | `{encounter_id?, episode_id?, place?, place_name?, hospital_surgery_id?, performed_at?, scheduled_at?, procs?[] \| procedure_codes?[], surgeon_id?, surgeon_name?, indication?, fields?{code: value}}` → 201 |
| GET | `operations/{procedure}` | `clinic.procedures.view` | read model |
| PUT | `operations/{procedure}` | `clinic.procedures.edit` | header (same keys, partial) |
| POST | `operations/{procedure}/sign` | `clinic.procedures.sign` | snapshot + sign → read model incl. `follow_ups` |
| POST | `operations/{procedure}/cancel` | `clinic.procedures.edit` | |
| POST | `operations/{procedure}/link-surgery` | `clinic.procedures.edit` | `{surgery_id}` |
| GET | `patients/{patient}/surgeries` | `clinic.procedures.view` | the patient's `hospital_surgeries` (id, case_no, operation, scheduled/done, status, linked procedure) |
| POST | `operations/{procedure}/histology` | `clinic.procedures.edit` | `{histo_result[], histo_date?}` (signed allowed) |
| GET | `operations/{procedure}/summary` | `clinic.procedures.view` | `{operation, discharge, followup, text}` |
| POST | `operations/{procedure}/discharge-document` | `clinic.documents.create` | → 201 P5 draft |
| GET | `discharge-presets` | `clinic.patients.view` | the company's presets |
| GET | `encounters/{encounter}/discharge` | `clinic.history.view` | `{values (p3 shape), rx_draft}` of the visit |
| POST | `encounters/{encounter}/discharge/apply` | `clinic.history.record` | `{template, replace?}` → `{values, rx_draft}` |
Read model: `{id, patient_id, encounter_id, episode_id, clinical_type, status, place, place_name, mode, surgery_required, hospital_surgery_id, performed_at, scheduled_at, procedure_codes, procs, surgeon_id, surgeon_name, indication, is_signed, signed_at, editable, record_type, fields (code ⇒ value), clavien, complications, warnings, follow_ups [{id, title, due_on, status}], attachments_count, summary}`. Operation fields: the shared `GET/PUT api/clinic/records/clinical_procedure/{id}/fields`.

### Tests — `Modules/Gyn/tests/Feature/G4aGynOperationsTest.php` (prefix `g4a_`)
installer seeds the 3 modules (operation `scope=record`, entity keys + followup schedule absent, `procs` present) + 58 catalog rows idempotently (long codes ≤ 30); record from `procs` → `procedure_codes` + mirror + `clinical_type gyn_ob`; operation field write through the shared record endpoint, through the encounter path 422, without `clinic.procedures.edit` 403, mirror write 422; sign → 4 tasks 7d/1m/3m/6m anchored at performed_at, snapshot columns, record frozen, Clavien warning; histology addendum after sign; mode external refuses in-house, centre accepts in-house without surgery, hospital requires it, link-surgery copies the op and refreshes the mirror; operation / discharge / followup summaries = the JS for scenario 3 + hand-made cases; the `operative` summary type of the encounter carries the three; discharge apply + `rx_draft`; discharge document draft; feature off ⇒ 422 + module hidden. Run also every `Modules/Gyn/tests`, `Af2IsolationTest`, `PlatformD0FieldIsolationTest`, `ClinicProfilePackTest`, `C1aEntitiesTest`, `C1bSummaryRecordTest`, `HospitalSurgeryTest` — keep green.

### Out of scope (G4a)
Any FE; booking a hospital surgery from the clinic (Hospital module flow); urogyn / pregnancy follow-up schedules (G6 / G5); CS / labour templates (G5 `cs` module); per-procedure follow-up rules; a Gyn discharge-Rx endpoint (P1's composer issues it); an operations statistics dashboard.

---

## G4b — FE (`src/app/features/gyn/`; no migrations)

Design consult (cheap agent, not Fable — owner rule) on: the operation card (header «TLH + BSO · 12 Oct 2026 · Dr. … · Signed», collapsed vs open, 6 sections, procedure-specific section appearing on pick), the procedure picker (PROC_LIB chips grouped + search), complications + Clavien inline, the discharge card (preset sheet → rows, edit, «Discharge Rx» → P1 composer prefilled from `rx_draft`, «Discharge summary» → P5 draft), the follow-up timeline (4 tasks with due/overdue).

**G4a hand-off notes:** `GET gyn/schema` lists the entity keys (date / surgeon / place / indication / status) and the 4 `gyn_followup_*` schedule codes in `sections[].codes` with **no** `fields[]` entry — render the operation header from the read model (`entity_fields` map on the module) and skip the empty follow-up «الجدول» section (the schedule = the read model's `follow_ups`). `gyn_operation_procs` is in `fields[]` but read-only (`mirrors`). Only the doctor set holds `clinic.procedures.view` today — the nurse / sonographer roles cannot open the operation card until the orchestrator grants it.

### Do
1. `gyn-operation-cards.component.ts` — the `operation` module card: the patient's operations (`GET patients/{p}/operations`), «＋ عملية», the header form (date, procs → `procs`, surgeon, place, indication; centre/hospital: place + «ربط بعملية المستشفى» from `GET patients/{p}/surgeries`), the template sections with `gyn-module-form` in record mode (`PUT clinic/records/clinical_procedure/{id}/fields`; `gyn_operation_procs` read-only, fed from the header), sign (shows `warnings`), cancel, histology addendum after sign, read-only when signed.
2. The discharge card: preset picker (`GET discharge-presets`, `POST encounters/{e}/discharge/apply`), rows editable, Rx button → P1 composer `kind=discharge` prefilled from `rx_draft`, «ملخص الخروج» → `POST operations/{id}/discharge-document` then the P5 editor.
3. The follow-up card: the tasks of the procedure (from the read model) + the visit rows.
4. i18n `GYN.OPERATION.*`, `GYN.DISCHARGE.*`, `GYN.FOLLOWUP.*` (ar + en), no version bump. `npx ng build --base-href /app/` green. No deploy.

---

## Report back (each WP)
Files created/edited; installer counts; test output with pass counts; migrations + dev commands; Gyn route lines (Clinic route lines to paste — should be none); permissions/settings needed; CHANGELOG EN/AR; decisions taken; files needed but not touched; any p3d field the JSON lacks or the summary port could not match exactly.
