Moon Clinic · خطة شاملة · تحليل وتصميم — التنفيذ هنا (moonui3)

المنصة الطبية الموحّدة

البيانات المشتركة والخاصة بكل تخصص، وشاشة كروت قابلة للتخصيص (كل تخصص بشكله، وكل عيادة ودكتور يرتّب لنفسه)، و«أول زيارة»، وتوحيد الروشتة والتحاليل والأشعة والمستندات والطباعة. نفس الكود للعيادة والمركز والمستشفى، والفرق إعدادات.

4 طبقات بيانات13 تكرار اتحلّكل تخصص بشكلهتخصيص لكل عيادة ودكتورأول زيارة على مرحلتينروشتة وطلبات موحّدةالنسا متدمج27 مرحلة (13 ★ للنسا)

الخلاصة

المشكلة: كل تخصص (عام، تغذية، أسنان، مستشفى، والنسا اللي جاي) بنى جزء من الحاجات المشتركة بطريقته. النتيجة إن الدكتور بيلاقي نفس الحاجة في مكان مختلف وشكل مختلف. والبيانات اتكررت: العلامات الحيوية في 5 أماكن، والحساسية في 4، والأمراض المزمنة في 5، والأدوية في 5، والتشخيص في 5. ومفيش شاشة «أول زيارة» خالص. وكل تخصص جديد بيكبّر الملخبطة.

الحل في 3 طبقات: 1. البيانات (الطبقات الأربعة): كل حقل يتوصف بحاجتين: للمريض أو للزيارة، ومشترك أو خاص بتخصص. - محرك حقول واحد، وهو موجود ومتوسّع جزئياً. - مخزن واحد للحقائق، ومخزن واحد للقياسات المتكررة (العلامات الحيوية وجولات التمريض وInBody). - الحساسية والأمراض والأدوية الخارجية ليها جداول منظّمة. كل تكرار من الـ13 ليه مالك واحد. 2. الشاشة (كروت قابلة للتخصيص): كل حاجة في الشاشة «كارت»، وكل تخصص ليه شكله الافتراضي: التغذية = البورد اللي الدكتور طلبه زي ما هو بالظبط، والأسنان = الشارت بكل تفاصيله، والعام والنسا = خطوات مرتبة. الترتيب بيتحدد على 3 مستويات: افتراضي التخصص ← العيادة ← الدكتور، ووضع «تخصيص الشاشة» بيخلّي كل دكتور يرتّب ويكبّر ويخفي ويضيف كروت. والثابت في كل الأشكال: الهيدر بالتنبيهات، و«أول زيارة»، والتوقيع والقفل، والملخص، والروشتة والطلبات والتشخيص بنفس الكود. - التخصص بيعلن كروته وشكله الافتراضي في registry، والتوحيد بيبقى في البيانات والمكوّنات والقواعد، مش إن كل الشاشات تبقى شبه بعض. - المستشفى «سياق» بيضيف محطات التمريض والأدوية والخروج فوق أي تخصص. - شاشة «أول زيارة» على خطوتين: المشترك مرة واحدة، والتخصص مرة واحدة عند أول دخول ليه. 3. البلوكات المشتركة (Clinical Core): روشتة واحدة (والمستشفى بيستخدمها)، ومنفّذ واحد للتحاليل والأشعة، والأشعة بتقريرها وصورها، ومستندات موحّدة (إجازة، تقرير، شهادة، ملخص خروج)، وتنبيهات، وطباعة PDF واحدة.

عيادة ولا مركز ولا مستشفى: نفس الكود، والفرق إعدادات بس. والتحكم في الشكل والحقول لكل عميل (مركز يشيل كروت أو حقول، ومركز تاني يسيبها)، وتخصيص الدكتور لنفسه اختياري بإعداد من العميل.

النسا (العميل الجديد): تحليل النسا متدمج جوه المنصة. 6 من جداوله المقترحة موجودة أصلاً في المنصة، و4 بقوا كيانات مشتركة (الحلقات، العمليات، المتابعات، التحويلات + مولّد الملخص)، و3 بس فاضلين خاصين بالنسا (الحمل السابق، الحمل، دورات العلاج). وفيه 13 مرحلة ★ لازمة علشان العميل يشتغل، ومنها الأمان «قبل التشغيل».

إزاي تقرا الخطة

القسم فيه إيه لمين
١ النموذج التفاعلي تقلّب بين التخصصات والسياقات، وأول زيارة ومريض راجع وزيارة موقّعة، وديسكتوب وتابلت وموبايل ليك — ابدأ بيه
٢ المراحل الموحّدة 27 مرحلة بترتيب واحد (منها 13 ★ لازمة لتشغيل عميل النسا)، وكل مرحلة ليها سيناريو تختبره على /app ليك وللوكيل
٣ ننفذ فين ✅ اتقرر: هنا (moonui3) للعلم
٤ القرارات المجمّعة 36 قرار (المنصة + النسا)، وكل واحد بتوصية، والمحسوم متعلّم قرار منك
٥ب دمج النسا تحليل النسا متركّب على المنصة: إيه موجود، وإيه بقى مشترك، وإيه فاضل خاص بالنسا، والأمان قبل التشغيل للوكيل
٥ تصميم الشاشة (UX) المناطق والمحطات وعقد الـ registry للوكيل
٦ تصميم البيانات الطبقات والمحرك وجدول تسكين كل حقل وحل التكرارات والهجرة للوكيل
٧ البلوكات المشتركة الروشتة والتحاليل والأشعة والمستندات والطباعة للوكيل

تصحيح بعد مراجعتك (2026-10-21): النسخة الأولى كانت بتفكّك بورد التغذية لمحطات، وبتختصر الأسنان. اتصلّحت: الشكل الحالي لكل تخصص هو الافتراضي زي ما هو، والتخصيص بيبقى طبقة فوقه.

اتساق بين التصاميم (اتظبط هنا): (١) اسم نوع النسا = gyn_ob في كل الوثائق. (٢) الحمل = حقل زيارة مشترك (طبقة ٣) يتملى مسبقاً 30 يوم، مش حقل تخصص. (٣) التنبيهات patient_alerts اتقدمت من P5 لـ D2. (٤) محرك الحقول الديناميكية (م6) شغّال فعلاً، فبنكمّله ومش بنبنيه من الأول.

١ · النموذج التفاعلي

جرّب: التغذية (بورد الدكتور زي ما هو)، والأسنان (الشارت وكل الشاشات الفرعية)، والعام والنسا (خطوات). اختار الطبيب (د. هبة بالافتراضي، ود. سارة بترتيبها الخاص)، وشغّل «تخصيص الشاشة» علشان ترتّب وتكبّر وتخفي وتضيف كروت وتحفظ لنفسك أو للعيادة. وجرّب كمان السياق «إقامة مستشفى»، و«أول زيارة»، وتابلت وموبايل. وتحت النموذج لوحة الـ Registry: دي اللي كل تخصص بيعلنها، ومنها بيتحسب شكل الشاشة.

افتح النموذج في صفحة كاملة ↗

بيانات تجريبية · الحفظ في المتصفح بس.

المراحل الموحّدة

ترتيب واحد يجمع التصاميم الثلاثة وتحليل النسا والتوليد والأمان (النسخة 3). P = البلوكات المشتركة، D = البيانات، S = الشاشة، E = المحرك، C = الكيانات الإكلينيكية المشتركة، G = النسا، SEC = الأمان. كل مرحلة بتتسلّم شغّالة وبتختبرها بنفسك على /app، والهيكل الجديد بيشتغل جنب الشاشة القديمة خلف الإعداد clinic.visit_shell لحد ما توافق.

★ = لازمة لتشغيل عميل النسا (عيادة بوضع عمليات برّه). النسا مش موديول لوحده: 6 من كياناته موجودة في المنصة، و4 بقوا مفهوم مشترك (الحلقات، العمليات، المتابعة، الملخص)، و3 بس جداول خاصة بيه. التفاصيل في تصميم الدمج (design-gyn-integration.md).

# المرحلة التسليم الحجم يعتمد على تختبر إيه
P0 ★ الأساس قائمة موحّدة لطرق الإعطاء والتكرار والشكل الصيدلي · encounters.kind + admission_id · قفل الزيارة الموقّعة من السيرفر · ربط المرفقات بأي كيان (+ نوع/لينك خارجي/خاص) · مستندات من غير زيارة · قراءة إعداد مصدر الأدوية S–M — زيارة موقّعة: إضافة روشتة أو طلب من الـ API بترجع رفض · الشكل الصيدلي dropdown بإضافة فورية
SEC1 ★ الجلسات والهوية انتهاء الـ tokens · خروج تلقائي بعد خمول · روابط تحميل موقّعة بدل ?token= · إيقاف المستخدم يقفل جلساته فوراً · مفيش حذف مستخدمين · throttle · MFA بتطبيق Authenticator M — (موازية) توقف مستخدم فجلسته تقع فوراً · MFA على دكتور · تحميل مرفق بلينك مؤقت
D0 ★ المحرك والعزل أعمدة التعريفات (clinical_type، carry_forward، fill_role، in_intake، storage…) · نوع gyn_ob وتعليم قسم النسا · قفل تسريب حقول التغذية · حقول إضافية وقت التسجيل · ClinicalTypeRegistry · تصحيح: إعادة تطبيق الباقة ما ترجّعش حقل العيادة خبّته M P0 تسجيل مريض في عيادة عامة: مفيش حقول تغذية · حقل مخفي يفضل مخفي بعد تحديث الباقة · حقل «للسيدات» يختفي لراجل
E1 ★ محرك الحقول نسخة 2 المنطق الشرطي الكامل (show_if بنفس الصيغة في السيرفر والفرونت) · موديولات (module_key) · صفوف متكررة · قيم مربوطة بعملية/دورة/حمل · أنواع جديدة (تاريخ/نص طويل/محسوب/استبيان/جدول/FIGO) · الحسابات (ComputedRegistry) · قوائم بإضافة فورية + مفضّلات لكل دكتور · الحقول الخاصة بصلاحية M–L D0 اختيار chip يفتح أسئلته · صف متكرر · حساب بيتحدّث وإنت بتكتب وبيتخزن · المفضّلات
S1 ★ هيكل الزيارة + محرك الكروت app-visit-shell + كتالوج الكروت + layout بيتحسب: افتراضي التخصص ← العيادة ← الدكتور (بس لو clinic.layout.allow_doctor_override مفتوح) ← السياق · مفاتيح {type}.feature.* بتشيل كروت · وضع «تخصيص الشاشة» · الخطوات للعام · إنهاء وتوقيع، خلف clinic.visit_shell M–L P0, D0 كشف عام كامل من الهيكل الجديد · الأدمن يرتّب شاشة العيادة · الدكتور ما يقدرش يغيّر إلا لو الإعداد مفتوح · «رجّع الافتراضي» شغال
P1 ★ روشتة نسخة 2 جملة جاهزة بدل «—» · تعديل قبل الطباعة · روشتة للزوج · مصدر الأدوية شغّال · بحث موحّد · PDF M P0 روشتة من جملة جاهزة تتطبع صح · تعديل بند · وضع «كتالوج مستقل» بدوا من غير منتج
D1 ★ مخزن القياسات الواحد clinical_observations + نقل البيانات القديمة + كتابة مزدوجة مؤقتة · الطول بيتملى مسبقاً · الـ trend · قياسات التخصص الإضافية (التغذية والنسا) M–L D0 زيارة تانية: الطول جاهز رمادي، والوزن جنبه «السابق 82» · trend الضغط · شارة القياسات في الطابور
D2 ★ الحقائق المنظّمة + الهيدر الموحّد patient_alerts (+ أكواد النسا: جلطة سابقة/سيولة/نقل دم/مجرى هوا) · الأمراض المزمنة chips على جدول · أدوية من برّه (kind=home) · الحمل والتدخين والحالة الاجتماعية مشتركين · clinical_notes (+ ملاحظة خاصة) · سجل تعديلات · ختم التنبيهات والأمراض والأدوية مع التوقيع L (3 WPs) D1, P1 «بياخد سيولة» في الأسنان يظهر أحمر في هيدر النسا · دوا من برّه يظهر في «الأدوية الحالية» · زيارة قديمة بتعرض اللي شافته وقتها · ملاحظة خاصة ما تظهرش لغير صاحبها
C1 ★ الكيانات الإكلينيكية المشتركة الحلقات clinical_episodes (حمل/دورة علاج/حالة تقويم/إقامة) · العمليات clinical_procedures + كتالوج hospital_operations + وضع clinic.procedures.mode (عيادة/مركز/مستشفى) · مهام المتابعة follow_up_tasks بقواعد لكل تخصص · الإحالة للفريق على ClinicReferral (نوع/فريق/حالة/عضو) · مولّد الملخص ClinicalSummaryService · PatientRecordService (من P4) · كارت الـ Timeline M–L E1, D2 يفتح حلقة · يسجّل عملية اتعملت في مستشفى برّه · مهمة متابعة بتتولّد لوحدها · إحالة لفريق بحالة · ملخص يتطبع
G1 ★ النسا — الملف والأساس باقة gyn_ob: الزوج، التنبيهات، التاريخ، الدورة، الحمل السابق + G/P/A/L في الهيدر، امتدادات الشكوى والفحص والفحوصات والتشخيص، التصنيفات، الفريق · الشكل الافتراضي · مفاتيح gyn.feature.* · الصلاحيات والأدوار · خطوة أول زيارة · ملخص العيادة · شبكة التحاليل القصوى (مشترك) M–L C1, S1 مريضة جديدة: الاستقبال يملا الزوج، التمريض التاريخ، الدكتورة تلاقي G/P/A/L جاهز · اختيار «AUB» يفتح كارته · مركز بيطفّي Urogyn فالاختيارات تختفي
G2 ★ النسا — GYN core الألياف (FIGO) · AUB · البطانة المهاجرة · الأدينوميوزس · الزوائد · PCOS · ألم الحوض · كتل الملحقات (RMI) · الأورام + MDT · عنق الرحم · الفرج والمهبل · ملخصاتهم M G1 Myoma 1..n بـ FIGO وملخص مجمّع · RMI ≥200 يقترح تحويل أورام
SEC2 ★ الاطلاع والتصدير سجل الاطلاع access_audit (مين فتح/حمّل/صدّر/طبع) · سجل التعديلات على كل موديلات العيادة · الأدمن ما ياخدش الطبي تلقائياً · نطاق البيانات على المرضى · صلاحيات منفصلة للرفع/التحميل/المشاركة/التصدير · تصدير بلا هوية M C1, G1 مين فتح ملف المريضة ومين حمّل · تصدير بلا اسم ولا تليفون
SEC3 ★ التشفير والنسخ تشفير القومي/التليفون/العنوان والملاحظات الخاصة (مع بحث شغّال) · نسخة احتياطية بالميديا، مشفّرة، خارج السيرفر، واسترجاع مجرّب M SEC2 بحث بالتليفون شغال رغم التشفير · استرجاع نسخة على بيئة تجريبية
— ▲ هنا عميل النسا يقدر يشتغل (لو الدكتورة قالت «التوليد الأول»، G5 تتقدّم مكان G3)
G3 النسا — الخصوبة تقييم العقم · السائل المنوي (WHO 2021) · محاولات سابقة · دورات التنشيط/IUI/IVF/FET ككروت بمتابعاتها · منظار تشخيصي · الزوج كمريض مرتبط M–L G2 دورة OI كارت بمتابعاتها · تفسير السائل المنوي تلقائي · IVF بنتيجتها
P5 المستندات إجازة مرضية، تقرير طبي، شهادة، ملخص خروج، تقرير UDS بقوالب ورقم متسلسل وPDF · نقل الطباعات القديمة على المحرك S–M P0 إجازة مرضية برقم تتطبع من لوحة الخروج
G4 النسا — العمليات قوالب الإجراءات (استئصال/حزام/قيصرية/vNOTES/Burch…) على clinical_procedures · النتائج والمضاعفات (Clavien) والعيّنات والميديا · خروج بأدوية جاهزة · متابعات تلقائية · ملخص العملية · وضع مركز/مستشفى بربط hospital_surgeries M–L C1, P5 تقرير عملية من القالب · المتابعات 1 أسبوع/1/3/6 شهور اتولّدت · نفس الشاشة لما الوضع يبقى مركز
D3 أول زيارة patient_intakes · خطوة مشتركة + خطوة تخصص · شارة «ملف ناقص» في الطابور · تأكيد دوري · فرض المحطات المنفصلة M D2 مريض جديد في التغذية: الاستقبال والتمريض يملوا، والدكتور يلاقي كله جاهز · نفس المريض في النسا: الخطوة النسائية بس
G5 النسا — التوليد الحمل (pregnancies) وبيملى حقل «حامل» المشترك · متابعة الحمل من القياسات (مفيش جدول زيارات تاني) · الحمل عالي الخطورة · VTE (score + تنبيه) · المخاض والولادة والقيصرية وما بعد الولادة · تقرير المواليد المتوقعة · ملخص الولادة والخروج L G1, D1 EDD/GA في الهيدر · زيارة متابعة تظهر في جدول المتابعة · VTE ≥4 ينبّه
S2 التخصصات ككروت التغذية: البورد الحالي زي ما هو كافتراضي (13 كارت بنفس الأعمدة والترتيب) ← الأسنان: الشارت + كل الشاشات الفرعية كافتراضي M–L S1 شاشة التغذية والأسنان شبه النهارده بالظبط · العيادة تقدر ترتّبها · الشكوى والتشخيص كروت اختيارية في التغذية
P2 أدوية الإقامة الأدوية على الروشتة بنوع «إقامة» · فوترة الجرعة وصرف المخزون صح · روشتة خروج M–L P1 دوا من نفس كومبوننت الروشتة · جرعة تتحاسب ويتصرف المخزون · روشتة خروج في «الأدوية الحالية»
S3 سياق الإقامة في الهيكل محطات الأدوية والتمريض + قياسات الجولة (NEWS2) + الخروج بدل المتابعة M P2, S1 فتح زيارة الإقامة من الهيكل نفسه بمحطات التمريض
P3 منفّذ الطلبات الواحد + الأشعة ExecuteCatalogItem · الاستقبال في وضع «معمل برّه» · مراحل الأشعة كاملة + إلغاء واسترداد + تغطية · طلبات من الإقامة · أدوار أخصائي/فني الأشعة L (4 WPs) P0 الاستقبال يطلب تحليل من كتالوج العيادة · أشعة: طلب ← تنفيذ ← تقرير ← «جاهز» عند الاستقبال · إلغاء قبل التنفيذ
G6 النسا — Urogyn LUTS · SUI · OAB + مذكرة المثانة · الفحص · POP-Q (قياسات بمرحلة تلقائية وقبل/بعد) · Urodynamics (تقرير يتعدّل ويتوقّع) · اضطرابات الإفراغ · الناسور · مضاعفات الـ mesh · المتابعة والاستبيانات قبل/بعد L G2, D1, P5 POP-Q stage تلقائي ومقارنة قبل/بعد · تقرير UDS يتعدّل ويتوقّع
P4 النتائج وملف المريض نتائج من غير زيارة · تاريخ التحاليل بالمريض · تقرير أشعة بقالب وصور وPDF · أكواد المطالبات M P3 تحليل walk-in يظهر في شاشة الكشف · تقرير أشعة PDF بصورة
G7 النسا — الصحة الجنسية + البحث الموديولات الخاصة بصلاحية منفصلة · FSFI / FSDS-R · ملخص الزوجين بلا الخاص · تصدير بحثي بلا هوية · مواد تعليمية M G2, SEC2 الموديول ما يظهرش لغير الطبيبة · ملخص الزوجين بلا الملاحظة الخاصة
D4 طي التخصصات جولات التمريض على مخزن القياسات · InBody (moonui) · تشخيص المستشفى في جدول واحد · محطة فرز (triage) اختيارية M D1 جولة تمريض تظهر في trend المريض · طوارئ: الحالة الحمرا أول الطابور
P6 صرف الصيدلية (POS) قائمة الروشتات المعلّقة في POS · البيع يعلّم «اتصرفت» عند الطبيب M P3, P1 روشتة ← POS ← بيع ← الشارة عند الطبيب

