# 20 — Final Architecture Synthesis (Execution Spec)

**Status:** Board-level final recommendation, post 3-proposal / 3-judge adversarial review.
**Decision:** Adopt **P-PLATFORM-FIRST** (winner on 2 of 3 judge lenses: Clinical Operations 8, Business/Product 8) **amended with the must-steal items** from OBGY-AS-SEED (Engineering lens winner, 8) and Thin-HIS/ERP-Maximalist (rejected as architecture, raided for clinical-safety ideas).
**Working name:** *Platform-First, OBGY-Seeded.*

Binding constraints honored verbatim (never reopen):
- **D1:** MPI = `lab_patients` upgraded in place; no second patient table; access via named scopes `internal()` / `forLab()`; **no blanket global scope**. B2B patients stay in `lab_patients` (`external_lab_id` + `UNIQUE(company_id, ext_scope_key, national_id)`).
- **D2:** HIS is **ONE** module `Modules/HIS`. HIS imports LIS/Accounting/HRM/Inventory/Core/NPHIES **forward only**; LIS **never** imports HIS; backward info via existing LIS events only.
- **D3:** Service-performer contract = Action entry point + `encounter_id` (template: `Modules/LIS/app/Actions/CreateLabRequest`, W1-3 extraction).
- **D4:** Encounter/Folio design approved, tables created at HIS kickoff; lab invoices enter the folio **by reference**, never re-posted.
- **D5:** LIS untouched in performance and behavior. Zero added hot-path queries. BE+FE in one deploy. Acceptance gate per item: all suites green + before/after curl timing on worklist + reception; regression reverts the item.

---

## 1. Verdict summary

**Q: Is OBGY the core of HIS? — No.**
- OBGY has no Encounter (clinical tables never reference `visits` — analysis §90.1); no inpatient/ADT/ER/eMAR; no insurance cycle (cash/visa only); ~48% women's-health-only content; zero portable code (PHP 5.6, system-wide SQLi, rule R12).
- Its own migration blueprint (§95 2.6) designs Encounter/OperativeNote/SurgicalBooking/queue module-agnostic "so the HMS module can consume them".

**Q: Separate module or merged? — Separate.**
- `Modules/HIS` = generic clinical platform (one nwidart module, internal folder split).
- `Modules/Obgy` = first specialty plug-in. **HIS never imports or names Obgy**; Obgy registers itself via registries. Same golden rule that keeps LIS sellable standalone, applied one level up → keeps Tier-2 "Moon Clinic" sellable without women's-health content.

**OBGY's role (4 things, no code):**
1. Pattern donor for the HIS core (bucket A ~32%: encounter/queue/visit-periods, 18-clone → 4 morph-table consolidation, Q&A history engine, per-body-system exam, perioperative workflow, lookup engine, annotated diagrams).
2. Specialty content (bucket B ~48%) inside `Modules/Obgy` — complex sheets as typed tables, simple sheets as seeded forms content.
3. First **paying pilot tenant** (signed during Phase 0) + ETL rehearsal corpus (10y data, ~190 production-curated Arabic vocabularies).
4. Proof that outpatient P1 is sellable standalone.

**Relationship sentences:**
- ERP↔LIS: LIS rides platform rails (BaseModel/DataScope/SequenceService) and posts GL only via `CreateJournalEntry`; platform knows nothing of LIS internals.
- ERP↔HIS: HIS consumes Core/Accounting/HRM/Inventory/NPHIES forward via Actions/Services; platform changes limited to the approved Generalization Register (chiefly `ChargePostingService`).
- HIS↔LIS: HIS calls `Modules\LIS\Actions\CreateLabRequest(encounter_id, source: in_patient|…)`; LIS never imports HIS; results return via `LabResultReleased` / `LabRequestCompleted` / `CriticalResultDetected`.
- HIS↔OBGY: Obgy imports HIS forward (encounters, folio charges, forms, lookups); registers via `PermissionDependencyRegistry::register('obgy', …)` + `EncounterContentRegistry`; HIS never names a specialty.
- OBGY↔LIS: lab orders via the HIS path + `obgy_lis_test_map` (276 legacy tests); **semen analyses & hormone panels become LIS catalog investigations with WHO reference ranges** (steal from ERP-Maximalist) — at most a thin obgy view over LIS results.
- OBGY↔ERP: patients = `lab_patients` internal rows (`partner_id → AccBpExt` replaces legacy cURL sync); drugs = Core Product + Inventory StockService; money only via `his_folio_charges → ChargePostingService → CreateJournalEntry`.

Judge scores: P-PLATFORM-FIRST 7 / **8** / **8**; OBGY-AS-SEED **8** / 7 / 7; Thin-HIS 4.5 / 4.5 / 6.

---

## 2. Final module map

