# 28 — برومت بناء تطبيقَي فلاتر (يُسلَّم لنموذج البناء كما هو) > **طريقة الاستعمال**: افتح جلسة جديدة لنموذج البناء وجذر عمله `~/development/App/Tripz`، وألصق كل ما تحت الخط. المالك يراجع مخرجات كل مرحلة قبل الإذن بالتي تليها. > كُتب 2026-07-19 بإملاء المالك، وكل بند فيه مسنود إلى وثيقة ملزمة في `docs/`. --- أنت مكلَّف ببناء تطبيقَي **Tripz**: الراكب (`apps/rider`) والسائق (`apps/driver`) — فلاتر، من الصفر على مستوى Dart، فوق باك إند NestJS **مكتمل وجاهز** على `https://tripz-api.intaleqapp.com/api`. المطلوب تطبيق نقل ركاب بمستوى عالمي: سهل، مفهوم، واضح، وفيه **إبداع حقيقي في الخريطة وتجربة الطلب** — لا قالب جاهز. ## 1. اقرأ قبل أول سطر كود — بهذا الترتيب، كاملةً 1. **`docs/23-flutter-conventions.md`** — قانون الكود المُلزِم: البنية، Cubit/Bloc، طبقة الشبكة، أعلام الميزات، **§15 القناة المزدوجة** (جوهر هذا البناء). أي تعارض بينه وبين اجتهادك يُحسم له. 2. **`docs/26-flutter-design-system.md`** — قانون الشكل: tokens · `TripzScaffold` · عدة `core/ui/` · الخطوط (Inter + IBM Plex Sans Arabic مضمّنة محلياً) · ليلي/نهاري · RTL/LTR · ARB. 3. **`docs/22-full-product-roadmap.md` §1.5 والمجموعة Q** — الطبقات وأعلام `const` والتسجيل المشروط. 4. **`docs/27-feature-catalog.md`** — كتالوج الميزات: ما هو أساسي ثابت وما هو مفتاح مدفوع. 5. **`docs/03-mobile-plan.md`** — أين Cubit وأين Bloc كامل (حصراً: دورة رحلة الراكب + عروض السائق). 6. **مستودع سيرو المرجعي** `~/development/App/Siro`: `siro_rider/` و`siro_driver/` — **تدرس السلوك ولا تنسخ الكود** (GetX محظور عندنا). عليك خصوصاً فهم: - `location_controller.dart` في تطبيق السائق: تسجيل كل 3 ثوانٍ · رفع دفعات كل دقيقتين · وعي بالبطارية (تخفيف عند 20٪) · سوكت للبث الحي + دفعات للحفظ. هذا النمط مثبت بالإنتاج — **يُنقل سلوكه حرفياً** إلى Cubit/Bloc. - كيف يعرض سيرو الرحلة على السائق، وكيف يرسم المسار، وكيف يتصرف عند ضعف الشبكة. 7. **حزمة الخرائط `intaleq_maps`** (pub.dev، إصدار 2.2.0، حزمة المالك نفسه فوق MapLibre GL) — واجهتها `LatLng`/`Marker`/`Polyline`/`CameraUpdate` بديل drop-in لخرائط جوجل. 8. **`backend/src/realtime/realtime.gateway.ts`** — أسماء أحداث السوكت الحقيقية: `trip:join` · `trip:update` · `trip:offer` · `trip:offer_taken` · `trip:new` · `driver:location` · `call:offer/answer/ice/end`. لا تخترع اسم حدث — اقرأه من هناك. ## 2. القيود الصلبة — لا تفاوض فيها - **Cubit افتراضاً، Bloc لآلتَي الحالة فقط. لا GetX إطلاقاً.** بنية المجلدات حرفياً من docs/23 §1. - **`intaleq_maps` حصراً.** ممنوع `flutter_map` و`latlong2` و`google_maps_flutter` (تصادم أنواع موثّق في docs/23 §6). - **تقسيم الخرائط**: البلاطات من التطبيق إلى انطلق مباشرة؛ **geocode / reverse / route / places / autocomplete كلها عبر سيرفرنا** (`/maps/*`) — مكيّشة Redis وأسرع من النداء المباشر. مفتاح الخريطة من الإعداد، لا في الكود. - **الطبقة الأصيلة لا تُمسّ**: `android/` · `ios/` · `trip_overlay_plugin` · `bubble-master` · `secure_string_operations` · `key/` · `shorebird.yaml` · ملفات Firebase — كلها قائمة ومختبَرة، تُستدعى ولا تُعاد كتابتها. - **طبقة الشبكة نقطة واحدة** (`core/api/api_client.dart`): `x-tenant-id` من `BuildConfig` · Bearer · `x-device-id` · توقيع HMAC للنقاط المالية (على الجسم كما يُرسل) · تجديد 401 مرة واحدة. التوكنات في `flutter_secure_storage`. - المصادقة **هاتف + OTP فقط** — لا كلمة مرور، لا Google/Apple. - **أعلام ميزات `const` + تسجيل مشروط** في DI والراوتر (docs/23 §5). كل ميزة من كتالوج docs/27 §3 خلف علمها. - **لا بناء ولا اختبار على الجهاز** — أنت تكتب، والمالك يبني ويشغّل ويعيد إليك النتائج. - لا منطق تسعير ولا حساب عمولة ولا قرار مطابقة في Dart — السيرفر مصدر الحقيقة، والتطبيق يعرض. ## 3. القلب المعماري: القناة المزدوجة بسباق داخلي (docs/23 §15 — طبّقه حرفياً) كل حالة رحلة تصل من قناتين متوازيتين: **WebSocket** (`trip:update`) و**FCM data-message** — والسيرفر يرسلهما معاً على كل انتقال أصلاً. المطلوب في التطبيق: 1. **مدخل موحّد** (`TripEventMerger`) يصبّ في `TripBloc` (راكب) و`OffersBloc` (سائق): أيّ القناتين سبقت فحدثها يُطبَّق فوراً. 2. **آلة حالة رتيبة** تحسم الازدواج والتعاكس: حدث يحمل حالة أقدم من أو تساوي المعروضة يُهمل بصمت. ترتيب الحالات في `backend/src/modules/trips/trips.service.ts`. 3. **صمام المصالحة**: `GET /trips/:id` عند عودة التطبيق من الخلفية وعند إعادة اتصال السوكت + مؤقّت خفيف **أثناء الرحلة النشطة فقط** (25 ثانية افتراضاً، قابل للضبط، معطّل خارج الرحلة). 4. **الفتح البارد**: `GET /trips/mine` لاستئناف رحلة غير منتهية + `GET /trips/rating/pending` — إن وُجدت رحلة بلا تقييم تُفرض شاشة التقييم **قبل** أي شيء آخر. 5. **عرض الرحلة على السائق** بنفس المبدأ: `trip:offer` عبر السوكت + FCM dataOnly بحمولة كاملة (نقاط، مسافة، أجرة، فئة، دفع) → الأسبق يعرض البطاقة/الـoverlay. القبول ذرّي على السيرفر — من خسر السباق يصله `trip:offer_taken` فتختفي البطاقة فوراً مع رسالة لطيفة «الرحلة لم تعد متاحة». ## 4. التصميم — المرجع البصري DiDi، والفلسفة docs/26 §8 **النموذج الذهني**: نظافة DiDi وبساطته — خريطة تملأ الشاشة، bottom sheet يقود كل التفاعل، معلومة واحدة كبيرة واضحة في كل لحظة، الأفعال في متناول الإبهام. كل شاشة داخل `TripzScaffold`، كل مكوّن من `core/ui/`، كل نص عبر ARB، ليلي/نهاري كاملان (الخريطة تبدّل ستايلها مع الثيم)، RTL/LTR يتبعان اللغة. **الشاشات المفصلية التي يُحكم عليك بها** (تُبنى بعناية فائقة): | الشاشة | المطلوب | |--------|----------| | **الهوم (راكب)** | خريطة كاملة، دبوس موقعي، sheet سفلي بسؤال واحد: «إلى أين؟» | | **اختيار الوجهة** | أوتوكومبليت عبر `/maps/places` بـdebounce ~300ms + كاش محلي للنتائج الأخيرة + عناوين مفضلة (البيت/العمل) + خيار «اختر من الخريطة» بدبوس يُسحب. دعم نقاط توقف (stops). | | **عرض الفئات والسعر** | `POST /tariff/quote`: بطاقات الفئات (عددها حسب المستأجر — علم) بسعر مقفول لكل فئة، اختيار الدفع (كاش/محفظة)، حقل كوبون، خيار جدولة. | | **البحث عن سائق** | حالة `searching` بحركة نبض على الخريطة + مهلة واضحة + إلغاء سهل. | | **قبول السائق** | بطاقة السائق: صورة، اسم، تقييم، المركبة ولونها **ولوحتها بارزة**، ETA حي، مسار وصول السائق مرسوماً، أزرار اتصال/دردشة. | | **وصول السائق** | «وصل سائقك» + عدّاد الدقائق المجانية الخمس ظاهر بصدق (B2) — الراكب يرى ما سيُحاسب عليه قبل حدوثه. | | **أثناء الرحلة** | تتبّع حي: ماركر السائق يتحرك بانسياب (tween بين النبضات)، **البولي لاين يُعاد رسمه عند انحراف السائق عن المسار** (route جديد عبر السيرفر عند تجاوز عتبة انحراف — لا على كل نبضة)، الكاميرا تتبع بذكاء مع زر إعادة توسيط. | | **الإنهاء/الفاتورة** | تفصيل الأجرة **كما جاء من السيرفر حرفياً**: الأجرة، الانتظار الزائد، الخصم، طريقة الدفع — أرقام Inter tabular لا ترقص. | | **التقييم** | نجوم + أسباب سريعة اختيارية — وتُفرض عند الفتح إن كانت معلّقة. | **الدراور (القائمة الجانبية)** — للطرفين: رحلاتي (سجل بفلاتر) · المحفظة · الكوبونات والدعوات (كود الإحالة) · الإعدادات (لغة/ثيم) · الدعم. **يضاف للسائق**: الأرباح · الرصيد التشغيلي والشحن (مع حالة الحجب عند تجاوز الأرضية) · وثائقي ومركبتي. **مساحة الإبداع المطلوبة منك** (هنا تُظهر مستواك، ضمن قوانين 26): مظهر الخريطة وستايلاها ليلاً ونهاراً، حركة الكاميرا والانتقالات بين مراحل الرحلة، الماركرات المتحركة، إخراج لحظة «تم القبول» و«وصل السائق» بحيث تُحَسّ لا تُقرأ فقط. ## 5. خصوصيات تطبيق السائق - **متحكّم الموقع** بنمط سيرو المذكور في §1.6 — Redis عبر `driver:location` على السوكت، ولا يفتح اتصالاً لكل نبضة. - **online/offline** واضح، ومع الحجب لتجاوز أرضية الرصيد تُعرض رسالة السبب وزر الشحن — لا فشل صامت. - **الـoverlay** فوق التطبيقات عبر `trip_overlay_plugin` القائم — يُستدعى من Dart، لا يُعاد بناؤه. - **الرحلات المتاحة**: قائمة `GET /trips/available` كمكمّل للعرض المباشر. - **التسجيل بالوثائق**: رفع المستندات والصور (صورتان للمركبة كحد أدنى) وفيديو حيوية الوجه — والسيرفر يتولى Gemini؛ التطبيق يعرض ما استُخرج (`ai_data`) مقابل ما أدخله السائق للمطابقة. ## 6. مراحل التسليم — بوابات مراجعة إلزامية توقّف في نهاية كل مرحلة وسلّم تقريراً بما بُني (شاشات، ملفات، قرارات) وانتظر مراجعة المالك: | المرحلة | النطاق | معيار القبول | |---------|--------|--------------| | **0** | نظام التصميم: docs/26 §11 (خطوط · tokens · typography · TripzColors · buildTheme · TripzScaffold · عدة ui · ARB · SettingsCubit) + إعادة صياغة auth/home القائمتين فوقه | كل قائمة 26 §9 | | **1** | الراكب: الهوم بالخريطة + اختيار الوجهة والأوتوكومبليت + الفئات والأسعار + إنشاء الطلب حتى `searching` | تجربة الطلب كاملة بلا سائق | | **2** | دورة الرحلة كاملة للراكب + **القناة المزدوجة والمصالحة** + الفاتورة + التقييم الإجباري | قطع الشبكة/قتل التطبيق في أي مرحلة ثم العودة = الحالة الصحيحة تُستأنف | | **3** | السائق: العروض (سوكت+FCM+overlay) + التنفيذ + متحكّم الموقع + الرصيد | رحلة كاملة من الطرفين على جهازين | | **4** | الدراور وملحقاته للطرفين + الدردشة والاتصال (`call:*` قائم على السوكت) + وثائق السائق | قائمة docs/23 §12 لكل ميزة | **في كل مرحلة**: قائمتا التحقق docs/23 §12 وdocs/26 §9 شرط تسليم، والمالك يبني release ويجرّب — رتّب كودك ليُختبر على أول بناء. ## 7. ممنوعات صريحة (تُرفض المراجعة عند أيٍّ منها) GetX · `flutter_map`/`latlong2` · `google_fonts` الشبكية · نداء HTTP خارج `ApiClient` · لون hex أو رقم مسافة خارج tokens · نص مرئي خارج ARB · `Scaffold` خام في `features/` · استيراد متقاطع بين الميزات · تعديل الطبقة الأصيلة أو الهويات (`applicationId` · bundle ID · shorebird) · نسخ كود من سيرو · أي منطق مالي في Dart · الاستماع للسوكت أو FCM من داخل شاشة مباشرة (كل شيء عبر الـBloc الموحّد). --- ← ذو صلة: [23-flutter-conventions](23-flutter-conventions.md) · [26-flutter-design-system](26-flutter-design-system.md) · [27-feature-catalog](27-feature-catalog.md) · [22 §Q](22-full-product-roadmap.md) · **تفصيل المرحلة 1 للراكب: [29-rider-phase1-prompt](29-rider-phase1-prompt.md)**