الأحجام: S ≈ أيام قليلة · M ≈ أسبوع · L ≈ أسبوعين أو أكتر (بتتقسم WPs). المراحل الـ ★ (13 مرحلة) ≈ 3–3.5 شهور متصلة لحد ما عميل النسا يشتغل؛ الكل ≈ 6–7 شهور. كل مرحلة ليها قيمة لوحدها، وممكن نقف بعد أي مرحلة. SEC1 ممكن تتعمل بالتوازي مع P0/D0 لأنها ما بتلمسش ملفات العيادة.

بعد كده: بوابة المريض تملا الـ intake · نقل dental_recalls ومتابعة التغذية على follow_up_tasks · طلبات المعمل من بوابة.

ننفذ فين — هنا (moonui3) ولا في moonui؟

✅ اتقرر (2026-10-21): هنا في moonui3، وmoonui متوقف لحد ما نخلص. اللي تحت هو التحليل اللي القرار اتبنى عليه، سايبينه للعلم.

الحقايق من تاريخ الكود (من منتصف سبتمبر): - موديول العيادة والتغذية: معظم الشغل من moonui، زي الروشتة والكالندر والأجهزة والخزينة وكشف التغذية الكامل (Nutrition كله بتاعه). وكمان LIS والحسابات. - moonui3 (هنا): إطار نوع التخصص (clinical_type)، والمستشفى كامل، والأسنان، وتحليل النسا، والتحليل ده. - الـ KB مش بيتزامن بين الحسابات. الخطة دي موجودة هنا بس، ولو اتنفذت في moonui لازم تتنقل يدوياً (rsync منك). - الخطة دي بتلمس الملفات الأكتر ازدحاماً: شاشة الكشف، والروشتة، والتاريخ المرضي، والعلامات الحيوية، وقارئات التغذية. لو اتنين اشتغلوا عليها في نفس الوقت، كل دمج هيبقى فيه تعارضات.

الاختيار المزايا العيوب
أ · moonui3 ينفّذ كله (تجميد ملفات العيادة المشتركة على moonui طول المراحل) الخطة والإطار والمستشفى والأسنان هنا · وكيل واحد ماسك التصميم من أوله لآخره ملفات العيادة اللي moonui بناها هتتغير هنا · لازم moonui يوقف أي تعديل على الملفات دي · تعديلات التغذية لازم تتنسق
ب · moonui ينفّذ كله صاحب العيادة والتغذية وعارف تفاصيلها · مفيش تعارض مع شغل التغذية الخطة تتنقل لـ KB بتاعه · مشغول دلوقتي بدفعات LIS والحسابات · المستشفى والأسنان (اللي هنا) لازم يتنسقوا العكس
ج · تقسيم (moonui3: P0، D0، S1–S3، P2، D4، الأسنان والنسا والمستشفى · moonui: P1 الروشتة، P3 الطلبات، P6، وتعديلات التغذية) كل واحد في المنطقة اللي يعرفها الاتنين بيلمسوا موديول العيادة في نفس الوقت = أعلى خطر تعارض · محتاج ترتيب صارم وmerge بعد كل مرحلة

القرار: (أ) — moonui3 ينفّذ كله، وmoonui متوقف. - moonui3 ماسك موديول العيادة المشترك والنسا والأمان طول المراحل. - تعديلات التغذية (قراية القياسات، الشكوى والتشخيص، الحساسية الغذائية) بتتعمل هنا بالاتفاق مع المالك، لأن moonui واقف. - merge لـ main بعد كل مرحلة، علشان لما moonui يرجع يبني على الجديد على طول. - الـ KB بتاع الخطة دي هنا بس؛ لما moonui يرجع يتنقل له يدوياً (rsync).

القرارات المجمّعة (المنصة + النسا — 36)

✅ = اتقرر · ⏳ = مستني منك · 👩‍⚕️ = مستني من الدكتورة (عميلة النسا)

# القرار التوصية الحالة
1 مكان الكور: موديول العيادة ولا موديول جديد؟ العيادة + مجلد app/Clinical/ ⏳
2 السياق: الزيارة بنوع (encounters.kind) ولا ربط polymorphic على كل جدول؟ الزيارة بنوع ⏳
3 المستشفى تخصص ولا سياق؟ سياق بيضيف محطات فوق أي تخصص ⏳
4 مخزنين للبيانات (حقائق + قياسات) ولا مخزن واحد؟ اتنين ⏳
5 الأمراض المزمنة والحساسية والأدوية الخارجية: جداول منظّمة بـ chips ولا أسئلة نعم/لا؟ جداول منظّمة + chips ⏳
6 الحمل: حقل زيارة مشترك بيتملى مسبقاً 30 يوم، ونلغي نسختي التغذية والأسنان؟ ولما النسا تيجي، سجل الحمل يملاه تلقائي أيوه ⏳
7 أقل حاجة لازم تتملى في أول زيارة: حساسية + أمراض مزمنة + أدوية (بخيار «لا يوجد» صريح)؟ أيوه ⏳
8 الشاشة الجديدة تشتغل جنب القديمة خلف إعداد لحد ما توافق؟ أيوه ⏳
8ب التشخيص في التغذية: لو العيادة شغالة تأمين ومفيش كارت تشخيص، يبقى تحذير وقت التوقيع ولا منع؟ تحذير (مش منع) ⏳ معلّق
8ج التحكم في الشكل لكل عميل أولاً: الأدمن يظبط شاشة العيادة (clinic.layout.manage)، والدكتور يعدّل لنفسه بس لو clinic.layout.allow_doctor_override مفتوح (افتراضي مقفول). الحقول بنفس الفكرة: إخفاء/إلزام لكل عيادة أيوه ✅ (تعليماتك)
9 أدوية المستشفى تتنقل على الروشتة (P2)؟ أيوه ⏳
10 الطباعة PDF من السيرفر؟ أيوه (المعاينة الحالية تفضل لحد ما تتأكد) ⏳
11 أشعة الأسنان تفضل صور على السنة، مش طلب أشعة؟ أيوه · الخارجي = طلب عادي ⏳
12 صرف الصيدلية من POS: بعد P3؟ أيوه ⏳
13 ننفذ فين (القسم اللي فوق)؟ هنا (moonui3)، وmoonui متوقف لحد ما نخلص ✅
14 تعديلات التغذية (القياسات/التشخيص/الحساسية الغذائية) تتعمل هنا بما إن moonui واقف؟ (ده بيغيّر اللي في تصميم البلوكات §5 وتصميم البيانات §7: «بالاتفاق مش بتعديل كودهم من هنا») أيوه — بموافقتك قبل D1 ⏳
15 التغذية والأسنان: الشاشات الحالية هي الافتراضي، والتخصيص طبقة فوقها أيوه ✅
16 النسا = موديول Gyn منفصل (زي الأسنان والتغذية) والكيانات المشتركة (الحلقات/العمليات/المتابعة/الملخص) في العيادة أيوه ⏳
17 حلقات النسا تبقى حلقات عامة clinical_episodes (تنفع للحمل والتقويم والبرنامج الغذائي والإقامة) أيوه ⏳
18 زيارة متابعة الحمل = زيارة عادية + قياسات، مفيش جدول زيارات حمل منفصل أيوه ⏳
19 POP-Q والاستبيانات = قياسات؛ تقرير Urodynamics = حقول + مستند — بلا جداول خاصة أيوه ⏳
20 الإحالة للفريق على ClinicReferral الموجود (نوع/فريق/حالة/عضو) مش جدول جديد أيوه ⏳
21 الزوج كمريض: تحاليل السائل المنوي محتاجة ملف مريض للزوج مربوط بالزوجة، والطلب من زيارتها أيوه ⏳
22 التشفير: الاسم يفضل بلا تشفير (عشان البحث)، والقومي/التليفون/العنوان بتشفير + فهرس بحث أيوه ⏳
23 MFA إلزامي للأدوار اللي ليها وصول طبي، اختياري للباقي أيوه ⏳
24 الصحة الجنسية: الافتراضي الطبيبة المعالجة بس، وملخص الزوجين نوع منفصل بلا الخاص أيوه ⏳
25 الأمان قبل تشغيل النسا: SEC1 (جلسات) + SEC2 (اطلاع وتصدير) + SEC3 (تشفير ونسخ) كلهم ضمن الـ ★ أيوه ⏳
G1 الاستضافة: سيرفر العيادة ولا سيرفر مخصص عندنا + أسماء اللي ليهم دخول تقني سيرفر العيادة 👩‍⚕️
G2 الأدوار الفعلية في العيادة ومين له Export وDownload جدول الأدوار في تحليل النسا §9 كبداية 👩‍⚕️
G3 التصنيفات المعتمدة (rASRM/#Enzian/EFI · IOTA/O-RADS · Robson · Clavien-Dindo) كلها متاحة وتتفعّل بالإعداد 👩‍⚕️
G4 جداول المتابعة الافتراضية (عمليات 1 أسبوع/1/3/6 شهور · Urogyn 6 أسابيع/3/6/12 شهر · الحمل بالخطورة) زي ما هي كقواعد افتراضية 👩‍⚕️
G5 الاستبيانات اللي هتتستخدم فعلاً (ICIQ-UI SF · UDI-6 · PGI-I · OAB-q · FSFI · FSDS-R) تتبذر كلها وتتطفّي اللي مش محتاجاه 👩‍⚕️
G6 لغة الملخص والطباعة وشكل الهيدر والتوقيع English طبي بعناوين عربية + إعدادات الطباعة الموجودة 👩‍⚕️
G7 أولوية المراحل بعد GYN core: الخصوبة ← العمليات ← التوليد ← Urogyn ← Sexual، ولا التوليد الأول؟ زي الترتيب في المراحل، والتوليد يتقدّم لو أهم 👩‍⚕️
G8 الموبايل: متصفح كفاية ولا تطبيق؟ متصفح دلوقتي 👩‍⚕️
G9 وضع العمليات للعيادة دلوقتي: في مستشفى برّه (external) ولا عندها غرفة عمليات؟ external في البداية؛ مرحلة G4 بتضيف المركز بإعداد 👩‍⚕️

القرارات التفصيلية كلها موجودة في كل تصميم: 13 قرار للبلوكات، و13 قرار للبيانات، وجدول المطابقة الكامل في تصميم دمج النسا.

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)

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).

دمج النسا والتوليد في المنصة الإكلينيكية الموحّدة

تصميم فقط — 2026-10-21. بيكمّل design.md (البلوكات) وdesign-data-layers.md (البيانات) وdesign-visit-shell.md (الشاشة) وmaster-plan.md. المرجع للنسا: plans/gyn-obstetrics-module.html (المصدر -src/p3a…p3g, p4a, p5-bottom) + clinic-dynamic-fields.md + gyna-reference.md. كل ادّعاء عن الكود اتفحص (file:line).


1. الخلاصة وقرارات الدمج

النسا مش موديول بشاشة لوحده — هي أول تخصص «كبير» بيركب على المنصة زي ما هي. تحليل النسا كان بيقترح 15 جدول + مجموعة آليات (قيم، تنبيهات، ملاحظات، ميديا، متابعة، audit، summary). بعد المطابقة مع التصاميم التلاتة: 6 منهم موجودين فعلاً في المنصة، 4 بيتحوّلوا لمفهوم مشترك (episodes، procedures، follow-up، summary)، و3 بس بيفضلوا جداول خاصة بالنسا (obstetric_history_rows، pregnancies، treatment_cycles + صف المتابعة). الباقي (POP-Q، PROMs، UDS، antenatal visits) بيتخزن في المخازن الموحّدة (القياسات / الإجابات / المستندات) ومفيش جداول ليه.

قرارات الدمج الأساسية (8):

  1. مفيش clinical_field_values. القيم كلها في patient_history_answers (قرار data-layers §3.2) مع alias ClinicalFieldValue. الامتداد الوحيد المطلوب للنسا: scope تالت = record (قيم مربوطة بعملية/دورة/حمل) — تفاصيله في §4.
  2. التحكم في الشكل والحقول لكل عميل أولاً (تعليمات المالك): default (كود) ← company (الأدمن) ← doctor بس لو clinic.layout.allow_doctor_override=true (الافتراضي false) ← context. الحقول نفسها بنفس الآليات الموجودة: is_active/is_required على التعريف المنسوخ للشركة + clinic.patient_form_fields {visible,required} + {type}.feature.*. مفيش آلية جديدة.
  3. موديولات النسا الـ 51 = كروت في الكتالوج بتتولّد من الباقة (module_key)، وshow_if بتاع الموديول هو اللي بيفتحها ويقفلها إكلينيكياً، وgyn.feature.* بيشيل مجموعات كاملة للعميل اللي مش محتاجها.
  4. الموديولات الأساسية بتاعة النسا (complaint/exam/imaging/dx/team) = الكروت المشتركة نفسها + حقول L4 من باقة gyn_ob بـ show_if على اختيارات الشكوى. مش كروت نسا منفصلة — وإلا نرجّع تكرار الشكوى والتشخيص اللي بنحلّه.
  5. العمليات = clinical_procedures في الكور (قرار المالك 2026-10-20، GYN §7.6)، والـ 5 جداول الكيانية المشتركة (episodes، procedures، follow_up_tasks، referral الممتد، summary) بتتبني مرة في مرحلة كور جديدة C1 قبل أول مرحلة نسا.
  6. الحمل والقياسات مش بيتكرروا: pregnancies جدول (كيان له حالة)، لكن زيارة المتابعة = encounter عادي في episode الحمل + قياساتها (BP/وزن/FHR/FH) في clinical_observations. مفيش antenatal_visits.
  7. الأمان مرحلتين مستقلتين (SEC1, SEC2) + مرحلة تشفير ونسخ (SEC3) — كلهم قبل تشغيل عميل النسا، والأغلب platform-wide مش نسا.
  8. كود النسا في Modules/Gyn + features/gyn (نفس نمط Dental/Nutrition)، والكور في Clinic. الباقة packs/gyn_ob بتتبذر بـ updateOrCreate(company_id, code) زي باقي الباقات.

2. جدول المطابقة — كل كيان في GYN §7 ومكانه في المنصة

الاختبار الواحد اللي اتطبّق على كل جدول: هو (أ) كيان له دورة حياة وحالة وتواريخ → جدول؛ (ب) قياس بيتكرر بالزمن → clinical_observations؛ (ج) نص بيتولّد ويتوقّع → clinical_documents؛ (د) حقول فورم → إجابات المحرك.

