فحص آليّ لنقاط docs/38 مقابل الكود كشف ثغرات لم تظهر بالقراءة.
## تسجيل السائق — أخطر ثغرة
لم يكن موجوداً أصلاً: سائق جديد يسجّل دخوله ثم يقف. بُنيت features/onboarding
كاملة — تقديم ← ملف ← مركبة ← وثائق ← انتظار الاعتماد.
- الخطوة تُشتقّ من حالة الخادم لا من تقدّم محلّي: سائق يعيد تثبيت التطبيق
يعود إلى حيث وقف لا إلى البداية
- الاعتماد يقع على الخادم تلقائياً حين تكتمل الوثائق؛ التطبيق لا يعتمد أحداً
- عند الاعتماد خروج إجباري: الدور يتغيّر على الخادم والتوكن القديم يحمل
القديم، فتفشل نقاط السائق بـ403 (مصيدة docs/38 §5)
- بوابة توجيه: مستخدم دوره ليس driver يُحجز في /onboarding
- الوثائق تُصوَّر بالكاميرا لا من المعرض: أصعب تزويراً
## الدردشة والكوبون
- Features.chat كان مفعّلاً بلا ميزة. features/chat باستطلاع كل خمس ثوان —
قائمة أحداث الخادم لا تتضمّن الرسائل (docs/38 §9)، فالاستطلاع قيد خادم لا
اختيار تصميمي
- الكوبون: حقل في ورقة التأكيد خلف طبقتَي الميزات، يُقيَّم على الخادم
## Features.calls أُطفئ صراحةً
الخادم يدعم WebRTC والتطبيق لا. عَلَم مفعّل بلا ميزة كذبٌ على القارئ التالي.
## بنية
- ApiClient.upload للرفع متعدّد الأجزاء
- AuthFailure → ApiFailure في core/api: يخدم المصادقة والملف والتسجيل
- tool/sync_from_rider.sh: المزامنة اليدوية بين التوأمين انكسرت أربع مرات،
فصارت سكربتاً واحداً يعرّف ما يملكه كل تطبيق
flutter analyze نظيف · الراكب 101 ملف/7,809 سطر · السائق 110 ملف/8,116 سطر.
فحوص آلية: صفر استيراد بين ميزتين · صفر عَلَم مفعّل بلا ميزة · كل نقاط العقد
المخصّصة للتطبيقين مستهلكة.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
## طبقتا الميزات مُطبَّقتان معاً
AppDrawer يفحص: Features.wallet && context.tenantHas('wallet')
- Features.x ثابت const: يقرّر ما يُبنى في الـbinary. إطفاؤه يحذف الكود
فلا يُستخرج (docs/23 §5)
- tenantHas من GET /tenant/config/:slug: يقرّر ما يُعرض ممّا بُني حسب اشتراك
المستأجر (docs/38 §10)
هذا هو ربط lite/pro/max عملياً. TenantCubit يعرض النسخة المخزّنة فوراً ثم
يحدّثها: إقلاع بلا إنترنت يعرض الميزات المعروفة آخر مرة لا شاشة فارغة.
## الشاشات
الدراور · تعديل الحساب · سجلّ الرحلات · الإعدادات (مظهر + لغة) · المساعدة.
الرقم في تعديل الحساب معطّل مع سبب معروض لا مخفي: هو هوية الحساب على الخادم
وتغييره يعني حساباً آخر (docs/38 §1).
## الإشعارات
PushService معزول — الملف الوحيد الذي يعرف Firebase. التسجيل بعد إثبات
الجلسة عبر خطّاف في SessionCubit، ومع اشتراك onTokenRefresh: بدونه تتوقّف
الإشعارات بصمت بعد أسابيع. الإعداد الأصلي كان جاهزاً مسبقاً.
## تصحيحات بنيوية كشفها فحص آلي
docs/23 §1 يمنع أن تستورد ميزة من أخرى — وكانت خمس مخالفات:
1. features/history أُدمجت في features/trip — السجلّ جزء من ميزة الرحلة
2. AppDrawer صعد إلى core/ui — هيكل تطبيق لا ميزة
3. AuthFailure → core/api/api_failure.dart، ومترجمه → core/ui/failure_text.dart
4. AuthHeader → core/ui/form_header.dart
5. ProfileRepository مستقلّ عن AuthRepository: تعديل الملف ليس مصادقة
flutter analyze نظيف · الراكب 98 ملف/7,497 سطر · السائق 95 ملف/6,931 سطر.
فحوص آلية نظيفة: صفر استيراد بين ميزتين · core يستورد features من di و
router وحدهما · Firebase و intaleq_maps و geolocator و socket_io كلٌّ معزول.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
## حسم تعارض الخرائط (docs/38 §7)
لصالح القرار الأحدث 2026-07-20: كل الخرائط — البلاطات والبحث والعكسي
والمسار — مباشرة إلى map-saas بترويسة x-api-key، بلا مرور بباك إند تريبز.
نقاط /maps/* في الباك إند لا تُستعمل، وإحداها (geocode) معطوبة على المنشور.
العقد تُحقّق حيّاً بـcurl قبل كتابة سطر.
## النواة المشتركة
- core/api/antlaq_api.dart: عميل منفصل بلا AuthInterceptor — توكن تريبز لا
شأن لخادم الخرائط به، وإرساله إليه تسريب بلا مقابل
- core/realtime: Socket.IO واحد (trip:update · driver:location · trip:offer
· trip:offer_taken)
- core/location: نقطة الموقع الوحيدة بمرشّح 25 متراً
- features/trip/data: سبعة نماذج + MapsRepository + TripRepository متطابق
حرفياً بين التوأمين
## الراكب
RideCubit بستّ مراحل + RidePage وثمانية ويدجت: الخريطة · دبّوس المنتصف ·
المخطّط · الخط الزمني · اختيار النوع · التأكيد · البحث عن سائق · الرحلة.
## السائق
DutyCubit بأربع مراحل + DutyPage: مفتاح الاتصال · العرض بمؤقّت · الرحلة.
## قرارات تحمي الأداء والصحّة
- GeoPoint مستقلّ عن حزمة الخريطة؛ intaleq_maps مستوردة في ملف واحد فقط
لكل تطبيق. تبديل محرّك الخريطة لا يلمس منطقاً
- الخريطة خارج BlocBuilder الورقة ولها BlocSelector خاص: نبضة موقع كل 25م
لا تعيد بناء الشاشة
- مهلة بحث محليّة 90ث + استطلاع كل 5ث: الخادم قد لا يُطلق expired/no_drivers
أبداً (ثغرة R1)، وانتظار حدث قد لا يصل = شاشة بحث أبدية
- offeredDrivers == 0 جواب نهائي فوري بلا انتظار المهلة
- الأجرة لا تُعرض إلا إن كانت صالحة: /tariff/quote يرجّع 200 بقيم null صامتة
- موقع السائق بمسارين عمداً: REST لمطابقة Redis والسوكت لخريطة الراكب
flutter analyze نظيف · الراكب 70 ملف/5,294 سطر · السائق 67 ملف/4,771 سطر.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>