### Modules/HIS (new, ONE module; folders: Mpi/, Scheduling/, Encounter/, Folio/, Orders/, Forms/, Registries/, Surgery/, Adt/)
P1 tables:
- Spine: `his_encounters`, `his_encounter_diagnoses` (typed ICD anchor for NPHIES), `his_episodes` (generic EpisodeOfCare; pregnancy = episode type — steal), `his_patient_spouses`, `his_referrals`.
- Scheduling: `his_appointments` (**`scheduled_at` + resource columns from day one** — steal; upgradeable to slot/diary/multi-resource), `his_visit_periods` (capacity), `his_clinic_closures`.
- Folio: `his_folios`, `his_folio_charges` (morph `source_type/source_id`, **`UNIQUE(source_type, source_id)`**, `service_code` per `sbscs_code` pattern, `cost_center_id`, unit_cost COGS), `his_folio_payments`, `his_deposits` (receipt-voucher backed, FIFO allocation).
- Orders: `his_prescriptions` + `his_prescription_items` (morph prescribable; subject patient|spouse; `product_id → Core products`), `his_service_orders` + items (morph orderable).
- Forms engine (built **last** in P1, extracted from real OBGY templates): `his_form_templates`, `his_form_versions` (**immutable; responses pin a version** — steal), `his_form_responses` (**status draft|signed|amended** — steal), `his_form_response_values` + typed projection index.
- Clinical primitives: `his_observations` (**typed FHIR-Observation time-series**: patient_id, episode_id?, encounter_id?, code, value_numeric, unit, body_site, observed_at — steal; vitals/ANC curves/IVF follicles), `his_clinical_exams`, `his_exam_findings` (body_system enum), `his_lookups` (domain, parent_id, title_ar, title_en).
- Surgery (platform-level from day one, per blueprint §95 2.6): `his_hospitals`, `his_surgical_bookings`, `his_operative_notes` (+ `his_operative_note_staff`), `his_anesthesia_types`, `his_incision_types`.

P2 (inpatient): `his_wards`, `his_rooms`, `his_beds`, `his_bed_assignments`, `his_encounter_movements`; ER triage model (**net-new design — no proposal designed it**: triage scale, tracking board, disposition); nursing basics; allergy/problem-list registry (flagged gap).

### Modules/Obgy (new, specialty plug-in; bucket B pruned by the content-vs-table rule)
Hard tables (metadata-break justified): `obgy_pregnancies`, `obgy_antenatal_visits`, `obgy_antenatal_ultrasounds`, `obgy_pregnancy_losses`, `obgy_delivery_registrations`, `obgy_ivf_cycles` + stage tables (`obgy_oocyte_retrievals`, `obgy_embryo_transfers`, `obgy_cryopreservations`, `obgy_endometrial_preps`, `obgy_cycle_outcomes`), `obgy_imaging_studies` + fetal/gyna scan findings, `obgy_endoscopy_procedures/findings/terms`, `obgy_infertility_files`, obstetric/menstrual/contraception histories, `obgy_lis_test_map`.
Pruned vs the blueprint (steals): follicle measurements → `his_observations` rows + observation-grid widget; semen/hormone results → LIS catalog seeders; simple sheets → forms-engine content (seeders); no patient/doctor/drug/price/treasury tables ever.

### Untouched / minimally touched
- `Modules/LIS`: zero changes except FK activation on the already-shipped inert `lab_requests.encounter_id` at kickoff (D5 gates apply).
- `Modules/Core`: Phase-0 items + `ChargePostingService` (extract `PostLabInvoice`/`PostLabPayment` parameterized by settings prefix `lis.*` → `his.*` — already named in the approved Generalization Register).
- `Modules/NPHIES`: widen `FhirPatientBuilder` / eligibility / claim type-hints from `LabPatient`/`LabInvoice` to the shared patient + HIS invoice (generalization, not rebuild). HIS invoices carry the proven `nphies_claim_status / nphies_preauth_ref / nphies_covered_amount / nphies_copay_amount` column set.
- `Accounting`, `HRM`, `Inventory`: consumed as-is (CreateJournalEntry, employees.user_id chain + shifts/payroll, warehouses + StockService FIFO/WAC).

---

## 3. Data spine schema sketch

