شاشة الصلاحيات: إعادة التصميم + خريطة «كل صلاحية بتتنفّذ فين في الواجهة»

دراسة المرحلة الأولى (بحث فقط — بدون أي كود) · شاشة /core/roles · Moon ERP / moonui2

🎨 إعادة تصميم UX (Fable) 🗺️ خريطة تطبيق 996 صلاحية ℹ️ وصف لكل صلاحية ⚙️ قاعدة: setting + صلاحيته التاريخ: 2026-07-13

١. المشكلة

شاشة الصلاحيات الحالية /core/roles فيها ثلاث مشاكل مترابطة طلب المالك معالجتها كلها كدراسة قبل أي كود:

أ
الشكل والمسمّيات لا تعبّر عن الصلاحية. ~1000 صلاحية تظهر كقائمة مسطّحة (مربع اختيار لكل صلاحية) داخل نافذة 800px، والاسم مركّب آليًّا («الفواتير - اعتماد») بدون أي شرح لما بتعمله الصلاحية فعلًا. المطلوب: تصميم احترافي سريع سهل الاستخدام، وكل صلاحية ليها «info» توضّح وظيفتها.
ب
«صلاحية موجودة لازم تتنفّذ في الواجهة» — وده غير متحقّق. المالك محتاج يعرف كل صلاحية مكانها فين في الـUI (أي زر/شاشة/حركة بتتحكم فيها)، عشان يضمن إنها مطبَّقة في كل مكان — لأن في صلاحيات ممنوحة لكن مالهاش أثر ظاهر في الواجهة.
ج
قاعدة الإعدادات. لما نعدّل أو نضيف أي setting، لازم نفتكر نضيف الـsetting وصلاحيته معه (كل إعداد جديد ياخد صلاحيته الخاصة).

٢. الوضع الحالي (ما هو موجود) — بالأدلة

٢.١ كيف تُبنى الشاشة اليوم

٢.٢ كيف تُطبَّق الصلاحية في الواجهة (3 طبقات)

كل الطبقات تمرّ عبر permissionMatches(owned, required) (permission.service.ts:18-22) — منطق «حدّ النقطة»:

الطبقةأينالدلالة
قائمة/منيوnav-items.config.ts + sidebar.component.ts (permissions:[…])يخفي عنصر القائمة
حارس المسارpermissionGuard + data.permissions في المساراتيمنع فتح الصفحة
زر/إجراء*appCan (can.directive.tshasAnyPermission)يخفي الزر
قاعدة المطابقة الحاسمة: المطابقة إما تطابق تام، أو بادئة تنتهي بنقطة. يعني بوابة sales.invoices تغطّي sales.invoices.delete (بادئة). لكن hrm.training لا تطابق hrm.training-programs.view (الحرف بعد training شرطة «-» مش نقطة). الـBE يُطبّق منفصلًا عبر Spatie permission:<الاسم-الدقيق>تطابق دقيق بلا بوادئ. السوبر-أدمن يتخطّى كل الفحوص (service:113).

٢.٣ النتيجة الكمية — خريطة التغطية (996 صلاحية)

استخرجنا كل سلاسل الكتالوج من RolePermissionSeeder::permissions() (سطور 293–1480) وكل بوابات الواجهة (585 سلسلة: 398 *appCan + 197 بوابة منيو/مسار)، وصنّفنا كل صلاحية:

430
مُطبّقة بدقة (43%)
السلسلة الكاملة موجودة كبوابة
422
تغطية خشنة فقط (42%)
«الزر لسه بيظهر»
144
بلا أثر في الواجهة (14%)
مُطبّقة في الـBE فقط
الموديولالكتالوجدقيقةخشنة فقطبلا واجهةالموديولالكتالوجدقيقةخشنة فقطبلا واجهة
accounting14154870cmms220139
lis179461330crm2101110
hrm11275370einvoicing7007
core7839390nphies8008
production5532230qms220913
sales4333100inventory4828182
purchases5036140webstore950095
clinic9375180pos / reports2212100
الإجمالي996430422144

٢.٤ الـ144 «بلا واجهة» = 7 موديولات كاملة بلا شاشات Angular

كل الـ144 مُطبَّقة فعلًا في الـBE عبر permission: middleware — بس مفيش لها زر/منيو/مسار في الـSPA. التصنيف الصحيح: «مُطبّقة في الـBE، غير مرئية في الواجهة» — مش «غير مطبّقة».