كيان GYN §7 القرار مكانه المرحلة
clinical_field_values alias patient_history_answers + repeat_index/value_json/source (D0) + scope record (E1) D0/E1
show_if / repeat / calc / module_key / lookup_key / is_private موجود في تصميم المحرك — بس grammar الـ show_if بتتبنّى من النسا لأنها الأشمل history_questions أعمدة §3.1 D0/E1
gyn_episodes يتعمّم → clinical_episodes (patient_id, clinical_type, kind, categories json, opened/closed_at, status, primary_doctor_id, team json) + encounters.episode_id nullable. التقويم والبرنامج الغذائي والإقامة كلهم «حلقات» Clinic core C1
patient_alerts موجود (D2). أكواد النسا (dvt_pe, thrombophilia, anticoag, transfusion, airway) = خيارات في clinic_history_options بـ is_alert — يعني موديول «alerts» = تعريفات storage=alert\|condition في الـ intake المشترك Clinic D2
obstetric_history_rows جدول نسا (كارت + بيغذّي G/P/A/L في الهيدر + تقارير) Modules/Gyn G1
pregnancies جدول نسا (كيان: lmp/edd/dating/risk/categories/status) + بيملى حقل الكور pregnant L3 بـ source=derived read-only Gyn G5
antenatal_visits يتشال. الزيارة = encounter في episode الحمل؛ BP/وزن/FHR/FH/EFW/AFI = observations (clinical_type=gyn_ob)؛ urine/sx/fm/presentation = إجابات L4. الإدخال الرجعي من الورق = observation set بـ encounter_id=NULL (مسموح أصلاً). كارت الـ flowsheet = view على الـ sets Clinic observations D1 + G5
treatment_cycles + cycle_visits + follicles جدولين نسا: treatment_cycles (كارت لكل دورة + إحصائيات) + cycle_monitoring (صف لكل يوم متابعة: cycle_id, encounter_id?, cd, et_mm, follicles json [{side,size}], decision). follicles كجدول تالت زيادة — الـ dashboard محتاج lead follicle بس (محسوب) Gyn G3
operations + operation_procedures كور: clinical_procedures (§7.6: patient_id, episode_id, performed_at, place, status, procedure_codes json → hospital_operations, approach, anesthesia, surgeon_id/name, hospital_surgery_id?, signed_at/by) + حقول القالب كإجابات scope=record. hospital_operations.clinical_template + clinic.procedures.mode. مفيش جدول بنود Clinic core (+ Hospital عمود واحد) C1 (الكيان) / G4 (قوالب النسا)
popq_measurements يتشال → observation set (9 تعريفات aa,ba,c,d,ap,bp,tvl,gh,pb + popq_stage محسوب على الـ set). قبل/بعد = مقارنة observed_at بتاريخ الـ procedure Clinic observations G6
prom_scores يتشال → نوع score: البنود في value_json على الزيارة + الإجمالي observation محسوب (iciq_total, udi6_total, pgii, oabq_total, fsfi_total, fsds_total) → baseline vs follow-up من الـ series Clinic G6/G7
urodynamic_studies يتشال → إجابات موديول uds على الزيارة + clinical_documents doc_type=uds_report (قالب، تعديل قبل التوقيع، PDF) Clinic documents G6
team_referrals تمديد ClinicReferral (clinic_referrals: موجود بـ referred_to_name/specialty/reason/notes بس — ClinicReferral.php:28-38): + kind (external\|team\|mdt), + episode_id, + team, + member_user_id, + status (requested\|seen\|opinion\|joint\|back), + plan. نطاق «حالاته» = عضوية الفريق من هنا ومن clinical_episodes.team Clinic C1
follow_up_tasks كور (patient_id, source_type/id morph, clinical_type, due_at, template json, status, done_encounter_id) + قواعد لكل تخصص في الـ registry (followup_rules). بيوحّد dental_recalls + admissions.follow_up_on + متابعة التغذية لاحقاً Clinic C1
clinical_notes موجود (D2) + is_private + module_key + record morph. الخاص = صلاحية Clinic D2
media موجود (P0): clinic_patient_attachments morph + kind (photo\|video\|link\|pdf) + external_url + is_private + module_key. التحميل بيتسجّل في SEC2 Clinic P0 (+SEC2)
access_audit كور في SEC2 (مش نسا) Core/Clinic SEC2
Summary generator ClinicalSummaryService واحد في Clinic: قوالب لكل module_key (الـ 51 دالة sum بتتنقل من JS لـ PHP + مرآة TS للملخص الحي) + أنواع من الـ registry (clinic, fertility, operative, antenatal, delivery, discharge, followup, uds, urogyn, couple). الخاص مستبعد إلا بـ include_private + صلاحية. الناتج = clinical_documents doc_type=summary (snapshot يتطبع) Clinic C1 (المحرك) / كل G (قوالبها)
GET /gyn/definitions · /record · PUT values الـ endpoints المشتركة: GET clinic/fields?clinical_type=gyn_ob (D0) · GET clinic/patients/{p}/record?sections= + PatientRecordService::extend('gyn_ob') (يتقدّم من P4 لـ C1) · upsert الإجابات الموجود + scope record Clinic D0/C1
صلاحيات gyn.* المشترك بيبقى clinic.*: notes.private, media.upload/download/share, export.identified/deidentified, alerts.manage, lookups.manage, summary.generate, procedures.view/edit/sign, episodes.manage. النسا بس: gyn.cycles.*, gyn.pregnancy.*, gyn.urogyn.*, gyn.uds.sign, gyn.sexual.view/edit. الأدوار المبذورة زي §7.3 Gyn seeder G1
Timeline كارت مشترك بيقرا encounters + episodes + procedures + documents + referrals + follow_up_tasks. مش كومبوننت نسا Clinic FE C1

3. الموديولات ككروت + التحكم لكل عميل

تلات آليات رؤية، كل واحدة ليها دور ما يتداخلش مع التانية:

الآلية بتتحكم في مين بيظبطها
gyn.feature.{fertility, obstetrics, urogyn, sexual, oncology, operations} (نمط dental.feature.* — DentalSettings.php:20) وجود مجموعة كاملة للعميل: chips التصنيفات + كروت الموديولات + الصلاحيات + قوالب الـ summary أدمن العيادة (إعدادات)
layout JSON clinic.layout.gyn_ob ترتيب/حجم/طي/إخفاء كروت الـ shell أدمن (clinic.layout.manage)؛ الدكتور لو allow_doctor_override
show_if على الموديول والحقل الرؤية الإكلينيكية جوه الزيارة (اختيار بيفتح موديول) التصميم — مش إعداد
is_active / is_required على التعريف المنسوخ للشركة + clinic.patient_form_fields حقل بعينه مخفي/إلزامي لعميل أدمن (شاشة الحقول — CRUD موجود)

تصحيح لازم في D0: ClinicProfilePackService.php:78-79 بيكتب is_active=true, is_required=false جوه قيم الـ updateOrCreate → أي إعادة تطبيق للباقة (تحديث MoonStack أو زرار «تطبيق باقة») بترجّع الحقول اللي العيادة خبّتها. القاعدة: الأعمدة دي تتكتب عند الإنشاء بس.

إزاي الـ 51 موديول بيبقوا كروت: الباقة بتبذر التعريفات بـ module_key، والـ registry بيولّد CardDef لكل module_key (kind:'spec', spec:'gyn_ob', feature:'gyn.feature.X', showIf:<module show_if>). الكارت بيتعرض بـ app-clinic-dynamic-field-renderer مفلتر بالـ module — مفيش كومبوننت لكل موديول. اللي ليه كومبوننت خاص: obhx (جدول الحمل السابق)، oi/ivf (كروت الدورات)، antenatal (flowsheet)، popq (ودجت)، operation (شاشة الـ procedure)، team (الإحالات)، timeline.

الـ layout الافتراضي gyn_ob: عمود ١ flow:true (محطات): القياسات 🔗 → الشكوى 🔗 (+ أسئلة النسا الشرطية) → التصنيفات (gyn_categories — chips لكل مجموعة مفعّلة؛ required) → الفحص 🔗 (+ فحص النسا) → الفحوصات المنظّمة (gyn_imaging) → التشخيص 🔗 → التحاليل/الأشعة/الروشتة 🔗 (الروشتة بـ subjectEnabled) → الإحالة/الفريق → المتابعة. عمود ٢ (flow:false): كروت الموديولات اللي show_if بتاعها صحيح، بترتيب المجموعات؛ الدورات والعمليات والحمل كروت قابلة للتكرار (صف لكل كيان). السكة: الهيدر فيه G/P/A/L + EDD/GA + التنبيهات؛ الـ timeline؛ الملخص الحي. فين الـ cat: اختيارات التصنيفات بتتخزن كإجابات L4 gyn_cat_{group} على الزيارة ∪ categories بتاعة الحلقات المفتوحة — وده اللي الـ evaluator بيقرا منه (النموذج كان بيحطها في state عام بلا بيت).

عميلين مختلفين: مركز A بيطفّي gyn.feature.urogyn وgyn.feature.sexual → chips الـ uro/sex وكروت الـ 13 موديول وصلاحيات gyn.sexual.* وقوالب الـ summary بتاعتهم بتختفي، ومفيش حاجة تتمسح. مركز B سايبهم. وجوّه نفس المركز، الأدمن يخفي حقل «Ferriman-Gallwey» بـ is_active=false، ويخلّي «الزواج السابق» إلزامي بـ is_required.


4. ملاءمة المحرك — الأنواع والشروط والحسابات

الأنواع (عدّ فعلي من الـ schema): chips 286 · seg 242 · text 145 · num 107 · bool 81 · date 56 · sel 53 · calc 42 · repeat 16 · area 8 · table 5 · media 5 · score 3 · popq 2 · figo 1.

نوع GYN في المحرك ملاحظة
chips / seg / sel / bool / num / text multi_select / single_select / boolean / numeric / text — موجود seg و sel نفس النوع بـ meta.render=segmented\|dropdown
date · area · calc جديد: date, textarea, computed computed = is_computed + computed_key (موجودين)
repeat · table repeat_group + value_json + repeat_index (D0) table = repeat بـ meta.render=grid
score جديد score: meta.items + البنود value_json + الإجمالي observation محسوب §2
media مش حقل — كارت المرفقات مفلتر بـ module_key P0 morph
popq جديد ودجت بيكتب observation set من 9 قيم + popq_stage G6
figo single_select بـ meta.render=figo G2

الفجوة الوحيدة في الأعمدة: meta json null (w/cols/items/render/card) — مش في قائمة data-layers §3.1، يتضاف في E1.

الـ show_if: الاستخدام الفعلي: k 337 · has 206 · any 111 · eq 93 · in 39 · cat 20 · mod 18 (35 مرجع فريد عبر الموديولات) · truthy 14 · all 4 · gt 3. القرار: grammar النسا هي grammar المنصة (أشمل من {field,op,value} في data-layers): المرجع k (نفس الموديول) أو mod:'m.k' أو patient.* أو encounter.*؛ العمليات eq\|in\|has\|nothas\|gt\|truthy؛ التركيب any\|all؛ وcat. مفسّر واحد ShowIfEvaluator في PHP (التحقق + الـ summary) وTS (العرض) بنفس حالات الاختبار. الـ mod: بيتحل من إجابات نفس الزيارة + الحلقة + المريض حسب scope التعريف المرجعي.

scope record (الامتداد الوحيد على القيم): scope_key عمود عادي بيساوي COALESCE(encounter_id,0) من saving() (migration 2026_07_03_100001:17-24,43-47)، والـ unique (patient_id, history_question_id, scope_key). الإضافة: record_type varchar(24) NOT NULL default '' + record_id nullable؛ الـ hook يبقى scope_key = record_id ?? encounter_id ?? 0؛ الـ unique (patient_id, history_question_id, record_type, scope_key, repeat_index). كده قيم العملية/الدورة/الحمل بتتخزن بنفس الجدول بلا عمود nullable في المفتاح.

الحسابات (30 مفتاح في الـ schema): - مرايا مش حسابات (7): from:imaging.pap/hpv/amh/fsh/afc_total, from:profile.rh, from:uroexam.pvr → computed_key=mirror + meta.ref. - قالب ملخص مش حساب (1): udsReport → ClinicalSummaryService نوع uds. نص ثابت (1): muiNote → meta.hint. - 27 حساب حقيقي في ComputedRegistry (PHP — موجود له bmi/news2) + مرآة TS: age, bmi, bmiProfile, gpal, utvol, afc, rasrm, rotterdam, rmi, semenTotal, semenWho, fertRate, edd, ga, gaAt, gdm, vte, bishop, pph, iciq, diary, diaryFrom, npi, popq, promChange, fsfi, fsds, oabClass, ufSum. البعض محتاج بيانات برّه الموديول: age/bmi (المريض)، gpal (obstetric rows + pregnancies)، edd/ga/gaAt (pregnancies)، popq (observation set)، promChange (series)، vte (BMI/السن/parity مشتقين). الـ BE هو الحاكم عند الحفظ (بيكتب القيمة source=derived للبحث والملخص)، والـ FE للعرض الحي.

المفردات: V (tube/hsgUt/tvsUt/endo/ovary/cx/pelvis/lap…) وPROC_LIB (60 إجراء) وCATS → clinic_history_options بـ lookup_key + إضافة inline بتترسّخ + favorites لكل دكتور* (جينا — clinic_favorites موجود). PROC_LIB بالذات → صفوف في hospital_operations (specialty=gyn) لأنه الكتالوج الواحد (§7.6).

الشبكة القصوى للتحاليل (GYN §7.5 + جينا): تعديل في الكومبوننت المشترك app-clinic-lab-orders (وضع grid بفئات + «حدد الفئة» + حارة favorites) — WP مشترك أول مستهلكه النسا، مش كود نسا.


5. الأمان «قبل التشغيل» — مراحل SEC

القائمة المرجعية = فجوات المنصة المسجّلة في clinic-dynamic-fields.md:168 + GYN §9. التقسيم:

المرحلة المحتوى platform / نسا
SEC1 — الجلسات والهوية (M) sanctum.expiration (دلوقتي null — config/sanctum.php:50) + خروج تلقائي للـ FE بعد خمول (auth.idle_minutes, افتراضي 15 على الموبايل) · شيل ?token= (ResolveAuthToken.php:24) — لازم روابط موقّعة قصيرة العمر للتحميل تتعمل في نفس المرحلة وإلا كل روابط التحميل تتكسر · إيقاف المستخدم = إلغاء كل الـ tokens فوراً + قفل جلسة جهاز بعينه · حذف المستخدمين soft · throttle عام على الـ API + على login (موجود بس على app-info) · MFA بـ TOTP (Authenticator) — إلزامي للأدوار اللي ليها clinic.* طبي، اختياري للباقي platform
SEC2 — الاطلاع والتصدير (M) جدول access_audit (user_id, patient_id, action view\|download\|upload\|export\|share\|print, record morph, ip, at) بيتكتب من middleware على endpoints الملف + listener على المرفقات والـ PDF · LogsActivity على موديلات Clinic (صفر دلوقتي) + ظهورها في شاشة الـ activity log · دور admin ما ياخدش *.view الطبي تلقائياً · DataScope على PatientController@index · صلاحيات منفصلة clinic.media.upload/download/share + clinic.export.identified/deidentified + export جداول الـ FE بصلاحية · De-identified export (اسم/تليفون/قومي/عنوان بتتشال، التواريخ → سنة) platform
SEC3 — التشفير والنسخ (M) encrypted casts على national_id, phone, address + blind index (hash) للبحث بالتليفون/القومي · الملاحظات الخاصة والـ value_json الحساسة مشفّرة · الـ backup يشمل الـ private disk + مشفّر + خارج السيرفر + تجربة استرجاع (RPO يوم / RTO 4 ساعات) · DPA platform (ops)
خاص بالنسا (جوه G1/G7) موديولات priv:true (sexhx/sexexam/sextx) بصلاحية gyn.sexual.view — الافتراضي الطبيبة المعالجة بس · الملاحظة الخاصة مستبعدة من أي summary/export إلا include_private بصلاحية · Couple summary نوع منفصل بلا خاص · نطاق «حالاته» للفريق من clinic_referrals.member_user_id + clinical_episodes.team نسا

قرار مطلوب: تشفير الاسم بيكسر البحث بالاسم (أهم بحث في الاستقبال). التوصية: الاسم يفضل plain، والتشفير على القومي/التليفون/العنوان بـ blind index.

الترتيب للتشغيل الآمن: SEC1 بدري (مستقلة عن الشغل الإكلينيكي، ممكن تتعمل جنب P0/D0) ← SEC2 بعد C1/G1 (عشان تغطي الـ endpoints الجديدة) ← SEC3 آخر حاجة قبل الـ go-live.


6. المراحل الموحّدة v3 (منصة + نسا + أمان)

P بلوكات · D بيانات · S شاشة · E محرك · C كيانات كور · G نسا · SEC أمان. ★ = لازمة لتشغيل عميل النسا (MVP: عيادة بوضع procedures.mode=external).

