1 الخلاصة في 4 نقاط (اقرأها الأول)
① الباك إند آمن. اختبرنا الحساب فعليًا: أي endpoint مالوش صلاحية فيه رجّع 403 (الأقسام، الأجهزة، QC، الخزائن، التقارير، المعامل الخارجية…). مفيش تسريب بيانات.
② المشكلة الأساسية = إعداد الدور، مش باج في الكود. دور "reception" ماخد 46 صلاحية على ~15 مورد. القائمة الجانبية بتعرض بالظبط اللي الدور بيسمح بيه — فهو "شايف كتير" لأن الدور نفسه واسع، مش لأن في خلل في الفلترة. ده أسرع حاجة تتظبط: من شاشة الأدوار.
③ الخطير مش "بيشوف" — الخطير "بيقدر يعمل". الدور فيه صلاحيات مدمّرة الكاشير المفروض ميكونش معاه: payments.void (إلغاء دفعات)، invoices.cancel، invoices.delete، requests.delete، patients.delete، doctors.delete. دي قدرات حقيقية (الباك إند بينفّذها لأنها ممنوحة)، مش مجرد شاشة فاضية.
④ تسريب شكلي (UX): راوتس /lab/* مفيهاش أي حارس صلاحيات — لو اليوزر كتب لينك شاشة ممنوعة بإيده، هيكل الشاشة بيظهر (عنوان + جدول فاضي + زرار «جديد») والداتا بترجع 403. منظر مزعج لكن مش تسريب بيانات.
2 إزاي الصلاحيات بتتطبّق؟ (3 طبقات)
| الطبقة | المكان | الحالة | التقييم |
| 1. الباك إند (الحماية الحقيقية) |
كل Controller فيه permission:lis.X.action على كل أكشن (view/create/update/delete/post/cancel…) |
دقيقة ومُفعّلة — بترجع 403 |
سليمة ✓ |
| 2. فلترة القائمة (Sidebar) |
lis-layout → filteredNavGroups → PermissionService.hasAnyPermission(prefix) |
بتخفي العناصر اللي مفيش ليها صلاحية (مجموعات External Labs / Costing / Quality اختفت كلها لـ emad) |
شغّالة بس بالـ prefix الخشن |
| 3. حُرّاس الراوت (Route Guards) |
lis-standalone.routes.ts (مسارات /lab/*) |
57 راوت — صفر حارس صلاحيات. الأب عليه authGuard بس (تسجيل دخول فقط) |
مفقودة ✗ |
المسارات المدمجة /core/lis/* عليها حارس واحد عام على الأب: data: { permissions: ['lis.'] } — يعني أي يوزر عنده أي صلاحية lis.* يقدر يفتح كل شاشات المعمل المدمجة. خشن جدًا.
3 حالة emad بالتفصيل — "بيشوف" مقابل "بيقدر يعمل"
الدور reception عنده 46 صلاحية. التقسيم:
أ) صلاحيات مدمّرة / مرتفعة — الأخطر — راجِعها فورًا
| الصلاحية | بتسمح بإيه | كاشير المفروض يكون معاه؟ |
lis.payments.void | إلغاء/تصفير دفعة متسجّلة | لأ |
lis.invoices.cancel | إلغاء فاتورة (قيد عكسي محاسبي) | لأ |
lis.invoices.delete | حذف فاتورة | لأ |
lis.requests.delete / requests.cancel | حذف/إلغاء طلب | لأ (الإلغاء ربما بصلاحية منفصلة) |
lis.patients.delete | حذف مريض | لأ |
lis.doctors.delete / create / update | إدارة الأطباء بالكامل | لأ (يكفي view) |
lis.visits.delete | حذف زيارة | لأ |
دي قدرات تنفيذية حقيقية — مش شاشات فاضية. لو الكاشير ضغط الزرار، الباك إند هينفّذ لأن الصلاحية ممنوحة فعلاً. دي أهم نقطة في الدراسة.
ب) صلاحية واحدة بتفتح أكتر من شاشة (الـ prefix الخشن)
الفلترة بتقارن بـ "يبدأ بـ" (startsWith)، فالصلاحية الواحدة بتكشف كل الشاشات اللي بتشترك في نفس البادئة:
| عند emad | الشاشات اللي بتظهر بسببها | ملاحظة |
lis.results.view فقط | Worklist + Review & Release (الاعتماد/الإصدار) | شاشة الإصدار حساسة — تفتح بصلاحية «عرض» فقط |
lis.payments.* | Payments + Cashier Shift + Cashier Reconciliation + Cash Flow | منحة واحدة → 4 شاشات (منها إدارية) |
lis.invoices.* | Invoices + Receivables | مقبول للكاشير |
ج) تسريب شكلي بالـ URL المباشر (دليل من اختبار حقيقي على جلسة emad)
القائمة الجانبية بتخفي الشاشات دي صح، لكن لو فتحتها بالـ URL مباشرة الهيكل بيظهر:
| الشاشة | النتيجة عند الفتح المباشر | الداتا |
/lab/machines | ظهر الهيكل كامل (عنوان «Lab Machines» + أعمدة + زر «New Machine») | 7 × 403 |
/lab/sections | ظهر الهيكل | 5 × 403 |
/lab/treasuries | ظهر الهيكل | 4 × 403 |
/lab/reports · /lab/external-labs · /lab/qc | كلها ظهر هيكلها | 403 |
بيانات محمية الباك إند بيرجع 403
هيكل ظاهر عنوان + جدول فاضي + أزرار
4 المشاكل وأماكنها في الكود
| # | المشكلة | المكان | الخطورة |
| 1 | دور "reception" واسع جدًا (46 صلاحية فيها مدمّرة) | إعداد الدور (شاشة الأدوار / السيدر) | عالية (قدرة فعلية) |
| 2 | صفر حُرّاس صلاحيات على /lab/* | lis-standalone.routes.ts | متوسطة (هيكل فقط) |
| 3 | حارس /core/lis/* عام بـ ['lis.'] | app.routes.ts سطر 186 | متوسطة |
| 4 | prefix خشن: صلاحية «عرض» تكشف شاشات إجراءات | permission.service.ts (startsWith) + nav prefixes | منخفضة (تصميم) |
| 5 | لينك «Settings» ظاهر دايمًا بدون صلاحية | هيدر lis-layout | منخفضة |
5 خطة العلاج — مرتبة بالأثر والسرعة
① فورًا (بدون كود): ظبط دور reception من شاشة الأدوار
شيل الصلاحيات المدمّرة (
void /
cancel /
delete / إدارة الأطباء) — يحل «بيشوف» و«بيقدر يعمل» مرة واحدة. ده
تغيير بيانات تعمله إنت دلوقتي.
② تحصين (كود FE): حارس صلاحيات على كل راوت /lab/*
نضيف
lisPermissionGuard يقرأ صلاحية الشاشة (نفس اللي في الـ nav) ويمنع الفتح المباشر — يوديه للداشبورد أو يعرض «لا تملك صلاحية» بدل الهيكل الفاضي. ونظبّط
/core/lis/* بصلاحية لكل شاشة بدل
['lis.'].
③ تحسين (طويل المدى): فصل صلاحيات العرض عن الإجراء
صلاحية مستقلة للإصدار (
lis.results.release)، وللكاشير-شيفت/التسويات/التدفق النقدي (بدل
lis.payments العامة) — في الـ nav والباك إند.
④ اختياري: دور «cashier» جاهز ومُصغّر
نعمل دور مخصص للكاشير بصلاحيات الحد الأدنى، ونحوّل عماد ليه.
اقتراح مجموعة صلاحيات «كاشير» مصغّرة (للنقاش — مش نهائي)
| يبقى | يتشال |
|
patients.view/create/update
requests.view/create/update
samples.view/collect/receive
invoices.view/create
payments.view/create
results.view
investigations/packages/price-lists.view
doctors.view
|
payments.void
invoices.cancel/delete
requests.cancel/delete
patients.delete
doctors.create/update/delete
visits.delete
|
تنبيه على invoices.post: ميزة «التحصيل بضغطة» اللي عملناها بترحّل الفاتورة المسودة تلقائيًا قبل الدفع. فلو الكاشير هيحصّل، محتاج invoices.post (نسيبها) — بس نشيل invoices.cancel/delete. قرار رقم 4.
6 قرارات محتاج رأيك فيها
قرار 1 — تنفيذ ظبط الدور
أظبّط دور "reception" دلوقتي بإزالة الصلاحيات المدمّرة؟
(توصيتي: نعم فورًا) — ولا تفضّل نعمل دور "cashier" جديد ونحوّل عماد ليه؟
قرار 2 — حُرّاس الراوت
أضيف
lisPermissionGuard على كل شاشات
/lab/* و
/core/lis/* عشان أمنع الفتح المباشر للهيكل؟
(توصيتي: نعم — تحصين مهم)
قرار 3 — فصل صلاحيات الإجراء
أفصل صلاحية الإصدار (Release) والكاشير-شيفت عن البادئات العامة؟
(توصيتي: مرحلة تانية بعد التحصين)
قرار 4 — مجموعة الكاشير المصغّرة
أعتمد المجموعة المقترحة فوق (مع إبقاء
invoices.post عشان التحصيل)؟ أنت تحدد القائمة النهائية.
7 الخلاصة
بياناتك محمية (الباك إند بيرجع 403). اللي محتاج تحرّك: (١) ظبط دور reception فورًا — يشيل القدرات المدمّرة ويقلّل اللي بيتعرض. (٢) حُرّاس راوت على شاشات المعمل — تمنع تسريب الهيكل. الباقي تحسينات granularity على مهل.