# Visit Shell — مواصفة UX لقشرة الزيارة الموحّدة (v3)

> تصميم فقط — 2026-10-21 (مراجعة ثالثة بعد توضيحات المالك: العميل هو مستوى التحكم الأساسي، والنسا على تحليل المالك الحقيقي). النموذج التفاعلي: `visit-shell-prototype.html` (نفس المجلد). المراجع: `r4-fields-screens.md` §G، `design.md` §5، `knowledge-base/topics/dental-module.md`، `nutrition-consult-board.component.html`، `knowledge-base/plans/gyn-obstetrics-module.html` + مصادره `gyn-obstetrics-module-src/p3a…p3g` (schema)، `p4a/p4b` (engine)، `p4c` (scenarios).

## 1. الفكرة في ثلاثة أسطر

**التوحيد = بيانات مشتركة + كومبوننتات مشتركة + قواعد مشتركة — مش شكل صفحة واحد.** الهيدر والتنبيهات، الاستقبال الأول (intake)، التوقيع والقفل، الملخص الحي، وكومبوننتات الروشتة/التحاليل/الأشعة/التشخيص/المستندات واحدة في كل التخصصات. **شكل المساحة الرئيسية layout من كروت**: لكل تخصص افتراضي يناسبه (التغذية = لوحة الدكتور ذات الشاشة الواحدة كما هي، الأسنان = workspace الفكّين + شريط الكشف كما اتوافق عليه، العام والنسا = تسلسل محطات + كروت النسا الديناميكية)، و**العميل** (المركز/العيادة) هو اللي يشيل/يرتب/يخفي حقول ويقفل مجموعات مزايا، والدكتور يخصّص لنفسه **بس لو العميل سامح**. الـ `@switch` (747 سطر) يتحول لـ shell + كتالوج كروت + layout محلول، والكومبوننتات التخصصية الموجودة تتستضاف زي ما هي.

## 2. تصحيح: التخصص يملك شكل شاشته — والعميل يتحكم فيه

توضيحات المالك: (1) لوحة التغذية **من تفاصيل الدكتور نفسه وهو طالبها كده** — ما تتحلّش. (2) الأسنان فيها تفاصيل كتير — ما تتختزلش. (3) «لما قلت التحكم طبقاً للطبيب كنت أقصد **العميل** — مركز بيشيل حاجات ومركز تاني لأ». (4) النسا لازم تعكس **تحليل المالك الحقيقي** للعميل الجديد (51 module، categories، show_if، ملخصات).

### 2.1 كتالوج الكروت (Widget catalog)
كل بلوك = كارت له `id`، عنوان، أحجام (`S|M|L|F`)، كومبوننت، نوع، و`feature` اختيارية (بتربطه بمجموعة مزايا العميل):
- **مشترك**: الهيدر+التنبيهات (مثبّت)، العلامات الحيوية (`full|compact|readonly`)، الشكوى، التاريخ (`patientScopeOnly`)، التشخيص، التحاليل، الأشعة، الروشتة (`kind`)، المستندات، الزيارات السابقة، الأدوية الحالية، النتائج بالتاريخ، الملاحظات، الصور، المتابعة، حالة الـ intake، سكة الطلبات، الملخص الحي.
- **تخصصي**: تغذية (13 كارت اللوحة + التقدم نحو الهدف) · أسنان (الفكّين بكل الـ sub-views، الزيارة دي، الفحص، الخطة، اللثة، FMX، التقويم، المعمل، Recall) · نسا (التصنيفات، مضيف الـ modules، الخط الزمني، مولّد الملخص + **41 module** غير-core كل واحد كارت قابل للإضافة `gyn_<key>`).
- **سياق** (الإقامة): MAR، التمريض/الجولات، الخروج.