الموديولالعددBE مُطبّق؟أمثلة
webstore95نعمwebstore.orders.*, webstore.products.* (متجر كامل)
qms13نعمqms.capa.*, qms.inspections.*
crm10نعمcrm.interactions.*, crm.sla.*
cmms9نعمcmms.pm-schedules.*
nphies8نعمnphies.claim.submit, nphies.preauth.submit
einvoicing7نعمeinvoicing.documents.submit, einvoicing.zatca.onboard
inventory (التكلفة)2نعمinventory.costing.view/configure
باگ حقيقي واحد اكتُشف: قائمة «تدريب HR» مبوّبة بـpermissions:['hrm.training'] (nav-items.config.ts:312), لكن الكتالوج فيه بس hrm.training-programs.*/training-sessions.*/training-enrollments.*. بسبب قاعدة «حدّ النقطة» فإن hrm.training لا تطابق أيًّا منها → قائمة تدريب HR تظهر للسوبر-أدمن فقط، ومفيش أي صلاحية مِنح تفتحها. البوابة المعلّقة الوحيدة (1 من 585).

٢.٥ الوصف والإعدادات — الوضع الحالي

٣. المطلوب

  1. إعادة تصميم شاشة /core/roles احترافية سريعة: مسمّيات معبّرة + info لكل صلاحية يوضّح وظيفتها، وتصفّح سريع لـ1000 صلاحية.
  2. سدّ فجوة التطبيق: كل صلاحية مؤثّرة يبقى ليها بوابة دقيقة في الواجهة (مش «الزر لسه بيظهر»)، مع معرفة «مكان كل صلاحية».
  3. مصدر موحّد للوصف (كتالوج أو i18n).
  4. قاعدة: كل setting جديد ياخد صلاحيته.

٤. الفجوة (GAP)

المحورموجود اليومالمطلوبما يجب تغييره
وصف الصلاحيةلا شيء — اسم مركّب آليًّا فقطinfo/شرح لكل صلاحيةكتالوج BE للصلاحيات (label/desc/danger/kind) يعمّم LisScreenCatalog، تستهلكه الشاشة
عرض الشاشةقائمة مسطّحة، مربع/صلاحية، نافذة 800pxاحترافي سريع، تصفّح 1000 صلاحية بسهولةمصفوفة «مورد × إجراء» + شريط وحدات + بحث ذكي + قوالب + وضع «حسب الشاشة»
تطبيق دقيق430 دقيقة / 422 خشنة / 144 بلا واجهةالصلاحيات المؤثّرة كلها بوابة دقيقةإنزال 420 بوابة خشنة لمستوى الإجراء عند *appCan (بالأولوية: خطير/مالي أولًا)
البوابة المعلّقةhrm.training يشوفها السوبر-أدمن فقطبوابة تطابق صلاحية موجودةتصحيح البوابة إلى hrm.training-programs.view (أو ما يناظرها)
معرفة «المكان»غير موثّقخريطة صلاحية ↔ مكان التطبيقالكتالوج يحمل حقل «الشاشة/الموقع»؛ اختبار CI يثبت التغطية (نمط LisScreenCatalogTest)
الإعداد ↔ الصلاحيةلا عمود، تبعية خشنة، 8 موديولات بلا settings.manageكل إعداد جديد له صلاحيتهعمود permission على setting_definitions يُفحَص لكل إعداد، + سدّ فجوة الـ8 موديولات

٥. الملفات المتأثّرة والاعتماديات

Backend

Frontend

٦. الحالات الحدّية

الحالةالمعالجة
صلاحية بلا صف وصف في الكتالوجfallback: desc_ar → i18n ROLES.DESCRIPTIONS.<key> → الاسم المركّب «مورد - إجراء». الشاشة لا تُظهر مفتاحًا خامًا أبدًا.
السوبر-أدمن (أدوار/صلاحيات فارغة)يتخطّى كل الفحوص — سلوك محفوظ بدون تغيير. المصفوفة تعرض له الكل محدَّدًا.
موديول غير مُفعَّل (module-activation)filteredPermissionGroups يبقى كما هو — لا نعرض وحدات غير مفعّلة.
الصلاحيات «بلا واجهة» (144)تظل قابلة للمنح (الـBE يُطبّقها) لكن بشارة «API فقط — لا شاشة بعد» حتى تُبنى شاشاتها. قرار للمالك (§8).
تبعية خفية (دور يشوف الفواتير بدون عرض الفروع)coverage lint يحذّر حيًّا («⚠ ناقصة عرض الموردين») مع زر «أضِفها» — نمط LisScreenCatalog.
إنزال بوابة خشنة لمستوى الإجراء قد يخفي زرًا كان ظاهرًامقصود (هو الإصلاح). لكن نبدأ بالخطير/المالي (حذف/اعتماد/ترحيل/تحويل) لتقليل المفاجآت، ونختبر دورًا نموذجيًّا لكل موديول.
الصلاحية الخطيرة (delete) بشكل مطابق للآمنةخلية حمراء + شارة «خطير» في المصفوفة و«info».
RTL + فاتح/داكنالمعاينة تستعمل خصائص منطقية + متغيّرات CSS تدعم prefers-color-scheme و[data-theme].

