دراسة متعمّقة للوضع الحالي + المشاكل + اقتراحات التظبيط + البيانات الناقصة + الإعدادات الجديدة المقترحة
Moon ERP · وحدة LIS · على نطاق: الميدل وير (Python) + شاشة الأجهزة + الكاتلوج + إعداد الجهاز
المنظومة مبنية بالكامل ومتكاملة من حيث الهيكل — الميدل وير بيستقبل من الأجهزة وبيرفع للكلاود، الكلاود مصدر الحقيقة للأجهزة، والكاتلوج + شاشة الربط موجودين. لكن فيه فجوات جوهرية بتمنع التشغيل الإنتاجي الموثوق، وأهمها متكررة عبر أكتر من طبقة:
TSH II ✅ بس FT4 III ❌). الحل: نلتقط الأكواد الحقيقية من نتايج الجهاز أو من شاشة الـassays.التقرير بيقسّم المشاكل حسب الخطورة: CRITICAL HIGH MEDIUM LOW · RESOLVED — وبيدّي لكل بيان ناقص طريقة عملية للإضافة.
كل ده اتعمل واتنشر (الميدل وير على الويندوز + الكلاود لايف + الـFE على /app/).
| # | المشكلة | الإصلاح | المكان |
|---|---|---|---|
| 1 | صف الجهاز يظهر «متوقف» رغم إنه شغّال | مفتاح port → listen_port في الـstats عشان يطابق مفتاح شاشة الـadmin | astm_tcp_server.py |
| 2 | الميدل وير بيسمح بإضافة/تعديل أجهزة يدوي (يخالف الكلاود) | شاشة admin بقت قراءة فقط — الأجهزة من الكلاود بس + توجل تشغيل لكل محطة | admin.py |
| 3 | الاستعلام يرجّع تحليل واحد بس (شكل الرد) | كل التحاليل كـrepeats في O record واحد + كل record في فريم STX..ETX منفصل | astm_base.py · astm_tcp_server.py |
| 4 | راك متعدد العينات: عينات بالتبادل بتضيع | حلقة الاستقبال بقت تتجاهل بايتات ACK/NAK اللي كانت بتتزرع جوّه الرسالة وتبوّظ الباركود (زي maglumi.py) | astm_tcp_server.py |
| 5 | الاستعلام يرجّع أكواد قديمة/محذوفة (FERR/FT4/FT3) | إضافة whereNull('deleted_at') + unique() — الـraw query كان بيتجاهل الـsoft-delete | LabMachineController::orders() |
| 6 | إنشاء mapping يفشل بـduplicate (صف محذوف ماخد المكان) | الحفظ بقى يرجّع الصف المحذوف ويحدّثه بدل insert جديد | LabMachineTestMappingController::store() |
| 7 | شاشة machine-setup فيها 3 أماكن مكرّرة للربط | دمج في جدول واحد (كاتلوج + يدوي) + صف إضافة واحد — اتشال الجدول المكرّر | machine-setup (FE) |
| 8 | بحث التحاليل بيحمّل الآلاف client-side | server-side search (debounce + 50 نتيجة) مع تثبيت المربوط | machine-setup (FE) |
Q|1|^<barcode>||ALL — عينة واحدة لكل رسالة، بس بيرسل راك كامل كـرسائل متتالية سريعة على نفس الاتصال. (لازم نتجاهل بايتات ACK بينهم — إصلاح #4.)TSH II/FT3 II/Vit B12 III اشتغلوا، FT4 III اترفض. المرجع الأدق = الكود اللي الجهاز بيبعته في النتيجة.orders() بيرجّع تقاطع (تحاليل الطلب ∩ المربوط للجهاز) بالـinvestigation_id — فلو التحليل مش مربوط، أو مربوط على نسخة مكرّرة مختلفة، ميرجعش.00039952) في النتيجة مش باركود النظام → لسه محتاج طبقة ترجمة عشان النتايج تتطابق.machine-results → نظبط كل الـmappings بالحرف. وبعدها multi-mapping للتحاليل المكرّرة.| الطبقة | المكوّن | الحالة |
|---|---|---|
| الميدل وير | lis-middleware/ (app, cloud, buffer, drivers, *_server, admin) | يعمل بنقاط ضعف في الموثوقية والأمان |
| شاشة الأجهزة | features/lis/machines + LabMachineController | يعمل · orders() اتصلّح (soft-delete) · كود ميت + بيانات وهمية باقية |
| الكاتلوج | device-catalog + LabDeviceModel | مبني لكن فارغ (مفيش seeder) |
| إعداد الجهاز | machine-setup + machine-test-mappings | اتحسّن · جدول موحّد + server search + إصلاح الـduplicate · باقي: multi-mapping |
run.py → يبدأ admin UI أولاً، ثم _start_devices() (listener لكل جهاز)، ثم login + sync_from_cloud()، ثم thread للرفع وthread للـheartbeat.{barcode, results[]} → يتسجّل في الـoutbox صف لكل قيمة + صف audit للرسالة الخام.Q record → _orders_for → GET /lis/machines/{id}/orders?barcode= → يرجّع الأكواد. الاستعلام مبني لـASTM فقط — مسار HL7 بيسجّل الاستعلام بس مبيردّش بطلب.sync_from_cloud يبني قائمة الأجهزة من GET /lis/machines؛ المحلي الوحيد = enabled.| الخطورة | المشكلة | التفصيل والإصلاح المقترح |
|---|---|---|
| CRITICAL | لا توجد مراقبة للعملية (process supervision) | مفيش Windows Service / watchdog / auto-restart / تشغيل عند الإقلاع. لو العملية ماتت، النتايج بتقف بصمت. الحل: سكربت تثبيت NSSM أو Task Scheduler مع «إعادة تشغيل عند الفشل + تشغيل عند الإقلاع» داخل الريبو. |
| CRITICAL | عدم مطابقة رقم العينة ↔ الباركود | الجهاز يبعت رقمه الداخلي مش باركود النظام. الحل: endpoint بحث عكسي في الكلاود GET /lis/machines/{id}/resolve-sample?analyzer_no= + استراتيجية محلية sample_number_map في connection_settings. |
| CRITICAL | الأسرار في config.json بنص واضح | التوكن/الإيميل/الباسوورد غير مشفّرين، وGET /api/config بيرجّعهم حرفياً. الحل: إخفاء الأسرار في الردود (****) + تفضيل توكن خدمة على تخزين باسوورد + DPAPI على ويندوز. |
| HIGH | شاشة admin بدون مصادقة افتراضياً | admin_password فاضي = مفتوح للكل. خطير لو الـhost اتغيّر لـ0.0.0.0. الحل: إلزام باسوورد لما الـhost ≠ 127.0.0.1. |
| HIGH | صفوف الرفع 4xx لا تُحل أبداً (poison rows) | 422/404 بتفضل pending وتتعاد كل 20 ثانية للأبد وتضخّم عدّاد الانتظار. الحل: تصنيف الأخطاء — 401/403→re-auth، 422/404→dead-letter يظهر للمشغّل، 5xx/شبكة→إعادة. |
| HIGH | فشل الـheartbeat غير مرئي | log.debug فقط — الجهاز بيقع offline في الكلاود من غير أي إشارة. الحل: log.warning + تتبّع last_heartbeat_at/last_heartbeat_error في status(). |
| HIGH | التوكن لا يُحفظ ويُعاد تسجيل الدخول عند كل reload | كل save/sync بيعمل CloudClient جديد ويرمي التوكن → login متكرر. الحل: تمرير التوكن عبر reload. |
| HIGH | إطار ASTM (framing) فضفاض وغير متطابق بين النقلين | الـTCP يتجاهل FN/checksum (يصلح لـMaglumi بس)، والـSerial صارم — سلوك مختلف لنفس الدرايفر. الحل: flag لكل جهاز astm_strict_framing. |
| MEDIUM | وقت/توقيت ساذج + إهمال توقيت الجهاز | الـoutbox يختم بالتوقيت المحلي بدون tz، وطابع وقت نتيجة الجهاز (ASTM R-13) يُحلّل ثم يُرمى. الحل: تمرير result_at + ختم UTC ISO-8601. |
| MEDIUM | استعلام أوفلاين يرجّع «لا طلبات» | لو الكلاود بطيء/مقطوع، الاستعلام يردّ «مفيش تحاليل» — أسوأ من الفشل (الأنبوبة ممكن تتخطّى). الحل: إعداد order_offline_behavior. |
| MEDIUM | اتصال SQLite واحد + DELETE عند الإرسال | مفيش أرشيف محلي دائم لما اترفع. الحل: جدول sent أو status='sent' مع تقليم دوري. |
| LOW | تسريب PHI في اللوج / كود ميت | mllp.feed يسجّل كل chunk خام (HL7 مريض) على INFO؛ KNOWN_DRIVERS قديمة؛ work_orders() dead code؛ سطور replace("\r","\r") وغيره. |
is_online (آخر اتصال خلال 5 دقايق) — بدون polling، بيتحدّث بس مع تحميل الصفحة.| الخطورة | المشكلة | التفصيل |
|---|---|---|
| CRITICAL | total_results_today بيانات ميتة | موجود في الموديل/الـResource/الـstatus لكن لا يُزاد ولا يُصفّر أبداً — دايماً 0. إمّا نوصّله (زيادة عند الـstore + reset يومي) أو نشيله. |
| CRITICAL | تضارب 5 دقايق مقابل 30 دقيقة | is_online = 5 دقايق، بينما status() يثبّت Offline بعد 30 دقيقة. وبما إن الـFE لا يستدعي /status أصلاً، فإن connection_status المخزّن «يُكتب Online فقط» ولا يرجع Offline أبداً. |
| CRITICAL | connection_status = Error لا يُضبط أبداً | القيمة موجودة في الـEnum لكن مفيش endpoint بيضبطها. جهاز في حالة خطأ فعلي بيفضل أخضر/Online طول ما الـheartbeat واصل. |
| HIGH | تبويبة النتايج تعرض قيم فاضية | الـHTML يربط raw_value/processed_value بينما الـResource يرجّع raw_result/parsed_result → كل خلية تعرض «-». |
| HIGH | لا يوجد إظهار للأخطاء/الصحة في القائمة | عمود الاتصال ثنائي بس (online/offline). مفيش «آخر خطأ» ولا عدّاد أخطاء ولا badge. |
| HIGH | لا يوجد «اختبار اتصال» من الكلاود | مفيش endpoint/زر يفحص الجهاز فعلياً — المشغّل بس بيستنى heartbeat. |
| HIGH | لا يوجد scoping للفروع | index مفلتر بالشركة فقط بدون branch_id — مستخدم الـspoke بيشوف أجهزة كل الفروع. |
| HIGH | endpoints الإدخال بدون صلاحيات | heartbeat, storeCommunicationLog, orders, agentConfig, work-orders, وmachine-results store بدون permission middleware — أي توكن يقدر يضخ نتايج/heartbeat. |
| MEDIUM | نموذجان متنافسان (~500 سطر ميت) | النموذج اليدوي القديم (Basic/Connection/Dates/Cost) غير قابل للوصول لكنه باقٍ — خطر صيانة + يكتب مفاتيح connection_settings مختلفة. |
| MEDIUM | الربط (mappings) لا يُدار من هنا | الشاشة لا تستورد LisMachineTestMappingService إطلاقاً؛ لو مفيش mapping كل النتايج تفضل pending للأبد — ومفيش UI هنا لإنشائها. |
| MEDIUM | status() يعدّل داخل GET | side-effect على قراءة + N استعلامات بدل bulk update. |
| MEDIUM | تضارب enum للتكلفة | الـFE: per_test/hourly/depreciation بينما الـBE: per_test/time_based — كسر عقد كامن. |
lab_device_models (name, manufacturer, driver, protocols[], barcode_fields[]) + lab_device_model_tests (analyzer_code, test_name, unit, default_ranges).instantiate() = المسار الجوهري: ينسخ الدرايفر + barcode_fields لـconnection_settings، وينسخ كل تحليل لـmachine_test_mappings بمطابقة آلية (كود ثم اسم)، وينسخ الـranges على الـinvestigation.| الخطورة | المشكلة | التفصيل |
|---|---|---|
| CRITICAL | لا يوجد كاتلوج مزروع (seeder) | مفيش أي seeder بيملأ lab_device_models — كل معمل بيبدأ بكاتلوج فاضي ولازم يدخّل كل جهاز/كود/وحدة/رينج بإيده. ده بيلغي فكرة «اضبط مرة واحدة». |
| CRITICAL | قائمة الدرايفرات hardcoded في الـFE | الدرايفرات الصالحة في component واحد (4 عناصر)، والاشتقاق driverFromProtocol هش (name.includes('mispa')?...:maglumi_astm). إضافة جهاز خامس بيشتق غلط بصمت. الـBE: عمود driver نص حر بدون enum/registry. |
| HIGH | protocols/transports مش data-driven بشكل نظيف | الـtransport مدسوس جوّه نفس مصفوفة protocols (مثال ["astm","serial","tcp"]) ويُفصل بـstring-filter في 3 أماكن. مفيش عمود transports. |
| HIGH | خريطة code→investigation ليست على مستوى الكاتلوج | الربط الفعلي يُنشأ لكل جهاز بمطابقة fuzzy وقت الإنشاء — كل نسخة جهاز تطابق بشكل مستقل وهش، وبدون LOINC. |
| HIGH | ازدواج بين الكاتلوج وconnection_settings | barcode_fields/driver منسوخين snapshot — تعديل الكاتلوج لا ينتشر للأجهزة الموجودة. value_types/send_ack غير موجودين في الكاتلوج أصلاً. |
| HIGH | الـranges تُنسخ snapshot بدون حماية | copyRanges يـinsert بدون dedup — إنشاء جهازين من نفس الموديل يكرّر الـranges على نفس الـinvestigation. |
| MEDIUM | تغطية الأجهزة الحقيقية ≈ صفر | 3 درايفرات بس متصوّرة (Dymind/Maglumi/Mispa) + JSON. مفيش Sysmex/Mindray/Cobas/Architect/Beckman/Erba/Horiba. |
| MEDIUM | نقص LOINC/الوحدات/الدقة على صفوف الكاتلوج | lab_device_model_tests مفيهاش loinc_code/decimal_places/result_type — الكاتلوج متأخّر عن باقي الـLIS. |
device_model_id → يجيب أكواد الكاتلوج ويربط كل كود بـmachine_test_mapping فتختار الـinvestigation لكل كود.barcode (مش sample_number) + machine_test_code بالظبط. لو الاتنين اتلاقوا → Matched → (اختياري) auto-apply + auto-verify.orders() + workOrders() يقرأوا نفس جدول الـmappings → الاتجاهان متّسقان على machine_test_code.| الخطورة | المشكلة | التفصيل |
|---|---|---|
| CRITICAL | الباقات (Panels) لا تتوسّع | الربط صارم investigation_id → كود واحد. باقة CBC = investigation واحد = كود واحد، فالـ13 محلّل الباقيين ملهمش هدف ربط ونتايجهم تتجاهل بصمت. أكبر فجوة وظيفية. |
| CRITICAL | الكود غير المعروف = إسقاط صامت | لو مفيش mapping، الصف يتسجّل Pending ومفيش أي حاجة تانية — لا خطأ ولا تنبيه ولا تمييز عن «مستني مطابقة يدوية». كود مكتوب غلط بيختفي. |
| CRITICAL | عدم معالجة رقم العينة مقابل الباركود | المطابقة متربطة بـbarcode فقط؛ كتير من الأجهزة بترجّع رقم العينة/الـaccession. لو اختلفوا → إسقاط صامت. مفيش fallback ولا إعداد لاختيار حقل الهوية. |
| HIGH | لا يوجد تحويل وحدات | يخزّن وحدة الجهاز كما هي. لو الجهاز mg/dL والرينج mmol/L → flags خاطئة سريرياً. عمود unit وصفي بس. |
| HIGH | لا توجد معالجة لنوع القيمة | كل حاجة تُخزّن string ويتفرّع بس على is_numeric. النتايج المرمّزة (POS، <0.01، تيتر 1:160) والنصية تُخزّن حرفياً بدون تطبيع، وresult_type للـinvestigation لا يُستشار. |
| HIGH | flags الجهاز تُهمل | flag الجهاز (HL7 OBX-8) لا يُلتقط؛ النظام يعيد الحساب بنفسه — مفيش سجل لاختلاف الجهاز/النظام (إشارة QC مفيدة). |
| HIGH | ازدواج الربط لكل جهاز | الربط UNIQUE(machine_id, investigation_id) — معمل بـ3 أجهزة Maglumi لازم يربط نفس الأكواد 3 مرات. مفيش «طبّق ربط الكاتلوج على كل النسخ». |
| HIGH | محرّر الـranges يعدّل رينج الـinvestigation المشترك | «ranges الجهاز» فعلياً بتعدّل الرينج العام لكل الأجهزة. NormalRange.machine_id + حقول valid/reportable موجودة لكن مسار الحفظ يتجاهلها. |
| MEDIUM | لا يوجد استيراد جماعي / re-map = delete+create / لا toggle لـis_active | الأكواد تُضاف صف-صف؛ إعادة الربط حذف+إنشاء غير ذرّي؛ ومفيش طريقة تعطيل mapping بدون حذفه. |
| الطبقة | العنصر | السبب |
|---|---|---|
| الميدل وير | تسجيل MLLP لكل chunk على INFO | تشخيصي + يسرّب PHI + ضوضاء — يتشال أو يتنقل لـDEBUG. |
| الميدل وير | سجلّات comm_log لكل رسالة | مفيدة وقت أول تكامل بس بتضاعف الترافيك والتخزين بعدين — تبقى opt-in لكل جهاز (archive_raw:false). |
| الميدل وير | KNOWN_DRIVERS، work_orders()، سطور serial cs/port، replace("\r","\r")، relay/forward | كود ميت/قديم أو ميزة relay غير مستخدمة بتكلّف تعقيد في معالج HL7. |
| الميدل وير | parsed_result يكرّر raw_result | زائد لحد ما يبقى فيه تحويل فعلي. |
| شاشة الأجهزة | total_results_today (دايماً 0) + calculated_hourly_cost + نموذج التكلفة الكامل (7 حقول) | تُرسَل في كل صف بدون UI يستهلكها (النموذج اليدوي ميت). |
| شاشة الأجهزة | أعمدة model/manufacturer/serial | تُعرض لكن المسار الفعّال لا يسمح بضبطها — أغلب الصفوف «-». |
| شاشة الأجهزة | مفاتيح connection_settings القديمة (timeout_seconds، hl7_version، encoding، folder_path...) + raw_value/processed_value | لا يُنتجها المسار الفعّال؛ raw_value/processed_value هي سبب باگ الأعمدة الفاضية. |
| الكاتلوج | driverInfo reference card + عمود model + ازدواج host/listen_host + port/listen_port + category نص حر | وصف عربي ضخم hardcoded + حقول مكرّرة/قليلة القيمة. |
| الربط | machine_test_name + sort_order (مخزّن وغير مستخدم) | تجميلي/معطّل — يُشتق عند القراءة. |
| الناقص | ليه مهم | طريقة الإضافة العملية |
|---|---|---|
| توسيع الباقات (Panel members) | الباقات بتسقط نتايجها | عمود panel_member_investigation_id (nullable) على الـmapping — كل كود محلّل يربط بعضو الباقة. orders()/workOrders() يوسّعوا الباقة لأكواد أعضائها، وstore() يحلّ كود العضو لنتيجة العضو. |
| ترجمة رقم الجهاز ↔ باركود النظام | كل النتايج pending | endpoint كلاود resolve-sample?analyzer_no= (الكلاود عنده الرقمين وقت إرسال الـworklist) + عمود match_identifier (barcode/sample_number/accession) لكل جهاز. |
| عامل تحويل + وحدة الجهاز | flags خاطئة سريرياً | أعمدة analyzer_unit + conversion_factor (default 1) + conversion_offset (default 0) على الـmapping. عند الإدخال: system_value = raw*factor+offset قبل حساب الـflag. |
| نوع القيمة + خريطة الترميز | النتايج المرمّزة/النصية | value_type (NM/ST/SN/CE) + coded_map JSON لكل mapping؛ واستشارة investigation.result_type في store(). |
| سلوك الكود غير المربوط | إسقاط صامت | unmapped_action (queue/drop/alert) لكل جهاز + عمود match_failure_reason على نتايج الجهاز للتمييز (no-sample / no-mapping / ambiguous). |
| الناقص | المكان | الإضافة |
|---|---|---|
| بورت TCP افتراضي | lab_device_models.default_port | migration + seeder + استخدامه كـlisten_port افتراضي في instantiate. |
| إعدادات serial افتراضية | serial_defaults JSON | migration + seeder + spread في بلوك السيريال بدل 9600/8/1/none الـhardcoded. |
| أعلام الإطار (framing) | framing JSON (send_ack، checksum، mllp) | migration + seeder + نسخ لـconnection_settings. |
| regex لرقم العينة/الباركود | sample_number_regex | migration + seeder + سطح في connection_settings للتطبيع/التحقق. |
| أنواع القيم المدعومة | value_types JSON | migration + seeder + نسخ في instantiate (حالياً fallback في agent-config بس). |
| LOINC + دقة + نوع نتيجة لكل تحليل | lab_device_model_tests.loinc_code/decimal_places/result_type/coded_map | migration + seeder + استخدام LOINC كمفتاح مطابقة أساسي في instantiate (LOINC ثم code ثم name). |
| endpoint إعادة المزامنة | POST device-models/{id}/resync-machines | يدفع تعديلات الكاتلوج لـconnection_settings للأجهزة الموجودة (يقفل فجوة الـsnapshot drift). |
| الناقص | المكان | الإضافة |
|---|---|---|
last_error / last_error_at | أعمدة على lab_machines | تُضبط في heartbeat/storeCommunicationLog لما status==='error' — تظهر الخطأ في القائمة من غير فتح لوج. |
expected_workstation | عمود | مقارنة بالـworkstation الحيّة لتنبيه «يعمل على محطة غير متوقعة». |
إصلاح total_results_today | منطق | زيادة في store() + أمر مجدول يومي للتصفير. |
| ranges خاصة بالجهاز | NormalRange.machine_id + valid/reportable (موجودة) | توصيل machine_id في محرّر الـranges + تفضيل الرينج الخاص بالجهاز في حساب الـflag. |
| UI لإدارة الربط داخل الشاشة | FE (الخدمة موجودة) | تبويبة/dialog «Test mapping» تستخدم LisMachineTestMappingService — بدون schema جديد. |
LIS → Machines.connection_settingsتخصّ الجهاز نفسه فتتبعه لو اتنقل لمحطة تانية.
| المفتاح | النوع | افتراضي | يتحكّم في |
|---|---|---|---|
match_identifier | enum: barcode/sample_number/accession | barcode | أي هوية عينة يرجّعها الجهاز (يحل مشكلة عدم المطابقة). |
sample_number_map | enum: none/lis_barcode/strip_leading_zeros/regex | none | استراتيجية ترجمة رقم الجهاز للباركود. |
sample_number_regex | string | "" | عند regex — مجموعة الالتقاط → الباركود. |
unmapped_action | enum: queue/drop/alert | queue | التصرّف مع كود بدون mapping. |
expand_panels | bool | true | توسيع الباقات لأكواد أعضائها في الاستعلام. |
astm_strict_framing | bool | false (TCP) / true (Serial) | إطار ASTM صارم مقابل المتسامح. |
auto_verify / auto_apply | bool | وراثة العام | تجاوز لكل جهاز — جهاز موثوق يتحقّق آلياً، وجهاز مشكوك لأ. |
trust_analyzer_flag | bool | false | استخدام flag الجهاز (OBX-8) لما النظام مفيهوش رينج. |
archive_raw | bool | false | إرسال سجلّات الرسائل الخام (تحكّم في الضوضاء). |
host_query_enabled | bool | true | هل يردّ على استعلامات الطلب. |
ack_timeout_seconds | number | 5 | مهلة انتظار ACK في ASTM. |
decimal_places | int | null | تقريب قيمة الجهاز لـN منازل. |
poll_interval / heartbeat_grace_minutes | int (sec/min) | 60 / 5 | تردّد الـpolling + عتبة اعتبار الجهاز offline. |
سياسات على مستوى المعمل كله.
| المفتاح | النوع | افتراضي | يتحكّم في |
|---|---|---|---|
lis.auto_apply_machine_results | bool | false | موجود في الكود بس مش مزروع ولا في أي UI — كتابة قيم الجهاز المطابقة على LabResult آلياً. |
lis.auto_verify_machine_results | bool | false | موجود في الكود بس مش مزروع/UI — ترقية القيم الناجحة لـvalidated آلياً. |
lis.machine_offline_threshold_minutes | int | 5 | مصدر وحيد لعتبة online/offline (يقتل تضارب 5 مقابل 30). |
lis.machine_unmapped_default_action | string | queue | fallback لـunmapped_action لما الجهاز مالوش. |
lis.machine_match_identifier_default | string | barcode | fallback لاستراتيجية الهوية. |
lis.machine_alert_on_unmapped | bool | true | تنبيه لما نتيجة متقدرش تتربط (يقفل ثقب الإسقاط الصامت). |
lis.machine_require_full_mapping | bool | false | منع تفعيل جهاز أكواده مش كلها مربوطة. |
lis.machine_critical_block_autoverify | bool | true | عدم التحقّق الآلي أبداً لقيمة حرجة حتى لو نجحت القواعد. |
lis.machine_heartbeat_alert | bool | false | إشعار لما جهاز نشط يقع offline (حالياً مفيش تنبيه). |
lis.middleware_upload_max_attempts | int | 50 | عتبة dead-letter لصفوف الرفع السامة. |
lis.middleware_log_redact_phi | bool | true | إخفاء بيانات المريض الخام من اللوج. |
lis.middleware_require_admin_password | bool | true | إلزام مصادقة شاشة الـadmin عند الربط لغير localhost. |
lis.middleware_order_offline_behavior | enum: no_order/reject/cache_last | reject | الرد على استعلام جهاز لما الكلاود مقطوع (عشان الأنبوبة متتخطّاش). |
جدول مرجعي lab_device_drivers أو map في config('lis.drivers') بشكل {code, label, protocol, default_transport, parser} — يقراه كلٌّ من تحقّق الكاتلوج والـFE dropdown، فالدرايفرات تبقى قابلة للتوسّع بدون تعديل كود، ويموت heuristic الـname.includes('mispa').
machine-results → نظبط كل الـmappings بالحرف (يحل رفض الجهاز لأكواد زي FT4 III).raw_value→raw_result).total_results_today.match_identifier).transports منفصل.