### 2.2 عقد الـ layout (TS)
```ts
export type CardSize = 'S'|'M'|'L'|'F';
export interface CardDef { id: string; titleKey: string; kind: 'shared'|'spec'|'ctx'; spec?: ClinicalTypeKey; component: Type<unknown>;
  sizes: readonly CardSize[]; required?: boolean; requiredWhen?: 'insured'; feature?: string; /* dental.feature.* / gyn.feature.* */ priv?: boolean; }
export interface LayoutCard { id: string; col: number; order: number; size: CardSize; collapsed?: boolean; props?: Record<string, unknown>; }
export interface VisitLayout { version: number; columns: readonly string[]; flow: boolean; cards: LayoutCard[]; }
export interface FieldRule { visible?: boolean; required?: boolean; input?: 'select'|'text'|'chips'; }  // input = تبديل نوع الإدخال للحقل (من Program Setting في نظام عمرو: Select ⟷ Text)
export interface ClientProfile { allowDoctorOverride: boolean; /* clinic.layout.allow_doctor_override — default false */
  layouts: Partial<Record<ClinicalTypeKey, VisitLayout>>;                         // clinic.layout.{type}
  fields: Record<string /* pack code */, FieldRule>;                             // clinic.fields.{type}
  features: Partial<Record<ClinicalTypeKey, Record<string, boolean>>>; }           // {type}.feature.*
export interface ClinicalTypeDef { key; labelKey; descriptionKey; layout: VisitLayout; actions?: readonly string[];
  vitalsPack; historyPack; intakePack; intakeRefs?; alerts?; settings?: { features?: Record<string, boolean>; [k: string]: unknown }; }
// resolveLayout(type, ctx, client, doctor?) → VisitLayout + per-card from: 'default'|'client'|'doctor'|'context'|'required'
```

### 2.3 الحلّ: default → client → (doctor لو مسموح) → context
1. **الافتراضي** من الـ registry (كود). 2. **العميل**: `clinic.layout.{type}` (ترتيب/حجم/إخفاء كروت) + `clinic.fields.*` (إخفاء/إلزام حقول الباقات) + `{type}.feature.*` (قفل مجموعات: اللثة/التقويم/المعمل في الأسنان، الخصوبة/التوليد/Urogyn/Sexual/الأورام في النسا) — يضبطها أدمن العميل بصلاحية `clinic.layout.manage`. 3. **الدكتور** — موجود فقط لو `clinic.layout.allow_doctor_override=true` عند العميل (الافتراضي off)؛ تفضيل شخصي في `settings` بـ `user_id`. 4. **السياق** (الإقامة) يضيف كروته. كل مستوى يستبدل اللي قبله كاملاً (مش merge) وله «إعادة الافتراضي». التحقق: كارت مجهول/تخصص تاني/feature مقفول → يُسقط · `required` → يُعاد في الأول · حجم غير مسموح → يُصحح · `version` أقل → migration. **الحقول المخفية عند العميل تختفي من الـ intake ومن الكروت معاً** (مصدر واحد)، والإلزامية تظهر بـ `*` وتُفرض عند التوقيع.

### 2.4 وضع «تخصيص الشاشة»
شريط لكل كارت (↑↓ · ◀▶ · الحجم · مطوي · إخفاء إلا الإلزامي) + «إضافة كارت» من الكتالوج مفلتراً بالتخصص ومزايا العميل. الحفظ: **«حفظ للعميل (المركز)» هو الأساسي**؛ «حفظ لي» يظهر فقط لو العميل سامح. مفتاح العميل في الـ shell (مركز النور يسمح للدكتور ويشغّل كل المزايا · عيادة د. منى تقفل اللثة/التقويم/المعمل وUrogyn/Sexual، تشيل 3 كروت من لوحة التغذية، وتخفي/تُلزم حقول) يبيّن الفرق فوراً، ولوحة الـ registry تطبع مصدر كل كارت.

### 2.5 المحطات = خاصية layout
`flow: true` = كروت العمود محطات مرتّبة (ترقيم، «تم ✓» يطوي لسطر ملخص، `Ctrl+Enter`/`Alt+↑↓`) — العام والنسا. `flow: false` = لوحة — التغذية والأسنان. التوقيع (`Alt+F`) والتحذيرات الناعمة واحدة.