# المرحلة التسليم حجم يعتمد على المالك يختبر على /app
P0 ★ الأساس (design.md P0) + المرفقات morph بـ kind/external_url/is_private/module_key S–M — زيارة موقّعة ترفض روشتة من الـ API · شكل صيدلي inline
SEC1 ★ الجلسات والهوية انتهاء tokens · خروج تلقائي · روابط موقّعة بدل ?token= · إيقاف = إلغاء الجلسات · soft delete · throttle · MFA M — (موازية) يوقف مستخدم وجلسته تقع فوراً · MFA على دكتور · تحميل مرفق بلينك موقّع
D0 ★ المحرك والعزل (data-layers D0) + تصحيح الباقة ما ترجّعش is_active/is_required + gyn_ob case M P0 تسجيل في عيادة عامة بلا حقول تغذية · حقل مخفي يفضل مخفي بعد إعادة تطبيق الباقة
E1 ★ محرك v2 grammar show_if الكاملة (PHP+TS) · module_key · repeat_group/value_json · scope record · أنواع date/textarea/computed/score/table/figo + meta · ComputedRegistry + مرآة TS · lookups بإضافة inline + favorites لكل دكتور · is_private بصلاحية من الـ registry M–L D0 حقل يفتح لما يختار chip · صف متكرر · محسوب بيتحدّث live وبيتخزن · favorites
S1 ★ هيكل الزيارة + الكروت (visit-shell §11-1,2) بالحل default ← company ← doctor(لو allow_doctor_override) ← context + {type}.feature.* بتسقط كروت M–L P0, D0 كشف عام من الهيكل · الأدمن يرتّب للعيادة · الدكتور ما يقدرش يعدّل إلا لو الإعداد مفتوح
P1 ★ روشتة v2 (design.md P1) + subject=spouse + PDF M P0 روشتة بجملة جاهزة · روشتة للزوج
D1 ★ مخزن القياسات (data-layers D1) + قياسات النسا (fundal_height, fetal_hr) M–L D0 طول prefill · trend
D2 ★ الحقائق + الهيدر (data-layers D2) + أكواد تنبيهات النسا في الكتالوج + clinical_notes.is_private/module_key/record L (3 WPs) D1, P1 «بياخد سيولة» أحمر في كل عيادة · ملاحظة خاصة ما تظهرش لغير صاحبها
C1 ★ الكيانات الإكلينيكية المشتركة clinical_episodes + encounters.episode_id · clinical_procedures + hospital_operations.clinical_template + clinic.procedures.mode · follow_up_tasks + قواعد الـ registry · تمديد ClinicReferral (kind/team/status/member/plan) · ClinicalSummaryService + doc_type=summary · PatientRecordService::extend (يتقدّم من P4) · كارت Timeline M–L E1, D2 يفتح حلقة · يسجّل عملية برّه (external) · مهمة متابعة بتتولّد · إحالة لفريق بحالة · ملخص يتطبع
G1 ★ نسا — الملف والأساس باقة gyn_ob (profile/الزوج، alerts، history، menstrual، obstetric_history_rows + G/P/A/L في الهيدر، امتدادات الشكوى/الفحص/الفحوصات/التشخيص، التصنيفات، الفريق) · layout افتراضي · gyn.feature.* · صلاحيات وأدوار · خطوة intake نسا · summary clinic · شبكة التحاليل القصوى (مشترك) M–L C1, S1 مريضة جديدة: الاستقبال يملا الزوج، التمريض التاريخ، الدكتورة تلاقي G/P/A/L في الهيدر · اختيار «AUB» يفتح كارته · مركز بيطفّي urogyn فالـ chips تختفي
G2 ★ نسا — GYN core fibroid (FIGO)، aub، endometriosis، adenomyosis، polyp، pcos، pelvic_pain، adnexal (RMI)، onc + MDT، cervical، vulval · قوالب الـ summary بتاعتهم M G1 Myoma 1..n بـ FIGO وملخص مجمّع · RMI ≥200 يقترح تحويل أورام
SEC2 ★ الاطلاع والتصدير access_audit · LogsActivity على Clinic · admin بلا طبي · DataScope على المرضى · صلاحيات media/export · de-identified export M C1, G1 مين فتح ملف المريضة ومين حمّل · export بلا هوية
SEC3 ★ التشفير والنسخ casts مشفّرة + blind index · backup بالميديا مشفّر + استرجاع مجرّب M SEC2 بحث بالتليفون شغال رغم التشفير · استرجاع نسخة على بيئة تجريبية
— ▲ نقطة تشغيل عميل النسا (مرهونة بقرار الدكتورة Q7: لو «التوليد الأول» G5 تتقدّم مكان G3)
G3 نسا — الخصوبة infertility، semen (WHO 2021)، prev_art، treatment_cycles + cycle_monitoring (OI/IUI/IVF/FET كروت)، diag_lap · الزوج كمريض مرتبط M–L G2 دورة OI كارت بمتابعاتها · تفسير السائل المنوي · IVF بالنتيجة
P5 المستندات (design.md P5) + doc_type=uds_report\|summary S–M P0 إجازة مرضية برقم
G4 نسا — العمليات قوالب الإجراءات (gyn_tlh, gyn_mus, gyn_cs, vnotes, burch…) على clinical_procedures · findings/Clavien/عيّنات/ميديا · discharge document + أدوية جاهزة · follow-up تلقائي · operative summary · وضع center/hospital (ربط hospital_surgeries) M–L C1, P5 تقرير عملية من القالب · المتابعات 1w/1m/3m/6m اتولّدت · نفس الشاشة لما الوضع يبقى مركز
D3 أول زيارة (data-layers D3) M D2 مريضة جديدة تملا الخطوة النسائية بس
G5 نسا — التوليد pregnancies (+ pregnant derived) · flowsheet من observations · highrisk · VTE (score + تنبيه) · labour/vd/cs/postpartum (scope record) · تقرير المواليد المتوقعة · delivery/discharge summary L G1, D1 EDD/GA في الهيدر · زيارة متابعة تظهر في الـ flowsheet · VTE ≥4 ينبّه
S2 التخصصات ككروت التغذية والأسنان كافتراضيات زي ما هم M–L S1 شاشة التغذية والأسنان شبه النهارده
P2 أدوية الإقامة (design.md P2) M–L P1 MAR من الروشتة
S3 سياق الإقامة (visit-shell) M P2, S1 محطات التمريض من الهيكل
P3 منفّذ الطلبات + الأشعة (design.md P3) L (4 WPs) P0 أشعة طلب ← تقرير ← جاهز
G6 نسا — Urogyn luts، sui، oab + bladder diary، uroexam، POP-Q (observation set widget)، uds (document)، voiding، fistula، meshc، urofu (PROMs baseline vs follow-up) L G2, D1, P5 POP-Q stage تلقائي ومقارنة قبل/بعد · تقرير UDS يتعدّل ويتوقّع
P4 النتائج والسجل نتائج بلا زيارة · تاريخ التحاليل · تقرير أشعة PDF · sbscs_code M P3 تحليل walk-in في الكشف
G7 نسا — Sexual health + بحث sexhx/sexexam/sextx (خاص)، FSFI/FSDS-R، couple summary، export بحثي بلا هوية، مواد تعليمية M G2, SEC2 الموديول ما يظهرش لغير الطبيبة · couple summary بلا الخاص
D4 طي التخصصات (data-layers D4) M D1 جولة تمريض في الـ trend
P6 صرف الصيدلية (design.md P6) M P3, P1 روشتة ← POS ← «اتصرفت»

الإجمالي: الـ MVP (13 مرحلة ★) ≈ 3–3.5 شهور متصلة؛ الكل ≈ 6–7 شهور. SEC1 ممكن تتعمل بالتوازي مع P0/D0 لأنها ما بتلمسش ملفات العيادة.


7. القرارات للمالك — القائمة المدمجة

✅ = اتقرر · ⏳ = مستني