٧. خطة التنفيذ (WPs بترتيب التنفيذ)

WPالنطاقالطبقةيعتمد علىالاختبار
WP1كتالوج الصلاحيات BE: جدول/Seeder permission_definitions (label_ar/en, desc_ar/en, danger, kind, screen) — يبدأ بـ Sales+Purchases+Core (تدريجي). إثراء GET /core/permissions.BEPest: الرد يحمل الحقول؛ اختبار تغطية نمط LisScreenCatalogTest
WP2إصلاحات دقيقة: تصحيح بوابة hrm.training المعلّقة + إضافة <module>.settings.manage للثمانية الناقصة.FE+BEng build؛ Pest للـseeder
WP3إعادة تصميم الشاشة (FE): مصفوفة مورد×إجراء + شريط الوحدات + بحث/فلاتر + قوالب + info popover + coverage lint + وضع «حسب الشاشة». تستهلك كتالوج WP1، وfallback للاسم المركّب.FEWP1ng build؛ اختبار يدوي للمالك على /app
WP4تصليب التطبيق: إنزال البوابات الخشنة لمستوى الإجراء عبر *appCanبالأولوية: الخطير/المالي أولًا (حذف، اعتماد، ترحيل، تحويل — ومنها أزرار التحويل من تحليل convert-buttons). مرحلي لكل موديول.FEWP1ng build؛ دور نموذجي/موديول؛ لوج ما لم يُغطَّ
WP5قاعدة «إعداد ⇒ صلاحيته»: عمود permission على setting_definitions + فحص لكل إعداد في مسار الكتابة، + توثيق العُرف في KB/CLAUDE.BEWP2Pest: كتابة إعداد بلا الصلاحية → 403
ملاحظة: WP4 هو الجزء الأكبر (420 بوابة). لا يُنفَّذ دفعة واحدة — يُرتّب بالمخاطر، ويُسجَّل ما لم يُغطَّ بعد (log) بدل الادّعاء بالاكتمال.

٨. قرارات تحتاج المالك

1
مصدر الوصف: كتالوج BE أم i18n؟
التوصية: كتالوج BE (يعمّم LisScreenCatalog/setting_definitions). السبب: 1000 مفتاح في i18n هتنفصل فورًا عن الـmiddleware الحقيقي ولا شيء يختبرها؛ الكتالوج بجانب الصلاحيات نفسها، مصدر واحد، وهو ما يشغّل coverage lint. مع fallback للـi18n ثم للاسم المركّب.
2
نطاق تصليب التطبيق (WP4): كل الـ420 البوابة الخشنة، أم بالأولوية؟
التوصية: بالأولوية — الخطير/المالي أولًا (حذف/اعتماد/ترحيل/تحويل)، ثم الباقي مرحليًّا. تغطية الـ420 دفعة واحدة مخاطرة عالية وبطيئة الاختبار.
3
الـ144 «بلا واجهة»: نسيبها في الشاشة أم نخفيها؟
التوصية: تظل قابلة للمنح بشارة «API فقط — لا شاشة بعد» (لأنها مُطبّقة فعلًا في الـBE)، بدل إخفائها فتبان الصلاحية «مش موجودة».
4
قاعدة الإعدادات: عمود permission على setting_definitions (قوي) أم عُرف + بوابة موديول (أخف)؟
التوصية: العمود — هو التنفيذ المباشر لطلبك «كل إعداد ياخد صلاحيته»، ويُفحَص لكل إعداد. مع سدّ فجوة الـ*.settings.manage الثمانية كحدّ أدنى فوري.
5
طرح المصفوفة: تستبدل النافذة الحالية كليًّا، أم خلف مفتاح تبديل مؤقّت؟
التوصية: استبدال كامل (النمط أثبت نفسه في LIS)، مع الحفاظ على كل الموجود (القوالب، الاسم/النطاق/الصفحة الرئيسية، تبويب المنيوهات).

٩. معاينة الواجهة المتوقّعة (قبل / بعد)

تصميم من وكيل Fable. الفكرة الجوهرية: نتوقّف عن عرض الصلاحيات كقائمة سلاسل، ونعرضها كـمصفوفة «مورد × إجراء» — صف واحد = مورد («فواتير المبيعات»)، أعمدة = الإجراءات (عرض/إنشاء/تعديل/حذف/اعتماد/ترحيل) + خلية «أخرى» للذيل الطويل. sales.invoices.* (8 صلاحيات) ينكمش من 8 سطور إلى سطر واحد. المبيعات: 50 سطر → 9. الكتالوج كله: ~1000 → ~180 سطر. مع info لكل صلاحية، شريط وحدات، قوالب جاهزة، وشريط تحذير تغطية حيّ.

