Files
tripz-llc/docs/28-flutter-build-prompt.md
T

14 KiB

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 · 26-flutter-design-system · 27-feature-catalog · 22 §Q