Files
tripz-llc/docs/03-mobile-plan.md
T
HamzaandClaude Opus 4.8 95fea546f5 first commit: منصة Tripz — خطط كاملة + سكافولد باك إند NestJS/Docker
- 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>
2026-07-16 15:22:06 +03:00

65 lines
4.6 KiB
Markdown

# 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](02-backend-plan.md) · التالي: [04-tariff-engine](04-tariff-engine.md)