# Slice D — specialties (nutrition / dental / gyn) + inpatient context + clinic/center

Paths: FE = `/home/moonui3/public_html/moon-erp/src/app/features/`, VS = `FE/clinic/visit-shell/`, BE = `/home/moonui3/moon-erp-be/Modules/`. Proto = visit-shell-prototype.html.

## 1. Verdict table

| # | prototype item (proto line) | implementation file:line | verdict | note |
|---|---|---|---|---|
| **NUTRITION** |||||
| N1 | 14 board cards as separate catalog cards, 3-col default (448-461, 494-502) | VS/specialties/nutrition.cards.ts:28-72 (`nut_measure` + `nut_board`, 2 tabs, `hideRail`) | 📝 deferred (S2b) | One bare card hosts the unchanged `app-nutrition-consult-board`. You can't move, hide or resize single cards, so the proto's «عيادة د. منى تشيل 3 كروت» example can't be done. |
| N2 | nut_patient (+ readonly vitals, ideal/required/water/fromFirst/outstanding/points/WHR/BMI) (868-871) | FE/nutrition/visit/nutrition-consult-board.component.html:91-170 (finance 143-150, loyalty 151, WHR+risk 157-160, vitals 165) | ✅ as spec | Reachable inside the board. |
| N3 | nut_quest yes/no + ✎ (872) | board html:218-223 (+ `app-nv-questionnaire-dialog` 614) | ✅ as spec | |
| N4 | nut_lifestyle (873) | board html:244 `app-nv-lifestyle-card` | ✅ as spec | |
| N5 | nut_appts + contact log (874) | board html:247-300 (📞 log contact 252, + book 255, last contact 300) | ✅ as spec | |
| N6 | nut_weights (+ وزن, InBody-due bar, sparkline, adherence ✎) (875-879) | board html:326-430 (InBody overdue 336-344, spark 347-361, adherence 408-429) | ✅ as spec | |
| N7 | nut_meas last-5 table incl. waist/hip (880) | board html:444-494 (waist 479, hip 480, WHR 481) | ✅ as spec | |
| N8 | nut_sessions (881) | board html:503 `app-nv-sessions-card` | ✅ as spec | |
| N9 | nut_plan (✎ / shopping / choose) (882) | board html:505-533 | ✅ as spec | |
| N10 | nut_notes / nut_meds / nut_labs (pending + external result) / nut_photos (883-887) | board html:543 / 550 / 558 (labs-card.component.ts:37-41 pending, 117 external dialog) / 598 | ✅ as spec | |
| N11 | nut_packages incl. «المنتجات المباعة» (886) | board html:569-597 | ⚠ partial | Packages and remaining count are there. The products-sold sub-table isn't, anywhere on the board or in its model. |
| N12 | nut_progress (888) | board html:324 `app-nv-progress-card` | ✅ as spec | Conditional, as S2a's comment says. |
| N13 | Header actions rx/lab/rad/nut_plan_dialog/print_plan/note/next_appt/stop (497) | board html:3-35 (rx 5, lab+rad dialog 8 & 668-669, plan 11, print 14, note 17, next 20, stop 32) | ✅ as spec | Rad is a tab of the lab dialog, not a separate button. |
| N14 | Measurements tab + service-order rail | VS/specialties/nutrition-measure-card.component.ts:161-175 | ✅ as spec | Hosts the classic tab with the order rail at 358px. |
| N15 | vitalsPack waist/hip/whr in the vitals card (495, 809) | BE Clinic/database/seeders/ClinicObservationDefinitionSeeder.php:88-89 (nut_waist/nut_hip defs) vs FE/clinic/services/clinic-vitals.service.ts:30-39 (`VITALS_WHITELIST`, 8 core) + vitals-panel.component.ts:215-217 | ⚠ partial | The specialty definitions are seeded but the vitals card only renders the 8 core fields, and there's no `nut_whr`. The nutrition layout has no vitals card anyway. Waist/hip/WHR can be reached through body comp (N7) and WHR (N2). |
| N16 | intakePack nut_* (496) | BE Clinic/app/Clinical/IntakeRegistry.php:59-67 | ⚠ partial | `nut_goal`, `nut_goal_weight` and `nut_activity_level` aren't intake codes; the goal lives in the nutrition patient profile. Other codes are renamed (naming drift). |
| **DENTAL** |||||
| D1 | dent_chart workspace F, `required:true` (463, 511) | VS/specialties/dental.cards.ts:23-32 (`dent_workspace`, tab «مخطط الأسنان») | ⚠ partial | Hosted unchanged, but it isn't `required`, so a client layout could drop it. That can't happen today because Decision 7 locks saves. |
| D2 | Odontogram FDI/Universal, permanent/primary, filter, legend (950-953, 919-923) | FE/dental/workspace/dental-workspace.component.html:36-50 (filter, dentition, notation) + 107-119 (odontogram, legend incl. note/xr) | ✅ as spec | Notation default comes from `dental.notation` (ts:229). |
| D3 | Side panel (surfaces, proc/cond palettes, status, sections, lab, notes, imaging) (924-944) | workspace ts:93-109 (surfaces/palette/procStatus/mobility/note/image) + html 107ff | ✅ as spec | Surfaces are gated by `features.surfaces` (ts:408), note templates by `note_templates` (ts:570). |
| D4 | Sub-views: chart/plan/perio/fmx/ortho/lab/recall tabs + quick mode (981-984, 947) | workspace html:12-27 (chart/perio/ortho/xray tabs), 71 simple mode, 96-101 views, 300 plan panel, 315 recall, 355 lab-case dialog | ⚠ partial | Matches the classic workspace. Plan sits under the chart, not as a tab. Lab board and recall are separate addable cards (dental.cards.ts:101-122), not workspace tabs. |
| D5 | dent_today (986) | dental.cards.ts:51-59 → consult/dental-today | ✅ as spec | |
| D6 | dent_exam: 12 items = 4 pain + 8 mouth (987-988) | FE/dental/consult/dental-exam.component.ts:10,41-44 | ✅ as spec | Driven by the dent_ pack (PAIN + swelling, mouth, notes). |
| D7 | historyPack dent_pain_* (504) | dental-exam.component.ts:10 | ✅ as spec | Lives in the exam card, not the complaint card (classic). |
| D8 | dent_plan / dent_fmx as cards (466, 468) | not in DENTAL_CARDS | 📝 deferred (S2c) | Both are still reachable inside the workspace (D4). |
| D9 | dent_perio / dent_ortho / dent_lab / dent_recall with `feature` (467-471) | dental.cards.ts:79-122 (feature perio/ortho/lab/recall + permission) | ✅ as spec | Catalog-only, not in the default. |
| D10 | settings mode/notation/features.* gate cards and tabs (508, 981) | BE Dental/database/seeders/DentalSettingDefinitionSeeder.php:25-34; VS/visit-shell.component.ts:176-183, 540-546; workspace html:12-27, 96-101 | ✅ as spec | Set in the clinic settings screen (group «الأسنان»). While meta loads, or if it fails, no lock is applied (documented). |
| D11 | Latex alert from dent_allergy_latex (507) | BE Clinic/app/Support/ClinicProfilePacks.php:199 (storage=alert, alert_code latex); PatientFactsReader.php:60 | ✅ as spec | Shows as a shared header alert pill. |
| D12 | intakePack + intakeRefs (shared refs not re-asked) (505-506) | BE IntakeRegistry.php:69-75 | ⚠ partial | The pack also has `dent_anticoagulant` and `dent_allergy_penicillin`, which overlap the shared anticoagulant/allergies. They route into the same alert/condition store, so the data is one source, but the question is asked twice. |
| D13 | Default: complaint(shared)/today/exam/diagnosis/rx + collapsed vitals, history(patientScopeOnly), previous; actions lab/rad (510-514) | dental.cards.ts:126-151; dental-more-card.component.ts:26-41 (vitals / history `[patientScopeOnly]="true"` / previous toggles + lab/rad dialog) | ✅ as spec | Same behaviour delivered as «المزيد». Kept the dental complaint card, `dent_alerts` and hidden rails (📝 S2c). |
| **GYN** |||||
| G1 | gyn_cats required, 4 group lines, chips + «＋ اختيار» picker (473, 1087-1090) | FE/gyn/gyn-shell-cards.ts:39-43 (required, station); FE/gyn/cards/gyn-category-picker.component.ts:95-117 | ✅ as spec | Answers stored as `gyn_cat_<group>`. With no category, a soft warning shows at sign (:131-139). |
| G2 | Locked group struck through «مقفول عند العميل (gyn.feature.x)» (1088; 25_mona) | picker :48-51, 102; BE Gyn/app/Http/Controllers/GynSchemaController.php:130-142 | ✅ as spec | Without `gyn.sexual.view` the sex line is hidden entirely (stricter than proto). Fertility only hides `infertility` (GynFeatures.php:25-37, documented clinical deviation). |
| G3 | gyn_modules required host, show_if engine, first module open, «اتفتح من الاختيار» (474, 1062-1072) | gyn-shell-cards.ts:44-48; FE/gyn/state/gyn-visit.store.ts:117-129, 142-150, 168-170; FE/gyn/engine/show-if.ts | ✅ as spec | Feature-off modules are filtered server-side (`GynModuleRegistry::visibleFor`, SchemaController:30). Core modules are excluded (gyn.models.ts:363). |
| G4 | Any non-core module addable as `gyn_<key>` card carrying its feature (1099-1101; §3) | gyn-shell-cards.ts:155-174; VS/card-catalog.ts:59-68 (`registerSpecCards`) | ✅ as spec | Labour/vd/cs are folded into one `gyn_delivery` card. Private modules need `gyn.sexual.view`. |
| G5 | gyn_timeline (475) | VS/card-catalog.ts:36 shared `timeline` card in GYN default (gyn-shell-cards.ts:128); BE Clinic TimelineService | ✅ as spec | Renamed: a shared timeline of visits, episodes (cycles and pregnancies, G3a), procedures and documents. |
| G6 | gyn_summary, 10 types (476, 1001, 1094) | FE/gyn/cards/gyn-summary-card.component.ts:9-15, 41-46; BE Clinic/app/Clinical/ClinicalTypeRegistry.php:121-155 | ✅ as spec | Types are filtered by feature. Saves as a numbered PDF (C1c). |
| G7 | Private (Sexual) excluded from **every** summary type (1083; §3) | BE Clinic/app/Services/Clinical/ClinicalSummaryService.php:55-70; FE/clinic/clinical/summary-card.component.ts:45-50 | ⚠ partial | Excluded by default and never in Couple, but there's an opt-in «تضمين المحتوى الخاص» for users holding `clinic.fields.private`. The card note says so. |
| G8 | Default flow order (521-523) | gyn-shell-cards.ts:102-134 | ✅ as spec | Superset: adds first_visit, obhx, exam, imaging, operation, discharge, team, gyn_followup. Order kept. |
| G9 | vitalsPack lmp/ga/fundal/fhr/urine_alb (516) | BE ClinicObservationDefinitionSeeder.php:95-96 (fundal, fhr defs); FE/gyn/cards/gyn-antenatal-flowsheet.component.ts:33-55 (GA, BP, weight, urine, FHR, FH…) | ⚠ partial | Not in the vitals card (whitelist, see N15). It lives in the `gyn_antenatal` card and the pregnancy module (LMP), which are catalog cards or host-opened, not in the default. |
| G10 | historyPack gyn_bleeding / gyn_discharge (516) | gyn-shell-cards.ts:177-189 (complaint slot); schema complaint fields `gyn_complaint_hmb_*`, `_irreg_pattern`, `_disch_char/_assoc` | ✅ as spec | Each complaint opens its own questions. |
| G11 | intakePack marital/spouse/marriage yrs/children/GPA/menarche/contraception (517) | FE/gyn/cards/gyn-first-visit-card.component.ts:20-25, 104-118 (profile, spouse panel, menstrual); BE Gyn routes intake-status; GynExtensions.php:193-206 (GPAL, spouse) | ✅ as spec | Uses the profile fields' `in_intake` flags. IntakeRegistry `gyn_ob` is empty (IntakeRegistry.php:75). |
| G12 | Pregnancy alert pill «حامل — 24 أسبوع» rose (518) | FE/clinic/shared/patient-alert-strip/patient-alert-strip.component.ts:251-252, 313-320 | ⚠ partial | Shown as a GA/EDD fact chip at the head of the facts line, not a rose alert pill (Fable decision). High-risk/VTE become alert pills. |
| G13 | gyn.feature.* fertility/obstetrics/urogyn/sexual/oncology (519) | BE Gyn/app/Support/GynFeatures.php:18-61 (+operations) | ⚠ partial | Enforcement is complete (schema, categories, cards, summaries, write guard 422). But the switches live only in `clinic.visit_layouts['gyn_ob'].features`. There's no setting definition and no FE screen, and `saveClient` doesn't send `features` (visit-shell.component.ts:782). Only the API can lock Urogyn/Sexual. |
| G14 | Layout saving for gyn | VS/visit-shell.component.ts:269-272 | ✅ as spec | Open for gyn_ob (flow, no tabs), locked for nutrition/dental (📝 Decision 7). |
| **INPATIENT CONTEXT** |||||
| I1 | addCards mar / nursing / discharge, F (529) | VS/contexts/inpatient.context.ts:42-68; inpatient.cards.ts | ✅ as spec | Split into `inp_mar` (L), `inp_round` (M), `inp_nursing_notes` (M, not for day case), `inp_discharge`. Each is permission-gated, and resolve-layout.ts:114-118 drops what the user can't use. |
| I2 | replace followup → discharge (529) | inpatient.context.ts:65; resolve-layout.ts:120-131 | ✅ as spec | A nurse without the discharge permission loses follow-up too (intended). |
| I3 | rx kind=inpatient (530, 849) | inpatient.context.ts:66; VS/visit-shell.component.html:277-287 (`app-inpatient-rx-composer` when MAR-on-Rx, else `app-clinic-prescription [kind]`) | ✅ as spec | When `hospital.mar_on_prescriptions` is off, the Rx card keeps its legacy behaviour. |
| I4 | MAR grid on prescription_items (890-891) | contexts/inpatient/inpatient-mar-card.component.ts (hosts `app-mar-board`, `[marOnRx]`, `hideOrder`) | ✅ as spec | |
| I5 | Nursing: notes + rounds/NEWS2 (892) | inpatient-round-card / inpatient-notes-card; FE/hospital/nursing/vital-round.component.html:3-10 | ✅ as spec | NEWS2 badge, ACVPU and O2 are in. Per-parameter NEWS2 scores are 📝 deferred. |
| I6 | ctx vitalsPack rr/avpu/pain/o2/**io**/news2 (530) | vital-round.component.html:7-10 (temp, pulse, BP, rr, spo2, pain, glucose, consciousness, on_oxygen) vs BE Hospital/app/Http/Controllers/NursingController.php:132-133 (accepts intake_ml/output_ml) | ⚠ partial | Lives in the round card, not the vitals card. There's no intake/output (I/O) input on the FE even though the BE accepts it. |
| I7 | Discharge: type/date/summary + «روشتة الخروج kind=discharge» + PDF (893) | contexts/inpatient/inpatient-discharge-card.component.html:44-52, 67-70 (`[kind]="'discharge'"`), 81-90 print Rx, 100 discharge_summary document | ✅ as spec | |
| I8 | Header bed · ward · day 2/4 + admitting doctor (530, 1172) | VS/visit-shell.component.html:22; contexts/inpatient-stay.service.ts:70-80 | ⚠ partial | Shows ward, bed and day N. There's no expected length of stay («/4») and no admitting doctor. Users without `hospital.beds.view…` get a bare «إقامة» chip (stay service :17-19). |
| I9 | orderingMode intent for inpatient (528) | VS/visit-shell.component.ts:208 (`encounter.ordering_mode`) | ⚠ partial | The context doesn't force intent; it follows the company setting (default intent). A company set to `immediate` gets immediate orders on inpatient visits too. |
| **CLINIC vs CENTER** |||||
| C1 | CONTEXTS clinic/center: orderingMode immediate/intent, lab standalone/integrated, pharmacy formulary/products (526-527) | BE Clinic/app/Support/OrderingMode.php:21-33; ClinicCatalogMode.php:26-36 (lab_mode + rad_mode); PharmacySource.php:23-27; EncounterResource.php:142-148; ClinicSettingDefinitionSeeder.php:210/226/258 | ⚠ partial | There's no single "context" switch. It's 4 independent company settings (`clinic.ordering_mode`, `clinic.lab_mode`, `clinic.rad_mode`, `clinic.pharmacy_source`) set in the settings screen and sent per encounter. The lab/rad/rx cards read them. Same outcome, but a clinic must set all four. |
| **GENERAL** |||||
| GN1 | Default flow vitals → complaint → history → exam → diagnosis → lab → rad → rx → documents → followup (489-493) | VS/card-catalog.ts:92-112 | ✅ as spec | Same order and sizes, plus a collapsed `timeline` before followup (C1c). |