ملاحظة قراءة: المعاينة أدناه mockup تقريبي بـHTML/CSS (بيانات نموذجية) — الغرض اعتماد «شكل الشاشة» قبل كتابة أي كود واجهة. الأرقام (22/50 إلخ) توضيحية.
قبل الشاشة الحالية — قائمة مسطّحة
تعديل دور — مسؤول مبيعات
💰 المبيعات 12 / 50
… وهكذا حتى ~1000 صلاحية في نافذة 800px
  • لا يوجد أي شرح: «الفواتير - اعتماد» — اعتماد إيه بالظبط؟ وماذا يترتب عليه؟
  • سطر لكل صلاحية: مورد واحد (أذون التسليم) = 8 سطور متطابقة الشكل؛ الوحدة كلها = 50 سطر تمرير.
  • لا يوجد «تحديد المورد كله» — فقط تحديد الوحدة بالكامل (50 صلاحية دفعة واحدة).
  • الحذف بجانب العرض بنفس الشكل — لا تمييز للصلاحيات الخطيرة.
  • لا تحذير تغطية: دور «يشوف الفواتير» بدون «عرض الفروع» = شاشة بيضاء، ولا أحد يعرف السبب.
بعد محرّر الصلاحيات الجديد — مصفوفة المورد × الإجراء + شرح لكل صلاحية
الكلالمحدّدة 34الخطيرة
🗂 المصفوفة🖥 حسب الشاشة
قوالب جاهزة: 👁 مُشاهد فقط✏️ مدخل بيانات ✅ مشرف اعتماد💼 محاسب فرع
💰 المبيعات 22/50
🚚 المشتريات 12/56
📦 المخزون 0/38
📊 المحاسبة 0/152
🧪 المختبر 0/121
👥 الموارد البشرية 0/74
🛒 نقاط البيع 0/30
⚙️ النظام الأساسي 0/82
+ 7 وحدات أخرى…
المورد / الشاشة عرضتحديد العمود إنشاءتحديد العمود تعديلحذفاعتمادترحيل / تأكيدإجراءات أخرى
💰 المبيعات 22 / 50 تحديد الكل ▾
  عروض الأسعارi +4 · إرسال، قبول، رفض، نسخ
  أوامر البيعi +3 · إلغاء، إقفال، نسخ
أوامر البيع sales.orders
أمر البيع هو تأكيد طلب العميل قبل التسليم والفوترة — تُبنى عليه أذون التسليم والفواتير.
عرضيشاهد قائمة أوامر البيع وتفاصيلها دون أي تعديل.
تأكيديحوّل الأمر من مسودة إلى أمر مؤكد يُسمح ببدء التسليم بناءً عليه.
حذف خطيرحذف نهائي للأمر — لا يمكن التراجع عنه.
عرض العملاء ⚠ لازمةصلاحية مشتركة من النظام الأساسي — بدونها لا تُفتح شاشة إنشاء الأمر.
  أذون التسليمi +3 · شحن، تسليم، إلغاء
  فواتير المبيعاتi +2 · إلغاء، نسخ
  مقبوضات العملاءi +1 · إلغاء
  مرتجعات المبيعاتi +1 · إلغاء
🚚 المشتريات 12 / 56 تحديد الكل ▾
  طلبات الشراءi +3 · تحويل لأمر، رفض، إلغاء
  أوامر الشراءi +3 · إدارة، إقفال، إلغاء
  إذن الاستلام (GRN)i +2 · فحص جودة، إلغاء
  فواتير الموردينi +1 · إلغاء
  أسعار الموردينi
⚠️ شاشة أوامر الشراء هتفشل — الدور معه «اعتماد أمر الشراء» لكن ناقصه «عرض الموردين» (النظام الأساسي). أضِفها
34 صلاحية محددة · وحدتان
وضع «حسب الشاشة» (المفتاح أعلى اليسار) يعرض نفس الدور مجمّعًا بشاشات النظام كما في محرّر أدوار المختبر: كل شاشة ببند أساسي + متطلباتها الخفية ⚠ + إجراءاتها، مع وصف لكل بند.

الخلاصة

~1000 صلاحية: 430 مُطبّقة بدقة، 422 تغطية خشنة (فئة «الزر لسه بيظهر»، ~420 منها على مستوى الإجراء — أغلبها LIS/محاسبة/core/HR)، 144 بلا واجهة (7 موديولات كاملة مُطبّقة في الـBE بلا شاشات). + بوابة معلّقة واحدة (hrm.training) يشوفها السوبر-أدمن فقط، ولا وصف لأي صلاحية. الحل: كتالوج صلاحيات BE (يعمّم LisScreenCatalog) + إعادة تصميم الشاشة لمصفوفة بـinfo وcoverage lint + تصليب تطبيق بالأولوية + ربط الإعداد بصلاحيته. هذا تحليل — بانتظار موافقتك قبل أي كود.