# القرار التوصية الحالة
1 مكان الكور: Clinic + app/Clinical/ Clinic ⏳
2 السياق = encounters.kind مش polymorphic أيوه ⏳
3 المستشفى سياق مش تخصص أيوه ⏳
4 مخزنين (حقائق + قياسات) اتنين ⏳
5 المزمن/الحساسية/الأدوية الخارجية جداول منظّمة + chips أيوه ⏳
6 الحمل حقل زيارة مشترك prefill 30 يوم، وpregnancies تملاه derived لما تيجي أيوه ⏳
7 الحد الأدنى للـ intake = حساسية + مزمن + أدوية أيوه ⏳
8 الشاشة الجديدة جنب القديمة خلف إعداد أيوه ⏳
8ب تشخيص التغذية مع التأمين: تحذير مش منع تحذير ⏳ (معلّق)
8ج التحكم في الشكل لكل عميل أولاً؛ الدكتور بس لو clinic.layout.allow_doctor_override (افتراضي مطفي) أيوه ✅ (تعليمات المالك)
9 أدوية المستشفى على الروشتة (P2) أيوه ⏳
10 الطباعة PDF من السيرفر أيوه ⏳
11 أشعة الأسنان صور على السنة أيوه ⏳
12 الصرف من POS بعد P3 أيوه ⏳
13 ننفذ فين moonui3، وmoonui متوقف ✅
14 تعديلات التغذية (القياسات/التشخيص/الحساسية الغذائية) تتعمل هنا بما إن moonui واقف — بموافقة المالك قبل D1. ده بيغيّر design.md §5 وdesign-data-layers.md §7 اللي كانوا بيقولوا «بالاتفاق مش بتعديل كودهم من هنا» أيوه ⏳
15 التغذية والأسنان: الشاشات الحالية هي الافتراضي أيوه ✅
16 النسا = Modules/Gyn + features/gyn، والكيانات المشتركة في Clinic (C1) أيوه ⏳
17 gyn_episodes → clinical_episodes عام أيوه ⏳
18 زيارة المتابعة الحملية = encounter + observations، مفيش antenatal_visits أيوه ⏳
19 POP-Q وPROMs = observations؛ UDS = إجابات + مستند — بلا جداول أيوه ⏳
20 الإحالة للفريق = تمديد ClinicReferral مش جدول جديد أيوه ⏳
21 الزوج كمريض: تحاليل السائل المنوي محتاجة صف lab_patients للزوج مربوط بـ spouse_patient_id، والطلب بيتعمل من زيارتها (subject=spouse على الروشتة بس مش كفاية للـ LIS). بيت واحد لبيانات الزوج: في الـ MVP إجابات L2 (gyn_spouse_*) هي السجل؛ من G3 صف lab_patients هو المصدر وإجابات الزوج تبقى مرايا (computed_key=mirror) — نفس آلية from:x.y أيوه ⏳
22 الاسم ما يتشفّرش (البحث)؛ القومي/التليفون/العنوان بـ blind index أيوه ⏳
23 MFA إلزامي للأدوار الطبية، اختياري للباقي أيوه ⏳
24 Sexual module: الافتراضي الطبيبة المعالجة بس، والـ couple summary نوع منفصل أيوه ⏳
25 الأمان قبل تشغيل النسا: SEC1 + SEC2 + SEC3 ضمن الـ ★ أيوه ⏳
G1 الاستضافة: سيرفر العيادة ولا سيرفر مخصص عندنا + أسماء اللي ليهم دخول سيرفر العيادة ⏳ (الدكتورة)
G2 الأدوار الفعلية ومين له Export/Download جدول §9 كبداية ⏳ (الدكتورة)
G3 التصنيفات المعتمدة (rASRM/#Enzian/EFI · IOTA/O-RADS · Robson · Clavien) كلها متاحة، تتفعّل بالإعداد ⏳ (الدكتورة)
G4 جداول المتابعة الافتراضية (عمليات 1w/1m/3m/6m · urogyn 6w/3/6/12m · حمل بالخطورة) زي ما هي كـ followup_rules ⏳ (الدكتورة)
G5 الاستبيانات المستخدمة فعلاً (ICIQ/UDI-6/PGI-I/OAB-q/FSFI/FSDS-R) تتبذر كلها، تتطفّي بـ is_active ⏳ (الدكتورة)
G6 لغة الـ summary والطباعة English طبي بعناوين عربية + هيدر clinic.print.* ⏳ (الدكتورة)
G7 أولوية المراحل بعد G2: الخصوبة ← العمليات ← التوليد ← Urogyn ← Sexual، ولا التوليد الأول؟ زي الترتيب في §6 (G5 تتقدّم لو التوليد أهم) ⏳ (الدكتورة)
G8 الموبايل: متصفح متصفح دلوقتي ⏳ (الدكتورة)
G9 clinic.procedures.mode للعيادة دلوقتي: external ولا center؟ external في الـ MVP (G4 بيضيف center) ⏳ (الدكتورة)

القرارات التفصيلية التانية موجودة في كل تصميم (13 للبلوكات، 13 للبيانات).

طبقات البيانات الإكلينيكية — الأربع طبقات + المحرك + الـ Intake (تصميم بيانات)

تحليل فقط — 2026-10-21. امتداد لـ design.md (Clinical Core) مش بديل له. المرجع: r3/r4 + فحص مباشر للكود (BE = /home/moonui3/moon-erp-be/Modules, FE = /home/moonui3/public_html/moon-erp/src/app/features). تصحيح مهم لـ design.md §4.7/§8: «vitals الديناميكية (م6) بعد P6» — م6 اتنفذ فعلاً: history_questions فيها scope/category/is_required (2026_07_03_100000) + unit/normal_*/danger_*/danger_values/is_computed/computed_key (2026_07_07_010001)، وpatient_history_answers فيها encounter_id nullable + scope_key + value_num (2026_07_03_100001, 2026_07_07_010002)، وVitalsService::mirrorToUnified بيكتب الـ vitals فيها، وencounters.history_snapshot بيتختم عند التوقيع. اللي ناقص هو الباقي اللي تحت.


1. الخلاصة

  • كل حقل إكلينيكي بيتوصف بـ بُعدين: scope (patient | encounter) × pack (core | تخصص). التقاطع هو الطبقات الأربع — مش عمود layer، ده مشتق.
  • محرك واحد = history_questions (موجود ومتوسّع) + مخزن واحد للحقائق = patient_history_answers (موجود) + مخزن واحد للقياسات = clinical_observations (جديد، time-series). الفرق: الحقيقة ليها قيمة واحدة لكل scope؛ القياس بيتكرر داخل نفس الـ scope (جولات تمريض، وزن تليفون، InBody).
  • الحقائق المهيكلة ليها جداولها: الحساسية → patient_alerts، الأمراض → past_medical_history (بتتسمى patient conditions)، العمليات/العائلي → جداولهم، الأدوية الخارجية → prescriptions.kind=home. الأسئلة الـ boolean المكررة (diabetes، dent_anticoagulant…) بتتحول لـ chips على الجدول المهيكل مش إجابات.
  • العزل بعمود clinical_type على التعريف بدل hack الـ prefix (isNutritionQuestion) — وده اللي بيقفل تسريب nut_ في شاشة التسجيل.
  • أول زيارة = Intake مرحلي: خطوة مشتركة مرة واحدة + خطوة لكل تخصص عند أول encounter في النوع ده، بحالة متتبعة في patient_intakes وشارة في الطابور.
  • التخصص بيعلن ولا يكرر: باقة L2/L4 + vitals إضافية + خطوة intake + endpoints الـ workspace — كلها في ClinicalTypeRegistry بالكود (قرار المالك 2026-10-03).

القرار المفتاحي الوحيد: الحقائق (facts) والقياسات (observations) مخزنين مختلفين على نفس التعريفات. محاولة «كل حاجة في patient_history_answers» (clinic-dynamic-fields §3.3) هي سبب وجود 3 جداول vitals موازية — المفتاح الفريد (patient_id, question_id, scope_key) بيسمح بقيمة واحدة للزيارة، والإقامة زيارة واحدة طولها أسبوع.


2. الطبقات الأربع

L1 — مريض / مشترك L2 — مريض / تخصص L3 — زيارة / مشترك L4 — زيارة / تخصص
التعريف scope=patient, clinical_type=NULL scope=patient, clinical_type=X scope=encounter, clinical_type=NULL scope=encounter, clinical_type=X
المحتوى ديموغرافيا، فصيلة، alerts/حساسية، أمراض مزمنة، عمليات، عائلي، أدوية حالية، اجتماعي (تدخين/حالة اجتماعية/وظيفة) نسا: دورة/G-P-A؛ تغذية: عادات أكل/هدف/تفضيلات؛ أسنان: alerts أسنان + baseline الشارت vitals الأساسية 9، شكوى (picks + سطر حرفي)، فحص، تشخيص، طلبات، Rx، مستندات، متابعة تغذية: محيط/InBody/خطة؛ نسا: fundal height/حمل؛ أسنان: فحص الأسنان 12 + الشارت؛ إقامة: جولات تمريض/NEWS2
مين بيملى استقبال (ديموغرافيا) + تمريض/مساعد (التاريخ) + الطبيب يراجع. لاحقاً: بوابة المريض أخصائي التخصص أو مساعده؛ التغذية: الاستقبال بيقدر (موجود) محطة القياسات (تمريض) → محطة الشيت (مساعد) → الطبيب طبيب التخصص (أو جهاز: InBody / تمريض للإقامة)
إمتى أول مرة (intake مشترك) ثم تأكيد دوري أول encounter في النوع ده (intake تخصصي) كل زيارة كل زيارة في التخصص
Carry-forward القيمة نفسها (مفيش نسخ): تتعرض مملوءة في كل زيارة بشارة «من {تاريخ}» (carried المحسوب — موجود) نفس القاعدة لا؛ بس تعريفات معينة carry_forward=prefill (طول/حمل) بـ stale_after_days لا
تعديل / Audit قابل للتعديل في أي زيارة؛ LogsActivity على الإجابات والجداول المهيكلة (مش موجود — يتضاف) + history_snapshot عند التوقيع (موجود) يختم اللي الزيارة شافته نفسه يتقفل مع توقيع الزيارة (EncounterLockedException) + amendments نفسه
فين بيظهر الهيدر الثابت (alerts/مزمن/أدوية) + محطة «البيانات الأساسية» من الـ rail قسم مطوي في محطة البيانات الأساسية (يظهر بس لو التخصص فعّال) محطات الـ shell بالترتيب خانة الـ SPECIALTY WORKSPACE

3. الـ Engine

3.1 التعريفات — history_questions (الاسم يفضل؛ model alias ClinicalFieldDefinition)

العمود الحالة الغرض
code, label_ar/en, input_type, section, department_id, is_active, sort_order, is_required, scope, category, unit, normal_min/max, danger_min/max, danger_values, is_computed, computed_key موجود زي ما هو (أسماء م6 مجمّدة)
clinical_type string(24) null يتضاف NULL = core؛ nutrition/dental/gyn_ob… = باقة التخصص. هو مفتاح العزل بدل department_id (مركز فيه 3 أقسام تغذية) وبدل prefix الكود. الـ prefix يفضل convention للـ idempotency بس
module_key string(32) null يتضاف (GYN v2) تجميع حقول الـ workspace لموديول (مثلاً antenatal)
show_if json null يتضاف (GYN v2) شرط إظهار {field, op, value} — مفسّر واحد PHP + TS. المرجع ممكن يكون حقل مريض (patient.gender, patient.age) أو سياق الزيارة (encounter.kind) — ده اللي بيخلي rr/on_oxygen/consciousness/news2 core (clinical_type=NULL) لكن تظهر بس في kind in [inpatient, emergency]. مفيش عمود kinds منفصل
repeat_group string(32) null يتضاف (GYN v2) صفوف متكررة (أطفال سابقين، أسنان…)
lookup_key string(32) null يتضاف (GYN v2) الخيارات من كتالوج مُدار بدل history_answer_options (مثلاً condition → clinic_history_options)
is_private bool يتضاف (GYN v2) يتطلب صلاحية clinic.fields.private
carry_forward string(8) default none جديد none | prefill (الزيارة الجديدة تبدأ بآخر قيمة، لازم تأكيد) — للـ scope=encounter بس (الـ patient-scope أصلاً قيمة واحدة)
stale_after_days smallint null جديد مع prefill: بعدها القيمة تتعرض رمادي ولازم إعادة إدخال (طول البالغين 365؛ حمل 30)
fill_role string(12) default doctor جديد reception | nurse | assistant | doctor | patient — مين بيملى افتراضياً؛ بيحدد المحطة والـ intake
in_intake bool default false جديد الحقل يظهر في خطوة الـ intake (المشتركة لو core، التخصصية لو clinical_type)
storage string(16) default answer جديد answer | observation | alert | condition | surgery | family | home_rx — فين القيمة بتتخزن. ده اللي بيخلي الـ chips المهيكلة تفضل «تعريفات» في نفس المحرك

category تفضل الـ router للوحة: profile (تسجيل) · history (حقائق طبية) · vitals (قياسات) · exam (جديد — فحص الزيارة/الـ workspace) · custom.

3.2 مخزن الحقائق — القرار: patient_history_answers يفضل، مفيش clinical_field_values كجدول

كل القرّاء الحاليين (VitalsService, PatientReadService chronic/allergies, SnapshotEncounterHistory, backfill 010003, الكنترولرين) بيقروا منه — جدول تاني = مكرر رقم 14. تمديد: - + repeat_index smallint default 0 يدخل في الـ unique: (patient_id, history_question_id, scope_key, repeat_index). - + value_json json null (multi_select/repeat rows بدل text). - + source string(12) default manual (manual | prefill | portal | import | derived). - LogsActivity (Spatie — موجود في الـ stack) على الموديل: answer_value/value_num/value_json فقط. - model alias ClinicalFieldValue extends PatientHistoryAnswer عشان كود GYN يتكتب بالاسم المقرر بلا جدول جديد. - صفوف category=vitals اللي اتعملت لها mirror تتهاجر لـ clinical_observations ثم تتمسح (المحرك يوقف الـ mirror).

3.3 مخزن القياسات — clinical_observations = مخزن الـ vitals الواحد

clinical_observations: id, company_id, patient_id, encounter_id? , history_question_id,
  value_num, value_text?, observed_at, set_id (ulid — جلسة قياس واحدة),
  source (manual|device|import|portal|carried), recorded_by, softDeletes
idx (patient_id, history_question_id, observed_at) · (encounter_id) · (set_id)
  • التعريفات: core 9 (موجودة category=vitals) + إضافات التخصص بـ clinical_type: تغذية waist, hip, fat_pct, muscle_kg, visceral_fat, bmr…؛ نسا fundal_height, fetal_hr؛ إقامة rr, on_oxygen, consciousness, pain, intake_ml, output_ml, news2 (is_computed, computed_key=news2).
  • الـ set = صف لكل قيمة + set_id يجمع الجلسة (جولة تمريض/InBody/قياسات الزيارة). الـ NEWS2 يتحسب على الـ set.
  • القراءة: ObservationService::latestFor(encounter|patient, codes) + series(patient, code) (trend). is_danger من التعريف في الـ Resource (قرار م6 §4 كما هو).
  • ده انحراف معلن عن clinic-dynamic-fields §3.3 («توحيد التخزين في جدول القيم») — الأسماء المجمّدة في §3.1/3.2 ما اتمستش؛ الاستراتيجية بس اتغيرت لأن المفتاح الفريد ما يحملش time-series.

مصير الجداول الخمسة:

الجدول القرار التبرير
clinical_examinations shim لريليس واحد ثم drop 13 مستهلك غير اختباري (QueueController has_vitals, EncounterResource, ClinicDashboardService, Nutrition ×2) — VitalsService يكتب observations + الصف القديم خلف flag، القرّاء يتحولوا على latestFor(encounter)
patient_history_answers (صفوف vitals) تتهاجر وتتمسح mirror بلا داعي بعد وجود observations
patient_vital_entries تتهاجر ثم drop هو بالظبط observation بـ encounter_id=NULL وobserved_at=recorded_on؛ صفحة /clinic/vitals تقرا الـ series
nutrition_body_compositions يفضل (موديول moonui) + يكتب observations 13 مقياس InBody = نتيجة جهاز بتتعرض كـ card؛ لكن weight/height/bmi/waist/hip تتكتب كـ observations بنفس set_id + encounter_id لو داخل زيارة. PatientNutritionMetrics يقرا مصدر واحد بدل 3
hospital_vital_rounds يفضل ريليس واحد ثم يتهاجر هو observation set بـ encounter_id = encounter الإقامة؛ شاشة التمريض تعرض الـ sets كصفوف. NEWS2 = computed. لوحة التمريض على moonui3 فالتنسيق داخلي

3.4 كتالوج الخيارات المُدار + المفضّلة + الإضافة اللحظية (مستفاد من نظام عمرو، مع تفادي عيوبه)

نظام عمرو القديم (amrtechogate/obgy) بيعرض الخيارات بـ «pick-don't-type» قوي؛ ناخد المميزات ونتفادى العيبين (جدول lookup لكل حقل + تخزين CSV). المعتمد:

  • كتالوج واحد مُدار بـ lookup_key (clinic_history_options/clinical_lookups): id, lookup_key, value_ar/en, parent_id (للفئات والشجرة)، display_order, specialty?, is_active. حقل التعريف بيشاور عليه بـ lookup_key بدل ما يملك جدوله. ممنوع جدول lookup مستقل لكل حقل (هُم عندهم عشرات: examinationhead/chest/abdomen/pelvis, diagnosis, husbndiagnosis1/2/3, operation…).
  • إضافة لحظية (inline-add): أي picker فيه صف «+ إضافة جديد» يعمل INSERT في الكتالوج (بصلاحية clinic.lookups.add) ويختار القيمة فورًا — زي زر Add + updateElementSelect عندهم.
  • مفضّلة لكل دكتور: clinical_lookup_favorites(user_id, lookup_key, value_id) — القيم المميّزة بـ ★ تطفو فوق في الـ picker (عندهم flag favorite بس على مستوى install؛ إحنا per-user). يغطّي سرعة المتكرر في التاريخ/التشخيص/الفحوصات.
  • شبكة فئات (full-grid): الفحوصات/الباقات = parent_id (فئة) + أبناء، بـ display_order — picker بفئات مطوية (يطابق investcats→invests).
  • تبديل نوع الإدخال للحقل: العميل يقرر الحقل select من الكتالوج ولا نص حر (FieldRule.input, مرآة Examination Controller عندهم) — من غير ما يتغير التخزين.
  • الاختيار المتعدد = صفوف ربط مُطبّعة (مثلاً encounter_diagnoses, أو value_json array مع storage) — ممنوع CSV في عمود واحد (diagnosisid="3,7,12") اللي بيكسر الـjoins والتقارير عندهم.

مرجع كامل: legacy-obgy-options-analysis.md.


4. جدول تسكين كل حقل

(الطبقة: 1–4 · الإجراء: keep / move / merge / delete)

الحقل / المجموعة المصدر الحالي طبقة المخزن المستهدف إجراء ملاحظة
ديموغرافيا + هوية + تأمين lab_patients أعمدة 1 lab_patients keep أعمدة core بـ uniqueness — مش EAV (clinic-profiles-fields)
blood_group lab_patients 1 lab_patients keep يرجع للفورم كحقل core مطفي افتراضياً
الحساسية ×4 medical_history json · سؤال allergies نص · dent_allergy_* ×3 · nutrition_patient_food_prefs.allergen 1 patient_alerts (kind=allergy, code, label, severity, reaction, ref_type/ref_id) merge 3 مصادر Clinic تتهاجر وتتعطّل؛ الحساسية الغذائية: صف alert بـ ref=nutrition_food (تنسيق moonui). الهيدر يقرا alerts بس
الأمراض المزمنة ×5 diabetes/hypertension bool · dent_ chronic ×10 · past_medical_history · medical_history json · admissions.diagnosis 1 past_medical_history (+ status, is_chronic) + كتالوج clinic_history_options (+ is_alert, alert_severity, alert_types json) merge الأسئلة الـ boolean تبقى تعريفات storage=condition = chips على نفس الجدول؛ dent_anticoagulant = chip كود anticoagulant بـ is_alert لكل الأنواع → يطلع alert في كل عيادة (سبب وجود باقة الأسنان أصلاً)
العمليات ×3 prior_surgery bool · past_surgical_history · nut_gastric_balloon_or_surgery 1 past_surgical_history merge prior_surgery يتحسب (صفوف موجودة)؛ nut_… = chip procedure=bariatric بعلم التغذية
العائلي ×2 family_history_flag · family_history 1 family_history merge العلم يتحسب
الأدوية ×5 on_medication · nut_supplements · nut_external_medications · medical_history meds · آخر Rx / MAR 1 (حالي) + 3 (الزيارة) prescriptions (kind=home للأدوية من برّه — Rx v2 في design.md 4.1) merge «الأدوية الحالية» = بنود active عبر issued/home/discharge؛ on_medication يتحسب؛ nut_* نص → بنود home بـ drug_name
التدخين smoking select (core) · nut_smoker bool 1 إجابة core smoking merge nut_smoker يتحذف، يتهاجر لـ smoking=current
الحالة الاجتماعية obgy marital_status · nut_marital_status 1 إجابة core profile marital_status (clinical_type=NULL) move تطلع من باقة obgy لباقة core بـ visibility مطفية افتراضياً؛ nut_ يتحذف
الوظيفة / النادي / عرفتنا منين / محوّل من nut_job, nut_club, nut_how_heard, nut_referred_from 1 (job, how_heard, referred_from) / 2 (club) core profile / باقة تغذية move / keep how_heard وreferred_from تسويق مشترك مش تغذية
الزوج/ة (اسم/مهنة/قومي/مدة زواج/أبناء) obgy pack 2 إجابات clinical_type=gyn_ob category=profile keep تتعلّم clinical_type بدل NULL
الحمل / الرضاعة nut_pregnant, nut_breastfeeding (patient) · dent_pregnant (patient) 3 تعريف core pregnant, breastfeeding scope=encounter, show_if gender=female, carry_forward=prefill, stale_after_days=30 merge الحمل episode مش حقيقة ثابتة. لما GYN تيجي، pregnancies النشطة تملاه source=derived read-only. النسختين يتحذفوا
الدورة الشهرية nut_cycle_regular 1 سؤال core واحد menstrual_pattern scope=patient show_if patient.gender=female merge بتهم التغذية والنسا والباطنة؛ النسا تمدّه بتفاصيل L2 (LMP/G-P-A) مش بنسخة
سبب الزيارة / الهدف nut_visit_reason (patient profile) · nutrition_patient_profiles.goal 2 nutrition_patient_profiles.goal (يتوسّع لـ 5 قيم) merge visit_reason حقيقة برنامج مش مريض؛ تنسيق moonui
nut_weight_stabilized nut profile 2 nutrition_patient_profiles.stopped_* (موجود) merge موجود أصلاً هناك
نمط الحياة 9 (وجبات/مياه/نوم/نشاط/أكل عاطفي…) nut_ category=history scope=patient 2 إجابات clinical_type=nutrition scope=patient in_intake=true keep صح إنها patient-level كـ baseline في الـ intake التخصصي؛ اللي بيتغير بالزيارة (الالتزام) موجود في visit_adherence L4
Vitals الأساسية 9 ×5 مخازن 3 clinical_observations merge §3.3
الطول يتعاد كل زيارة ×3 3 observation بـ carry_forward=prefill, stale_after_days=365 (بالغ) / 0 (<18 سنة بـ show_if age) keep يظهر رمادي من آخر قياس؛ تأكيد بنقرة
محيط الخصر/الورك + InBody nutrition_body_compositions 4 تعريفات clinical_type=nutrition category=vitals → observations (+ الجدول للـ 13 مقياس) keep + mirror يحمل encounter_id لما يتقاس في زيارة (تنسيق moonui)
جولات التمريض + NEWS2 hospital_vital_rounds 4 observations sets (clinical_type=NULL لكن kind=inpatient) move (لاحقاً) §3.3
الشكوى encounters.chief_complaint نص · encounter_complaints picks 3 الاتنين بدور محدد: picks = المهيكل، chief_complaint = جملة المريض الحرفية keep التغذية لازم تستخدمهم (moonui)
التشخيص ×5 encounter_diagnoses · admissions.diagnosis · dental_ortho_cases.diagnosis · surgery pre/post · preauth dx 3 encounter_diagnoses + stage (primary|admitting|pre_op|post_op|discharge) merge admissions.diagnosis يبقى «سبب الدخول» نص (design.md 4.7)؛ ortho = تصنيف حالة (Angle class) حقل L2 مش تشخيص؛ preauth ينسخ من الجدول
الفحص الإكلينيكي العام مفيش عمود 3 تعريفات core category=exam (general exam chips + نص) new يملا فجوة «NO exam/plan column»
فحص الأسنان 12 dent_ scope=encounter 4 إجابات clinical_type=dental category=exam keep تتعلّم clinical_type
الشارت/perio/ortho/lab cases جداول Dental 2/4 تفضل keep «بيتعرض كـ cards» = جدول خاص مسموح
خطة غذائية / adherence / جلسات جداول Nutrition 4 تفضل keep نفس القاعدة
ملاحظات المريض ×7 important_note · treatment_plan · general_health_note · nutrition_patient_profiles.notes · nutrition_case_notes · dental_tooth_notes · admissions.notes/nursing_notes 1 / 3 important_note → patient_alerts kind=note (هيدر)؛ treatment_plan/general_health_note → clinical_notes kind=sticky (GYN v2/design.md 4.7)؛ case/nursing → clinical_notes kind=case|nursing؛ tooth notes تفضل (مرتبطة بسنة)؛ admissions.notes إداري يفضل merge clinical_notes يتقدّم من «بعد P6» لـ D2
medical_history json lab_patients — يتفكك: allergies→alerts، chronic→conditions، meds→home Rx؛ ثم read-only ويتشال من الفورم delete (تدريجي) PatientReadService::pluckList يفضل قارئ fallback ريليس واحد
بيانات الإقامة (companion, payer, nights, discharge…) hospital_admissions سياق تفضل keep إدارية، مش إكلينيكية

الإصلاحات الستة: (1) nut_visit_reason → goal ✔؛ أما نمط الحياة فقرار مش إصلاح: بيفضل patient-level عن قصد كـ baseline في الـ intake التخصصي (التغيير لكل زيارة مكانه visit_adherence L4) — قرار #13 في §9. (2) الطول: carry_forward=prefill ✔. (3) Body comps بلا encounter: encounter_id + observations ✔ (moonui). (4) الحقول الإضافية عند الإنشاء: POST clinic/patients يقبل profile_answers[] → savePatientAnswers في نفس الـ transaction. (5) تسريب nut_: PatientProfileFieldController يفلتر clinical_type IS NULL افتراضياً، و?clinical_type= يضيف باقة تخصص واحدة (شاشة الـ intake التخصصي). (6) المحطات المنفصلة: clinic.visit_stations=split يتفرض في الـ BE بـ fill_role — الطبيب يشوف محطة القياسات read-only ما لم يمتلك clinic.vitals.record.


5. أول زيارة — Intake

التتبع: جدول صغير patient_intakes (patient_id, clinical_type? (NULL=مشترك), status pending|partial|complete|skipped, completed_at/by, confirmed_at, skip_reason). الاكتمال مشتق من التعريفات: كل in_intake=true AND is_required في الطبقة ليها قيمة. الجدول بيخزن الحالة + التأكيد + التخطي بس.

الفلو: 1. الخطوة المشتركة (L1) — بتفتح تلقائياً من: فورم التسجيل (الاستقبال، fill_role=reception فقط: ديموغرافيا + فصيلة + حالة اجتماعية + وظيفة + how_heard) ثم من محطة الشيت (fill_role=nurse|assistant: alerts/حساسية، مزمن chips، عمليات، عائلي، أدوية من برّه، تدخين). الحد الأدنى الإلزامي: الحساسية (أو «لا يوجد» صريح — alert kind=nka) + المزمن (أو «لا يوجد») + الأدوية الحالية. أي حاجة تانية اختيارية. 2. الخطوة التخصصية (L2) — بتتفعّل عند أول encounter في department.clinical_type=X للمريض ده ولو patient_intakes(X) مش complete: تعرض حقول clinical_type=X, scope=patient, in_intake=true (+ أي مشترك ناقص). التغذية: نمط الحياة + تفضيلات + هدف. النسا: دورة/G-P-A/زوج. الأسنان: alerts الأسنان (chips بعلم) + baseline الشارت. 3. الحفظ الجزئي — كل حقل autosave (نمط history-panel الموجود)؛ الحالة partial لحد ما الإلزامي يكمل. 4. شارة الطابور — chip تالت جنب has_vitals/has_sheet: intake: ok | missing_shared | missing_specialty (من ClinicDashboardService). الطبيب يشوفها قبل ما يفتح. 5. إعادة الـ intake — المشترك: لو confirmed_at أقدم من clinic.intake.reconfirm_days (default 365) → بانر «أكّد البيانات» بنقرة واحدة (بيحدّث confirmed_at) أو عدّل. التخصصي: مرة واحدة ما لم التخصص يعلن reintake_days. 6. مين قبل الزيارة — الاستقبال بيعمل التسجيل + L1 الإداري وقت الحجز؛ التمريض/المساعد بيعمل L1 الطبي في محطة الشيت؛ الطبيب بيراجع ويعدّل مش بيملى من الصفر. لو العيادة visit_stations=merged الطبيب بيشوف الخطوة كلها كـ station أولى بتظهر مرة واحدة. 7. بوابة المريض (لاحقاً) — نفس التعريفات بـ fill_role=patient تتعرض في الـ portal (lab_patients.portal_* موجود) وتتكتب بـ source=portal بحالة «في انتظار مراجعة» → تظهر للتمريض كمسودة. 8. Triage (اختياري) — محطة قبل القياسات لو encounters.kind=emergency (إضافة لقائمة design.md §3-2) أو إعداد clinic.stations.triage=true: تعريفات core triage_level (select بـ danger_values=[red,orange])، triage_note، + الـ vitals الأساسية كـ observation set source=triage. الطابور يترتب بالـ level.


6. عقد التخصص — الجانب البياني

Modules/Clinic/app/Clinical/ClinicalTypeRegistry (PHP، بالكود) + نفس الـ entry في clinical-types.ts. التخصص بيعلن:

البند الشكل مثال تغذية
key + enum case ClinicalType::Nutrition موجود
packs seeder class بيعمل updateOrCreate(company_id, code) لتعريفات بـ clinical_type=key فقط nutritionQuestions() تنتقل من ClinicProfilePacks لـ NutritionFieldPack داخل Clinic (الكود هناك أصلاً)
vitals_extras أكواد تعريفات category=vitals clinical_type=key waist, hip, fat_pct…
intake {required: [...codes], optional: [...], reintake_days?} lifestyle + prefs
workspace {component, endpoints: [record sections]} — بيمد PatientRecordService::extend(key, fn) (design.md 4.7) nutrition.metrics, nutrition.plan
alert_conditions أكواد في clinic_history_options تتعلّم is_alert + alert_types أسنان: anticoagulant, bisphosphonate, bleeding
stations ترتيب المحطات + أي station يتخفى (الجزء الـ UI — في design الـ shell) —

القواعد: (1) ممنوع تعريف حقل موجود في core بكود تاني — الـ seeder يرفض code مكرر بدون prefix. (2) أي حقل تخصص = prefix {key}_ و clinical_type=key (العمود هو الفلتر، الـ prefix للتوثيق). (3) حقيقة بتهم كل العيادات (حساسية/مرض/حمل) ممنوع تتعرّف في باقة؛ التخصص بيعلّم chips من الكتالوج المشترك بس. (4) العزل في BE بـ clinical_type على encounter ↔ تعريف، مش في FE. (5) ممنوع جدول vitals/alerts/notes خاص — الجدول الخاص مسموح بس لما بيتعرض كـ card أو بيتبحث فيه (odontogram, InBody, pregnancies).


7. الهجرة بدون كسر

كل خطوة additive وقابلة للرجوع؛ البيانات الحية على moonui3 صغيرة. على MySQL (SQLite يبلع أعمدة ناقصة — درس مسجّل).

  1. أعمدة التعريفات (§3.1) nullable + backfill clinical_type من الـ prefix (nut_→nutrition, dent_→dental, obgy spouse→gyn_ob) + storage للأسئلة المهيكلة. شرط: ClinicalType النهارده general/nutrition/dental بس، وعيادة النسا في co4 شغالة كقسم general → نضيف case gyn_ob في D0 (enum + registry entry بتاب consultation العادي، بلا workspace) ويتعلّم قسم النسا بيه قبل الـ backfill؛ وإلا حقول الزوج تختفي من شاشة الملف بعد D0. بديل مرفوض: إبقاء باقة obgy clinical_type=NULL (تظهر لكل العيادات). الكنترولرين يفلتروا بالعمود؛ isNutritionQuestion/isDentalQuestion يفضلوا كـ fallback ريليس واحد.
  2. القيم: repeat_index + unique الجديد + value_json + source + LogsActivity.
  3. clinical_observations: create → backfill من clinical_examinations (set لكل صف) + patient_vital_entries (encounter NULL) + صفوف answers category=vitals → VitalsService يكتب الاتنين خلف clinic.vitals.dual_write → القرّاء الـ 13 يتحولوا → حذف mirror + drop الجدولين الريليس اللي بعده.
  4. patient_alerts (design.md 4.5 — يتقدّم): create → backfill من medical_history.allergies + سؤال allergies (split بالفاصلة) + dent_allergy_*=true + important_note (kind=note) → PatientReadService::allergiesList يقرا alerts فقط → الأسئلة الثلاثة is_active=false. SnapshotEncounterHistory يتوسّع يختم alerts النشطة في history_snapshot (النهارده بيختم إجابات patient-scope بس).
  5. Conditions: past_medical_history + status/is_chronic + كتالوج is_alert/alert_types → backfill diabetes/hypertension/dent_*=true → صفوف بكود؛ الأسئلة تتحول storage=condition (تفضل ظاهرة كـ chips). نفس الشيء prior_surgery/family_history_flag (يتحسبوا). الـ snapshot يختم conditions/surgical/family كمان.
  6. Home meds: يعتمد على P1 (Rx v2 drug_name snapshot) → prescriptions.kind=home + backfill nut_supplements/nut_external_medications/medical_history.meds. الـ snapshot يختم بنود home النشطة.
  7. الحمل/التدخين/الاجتماعية: تعريفات core الجديدة + backfill من nut_/dent_ ثم حذف النسخ.
  8. encounter_diagnoses.stage + backfill primary؛ المستشفى يكتب pre/post هنا.
  9. clinical_notes + backfill treatment_plan/general_health_note (sticky) ثم نقل hospital_nursing_notes (kind=nursing).
  10. patient_intakes + backfill: مريض عنده إجابات L1 إلزامية كاملة = complete بتاريخ آخر إجابة.
  11. medical_history json: بعد 4+5+6 يتشال من الفورم ويفضل read-only.

مخاطر: الـ dual-write للـ vitals (شاشتين يكتبوا في وقت واحد) → الـ flag يتقفل بعد ما المالك يتست؛ unique الجديد على answers مع repeat_index (backfill 0 الأول)؛ QueueController has_vitals لازم يتحول في نفس الريليس وإلا الطابور يفقد الشارة.

تنسيق moonui (Nutrition): (أ) nutrition_body_compositions.encounter_id + كتابة observations عبر ObservationService::recordSet()؛ (ب) PatientNutritionMetrics::weightSeries يقرا observations بس؛ (ج) goal 5 قيم + استقبال nut_visit_reason؛ (د) food_prefs kind=allergy → patient_alerts بـ ref=nutrition_food؛ (هـ) تبنّي picks/diagnosis (design.md). Clinic-side بلا تنسيق: نقل nutritionQuestions() لباقة بـ clinical_type، العزل، حذف nut_smoker/marital/pregnant/visit_reason بعد الهجرة (الكود في Clinic).


8. المراحل — دمج مع P0–P6

# المرحلة التسليم حجم المالك يختبر على /app
P0 أساس Clinical Core (design.md) S–M (design.md)
D0 المحرك + العزل أعمدة §3.1 + §3.2 · case gyn_ob + تعليم قسم النسا · backfill clinical_type · الفلترة بالعمود · profile_answers عند الإنشاء · ClinicalTypeRegistry PHP · show_if مفسّر (patient.* + encounter.kind) M يفتح تسجيل مريض في عيادة عامة: مفيش حقول تغذية؛ يملا حقل إضافي وقت الإنشاء؛ حقل show_if gender=female يختفي لذكر
P1 روشتة v2 (design.md) M (design.md)
D1 مخزن القياسات الواحد clinical_observations + backfill + dual-write · طول prefill رمادي · trend من الـ series · صفحة /clinic/vitals على الـ series · vitals_extras للتغذية (waist/hip) M–L يسجل قياسات في زيارة، يفتح زيارة تانية: الطول جاهز رمادي والوزن فاضي بجنبه «السابق 82»؛ trend الضغط 5 زيارات؛ شارة has_vitals شغالة
D2 الحقائق المهيكلة + الهيدر patient_alerts (يتقدّم من P5) · conditions + chips + is_alert · home meds (kind=home) · حمل/تدخين/اجتماعية core · clinical_notes · LogsActivity · توسيع SnapshotEncounterHistory ليختم alerts + conditions + home-Rx · هيدر واحد يقرا alerts+conditions+meds L (3 WPs) يعلّم «بياخد سيولة» في عيادة الأسنان → يظهر أحمر في هيدر عيادة النسا؛ يكتب دوا من برّه → يظهر في «الأدوية الحالية»؛ يغيّر حساسية بعد توقيع زيارة → الزيارة القديمة بتعرض اللي شافته
P2 أدوية الإقامة (design.md) M–L (design.md)
D3 الـ Intake patient_intakes · خطوة مشتركة + تخصصية · شارة الطابور · إعادة التأكيد · fill_role يفرض split M مريض جديد في التغذية: الاستقبال يملا الإداري، التمريض الطبي، الدكتور يفتح يلاقي كله مملي + نمط الحياة؛ نفس المريض يروح النسا: يطلعله بس الخطوة النسائية؛ الطابور يعرض «intake ناقص»
P3 منفّذ واحد + أشعة (design.md) L (design.md)
P4 النتائج والسجل + PatientRecordService::extend يستخدمه الـ registry M (design.md)
P5 المستندات (+ التنبيهات اتعملت في D2) (design.md ناقص alerts) S–M (design.md)
D4 طي التخصصات hospital_vital_rounds → observations + NEWS2 computed · body comps ↔ observations (moonui) · encounter_diagnoses.stage للمستشفى · triage station · medical_history read-only M جولة تمريض تظهر في trend المريض بعد الخروج؛ ER: مريض triage أحمر يطلع أول الطابور
P6 صرف الصيدلية (design.md) M (design.md)

9. قرارات مطلوبة من المالك

  1. مخزنين (حقائق + قياسات) ولا مخزن واحد؟ التوصية: اتنين — المفتاح الفريد ما يحملش جولات/سلاسل، والدليل 3 جداول موازية اتعملت بسببه.
  2. المزمن: جدول مهيكل + chips (التوصية) ولا أسئلة boolean؟ المهيكل يدّي since_when/status وعلامة alert لكل العيادات؛ الـ chips بتحافظ على «يختار مش يكتب».
  3. الحساسية الغذائية تتوحّد في patient_alerts (التوصية، تنسيق moonui) ولا تفضل في التغذية بس؟
  4. الحمل حقل زيارة بـ prefill 30 يوم (التوصية) لحد ما pregnancies تتبنى — موافقة على حذف نسختي التغذية والأسنان.
  5. الأدوية الخارجية = prescriptions.kind=home (التوصية، يعتمد على P1) ولا جدول patient_medications منفصل؟
  6. patient_alerts + clinical_notes يتقدّموا لـ D2 (قبل P2/P3) — موافقة على إعادة الترتيب.
  7. marital_status/job/how_heard/referred_from تبقى core profile مطفية افتراضياً (التوصية) ولا تفضل في الباقات؟
  8. الحد الأدنى الإلزامي للـ intake المشترك = حساسية + مزمن + أدوية (بخيار «لا يوجد» صريح) — تأكيد أو تقليل.
  9. encounters.kind=emergency + محطة triage (التوصية: نضيفها في D4 كإعداد مطفي) — موافقة على الإضافة لقائمة design.md.
  10. hospital_vital_rounds تتهاجر (D4) ولا تفضل للأبد كجدول تمريض خاص؟ التوصية: تتهاجر — لوحة التمريض عندنا على moonui3.
  11. طول الأطفال (<18): إعادة قياس كل زيارة (التوصية) ولا نفس الـ 365؟
  12. مين يبدأ تنسيق moonui (البنود أ–هـ في §7) وإمتى — قبل D1 ولا بعده؟ التوصية: الاتفاق قبل D1، التنفيذ عندهم بعد D1.
  13. نمط حياة التغذية (9 حقول) يفضل patient-level كـ baseline في الـ intake التخصصي (التوصية) ولا يتحول لحقول زيارة؟ الدليل: الـ r4 اعتبرها «خطأ patient-level»، لكن التغيير بالزيارة عنده مكان فعلاً (visit_adherence)، والحقائق دي بتتسأل مرة وبتتراجع — مش بتتقاس.

Clinical Core — توحيد البلوكات الطبية المشتركة (روشتة / تحاليل / أشعة / …)

تحليل فقط — 2026-10-21. المرجع: التقارير r1/r2/r3 + فحص مباشر للكود (file:line تحت كل ادّعاء). BE = /home/moonui3/moon-erp-be/Modules، FE = /home/moonui3/public_html/moon-erp/src/app/features.


1. الخلاصة

الـ Clinical Core = مجموعة بلوكات طبية واحدة بتشتغل في كل عيادة (عام / تغذية / أسنان / نسا / إقامة مستشفى) من غير ما أي تخصص يبني نسخته. كل تخصص بيستضيف البلوك ويضيف عليه حقول/قوالب/مفضّلات — لكن ما يعملش جداول أوامر خاصة بيه.

البلوكات اللي بنوحّدها دلوقتي (المرحلة الأولى): (1) الروشتة والأدوية (بما فيها أدوية الإقامة MAR وروشتة الخروج)، (2) طلبات التحاليل، (3) طلبات الأشعة (بتقريرها وصورها)، (4) النتائج والمستندات الإكلينيكية (نتيجة/تقرير/إجازة مرضية/تقرير طبي/شهادة)، (5) المرفقات والتنبيهات، (6) محرك الطباعة. الباقي (التشخيص، العلامات الحيوية الديناميكية، الملاحظات، المتابعة) موجود أو مخطط في الـ KB وبينضم بترتيب لاحق.

أكبر قرار: موديول Clinic هو الـ Clinical Core — مفيش موديول جديد، والـ Encounter هو سياق كل أمر طبي (زيارة عيادة / إقامة / يوم عملية / متابعة تليفون) بدل ما نعمل ربط polymorphic على كل جدول. الإقامة أصلاً بتفتح encounter (hospital_admissions.encounter_id)، وكل جداول الأوامر مفتاحها encounter_id، والـ LIS عنده RequestSource::InPatient. يبقى اللي ناقص نوع للـ encounter مش أنكر جديد.

الوضع الحالي باختصار: 3 نماذج أدوية ما بيكلموش بعض (روشتة العيادة، MAR المستشفى بنص حر، صورة روشتة المتجر)، الروشتة السريعة بتخزّن «—» في الحقول المهيكلة، إعداد مصدر الأدوية ما بيتقراش، الأشعة بتقف عند ordered للأبد، والاستقبال بيعمل طلبات تحاليل/أشعة بيتخطى وضع standalone.


2. الوضع الحالي

البلوك عام (Clinic) تغذية أسنان مستشفى نسا (مخطط) LIS WebStore العيب المؤكد (file:line)
روشتة ✅ أصل ♻️ reused (nutrition-consult-board.html:650) ♻️ reused (consultation.html:440) ❌ مكرر hospital_med_orders بدواء نص حر — (هيعيد استخدام) — ❌ مكرر (صورة فقط) ✔ مؤكد: preset بيكتب '—' في dose/frequency/duration (prescription.component.ts:87,595-597) · IssuePrescription.php:51-55 بيفرض الثلاثة required + drug_id في products · hospital_med_orders.drug string (2026_10_12_100005:28) · NursingService::ROUTES (:30) ≠ MedicationRoute (10 vs 10 مختلفين: المستشفى فيه sublingual/ng/other وناقصه ophthalmic/otic/nasal) · FE التمريض بيبعت drug نص بلا product (nursing-panel.component.ts:43) · clinic.pharmacy_source معرّف ومش مقروء في أي مكان (seeder + clinic-settings.registry.ts:247 فقط) · product_drug_details.dosage_form_id موجود (Core 2026_08_02_100300:31) ومش مستخدم في الروشتة
قفل الزيارة على الكتابة ⚠️ FE فقط ⚠️ ⚠️ — — — — ✔ مؤكد: Encounter::isLocked() (Encounter.php:233) بيتستخدم في EncounterController:175 وEncounterService:314 فقط — مش في IssuePrescription / StoreClinicalIntent / CreateRadOrder / OrderLabFromEncounter / SubmitExternalResult
طلب تحاليل ✅ intent + decide ♻️ reused (:672) ♻️ عبر dialog ❌ ناقص (مفيش شاشة طلب على الإقامة) — ✅ أصل النتائج — ✔ تصحيح للـ KB: clinic_service موجود في whitelist النية (StoreClinicalIntentRequest.php:33,55) ومستهلك (DecideClinicalIntent.php:95-121) والـ picker بيقلب على lab_mode (lab-orders.component.ts:109) — F2/F3 اتعملوا. الفجوة الحقيقية: CreateVisitRequest.php:89,94 بيقبل lab_investigations/rad_procedures ids فقط → الاستقبال في standalone ما يقدرش يطلب من الكتالوج · 5 مسارات لإنشاء سطر تحاليل (r2 §6)
طلب أشعة ✅ RIS-lite ♻️ (:683) ❌ صور أسنان مش rad order (dental_tooth_images) ❌ ناقص — — — ✔ مؤكد: RadOrderStatus فيه Scheduled/Performed/Reported (RadOrderStatus.php:7-11) لكن الوحيد اللي بيتكتب Ordered (CreateRadOrder.php:89) · MarkEncounterRadComplete.php:27 بيرجع فاضي لو encounter_id null — وهي nullable (170002:27) فطلبات الاستقبال عمرها ما تكتمل · مفيش cancel/refund/templates/صور (study_uid ما بيتكتبش)
نتائج ↔ الشيت ✅ clinical_documents ♻️ بيقرا lab_results بالكود ♻️ ⚠️ عبر encounter الإقامة بس — ✅ — ✔ clinical_documents.encounter_id NOT NULL + unique (company, encounter, ref_key) (clinical_documents migration:21,37) → نتيجة بلا زيارة ما تتسجلش · DropLabReportOnEncounter بيتخطى no-encounter
تشخيص/شكوى ✅ encounter_diagnoses ❌ ناقص (chief_complaint بس) ♻️ ❌ مكرر admissions.diagnosis string (100002:52) — — — r3 §2
تنبيهات/حساسية ⚠️ مشتق من history ⚠️ جزئي ♻️ dent_ pack ❌ ناقص يقترح patient_alerts — — PatientReadService.php:249-272
مرفقات/ميديا ✅ clinic_patient_attachments ♻️ ♻️ ❌ ناقص يقترح morph+kind — — الجدول patient-level فقط (patient_id, disk, path, mime…) بلا attachable
مستندات (إجازة/تقرير/شهادة) ❌ ❌ ❌ ❌ (discharge_summary نص) — — — غير موجود في أي مكان
طباعة FE clinic-print-shell ♻️ + BE print-context مكرر ❌ window.print يدوي ❌ — ✅ BE DomPDF — r3 §9 — 3 طرق، مفيش PDF إكلينيكي من الـ BE
Record API ❌ ✅ VisitRecordService ❌ ❌ هيقلّد التغذية — — r3 §10

3. المبادئ الملزمة للتوحيد

  1. كيان واحد لكل مفهوم. روشتة = prescriptions/prescription_items بس. طلب تحاليل/أشعة من الطبيب = clinic_clinical_intents بس. تقرير أشعة = rad_reports بس. أي تخصص (أسنان/تغذية/نسا/مستشفى) ممنوع يعمل جدول أوامر أو أدوية خاص بيه.
  2. السياق = Encounter، والـ Encounter ليه نوع. encounters.kind (outpatient | inpatient | day_case | remote) + encounters.admission_id nullable. الإقامة = encounter واحد طول مدتها (موجود فعلاً). الحلقة (episode) والإجراء (clinical_procedure) بيربطوا encounters، مش بيستبدلوها. الأرضية الدنيا = patient_id (موجود على كل الجداول) للحالات اللي مفيهاش encounter (LIS walk-in).
  3. المفردات من مكان واحد. طرق الإعطاء = Clinic\Enums\MedicationRoute (اتحاد القائمتين = 13 قيمة). التكرار = Clinic\Enums\MedicationFrequency (كود → أوقات/يوم، منقول من NursingService::FREQ). الشكل الصيدلي = Core dosage_forms. ممنوع قوائم ثابتة في أي كومبوننت أو سيرفس تاني.
  4. الـ BE هو اللي بيفرض القفل والتوقيع. كل كتابة إكلينيكية على encounter موقّع = EncounterLockedException من الـ action نفسه. الـ FE [locked] تجميل بس.
  5. الوضع = إعداد، مش كود. clinic.ordering_mode / lab_mode / rad_mode / pharmacy_source / pos.pharmacy.* / clinic.print.* موجودين — بنقراهم في نقطة واحدة لكل واحد (OrderingMode, ClinicCatalogMode, وPharmacySource الجديد).
  6. منفّذ واحد للطلب. كل اللي بيحوّل «بند كتالوج» لـ (سطر فوترة + LabRequest/RadOrder/self) بيعدّي على action واحد ExecuteCatalogItem (يتستخرج من فرع DecideClinicalIntent::here). النية (clinic_clinical_intents) = سجل الطبيب وبتتطلب encounter؛ طلب الاستقبال المباشر (CreateVisit) بينادي نفس المنفّذ مربوط بـ service_order_id + patient_id بلا encounter وهمي (عشان ما يطلقش EncounterStarted → in_consultation). وضع immediate = النية بتتقرر «هنا» فوراً بنفس المنفّذ.
  7. الصرف مش على شاشة الطبيب أبداً. الروشتة بتصدر event وتحمل dispense_status؛ الصرف/البيع في POS/Sales. الطبيب بيشوف «اتصرفت» كشارة بس.
  8. النتيجة بترجع للمريض، والزيارة اختيارية. clinical_documents بتتربط بالـ patient دايماً وبالـ encounter لو موجود. العرض موحّد بشارة المصدر (LIS / RIS / خارجي).
  9. محرك طباعة واحد في الـ BE (DomPDF — نفس اللي LIS مثبته بالعربي) بقوالب لكل نوع مستند، وإعدادات clinic.print.* الموجودة. الـ FE preview يفضل لحد ما الـ PDF يثبت، بعدها يتشال.
  10. ALTER قبل CREATE. جدول جديد بس لو الـ KB (GYN §7.2) اقترحه قبل كده أو مفيش مكان منطقي له.

4. التصميم لكل Block

4.1 الروشتة والأدوية (Prescription / Medication)

المالك: Modules/Clinic (موجود). الكتالوج: Core products (+product_drug_details) أو clinic_drugs حسب الإعداد.

التفصيل
جداول — keep prescriptions, prescription_items, clinic_drugs, clinic_drug_presets, clinic_drug_alerts, clinic_favorites, Core dosage_forms/product_drug_details
ALTER prescriptions + kind string(16) default outpatient (outpatient | inpatient | discharge) · + subject string(12) default patient (patient | spouse | other) + subject_name nullable (حالة «الزوج» في النسا، gyna-reference:114) · + dispense_status string(16) default pending (pending | partial | dispensed | not_applicable) · + admission_id nullable (denormalized للسرعة — المصدر encounter.admission_id) · encounter_id يفضل NOT NULL
ALTER prescription_items dose/frequency/duration → nullable · + sentence text nullable (الجملة الجاهزة — بديل «—») · + frequency_code string(12) nullable (من MedicationFrequency) · + times json nullable · + prn bool default 0 · + starts_at/ends_at/stopped_at timestamps nullable + stopped_by · + item_status string(10) default active (active | stopped | completed) · + dosage_form_id nullable → dosage_forms + form string(100) snapshot · drug_id → nullable + + clinic_drug_id nullable → clinic_drugs + drug_name string(191) snapshot · + dispensed_qty decimal nullable · route يتوسع لـ 13 قيمة
ALTER clinic_drug_alerts drug_id → nullable (الـ FK على products — 2026_10_09_110000:34) + clinic_drug_id nullable → clinic_drugs (xor) + unique يبقى (company_id, drug_id, clinic_drug_id)؛ ClinicDrugAlert::notesFor() ياخد المفتاحين — وإلا التنبيهات بتختفي في وضع standalone_formulary (وبتختفي من التغذية اللي بتستخدمه).
قاعدة التحقق (BE) لكل بند: (sentence) أو (dose+frequency+duration) — واحد منهم على الأقل. (drug_id) xor (clinic_drug_id) حسب clinic.pharmacy_source: products → drug_id إلزامي؛ standalone_formulary → clinic_drug_id إلزامي وممنوع ResolveDrugProduct يعمل firstOrCreate منتج (ResolveDrugProduct.php:46-70 يتقيّد بالوضع). الحالة المختلطة الحالية (clinic_drugs.product_id) تفضل للتوافق.
State machine روشتة: issued → printed → cancelled؛ + dispense_status مستقل. بند الإقامة: active → stopped \| completed. تعديل الروشتة مسموح قبل الطباعة وقبل توقيع الزيارة (endpoint جديد PUT prescriptions/{id})؛ بعدها cancel + إصدار جديد (الإلغاء بعد التوقيع يفضل مسموح — PrescriptionController:124).
API (واحد لكل السياقات) GET/POST encounters/{e}/prescriptions (موجود) + PUT prescriptions/{p} (جديد) + POST prescriptions/{p}/cancel (موجود) + GET prescriptions/{p}/pdf (جديد، BE PDF) · بنود الإقامة: POST prescriptions/{p}/items/{i}/stop (جديد) · كتالوج موحّد: GET clinic/drugs/search?q= يرجّع صفوف موحّدة {source: product\|formulary, id, name, form, dosage_form_id, alert_note, presets[]} حسب pharmacy_source (يستبدل البحث المزدوج في clinic-prescription.service.ts:201-228)
FE app-clinic-prescription [encounterId] [patientId] [locked] [kind=outpatient\|inpatient\|discharge] [subjectEnabled] — نفس الكومبوننت في العيادة/التغذية/الأسنان/ملف الإقامة. يشيل PRESET_FIELD_PLACEHOLDER ويبعت sentence. الشكل من dosage_forms dropdown (مع إضافة inline).
Settings موجود: clinic.pharmacy_source (يبقى مقروء في Support/PharmacySource.php), pos.pharmacy.dispensing_enabled / allow_partial_dispense / prescription_validity_days / require_prescription_rx, clinic.print.*. جديد: clinic.rx.item_model = sentence | structured | both (default both) — بيحدد الافتراضي في الفورم بس.
Permissions موجود clinic.prescriptions.view/create/print + جديد clinic.prescriptions.update, clinic.prescriptions.inpatient (للتمريض/الطبيب المعالج).
Events PrescriptionIssued (موجود، بلا listeners) · جديد: PrescriptionUpdated, PrescriptionItemStopped, PrescriptionDispensed (يطلقه POS).

المستشفى (MAR) ← نفس الموديل: hospital_med_orders بتتقسم جزئين: الإكلينيكي (drug/dose/route/frequency/times/prn/starts/ends/status/ordered_by/stopped) → prescription_items تحت prescriptions.kind=inpatient على encounter الإقامة. المالي/المخزني (product_id, warehouse_id, unit_price, charge_per_dose) → يفضل في Hospital كجدول جديد hospital_med_charging (صف لكل بند: prescription_item_id unique, product_id, warehouse_id, unit_price, charge_per_dose) — مش على hospital_med_admins لأن الأعمدة دي لكل أمر مش لكل جرعة. hospital_med_admins: + prescription_item_id nullable (backfill من order_id)، وNursingService بيحسب الـ slots من prescription_items.times. إصلاح مرافق: صرف المخزون (ConsumptionService::issue) يتفك من شرط التحصيل (NursingService.php:129-135) ويشتغل لو product_id+warehouse_id موجودين. روشتة الخروج = prescriptions.kind=discharge على نفس encounter الإقامة، بتتطبع مع ملخص الخروج، وبتظهر في «الأدوية الحالية» للمريض.

الصرف (hand-off): الطبيب يصدر → PrescriptionIssued → POS صيدلية (Phase 6) عنده worklist GET pos/pharmacy/prescriptions?status=pending يقرا من prescriptions مباشرة؛ البيع يستدعي MarkPrescriptionDispensed (يحدّث dispensed_qty/dispense_status). التغذية DispensedItemsService يفضل قارئ عرض.

4.2 طلبات التحاليل (Lab orders)

المالك: Clinic للطلب/النية/الفوترة، LIS للتنفيذ والنتائج.

التفصيل
جداول — keep clinic_clinical_intents, service_order_lines, LIS lab_requests/lab_results, clinical_documents
ALTER clinic_clinical_intents.encounter_id يفضل NOT NULL (كل طلب له encounter — حتى طلب الاستقبال «تحاليل بس» بيعمل encounter نوعه outpatient خفيف) · lab_investigations + lab_packages: + sbscs_code (للمطالبات) · clinical_documents.encounter_id → nullable + unique يتغير لـ (company_id, ref_key) (الـ ref_key أصلاً global: lab:reqinv:123)
منفّذ واحد جديد Actions/ExecuteCatalogItem = الفرع اللي جوه DecideClinicalIntent::here (:86-160): ياخد {catalog_ref_type, catalog_ref_id, order, doctor_id, encounter?} ويقرر حسب ClinicCatalogMode: lis_investigation/lis_package → OrderLabFromEncounter::handleForOrder · rad_procedure → CreateRadOrder::handleForOrder · clinic_service → AddServiceOrderLine fulfillment=self. المستهلكون: (أ) DecideClinicalIntent::here (الطبيب → الاستقبال). (ب) OrderingMode=immediate: StoreClinicalIntent ينادي here فوراً — endpoints POST encounters/{e}/lab-orders|rad-orders يبقوا wrappers (الروتس تفضل). (ج) CreateVisit.php:132-146 ينادي ExecuteCatalogItem بدل الاستدعاء المباشر — بلا encounter (الزيارة «تحاليل بس» تفضل بلا encounter زي النهارده؛ rad_orders.encounter_id nullable لنفس السبب). (د) CreateVisitRequest يقبل lab.items[] / radiology[] {catalog_ref_type, catalog_ref_id} (التوافق: investigation_id/procedure_id القديمة تتحوّل داخلياً).
التسعير متكامل: LIS price list للـ payer (موجود OrderLabFromEncounter:78). سعر تعاقدي لكل تحليل = LabInsuranceContract في LIS (قرار §9). مستقل: clinic_services بالـ 3 محاور + العقد (موجود).
النتائج لكل سياق DropLabReportOnEncounter يبطّل يتخطى no-encounter: يكتب clinical_documents بـ patient_id + encounter_id nullable. الإقامة: lab_requests.encounter_id = encounter الإقامة وsource يفضل clinic — ده قرار مسجّل (his.md:219 «RequestSource::clinic قيمة جديدة مش in_patient»، وRequestSource.php:10-12)، وكبت فاتورة LIS بيتم بالـ sentinel _suppress_invoice (CreateLabRequest.php:43-44) مش بالـ source فمفيش خطر فوترة مزدوجة. التمييز «إقامة» من encounter.kind. لو المالك عايز LIS يعرض «مريض داخلي» → قرار §9 #13. PatientLabHistoryService يقرا بـ patient_id (مش encounter join) فيشمل زيارات LIS المباشرة.
المطالبات ClaimAssembler.php:68 ياخد sbscs_code من الكتالوج الفعلي (lab_investigations/rad_procedures/clinic_services) حسب catalog_ref_type. سطر الفوترة يفضل واحد لكل request، لكن ClaimLine تتفرد لكل lab_request_investigation.
FE app-clinic-lab-orders [encounterId] [locked] [orderingMode] [kind] (موجود ويقلب على lab_mode — م7 WP5). يتستضاف زيادة في ملف الإقامة (تاب «طلبات»). شاشة قرار واحدة (reception-order) — كارت التغذية يستخدم نفس الـ dialog.
Settings موجودة: clinic.ordering_mode, clinic.lab_mode, clinic.results.external (permission). لا جديد.
Permissions موجودة clinic.intents.*, clinic.lab-orders.*, clinic.lab_results.view, clinic.results.external. تصحيح preset الاستقبال: يضاف clinic.lab_results.view (r2 §7).
Events LIS موجودة (LabResultReleased, LabRequestCompleted, LabRequestCancelled…) — بلا تغيير.

4.3 طلبات الأشعة (Radiology)

المالك: Clinic (RIS-lite موجود).

التفصيل
keep rad_procedures, rad_orders, rad_studies, rad_reports
ALTER rad_orders: + cancel_reason/cancelled_by/cancelled_at, + payer_contract_id nullable · rad_procedures: + sbscs_code, + default_template_id nullable · rad_reports: + template_id nullable, + body_structured json nullable · service_order_lines نوع radiology يستخدم result_status الموجود
جديد (صغير) clinical_templates (kind = rad_report | note | discharge | sick_leave | medical_report | certificate, scope_ref_type/id nullable, name_ar/en, body_ar/en, fields json, is_active, sort_order) — جدول قوالب واحد لكل المستندات بدل dental_note_templates + قوالب أشعة + قوالب خروج (الأسنان تتهاجر له لاحقاً).
State machine (نكمّل الموجود) Order: ordered → scheduled (عند إنشاء الـ study — CreateRadStudyOnOrder) → performed (عند RadStudyController acquired) → reported (عند RadReportReleased) → cancelled (action جديد CancelRadOrder مسموح قبل performed، يطلق RadOrderCancelled → FlagLinesForRefund نفس اللي للتحاليل). MarkEncounterRadComplete يشيل شرط encounter_id ويحط result_status=ready على السطر. الـ worklist تخفي reported.
الصور/المرفقات clinic_patient_attachments + attachable_type/id (رقم 4.5) — الدراسة تربط صورها attachable=rad_study. study_uid يتكتب عند الاقتناء.
تقرير + طباعة rad_reports تتعرض/تتطبع عبر GET rad-reports/{r}/pdf من محرك الطباعة (4.6). المحرر rad-report-editor ياخد القالب الافتراضي للإجراء.
التسعير متكامل: CreateRadOrder يمر على CoverageService::applyCoverage بنفس طريقة السطر العادي (دلوقتي بسعر الإجراء الخام). مستقل: clinic_services نوع radiology (موجود).
أشعة الأسنان — قرار صريح: مش rad order. dental_tooth_images (PA/BW/OPG/CBCT داخل العيادة، بلا تقرير) تفضل صور على السنة عبر المرفقات. لو العيادة بتبعت OPG/CBCT لمركز خارجي → طلب أشعة عادي في وضع standalone من نفس الكومبوننت.
FE app-clinic-rad-orders [encounterId] [locked] [orderingMode] [kind] (موجود). الـ worklist/report-editor زي ما هم + زرار إلغاء + طباعة PDF.
Settings clinic.rad_mode (موجود). لا جديد.
Permissions موجودة + presets جديدة: radiologist (rad-worklist.view, rad-reports.enter/verify/release) وrad_technologist (rad-worklist.view, rad-studies.update).
Events موجود RadOrderPlaced, RadReportReleased + جديد RadStudyAcquired, RadOrderCancelled.

4.4 النتائج والمستندات الإكلينيكية (ينضم الآن)

clinical_documents هو كيان المستند الموحّد: doc_type ينضم له sick_leave · medical_report · certificate · discharge_summary · rx_print (snapshot الطباعة). ALTER: encounter_id nullable (4.2) · + document_number (SequenceService) · + template_id → clinical_templates · + signed_at/signed_by · + from_date/to_date (للإجازة). API: POST encounters/{e}/documents {doc_type, template_id, data} + GET documents/{d}/pdf. FE: app-clinical-document-dialog [encounterId] [docType] يظهر في لوحة الخروج (consultation.html:685-734) وفي ملف الإقامة. Permissions: clinic.documents.create/print. المستشفى: admissions.discharge_summary يفضل نص للتوافق لكن الطباعة من المستند.

4.5 المرفقات والتنبيهات (ينضم الآن)

  • المرفقات: ALTER clinic_patient_attachments: + attachable_type/attachable_id nullable (morph: rad_study | clinical_intent | prescription | dental_tooth | clinical_procedure…) · + kind string(16) (image | pdf | photo | video | link) · + is_private bool. المستشفى يستخدمه من ملف الإقامة. مفيش جدول ميديا جديد (GYN §7.2 «media (موجود: attachments)» ✔).
  • التنبيهات: جديد patient_alerts (كما في GYN §7.2: patient_id, code, label, severity, source (history_answer \| manual \| drug_alert), source_ref, active, set_by). يتغذى تلقائياً من PatientReadService allergies (listener على حفظ history) + يدوي. الهيدر المشترك clinic-patient-header يقرا منه في كل الشاشات بما فيها ملف الإقامة. Permission: clinic.alerts.manage.

4.6 محرك الطباعة (ينضم الآن)

Clinic/app/Services/ClinicalPdfService فوق DomPDF (نفس LabReportPdfService): قوالب Blade لكل نوع (prescription, rad_report, document, visit_summary, referral). الهيدر/الفوتر/اللوجو/الورق من clinic.print.* (موجودة) + توقيع لكل طبيب (lab_doctors.signature_attachment_id جديد). endpoint نمطي GET clinic/print/{kind}/{id}.pdf. الـ FE clinic-print-shell.service.ts يفضل للـ preview السريع حتى يتأكد المالك من الـ PDF، بعدها نحوّل الـ 5 طباعات + الأسنان + التغذية (بتنسيق مع moonui) عليه.

4.7 البلوكات اللاحقة (مخططة في الـ KB — ترتيبها بعد المراحل دي)

البلوك القرار
تشخيص/شكوى encounter_diagnoses + ClinicComplaint هم الكيان. المستشفى يستخدمهم على encounter الإقامة (admissions.diagnosis يبقى «سبب الدخول» فقط). التغذية تضيف لوحة التشخيص (moonui).
علامات حيوية محرك الحقول الديناميكية (م6 — clinic-dynamic-fields). hospital_vital_rounds تفضل (time-series تمريضي بـ NEWS2) لكن تعريفاتها/حدود الخطر من المحرك.
ملاحظات/addenda clinical_notes (GYN §7.2) — immutable + addendum؛ EncounterAmendment يفضل للزيارة الموقّعة. hospital_nursing_notes تتهاجر له بـ kind=nursing لاحقاً.
متابعة/إحالة ClinicReferral موجود · follow_up_tasks (GYN) يوحّد dental_recalls + admissions.follow_up_on + متابعة التغذية.
Patient record API GET clinic/patients/{p}/record?encounter_id=&sections= في Clinic (PatientRecordService بنفس نمط safe() بتاع التغذية) — التغذية والنسا بيمدّوه بأقسامهم بدل ما يبنوا endpoint لكل تخصص.
access_audit قبل تشغيل أي عميل طبي (GYN مرحلة 0).

5. الـ Extension contract للتخصصات

التخصص = ClinicalType (enum بالكود) + entry في registry الـ FE + باقة حقول. اللي يقدر يعمله:

مسموح ممنوع
حقول إضافية عبر محرك history_questions (packs بـ prefix: nut_, dent_, gyn_) بـ scope patient/encounter + show_if لما يتنفذ جدول روشتة/أدوية/أوامر تحاليل/أشعة خاص
Presets أدوية وقوالب (clinic_drug_presets, clinical_templates بـ scope_ref_type=clinical_type) ومفضّلات لكل طبيب قوائم route/frequency/form خاصة
جداول خاصة للي بيتعرض كـ cards أو بيتبحث فيه (odontogram، InBody، دورات العقم، حمل…) — زي GYN §7.2 نسخ من clinical_documents/attachments/patient_alerts
استضافة الكومبوننتات المشتركة بالـ inputs ([encounterId] [patientId] [locked] [kind]) وإخفاء/إظهار بلوك بإعداد {type}.feature.* (نمط dental.feature.*) فورك كومبوننت مشترك أو طباعة يدوية (window.print)
قراءة الـ record API المشترك وإضافة أقسام عليه (PatientRecordService::extend('nutrition', fn)) endpoint record خاص بكل تخصص

المستشفى = سياق مش تخصص. الإقامة ما تبقاش clinical_type؛ القسم المعالج يفضل بتخصصه (جراحة/نسا/باطنة)، وencounters.kind=inpatient هو اللي بيفتح بلوكات الإقامة (MAR، التمريض، الخروج) جنب نفس الروشتة/التحاليل/الأشعة. ملف الإقامة (admissions/:id) يستضيف app-clinic-prescription [kind=inpatient], app-clinic-lab-orders, app-clinic-rad-orders, المستندات، المرفقات. AdmissionService.php:125-131 يفتح الـ encounter بـ kind=inpatient + admission_id.

التغذية (moonui): بتستضيف الكومبوننتات فعلاً. التغيير المطلوب منهم: (1) PatientMedicationsService يقرا sentence ?? dose/frequency/duration (وإلا تظهر فراغات بعد الهجرة)، (2) تبنّي لوحة التشخيص المشتركة، (3) تحويل print-context على محرك الطباعة. يتم بالاتفاق مش بتعديل كودهم من هنا.


6. عيادة / مركز / مستشفى — نفس الكور بإعدادات

الإعداد عيادة واحدة مركز مستشفى
his.mode single_clinic center center
clinic.ordering_mode immediate (الدكتور بينفذ) intent (الاستقبال بينفذ) intent
clinic.lab_mode / rad_mode standalone (معمل برّه) integrated أو standalone integrated
clinic.pharmacy_source standalone_formulary products products
pos.pharmacy.dispensing_enabled false true (صيدلية POS) true
encounters.kind المستخدمة outpatient / remote outpatient / day_case + inpatient (Hospital module)
clinic.procedures.mode (GYN §7.6) external center hospital
clinic.visit_stations مدمجة منفصلة منفصلة
الطباعة clinic.print.* + توقيع الطبيب نفسه نفسه + ملخص خروج

مفيش سطر كود يتغير بين الأعمدة الثلاثة.


7. الهجرة بدون كسر

كل الخطوات additive وقابلة للرجوع؛ البيانات الحية على moonui3 صغيرة.

  1. بنود «—»: migration تمشي على prescription_items حيث dose='—' OR frequency='—' OR duration='—' → sentence = instructions، الحقول الثلاثة = NULL، form = القيمة اللي كانت في dose لو مش «—». instructions تفضل زي ما هي. الطباعة القديمة اللي كانت بتمسح «—» (clinic-prescription.service.ts:295-305) تتشال.
  2. الشكل الصيدلي: seed dosage_forms بالقائمة العربية الشائعة (من COMMON_DRUG_FORMS_AR في الكومبوننت) لكل شركة (updateOrCreate على code) → backfill prescription_items.dosage_form_id / clinic_drugs / clinic_drug_presets بمطابقة الاسم؛ اللي ما يتطابقش يفضل نص في form.
  3. الطرق/التكرار: MedicationRoute يتوسع (إضافة قيم بس = backward-safe). MedicationFrequency جديد؛ بنود الإقامة القديمة frequency كود صغير يتنقل لـ frequency_code.
  4. MAR → prescriptions: migration تعمل لكل إقامة عندها hospital_med_orders روشتة واحدة kind=inpatient على encounter الإقامة، وتنسخ كل order لبند (drug_name=drug, drug_id=product_id, times, prn, starts_at, ends_at, item_status) وتكتب hospital_med_admins.prescription_item_id. hospital_med_orders يفضل للقراءة ريليس واحد (NursingService يكتب في الاتنين خلف flag hospital.mar_on_prescriptions) ثم يتجمّد. الروتس api.hospital.nursing.orders.* تفضل وتنادي الـ Clinic actions.
  5. الأشعة الواقفة عند ordered: migration تصلّح الحالة من الواقع: order له study acquired → performed؛ له report released → reported + سطر result_status=ready. مفيش بيانات بتتمسح.
  6. الجسر clinic_services.lis_investigation_id/rad_procedure_id: يُحذف من الـ API (الحارسان + الـ import) ويفضل العمود ريليس واحد ثم drop. السبب: القرار المعتمد «بلا mirror» + الوضع المتكامل بيختار من كتالوج LIS مباشرة، فالجسر ما لوش مستهلك.
  7. clinical_documents.encounter_id nullable + unique جديد: migration: drop unique القديم → add (company_id, ref_key). تتأكد الأول إن مفيش تكرار (ref_key global فعلاً).
  8. CreateVisit: الـ payload القديم (lab.investigations[].investigation_id, radiology[].procedure_id) يتقبل ويتحوّل داخلياً — الـ FE يتحدّث في نفس المرحلة، مفيش كسر للعملاء.
  9. الطباعة: PDF endpoints تتضاف جنب الـ FE preview؛ التحويل الكامل بعد اختبار المالك.

8. المراحل

# المرحلة التسليم الحجم المخاطر المالك يختبر على /app
P0 الأساس MedicationRoute 13 قيمة + MedicationFrequency + seed dosage_forms · encounters.kind/admission_id (+ AdmissionService يملاهم) · قفل BE على الـ 5 actions · clinic_patient_attachments morph · clinical_documents.encounter_id nullable · PharmacySource reader S–M unique الجديد على المستندات يفتح زيارة موقّعة ويحاول يضيف روشتة/طلب من الـ API → 409؛ dropdown «الشكل» في الروشتة بيقرا من dosage_forms ويقبل إضافة inline
P1 روشتة v2 نموذج البند (جملة أو مهيكل) بلا «—» · PUT prescriptions قبل الطباعة · subject (زوج) · clinic.pharmacy_source فعّال (standalone بلا منتج) · بحث أدوية موحّد · GET prescriptions/{p}/pdf · migration «—» M التغذية بتقرا الحقول القديمة (تنسيق moonui) · DomPDF عربي (مثبت في LIS) روشتة من preset → الطباعة فيها الجملة صح وبلا «—»؛ يعدّل بند ويطبع؛ يقلب الإعداد لـ standalone ويروشت دوا من clinic_drugs بلا ما يتخلق منتج
P2 أدوية الإقامة على الروشتة MAR على prescription_items kind=inpatient · hospital_med_charging · إصلاح صرف المخزون · روشتة الخروج تتطبع مع ملخص الخروج · ملف الإقامة يستضيف app-clinic-prescription M–L migration الـ admins · لوحة التمريض بتتغير يدخل مريض، يأمر دوا من نفس كومبوننت الروشتة (كاتالوج حقيقي بدل نص)، التمريض يدي جرعة → تتحاسب ويتصرف المخزون؛ روشتة خروج تظهر في «الأدوية الحالية»
P3 منفّذ واحد + إكمال الأشعة استخراج ExecuteCatalogItem · immediate عبر النية · CreateVisit على نفس المنفّذ (standalone للاستقبال، بلا encounter) · state machine الأشعة + إلغاء/refund + coverage · result_status للأشعة · طلبات من ملف الإقامة على encounter الإقامة · presets radiologist/technologist L (يتقسم 4 WPs) أكبر تغيير في فلو الاستقبال في standalone: الاستقبال يحجز زيارة فيها تحليل من كتالوج العيادة ويتحاسب؛ أشعة: طلب → worklist → اقتناء → تقرير → الطلب reported وبيختفي من الـ worklist وبيظهر «جاهز» عند الاستقبال؛ إلغاء طلب أشعة قبل التنفيذ يعلّم السطر للاسترداد
P4 النتائج والسجل نتائج بلا زيارة على ملف المريض · PatientLabHistory بالمريض · تقرير أشعة بقالب + صور + PDF · sbscs_code في المطالبات · GET clinic/patients/{p}/record في الكور (التغذية تمدّه) M تنسيق التغذية على الـ record طلب LIS مباشر (walk-in) يظهر في تاريخ تحاليل المريض من شاشة الكشف؛ تقرير أشعة بقالب يتطبع PDF بصورة مرفقة
P5 المستندات والتنبيهات إجازة مرضية / تقرير طبي / شهادة من clinical_documents + clinical_templates + PDF · patient_alerts في الهيدر في كل الشاشات بما فيها الإقامة · تحويل الطباعات القديمة على المحرك M — يطلع إجازة مرضية برقم متسلسل من لوحة الخروج ويطبعها؛ حساسية مسجلة في history تظهر كتنبيه أحمر في ملف الإقامة
P6 صرف الصيدلية (POS) worklist روشتات معلقة في POS · بيع → PrescriptionDispensed · dispense_status شارة عند الطبيب · إعدادات pos.pharmacy.* فعّالة M يعتمد على POS يروشت → يفتح POS يلاقي الروشتة → يبيع → الشارة «اتصرفت» عند الطبيب

بعد P6: clinical_notes, follow_up_tasks, هجرة dental_note_templates/dental_recalls, vitals الديناميكية (م6), access_audit.


9. المخاطر والقرارات المطلوبة من المالك

  1. مكان الكور: موديول Clinic (التوصية) ولا موديول جديد ClinicalCore؟ Clinic بيملك فعلاً 30+ جدول إكلينيكي وكل التخصصات بتعتمد عليه. موديول جديد = نقل جداول وكسر namespaces بلا فايدة. توصية: Clinic، مع مجلد app/Clinical/ للـ actions المشتركة.
  2. السياق: Encounter بنوع (التوصية) ولا polymorphic context على كل جدول؟ الدليل: hospital_admissions.encounter_id + service_order_id موجودين، كل جداول الأوامر encounter_id، LIS عنده in_patient، والسياق الوحيد بلا encounter هو LIS walk-in وده مغطّى بـ patient_id. Polymorphic = فقد FKs + إعادة كتابة كل القرّاء والـ listeners. توصية: Encounter + kind.
  3. هجرة MAR على الروشتة (P2) — دلوقتي ولا بعد P3؟ المستشفى اتبنى على moonui3 (نفس الإنستانس) فالتنسيق سهل. توصية: P2 زي الترتيب لأن الإقامة هي أكبر مكرر.
  4. محرك الطباعة: BE PDF (التوصية) ولا نكمل FE HTML؟ LIS مثبت DomPDF بالعربي. توصية: BE PDF مع إبقاء الـ preview لحد ما تختبر.
  5. سعر تعاقدي لكل تحليل في الوضع المتكامل: LabInsuranceContract في LIS (التوصية) ولا تمديد عقود العيادة؟ توصية: LIS — الكتالوج هناك والسعر هناك.
  6. أشعة الأسنان: مش rad order (التوصية) — صور على السنة؛ الخارجي = طلب standalone. محتاج تأكيد.
  7. الصرف (P6): دلوقتي ولا بعدين؟ الإعدادات pos.pharmacy.* مزروعة ومكتوب عليها «لسه هتتبني». توصية: بعد P3 — البنية جاهزة من P1 (dispense_status + event).
  8. التغذية: الهجرة في P1 هتغيّر اللي PatientMedicationsService بيعرضه. قرار: مين يعدّل قارئ التغذية (moonui) وإمتى؟ ومعاه تبنّي لوحة التشخيص والـ record المشترك.
  9. حذف جسر clinic_services.lis_investigation_id/rad_procedure_id (التوصية: يتشال — بلا مستهلك، والقرار «بلا mirror» معتمد) ولا يتفعّل؟
  10. المطالبات: تفريد ClaimLine لكل تحليل (التوصية) ولا سطر واحد للطلب؟ NPHIES محتاج كود لكل خدمة.
  11. presets الصلاحيات الجديدة (radiologist, rad_technologist) وتصحيح preset الاستقبال بإضافة clinic.lab_results.view — موافقة.
  12. الروتس المباشرة POST encounters/{e}/lab-orders|rad-orders: تفضل كـ wrappers (التوصية) ولا تتشال؟ إبقاؤها = صفر كسر للـ FE.
  13. مصدر طلبات التحاليل من الإقامة في LIS: يفضل source=clinic (التوصية — قرار مسجّل في his.md:219، والتمييز من encounter.kind) ولا نرجع لـ in_patient عشان شاشات LIS تعرض «مريض داخلي»؟ لو in_patient: تعديل سطر واحد في OrderLabFromEncounter + فلاتر LIS اللي بتعتمد على clinic.

مخاطر عامة: (أ) حجم P3 — يتقسم WPs صغيرة (immediate-via-intent / CreateVisit / rad SM / coverage) كل واحدة بسيناريو على /app. (ب) الاختبارات على SQLite ما بتكشفش أعمدة ناقصة — كل migration تتراجع على MySQL moonui3. (ج) أي تعديل في AddServiceOrderLine/CollectReceptionReceipt يتعمل مرة واحدة في الطبقة المشتركة (قاعدة المالك).

Moon Clinic · المنصة الطبية الموحّدة — 2026-10-21 · حصر الكود + تصميم Fable (البلوكات المشتركة، والبيانات، والشاشة v2) · التنفيذ على moonui3