### 2.6 عرض الخيارات = «pick-don't-type» مُركّز (مستفاد من نظام عمرو القديم)
**المشكلة في v3:** الاختيارات كانت **كلها مفرودة ومعروضة** (chips طويلة، كل module في النسا كارت ظاهر، قوائم خيارات دايماً مفتوحة) → الشاشة تتخم. **الحل المعتمد من نظام عمرو (مع تفادي عيوبه):**
- **الخيار = select/picker مُركّز مش قائمة مفرودة.** المعروض = الملخص المختار بس + زر **«＋ اختيار / بحث»** يفتح picker مركّز (dialog/popover). الـchips تفضل للمختار فقط.
- **الـpickers الثقيلة ورا أزرار** (زي HISTORY / EXAMINATION / INVESTIGATIONS عندهم): التاريخ، الفحص، الفحوصات، التشخيص — كلها تفتح من زر في picker فيه **بحث + المفضّلة (★) فوق + تجميع بالفئة + اختيار متعدد + صف inline «＋ إضافة جديد»** يكتب مصطلح في الكتالوج بصلاحية.
- **picker الفحوصات = شبكة فئات** (يطابق `investcats`→`invests`): فئات بـ `display_order` تتفرد لفحوصاتها، اختيار متعدد، مفضّلة، مطوية افتراضياً.
- **الروشتة = دواء + جملة افتراضية** (Rx v2): اختيار الدواء من الكتالوج → جملة الجرعة العربية الافتراضية تتملى في حقل قابل للتعديل؛ **«تكرار»** يكلِّن صف بجملة بديلة. صف واحد مُركّز لكل دواء.
- **المفضّلة لكل دكتور** (مش install): ★ على أي خيار = مفضّلة شخصية تطفو فوق في المرة الجاية — جدول `clinical_lookup_favorites(user_id, lookup_key, value_id)`.
- **تبديل نوع الإدخال للحقل** (`FieldRule.input` = select/text) زي Examination Controller عندهم: العميل يقرر الحقل يتعرض dropdown من الكتالوج ولا نص حر.

**تفادي عيوبهم (حُرّاس):** (أ) **كتالوج lookup واحد مُدار بـ `lookup_key`** — ممنوع جدول lookup مستقل لكل حقل (هُم عندهم عشرات: `examinationhead/chest/abdomen/pelvis`, `husbndiagnosis1/2/3`…). (ب) **الاختيار المتعدد = صفوف ربط مُطبّعة** (مثلاً `encounter_diagnoses`) — ممنوع تخزين CSV في عمود واحد (`diagnosisid="3,7,12"`) لأنه بيكسر التقارير. الـchips في الـUI مدعومة بصفوف، مش بسترينج.

**مصدر كل picker مختلف — مش كله من الكتالوج العام:**
- **المصطلحات الإكلينيكية** (شكوى، فحص، تشخيص، أسئلة تاريخ) → كتالوج `clinical_lookups` العام بـ `lookup_key`.
- **الأدوية** → **فورمولاري `clinic_drugs`** (`drug_name/form/active_ingredient` + الجملة `use_note` + `clinic_drug_presets`)، كل دواء مربوط **اختيارياً** بمنتج مخزون (`product_id`) حسب `clinic.pharmacy_source` (`products` ⟷ `standalone_formulary`). الروشتة تشاور على `clinic_drug_id` **أو** `drug_id` (مش lookup عام). تفاصيل `design.md §4.1`.
- **التحاليل/الأشعة** → كتالوج **LIS** (`LabInvestigation` + `LabInvestigationCategory` + `LabPackage`) / كتالوج الأشعة (`rad_procedures`)، موصولة للعيادة عبر جسر `clinic_catalog` (`lis_investigation_id`/`rad_procedure_id`) بالتسعير. تفاصيل `design.md §4.2/4.3`.

