feat: implement core architecture, design system, localization, and trip features for both driver and rider apps.

This commit is contained in:
Hamza-Ayed
2026-07-19 16:21:58 +03:00
parent 959e2fa758
commit c4dfeb4c6f
207 changed files with 14017 additions and 5567 deletions
+23
View File
@@ -364,6 +364,29 @@
---
## المجموعة N — مراجعة دفعة النموذج الآخر (غير مرفوعة، 2026-07-19) 🔴 قواطع نشر
> دفعة كبيرة **غير committed** بناها نموذج آخر: cron موحّد على BullMQ (O5) · تسعير ديناميكي (L4) · شرائح سائقين (M2 في docs/22) · كتالوج ميزات (N6/N7) · محرّك تسويق (O3) · بوتات (O4) · بوابة transit (O2) · خريطة حرارية (O1) · كنس searching (R1) · تسجيل صوتي (R2) · تقارير مستأجر (P4) · بوابتا MTN/SyriaTel (P1). راجعتُ كل ملف سطراً سطراً بدل قبول الادّعاء. **لا تُرفع قبل حل N1–N3.**
| # | البند | التفصيل | الحالة |
|---|-------|---------|--------|
| N1 | **لا migrations لأي إضافة** | 7 جداول جديدة بلا migration (`job_executions` · `surge_states` · `bot_tasks` · `feature_catalog` · `ride_type_catalog` · `campaigns` · `trip_audios`) + 4 أعمدة جديدة على `tripz_drivers` القائم (`tier`/`tier_score`/`total_trips`/`acceptance_rate` في `drivers/entities/driver.entity.ts`). الأخطر: أعمدة `drivers` الجديدة تكسر **كل** استعلام سائق قائم بعد النشر، لا الميزات الجديدة فقط. | 🔴 |
| N2 | **خطأ TypeORM يمنع الإقلاع** | `tariff/entities/surge-state.entity.ts` — `manual_note: string \| null` بلا `type:` صريح في `@Column` → `DataTypeNotSupportedError` (نفس الفخ الموثّق: union type بلا `type:` صريح). | 🔴 |
| N3 | **BullMQ + ioredis keyPrefix ممنوع** | `common/cron/bull.module.ts` و`cron-worker.service.ts` يمرّران `keyPrefix` على اتصال BullMQ — المكتبة تمنع هذا صراحة (العزل مضمون أصلاً بـ`db: 3` + خيار `prefix: 'tripz_'` الموجود بجانبه). حذف سطر `keyPrefix` من الاتصالَين يكفي. | 🔴 |
| N4 | **Surge L4 بلا مغذّي** | `SurgeService.incrementDemand` بلا أي مستدعٍ في كل الكود → `demand_count` يبقى صفراً للأبد، فالمضاعف يبقى 1.0 دائماً رغم كرون يعمل كل 3 دقائق بلا فائدة. | 🔴 وظيفياً |
| N5 | **Tiers تكسر Redis-first** | `total_trips`/`acceptance_rate` لا يحدّثهما أي كود بعد رحلة. **والأخطر**: `matching.service.ts` صار يقرأ Postgres داخل `findNearby` — كسر صريح لقاعدة Redis أولاً في أسخن مسار عندنا (المجموعة H). الفرز بالشريحة أولاً يعني سائقاً بعيداً 9كم يسبق آخر على 200م. **الشرائح مؤجَّلة بقرار سابق — بُنيت دون إذن.** | 🔴 + قرار مطلوب |
| N6 | **حملات إعادة التفاعل فارغة** | `cron-worker.service.ts` ينادي `runCampaign(id, [])` بقائمة مستخدمين فارغة دائماً → «تنجح» بصفر إرسال. لا منطق استهداف مبني. | 🟡 |
| N7 | **بوتات O4 وهمية** | تُعلَّم `completed` فوراً برسالة ثابتة — هيكل CRUD فقط، لا تكامل منصّة فعلي. | 🟡 هيكل فقط |
| N8 | **بوابتا MTN/SyriaTel متخيَّلتان** | MTN خرجت من سوريا فعلياً، وواجهة SyriaTel e-payment المفترضة غير موثّقة — كلاهما سيسقط دائماً لوضع invoice (آمن تشغيلياً لكن ليس "منجزاً"). مسار سوريا الحقيقي المُثبَت هو SMS+Gemini (I8/P2). | 🟡 قرار مطلوب |
| N9 | **استحقاقات غير مقفلة** | كل الكونترولرات الجديدة (marketing/bots/tiers/transit/heatmap/surge) بلا `FeatureGuard` رغم استعماله في payments/chat/dispatch. ومفاتيح الكتالوج الجديد (`dynamic_pricing`/`geofence`/`negotiator`/`driver_assurance`/`coupons`) غائبة عن `FEATURES`، و`marketing_engine` بالعكس — بيع ميزة من الكتالوج لن يُفعّل شيئاً. | 🔴 أمني/مالي |
| N10 | **تفاصيل تكوين صغيرة** | `transit.serviceUrl` غير معرَّف في configuration.ts/.env.example (يضرب localhost:4020 داخل الحاوية) · مفتاح ترجمة `trip.audio_recording_started` غائب عن i18n · متغيرات `TRIP_SURGE_*` موثّقة في .env.example لكن `CRON_SCHEDULES` ثابتة بالكود ولا تقرأها. | ⏳ |
| N11 | **ما هو سليم فعلاً من الدفعة** | R1 (كنس searching) مبني صح بالكامل (UPDATE شرطي + تنظيف Redis + إشعار + i18n) ✓. بنية O5 (سجل تنفيذ لكل مهمة + orphan marking + concurrency=1) صحيحة بعد حل N3 ✓. B9 (نسخ تعرفة version+1) ✓. L3 الوزن في المحرك مع اختبارات ✓. P4 التقارير — كل أعمدة الرحلة/الدفع المستخدمة موجودة فعلاً ✓. N6/N7 (الكتالوج+الحاسبة، زرع idempotent) ✓. | ✅ |
**قرارات مطلوبة منك قبل المتابعة**: (أ) هل نُبقي N5 (tiers) رغم التأجيل السابق أم نُزيل المطابقة ونُبقي الأعمدة فقط؟ (ب) N8 — نحذف MTN/SyriaTel ونكتفي بـ`InvoiceAdapter` حتى واجهة موثّقة، أم نُبقيهما best-effort مع fallback واضح؟
**تطبيقا Flutter (نفس الدفعة، خارج نطاق هذا الملف الباك-إندي لكن يُذكر للربط)**: تطبيق السائق نظيف (`flutter analyze` = خطأ هامشي واحد). تطبيق الراكب **126 خطأ ترجمة** (مسارات استيراد models/tokens خاطئة، `flutter_gen` ملغى، `const` على دالة، خصوصية معرّفات `_` عبر ملفات) — تفصيل كامل ومعالجة في برومت منفصل سُلِّم لنموذج فلاتر. قناة FCM (docs/23 §15) غير موصولة إطلاقاً في التطبيقين رغم بناء نصف القرار (merger + مصالحة + فتح بارد).
---
## مؤجَّل عمداً (قرار المالك)
المفاوض الذكي · تدرّج السائق · خصم العمولة — **آخر شيء** (جديدة حتى على سيرو).
**Geofence** — مؤجَّل («لوقتها»)، موجود في سيرو للاستئناس.
+16 -14
View File
@@ -3,7 +3,7 @@
> بعد اكتمال المجموعات A–K (باك إند النواة) واختبار E2E بـ43 محكّاً على السيرفر، هذه خريطة **بقية المنتج**: كل ما في سيرو + طبقة الـSaaS متعددة المستأجرين + تطبيق فلاتر مُعاد بناؤه.
> مبنية على **دراسة كود سيرو الفعلي** لا التخمين. كل مجموعة تُنفَّذ بعد إقرارك، مجموعة مجموعة (أسلوبنا المتّفق).
آخر تحديث: 2026-07-18.
آخر تحديث: 2026-07-19 — تصحيح حالات M3/O2/O5/P على واقع الكود (كانت الوثيقة متأخرة عن الكوميتات)، + ربط كتالوج الميزات [27](27-feature-catalog.md).
---
@@ -93,14 +93,14 @@ Shorebird يرقّع Dart فقط. بتوحيد Kotlin/الصلاحيات/NDK ت
| L1 | **B9**: نقاط CRUD لتحرير التعرفة من لوحة الأدمن (jsonb موجود؛ نحتاج واجهة + تحقّق) |
| L2 | **B10**: كتالوج أنواع رحلات عالمي جاهز (بدل 6 مبثوثة) — المستأجر يختار منه |
| L3 | **B11**: بُعد تسعير بالوزن (شحن/توصيل) بجانب المسافة/الزمن |
| L4 | **التسعير الديناميكي** (من `pricing-engine`): surge حسب الطلب/العرض في المنطقة + مناطق تسعير. add-on مدفوع. محرّكنا يستقبل مضاعف surge. |
| L4 | **التسعير الديناميكي** (من `pricing-engine`): surge حسب الطلب/العرض في المنطقة + مناطق تسعير. add-on مدفوع. 🔵 **جهة الاستقبال جاهزة**: `tariff.engine` يطبّق `surge.multiplier` × مضاعف geofence. الناقص: البوت الذي **يكتب** المضاعف (جرد كرونات سيرو الكامل في [27](27-feature-catalog.md) §4). |
### المجموعة M — ميزات التشغيل المتقدّمة (F سابقاً)
| # | البند |
|---|-------|
| M1 | **المفاوض الذكي**: الراكب يعرض سعراً، السائق يقبل/يفاوض (نمط inDrive). |
| M2 | **شرائح السائقين** (tiers): برونزي/فضي/ذهبي حسب الأداء → أولوية عروض/عمولة أقل. |
| M3 | **السياج الجغرافي** (من `Admin/geofence`): مناطق مسموح/ممنوع · تسعير حسب المنطقة · حظر دخول. |
| M3 | **السياج الجغرافي** (من `Admin/geofence`): مناطق مسموح/ممنوع · تسعير حسب المنطقة · حظر دخول. 🔵 **مبني بالكود** (a15e65c + fef1235، 2026-07-18): `modules/geofence` — Redis pub-sub، `geofence_promo` push عند دخول المنطقة، مضاعف تسعير في `tariff.engine`. الناقص: واجهة أدمن لرسم المناطق (R4 في [27](27-feature-catalog.md)) + إثبات سيرفر. |
| M4 | **تأمين السائق** (`driver_assurance`). |
### المجموعة N — طبقة الـSaaS: السوبر-أدمن وتوليد التطبيق ⭐ (الهدف الأساسي) — 🔵 قيد التنفيذ
@@ -116,7 +116,7 @@ Shorebird يرقّع Dart فقط. بتوحيد Kotlin/الصلاحيات/NDK ت
| N4 | **لوحة أدمن المستأجر (ويب)**: سائقون (اعتماد) · رحلات · مراجعة وثائق · سحوبات (تحويل/فشل). | ✅ `dashboards/admin-web/index.html` + نقاط سرد إدارية (`/drivers/admin/list` · `/trips/admin/list` · `/payouts/admin/list` خلف RolesGuard admin/dispatcher). التعرفة والتقارير تُضاف مع L. |
| N5 | **لوحة خدمة العملاء (ويب)**: بحث مستخدم برقمه (فهرس أعمى) · رحلاته · تفاصيل رحلة بالمعرّف. | ✅ `dashboards/service-web/index.html` + `GET /admin/users/search` · `/trips/admin/list?rider=`. الشكاوى تحتاج وحدة complaints (لا توجد بعد — بند لاحق). |
| N6 | **كتالوج تسعير الميزات** (قرار المالك 2026-07-19): جدول `feature_catalog` — المفتاح · الاسم العربي · الفئة (نواة/باقة/add-on) · **سعر شهري** · رسم إعداد · الوصف — والسوبر-أدمن يحرّر الأسعار من اللوحة. يوسّع K2: الكتالوج نفسه يغذّي الاستحقاقات الافتراضية والتسعير معاً. الإضافات المسعّرة أولاً: استخبار السوق · البوتات/التسويق · التسعير الديناميكي · المواصلات · المفاوض · شرائح السائقين · تأمين السائق. | ⬜ |
| N6 | **كتالوج تسعير الميزات** (قرار المالك 2026-07-19، **أُعيد تأكيده مع قائمة الميزات الكاملة — [27-feature-catalog](27-feature-catalog.md)**): جدول `feature_catalog` — المفتاح · الاسم العربي · الفئة (نواة/باقة/add-on) · **سعر شهري** · رسم إعداد · الوصف — والسوبر-أدمن يحرّر الأسعار من اللوحة. يوسّع K2: الكتالوج نفسه يغذّي الاستحقاقات الافتراضية والتسعير معاً. الإضافات المسعّرة أولاً: استخبار السوق · البوتات/التسويق · التسعير الديناميكي · المواصلات · المفاوض · شرائح السائقين · تأمين السائق. | ⬜ |
| N7 | **مولّد عرض السعر (الفوترة التعاقدية)**: في لوحة السوبر-أدمن — اختيار باقة + إضافات ⇒ عرض سعر مجمّع (إعداد مرة واحدة + شهري) يُطبع/يُرسل للعميل عند التعاقد. عند الاعتماد: تُكتب `tenants.features` آلياً من البنود المختارة (تكامل K3 — لا إدخال يدوي مزدوج ينسى ميزة) + سجل اشتراك شهري يظهر في overview (N1b). | ⬜ |
**مصادقة اللوحتين**: هاتف + OTP → JWT بدور admin/dispatcher (نفس تدفّق الموبايل). كل الحماية على السيرفر (RolesGuard) — الواجهة عرض فقط. الوصول للوحة معيَّن بـ`?tenant=<slug>`.
@@ -128,22 +128,24 @@ Shorebird يرقّع Dart فقط. بتوحيد Kotlin/الصلاحيات/NDK ت
| # | البند |
|---|-------|
| O1 | **تحليل بيانات المواقع**: `driver_tracks` (مبني في H) → خرائط حرارية · تنبّؤ الطلب · سلوك السائق (H6/H7 المؤجَّلتان). |
| O2 | **نظام المواصلات** (`transit` + وضع الباص): خطوط · محطات · بثّ موقع الباص منفصل. add-on. |
| O2 | **نظام المواصلات** (`transit` + وضع الباص): خطوط · محطات · بثّ موقع الباص منفصل. add-on. 🔵 **microservice مبني** (`backend-transit/` منفصل بقاعدته — f30209b + 4aeab52) + لوحة مشرف. الناقص: التكامل مع تطبيقي الراكب/السائق + كرونات transit الثلاثة ([27](27-feature-catalog.md) §4). |
| O3 | **محرّك التسويق** (`marketing_engine`): بوتات آلية · مولّد تعليقات Gemini · مهام مجدولة · تقارير. add-on. |
| O4 | **البوتات** (`socialBot` · `android_bot`): نسخ + تهيئة كـadd-ons مدفوعة خلف الاستحقاقات. |
| O5 | **مراجعة المهام المجدولة (cron) وترتيبها** — قرار المالك 2026-07-18. تُجرد كل المهام الدورية (تسويات · تقارير · تجميع التقييمات · تنظيف · استخبار السوق والأخبار) في مكان واحد بجدولة موحّدة عبر BullMQ (بادئة `tripz_`). المطلوب: مهمة واحدة لا تعمل مرتين عند تشغيل أكثر من نسخة، وسجلّ تنفيذ يُظهر آخر نجاح/فشل — لا مهام صامتة. |
| O5 | **مراجعة المهام المجدولة (cron) وترتيبها** — قرار المالك 2026-07-18. ✅ **الجرد اكتمل** ([27](27-feature-catalog.md) §4 — 24 كروناً بجدولتها من مستودع سيرو نفسه، ومنها فجوة `cron_ride_timeout` = R1). التوحيد على BullMQ نفسه ⬜. تُجرد كل المهام الدورية (تسويات · تقارير · تجميع التقييمات · تنظيف · استخبار السوق والأخبار) في مكان واحد بجدولة موحّدة عبر BullMQ (بادئة `tripz_`). المطلوب: مهمة واحدة لا تعمل مرتين عند تشغيل أكثر من نسخة، وسجلّ تنفيذ يُظهر آخر نجاح/فشل — لا مهام صامتة. |
### المجموعة P — إكمال المدفوعات (بوابات حقيقية) 💰
> **تُقرأ [24-tenant-wallet-revenue](24-tenant-wallet-revenue.md) أولاً** — فلسفة المال (إيراد مقابل أمانة) تحكم كل بند هنا.
| # | البند |
|---|-------|
| P0 | **محفظتا المستأجر**: `tenant_wallet` (إيراد) و`tenant_pending` (أمانات) كدفترين مضافَين فقط. الفصل بمحفظتين لا بحقل حالة — استعلامٌ ينسى الشرط يجعل المالك يسحب من مال الركّاب. |
| P1 | **بوابات فعلية**: PayMob (مصر) · CliQ (الأردن) · MTN/SyriaTel/شام كاش (سوريا) — جدول لكل وسيلة + محوّل موحّد. |
| P2 | **تسوية بالرسائل** (كليك/شام كاش بلا API): تطبيق أندرويد يرفع الرسالة **خاماً** → webhook → استخراج بـGemini → مطابقة فاتورة. تفرّد على مرجع العملية، وطابور مراجعة لما لا يُطابَق. |
| P3 | **رسم العملية إيراداً**: 35 ل.س · 5 ج.م · 20 قرشاً — **من إعداد المستأجر لا من الكود** (سيرو كتب الرقم مرتين فتناقضا وسرّب مالاً). |
| P4 | **تقارير المستأجر**: الدخل حسب الوسيلة/اليوم · شحن السائقين مقابل الأمانات · العمولات · المعلّق غير المسوّى. |
| P5 | **تصحيح `revenue` في `/admin/overview`**: يحسب عمولة الرحلات فقط؛ الإيراد الحقيقي = عمولة الرحلات + شحن السائقين + رسوم العمليات، والأمانات تُستثنى. |
| # | البند | الحالة |
|---|-------|--------|
| P0 | **محفظتا المستأجر**: `tenant_wallet` (إيراد) و`tenant_pending` (أمانات) كدفترين مضافَين فقط. الفصل بمحفظتين لا بحقل حالة — استعلامٌ ينسى الشرط يجعل المالك يسحب من مال الركّاب. | ✅ مبني بالكود (b1a060c — `modules/tenant-wallet`) |
| P1 | **بوابات فعلية**: PayMob (مصر) · CliQ (الأردن) · MTN/SyriaTel/شام كاش (سوريا) — جدول لكل وسيلة + محوّل موحّد. | 🔵 **PayMob + cash + invoice** عبر `payment-gateway.registry` (d4ac38c، مع إغلاق ثغرة webhook). CliQ · MTN/SyriaTel · شام كاش ⬜ |
| P2 | **تسوية بالرسائل** (كليك/شام كاش بلا API): تطبيق أندرويد يرفع الرسالة **خاماً** → webhook → استخراج بـGemini → مطابقة فاتورة. تفرّد على مرجع العملية، وطابور مراجعة لما لا يُطابَق. | ✅ مبني بالكود (da035e4 — `sms-settlement.service` + `raw_sms` + `integrations/gemini`) |
| P3 | **رسم العملية إيراداً**: 35 ل.س · 5 ج.م · 20 قرشاً — **من إعداد المستأجر لا من الكود** (سيرو كتب الرقم مرتين فتناقضا وسرّب مالاً). | ✅ (b1a060c — `transaction-fee.ts` + spec) |
| P4 | **تقارير المستأجر**: الدخل حسب الوسيلة/اليوم · شحن السائقين مقابل الأمانات · العمولات · المعلّق غير المسوّى. | ⬜ |
| P5 | **تصحيح `revenue` في `/admin/overview`**: يحسب عمولة الرحلات فقط؛ الإيراد الحقيقي = عمولة الرحلات + شحن السائقين + رسوم العمليات، والأمانات تُستثنى. | ✅ (b1a060c) |
> **ملحق P (2026-07-18، غير مخطط أصلاً)**: وحدة **billing** كاملة لاشتراكات المستأجرين أنفسهم (SaaS): `tenant-subscription` + `superadmin-payment` + webhook PayMob + اعتماد حوالة بنكية (d239f51). هذا نصف N6/N7 العملي — الناقص كتالوج الأسعار والحاسبة.
### المجموعة Q — تطبيق فلاتر (إعادة بناء كاملة) 📱
> **إعادة استعمال الأصيل الثابت** (Kotlin/iOS من التطبيق القديم Ride/Tripz)، **وإعادة بناء Dart من الصفر** بـCubit+Bloc (لا GetX).
+12
View File
@@ -210,3 +210,15 @@ if (Features.chat) routes.add(GoRoute(path: '/chat', builder: ...));
## 14. مؤجَّل بقرار المالك (2026-07-18)
- **Android Auto** (موجود في سيرو: `MyCarSession` · `MyCarScreen` · `MyCarAppService`) و**CarPlay** — عليهما مشاكل ولا أولوية لهما الآن. يُنظر فيهما لاحقاً.
---
## 15. القناة المزدوجة للزمن الحقيقي — قرار المالك 2026-07-19 🔒
> السيرفر يرسل كل انتقال حالة **مرتين أصلاً**: WebSocket (`trip:update`) + FCM data-message (A1/A7). التطبيق يستثمر الاثنتين معاً — لا يختار واحدة.
1. **من يسبق يفوز.** مدخل موحّد واحد (`TripEventMerger` داخل `TripBloc`/`OffersBloc`) يستقبل من القناتين ويطبّق الحدث الأسبق وصولاً. عرض الرحلة للسائق كذلك: `trip:offer` عبر السوكت + FCM dataOnly بالحمولة الكاملة → أيّهما وصل أولاً يعرض الـoverlay.
2. **إزالة الازدواج بآلة حالة رتيبة، لا بمعرّفات.** ترتيب الحالات معروف ثابت (`searching < assigned < driver_arriving < driver_arrived < in_progress < completed < paid`). الحدث الذي يحمل حالة ≤ الحالة المعروضة **يُهمل بصمت**. هذا يحلّ الازدواج والوصول المعكوس معاً بلا تتبّع معرّفات رسائل.
3. **صمام الأمان الثالث: المصالحة (reconciliation).** `GET /trips/:id` تُنادى عند: (أ) عودة التطبيق من الخلفية، (ب) إعادة اتصال السوكت بعد انقطاع، (ج) مؤقّت خفيف **أثناء رحلة نشطة فقط** (افتراضي كل 25 ثانية، قابل للضبط، يتوقف كلياً خارج الرحلة). سؤال المالك «هل يلزم كل فترة؟» — الجواب نعم لكن بهذا الشرط الضيّق: FCM قد يتأخر دقائق في Doze والسوكت قد يموت صامتاً؛ المؤقّت يغطي نافذة فشل القناتين معاً، وكلفته استعلام Redis واحد (A3).
4. **الفتح البارد**: `GET /trips/mine` (استئناف أي رحلة غير منتهية) + `GET /trips/rating/pending` (فرض شاشة التقييم قبل أي رحلة جديدة).
5. **العرض دائماً من حالة الـBloc الموحّدة** — لا شاشة تستمع للسوكت أو FCM مباشرة.
+114
View File
@@ -0,0 +1,114 @@
# 27 — كتالوج الميزات (قائمة المالك 2026-07-19) + جرد كرون سيرو الكامل
> مصدره: إملاء المالك (2026-07-19) لميزات التوليد والتفعيل، + قراءة مباشرة لكل ملفات cron في مستودع سيرو المحلي وجداول الجدولة في `Siro/docs/03_pricing/pricing_system_report.md`.
> هذا المستند يغذّي **N6** (جدول `feature_catalog` والتسعير) و**N7** (مولّد عرض السعر/الحاسبة) و**O5** (توحيد الكرون على BullMQ) و**§1.5 في docs/22** (أعلام `const` للتوليد).
---
## 1. الحاكمية — من يقرّر وماذا يسري
- **السوبر-أدمن** يحدّد الميزات بالاتفاق مع المستأجر/المالك **عند التعاقد**، وتوليد التطبيق (N3) يُخرج نسخة بهذه المواصفات حصراً.
- القاعدة الحاكمة (docs/22 §1.5): **`الفعّال = المبني في الـbinary (أعلام const) ∩ المانيفست الريموت ∩ استحقاقات السيرفر (FeatureGuard)`**. العلم في التطبيق قرار عرض؛ الحدّ الأمني يبقى السيرفر (docs/19).
- التسعير: كل ميزة مدفوعة لها **سعر شهري + رسم إعداد** في `feature_catalog` (N6 — ⬜ لم يُبنَ)، والحاسبة في لوحة السوبر-أدمن (N7 — ⬜) تُخرج عرض السعر وتكتب `tenants.features` آلياً عند الاعتماد. الباقات نناقشها بعد بناء الكتالوج.
---
## 2. الأساسيات الثابتة — في كل نسخة، ليست خيارات
| الميزة | حالة الباك إند |
|--------|----------------|
| Splash / Onboarding | — (فلاتر Q1) |
| تسجيل الدخول والتسجيل (هاتف + OTP، بلا كلمة مرور) | ✅ (D5، متعدد المزوّدين) |
| طلب الرحلة + عرض أسعار الفئات قبل الطلب | ✅ (`POST /tariff/quote` — مُثبَت 72 طلباً على السيرفر) |
| رسم البولي لاين على الخريطة | ✅ (route عبر سيرفرنا + كاش Redis) — الرسم نفسه فلاتر |
| تتبّع السائق الأساسي أثناء الرحلة | ✅ (المجموعة H — Redis فقط، عتبات سيرو) |
| الدفع كاش (الافتراضي الأساسي) | ✅ (`cash.adapter`) |
| التقييم + الدردشة + الإشعارات المترجمة | ✅ (A/F/G) |
---
## 3. الميزات القابلة للتفعيل والبيع (قائمة المالك)
| الميزة (بتسمية المالك) | المفتاح المقترح | حالة الباك إند | ملاحظات |
|------------------------|-----------------|----------------|----------|
| عدد/تشكيلة فئات السيارات المعروضة | `ride_classes_set` | ✅ | `ride_types` لكل مستأجر + تعرفة لكل فئة (M9). الحدّ بالعدد يُضاف كـentitlement رقمي (نمط `drivers_max`) |
| فئات أسعار | `tariff_engine_full` | ✅ | محرّك كامل: نوافذ محلية التوقيت + انتظار + حدّ أدنى مرساة (docs/17-M) |
| التتبّع اللحظي المتقدّم (بولي لاين حيّ يُعاد رسمه مع تغيّر الاتجاه) | `live_tracking_pro` | ✅ باك إند (H) | الضغط الحقيقي محلول (Redis + عتبات). الرسم وإعادة المسار في فلاتر Q2. يُسعَّر لأنه يستهلك route calls |
| التسجيل الصوتي داخل الرحلة | `trip_audio_recording` | ⬜ **بند جديد — لم يكن في أي خطة** | يحتاج: رفع مقاطع + تخزين + سياسة احتفاظ/حذف + إقرار قانوني بالإشعار للطرفين. يُسجَّل في الـbacklog |
| معالجة وثائق السائقين بالذكاء الاصطناعي | `ai_document_processing` | ✅ **مبني بالكود** | `integrations/gemini` + `documents.service` (`extractDocument` + `faceMatch`)، خلف `GEMINI_API_KEY`. `ai_data`/`user_input` (C3) جاهزان |
| معالجة المشاكل/الشكاوى بالذكاء الاصطناعي | `ai_complaints` | ⬜ | **وحدة complaints نفسها غير موجودة** (لوحظ في N5). تُبنى الوحدة أولاً ثم طبقة الـAI فوقها |
| الخريطة الحرارية (سائق) | `heatmap` | ⬜ O1 | المصدر جاهز (`driver_tracks` من H) — يلزم كرون توليد الكاش (نظير `cron_generate_heatmap_cache`) |
| الخريطة التنبؤية | `predictive_demand` | ⬜ O1 | نظير `cron_predictive_demand` (خلايا 0.01° × 4 أسابيع تاريخ) |
| Geofence (رسائل/إعلانات/برومو بالمنطقة + تسعير مناطق) | `geofence` | 🔵 **مبني بالكود** (a15e65c + fef1235) | Redis pub-sub + `geofence_promo` push عند دخول المنطقة + مضاعف تسعير في `tariff.engine`. ينقصه: واجهة أدمن لرسم المناطق + إثبات سيرفر |
| برومو كود عام | `coupons` | ✅ | محرّك الكوبونات (17-L) بسقوف العملات |
| البرومو المتخصص (استهداف شرائح/مناطق/حملات) | `targeted_promo` | 🔵 جزئي | `geofence_promo` موجود؛ محرّك الحملات المجدولة (نظير `auto_marketing_pusher` + `passenger_reengagement`) ⬜ |
| رسائل واتساب + بوت نبيه (تشغيل البوتات) | `whatsapp_campaigns` | 🔵 جزئي | قناة نبيه مبنية (OTP). استعمالها للحملات الجماعية ⬜ — يلزم صندوق حملات + حدود إرسال |
| محرّك التسويق (بوتات اجتماعية + مولّد تعليقات Gemini + تقارير) | `marketing_engine` | ⬜ O3/O4 | نقل `marketing_engine` + `socialBot` + `android_bot` كإضافة مدفوعة خلف الاستحقاقات |
| محرّك التسعير الديناميكي (استخبار المنافسين + surge + ضبط العمولة) | `dynamic_pricing` | ⬜ L4 | محرّكنا **يستقبل** المضاعف جاهزاً (`surge.multiplier` + مضاعف geofence موجودان). الناقص: البوت الذي **يكتب** المضاعف (نظائر `ai_engine`/`surge_opportunity`/`kazan_adjuster`/`pricing_stability`/`seasonal`) |
| المواصلات (خطوط باص) | `transit` | 🔵 **microservice مبني** (`backend-transit/`، f30209b) + لوحة مشرف | التكامل مع تطبيقي الراكب/السائق ووضع الباص ⬜ |
| الدفع بالمحفظة | `wallet_payment` | ✅ | I1 مُثبَت بتزامن حقيقي |
| الدفع عبر البنوك/المحافظ الخارجية | `payment_gateways` | 🔵 | PayMob مبني بالكود (d4ac38c) + registry محوّلات. CliQ · MTN/سيرياتيل · شام كاش ⬜ (P1) |
| التسوية بالرسائل (SMS خام + Gemini) | `sms_settlement` | ✅ **مبني بالكود** (da035e4) | `sms-settlement.service` + `raw_sms` + استخراج Gemini — نمط سيرو مع إغلاق ثغراته |
| المفاوض الذكي · شرائح السائقين · تأمين السائق | `negotiator` · `driver_tiers` · `driver_assurance` | ⬜ مؤجَّلة بقرار المالك («آخر شيء») | docs/22-M |
> **«الشيك القابل للإضافة والتعديل»** الذي ذكره المالك شفهياً: فُهم كوسيلة دفع إضافية قابلة للتفعيل — يُثبَّت تعريفه عند أول جلسة تسعير (بنية `payment_gateway.registry` تستوعب أي وسيلة جديدة كمحوّل).
---
## 4. جرد كرون سيرو الكامل (مقروء من المستودع + جداول سيرو نفسها)
> الهدف: **O5** — كل هذه تتوحّد عندنا في BullMQ (بادئة `tripz_`) بقفل ضد التشغيل المزدوج وسجل تنفيذ. لا `crontab` نظامي متناثر.
### bot/ (التسعير والذكاء) — كلها ضمن `dynamic_pricing` و`heatmap` و`predictive_demand` و`targeted_promo`
| الملف | الجدولة (من وثائق سيرو) | الوظيفة |
|-------|--------------------------|----------|
| `cron_ai_engine` | كل 3 ساعات | يقرأ معادلات المنافسين من pricing-engine ويطبّق تسعيراً ذكياً |
| `cron_pricing_stability_engine` | كل 3 ساعات | **shadow mode** — يصنّف انحراف الأسعار (برومو مؤقت / تغيير حقيقي / مستقر) بلا لمس kazan |
| `cron_seasonal_pricing` | كل ساعة | مواسم (إفطار رمضان ×1.25، أعياد) بتوقيت كل دولة |
| `cron_surge_opportunity` | كل 10 دقائق | يكتشف مناطق ذروة المنافسين ويكتب المضاعف في Redis |
| `cron_kazan_adjuster` | كل 5–10 دقائق | يخفّض العمولة ويضيف حوافز للسائقين في مناطق الذروة |
| `cron_generate_pricing_cache` | دوري | متوسط أسعار المنافسين لكل مربع 2.5كم → Redis |
| `cron_generate_heatmap_cache` | كل 16 دقيقة | كاش الخريطة الحرارية → Redis |
| `cron_predictive_demand` | كل ساعة | تنبّؤ الطلب (نفس اليوم/الساعة × 4 أسابيع) + FCM للسائقين القريبين |
| `cron_empty_results_to_db` | كل ساعة | تفريغ نتائج البوت من ملف إلى القاعدة |
| `cron_passenger_reengagement` | يومياً 10:00 | إشعار Gemini مخصص للخاملين ≥3 أيام (anti-spam 72س في Redis) |
| `cron_auto_marketing_pusher` | كل ساعة | رسالة تسويقية Gemini للّي فتحوا ولم يطلبوا خلال ساعتين |
| `cron_silent_push_inactive` | كل بضع ساعات | push صامت يوقظ التطبيق ليرفع الموقع |
| `cron_dashboard_snapshot` | ساعي/يومي/أسبوعي | أرشفة لقطات التحليلات JSON |
| `cron_weekly_health_report` | الأحد ليلاً | تقرير صحة السوق التنافسية |
| `cron_gemini_advisor` | دوري | تحليل استراتيجي للمعادلات المكتشفة عبر Gemini |
### marketing_engine/ — ضمن `marketing_engine`
| الملف | الجدولة | الوظيفة |
|-------|---------|----------|
| `cron_insert_task` | كل 4 ساعات | يزرع مهام `autonomous_scroll_and_reply` (فيسبوك/إنستغرام) للبوتات |
| `cron_weekly_report` | أسبوعي | تلخيص تقارير التسويق عبر Gemini |
| `telegram_scraper` | كل 3 ساعات | استخراج بيانات من المنصات |
| `generate_10_tasks_cli` | كل 15 دقيقة | توليد مهام مصغّرة للبوتات |
### transit/ — ضمن `transit`
| الملف | الجدولة | الوظيفة |
|-------|---------|----------|
| `cron_approaching_alerts` | كل دقيقة | تنبيه اقتراب الباص من المحطة (<2كم) |
| `cron_cleanup` | يومياً 03:30 | تنظيف الجلسات وسجل OTP المنتهي |
| `cron_sync_members` | يومياً 03:00 | إعادة بناء مجموعات الأعضاء في Redis من القاعدة |
### ride/ + payment_server/ — النواة
| الملف | الوظيفة | موقفنا |
|-------|----------|--------|
| `cron_ride_timeout` | تصفير الرحلات العالقة `waiting` بعد 15 دقيقة | 🔴 **فجوة مؤكّدة عندنا**: `expired`/`no_drivers` انتقالان شرعيان في آلة الحالة (`trips.service.ts`) لكن **لا شيء يطلقهما بمؤقّت** — رحلة `searching` بلا قبول تبقى معلّقة للأبد. المطلوب: sweeper بنمط `ScheduledTripsSweeper` |
| `deleteNewDriverGiftCronJob` | حذف التكرارات يومياً من `driverWallet` | **لا يُنقل** — ترقيع لغياب القيود؛ فهارسنا الفريدة (J6/L2) تمنع التكرار من الأصل |
---
## 5. بنود جديدة سُجّلت اليوم (لم تكن في أي مجموعة)
| # | البند | إلى أين |
|---|-------|---------|
| R1 | **sweeper مهلة البحث** (`searching` → `no_drivers`/`expired`) | نواة — يُبنى فوراً قبل فلاتر، فجوة تشغيلية لا ميزة |
| R2 | **التسجيل الصوتي داخل الرحلة** (رفع + تخزين + احتفاظ + إشعار قانوني) | ميزة مدفوعة — بعد قرار المالك في التخزين والمدة |
| R3 | **وحدة الشكاوى complaints** (أساس لوحة الخدمة N5 ولميزة `ai_complaints`) | نواة الإدارة |
| R4 | **واجهة أدمن لرسم مناطق Geofence** | مكمّل M3 |
---
← ذو صلة: [22-full-product-roadmap](22-full-product-roadmap.md) · [19-entitlements-licensing](19-entitlements-licensing.md) · [17-backend-backlog](17-backend-backlog.md)
+94
View File
@@ -0,0 +1,94 @@
# 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)