📋 LIS Structural Refactor — Detailed Task List

Reference for Codex review. كل مهمة فيها: file path دقيق، LOC الحالي، اللي يتعمل، شرط القبول (acceptance criteria). الـ surveys بنيت بناء على read فعلي للملفات.

A. ملخص الـ Code Inventory

A.1 Backend (10 controllers + 8 models + 3 services + 1 listener)

الملفLOCالأثر
Http/Controllers/LabSampleController.php562HIGH — defer/recollect/aliquot logic
Http/Controllers/LabRequestController.php1,008MEDIUM — store + index counters
Http/Controllers/LabResultController.php709MEDIUM — retest/correct/retract
Http/Controllers/LabRequestInvestigationController.php188MEDIUM — bulk transitions
Http/Controllers/LabSectionKanbanController.php250MEDIUM — kanban shape
Http/Controllers/LabExternalLabReferralController.php~600MEDIUM — TAT + assigned_to
Http/Controllers/LabMachineResultController.php245LOW — link pivot on match
Http/Controllers/LabRejectionReasonController.php112DONE — no further changes
Services/LabSampleService.php450CRITICAL — collect/deliver/reject/recollect
Services/LabResultService.php~250MEDIUM — retest creates pivot rows
Listeners/GenerateResultsOnSampleReceived.php136CRITICAL — replace section inference
Models/LabSample.php155HIGH — new relation
Models/LabResult.php143MEDIUM — entry_source + machine_id + comments
Models/LabInvestigation.php100+MEDIUM — tat_hours
Models/LabExternalLabPricing.php73MEDIUM — tat_hours
Models/LabExternalLabReferral.php99MEDIUM — assigned_to_user_id
Enums/SampleStatus.php35NONE
Enums/ResultStatus.php14NONE
routes/api.php~400MEDIUM — new bulk endpoint + unpublish

A.2 Frontend (5 screens + 6 services + 5 models)

الملفLOCالأثر
features/lis/collection-worklist/collection-worklist.component.ts1,513HIGH — tubes builder
features/lis/dept-worklist/dept-worklist.component.ts1,260HIGH — actions + per-test status
features/lis/validation-worklist/validation-worklist.component.ts1,892HIGH — bulk ops + history columns
features/lis/kanban/lis-kanban.component.ts1,490MEDIUM — legacy kanban; لو routed يبقى نعدله، لو غير مستخدم نمسحه
features/lis/referrals/lis-referrals.component.ts~700MEDIUM — TAT col + assigned_to
features/lis/requests/lis-requests.component.ts~750LOW — minor: read counts from new field
features/lis/sample-reasons/lis-sample-reasons.component.ts~250DONE
features/lis/samples/lis-samples.component.ts1,243MEDIUM — fallback path (might delete)
features/lis/lis-layout/lis-layout.component.ts~400MEDIUM — nav entry للـ Reception
core/services/lis-sample.service.ts154MEDIUM — bulk action methods
core/services/lis-result.service.ts189MEDIUM — bulk actions
core/services/lis-utils.ts190LOW — eventually remove
core/services/lis-barcode-label.service.ts269LOW — show per-test status badge
core/models/lis-sample.model.ts48HIGH — add investigations[]
core/models/lis-result.model.ts84MEDIUM — entry_source + comments
core/models/lis-investigation.model.ts~70LOW — tat_hours field
core/models/lis-referral.model.ts~60MEDIUM — TAT + assigned_to

B. Schema Changes (Migrations)

B.1 New Tables (2)

Migration M1: create_lab_sample_investigations_table

Schema::create('lab_sample_investigations', function (Blueprint $t) {
    $t->id();
    $t->foreignId('company_id')->constrained()->cascadeOnDelete();
    $t->foreignId('lab_sample_id')->constrained('lab_samples')->cascadeOnDelete();
    $t->foreignId('lab_investigation_id')->constrained('lab_investigations');
    $t->foreignId('lab_request_investigation_id')->nullable()
        ->constrained('lab_request_investigations')->nullOnDelete();
    $t->foreignId('lab_request_id')->constrained('lab_requests');  // denormalized
    $t->string('status', 30)->index();
    //   pending, collected, received, in_progress, result_entered, validated,
    //   released, printed, published, deferred, rejected, cancelled,
    //   outsourced, retracted
    $t->foreignId('lab_external_lab_id')->nullable()
        ->constrained('lab_external_labs')->nullOnDelete();
    $t->timestamp('external_send_at')->nullable();
    $t->timestamp('external_received_at')->nullable();
    $t->foreignId('assigned_to_user_id')->nullable()
        ->constrained('users')->nullOnDelete();
    $t->unsignedSmallInteger('retest_count')->default(0);
    $t->timestamps();
    $t->softDeletes();
    $t->unique(['lab_sample_id', 'lab_investigation_id', 'deleted_at'],
              'lab_sample_inv_unique');
    $t->index(['company_id', 'lab_request_id', 'status']);
    $t->index(['lab_investigation_id', 'status']);
});