**الطلب ≠ التنفيذ (حدّ واضح):** كروت التحاليل/الأشعة/الروشتة في الزيارة بتعمل **طلبات/نيّة** بس (`service_order_lines` status=Ordered / `prescriptions` status=issued). التنفيذ سطح منفصل: LIS بيعمل `LabRequest` بدورة حياته (`sample_collected → in_progress → resulted`)، والصيدلية بتصرف (`dispense_status`) — ويقدر يسحب طلبات الطبيب كتسهيل **من غير ما ينفّذ/يصرف الكل**. النتائج ترجع للزيارة أوتوماتيك لو اتعملت جوّه السيستم، أو **إدخال يدوي** لو من بره (`clinic.results.external` + مسار `LabExternalLab*`). الربط بـ `fulfillment_type/fulfillment_id`.

### 2.7 شاشة إعدادات العميل = تعميم «Program Setting»
نظام عمرو أثبت إن كود واحد يتقاد بجدول إعدادات (إظهار/إخفاء عناصر، تشغيل تابات، Select/Text لكل حقل، سويتش Clinic/Hospital، General/Gynecology). إحنا نعمّمه: نفس الأفكار بس **لكل عميل ← الدكتور (اختياري)** عبر `ClientProfile` (layouts/fields/features) + `FieldRule.input` + **Hospital = context** (مش تخصص). شاشة الإعداد تعرض: كروت التخصص (ترتيب/حجم/إخفاء)، قواعد الحقول `{visible, required, input}`، ومجموعات المزايا `{type}.feature.*`.

## 3. النسا والتوليد — كروت ديناميكية من تحليل المالك
- **المصدر**: schema النسا (p3a…p3g) كما هو: 8 مجموعات (core/gyn/fert/op/ob/uro/sex/fu)، قوائم التصنيفات (CATS)، 51 module بأقسامها وحقولها و`show_if`، أنواع الملخص العشرة. مضمّن في النموذج حرفياً: الفهرس الكامل (51) + 8 modules كاملة التفاعل (الرحم والألياف Myoma 1..n FIGO، العقم، دورات التنشيط OI ككروت، الحمل EDD/GA تلقائي، VTE score RCOG 37a، POP-Q بحساب الـ Stage، Urodynamics، Sexual history 🔒) + قيم السيناريوهات (p4c).
- **كارت التصنيفات** (`app-gyn-category-picker`، إلزامي): تابات GYN / الخصوبة / الحمل والولادة / Urogyn / Sexual 🔒 — كل تاب chips اختيار متعدد؛ المجموعة المقفولة بـ `gyn.feature.*` تختفي ومعها categories وmodules بتاعتها.
- **مضيف الـ modules** (`app-gyn-module-host`، إلزامي): يقيّم `show_if` (cat / mod.key eq|in|has|truthy / any|all) بنفس محرك p4b ويرسم الـ modules المفتوحة ككروت فرعية بنفس محرك الحقول (text/num/date/seg/sel/chips/bool/calc/repeat/table/figo/popq/media) مع شارة «اتفتح من الاختيار». **الـ core modules (profile/alerts/history/obhx/menstrual/complaint/exam/imaging/team/dx) = الكروت المشتركة** في الـ shell — ما بتترسمش تاني.
- **الكارت الخاص** (Sexual health): لون داكن + قفل + صلاحية `gyn.sexual.view` + «يُسأل على انفراد»، ومستبعد من **كل** أنواع الملخص بما فيها Couple.
- **مولّد الملخص** (`app-gyn-summary`): Clinic / Fertility / Operative / Antenatal / Delivery / Discharge / Follow-up / UDS / Urogyn / Couple (no private) — يجمع قيم الـ modules المفتوحة بأسماء الحقول + سطر «من الكروت المشتركة». **الخط الزمني** (`app-gyn-timeline`): زيارات/دورات/عمليات/حمل.
- أي module من الـ 41 قابل للإضافة ككارت مستقل من الكتالوج (`gyn_cs`، `gyn_ivf`…) بغض النظر عن `show_if`، ويحمل `feature` مجموعته.

