تدقيق فني عميق · 6 محاور متوازية · تركيز على الـ UI

تقرير تدقيق موديول المعمل (LIS) — Moon ERP

تحليل شامل لنظام معلومات المعمل: قسم خاص ومفصّل للـ UI/UX واقتراحات التحسين، بالإضافة للمعمارية، سلامة المريض، الأمان، الأداء، والاكتمال — بأدلة من الكود.

2026-06-15 · Backend ~82.7K LOC (67 ctrl · 66 model · 139 migration · 35 service) · Frontend ~49K LOC (70 شاشة · 97 component) · Python middleware (ASTM/HL7)
⚠️ تحذير عاجل — خطر فقدان بيانات: فيه كود متعلّم عليه 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.
ناضج جداًالحكم: نظام LIS حقيقي
6+حرجة (سلامة مريض)
6ثغرات أمان PHI حرجة
~9Kسطر كود ميت (شاشات مهجورة)
~132Kإجمالي سطور الكود
⚖️

٠ — الحكم العام

نظام LIS واسع وناضج جداً — أكبر موديول في الـ ERP — بأساس قوي، لكن فيه مخاطر حرجة في سلامة المريض والأمان لازم تتعالج فوراً.

ده نظام معلومات معمل كامل ومبني باحتراف: catalog وتحاليل وباقات، عيّنات وحضانة (custody)، تكامل أجهزة فعلي (ASTM/HL7 مع outbox موثوق)، QC بقواعد Westgard، auto-verification، فوترة وتأمين ومعامل خارجية (B2B) وعمولات أطباء وكاشير — كلها مبنية. الأساس متين، والـ تكامل الأجهزة وقواعد الجودة من أقوى ما يكون.

بس الخطورة: العيوب الحرجة مركّزة في 3 أماكن خطيرة — (1) مسار اعتماد النتائج البشري بيتجاوز فحوصات الأمان (auto-verify/critical)، (2) بوابة المرضى العامة فيها ثغرات PHI خطيرة، (3) كود مؤقت معرّض للمسح فيه schema حيوي. دي مش مشاكل تجميلية — دي مخاطر إكلينيكية وقانونية.

القسم الخاص — تحليل الـ UI / UX (/app/lab)

تحليل معمّق لواجهة المعمل + اقتراحات تحسين عملية ومرتّبة بالأولوية. ده القسم اللي طلبته بالتحديد.
العنوان الكبير: الواجهة عدت بإعادة هيكلة كبيرة (من Kanban/Results القديمة إلى تصميم Worklist-first) — بس الشاشات القديمة ماتمسحتش. فيه ~8-9 آلاف سطر شاشات ميتة على الديسك، والـ CLAUDE.md لسه بيوثّق المعمارية المتقاعدة، وطبقة التصميم غير متسقة (2,471 لون hex متكتوب يدوي، اللون الأساسي متكرر في 36 ملف، ومجلد shared/ شبه مش مستخدم).

١. هيكل المعلومات والتنقّل (IA)

الـ sidebar بيجمّع ~50 عنصر في 7 مجموعات (Operations / Catalog / External Labs / Financial / Costing / Quality / Reports)، كلها permission-gated. التصنيف معقول بس متضخّم (Catalog لوحده 14 عنصر). أدوات تنقّل ممتازة: بحث فوري (debounce 300ms)، breadcrumbs، "شاشات حديثة"، badges أعداد حيّة، تنبيهات حرجة بالـ polling — فوق المتوسط لـ ERP.

المشكلة الجوهرية — شاشات مكرّرة/ميتة (متأكَّد منها بـ grep = صفر مراجع خارجية):
الوظيفةالشاشة الحيّةالميتة (موجودة على الديسك)
إنشاء طلبrequest-wizard-v2request-wizard v1 (1,394 سطر) — ميتة
لوحة المعالجةdept-worklistkanban (1,490 سطر) — redirect — ميتة
إدخال النتائجdept-worklist + validation-worklistresults/lis-results (1,803 سطر) — redirect — ميتة
جمع العيّناتcollection-worklistsamples/lis-samples (1,244 سطر) — ميتة
استلام العيّنةreceptionspecimen-receiving (644 سطر) — ميتة
كمان فيه 3 لوحات "نظرة عامة" (dashboard / board / worklist) المستخدم لازم يتعلّمهم، و3 شاشات أجهزة بتبان مكرّرة (وهي فعلاً 3 طبقات صح: قالب جهاز ← نسخة ← ربط تحاليل).

