تحليل شامل لنظام معلومات المعمل: قسم خاص ومفصّل للـ UI/UX واقتراحات التحسين، بالإضافة للمعمارية، سلامة المريض، الأمان، الأداء، والاكتمال — بأدلة من الكود.
FRONTEND-PATCH … wiped on next deploy — وفيه الـ schema الوحيد للميكروبيولوجي والهستوباثولوجي وأنواع النتائج الجديدة (ResultType::Culture/Histopathology، LabAntibiotic، LabHistopathResult، migration 2026_05_24_000001). أي deploy بـ git reset --hard origin/main هيمسح الجداول دي ويسيب شاشات الـ frontend بدون قاعدة بيانات. لازم يتصالح مع "migrations أحمد الرسمية" قبل أي deploy.
ده نظام معلومات معمل كامل ومبني باحتراف: catalog وتحاليل وباقات، عيّنات وحضانة (custody)، تكامل أجهزة فعلي (ASTM/HL7 مع outbox موثوق)، QC بقواعد Westgard، auto-verification، فوترة وتأمين ومعامل خارجية (B2B) وعمولات أطباء وكاشير — كلها مبنية. الأساس متين، والـ تكامل الأجهزة وقواعد الجودة من أقوى ما يكون.
CLAUDE.md لسه بيوثّق المعمارية المتقاعدة، وطبقة التصميم غير متسقة (2,471 لون hex متكتوب يدوي، اللون الأساسي متكرر في 36 ملف، ومجلد shared/ شبه مش مستخدم).الـ sidebar بيجمّع ~50 عنصر في 7 مجموعات (Operations / Catalog / External Labs / Financial / Costing / Quality / Reports)، كلها permission-gated. التصنيف معقول بس متضخّم (Catalog لوحده 14 عنصر). أدوات تنقّل ممتازة: بحث فوري (debounce 300ms)، breadcrumbs، "شاشات حديثة"، badges أعداد حيّة، تنبيهات حرجة بالـ polling — فوق المتوسط لـ ERP.
| الوظيفة | الشاشة الحيّة | الميتة (موجودة على الديسك) |
|---|---|---|
| إنشاء طلب | request-wizard-v2 | request-wizard v1 (1,394 سطر) — ميتة |
| لوحة المعالجة | dept-worklist | kanban (1,490 سطر) — redirect — ميتة |
| إدخال النتائج | dept-worklist + validation-worklist | results/lis-results (1,803 سطر) — redirect — ميتة |
| جمع العيّنات | collection-worklist | samples/lis-samples (1,244 سطر) — ميتة |
| استلام العيّنة | reception | specimen-receiving (644 سطر) — ميتة |
shared/ فيه 3 كومبوننتس بس، واحد مستخدم في مكان واحد والاتنين التانيين صفر استخدام.p-table بس 13 بيستخدم <table> خام. مفيش wrapper موحّد. كل worklist بيعيد تنفيذ الـ badges والـ chips بشكل مختلف شوية.WorklistGrid + StatusBadge + FlagBadge + KPICard وتوكنة الألوان.| المرحلة | التقييم | التفاصيل |
|---|---|---|
| الاستقبال (reception) | قوي | barcode-first مع إعادة تركيز تلقائي، صوت تأكيد (نغمة نجاح/فشل)، رفض جزئي لكل تحليل. UX حقيقي لأرض المعمل. ناقص: keyboard tab-switch، ARIA، وفلترة client-side مش هتتحمّل فوق 1000 أنبوبة. |
| إنشاء الطلب (wizard-v2) | الحلقة الأضعف | تصميم ذكي (صفحة واحدة + ملخّص حي + تسعير/تأمين/NPHIES فوري)، بس صفر دعم keyboard — مفيش Enter/Ctrl+S، واختيار التحليل كليك لكل تحليل (مؤلم لطلب 30-50 تحليل). أكبر احتكاك يومي في التطبيق. |
| إدخال النتائج (dept-worklist) | ممتاز | تحرير inline بالكامل، Enter بيحفظ وينتقل للتالي، Tab/Shift+Tab مخصّص، حساب flag لحظي، auto-save كل 30 ث. 3-4 ضغطات لكل نتيجة — الكثافة اللي معمل مزدحم محتاجها بالظبط. (دليل إن الفريق يقدر يبنيها — بس مش مطبّقة في الـ wizard). |
| التحقّق والنشر | جيد | زر إجراء تدريجي (validate→approve→release) بـ badges، إجراءات bulk. ~4 كليك. احتكاك: 7 أنواع modals = إرهاق نوافذ؛ والمشرف يقدر يعدّل القيم بصمت بدون خطوة تصحيح صريحة. |
validation-worklist.component.ts = 3,727 سطر (HTML 1,623)! · dept-worklist = 2,848 · request-wizard-v2 = 1,981. مخالفين حد الـ 800 سطر بـ 2.5-4.6×.OnPush رغم إنهم signal-driven — خسارة أداء حقيقية على جداول 1000 صف، ومكسب سهل.ngModel + تتبّع dirty يدوي بطفرة (بيخالف قاعدة الـ immutability).| أولوية | التحسين |
|---|---|
| P0 نظافة | امسح الشاشات الميتة (wizard v1، kanban، lis-results، lis-samples، specimen-receiving) = ~8-9K سطر بصفر مخاطرة (متأكَّد بـ grep). وأعد كتابة الـ CLAUDE.md للمعمارية الحقيقية (Worklist-first) — الحالي بيضلّل المطوّرين. |
| P1 إنتاجية | ضيف دعم keyboard للـ wizard-v2: Enter للانتقال، Ctrl+S للحفظ، تركيز أول حقل، و"اختر كل تحاليل الفئة/الباقة". انقل نمط data-input-idx/focusInput() الناجح من dept-worklist. ده أكبر إصلاح احتكاك يومي. |
| P1 إنتاجية | قلّل إرهاق الـ modals في التحقّق: خلي الإجراءات المتكررة (تصحيح قيمة، رفض) inline مع undo toast، وسيب الـ modals للحاجات المدمّرة بس. |
| P1 تصميم | استخرج طبقة كومبوننتس تشغيلية مشتركة: WorklistGrid، StatusBadge، FlagBadge، KPICard، PageHeader، BarcodeScanInput (بصوت الاستقبال جواه). وتوكِّن الألوان (36 موقع + 2471 hex → var(--lab-*)). |
| P2 جودة | فكّك validation-worklist (3,727 سطر) و dept-worklist، وضيف OnPush للشاشات الـ signal-driven (3/97 دلوقتي) — مكسب أداء مباشر. |
| P2 إتاحة | جولة a11y على الـ worklists/reception/wizard: aria-label على حقول النتائج، aria-live على العدادات، focus-trap في الـ dialogs. مطلوب لنظام إكلينيكي. |
| P2 IA | تصميم Worklist-first: خلي الـ Worklist هي صفحة الهبوط، ونزّل board/dashboard لمستوى تانٍ، وضيف "الخطوة التالية" صريحة بين الـ 6 شاشات. واجمع شاشات الأجهزة الـ 3 تحت قائمة "Instruments" واحدة. |
استقبال/زيارة ← LabRequest ← LabSample ← استلام (بيولّد LabResult) ← إدخال (يدوي أو من الجهاز) ← تحقّق/auto-verify ← اعتماد ← نشر (بوابة/PDF + قيود B2B). كل انتقال بيكتب audit log غير قابل للتعديل.
| الملف | الحجم | المشكلة |
|---|---|---|
WorklistContextService.php | 2,110 سطر | أسوأ god class — بيخلط التجميع والـ rollup وتنسيق العرض |
ExternalLabPortalRequestController.php | 1,395 سطر | store() بيكرّر منطق CreateLabRequest كله inline بدل ما يستخدمه |
LabResultController.php | 1,077 سطر | retract/correct فيهم transactions تكرّر LabResultService |
كمان: تتبّع حالة ثلاثي (RequestInvestigation / SampleInvestigation / Result) بيخلّق معظم تعقيد مزامنة الـ workflow؛ والـ Jobs شبه مش مستخدمة (شغل تقيل زي الـ PDF والنشر متعدد القنوات بيشتغل synchronous).
التحقّق/الاعتماد البشري مبيستدعيش verify() — يعني delta/critical/range checks موصولة بس في مسار الجهاز. وفي مسار الجهاز، verify() بيرجّع passed:true للقواعد الفاضية وisCritical() متحسوبة بس مبتتفحصش قبل الاعتماد التلقائي → قيمة حرجة (panic) ممكن تتنشر بدون مراجعة بشرية.
LabSample::where('barcode')->first() بدون فلتر company_id → نتيجة جهاز ممكن تتكتب في ملف مريض شركة تانية، والتنبيه الحرج يضرب على السجل الغلط.
فلتر النوع متعشّش جوه if ($patient && $patient->date_of_birth) — فلو DOB ناقص، النطاق الخاص بالنوع بيتختار عشوائياً بـ first() → flags غلط (H/L) على تحاليل زي الهيموجلوبين.
| # | المشكلة | المكان | الخطورة |
|---|---|---|---|
| — | انتقالات حالة النتيجة بدون قفل (check-then-act) → نتيجة تتعتمد/تتنشر مرتين | LabResultService.php:52-282 | CRIT |
| — | ACK يتبعت قبل حفظ النتيجة (ASTM) → نتيجة تضيع نهائياً عند crash | astm_tcp_server.py:219 | CRIT |
| — | مفيش idempotency → ابتلاع مكرّر (تنبيهات/كاشف مكرّر، قيمة قديمة تدوس مصحّحة) | LabMachineResultController.php:164 | CRIT |
| H | حدود < vs <= غير متسقة → قيمة على عتبة الـ panic بالظبط مبترفعش تنبيه | LabResultService.php:699 | HIGH |
| H | تنبيه حرج بيتبعت بس عند enter الفردي — مش في bulk ولا بعد التصحيح | LabResultController.php:391 | HIGH |
| H | أرقام بفاصلة عشرية (locale) بتتجاوز كشف الحرج وتتخزّن كنص | astm_base.py:70 | HIGH |
| H | كود جهاز واحد ← عدة تحاليل: بيكتب نفس القيمة لكلهم (GLU → FBS و PPBS) | LabMachineResultController.php:207 | HIGH |
| H | وحدة الجهاز بتتنسخ بدون تحقّق/تحويل (mg/dL مقابل mmol/L ~18×) | LabMachineResultController.php:222 | HIGH |
| H | سجل الحضانة (custody) مبيتكتبش في دورة العيّنة الداخلية → فشل CAP/ISO 15189 | LabSampleService.php | HIGH |
| C$ | سباق دفع زائد على مدفوعات المرضى (بدون قفل/transaction) | LabPaymentController.php:178 | CRIT |
| C$ | تصادم amount_paid بين B2B والمريض → يمسح تخصيصات B2B | PostLabPayment.php:65 | CRIT |
AutoVerificationService خالص — صفر تغطية لـ critical/range/delta. ومفيش تستات للحدود على عتبة الـ panic، ولا لمسار ابتلاع الأجهزة، ولا للدفع المتزامن. (ملاحظة إيجابية: SequenceService وLabReagentService::consumeFifo وSampleInvestigationService::moveTo بيستخدموا القفل الصح — العيوب بتتجمّع فين ما النتائج/الفلوس مابتعيدش استخدام النمط الموجود).مسارات البوابة مسجّلة بـ ['api'] بس، ومفيش throttle. الدخول بـ mrn + date_of_birth بس (معرّفين منخفضي الإنتروبيا). مهاجم بيعدّ الـ MRN ويخمّن تاريخ الميلاد ويحصل على توكن دائم لأي مريض → تسريب PHI كامل (نتائج، تشخيصات سرطان ICD-O، فواتير، مرفقات).
كل واحدة بتلفّ LabResult::find($id) بدون scope للشركة، ومفيش global tenant scope. مستخدم من شركة A يبعت IDs بتاعة شركة B ويسوق دورة حياتها (enter→validate→approve→release) أو يدوس قيم draft. POST /api/lis/results/bulk-release {"result_ids":[competitor_id]} بينشر نتائج معمل تاني.
| # | المشكلة | المكان | الخطورة |
|---|---|---|---|
| C2 | توكنات جلسة البوابة مبتنتهيش أبداً (TTL = null) — توكن مسرّب = وصول دائم | PatientPortalController.php:74 | CRIT |
| C3 | توكن رابط دائم (single-factor) مبيتدوّرش، ومكشوف في QR/واتساب وفي الـ staff API | PatientPortalController.php:53 | CRIT |
| C5 | النتائج المنشورة ممكن تتعدّل في مكانها وسجل النشر الأصلي يتكتب فوقه (مفيش توقيع) | LabResultController.php:663 | CRIT |
| C6 | سياسة الاحتفاظ مش مفروضة + hard-delete بيمسح سجل التدقيق نفسه | LabRequestController.php:555 | CRIT |
| H1 | عمليات النتائج الـ bulk مبتكتبش audit log (التدقيق معتمد على المطوّر مش مفروض مركزياً) | LabResultController.php:911 | HIGH |
| H4 | كنترولر الهستوباثولوجي بدون permission middleware — أي مستخدم يعتمد تشخيص سرطان | LabNewTypesController.php | HIGH |
| H2 | mass-assignment لـ company_id/توكنات البوابة على LabPatient | LabPatient.php:25-55 | HIGH |
Global Tenant Scope — العزل 100% يدوي، فأي نسيان = تسريب. التوصية: CompanyScope عام.كل البايبلاين (mapping + flag + events + audit + auto-verify) بيشتغل synchronous على thread الـ request، نتيجة واحدة لكل HTTP call. أنبوبة CBC (~25 بارامتر) = 25 POST + 25 بايبلاين كامل، وكل POST بـ TCP+TLS جديد (بدون keep-alive)، ورافع واحد single-threaded. ده سقف الإنتاجية تحت ضغط الأجهزة.
lab_results.sample_id ناقص — أخطر فجوة فهرسة
الـ FK sample_id مش متفهرس → كل تحميل إدخال نتيجة / مطابقة جهاز بالعيّنة = full scan. أكبر ضرر منفرد.
| المشكلة | المكان | الخطورة |
|---|---|---|
worklist الاستقبال ->get() غير محدود + whereDate() بيعطّل الفهرس + N+1 في الـ Resource | ReceptionWorklistService.php:31, LabSampleResource.php:104 | CRIT |
التقارير بدون حد أقصى لمدى التاريخ → from=2015 بيسكان كل التاريخ (DoS)، وبدون أي caching | LISReportController.php:45 | CRIT |
Frontend: 0 من 14 شاشة ثقيلة بتستخدم OnPush؛ kanban/dashboard بـ polling + ساعة كل ثانية + آلاف كروت بدون virtualization؛ listAll() بيحمّل كل الجدول للمتصفح | lis-kanban:270, requests:378 | CRIT |
| جداول نمو غير محدود بدون أرشفة: communication logs، publish logs، audit logs | migrations | HIGH |
lab_results.sample_id (+ المركّبات). (3) حُد مدى التقارير + caching. (4) صلّح N+1 في الـ Resources وحُدّ الاستقبال/kanban. (5) Frontend: OnPush + server pagination + شيل ساعة الثانية.Westgard QC auto-verification framework audit trail (قيمة/حالة/IP/UA) معامل خارجية B2B كاملة كواشف/lots تأمين وفوترة عمولات أطباء كاشير/خزينة middleware الأجهزة تقارير/طباعة رفض عيّنات + custody
nphies-log/settings موجودة بس مفيش backend في موديول LIS (متفوّض لـ core) — لازم يتأكّد.| الموجة | الشغل | ليه دلوقتي |
|---|---|---|
| ٠ — منع فقدان بيانات | صالح كود الـ FRONTEND-PATCH مع الـ migrations الرسمية قبل أي deploy | خطر مسح schema حيوي بـ git reset |
| ١ — سلامة المريض | استدعِ verify() ببوابة حرجة في المسار البشري، قفل انتقالات النتيجة، scope ابتلاع الجهاز بالشركة + idempotency + تطبيع الأرقام/الوحدات | مخاطر إكلينيكية مباشرة على المرضى |
| ٢ — أمان PHI | throttle + TTL + تدوير توكن + OTP لبوابة المرضى، scope الـ bulk results، تدقيق/custody مركزي بـ observers، وقف تعديل المنشور | تسريب بيانات صحية + امتثال قانوني |
| ٣ — UI/UX | امسح الشاشات الميتة + صلّح CLAUDE.md، keyboard للـ wizard، قلّل الـ modals، استخرج طبقة كومبوننتس + توكنة ألوان، OnPush | القسم اللي طلبته — إنتاجية يومية واتساق |
| ٤ — أداء | queue لابتلاع النتائج + batch endpoint، فهرس sample_id، حد مدى التقارير + caching، server pagination في الـ frontend | ضروري قبل ما الأحجام تكبر |
| ٥ — اكتمال | إكمال الميكروبيولوجي (كائنات/MIC/antibiogram)، إرسال آلي للقيم الحرجة، reflex engine، تأكيد NPHIES | متطلبات اعتماد ووظائف معمل ناقصة |