docs: backend backlog from owner review + Siro schema comparison (17)

Groups: A realtime/FCM/Redis/race · B trip model (started/waiting/price split/stops) · C driver+car data (color_hex, ai_data) · D security (phone normalize EG, device fingerprint, HMAC) · E fraud (driver_ride_scam) · F chat

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-17 01:42:04 +03:00
co-authored by Claude Opus 4.8
parent 6116d23d0c
commit b7e91e5de6
+86
View File
@@ -0,0 +1,86 @@
# 17 — Backlog الباك إند (مراجعة المالك + مقارنة سيرو)
> مصدره: مراجعة المالك (2026-07-17) + قراءة مباشرة لجداول سيرو (`schema_primary.sql`, `schema_ride.sql`).
> الترتيب حسب الأثر. نمشي **مجموعة مجموعة**.
---
## المجموعة A — الزمن الحقيقي والإشعارات (الأعلى أولوية)
> شكوى المالك الأساسية: «تسأل القاعدة كثيراً، أقرب للـ polling»، والإشعارات ناقصة.
| # | البند | التفصيل |
|---|-------|---------|
| A1 | **FCM على كل حالات الرحلة** | حالياً push عند `assigned` فقط. المطلوب: FCM **+** WebSocket على **كل** انتقال. ضروري للخلفية (background). |
| A2 | **ترجمة الإشعارات** | الإشعارات تُرسل إنجليزي والهاتف عربي → نصوص الإشعارات في **ملفات ترجمة** وتُرسل حسب لغة المستخدم. |
| A3 | **تقليل استعلامات القاعدة** | حالة الرحلة الجارية + المواقع في **Redis**؛ القاعدة للحقيقة الدائمة فقط. (الآن كل انتقال يقرأ/يكتب عدة مرات + يقرأ السائق ثانيةً). |
| A4 | **Race condition عند القبول** | سائقان يقبلان بنفس اللحظة → **قبول ذرّي** (Redis SETNX / UPDATE شرطي `WHERE status='searching'`). أول قبول يفوز، والثاني يُرفض بوضوح. |
| A5 | **إلغاء العرض عند القبول** | فور القبول: بث WebSocket **+ FCM** لبقية السائقين المعروض عليهم → «الرحلة لم تعد متاحة» فتختفي من شاشتهم/الـ overlay. |
| A6 | **الرحلات المتاحة (available rides)** | قائمة طلبات متاحة يسحبها السائق (بديل/مكمّل للعرض المباشر). |
| A7 | **overlay أندرويد** | معلومات الرحلة للقبول/الرفض فوق التطبيقات — يحتاج FCM data-message + payload كامل. |
---
## المجموعة B — اكتمال نموذج الرحلة
> مقارنة بجدول `ride` في سيرو + قواعد التشغيل.
| # | البند | التفصيل |
|---|-------|---------|
| B1 | **حالة `started` وفصل الوصول عن البدء** | السائق وصل ≠ الرحلة بدأت. الراكب قد لا يرد/يلغي. نحتاج تمييزاً صريحاً. |
| B2 | **عدّاد انتظار 5 دقائق (قانون)** | يبدأ عند وصول السائق (بعد **تأكيد المسافة** من فلاتر). عند انتهائه: خيار للراكب — يبقى السائق منتظراً، أو **تعويض** فترة الانتظار. |
| B3 | **احتساب مشوار الوصول للراكب** | المسافة/الزمن من موقع السائق حتى الراكب تُحتسب بالتعرفة (دقائق + مسافة). |
| B4 | **نقاط توقف (stops)** | نقطتا توقف ضمن الرحلة (كما في سيرو/شير). |
| B5 | **حجز مسبق/جدولة** | جداول الرحلة (`date`/`time`/`endtime` في سيرو). |
| B6 | **فصل السعر** | `price_for_driver` مقابل `price_for_passenger` (العمولة) — **ناقص عندنا**. |
| B7 | **طوابع زمنية دقيقة** | `DriverIsGoingToPassenger` · `rideTimeStart` · `rideTimeFinish` (سيرو) — عندنا `assigned_at`/`completed_at` فقط. |
| B8 | **مطابقة الوجهة** | `is_destination_match` + خصم الراكب. |
| B9 | **تعديل التعرفة من لوحة الأدمن** | جداول تعرفة قابلة للتحرير (موجودة كـ jsonb — نحتاج واجهة/نقاط CRUD). |
---
## المجموعة C — بيانات السائق والمركبة (من سيرو)
| # | البند | التفصيل |
|---|-------|---------|
| C1 | **CarRegistration كامل** | `vin` · `car_plate` · `make` · `model` · `year` · `expiration_date` · **`color` + `color_hex`** (لتلوين السيارة في فلاتر) · `owner` · `fuel` · `isDefault` · `vehicle_category_id` · `fuel_type_id` · `status`. |
| C2 | **حقول السائق** | `gender` · `national_number` (فريد) · `name_arabic` · `first/last_name` · `birthdate` · `license_type/categories/issue/expiry` · `address` · `accountBank`/`bankCode` · `employmentType` · `maritalStatus` · **`rejected_reason`** (سبب رفض خدمة العملاء). |
| C3 | **`ai_data` + `user_input`** | تخزين مخرجات Gemini الخام **و** ما أدخله السائق — للمقارنة والتدقيق (نمط سيرو). |
| C4 | **صور السيارة ×2** | صورتان للمركبة (لا واحدة). |
| C5 | **فيديو/liveness للوجه** | تأكيد حيّ للوجه (غير السيلفي الثابت). |
---
## المجموعة D — الأمان والمصادقة
| # | البند | التفصيل |
|---|-------|---------|
| D1 | **تطبيع أرقام الهاتف (JO/EG/SY)** | خصوصاً **مصر**: الناس تكتب `01…` بدل `1…` وتظن المفتاح `2` لا `20`. نحتاج normalize احترافي لكل دولة. |
| D2 | **بصمة الجهاز (device fingerprint)** | تُرسل من فلاتر مع **كل** request وتُربط بالجلسة (نمط سيرو: التوكن المسروق لا يعمل على جهاز آخر). |
| D3 | **HMAC للعمليات الحساسة** | خصوصاً **المدفوعات** — توقيع الطلب. |
---
## المجموعة E — كشف الاحتيال (من `driver_ride_scam`)
| # | البند | التفصيل |
|---|-------|---------|
| E1 | **تسجيل زر الاتصال** | `isDriverCallPassenger` لكل رحلة (سيرو). |
| E2 | **ربط الاتصال بالإلغاء** | اتصال ثم إلغاء = مؤشر اتفاق خارج التطبيق. **3 إلغاءات/يوم → إنذار**؛ التكرار → إجراء. |
---
## المجموعة F — الدردشة
| F1 | إشعار الرسالة يُرسل **فقط** إذا لم تكن صفحة الدردشة مفتوحة (المعالجة الأساسية في فلاتر؛ الباك إند يرسل دائماً ويترك القرار للعميل أو عبر presence). |
---
## مؤجَّل عمداً (قرار المالك)
المفاوض الذكي · تدرّج السائق · خصم العمولة — **آخر شيء** (جديدة حتى على سيرو).
---
## ترتيب التنفيذ المقترح
1. **A** (الزمن الحقيقي + FCM + Redis + race) — الأعلى أثراً وأهم شكوى.
2. **B** (نموذج الرحلة: started/انتظار/فصل السعر/الطوابع/stops).
3. **C** (بيانات المركبة والسائق + ai_data).
4. **D** (تطبيع الهاتف + بصمة الجهاز + HMAC).
5. **E** (الاحتيال) ثم **F**.