## 4. مناطق الشاشة
App bar (المسار · العميل · الطبيب · `layout: flow/board · من default/client/doctor` · `encounter.kind`) · هيدر المريض sticky بالتنبيهات دايماً · سكة البداية (230px؛ drawer على التابلت/الموبايل) · المساحة الرئيسية (layout محلول + رأس اللوحة بأزرار الـ dialogs) · سكة النهاية (الملخص الحي + الفاتورة) · Footer (تقدم/عدد الكروت · طباعة · كاشير · إنهاء). الأعمدة من `layout.columns`؛ التابلت عمودان والثالث ينزل، الموبايل عمود واحد.

## 5. تشريح الكارت
رأس: أيقونة/رقم · العنوان · 🔗 مشترك / 🏷 خاص / سياق · الطبقة · **مصدر الكارت** (افتراضي/العميل/الدكتور/سياق/إلزامي) · الملخص عند الطيّ · «تم ✓» في flow. الحالات: مفتوح/مطوي · flow: `todo → active → done` · بعد التوقيع read-only. كل كارت تخصصي يلتزم بـ `[encounterId] [patientId] [locked]` ويصدر `summary$`.

## 6. طبقات البيانات
١ مريض مشترك (lab_patients + 7 أسئلة + حساسية + مضاد تجلط — intake خطوة ١) · ٢ مريض تخصصي (nut_/dent_/obgy packs — intake خطوة ٢؛ المراجع المشتركة لا تُسأل تاني) · ٣ زيارة مشترك (علامات، شكوى، تشخيص، طلبات، روشتة، مستندات، متابعة) · ٤ زيارة تخصصي (الأوزان/InBody، الفكّين/الخطة/اللثة، modules النسا، MAR/الجولات). حقول الطبقتين ٢ و٤ بتخضع لقواعد العميل `{visible, required}`.

## 7. قواعد التفاعل
حفظ تلقائي (debounce) · الملخص الحي من نفس الـ signals · إنهاء الزيارة = تحذيرات ناعمة (منها «التشخيص مطلوب للمطالبة» لو المريض مؤمّن والكارت مش في اللوحة) ثم توقيع؛ القفل من الـ BE · Addendum بعد التوقيع · التنبيهات من `patient_alerts` · أزرار الـ dialogs تفتح نفس الكومبوننتات المشتركة · لوحة المفاتيح في flow.

## 8. الاستقبال الأول
نفس الـ wizard لكل التخصصات: خطوة ١ مشتركة → خطوة ٢ `intakePack` التخصص؛ الحقول المخفية عند العميل لا تظهر، الإلزامية بـ `*`. الشارة في الهيدر تفتح خطوة ٢.

## 9. من شاشات النهاردة للـ shell
| النهاردة | في الـ shell | يختفي |
|---|---|---|
| **عام** | layout `flow` بنفس الترتيب؛ الزيارات السابقة/الأدوية/النتائج → السكة | الـ `@switch`؛ لوحة التغذية المضمّنة |
| **تغذية** (لوحة الدكتور) | **كما هي** = الافتراضي: 3 أعمدة × 13 كارت بنفس الترتيب، روشتة/تحاليل/أشعة dialogs. الشكوى/التشخيص في الكتالوج فقط. العميل يشيل كروت (مثال: الجلسات/الباقات/الصور) ويخفي حقول (كيف عرفتنا، الوظيفة) | بطاقة المريض المكررة؛ `app-nutrition-consult-board` كصفحة ثابتة |
| **أسنان** (workspace + dental_consult) | **كما هو** = الافتراضي: الفكّين F بكل الـ sub-views والوضع السريع + شريط الكشف + «المزيد» مطوي؛ العميل يقفل `dental.feature.{perio,ortho,lab,…}` فتختفي التابات والكروت | `app-dental-alerts` (الهيدر)؛ dent_ المكررة |
| **نسا** (خطة GYN — جديد) | flow: علامات → شكوى → تاريخ → **التصنيفات** → **مضيف الـ modules** → تشخيص → تحاليل → أشعة → روشتة → مستندات → **الخط الزمني** → **مولّد الملخص** → متابعة. 51 module ككروت، 8 مضمّنة بالكامل | — (الكومبوننت `app-gyn-workspace` المقترح سابقاً يتفكك لـ picker + host + summary + timeline) |
| **إقامة** | سياق فوق أي layout: MAR · التمريض · الخروج، الروشتة `kind=inpatient` | `admissions.diagnosis` النصي، `hospital_med_orders` النصي |

