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

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