## 2. Real bugs found (implemented but would misbehave)

1. **GYN visit in the inpatient context ends up with two discharge cards and a leftover follow-up.** The context replaces only the shared `followup` with `inp_discharge` (inpatient.context.ts:65). The GYN default also has `gyn_discharge` (gyn-shell-cards.ts:125) and `gyn_followup` (:131), and those stay. An admitted GYN patient sees «الخروج» twice (GYN discharge module + admission discharge order) plus the GYN follow-up schedule. It's not data-corrupting, but it is confusing.
2. **Specialty and inpatient vitals definitions are seeded but never rendered.** ClinicObservationDefinitionSeeder.php:88-112 seeds nut_waist/nut_hip/…, gyn_fundal_height/gyn_fetal_hr and rr/consciousness/pain/intake/output/news2, but `VITALS_WHITELIST` (clinic-vitals.service.ts:30-39) caps the vitals card at the 8 core fields. A client who enables or edits these definitions expecting them in «العلامات الحيوية» will see nothing. That's dead config, not a crash.
3. **Inpatient round has no I/O fields.** `NursingController` accepts `intake_ml`/`output_ml` (:132-133), but the round form (vital-round.component.html:7-10) has no inputs for them, so fluid balance can't be recorded from the shell.
4. **GYN feature locks can't be set from the UI.** `GynFeatures` reads `clinic.visit_layouts['gyn_ob'].features` (GynFeatures.php:9-11, 52-60). The FE save sends `{clinical_type, layout}` only (visit-shell.component.ts:782), and no setting definitions exist. The approved «عيادة د. منى» lock (screenshot 25) can only be made with a raw API call.

(Lesser: an inpatient nutrition visit prescribes through the board's own `app-clinic-prescription` dialog (board html:650) with no `kind=inpatient`, because the nutrition layout has no shared `rx` card for `cardProps` to reach.)

## 3. Top 5 gaps by owner impact

1. Nutrition is still one monolithic board (📝 S2b). Every board element can be reached today, but per-card hide/reorder for the client (the proto's main point for nutrition) isn't possible.
2. There's no UI for `gyn.feature.*` (fertility/obstetrics/urogyn/sexual/oncology/operations). Enforcement works, but an admin can't turn a group off.
3. Specialty and context vitals packs (waist/hip/WHR, FHR/fundal/urine/LMP-GA, RR/AVPU/I-O) aren't in the vitals card. They're spread over body comp, the antenatal card and the round card, and the round card has no I/O.
4. Clinic vs center isn't one context. It's 4 separate settings (ordering/lab/rad/pharmacy), and inpatient doesn't force intent ordering.
5. The inpatient header has no admitting doctor or expected length of stay, falls back to a bare chip for users without `hospital.beds.view`, and a GYN admission shows duplicate discharge/follow-up cards.
