feat(apps): سقالة rider_new و driver_new على Cubit — المرحلة 1

بناء من الصفر على باك إند NestJS، بقرار المالك 2026-08-04 الذي يعكس قرارَي
نقل GetX (2026-07-21) واعتماد باك إند PHP (2026-07-27). لا يُورَّث سطر دارت
من apps/*-archive-cubit، وسيرو مرجع بصري وسلوكي لا مصدر نسخ.

الوثائق:
- docs/37: الخطة الكاملة بستّ مراحل وبواباتها
- docs/38: عقد الـAPI من 37 controller، معظمه متحقَّق حيّاً من السيرفر المنشور
- docs/39: جرد 202 شاشة في تطبيقَي سيرو، مصنّفة داخل/خارج النطاق

الطبقة الأصلية منقولة من *-archive-cubit وحدها لأنها هوية النشر:
- rider_new  → com.mobileapp.store.ride · shorebird 496cb3ac
- driver_new → com.sefer_driver (أندرويد) · com.sefer.driver (iOS) · 68cc9345
- أُصلح تعارض: هدف RunnerTests في driver_new كان يحمل bundle الراكب

الأصول مصدرها *-archive-cubit لا سيرو: أصول الأرشيف مجموعة أشمل (كل صور
سيرو + صور تريبز) وخطوطها هي خطوط docs/26. استُكمل السائق بعشرة ملفات
ناقصة من سيرو (شعارات مزوّدي الدفع + صوتان).

lib/ مكتوب من الصفر (11 ملف لكل تطبيق):
- AppConfig بأعلام const — أساس نموذج lite/pro/max
- TokenStore على التخزين الآمن، يقرأ exp محليّاً بلا حزمة خارجية
- AuthInterceptor بتجديد استباقي وطلقة واحدة — عمر التوكن 15 دقيقة فقط
- ApiClient و ApiException يفهم مصفوفة message في NestJS

flutter analyze نظيف في التطبيقين. البناء الفعلي لم يُجرَّب بعد: بوابة
المرحلة 1 تتطلّب البناء على السيرفر، والوصول إليه غير متاح حالياً.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Hamza-Ayed
2026-08-04 21:21:26 +03:00
co-authored by Claude Opus 5
parent 1243e5a3b2
commit 69da4abc01
379 changed files with 15686 additions and 0 deletions
@@ -0,0 +1,36 @@
/// إعداد البناء — كل قيمة هنا `const` تُمرَّر عبر `--dart-define` عند البناء.
///
/// هذا هو أساس نموذج lite/pro/max (docs/37 §6.25): بناء مولَّد بأعلام ثابتة،
/// لا فروع كود. القيم الافتراضية تشير للسيرفر التجريبي.
class AppConfig {
const AppConfig._();
/// أصل الـAPI **مع** `/api` — كما في docs/38.
static const String apiBaseUrl = String.fromEnvironment(
'API_BASE_URL',
defaultValue: 'https://tripz-api.intaleqapp.com/api',
);
/// أصل الـWebSocket — بلا `/api` (docs/38 §9).
static const String wsBaseUrl = String.fromEnvironment(
'WS_BASE_URL',
defaultValue: 'https://tripz-api.intaleqapp.com',
);
/// **slug** المستأجر لا الـUUID — مصيدة docs/38 §12.9.
static const String tenantSlug = String.fromEnvironment(
'TENANT_SLUG',
defaultValue: 'siro',
);
/// يحدّد هوية المستخدم على الخادم: نفس الرقم بدورين = حسابان منفصلان
/// (docs/38 §1). **يُثبَّت عند البناء ولا يتغيّر في وقت التشغيل أبداً.**
static const String appRole = 'rider';
/// هامش التجديد الاستباقي. عمر التوكن 15 دقيقة فقط (docs/38 §2)، فالانتظار
/// حتى 401 يعني فشل طلب في منتصف رحلة.
static const Duration tokenRefreshLeeway = Duration(seconds: 60);
static const Duration connectTimeout = Duration(seconds: 20);
static const Duration receiveTimeout = Duration(seconds: 30);
}