Migration M2: create_lab_sample_investigation_logs_table

Schema::create('lab_sample_investigation_logs', function (Blueprint $t) {
    $t->id();
    $t->foreignId('company_id')->constrained();
    $t->foreignId('lab_sample_investigation_id')->nullable()
        ->constrained('lab_sample_investigations')->nullOnDelete();
    $t->foreignId('lab_sample_id')->constrained('lab_samples');
    $t->foreignId('lab_investigation_id')->constrained('lab_investigations');
    $t->string('action', 30);
    //   created, collected, received, started, result_entered, validated,
    //   released, printed, published, deferred, cancelled, outsourced,
    //   rejected, recollected, rerun, retracted, assigned, received_back
    $t->string('from_status', 30)->nullable();
    $t->string('to_status', 30)->nullable();
    $t->string('reason_code', 30)->nullable();
    $t->text('reason_text')->nullable();
    $t->text('result_value_before')->nullable();  // for rerun
    $t->json('meta')->nullable();
    $t->foreignId('user_id')->nullable()->constrained();
    $t->string('ip_address', 45)->nullable();
    $t->string('user_agent', 255)->nullable();
    $t->timestamp('created_at')->useCurrent();
    $t->index(['lab_sample_investigation_id', 'created_at']);
    $t->index(['lab_sample_id', 'created_at']);
    $t->index(['lab_investigation_id', 'created_at']);
});

B.2 ALTER existing tables (5)

الجدولالإضافةMigration name
lab_investigations tat_hours int nullable add_tat_hours_to_lab_investigations
lab_external_lab_pricing tat_hours int nullable add_tat_hours_to_lab_external_lab_pricing
lab_external_lab_referrals assigned_to_user_id FK nullable add_assigned_to_user_id_to_lab_external_lab_referrals
lab_results entry_source enum
printable_comment text
internal_note text
defer_comment text
machine_id FK
raw_data json
add_entry_source_and_comments_to_lab_results
lab_samples (Phase 5) drop is_deferred, deferred_investigation_ids, deferred_reason drop_legacy_deferred_columns_from_lab_samples

B.3 Truncate Plan (Dev only — test data)

الـ catalog tables (lab_investigations, lab_investigation_categories, lab_sections, lab_specimen_types, lab_patients, lab_doctors, lab_external_labs, lab_external_lab_pricing) تفضل كما هي.

الـ tables اللي بنمسحها:

C. Backend Tasks (٢٢ task)

Phase 1: Schema + Models (BE-1 to BE-7)

BE-1NEW · Schema
كتابة الـ migrations الـ ٢ الجديدة (M1, M2) + الـ ٤ ALTERs.
php artisan migrate ينجح بدون warnings؛ الجداول والأعمدة موجودة بالـ شكل الموصوف.
BE-2NEW · Model
إنشاء model LabSampleInvestigation + factory + seed-ready.
عمل LabSampleInvestigation::factory()->create() ينجح؛ الـ relations كلها تشتغل.
BE-3NEW · Model
إنشاء model LabSampleInvestigationLog.
log row بيتعمل بـ LabSampleInvestigationLog::create([...]) ومرتبط صح.
BE-4NEW · Enum
إنشاء enum SampleInvestigationStatus.
enum يحدد الـ transitions الصحيحة (راجع State Machine في blueprint).
BE-5NEW · Enum
إنشاء enum SampleInvestigationAction للـ logs.
enum مستخدم في الـ logs writer service.
BE-6HIGH · Model edit
تعديل LabSample model.
eager loading $sample->load('investigations.investigation') يشتغل.
BE-7MED · Model edit
تعديل LabResult, LabInvestigation, LabExternalLabPricing, LabExternalLabReferral models.
PHPUnit tests للـ models تنجح؛ الـ casts صح.

Phase 2: Writers (BE-8 to BE-16)