```sql
-- MPI: NO new table. lab_patients promoted in place (D1).
-- HIS access: LabPatient::internal()  (external_lab_id IS NULL)
-- OBGY ETL: statusno→mrn, NID→national_id(+national_id_type); spouse → his_patient_spouses.

his_encounters (
  id, company_id, branch_id, encounter_number,            -- SequenceService('his','encounter'), per-branch
  patient_id  FK lab_patients (internal only),
  episode_id  FK his_episodes NULL,
  type ENUM(opd, ipd, er, daycase), status ENUM(planned, in_progress, completed, cancelled),
  attending_doctor_id FK lab_doctors,                     -- → employees via employee_id (W1-2) → users
  parent_encounter_id FK his_encounters NULL,
  queue_position INT NULL, source ENUM(reception, appointment, referral, migration),
  ... BaseModel: TenantAware + Auditable + SoftDeletes
)

his_episodes ( id, company_id, patient_id, type,          -- pregnancy | infertility_file | ivf_cycle | chronic_program
  status, opened_at, closed_at, owner_module VARCHAR )    -- longitudinal EpisodeOfCare header

his_folios ( id, company_id, folio_number, encounter_id FK,
  payer_type ENUM(self_pay, insurance, b2b_account), insurance_contract_id NULL,
  status, total_charges DECIMAL(12,3), total_payments, balance )

his_folio_charges ( id, folio_id FK,
  source_type, source_id,                                  -- morph: lab_invoice(by-ref), obgy_service, his_prescription_item, bed_day, or_procedure...
  UNIQUE(source_type, source_id),                          -- a clinical act bills exactly once (DB constraint, not convention)
  service_code,                                            -- SBS/nafis pattern from lab_investigations
  qty, unit_price, total, cost_center_id, unit_cost )

his_observations ( id, company_id, patient_id, encounter_id NULL, episode_id NULL,
  code, value_numeric, value_text NULL, unit, body_site NULL, observed_at, recorded_by )

his_form_versions ( id, form_template_id, version_no, schema_json, published_at )   -- immutable
his_form_responses ( id, form_version_id FK, encounter_id, patient_id, subject ENUM(patient, spouse),
  status ENUM(draft, signed, amended), signed_by, signed_at, amended_from_id NULL )
```

Posting path: `FolioClosed` → payer-split invoice(s) → `Core\ChargePostingService` (settings prefix `his.*`: receivable/revenue/tax/COGS account keys, AccBpExt AR fallback chain — exact PostLabInvoice semantics) → `Modules\Accounting\Actions\CreateJournalEntry(source_type='his_invoice')` → insurance share → `NphiesClaimService::submit()` → `nphies_transactions`.

---

## 4. Event contracts

| Event | Emitter | Consumers | Payload |
|---|---|---|---|
| `LabResultReleased` (existing) | LIS | HIS (attach to encounter), Obgy (render in sheet) | LabResult |
| `LabRequestCompleted` / `CriticalResultDetected` (existing) | LIS | HIS (order closure / clinician inbox) | LabRequest / alert |
| `BusinessPartnerCreated` (existing) | Core | Accounting `CreatePartnerAccounts` (patient AR) | partner |
| `EncounterOpened/Closed` (new) | HIS | Obgy, reporting, notifications | encounter_id, patient_id, type |
| `AppointmentBooked/CheckedIn` (new) | HIS | waiting screen, portal | appointment_id, period_id |
| `FolioChargePosted` (new, universal hook) | HIS | any clinical module; declared D3 template for radiology/OR | folio_id, source_type, source_id, total |
| `FolioClosed` (new) | HIS | invoice generation → ChargePostingService → JE → NPHIES | folio_id |
| `PatientAdmitted/Transferred/Discharged` (new, P2) | HIS | nightly bed-day folio job, bed board | encounter_id, bed_id |
| `PrescriptionDispensed` (new) | HIS | Inventory `StockService::decreaseStock(reference_type='his_prescription')` + folio charge | prescription_id, encounter_id |
| `FormResponseSubmitted` (new, steal) | HIS | specialty listeners (e.g., Obgy advances IVF stage on signed retrieval form) | form_response_id, form_code, encounter_id |
| `PregnancyOpened/Closed`, `IvfCycleStageCompleted` (new) | Obgy | inside Obgy + reporting only — HIS never listens to a specialty | pregnancy_id / cycle_id, stage |

FK contracts: `lab_requests.encounter_id → his_encounters.id` (FK at kickoff); `his_encounters.attending_doctor_id → lab_doctors → employees(employee_id, W1-2) → users`; `lab_patients.partner_id → business_partners → AccBpExt.ar_account_id`.

---

## 5. Dependency rules (enforced)