## 10. الاستجابة والـ RTL وإمكانية الوصول
تابلت: لمس ≥ 44px، لوحتان، الفكّين فوق لوحة السنة. موبايل: عمود واحد، تمرير أفقي للفكّين وشارت اللثة، ملخص sticky. RTL أولاً؛ الأرقام/الأكواد/الـ popq grid `ltr`. رؤوس الكروت `button` بـ `aria-expanded`، الحالة بالنص، تباين ≥ 4.5:1؛ الكارت الخاص يحمل `aria-label` بالقيد.

## 11. مخزون الكومبوننتات (FE)
**جديد (الـ shell):** `app-visit-shell` (resolveLayout + grid + flow) · `app-visit-header` · `app-visit-card` · `app-visit-layout-editor` (تخصيص + كتالوج + حفظ بالمستوى) · `app-visit-rail-start` · `app-visit-summary-rail` · `app-visit-intake-wizard` · `app-visit-finish-panel` · `app-clinic-exam` · `app-clinic-complaint`.
**نسا (جديد من الخطة):** `app-gyn-category-picker` · `app-gyn-module-host` (محرك p4b: `ev` + `fieldHTML` + calcs) · `app-gyn-summary` · `app-gyn-timeline`.
**يُعاد استضافته بلا تغيير ككروت مشتركة:** `app-clinic-vitals-panel` · `app-clinic-history-panel` · `app-clinic-diagnosis-panel` · `app-clinic-lab-orders` · `app-clinic-rad-orders` · `app-clinic-prescription` · `app-clinic-previous-visits` · `app-referral-dialog` · `app-external-result-dialog` · `app-lab-history-groups` · `app-clinic-dynamic-field-renderer` · `app-clinic-service-order-rail`.
**يُعاد استضافته ككروت تخصصية:** تغذية: `app-nutrition-patient-panel`، `app-nv-*` cards، `app-patient-body-comp`، `app-nutrition-plan-builder`… · أسنان: `app-dental-workspace` (+ `app-odontogram`، `app-dental-perio`، `app-dental-fmx`، `app-dental-ortho`، `app-dental-plan-panel`)، `app-dental-today`، `app-dental-exam`، `app-dental-lab-board`، `app-dental-recall` · إقامة: `app-nursing-panel`.
**يتفكك/يتشال:** الـ `@switch` · `app-nutrition-consult-board` كصفحة · `app-dental-alerts` · التضمينات المكررة في `clinic-patient-file`.

## 12. ترتيب التنفيذ المقترح
1. `CARD_CATALOG` + `VisitLayout` + `ClientProfile` + `resolveLayout` + `app-visit-shell` بالعام خلف `clinic.visit_shell=true`.
2. السكك + الملخص + إنهاء/توقيع (قفل BE من design.md P0) + `app-visit-layout-editor` (العميل أولاً، الدكتور خلف الإعداد) + قواعد الحقول.
3. الأسنان (الافتراضي = workspace + consult) → التغذية (بالاتفاق مع moonui) → النسا (picker + host على schema p3 + summary).
4. سياق الإقامة (بعد P2) → الـ intake wizard + `patient_alerts` (P5).