BE-8CRIT · Writer Service
كتابة SampleInvestigationService مركزي.
unit tests تغطي defer/cancel/send-out/reject/recollect transitions.
BE-9CRIT · Listener refactor
إعادة كتابة GenerateResultsOnSampleReceived listener.
عند delivery لـ sample فيه TG deferred، النتيجة بتتعمل بس للـ tests الفعلية (مش TG).
BE-10CRIT · Controller edit
تعديل LabRequestController::store().
عمل request جديد بـ Lipid Panel → الـ sample يبقى عنده ٦ rows في lab_sample_investigations (LIPID + 5 members).
BE-11CRIT · Controller edit
إعادة كتابة LabSampleController::defer().
defer لـ TG من Lipid Panel → row واحد بس بـ investigation_id=16 ينتقل لـ deferred sample جديد.
BE-12CRIT · Controller edit
إعادة كتابة LabSampleService::recollect().
recollect لـ TG → sample جديد فيه row واحد TG بـ status=pending.
BE-13HIGH · New endpoints
إضافة endpoints جديدة في LabSampleController.
curl tests للـ endpoints الجديدة تشتغل.
BE-14HIGH · Service edit
تعديل LabSampleService::aliquot().
aliquot لـ sample فيها 6 tests على 3 sections → 3 children كل واحد بياخد rows بتاعت section بتاعه.
BE-15HIGH · Service edit
تعديل LabSampleService::collect() و deliver() و reject().
كل status transition يظهر في lab_sample_investigation_logs.
BE-16HIGH · Result actions
تعديل LabResultController + LabResultService.
unpublish لـ result بعد published → row يبقى status=retracted؛ يقدر يعمل rerun/cancel/send-out بعد كده.

Phase 3: Readers + Resources (BE-17 to BE-22)

BE-17HIGH · Resource
تعديل LabSampleResource.
GET /samples/{id} يرجع investigations: [...] بشكل كامل.
BE-18MED · Resource
تعديل LabSectionKanbanController.
GET /sections/{id}/kanban يرجع كل card فيها list الـ tests الفعلية على الـ sample.
BE-19MED · Resource
تعديل LabExternalLabReferralResource + endpoints.
FE referrals يعرض TAT + Assigned To.
BE-20MED · Bulk endpoint
endpoint جديد POST /sample-investigations/bulk-action.
bulk validate لـ ٢٤ row في request واحد ينجح في transaction واحد.
BE-21MED · Filter endpoint
endpoint جديد GET /sample-investigations للـ smart search.
filter بـ investigation_id=16 + date=today يرجع كل الـ TG النهارده.
BE-22LOW · Machine link
تعديل LabMachineResultController::store().
machine بتبعت result → row pivot يبقى result_entered + lab_result جديد بـ entry_source=machine.

D. Frontend Tasks (٢٤ task)

Phase 4.A: Models + Services (FE-1 to FE-6)

FE-1NEW · Model
إنشاء LisSampleInvestigation model.
model imported في الـ sample service.
FE-2HIGH · Model edit
تعديل LisSample model.
tsc ينجح؛ types صح.
FE-3MED · Service
إنشاء LisSampleInvestigationService.
unit test باستخدام HttpTestingController.
FE-4MED · Service edit
تعديل LisSampleService.
callers في collection-worklist تستخدم الـ methods الجديدة.
FE-5MED · Service edit
تعديل LisResultService.
قابل للـ unit tests.
FE-6LOW · Models update
تعديل models أخرى صغيرة.
tsc clean.

Phase 4.B: Collection Worklist (FE-7 to FE-9)

FE-7CRIT · Component refactor
إعادة كتابة tube builder في collection-worklist.
tube مع TG deferred → الـ display يعرض TG فقط، مش LIPID.
FE-8HIGH · UI tabs
إضافة Cancelled و Sent Out tabs في collection-worklist.
4 tabs (Pending, Deferred, Cancelled, Sent Out, History) شغّالة.
FE-9HIGH · Defer dialog
تحويل defer dialog إلى shared component يستخدم في Defer/Cancel/Send Out/Reject.
نفس الـ component يستخدم في 3 شاشات مع modes مختلفة.

Phase 4.C: Reception Screen (FE-10 to FE-11)

FE-10NEW · Screen
شاشة جديدة /lab/reception.
scan ينجح؛ receive يحدث الـ status لكل rows على الـ sample.
FE-11MED · Routing + Nav
إضافة الـ route والـ nav entry.
/lab/reception accessible.

Phase 4.D: Worklist + Validation (FE-12 to FE-17)