1. HIS → {Core, LIS, Accounting, HRM, Inventory, NPHIES} forward via Actions/Services only.
2. LIS never imports HIS (D2). Obgy → {HIS, Core, LIS} forward; **nobody imports Obgy**.
3. **CI grep gates** (steal — nwidart enforces nothing; 3 inversions already existed): fail build on `use Modules\\Obgy` outside Modules/Obgy and `use Modules\\HIS` inside Modules/LIS.
4. Patient access only via `LabPatient::internal()` / `forLab()`; no global scope (spec constraint #2).
5. All GL via ChargePostingService → CreateJournalEntry; Obgy never posts GL — it only inserts `his_folio_charges` rows.
6. Permissions: `PermissionDependencyRegistry::register('his', …)` / `('obgy', …)` in ServiceProvider boot (W1-4 / LIS precedent); FE route `data.permissions=['his.']/['obgy.']` + `*appCan`.
7. Governance (steals): any new **generic engine** in HIS core requires a named second consumer or passage of the second-specialty gate (board-approved); any new **specialty hard table** requires a metadata-break justification. Forms/lookup generalization is sequenced LAST, extracted against real OBGY templates.
8. Release rule (steal): every core table must have a production consumer in its first release train (OBGY pilot exercises encounters/appointments/forms/lookups before Tier-2 GA).

Frontend: `features/his/` standalone components at `/core/his/*` (+ fullscreen `/clinic/*` HisLayoutComponent mirroring `/lab/*`); `features/obgy/` mounting encounter-workspace tabs via registry; `core/services/his-*.service.ts` / `obgy-*.service.ts` (listAll() convention, X-Authorization); queue = lis-worklist server-driven contract clone; booking = request-wizard-v2 clone; clinical printing = lis-html-report/lis-report-pdf clones; portal = `/p/:token` pattern; HIS/OBGY namespaces in en.json/ar.json (English-first UPPER_SNAKE). Conceded bespoke widgets: observation grid (IVF/ANC flowsheets) + episode timeline.

---

## 6. Phase plan

| Phase | Scope | Size | Sellable increment |
|---|---|---|---|
| **0** (approved, NOT started) | hms-phase0-spec W1-1..W2-2: DataScope hoist, lab_doctors.employee_id, CreateLabRequest extraction + encounter_id, PermissionDependencyRegistry, B2B hardening (internal()/forLab()), module-gating API enforcement log-only | S, ~7–10 dev-days | gate for everything; unblocks tier licensing |
| **0b** (parallel, ops) | Legacy remediation (SQLi, mobileservices.php, web-root dumps); **fresh production export** of ~190 vocabularies + RedBean tables (R7 blocking gate); **sign OBGY clinic as paying pilot** (billable migration engagement) | S | migration-services revenue starts pre-code |
| **1** HIS P1 outpatient | Modules/HIS scaffold; encounter/episode/folio spine + ChargePostingService extraction; appointments/queue/periods; price-list + insurance generalization + FhirPatientBuilder widening (**NPHIES with first new tier**); /clinic workspace; forms+lookups+observations engine LAST | L, 8–14 pw | **Tier-2 Moon Clinic** (release-gated on pilot exercising every core table) |
| **2** Modules/Obgy + pilot go-live | Pruned obgy_* tables; simple sheets as form content; semen/hormones as LIS seeders; ETL (patients→lab_patients; visits split — `detectionid ∈ (−99,999,9999)` rows → folio payments; unmatched clinical rows → `source=migration` encounters with confidence scores + clinician review queues, R2); 4.8GB media migration; go-live | L, 8–12 pw (overlaps P1 tail) | **Tier-3 Moon Women's Health** (~22–34 pw cumulative) |
| **3** Second-specialty genericity gate (**binding**) | One thin specialty (e.g., general medicine) as pure content — zero hard tables; proves the core is specialty-neutral | S–M, 2–4 pw | live "add a specialty in weeks" demo; **prerequisite for Phase 4 funding** |
| **4** Inpatient/ADT | wards/rooms/beds/assignments/movements; admission/transfer/discharge events; nightly bed-day charges; deposits; **ER triage (net-new design: scale, tracking board, disposition)**; nursing basics; allergy/problem list | L, 10–16 pw | **Tier-4 Moon Hospital** |
| **5** Extensions | Clinical pharmacy + eMAR (MedicationAdministration layer — absent from all proposals, must be designed); OR generalization (validated first on OBGY pilot's real surgical caseload); radiology via D3 contract | M–L each, 4–10 pw | priced upgrades within Tier-3/4 |

**Decisions needed from ownership:** (1) one scoping amendment — deep clinical documentation allowed only inside licensed specialty modules (reconciles Obgy depth with the approved admin-financial HIS v1, Risk #7); (2) date for switching module/license enforcement from log-only to enforce; (3) production-export access authorization; (4) clinician review-time budget inside the paid migration contract; (5) the second-specialty gate as a binding financial precondition for Phase 4; (6) Tier-4 not marketed before ER/nursing items complete.

---

## 7. Deliverables index
- `sections/20-verdict.html` — Arabic board verdict (this synthesis, management form)
- `sections/21-scenarios.html` — 5 end-to-end operational walkthroughs
- `sections/22-roadmap.html` — phases + risk/decision table
- Companion evidence: `md/01..09-*.md`, proposals `md/p-*.md`, `/home/moonui/hms-phase0-spec.md`, `obgy-erp-analysis.md` §90.1/§95
