- docs/00-15: دراسة، بنية، محرك تعرفة، تسعير، نموذج استئجار، تكاملات، بيانات، realtime، خطة، devops، لاندنج، مخاطر، اصطلاحات سيرفر، تدفق نشر - backend/: NestJS 11 على Docker (health + tenants + عزل tenant_id + بادئة tripz_ + Redis DB 3) - apps/rider, apps/driver, dashboards/admin-web, dashboards/superadmin-web (هياكل) - sync-to-server.sh + .gitignore Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4.6 KiB
4.6 KiB
03 — خطة تطبيقات الموبايل (Flutter)
الحزمة التقنية
- Flutter (أحدث مستقر) + Dart 3.
- إدارة الحالة: flutter_bloc — Cubit افتراضياً، Bloc كامل لآلتَي حالة فقط.
- التوجيه: go_router · الحقن: get_it (+ injectable اختياري).
- الشبكة: dio + interceptors (tenant header, auth, retry).
- الخرائط: عميل انطلق (بلاطات vector عبر
maplibre_glأو ما يعادله فوق Martin). - الترجمة: flutter_localizations + ARB، RTL أول درجة.
لماذا Cubit افتراضياً؟
الانتقال من GetX Controller شبه مباشر: Controller → Cubit، update() → emit(state). نكسب قابلية الاختبار (bloc_test) والقبول الصناعي لمنتج يُرخّص ويُدقّق، دون كلفة أحداث Bloc الكاملة في الشاشات الاعتيادية.
أين نستخدم Bloc الكامل (حصراً)
| آلة الحالة | لماذا Bloc |
|---|---|
| دورة حياة الرحلة (راكب) | سلسلة انتقالات مسماة تأتيها أحداث من 3 جهات (المستخدم، socket، مؤقتات) — الأحداث الصريحة تمنع أخطاء التزامن وتعطي سجل انتقالات للتشخيص |
| تدفق العروض/الطلبات (سائق) | نفس السبب: عروض تصل وتنتهي صلاحيتها بتزامن حسّاس |
بنية الحزمة (packages / flavors)
كود موحّد + نكهة لكل مستأجر:
mobile/
├── packages/
│ └── tripz_core/ # مشترك: نماذج، شبكة، تعرفة، خرائط، ثيم، l10n
├── apps/
│ ├── rider/ # تطبيق الراكب
│ └── driver/ # تطبيق السائق
└── flavors/ # إعداد لكل مستأجر (bundle id, ألوان, أيقونة, مفاتيح)
- ما يتغير بالبناء فقط: bundle id، الأيقونة، اسم التطبيق، مفاتيح FCM → في الـ flavor.
- ما يمكن جعله ديناميكياً: النصوص، الميزات المفعّلة، طرق الدفع، التعرفة، الألوان → يُجلب من
GET /tenant/configعند الإقلاع. - درء رفض آبل (بند 4.3): كل نكهة بأصول ومحتوى متجر مميّز؛ خيار «التطبيق الجامع» (راكب واحد يضم مشغّلين) للباقة المجانية.
طبقات كل تطبيق
lib/
├── main_<flavor>.dart # نقطة دخول لكل نكهة
├── app.dart # MaterialApp.router + ثيم + l10n
├── core/ # DI, router, dio client, config bootstrap
├── data/ # repositories, data sources, models (DTO↔domain)
├── domain/ # entities, use cases (نقية)
└── features/
├── auth/ # cubit + screens
├── home/ # الخريطة + طلب رحلة
├── trip/ # ★ TripBloc (Bloc كامل) + شاشات دورة الرحلة
├── offers/ (سائق) # ★ OffersBloc (Bloc كامل)
├── earnings/ (سائق) # cubit
├── wallet/ # cubit (P3)
├── chat/ rating/ profile/ settings/ # cubits
الشاشات الأساسية (P1)
الراكب: onboarding/OTP → الخريطة والطلب → اختيار الوجهة والسعر المقفول → انتظار الإسناد → تتبع حي → دردشة → إنهاء ودفع كاش → تقييم · العناوين المفضلة · السجل. السائق: OTP → تسجيل بالوثائق → الحالة (متصل/مشغول) → استقبال العرض → التوجّه/الوصول → بدء/إنهاء الرحلة → الأرباح.
قواعد الهندسة
- لا منطق عمل في الـ Widgets — في الـ Cubit/Bloc والـ use cases.
- الثيم والنصوص من config حيث أمكن — لا قيم مبعثرة.
- RTL افتراضي، اختبار كل شاشة بالعربية أولاً.
- اختبار:
bloc_testلكل Cubit/Bloc حرج + golden tests للشاشات الرئيسية. - تجريد الخرائط في
tripz_core/mapsلتبديل المزوّد لأي مستأجر خارج تغطية انطلق.
← السابق: 02-backend-plan · التالي: 04-tariff-engine