٢. نظام التصميم والاتساق

٣. تجربة الـ workflow الأساسي (استقبال ← عيّنة ← نتيجة ← تحقّق ← نشر)

المرحلةالتقييمالتفاصيل
الاستقبال (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 = إرهاق نوافذ؛ والمشرف يقدر يعدّل القيم بصمت بدون خطوة تصحيح صريحة.
الخلاصة: إدخال النتائج والتحقّق ممتازين (keyboard + inline)، الاستقبال جيد (barcode + صوت)، إنشاء الطلب هو الحلقة الضعيفة (ماوس بس + كليك لكل تحليل).

٤. جودة الكود (Frontend)

٥. اقتراحات التحسين (مرتّبة بالأولوية) 💡

أولويةالتحسين
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" واحدة.
🏛️

١ — المعمارية والمجال

66 model في 13 نطاق فرعي، workflow مدفوع بالأحداث، تكامل أجهزة قوي — بس فيه god classes.

السلسلة الأساسية (event-driven)

استقبال/زيارة ← LabRequestLabSample ← استلام (بيولّد LabResult) ← إدخال (يدوي أو من الجهاز) ← تحقّق/auto-verify ← اعتماد ← نشر (بوابة/PDF + قيود B2B). كل انتقال بيكتب audit log غير قابل للتعديل.

تكامل الأجهزة (قوة حقيقية): middleware بايثون (ASTM serial/TCP + HL7/MLLP) مع طبقة drivers قابلة للتوسّع لكل جهاز، outbox SQLite (store-and-forward) يفصل التقاط الجهاز عن توفّر السحابة، واستعلام مضيف ثنائي الاتجاه. ونتائج الأجهزة بتمرّ على نفس pipeline الأمان بتاع الإدخال اليدوي.

الضعف المعماري

الملفالحجمالمشكلة
WorklistContextService.php2,110 سطرأسوأ god class — بيخلط التجميع والـ rollup وتنسيق العرض
ExternalLabPortalRequestController.php1,395 سطرstore() بيكرّر منطق CreateLabRequest كله inline بدل ما يستخدمه
LabResultController.php1,077 سطرretract/correct فيهم transactions تكرّر LabResultService

كمان: تتبّع حالة ثلاثي (RequestInvestigation / SampleInvestigation / Result) بيخلّق معظم تعقيد مزامنة الـ workflow؛ والـ Jobs شبه مش مستخدمة (شغل تقيل زي الـ PDF والنشر متعدد القنوات بيشتغل synchronous).

🩺

٢ — سلامة المريض وسلامة البيانات

العيوب الأخطر — لإنها بتأثر على نتائج المرضى مباشرة.
CRITICAL auto-verify مبيحرسش المسار البشري — وممكن ينشر نتيجة حرجة تلقائياً
LabResultService::validate/approve (156-216) · LabMachineResultController.php:268 · AutoVerificationService.php:18-27

التحقّق/الاعتماد البشري مبيستدعيش verify() — يعني delta/critical/range checks موصولة بس في مسار الجهاز. وفي مسار الجهاز، verify() بيرجّع passed:true للقواعد الفاضية وisCritical() متحسوبة بس مبتتفحصش قبل الاعتماد التلقائي → قيمة حرجة (panic) ممكن تتنشر بدون مراجعة بشرية.

CRITICAL ربط عيّنة عبر شركات (cross-tenant) في استقبال نتائج الأجهزة
LabMachineResultController.php:181

LabSample::where('barcode')->first() بدون فلتر company_id → نتيجة جهاز ممكن تتكتب في ملف مريض شركة تانية، والتنبيه الحرج يضرب على السجل الغلط.

CRITICAL نطاق مرجعي غلط لما تاريخ ميلاد المريض null
LabResultService.php:810-828

فلتر النوع متعشّش جوه if ($patient && $patient->date_of_birth) — فلو DOB ناقص، النطاق الخاص بالنوع بيتختار عشوائياً بـ first() → flags غلط (H/L) على تحاليل زي الهيموجلوبين.

#المشكلةالمكانالخطورة
انتقالات حالة النتيجة بدون قفل (check-then-act) → نتيجة تتعتمد/تتنشر مرتينLabResultService.php:52-282CRIT
ACK يتبعت قبل حفظ النتيجة (ASTM) → نتيجة تضيع نهائياً عند crashastm_tcp_server.py:219CRIT
مفيش idempotency → ابتلاع مكرّر (تنبيهات/كاشف مكرّر، قيمة قديمة تدوس مصحّحة)LabMachineResultController.php:164CRIT
Hحدود < vs <= غير متسقة → قيمة على عتبة الـ panic بالظبط مبترفعش تنبيهLabResultService.php:699HIGH
Hتنبيه حرج بيتبعت بس عند enter الفردي — مش في bulk ولا بعد التصحيحLabResultController.php:391HIGH
Hأرقام بفاصلة عشرية (locale) بتتجاوز كشف الحرج وتتخزّن كنصastm_base.py:70HIGH
Hكود جهاز واحد ← عدة تحاليل: بيكتب نفس القيمة لكلهم (GLU → FBS و PPBS)LabMachineResultController.php:207HIGH
Hوحدة الجهاز بتتنسخ بدون تحقّق/تحويل (mg/dL مقابل mmol/L ~18×)LabMachineResultController.php:222HIGH
Hسجل الحضانة (custody) مبيتكتبش في دورة العيّنة الداخلية → فشل CAP/ISO 15189LabSampleService.phpHIGH
C$سباق دفع زائد على مدفوعات المرضى (بدون قفل/transaction)LabPaymentController.php:178CRIT
C$تصادم amount_paid بين B2B والمريض → يمسح تخصيصات B2BPostLabPayment.php:65CRIT
أكبر فجوة تستات: مفيش ملف تست لـ AutoVerificationService خالص — صفر تغطية لـ critical/range/delta. ومفيش تستات للحدود على عتبة الـ panic، ولا لمسار ابتلاع الأجهزة، ولا للدفع المتزامن. (ملاحظة إيجابية: SequenceService وLabReagentService::consumeFifo وSampleInvestigationService::moveTo بيستخدموا القفل الصح — العيوب بتتجمّع فين ما النتائج/الفلوس مابتعيدش استخدام النمط الموجود).
🔐

٣ — الأمان (PHI) والامتثال

أعلى سطح خطورة = بوابة المرضى العامة. بيانات صحية = الخطورة مرفوعة.
CRITICAL C1 — بوابة المريض العامة: تخمين MRN + تاريخ ميلاد بدون rate limiting
PatientPortalController.php:29-44 · routes/portal.php:8 · bootstrap/app.php:45-61

مسارات البوابة مسجّلة بـ ['api'] بس، ومفيش throttle. الدخول بـ mrn + date_of_birth بس (معرّفين منخفضي الإنتروبيا). مهاجم بيعدّ الـ MRN ويخمّن تاريخ الميلاد ويحصل على توكن دائم لأي مريض → تسريب PHI كامل (نتائج، تشخيصات سرطان ICD-O، فواتير، مرفقات).

CRITICAL C4 — كتابة عبر-شركات (IDOR) على عمليات النتائج الـ bulk
LabResultController.php:919 (bulkEnter), :954, :995, :1034 (bulkRelease), :834

كل واحدة بتلفّ 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:74CRIT
C3توكن رابط دائم (single-factor) مبيتدوّرش، ومكشوف في QR/واتساب وفي الـ staff APIPatientPortalController.php:53CRIT
C5النتائج المنشورة ممكن تتعدّل في مكانها وسجل النشر الأصلي يتكتب فوقه (مفيش توقيع)LabResultController.php:663CRIT
C6سياسة الاحتفاظ مش مفروضة + hard-delete بيمسح سجل التدقيق نفسهLabRequestController.php:555CRIT
H1عمليات النتائج الـ bulk مبتكتبش audit log (التدقيق معتمد على المطوّر مش مفروض مركزياً)LabResultController.php:911HIGH
H4كنترولر الهستوباثولوجي بدون permission middleware — أي مستخدم يعتمد تشخيص سرطانLabNewTypesController.phpHIGH
H2mass-assignment لـ company_id/توكنات البوابة على LabPatientLabPatient.php:25-55HIGH
إيجابي: مفيش SQL injection (كل الـ raw queries بـ literals/bound params). وكل الـ controllers الأساسية بتعمل company-scoping يدوي + صلاحيات granular. المشكلة المنهجية: مفيش Global Tenant Scope — العزل 100% يدوي، فأي نسيان = تسريب. التوصية: CompanyScope عام.

٤ — الأداء

نظام عالي الإنتاجية — المشاكل بتظهر مع آلاف الطلبات/النتائج يومياً.
CRITICAL ابتلاع نتائج الأجهزة synchronous — POST لكل بارامتر
LabMachineResultController.php:149-317 · cloud.py:118-134 · server.py:129

كل البايبلاين (mapping + flag + events + audit + auto-verify) بيشتغل synchronous على thread الـ request، نتيجة واحدة لكل HTTP call. أنبوبة CBC (~25 بارامتر) = 25 POST + 25 بايبلاين كامل، وكل POST بـ TCP+TLS جديد (بدون keep-alive)، ورافع واحد single-threaded. ده سقف الإنتاجية تحت ضغط الأجهزة.

CRITICAL فهرس lab_results.sample_id ناقص — أخطر فجوة فهرسة
migration 2026_03_02_100001:17

الـ FK sample_id مش متفهرس → كل تحميل إدخال نتيجة / مطابقة جهاز بالعيّنة = full scan. أكبر ضرر منفرد.

المشكلةالمكانالخطورة
worklist الاستقبال ->get() غير محدود + whereDate() بيعطّل الفهرس + N+1 في الـ ResourceReceptionWorklistService.php:31, LabSampleResource.php:104CRIT
التقارير بدون حد أقصى لمدى التاريخ → from=2015 بيسكان كل التاريخ (DoS)، وبدون أي cachingLISReportController.php:45CRIT
Frontend: 0 من 14 شاشة ثقيلة بتستخدم OnPush؛ kanban/dashboard بـ polling + ساعة كل ثانية + آلاف كروت بدون virtualization؛ listAll() بيحمّل كل الجدول للمتصفحlis-kanban:270, requests:378CRIT
جداول نمو غير محدود بدون أرشفة: communication logs، publish logs، audit logsmigrationsHIGH
أعلى 5 إصلاحات: (1) انقل ابتلاع النتائج لـ queue + endpoint batch. (2) ضيف فهرس lab_results.sample_id (+ المركّبات). (3) حُد مدى التقارير + caching. (4) صلّح N+1 في الـ Resources وحُدّ الاستقبال/kanban. (5) Frontend: OnPush + server pagination + شيل ساعة الثانية.
🧩

٥ — الاكتمال والنواقص

تغطية وظيفية واسعة — النواقص في ميزات تخصصية واعتماد، مش stubs.

مبني بصلابة — متعملش فيه

Westgard QC auto-verification framework audit trail (قيمة/حالة/IP/UA) معامل خارجية B2B كاملة كواشف/lots تأمين وفوترة عمولات أطباء كاشير/خزينة middleware الأجهزة تقارير/طباعة رفض عيّنات + custody

ناقص / جزئي

🗺️

٦ — خطة العمل (بالأولوية)

الموجةالشغلليه دلوقتي
٠ — منع فقدان بياناتصالح كود الـ FRONTEND-PATCH مع الـ migrations الرسمية قبل أي deployخطر مسح schema حيوي بـ git reset
١ — سلامة المريضاستدعِ verify() ببوابة حرجة في المسار البشري، قفل انتقالات النتيجة، scope ابتلاع الجهاز بالشركة + idempotency + تطبيع الأرقام/الوحداتمخاطر إكلينيكية مباشرة على المرضى
٢ — أمان PHIthrottle + 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متطلبات اعتماد ووظائف معمل ناقصة
الخلاصة: أقوى موديول عندك من ناحية البناء (تكامل أجهزة + QC ممتازين) — بس فيه 3 مخاطر حرجة (فقدان بيانات، سلامة نتائج، PHI) لازم الأولوية المطلقة. الـ UI متين في إدخال النتائج، وأكبر مكسب فيه = حذف الميت + keyboard للـ wizard + design system.
تقرير تدقيق موديول المعمل (LIS) — Moon ERP · 6 محاور (UI/UX · معمارية · سلامة · أمان · أداء · اكتمال) · أدلة من الكود · 2026-06-15