بدأ التدقيق من واقعة محددة: مستخدم جديد بدور «مندوب توصيل» علِق التطبيق معه فور تسجيل الدخول. أعدنا إنتاج العطل بمستخدم تجريبي حي، وحددنا السبب الجذري بالملف والسطر، ثم وسّعنا التدقيق ليشمل دورة حياة الصلاحية كاملة — من الزارع إلى الواجهة.
العطل ليس بطئاً ولا مشكلة خادم: هو حلقة توجيه لا نهائية داخل الواجهة. عندما يرفض حارس الصلاحيات صفحةً، يعيد التوجيه إلى /dashboard — لكن /dashboard نفسها تتطلب صلاحية core.dashboard التي لا يملكها دور المندوب، فيرفضها الحارس ويعيد التوجيه إليها من جديد… إلى ما لا نهاية. المستخدم يرى «تحميلاً أبدياً» بينما الموجّه يدور على نفسه.
courior) أُنشئ صحيحاً من شاشة الأدوار وتوسّعت تبعياته كما يجب. المشكلة محصورة في منطق التوجيه بالواجهة، وحلّها الجذري يومان عمل.التدقيق الموسّع كشف أن هذه الواقعة عرَض لنمط أعمق: لا يوجد «حد أدنى» معرّف لدور يستطيع الدخول، ومساران مختلفان لحفظ الأدوار بقواعد مختلفة، وحراسة الشاشات تعتمد على إخفاء عناصر القائمة أكثر من اعتمادها على حراسة فعلية — التفاصيل والحلول في القسمين 3 و4.
حمولة الدخول الفعلية للمستخدم التجريبي (نفس دور حالة ctest — والدور الحقيقي خلفها اسمه courior — بهذا الإملاء في قاعدة البيانات نفسها):
lis.samples.view توسّعت تلقائياً).home_page = null (قالب المندوب الجاهز لا يضبطها) → الواجهة تتجه للمسار الافتراضي /./ يحوّل تلقائياً إلى /dashboard — لوحة الـ ERP الرئيسية./dashboard تتطلب core.dashboard — والمندوب يملك lis.* فقط. (مفارقة: القالب يمنحه lis.dashboard.view — لكنها صلاحية للوحة المعمل لا لوحة الـ ERP، بل وتبيّن أنها صلاحية «وهمية» لا يستخدمها أي مسار خادمي.)/dashboard» — أي إلى نفس الصفحة التي رفضته للتو. توجيه → رفض → توجيه… لا توجد أي شبكة أمان (لا معالج أخطاء تنقّل، لا كاشف حلقات، لا صفحة «غير مصرّح»). الملاحة لا تكتمل أبداً والشاشة تعلق.core.dashboard — من أي حارس فاشل، ومن حارس الموديولات، وحتى من أي رابط خاطئ (المسار الشامل ** يصبّ في نفس القمع). كل الأدوار المعملية المصغّرة بلا صفحة هبوط مرشّحة للسقوط فيها./dashboard المحروسة بـcore.dashboard — أي مستخدم لا يملكها يدخل دوامة أبدية بدل رسالة واضحة. لا يوجد withNavigationErrorHandler ولا أي قاطع حلقات في إعداد الموجّه./lab/courier-pickups — فحتى الأدمن الحريص لا يستطيع اختيارها. كما يتضمن الكتالوج مسارات ميتة (/lab/receiving محذوفة) تصبّ بدورها في الحلقة./lab — 62 تعريف مسار، تحققنا منها عدّاً — (وكذلك توأمها المدمج) لا تحمل أي متطلب صلاحية — أي مستخدم يملك صلاحية معملية واحدة يفتح أي شاشة معملية بكتابة الرابط، والحماية الفعلية متروكة كلياً لأخطاء 403 من الخادم.data.permissions لكل شاشة (نفس خريطة صلاحيات القائمة الجانبية الموجودة فعلاً — نقل لا تأليف).Gate::before خادمياً لنفس الشرط، أو إلغاء الإشارة الواجهية واستبدالها بدور صريح super-admin.admin محدداً مسبقاً — أدمن واحد غافل = مستخدم عادي بصلاحيات إدارية. خيار افتراضي خطير بلا مبرر.all — مندوب جديد يرى بيانات كل الفروع، أي أن مستخدماً قُصد تقييده بفرعه قد يطّلع على بيانات بقية الفروع حتى يُضبط النطاق يدوياً. الافتراض الآمن هو الأضيق لا الأوسع.branch مع رفع صريح من الأدمن عند الحاجة.lis.samples.pickup «تبدأ بـ» lis.samples — فيرى المندوب قوائم سحب العينات والاستقبال أيضاً. نظام البادئة لا يفرّق بين «أفعال» داخل نفس المورد، ويتفاقم مع غياب حراسة المسارات (مشكلة 5).lis.dashboard.view مزروعة وممنوحة في كل القوالب، لكن لا يستخدمها أي مسار خادمي — وبيانات لوحة المعمل الفعلية تتطلب صلاحيات أخرى لا يملكها المندوب، فلوحته تفتح فارغة بأخطاء.hr. بينما الصلاحيات hrm.* (لا يطابق أبداً)؛ صفحة الهبوط عند تعدد الأدوار تُحسم اعتباطياً بأول قيمة؛ وGET /lis/roles/{id} يعيد صفحة HTML بدل JSON (مسار ناقص).APP_DEBUG=true فعلياً (سطر تالف في ملف البيئة يلغي القيمة المقصودة false) — كل خطأ 403/404 يسرّب أثر مكدس كاملاً؛ وحفظ الأدوار غير معاملاتي، وكاش صلاحيات spatie ملفّي وقد ينكسر بصمت بملكيّات ملفات خاطئة على هذه الاستضافة.