FE-12HIGH · Worklist refactor
تحديث dept-worklist ليقرأ من sample_investigations.
المعمل يشتغل بـ per-test workflow بدل sample-level.
FE-13HIGH · Rerun action
إضافة Rerun button في dept-worklist + validation.
Rerun يحفظ القيمة القديمة في log + يعرض history.
FE-14HIGH · Validation refactor
تحديث validation-worklist.
columns واضحة + قابلة للسورت.
FE-15HIGH · Smart Search bar
filters متعددة في validation + worklist.
filter "CBC + Today" يرجع الكل صح.
FE-16HIGH · Bulk action bar
multi-select + bulk action bar.
bulk validate لـ 20 rows → toast {succeeded: 20}.
FE-17HIGH · Unpublish
زرار Unpublish في validation.
unpublish ينجح؛ النتيجة تختفي من portal فوراً.

Phase 4.E: Referrals + Other (FE-18 to FE-24)

FE-18MED · Referrals
إضافة TAT + Assigned To في referrals.
referrals page يعرض TAT المتوقع + المسؤول.
FE-19MED · TAT in investigations
إضافة tat_hours في investigations form.
save + load يحفظ tat_hours.
FE-20MED · TAT in external pricing
إضافة tat_hours per external-lab pricing.
save + load يحفظ tat_hours بـ external pricing.
FE-21LOW · Comments UI
3 comment fields في dept-worklist + validation.
save لكل field على حدا.
FE-22LOW · Barcode labels
عرض per-test status على الباركود.
label يعكس الـ state.
FE-23LOW · Cleanup utilities
حذف filterBillableTests/buildPanelMemberMap بعد ما الـ callers يتحولوا.
grep لـ filterBillableTests يرجع 0 hits.
FE-24LOW · Cleanup screens
حذف lis-samples.component.ts و lis-kanban.component.ts لو مش routed.
build clean بدون unused imports.

E. Order of Execution

  1. BE-1 → BE-7 (Schema + Models) — Phase 1
  2. Truncate dev DB + run migrations
  3. BE-8 → BE-16 (Writers) — Phase 2 — defer/cancel/send-out أولاً، aliquot ثانياً
  4. BE-17 → BE-22 (Readers + bulk endpoints) — Phase 3
  5. FE-1 → FE-6 (Models + Services) — Phase 4.A
  6. FE-7 → FE-9 (Collection) — Phase 4.B
  7. FE-10 → FE-11 (Reception) — Phase 4.C
  8. FE-12 → FE-17 (Worklist + Validation) — Phase 4.D
  9. FE-18 → FE-24 (Referrals + Cleanup) — Phase 4.E
  10. End-to-end test: defer TG → recollect → collect → receive → start → enter result → validate → release → publish → unpublish → rerun → publish
  11. Cleanup (legacy columns + utilities) — Phase 5

F. Risk Register

الخطرالتأثيرالمعالجة
الـ Kanban controller شاشة legacy + شاشة جديدةMEDتأكيد أي شاشة الـ user بيستخدمها فعلاً قبل تعديل
الـ GenerateResultsOnSampleReceived بيحسب section logic معقدHIGHاعادة كتابة كامل + unit tests على edge cases (panel partial defer)
الـ aliquot logic يفترض كل tests القسم في sample واحدMEDالـ refactor بيخلي الـ aliquot ينقل rows من parent — يبقى الـ logic مبسّط
الـ Machine integration بيستخدم sample_id+investigation_id directLOWعند match، يحدّث pivot row + ينشئ lab_result
الـ Referrals بتربط بـ sample كامل دلوقتيMEDلازم نضيف investigation_id في الـ referral table أو يستخدم pivot rows اللي status=outsourced
الـ user testing على prod = dev backend (مش Ahmed's prod)LOWالتحقق من config.json + إعطاء الـ user URL واضح
الـ build size في FE يزيد بسبب الـ shared componentsLOWcode splitting إذا لزم
FE caching يخلي الـ user يشوف JS قديمMEDhash في chunk names بيمنع ده، بس index.html لازم not-cached

G. Estimated effort

PhaseBE tasksFE tasksEst. days
1. Schema + Models71
2. BE Writers92
3. BE Readers61
4.A FE Models + Services60.5
4.B FE Collection31
4.C FE Reception21
4.D FE Worklist + Validation62
4.E FE Referrals + Cleanup71
Testing + bug fixing1
Total2224~10 days

H. Final Confirmation Needed

قبل ما أبدأ Phase 1:
  1. الـ scope ده مقبول (٢٢ BE + ٢٤ FE = ٤٦ task)؟
  2. الـ truncate dev DB موافق عليه؟
  3. تحب نـ feature branch واحدة (refactor/per-test-status) ولا نقسم Phase 1 / Phase 2 على branches منفصلة؟
  4. أي شي ناقص أو غامض؟ راجع كل task ونقاطه وقولي.