docs: restructure documentation, add digital legacy report, and secure contracts

This commit is contained in:
Hamza-Ayed
2026-07-14 18:45:29 +03:00
parent 540ae4d4bc
commit 48382f5d4a
60 changed files with 2106 additions and 657 deletions
@@ -0,0 +1,181 @@
# مراجعة شاملة لنظام مواصلاتي — 2026-07-12
دراسة كاملة للنظام عبر: الباك اند (`backend/transit/` + `backend/Admin/transit/`)، سيرفرات السوكيت (`loction_server/driver_socket.php` + `passenger_server/passenger_socket.php`)، والتطبيقات الثلاثة (siro_rider / siro_driver / siro_admin).
كل مهمة في القسم الأخير مكتوبة كأمر مستقل جاهز للتنفيذ على نموذج آخر — تحتوي المسارات والسياق الكافي.
---
## 1. جرد ما هو مبني وشغّال
### الباك اند — `backend/transit/` (بوابتان)
| البوابة | المصادقة | الملفات |
|---|---|---|
| `connect_app.php` | JWT الرئيسي (راكب/سائق) + RateLimiter | trip/*, enrollment/activate + my_enrollments, route/for_org, org/browse, driver/me, driver/activate, notification/subscribe |
| `connect_admin.php` | Session token (هاتف + OTP) + CORS | admin/*, vehicle/*, driver/invite + list, route/add + get + list, schedule/add, enrollment/list + approve + import_roster, broadcast/send |
### الباك اند — `backend/Admin/transit/` (فريق سيرو، JWT admin/super_admin)
`org/create` · `org/list` · `org/details` · `org/admins_list` · `org/admin_add` · `org/admin_toggle`
### سيرفرات السوكيت (إضافات فقط، لم يُمس منطق الرحلات)
- سائق الباص: `update_bus_location` مع **تحقق ملكية الرحلة** من `transit:trip:{id}:owner` (يُكتب عند trip/start، يُحذف عند trip/end) — و`route_id` يُؤخذ حصرياً من الكاش الموثوق لا من العميل
- الراكب: `subscribe_transit_route` / `unsubscribe_transit_route` + بثّ `bus_location_update` لغرفة `transit_route_{id}`
- HTTP داخلي: `get_bus_position` (driver_socket) + `broadcast_bus_location` (passenger_socket)
### التطبيقات
- **الراكب**: 4 شاشات (عضوياتي → تصفح مؤسسات وتفعيل بالرقم الجامعي → خطوط → خريطة حية بالسوكيت) + مدخل بالقائمة الجانبية + ترجمات ar_jo/ar_sy/ar_eg
- **السائق**: شاشة رحلات اليوم (بدء/إنهاء/تأخير) + "وضع الباص" داخل LocationController (يحوّل البث لـ update_bus_location ويخرج من حوض الرحلات) + مدخل بالـ Drawer
- **سيرو آدمن**: قائمة مؤسسات + إنشاء مؤسسة + تفاصيل وتحليلات + إدارة مشرفين (إضافة/تعليق مع إبطال جلسات فوري)
---
## 2. أخطاء حرجة أُصلحت في هذه الجلسة (2026-07-12)
| # | الخطأ | الملفات | الأثر قبل الإصلاح |
|---|---|---|---|
| 1 | تضارب تعريف `normalizePhone()` — fatal error | `Admin/rides/admin_get_rides_by_phone.php`, `Admin/rides/monitorRide.php`, `nabeh/resolve_user.php` | **ثلاثة endpoints إنتاجية معطلة تماماً** (منها تكامل نابه مع سيرفر الدفع) — حُذفت التعريفات المحلية لصالح الموحّدة في helpers.php |
| 2 | `schedule/add.php` يُدرج عمود `created_by` غير موجود في `transit_schedules` | `transit/schedule/add.php` | إضافة أي جدول زمني = SQL error دائم |
| 3 | `transit_enrollments.passenger_id NOT NULL` بينما استيراد الكشف يُدرج NULL | `schema_transit.sql` | استيراد كشف الطلاب معطّل بالكامل (+ ALTER للقاعدة القائمة بآخر الملف) |
| 4 | `transit_trips.vehicle_id NOT NULL` بينما الجداول تسمح بجدول بلا باص | `schema_transit.sql` | إنشاء رحلات اليوم يفشل لأي جدول بدون مركبة (+ ALTER) |
| 5 | `driver/list.php` يفك تشفير عمود `phone` غير مُحدد في SELECT | `transit/driver/list.php` | الهاتف لا يظهر أبداً في قائمة السائقين |
| 6 | `org/register.php` يقرأ `SOCKET_INTERNAL_KEY` (اسم خاطئ) بدل `INTERNAL_SOCKET_KEY` | `transit/org/register.php` | التسجيل الداخلي يرفض دائماً 403 — الآن عبر `getInternalSocketKey()` |
نتائج فحص إضافية مطمئنة: `encryptData` **حتمي** (CBC بـ IV ثابت) فمطابقة الهاتف/الرقم الجامعي المشفّر تعمل. مفاتيح Redis متسقة (بادئة `siro:` للجلسات على المثيلين). مسارات AppLink بالتطبيقات الثلاثة تطابق مسارات الباك اند.
---
## 3. الثغرات الأمنية المتبقية (بالترتيب)
### أ. حرجة — IDOR في endpoints رحلات السائق
`trip/today.php` و`trip/start.php` و`trip/end.php` و`trip/delay.php` تستقبل `driver_transit_id` من العميل **دون التحقق أن JWT المتصل هو صاحب هذا المعرّف**. أي مستخدم مسجّل (حتى راكب) يستطيع بدء/إنهاء/تأخير رحلات أي سائق باص بتخمين أرقام تسلسلية. السوكيت محمي بملكية الرحلة، لكن REST مكشوف.
**الإصلاح**: في الملفات الأربعة — اشترط `$transit_user_role === 'driver'` ثم اجلب سجل السائق بـ `WHERE main_driver_id = $transit_user_id` وتجاهل `driver_transit_id` القادم من العميل نهائياً (أو تحقق من تطابقه).
### ب. حرجة وظيفياً — `main_driver_id` لا يُضبط أبداً
`driver/invite.php` يقبله كحقل اختياري يدخله مشرف المؤسسة (لا يعرفه عملياً)، و`driver/activate.php` لا يضبطه. النتيجة: `driver/me.php` يرجع `is_bus_driver=false` للجميع، و`trip/start.php` يرفض بـ 422 — **مسار السائق كامل غير قابل للاستخدام end-to-end**.
**الإصلاح المقترح**: نقطة تفعيل جديدة تعمل بـ JWT السائق (`connect_app.php` + role=driver): يرسل `invite_token` فقط، والباك اند يطابق التوكن ويضبط `main_driver_id = $transit_user_id` تلقائياً. هذا يحل (أ) و(ب) معاً ويلغي الحاجة لـ OTP في التفعيل.
### ج. عالية — التفعيل الحالي `driver/activate.php` بلا مصدر OTP
يتحقق بـ `transitVerifyAdminOtp` لكن لا يوجد endpoint يرسل OTP لهاتف السائق (login_request يشترط وجوده في `transit_org_admins`). المسار ميت — يُستبدل بحل النقطة (ب).
### د. عالية — اشتراك سوكيت الراكب بلا تحقق عضوية
`subscribe_transit_route` في passenger_socket يضم أي راكب مصادَق لأي غرفة خط دون التحقق من عضويته النشطة — تسريب مواقع الباصات لغير المشتركين (REST محمي، السوكيت لا).
**الإصلاح**: عند التفعيل/الموافقة يكتب الباك اند عضوية الراكب في Redis (مثال `transit:route_members:{org_id}` Set على Redis الموقع)، والسوكيت يتحقق منها قبل `join`.
### هـ. متوسطة — لا Rate limiting على مسارات OTP والجلسات
`admin/login_request.php` و`login_verify.php` و`connect_admin.php` تُحمّل bootstrap مباشرة بدون `RateLimiter->enforce()` — إغراق OTP (سبام واتساب) وتعداد هواتف المشرفين (رسالة 401 مميزة) ممكنان. مع OTP من 3 خانات (900 احتمال، قفل بعد 3 محاولات) يصبح الحد الإلزامي أهم.
**الإصلاح**: أضف RateLimiter في الملفين + `connect_admin.php`، ووحّد رد login_request لغير الموجود (نفس رسالة النجاح دون إرسال).
### و. متوسطة — `trip/update_position.php` بلا أي مصادقة
موثّق كـ fallback مهجور لكنه منشور ويكتب مواقع في Redis لأي طارق. **احذفه أو ضعه خلف JWT**.
### ز. منخفضة
- جلسات `transit_sessions` المنتهية لا تُنظّف من MySQL (أضف لتنظيف الكرون الموجود)
- لا endpoint لتسجيل خروج مشرف المؤسسة (حذف الجلسة)
- رسائل أخطاء 4xx من `jsonError` لا تصل للتطبيقات — دوال CRUD في التطبيقات الثلاثة ترجع `'failure'` لأي 4xx (عدا 401) دون قراءة الرسالة → المستخدم يرى خطأ عام بدل "Enrollment already exists". قرار معماري: إما إرجاع 200 مع `status=failure` بمسارات transit، أو تعديل `_makeRequest` ليقرأ جسم 4xx
---
## 4. الفجوات الوظيفية لكل طرف
### مشرف المؤسسة (الأكبر — لا واجهة إطلاقاً)
الـ API موجود لكن **لا توجد لوحة ويب**. راجع القسم 5 للمواصفات الكاملة. فجوات API نفسها:
- **لا يوجد endpoint لاعتماد/تفعيل خط**: `route/add` ينشئ `status='draft'` والمخطط يقول الاعتماد لفريق سيرو (`approved_by`) — لكن لا endpoint في `Admin/transit/` ولا في `transit/` يحوّل draft→active. **بدونها الراكب لا يرى أي خط أبداً**
- لا تعديل/حذف: route/update، stop إدارة مستقلة (مجلد `transit/stop/` فارغ)، schedule/list+delete، vehicle/update+delete، driver/suspend، org/profile update
- لا إلغاء رحلة (enum فيه cancelled/no_show بلا endpoint)
- لا قائمة كشوف مستوردة (rosters list) ولا سجل إعلانات (broadcasts list — موجود جزئياً في dashboard آخر 5)
### فريق سيرو (siro_admin)
- اعتماد الخطوط (النقطة أعلاه) — endpoint + شاشة
- إدارة حالة العقد (trial/active/suspended/terminated) — لا endpoint ولا UI
- تعديل بيانات مؤسسة قائمة
### الراكب (siro_rider)
- **اشتراك FCM Topic فعلي غائب**: التطبيق لا يستدعي `subscribeToTopic('transit_route_{id}')` ولا `transit_org_{id}` — إشعارات الانطلاق/التأخير/الإعلانات لا تصل لأحد
- إشعار الموافقة على العضوية يُرسل لموضوع `passenger_{id}` والتطبيق يشترك فقط بموضوع `"passengers"` العام — لا يصل. الحل: اشتراك التطبيق بموضوعه الشخصي عند تسجيل الدخول، أو تغيير آلية الإرسال
- الخريطة الحية لا ترسم polyline الخط (البيانات موجودة في `trip/live.php`؛ متوفر `PolylineUtils.decode` في intaleq_maps) ولا أيقونة باص مخصصة (ماركر hue فقط)
- زر "فاتك الباص؟ اطلب سيارة" — الميزة التسويقية الأساسية من الرؤية، غير مبنية
### السائق (siro_driver)
- **كشف الوصول للمحطات (geofence) غير مبني**: لا منطق يكتشف دخول نطاق محطة ويرسل `current_stop_seq` — تتبع تقدّم الباص على المحطات لا يعمل
- خدمة الخلفية (`background_service.dart`) لها سوكيت مستقل غير واعٍ لوضع الباص — عند طيّ التطبيق أثناء رحلة باص قد يعود البث العادي (تلوث حوض الرحلات) ويتوقف بث الباص. تحتاج مراجعة وتمرير حالة وضع الباص
- لا معالج deep link لرابط الدعوة `siromove.com/driver/transit-activate?token=` (يُحل ضمن مسار التفعيل الجديد بالنقطة 3-ب)
- `trip/start` قد يرسل lat/lng = 0,0 إن لم يُلتقط الموقع بعد — أضف انتظار/تحقق
### النظام
- كرون مقترح: تنظيف `transit_sessions` المنتهية + إنشاء رحلات الغد مسبقاً (اختياري — حالياً تُنشأ عند أول فتح للسائق) + تقارير أسبوعية للمؤسسات (مؤجل باتفاق)
- `TRANSIT_STUDENT_ID_KEY` في `.env.example` لم يعد مستخدماً (نستخدم `$encryptionHelper` العام) — احذفه منعاً للالتباس
---
## 5. لوحة مشرف المؤسسة — المواصفات الكاملة
الأسئلة المطروحة: كيف يدخل المشرف؟ كيف يرسم الخطوط بتفاصيلها؟ كيف يديرها؟ هذه الإجابة الكاملة، مبنية على الـ API القائم:
**التقنية المقترحة**: ويب SPA (تُنشر على `transit.siromove.com` — CORS جاهز في `connect_admin.php`). كل الطلبات POST مع هيدر `Authorization: Bearer {session_token}`. الردود: `{status:'success', message:{...}}`.
### تدفق الدخول
1. شاشة هاتف → `transit/admin/login_request.php` {phone} → OTP واتساب (3 خانات)
2. شاشة رمز → `transit/admin/login_verify.php` {phone, otp} → `{token, expires_in, admin{}, org{}}` — يُخزن التوكن (صالح 24 ساعة)
### الشاشات (بترتيب البناء)
1. **اليوم (Dashboard)** — `admin/dashboard.php`: رحلات اليوم بحالاتها + موقع حي لكل باص started + عدادات + آخر 5 إعلانات. تحديث كل 15 ثانية
2. **الأسطول** — vehicles: قائمة `vehicle/list` + نموذج `vehicle/add` (plate, make, model, year, color, capacity, vehicle_type)
3. **السائقون** — `driver/list` + دعوة `driver/invite` {name, phone, license_number} → واتساب تلقائي برابط تفعيل. حالات invited/active/suspended
4. **الخطوط (الأهم)** — `route/list` + إنشاء بخريطة تفاعلية:
- خريطة (Leaflet/MapLibre) ينقر عليها المشرف لإضافة المحطات بالترتيب؛ لكل محطة: name_ar، name_en، نصف قطر الجيوفينس (افتراضي 150م)، eta_offset_min، is_major
- يرسم المسار (polyline مشفّر) بين المحطات — إما يدوياً أو عبر routes-osm القائم
- حفظ → `route/add` {name_ar, name_en, direction, polyline, distance_km, duration_min, stops:JSON} → يُنشأ **draft** بانتظار اعتماد فريق سيرو
- تفاصيل خط: `route/get` (محطات + جداول)
5. **الجداول** — من شاشة الخط: `schedule/add` {route_id, departure_time, days_mask, driver_id?, vehicle_id?, valid_from, valid_until} — واجهة اختيار أيام أسبوع تبني الـ bitmask (bit0=أحد … bit6=سبت، 62=أحد–خميس)
6. **الطلاب** — `enrollment/list` (فلترة بالحالة + ترقيم) + رفع كشف CSV `enrollment/import_roster` (أعمدة student_id, name) + موافقة/رفض `enrollment/approve`
7. **الإعلانات** — `broadcast/send` {body_ar, title_ar, target_type: all|route, target_id}
### ما يجب إضافته للـ API قبل/أثناء بناء اللوحة
route/update + route/submit (طلب اعتماد) · schedule/delete · vehicle/toggle · driver/suspend · trip/cancel · logout · rosters/list
---
## 6. تعليمات التنفيذ للنموذج الآخر — مهام مرتبة بالأولوية
كل بند أدناه Prompt مستقل. نفّذها بالترتيب؛ المهام 1–4 شرط لأي إطلاق تجريبي.
### المهمة 1 — إغلاق IDOR وربط حساب السائق (حرجة، باك اند + فلاتر)
> في مشروع Siro: أصلح ثغرة IDOR في `backend/transit/trip/today.php` و`start.php` و`end.php` و`delay.php` — جميعها تثق بـ `driver_transit_id` من العميل. المطلوب: (1) في كل ملف اشترط `$transit_user_role === 'driver'` ثم استخرج سجل السائق بـ `SELECT id, org_id FROM transit_drivers WHERE main_driver_id = ? AND status='active'` باستخدام `$transit_user_id` من `connect_app.php`، وتجاهل `driver_transit_id` القادم من العميل. (2) أنشئ `backend/transit/driver/activate_by_app.php` يعمل عبر `connect_app.php` بدور driver: يستقبل `invite_token` فقط، يطابقه في `transit_drivers`، يضبط `main_driver_id = $transit_user_id` و`status='active'` و`activated_at=NOW()` ويصفّر التوكن — هذا يحل مشكلة أن `main_driver_id` لا يُضبط أبداً حالياً. (3) في `siro_driver/lib/controller/transit/transit_driver_service.dart` أضف دالة `activateByInviteToken` وأنشئ شاشة إدخال رمز الدعوة تُعرض داخل `transit_driver_home_page.dart` عندما `is_bus_driver=false`، مع معالجة deep link للمسار `siromove.com/driver/transit-activate?token=`. (4) احذف `backend/transit/driver/activate.php` القديم (مساره ميت — لا مصدر OTP له) وحدّث نص رسالة الواتساب في `driver/invite.php` ليوجّه لفتح تطبيق السائق. اتبع أنماط النظام: `filterRequest`, `jsonSuccess/jsonError`, `appLog`. لينت PHP وDart بعد كل تعديل.
### المهمة 2 — اعتماد الخطوط draft→active (حرجة، باك اند + سيرو آدمن)
> في مشروع Siro: لا يوجد أي مسار يحوّل خط مواصلاتي من draft إلى active، فالراكب لا يرى الخطوط أبداً. المطلوب: (1) أنشئ `backend/Admin/transit/route/approve.php` بنمط ملفات `backend/Admin/transit/org/` (فحص `$role` admin/super_admin، `Database::get('transit')`): يستقبل route_id و action (approve|suspend|reject)، يحدّث `transit_routes.status` و`approved_by` (من `$user_id` بالـ JWT) و`approved_at`. (2) أنشئ `backend/Admin/transit/route/pending.php` يرجع كل خطوط draft عبر المؤسسات مع اسم المؤسسة وعدد المحطات. (3) في siro_admin أضف شاشة "اعتماد الخطوط" (`lib/views/transit/route_approval_page.dart` بنفس ثيم `org_list_page.dart` الداكن) تعرض المسودات مع محطاتها على خريطة مصغرة إن أمكن وزرّي اعتماد/رفض، واربطها من `admin_home_page.dart` فئة مواصلاتي، ووسّع `transit_admin_service.dart` و`transit_admin_controller.dart`. لينت كل شيء.
### المهمة 3 — تحقق العضوية في اشتراك السوكيت (حرجة، باك اند + سوكيت)
> في مشروع Siro: `subscribe_transit_route` في `passenger_server/passenger_socket.php` يضم أي راكب لأي غرفة خط دون تحقق. المطلوب: (1) في `backend/transit/functions.php` أضف `transitCacheEnrollment(int $orgId, string $passengerId)` تكتب `SADD transit:org_members:{orgId}` على `$redisLocation` (بدون بادئة) مع TTL تجديدي 7 أيام، و`transitDropEnrollment` للحذف. استدعِ الإضافة عند تفعيل العضوية في `enrollment/activate.php` (الحالتان) وعند الموافقة في `enrollment/approve.php`، والحذف عند الرفض/التعليق. (2) أنشئ سكربت `backend/transit/cron_sync_members.php` يعيد بناء المجموعات من MySQL (للتشغيل اليدوي والكرون اليومي). (3) في `passenger_socket.php` عند `subscribe_transit_route` استعلم Redis المحلي: خذ org_id للخط من هاش جديد `transit:route_org:{routeId}` (اكتبه من `route/add.php` وapprove في المهمة 2) ثم `SISMEMBER transit:org_members:{orgId} passengerId` — ارفض الانضمام إن لم يكن عضواً وسجّل بالـ log. انتبه: سوكيت الراكب يتصل بـ Redis؟ إن لم يكن فيه اتصال Redis أضف واحداً بنمط `getRedis()` من `loction_server/driver_socket.php`. لينت PHP.
### المهمة 4 — Rate limiting ومصادقة المسارات المكشوفة (عالية، باك اند)
> في مشروع Siro: (1) أضف `RateLimiter($redis)->enforce(RateLimiter::identifier(), 'api')` (كما في `backend/transit/connect_app.php`) إلى: `backend/transit/admin/login_request.php`، `login_verify.php`، و`backend/transit/connect_admin.php`. (2) في `login_request.php` وحّد الرد: عند هاتف غير موجود أعد نفس رسالة النجاح دون إرسال OTP (منع تعداد المشرفين). (3) احذف `backend/transit/trip/update_position.php` نهائياً (fallback مهجور بلا مصادقة — المسار الفعلي عبر السوكيت). (4) أنشئ `backend/transit/admin/logout.php` يحذف الجلسة من Redis (`siro:transit:session:{hash}`) وMySQL. (5) أضف تنظيف `DELETE FROM transit_sessions WHERE expires_at < NOW()` إلى سكربت كرون التنظيف القائم في الباك اند (ابحث عن كرونات التنظيف الموجودة واتبع نمطها). لينت.
### المهمة 5 — إشعارات FCM فعلية (عالية، فلاتر رايدر + باك اند)
> في مشروع Siro: الإشعارات لا تصل لأن الاشتراك بالمواضيع غير مبني. المطلوب: (1) في `siro_rider/lib/controller/firebase/firbase_messge.dart` يوجد `subscribeToTopic("passengers")` — أضف بعده اشتراكاً بالموضوع الشخصي `passenger_{id}` من `box.read(BoxName.passengerID)`. (2) في `siro_rider/lib/controller/transit/transit_controller.dart`: عند نجاح `activateEnrollment` اشترك بـ `transit_org_{orgId}`، وفي `openLiveRoute`/زر جديد "تنبيهات الخط" اشترك بـ `transit_route_{routeId}` عبر `FirebaseMessaging.instance.subscribeToTopic` مع استدعاء `backend/transit/notification/subscribe.php` القائم لتسجيل المحطة المفضلة، ومع إلغاء الاشتراك المقابل. (3) تحقق أن معالج الرسائل الحالي يعرض إشعارات data type=transit_* عندما يكون التطبيق بالمقدمة. لينت Dart.
### المهمة 6 — لوحة مشرف المؤسسة الويب (كبيرة — قسّمها على جلسات)
> في مشروع Siro: ابنِ لوحة ويب لمشرف المؤسسة حسب المواصفات في `docs/mawasalati_full_system_review.md` قسم 5. أنشئها في مجلد جديد `transit_dashboard/` بجذر المشروع (Vue 3 أو React + Vite، عربي RTL أساسي مع تبديل فاتح/داكن). الدخول: `POST {SERVER}/transit/admin/login_request.php` ثم `login_verify.php`، التوكن في `Authorization: Bearer`. ابدأ بجلسة أولى: هيكل المشروع + الدخول + Dashboard اليوم + قائمة المركبات والسائقين. الجلسة الثانية: منشئ الخطوط بالخريطة (MapLibre + نقر لإضافة محطات + حفظ route/add) والجداول (days_mask bitmask: bit0=أحد…bit6=سبت). الجلسة الثالثة: الطلاب (قائمة/كشف CSV/موافقات) والإعلانات. أضف أثناء ذلك endpoints الناقصة الموثقة نهاية قسم 5 بنفس أنماط `backend/transit/` (connect_admin, filterRequest, jsonSuccess).
### المهمة 7 — جيوفينس المحطات في تطبيق السائق (متوسطة)
> في مشروع Siro: سائق الباص لا يكتشف وصوله للمحطات. في `siro_driver/lib/controller/transit/transit_driver_controller.dart` أضف منطقاً أثناء الرحلة النشطة: قارن موقع `LocationController.myLocation` (استمع عبر نفس تدفق التحديث) مع محطات `activeTrip.stops` — عند دخول نطاق `geofence_radius` لمحطة تسلسلها أعلى من الحالي، مرّر `currentStopSeq` الجديد إلى `emitBusLocationToSocket` (المعامل موجود جاهز في `location_controller.dart`) وحدّث الواجهة بشريط تقدم المحطات في `transit_driver_home_page.dart`. استخدم `geo.Geolocator.distanceBetween` الموجود. لا تستدعِ REST — السوكيت يخزّن التسلسل في Redis ويبثه.
### المهمة 8 — مراجعة خدمة الخلفية لوضع الباص (متوسطة، سائق)
> في مشروع Siro: افحص `siro_driver/lib/controller/functions/background_service.dart` بالكامل: هل ينشئ سوكيتاً خاصاً ويبث `update_location` عندما يكون التطبيق بالخلفية؟ إن كان كذلك فعند وضع الباص (`LocationController.isBusMode`) سيلوث حوض الرحلات ويوقف بث الباص. مرّر حالة وضع الباص وبيانات الرحلة (trip_id/route_id — خزّنها في GetStorage box عند `setBusMode`) إلى الخدمة الخلفية وبدّل الحدث إلى `update_bus_location` بنفس الحمولة المستخدمة في `emitBusLocationToSocket`. اختبر السيناريو: بدء رحلة باص → طي التطبيق → التأكد من استمرار البث الصحيح.
### المهمة 9 — تحسينات خريطة الراكب (منخفضة)
> في مشروع Siro، ملف `siro_rider/lib/views/transit/transit_live_map_page.dart`: (1) ارسم polyline الخط — الحقل `polyline` يأتي ضمن `trip/live.php`؟ تحقق؛ إن لم يكن أضفه للاستعلام في `backend/transit/trip/live.php` (من `transit_routes.polyline`)، ثم فكّه بـ `PolylineUtils.decode` من حزمة intaleq_maps وأضف `Polyline` للخريطة بلون `AppColor.accentColor`. (2) استخدم أيقونة باص مخصصة للماركر عبر `InlqBitmap.fromAsset` (أضف أصل `assets/images/bus.png` — انظر pubspec). (3) أضف بطاقة سفلية بمعلومات الرحلة (السائق، الانطلاق، المحطة الحالية باسمها بدل الرقم). (4) زر "فاتك الباص؟ اطلب سيارة الآن" يوجّه لطلب رحلة عادية من موقع المستخدم — نقطة التحويل التجارية الأساسية.
### المهمة 10 — إدارة العقود وتعديل المؤسسات (منخفضة، سيرو آدمن)
> في مشروع Siro: أنشئ `backend/Admin/transit/org/update.php` (تعديل بيانات مؤسسة + `contract_status` مع تحقق enum) بنمط `org/create.php`، وعند suspended/terminated أبطل كل جلسات مشرفي المؤسسة (انظر منطق `org/admin_toggle.php`). في siro_admin أضف للشاشة `org_details_page.dart` قائمة إجراءات (تعليق/تفعيل/إنهاء عقد + تعديل الحقول) عبر `transit_admin_service.dart`. لينت.
---
## 7. تشيك ليست النشر (قبل أول تجربة حقيقية)
1. تنفيذ ALTERs الترحيل (نهاية `schema_transit.sql`) على `siroTransitDb` القائمة
2. `.env` الإنتاج: قيم `DB_TRANSIT_*` + تأكيد `REDIS_LOCATION_HOST` مضبوط (وإلا لا يظهر موقع الباص إطلاقاً — نفس شرط كثافة السائقين)
3. إعادة تشغيل `driver_socket.php` و`passenger_socket.php` بالنسخ المحدثة ومراقبة اللوج: رسائل `🚫 update_bus_location rejected` تعني مشكلة ملكية؛ `[TRANSIT]` بسوكيت الراكب تؤكد الاشتراكات
4. جدولة كرون: تنظيف الجلسات + مزامنة أعضاء Redis (المهمة 3)
5. اختبار دخاني كامل: إنشاء مؤسسة من سيرو آدمن → دخول مشرف OTP → مركبة + سائق (دعوة) → تفعيل السائق من تطبيقه (المهمة 1) → خط + محطات + جدول → اعتماد الخط من سيرو آدمن (المهمة 2) → كشف طلاب → تفعيل طالب بالرقم الجامعي → رؤية الخط → بدء الرحلة من السائق → الموقع الحي يصل للراكب → إنهاء الرحلة
@@ -0,0 +1,46 @@
# خطة مواصلاتي (Siro Transit) - ما تم إنجازه وما لم يتم
تُوثق هذه الوثيقة حالة ميزة "مواصلاتي" (النقل المؤسسي للجامعات والفنادق) في منصة سيرو، وتفصل ما تم بناءه حتى الآن وما يتبقى إكماله قبل الإطلاق النهائي.
## ✅ أولاً: ما تم إنجازه
### 1. البنية التحتية وقواعد البيانات (Backend)
- تصميم قواعد البيانات وإضافة الجداول اللازمة (مؤسسات، خطوط، محطات، جداول زمنية، رحلات، واشتراكات الركاب).
- بناء مسارات الـ API بلغة PHP لخدمة الراكب والسائق (جلب المؤسسات، المسارات، المحطات، الرحلات اليومية).
### 2. تطبيق الراكب (Rider App)
- شاشة **تصفح المؤسسات** (`TransitOrgBrowsePage`) لعرض الجامعات والفنادق المتاحة.
- شاشة **مسارات المؤسسة** (`TransitRoutesPage`) لعرض الخطوط والمحطات على الخريطة.
- شاشة **الصفحة الرئيسية للمواصلاتي** (`TransitHomePage`) لعرض اشتراكات الراكب الحالية.
- شاشة **التتبع الحي** (`TransitLiveMapPage`) المهيأة مبدئياً لتتبع الباص.
- إصلاح مشاكل الـ UI (ParentDataWidget و initState).
### 3. تطبيق السائق (Driver App)
- شاشة **الرحلات المجدولة** (`TransitDriverHomePage`) لعرض الرحلات المطلوبة من السائق اليوم، مع أزرار "بدء الرحلة" و"إنهاء الرحلة".
- تحسين خريطة السائق الأساسية (`home_captin.dart`) وتفعيل ماركر السيارة الصحيح (`car_icon`) ليكون جاهزاً لبث الموقع الفعلي أثناء الرحلة، وإصلاح مشاكل الـ UI (Overflow).
---
## ⏳ ثانياً: ما لم يتم إنجازه (الخطوات القادمة والأولويات)
> [!IMPORTANT]
> تم تعليق (إخفاء) أزرار الوصول لخدمة "مواصلاتي" مؤقتاً من تطبيقي الراكب والسائق حتى يتم الانتهاء من هذه الخطوات واختبارها فعلياً على سيرفرات الإنتاج.
### أولوية 1: الاختبار الميداني الحقيقي
- **بث واستقبال الموقع الحي (WebSockets):** تشغيل واختبار `driver_socket.php` و `passenger_socket.php` على سيرفر الإنتاج الفعلي.
- التأكد من إعدادات الـ Redis (`REDIS_LOCATION_HOST`) في الـ `.env`.
- التأكد من أن "ماركر" الباص يتحرك بسلاسة على خريطة الراكب عندما يبدأ السائق الرحلة.
### أولوية 2: دورة حياة الرحلة للسائق والتذاكر
- **وضع التوجيه للسائق (Active Trip Navigation):** شاشة تظهر للسائق عند الضغط على "بدء الرحلة" لترشده للمحطات بالترتيب وتتبع تقدمه.
- **الاشتراكات والتذاكر (Ticketing):** شراء الراكب للاشتراك وخصم الرصيد من المحفظة.
- **مسح كود الصعود (QR Boarding):** آلية لكي يثبت الراكب صعوده للباص (إما السائق يمسح كود الراكب، أو يعلّم عليه في قائمة الركاب).
### أولوية 3: لوحة تحكم المؤسسات والتنبيهات
- **واجهة الويب للمؤسسات (B2B Admin Dashboard):** واجهة ويب تتيح لمدير الحركة في الجامعة إضافة المسارات، الباصات، وتتبع الأسطول.
- **استيراد كشف الركاب:** واجهة لرفع ملفات CSV (`import_roster.php`) لتعريف طلاب الجامعة المسموح لهم بالركوب.
- **التنبيهات الجغرافية (Geofence Push Notifications):** تفعيل إشعارات FCM ("الباص على بُعد 5 دقائق من محطتك").
- **إدارة العقود:** زر في تطبيق `siro_admin` لتفعيل/تعليق عقود المؤسسات (`contract_status`).
---
سيتم الرجوع لهذه الخطة واستئناف العمل عليها في المرحلة القادمة بعد الانتهاء من الأولويات الحالية للنظام.
@@ -0,0 +1,200 @@
ممتاز، ملاحظاتك واضحة كلها. سأشتغل على ثلاث جبهات قبل كتابة التقرير المفصل: أولاً فحص سريع للكود (بوليغونات الدول، وكيف يميّز النظام الحالي أنواع المركبات والسائقين)، ثانياً بحث معمّق عن نموذج أسطول سالك وسويفل (باصاتهم أم باصات الجامعات)، ثالثاً أبني على هذا كله المعمارية الكاملة والتقرير.
وصلتني نتائج البحث كاملة، والصورة الآن واضحة تماماً. إليك التقرير المفصل الثاني — نسخة العمليات والمعمارية:
---
# التقرير الثاني: منصة «مواصلاتي» — نموذج التشغيل، المعمارية الكاملة، ودليل العلاقات العامة
## القسم الأول: نتيجة البحث — كيف يعمل سويفل وسالك فعلياً؟
هذا جواب سؤالك المباشر، وهو أهم معلومة في التقرير كله:
**سويفل لا تملك أي باص ولا توظف أي سائق.** شروط خدمتها تنص حرفياً على أنها ليست ناقلاً، لا تملك ولا تشغّل مركبات، ولا توظف سائقين — هي منصة تقنية وسوق حجز. مصدر الباصات عندهم نوعان: «كباتن» مستقلون يملكون باصاتهم أو فانات (ووصل بهم الأمر لعقد شراكات مع بنوك مصرية مثل بنك ناصر الاجتماعي لتمويل شراء الكباتن باصات فورد ترانزيت)، وشركات نقل متعاقدة. وفوق هذا يبيعون منتجين مؤسسيين: النقل كخدمة (هم يدبّرون الباصات للشركة/المدرسة)، وبرمجيات إدارة النقل كخدمة مستقلة تعمل على أسطول العميل نفسه.
**سالك بنفس المنطق تقريباً:** منصة اشتراكات للطلاب — الطالب يشترك عند سالك مباشرة (باقات، أكثر من ١٥٠ نقطة تجميع)، والرحلات على باصات متعاقدة تديرها سالك، وليست باصات الجامعات. أي أن سالك يبيع المقعد للطالب، والجامعة ليست طرفاً في العقد أصلاً — هي فقط الوجهة.
**ماذا يعني هذا لنا؟ ثلاث خلاصات حاسمة:**
- الفراغ السوقي الحقيقي هو بالضبط ما تنوون فعله: **لا أحد يقدّم للجامعة برمجيات مجانية على أسطولها هي**. سويفل تبيع البرمجيات كمنتج مدفوع للشركات الكبيرة، وسالك يتجاهل أسطول الجامعة كلياً. عرضكم (مجاني + أسطولهم + تطبيقكم) لا منافس مباشراً له.
- نموذجهم يؤكد صحة قرار عدم امتلاك باصات: أكبر شركة في المجال، مدرجة في ناسداك، رفضت امتلاك الأصول من اليوم الأول.
- فكرة «شركة باصات نتعاقد معها» التي طرحتَها هي حرفياً نموذج كباتن سويفل — وهي سليمة، لكن مكانها الصحيح في نموذجنا هو **حل حالة الجامعة التي لا تملك أسطولاً** (وأغلبها الحكومية)، وليست أساس النموذج.
---
## القسم الثاني: نموذج التشغيل — ثلاثة أنماط عرض في منصة واحدة
المعمارية يجب أن تدعم من اليوم الأول ثلاثة أنماط، لأن كل عميل سيقع في واحد منها:
**النمط الأول — أسطول المؤسسة (النمط الرئيسي):** الجامعة/المدرسة/الفندق/الشركة تملك باصاتها وسائقيها. نحن نقدّم البرمجيات فقط: تتبع، إشعارات، لوحة تحكم، تسجيل طلاب. مجاني. هذا نمط الجامعات الخاصة في الدول الثلاث، وهو الأسرع إغلاقاً لأنه لا يكلف الجامعة قرشاً ولا يهدد موظفيها.
**النمط الثاني — الناقل المتعاقد (طبقة التنظيم):** المؤسسة لا تملك أسطولاً — الحالة الغالبة في الجامعات الحكومية بالأردن وسوريا. نحن نُدخل طرفاً ثالثاً: شركة باصات أو مكتب نقل محلي يسجَّل عندنا ككيان «ناقل»، ونربطه بالجامعة. الجامعة تعطي المباركة الرسمية ونقاط الانطلاق داخل الحرم، الناقل يشغّل، ونحن ننظّم ونتتبع. هنا لاحقاً يوجد إيراد حقيقي (عمولة من الناقل أو رسم تنظيم)، لكن في البداية نفس المنطق: مجاني لبناء الشبكة.
**النمط الثالث — مقاعد بالاشتراك (مؤجل عمداً):** أن نبيع المقعد للطالب مباشرة كما تفعل سالك. لا ندخله الآن إطلاقاً — هو الوحيد الذي يتطلب عمليات ثقيلة وضمان إشغال، وهو ساحة سويفل وسالك المحصّنة. يبقى خياراً مستقبلياً تفتحه البيانات التي سنجمعها (سنعرف بالضبط أي المسارات مكتظة وأيها مهمَل).
**مصفوفة الاستخدام:** جامعة خاصة ← النمط الأول. جامعة حكومية ← النمط الثاني. مدرسة خاصة ← الأول (عندها باصات غالباً). فندق ← الأول (فاناته) + حساب مشاوير مؤسسي. شركة/مصنع ← الأول أو الثاني حسب ملكية الأسطول.
---
## القسم الثالث: الاستراتيجية متعددة الدول — لا مصر وحدها
تصحيح زاوية التقرير الأول: المنصة تُبنى محايدة للدولة تماماً، وكل كيان مؤسسي يحمل حقلَي دولة ومدينة، والبوليغونات موجودة عندكم أصلاً في `country_polygons.dart` للأردن وسوريا ومصر (وقلتَ إن بوليغونات الجامعات الخاصة في مصر شبه جاهزة — تُخزَّن كبوليغون للحرم مرتبط بكيان الجامعة، وتفيد في الاقتراح التلقائي للجامعة عند التسجيل وفي جيوفينس الوصول للحرم).
**الأردن:** الجامعات الخاصة (البترا، الشرق الأوسط، الزيتونة، الإسراء، العلوم التطبيقية...) تشغّل خطوط باصات فعلية من المدن — عملاء نمط أول مثاليون. الجامعات الحكومية (الأردنية، اليرموك، مؤتة، آل البيت...) طلابها على باصات النقل العام والمكاتب الخاصة — نمط ثانٍ: نتعاقد مع مكاتب الباصات العاملة أصلاً على خطوط الجامعات ونعطي الجامعة نظام التتبع مجاناً مقابل التبني الرسمي. قناة إضافية مهمة بالأردن: اتحادات الطلبة وعمادات شؤون الطلبة.
**سوريا:** الفرصة الأعمق والمنافسة صفر تقريباً. الجامعات حكومية ضخمة (دمشق، حلب، تشرين، البعث) والنقل الطلابي فوضوي (سرافيس وميكروباصات خاصة). النمط الثاني هو الطريق: التعاقد مع متعهدي نقل قائمين على خطوط الجامعات + مذكرة تفاهم مع الجامعة أو حتى وزارة التعليم العالي (في سوريا القرار مركزي — علاقة واحدة جيدة بالوزارة تفتح كل الجامعات دفعة واحدة). وميزة سوريا: وجودكم التشغيلي القائم وعقدكم الاستثماري هناك يعطيكم أرضية علاقات جاهزة.
**مصر:** كما في التقرير الأول — الجامعات الخاصة أولاً (والطلب وارد فعلاً من جامعة)، مع وعي كامل بوجود سالك وسويفل، وتمايزنا أننا لا نبيع مقاعد بل نرقمن أسطول الجامعة مجاناً.
**التوظيف:** مسؤول شراكات ميداني واحد لكل دولة (وصفه الوظيفي الكامل في القسم الحادي عشر)، يتبع لمدير تطوير أعمال مركزي. لا حاجة لأكثر في السنة الأولى.
---
## القسم الرابع: المعمارية التقنية الكاملة
### ١. مبدأ العزل من اليوم الأول — جواب فكرة «السيرفر الصغير المنفصل»
فكرتك عن سيرفر مستقل صغير بقاعدة بيانات وردس خاصين **صحيحة معمارياً مئة بالمئة**، وتحليل الحمل يثبتها: الضغط هنا معكوس عن النقل العادي. في المشاوير عندك آلاف السيارات وكل سيارة يتابعها راكب واحد؛ في الباصات عندك عشرات الباصات وكل باص يتابعه **مئات الطلاب في نفس اللحظة** (الثامنة صباحاً). خمسمئة باص ترسل إحداثية كل ٤ ثوانٍ = ١٢٥ رسالة/ثانية فقط (تافهة)، لكن توزيعها الساذج على ٥٠ ألف طالب = ملايين الرسائل. الحل ليس قوة سيرفر بل **نمط النشر**: غرفة سوكيت لكل خط، الطالب يشترك بغرفة خطه فقط، وكل نبضة GPS تُبث مرة واحدة للغرفة. بهذا النمط سيرفر صغير جداً (٢ كور / ٤ غيغا) يخدم مئات الجامعات.
التنفيذ على مرحلتين حتى لا نؤخر الإطلاق:
- **المرحلة الأولى (الإطلاق):** الكود في مجلد مستقل `backend/transit/` على السيرفر الرئيسي الحالي، لكن بقاعدة بيانات MySQL مستقلة تماماً اسمها `siro_transit` تُضاف كاتصال ثالث في نمط `Database::get('transit')` الموجود عندكم (نفس آلية main وride)، وردس بمساحة أسماء خاصة `transit:*`. **قاعدة ذهبية: ممنوع أي JOIN بين قاعدة transit وقواعد النقل الرئيسية** — الربط بالمعرّفات فقط (passenger_id، driver_id) وعبر استدعاءات HTTP داخلية بنمط `sendToLocationServer` الموجود. هذه القاعدة وحدها هي ما يجعل الفصل لاحقاً عملية نقل ملفات وتغيير سطر في `.env`، لا إعادة كتابة.
- **المرحلة الثانية (عند تجاوز ~٥ جامعات فعّالة):** نقل قاعدة `siro_transit` وعملية سوكيت مستقلة `transit_socket.php` (استنساخ نمط `passenger_socket.php` بوركرمان الذي يعمل عندكم) إلى VPS صغير مستقل بردسه الخاص. تتبع الباصات يبقى في البداية على سوكيت السائقين الحالي في خادم المواقع بوسم `vehicle_kind=bus`، وينتقل مع الفصل.
### ٢. مخطط قاعدة البيانات (قاعدة `siro_transit`)
- جدول `transit_orgs`: المؤسسات — المعرّف، النوع (جامعة/مدرسة/شركة/فندق/**ناقل**)، الاسم بالعربية والإنجليزية، الدولة، المدينة، بوليغون الحرم، الشعار، حالة العقد، تاريخ التفعيل. نوع «ناقل» هو ما يفعّل النمط الثاني.
- جدول `transit_org_links`: ربط ناقل ↔ مؤسسة (جامعة حكومية تخدمها شركة باصات).
- جدول `transit_org_admins`: مشرفو المؤسسة — الهاتف، الاسم، الدور (مالك/مشرف نقل/مُرسِل)، صلاحيات، دخول بهاتف + OTP على لوحة الويب.
- جدول `transit_vehicles`: الباصات — المؤسسة المالكة، اللوحة، السعة، الموديل، الحالة. (منفصل عن `captains_car` عمداً — باص الجامعة ليس سيارة كابتن).
- جدول `transit_drivers`: سائقو الباصات — الهاتف، الاسم، المؤسسة، رقم الرخصة وصورتها، حالة التفعيل، وحقل `main_driver_id` اختياري يربطه بجدول `driver` الرئيسي إن كان كابتن مشاوير أيضاً (سائق فندق مثلاً).
- جدول `transit_routes`: الخطوط — المؤسسة، الاسم («خط الزرقاء صباحي»)، الاتجاه (ذهاب/عودة)، البوليلاين المشفّر، المسافة، الزمن التقديري، الحالة (مسودة/معتمد/موقوف).
- جدول `transit_stops`: المحطات — الخط، الترتيب، الاسم، الإحداثيات، نصف قطر الجيوفينس بالمتر (افتراضي ١٥٠م)، الإزاحة الزمنية التقديرية عن الانطلاق.
- جدول `transit_schedules`: الجداول — الخط، أيام الأسبوع (قناع بتات)، وقت الانطلاق، فترة السريان (بداية/نهاية الفصل الدراسي).
- جدول `transit_trips`: الرحلة الفعلية اليومية — الجدول، التاريخ، السائق، الباص، الحالة (مجدولة/انطلقت/انتهت/ملغاة)، أوقات البدء والانتهاء الفعلية. هذا الجدول هو مصدر تقارير الالتزام.
- جدول `transit_enrollments`: العضويات — معرّف الراكب (من النظام الرئيسي)، المؤسسة، **الرقم الجامعي/الوظيفي**، الدور (طالب/موظف/نزيل)، الحالة (نشط/موقوف/منتهي)، تاريخ انتهاء الصلاحية (نهاية الفصل — التجديد الفصلي يحصل بإعادة استيراد الكشف وتحديث التواريخ تلقائياً).
- جدول `transit_rosters`: سجل عمليات استيراد كشوف الطلاب — من رفعها، متى، كم سجلاً، وفروقات النسخة السابقة (من تخرّج يُعطَّل تلقائياً).
- جدول `transit_guardians`: أولياء الأمور (للمدارس) — راكب وليّ الأمر مربوط بعضوية الطالب/الطفل، صلة القرابة، أنواع الإشعارات المفعّلة.
- جدول `transit_boardings` (مرحلة ثانية): إثبات الصعود — الرحلة، العضوية، وقت الصعود/النزول، الطريقة (QR/تأشير السائق/جيوفينس).
- جدول `transit_broadcasts`: إعلانات المشرف («غداً عطلة — لا باصات») مع سجل التسليم.
### ٣. تدفق التتبع والإشعارات
- **الإرسال:** تطبيق السائق في وضع الباص يبث الموقع لسوكيت المواقع الحالي بوسم الرحلة. المعالج يكتب في ردس `transit:trip:{id}:pos` وينشر في قناة `transit:route:{id}`.
- **الاستقبال الحي:** الطالب الفاتح للخريطة مشترك بغرفة خطه فقط — بث واحد لكل نبضة.
- **الإشعارات الخاملة (الأهم):** الطالب غير الفاتح للتطبيق يصله إشعار FCM عبر **اشتراك Topic لكل خط** (`transit_route_123`) — وهذا قرار مهم للتكلفة: مواضيع FCM مجانية وتوزّع للآلاف بلا أي حمل على سيرفرنا، ولا نحتاج إدارة توكنات فردية للبث العام.
- **إشعار الاقتراب الشخصي:** الطالب يحدد «محطتي» مرة واحدة؛ عند دخول الباص جيوفينس المحطة السابقة لمحطته، يُرسل إشعار موجّه «الباص يبعد محطة واحدة عنك». الحساب يتم سيرفرياً بمقارنة موقع الباص بمحطات الخط (وجدول `geofence_zones` وخبرة خدمة الجيوفينس الموجودة في تطبيق الراكب تُعاد هنا).
- **حزمة إشعارات لكل شخصية:** للطالب (انطلق الباص، اقترب من محطتك، تأخر، آخر نداء، إعلانات المشرف)؛ لولي الأمر في المدارس (صعد ابنك ✓ نزل ابنك ✓ الباص اقترب من البيت)؛ للفندق (السائق وصل البوابة لنزيل الغرفة كذا، تقرير شهري)؛ للمشرف (باص لم ينطلق بموعده، باص خرج عن المسار، سائق أغلق التطبيق أثناء رحلة، ملخص التزام يومي). مع قواعد ضبط: ساعات هدوء، ومنع التكرار خلال نافذة زمنية.
---
## القسم الخامس: جهة السائق — كيف نميّز سائق الباص ونديره
هذا جواب سؤالك التشغيلي، والمبدأ الحاكم: **سائق الباص ليس كابتن مشاوير، فلا يمر بمسار الكباتن إطلاقاً.**
- **التمييز في البيانات:** يوجد عندكم حقل `employmentType` في جدول السائق أصلاً — سائق الباص يُسجَّل في `transit_drivers` بربط اختياري فقط مع الجدول الرئيسي. لا يستقبل عروض مشاوير أبداً، لا يظهر في بحث السيارات القريبة، ولا يدخل منظومة الأرباح والمحفظة (راتبه من الجامعة).
- **التسجيل مقلوب:** الكابتن العادي يسجّل نفسه ثم توافقون؛ سائق الباص **يُنشئه مشرف الجامعة** من لوحة التحكم (اسم + هاتف + رخصة)، فتصله رسالة دعوة، يحمّل تطبيق السائق نفسه، يدخل بهاتفه + OTP، فيتعرف النظام عليه كسائق باص ويفتح له «وضع الباص» مباشرة. لا وثائق جنائية ولا فحص منا — الجامعة موظِّفه وهي المسؤولة، ونوثّق ذلك في العقد.
- **واجهة وضع الباص (بساطة متطرفة عمداً):** شاشة واحدة: رحلة اليوم القادمة (الخط، الوقت، الباص) وزر كبير «ابدأ الرحلة». أثناء الرحلة: شريط المحطات يتقدم تلقائياً بالجيوفينس (بلا أي إدخال يدوي)، زر «تأخير» يبث إشعاراً جاهزاً للمشتركين، زر طوارئ، ودردشة مع المشرف (نفس بنية دردشة `backend/ride/chat` الجاهزة). زر «أنهِ الرحلة» يظهر عند آخر محطة. لا عدّاد، لا أسعار، لا خريطة طلبات.
- **السائق المزدوج:** سائق فان الفندق قد يكون كابتن مشاوير مساءً — الربط عبر `main_driver_id` يسمح له بالتبديل بين الوضعين من زر واحد، ولا يمكن أن يكون في الوضعين معاً.
- **حل مشكلة الالتزام (لأن السائق ليس شريكنا اقتصادياً):** أداتنا هي الجامعة نفسها — تقرير الالتزام اليومي للمشرف (انطلق بالموعد؟ أغلق التطبيق؟ أنهى الخط؟) يجعل تشغيل التطبيق جزءاً من تقييم السائق الوظيفي عند مديره. ونضيف تحفيزاً ناعماً: شارة «سائق ممتاز» وتقييم الطلاب للرحلة.
---
## القسم السادس: جهة الطالب — التسجيل والتحقق بالتفصيل
- **المبدأ الذي حددتَه صحيح:** الطالب راكب عادي أولاً — نفس تسجيل الراكب (هاتف + OTP الموجود). تبويب «مواصلاتي» مقفل حتى يفعّل عضويته.
- **تدفق التفعيل:** يفتح مواصلاتي ← يظهر له اختيار الجامعة (مرشّحة تلقائياً حسب موقعه وبوليغون الدولة) ← يدخل رقمه الجامعي ← التحقق بإحدى ثلاث طرق حسب جاهزية الجامعة: **أ)** استعلام API مباشر من نظام الجامعة إن وُجد (الأفضل، ونجهّز له عقد ربط موحّداً بسيطاً: endpoint واحد يستقبل الرقم ويرجع الحالة والاسم)؛ **ب)** الكشف المستورد — المشرف رفع ملف إكسل/CSV بأرقام الطلاب (وهواتفهم إن توفرت) ونطابق محلياً؛ **ج)** الموافقة اليدوية — الطلب يذهب لطابور المشرف يوافق عليه من اللوحة (للجامعات الأقل تنظيماً).
- **نقطة ذكية في موضوع OTP توفّر مالاً حقيقياً:** الطالب هاتفه موثّق أصلاً بـOTP عند تسجيله كراكب. فإن كان كشف الجامعة يحتوي أرقام الهواتف وطابق هاتف الحساب = هذا أقوى توثيق ممكن **بصفر رسائل SMS إضافية**. نرسل OTP ثانياً فقط عند عدم التطابق أو غياب الهاتف من الكشف. ومع آلاف الطلاب، كل OTP موفَّر يعني خفضاً مباشراً لفاتورة SMS — ولديكم أصلاً قناة واتساب عبر نابح كبديل أرخص عند الحاجة.
- **دورة الحياة:** العضوية تنتهي بنهاية الفصل تلقائياً (حقل الصلاحية)، وإعادة استيراد كشف الفصل الجديد تجدد النشطين وتعطّل المتخرجين. طالب انتقل جامعة؟ عضويات متعددة مسموحة نظرياً، والمشرف يرى قائمته فقط.
- **داخل التبويب:** خطوط جامعته وجداولها، خريطة الباص الحي، «محطتي» المفضلة، إشعاراته، وإعلانات الجامعة. **وأهم زر في المشروع كله:** عندما يفوت الطالب الباص أو يكون الانطلاق القادم بعيداً، يظهر «فاتك الباص؟ اطلب سيارة الآن» بمسار معبأ مسبقاً نحو الجامعة — هذه نقطة تحويل الدعاية إلى إيراد، وقياس نقراتها هو مؤشر نجاح المشروع الأول.
---
## القسم السابع: تعريف الخطوط — من يرسمها؟
جواب مباشر لسؤالك: **الاثنان معاً، لكن بترتيب زمني وبحوكمة.**
- **في الإطلاق: فريقنا يرسم.** جودة أول انطباع أهم من التفويض. نبني محرر خطوط في لوحة الإدارة: المشرف عندنا ينقر المحطات على الخريطة بالترتيب، والنظام يولّد البوليلاين تلقائياً عبر محرك التوجيه بين المحطات، مع إمكانية سحب المسار لتعديله (وخرائطكم الخاصة intaleq_maps تعني صفر تكلفة API هنا). جلسة تجهيز جامعة كاملة (١٠–١٥ خطاً) = يوم عمل واحد مع مشرف نقل الجامعة على الهاتف.
- **من الفصل الثاني: نفس المحرر يُفتح لمشرف الجامعة** في لوحته، لكن بسير عمل «مسودة ← اعتماد»: أي خط يرسمه أو يعدّله يبقى مسودة حتى يعتمده فريقنا (فحص جودة: محطات منطقية، جيوفينس لا يتداخل، المسار سالك). بهذا نفوّض الجهد ونحتفظ بالجودة.
- **المحطات جيوفينس من اليوم الأول** كما اقترحت: كل محطة دائرة بنصف قطر قابل للضبط، وهي أساس ثلاث وظائف دفعة واحدة: تقدّم شريط المحطات عند السائق، إشعار الاقتراب للطالب، وكشف الخروج عن المسار للمشرف.
---
## القسم الثامن: لوحة مشرف المؤسسة (ويب)
صفحة ويب عربية RTL بسيطة (ضمن نفس نمط لوحاتكم الحالية)، وظائفها بالترتيب الذي يراه المشرف: لوحة اليوم (خريطة كل الباصات الحية + حالة كل رحلة)، إدارة الخطوط والجداول، إدارة السائقين (إضافة/إيقاف/تقرير التزام)، إدارة الباصات، إدارة الطلاب (استيراد الكشف، طابور الموافقات، بحث وإيقاف)، الإعلانات (نص يصل إشعاراً لكل مشتركي خط أو للجميع)، والتقارير (التزام السائقين، إشغال تقديري لكل خط، ذروة الاستخدام — وهذه التقارير تحديداً هي ما يجعل الجامعة لا تستغني عنا بعد فصل واحد، لأنها ستكتشف خطوطها الخاسرة لأول مرة بالأرقام).
---
## القسم التاسع: تفريعات المدارس والفنادق والشركات
- **المدارس:** نفس البنية مع طبقة ولي الأمر: الأهل يسجلون كركاب عاديين ويربطون أبناءهم برمز من إدارة المدرسة، وإشعارات «صعد/نزل» تتطلب إثبات صعود (مرحلة ثانية: تأشير السائق على قائمة الطلاب أو QR). حساسية بيانات القاصرين أعلى — عقد معالجة بيانات إلزامي، ولا يظهر اسم الطفل الكامل في أي إشعار.
- **الفنادق:** الوجه المجدول (مكوك مطار بمواعيد) يستخدم نفس بنية الخطوط، والوجه الأهم (سيارة للنزيل من الاستقبال بفوترة شهرية) هو مشاوير عادية بحساب مؤسسي — موظف الاستقبال مشرفٌ يطلب من اللوحة، والفاتورة تتجمع على كيان الفندق. دفعكم جاهز بالدول الثلاث فالفوترة الشهرية تركيب محاسبي فوق الموجود.
- **الشركات والمصانع:** أقرب نسخة للجامعات (خطوط تجميع موظفين بورديات)، مع فارق وحيد: الجداول تتبع الورديات لا الفصول، والعضوية برقم وظيفي. هي أيضاً بلا موسمية — تملأ صيف الجامعات.
---
## القسم العاشر: النموذج المجاني — ماذا نكسب بالضبط وكيف نضبط كلفته
تثبيتاً لقرارك: الخدمة مجانية بالكامل للجميع (الجامعة، الطالب، السائق)، ونحن نكسب أربعة أشياء تُقاس رقمياً:
- **التثبيتات:** كل جامعة = آلاف تثبيتات بقرار واحد. المؤشر: تثبيتات لكل مؤسسة مفعّلة.
- **العادة اليومية:** فتحتان يومياً على الأقل لكل طالب نشط. المؤشر: نسبة النشطين يومياً من المسجلين.
- **التحويل لمشاوير مدفوعة:** زر «فاتك الباص» + الاستخدام المسائي. المؤشر الحاكم للمشروع كله: نسبة الطلاب الذين طلبوا أول مشوار مدفوع خلال ٣٠ يوماً من تفعيل العضوية.
- **السمعة والمرجعية:** شعارات الجامعات في العرض التسويقي وأمام المستثمرين.
وضبط التكلفة ممكن لأن أثقل بندين عندكم محلولان: الخرائط ملككم (صفر رسوم لكل طلب — ميزة قاتلة على أي منافس يدفع لغوغل عن كل طالب يفتح الخريطة)، وSMS نقلّصه بحيلة مطابقة هاتف الكشف أعلاه وبواتساب نابح. الباقي (سيرفر صغير + تخزين) هامشي. أي أن «الدعاية» هذه تكلفتها التشغيلية شبه ثابتة مهما كبر عدد الطلاب — وهذا ما يجعل النموذج المجاني آمناً مالياً.
مع تحفّظ واحد أسجله بأمانة: نُبقي في العقد بنداً يسمح بخدمات مدفوعة اختيارية لاحقاً (نسخة بعلامة الجامعة، باقة تقارير متقدمة، إشعارات أهل مميزة في المدارس) حتى لا نقفل باب الإيراد المباشر للأبد بوعد «مجاني إلى الأبد» مكتوب.
---
## القسم الحادي عشر: دليل مدير العلاقات العامة — كتيّب العمل الكامل
**الوصف الوظيفي:** مسؤول شراكات ميداني في كل دولة، خلفية مبيعات B2B أو علاقات جامعية، هدفه الرقمي: ٤ اجتماعات أسبوعياً، تجربتان موقّعتان كل ربع سنة، ومتابعة تفعيل ما يوقّعه (التوقيع بلا تفعيل لا يُحتسب له).
**بناء قائمة الأهداف:** يبدأ بالجامعات الخاصة التي تعلن خطوط باصات على مواقعها (القائمة تُجهّز مكتبياً قبل أي زيارة)، ثم المدارس الخاصة الكبرى، ثم الفنادق ٤–٥ نجوم، ثم مديري الحركة في الشركات الصناعية.
**من يقابل بالترتيب:** مدير الحركة/النقل أولاً (لا تتجاوزه أبداً — إن شعر أن النظام سيكشف تقصيره أو يستبدله سيقتل الصفقة من الظل؛ العرض يُصاغ له هو: «نظام يريحك من مكالمات وين الباص ويظهر انضباط دائرتك أمام الرئاسة»)، ثم نائب الرئيس للشؤون الإدارية (صاحب التوقيع)، وعمادة شؤون الطلبة (حليف داخلي لأن رضا الطلاب معيار أدائها). في الحكومية يضاف: اتحاد الطلبة كقناة ضغط إيجابي، والوزارة في سوريا.
**نص العرض في ثلاث جمل (يحفظها حفظاً):** «طلابكم يتصلون كل صباح يسألون وين الباص، وأهاليهم قلقون، ومكتب النقل غارق. نعطيكم نظام تتبع وإشعارات ولوحة تحكم كاملة على باصاتكم أنتم وسائقيكم أنتم — مجاناً بالكامل، تجهيزه أسبوعان. نكسب نحن أن الطالب يستخدم تطبيقنا، وتكسبون أنتم جامعة أهدأ وأكثر أماناً وتقارير تعرفون منها خطوطكم الخاسرة.»
**الاعتراضات المتوقعة وردودها الجاهزة:**
- «عندنا GPS على الباصات أصلاً» ← «نظام التتبع عندكم يراه موظف واحد في غرفة؛ نحن نضعه بجيب كل طالب وولي أمر، مع إشعارات — الفرق بين كاميرا مراقبة وخدمة.»
- «ليش مجاني؟ شو مصلحتكم؟» ← الصدق الكامل، فهو أقوى رد: «مصلحتنا أن ينزّل طلابكم تطبيقنا ويستخدموه بمشاويرهم الخاصة خارج الدوام. أنتم دعايتنا ونحن خدمتكم.» الشفافية هنا تبني الثقة ولا تضرّ.
- «بيانات طلابنا؟» ← «تُستخدم للتحقق فقط، عقد معالجة بيانات موقّع، لا نبيعها ولا نستخدمها إعلانياً، وتُحذف بانتهاء العقد.» (ويجب أن يكون هذا صادقاً وملزماً داخلياً).
- «ما عندنا وقت ولا فريق تقني» ← «لا نطلب أي ربط تقني: ملف إكسل واحد بأرقام الطلاب ويوم واحد مع مدير الحركة لرسم الخطوط. كل شيء علينا.»
- «خلونا نفكر» ← عرض التجربة المصغّرة فوراً: «جرّبوا على ٣ باصات فقط لشهر واحد، بلا أي التزام ولا توقيع طويل — إن لم يحبها الطلاب نسحبها بصمت.»
**العدّة التي نجهزها له:** صفحة تعريفية عربية واحدة، عرض حي على هاتفه فيه باص تجريبي يتحرك فعلاً (أقوى أداة إقناع على الإطلاق — تجهيزه على بيئة تجريبية إلزامي قبل أول زيارة)، نموذج اتفاقية تجربة من صفحتين، نموذج عقد معالجة بيانات، وبعد أول جامعة: دراسة حالة بأرقامها وفيديو شهادة من مدير نقلها.
**مراحل الصفقة التي يُدار بها (تُتابع أسبوعياً):** رصد ← اجتماع أول ← عرض حي ← اتفاقية تجربة ← استيراد الكشف ورسم الخطوط ← تفعيل ← مراجعة نهاية التجربة ← عقد سنوي مجاني موقّع + حق استخدام الشعار.
---
## القسم الثاني عشر: خطة التنفيذ المحدّثة
- **الآن — نهاية يوليو:** تجميد نطاق النسخة الأولى، وبدء `backend/transit/` وقاعدة `siro_transit`، واجتماع الجامعة المصرية (هي التجربة الأولى بحكم أنها طلبت)، وبدء توظيف مسؤول الشراكات الأول.
- **أغسطس:** بناء النسخة الأولى: الكيانات + الخطوط بالمحرر الداخلي + عضوية الطالب بالكشف المستورد + تتبع حي بغرف السوكيت + إشعارات الانطلاق والاقتراب + وضع الباص للسائق + لوحة مشرف بأساسياتها (خريطة اليوم، السائقون، الكشف، إعلان). بيئة العرض الحي للمندوبين تجهز من هذه النسخة نفسها.
- **سبتمبر:** إطلاق فعلي مع الجامعة المصرية أول أيام الفصل، والمندوبون يفتحون الأردن بالجامعات الخاصة على نفس النسخة.
- **الفصل الثاني (فبراير):** التحقق عبر API، محرر الخطوط للمشرفين، تقارير الإشغال، إثبات الصعود، أول مدرسة وأول فندق، وفتح سوريا بالنمط الثاني (ناقل متعاقد + مذكرة جامعة).
- **الصيف القادم:** الفصل الفيزيائي للسيرفر الصغير إن تحقق حده (~٥ مؤسسات فعالة)، ودخول الشركات والمصانع لملء الصيف.
---
## القسم الثالث عشر: جدول المخاطر المحدّث
| الخطر | الاحتمال | التخفيف |
|---|---|---|
| سالك أو سويفل يقلدان العرض المجاني | متوسط | سرعة توقيع عقود حصرية مع بند تجديد تلقائي؛ ميزتنا البنيوية أن خرائطنا مجانية وهم يدفعون عن كل مستخدم |
| مدير النقل يعرقل من الداخل | عالٍ إن أُهمل | العرض يُبنى حوله لا فوقه (القسم الحادي عشر) |
| كشوف طلاب متسربة أو مساء استخدامها | منخفض لكن كارثي | عزل قاعدة transit، تشفير حقل الرقم الجامعي، صلاحيات دنيا، والتزام حرفي بعقد المعالجة |
| سائقون لا يشغّلون التطبيق | متوسط | تقرير الالتزام للمشرف + واجهة الزر الواحد |
| موسمية أكاديمية | مؤكد | المصانع والفنادق تملأ الصيف (مرحلة مخططة أصلاً) |
| تضخم النطاق قبل الإطلاق | عالٍ | قائمة النسخة الأولى مجمّدة: تتبع، جداول، عضوية، إشعارات، لوحة أساسية — لا شيء غيرها |
---
**المصادر:** [شروط خدمة سويفل — ليست ناقلاً ولا تملك مركبات](https://www.swvl.com/terms-of-service)، [سويفل على ويكيبيديا](https://en.wikipedia.org/wiki/Swvl)، [منتج البرمجيات كخدمة من سويفل](https://www.swvl.com/services/software-as-a-service)، [نظرة عامة على أعمال سويفل وتمويل كباتنها](https://www.bitget.com/stock/nasdaq-swvl/what-is)، [تطبيق سالك على غوغل بلاي](https://play.google.com/store/apps/details?id=com.salek.studentapp&hl=en_US)، [موقع سالك](https://salekbus.com/).
هذا التقرير جاهز ليكون وثيقة العمل المرجعية للمشروع. الخطوة العملية التالية بيدك أنت: تجميد نطاق النسخة الأولى والبدء بمجلد `backend/transit/` وقاعدة البيانات — وأنا جاهز أبدأ ببناء المخطط التنفيذي للجداول وهيكل الملفات فور ما تقول ابدأ.
@@ -0,0 +1,80 @@
# تقرير شامل: سير عمليات نظام «مواصلاتي» (Workflow & Architecture)
**تاريخ الإصدار:** 2026-07-14
**المشروع:** منصة Siro - وحدة مواصلاتي (Transit)
---
## 1. مقدمة عن النظام
نظام «مواصلاتي» هو منصة تقنية متكاملة تهدف إلى رقمنة أساطيل النقل للمؤسسات (الجامعات، المدارس، الشركات، الفنادق) دون الحاجة لامتلاك المنصة لأي مركبات. يعتمد النظام على توفير البرمجيات (SaaS) مجاناً للمؤسسات مقابل استحواذ المنصة على المستخدمين (الطلاب/الموظفين) لتحويلهم لاحقاً إلى مستخدمين مدفوعين في خدمات النقل الذكي (Ride-hailing) الخاصة بـ Siro.
يدعم النظام نمطين تشغيليين رئيسيين:
1. **أسطول المؤسسة:** الجامعة/المدرسة تمتلك باصاتها وسائقيها.
2. **الناقل المتعاقد:** يتم إدخال طرف ثالث (شركة نقل متعاقدة) لتشغيل خطوط جامعة أو مؤسسة لا تملك أسطولاً، مع توفير برمجيات التتبع والتنظيم.
---
## 2. الهيكلة التقنية والمعمارية
لضمان الأداء العالي وعدم التأثير على تطبيق النقل الذكي الرئيسي، تم بناء النظام بمعمارية معزولة جزئياً:
- **قاعدة بيانات مستقلة (`siro_transit`):** تحتوي على جداول منفصلة للمؤسسات، السائقين، الباصات، الخطوط، الجداول، والعضويات. يُمنع عمل JOIN مباشر مع قواعد النقل الرئيسية لتسهيل فصل النظام مستقبلاً.
- **طبقة التخزين المؤقت (Redis):** تُستخدم لتخزين الجلسات، مواقع الباصات الحية، وتتبع حالة السائقين بشكل لحظي.
- **خوادم السوكيت (WebSockets):** سيرفرات مستقلة (`driver_socket.php` و `passenger_socket.php`) تتعامل مع بث مواقع الباصات واستقبالها لتقليل الضغط السحابي (آلاف الطلاب يتابعون عشرات الباصات).
---
## 3. سير العمليات الكامل (The Complete Workflow)
يتوزع سير العمل على أربعة أطراف رئيسية، تتفاعل مع بعضها لضمان رحلة سلسة من نقطة الانطلاق حتى الوصول:
### أ. إدارة النظام (فريق Siro / Super Admin)
1. **إنشاء المؤسسة:** يقوم فريق Siro بإنشاء حساب المؤسسة (مثال: جامعة الزرقاء)، ويحدد نوعها (جامعة/مدرسة/فندق) وموقعها (بوليغون الحرم الجامعي).
2. **إضافة مشرفي المؤسسة:** يتم إضافة مشرفي النقل التابعين للجامعة وتسجيل أرقام هواتفهم لمنحهم حق الوصول للوحة التحكم.
3. **اعتماد الخطوط (Route Approval):** عند قيام مشرف المؤسسة برسم خط جديد، يبقى في حالة "مسودة" (Draft). يقوم فريق Siro بمراجعته (مساره ومحطاته) ثم اعتماده ليصبح "نشطاً" (Active) ويظهر للطلاب.
### ب. مشرف المؤسسة (لوحة تحكم الويب Web Dashboard)
مشرف النقل في الجامعة يدير الأسطول عبر لوحة تحكم ويب مستقلة `transit_dashboard`:
1. **تسجيل الدخول:** باستخدام رقم الهاتف ورمز تحقق (OTP) عبر الواتساب.
2. **إدارة الأسطول:** إدخال بيانات الباصات (رقم اللوحة، السعة، الموديل).
3. **إدارة السائقين:** إضافة سائقي الباصات (الاسم، رقم الهاتف). النظام يرسل رسالة دعوة (Invite) للسائق مع رابط لتحميل تطبيق `siro_driver`. السائق هنا منفصل تماماً عن كابتن المشاوير ولا يتلقى طلبات عادية.
4. **رسم الخطوط والمحطات:**
- يقوم المشرف برسم مسار الباص على خريطة تفاعلية (Leaflet/MapLibre).
- يحدد نقاط التوقف (Stops) ومحيط كل نقطة (Geofence Radius - افتراضياً 150 متراً).
- يرسل الخط لفريق Siro للاعتماد.
5. **جداول الرحلات (Schedules):** بعد اعتماد الخط، يقوم المشرف بتحديد أوقات الانطلاق وأيام العمل (مثلاً: من الأحد للخميس، الساعة 7:30 صباحاً).
6. **إدارة الطلاب:** يرفع المشرف كشفاً بأسماء الطلاب وأرقامهم الجامعية عبر ملف CSV (Import Roster)، مما يتيح للطلاب تفعيل عضوياتهم فوراً في التطبيق.
### ج. السائق (تطبيق `siro_driver`)
تجربة السائق مصممة لتكون في غاية البساطة ولا تتطلب أي تشتت:
1. **التفعيل:** يتلقى رابط الدعوة، يفتح التطبيق، ويدخل رمز التفعيل أو الـ OTP.
2. **وضع الباص (Bus Mode):** يتعرف التطبيق عليه كسائق باص، ويخفي واجهة طلبات المشاوير العادية.
3. **بدء الرحلة:** تظهر أمامه رحلته القادمة. يضغط زر "ابدأ الرحلة" (`trip/start`).
4. **أثناء الرحلة:**
- يبدأ التطبيق ببث موقعه (Lat/Lng) عبر الـ Socket كل عدة ثوانٍ.
- **المرور التلقائي بالمحطات (Geofencing):** عند دخول الباص النطاق الجغرافي لأي محطة، يتحدث شريط التقدم تلقائياً دون تدخل السائق، ويتم إشعار النظام.
- يتوفر زر "تأخير" في حالة الزحام لإشعار المشتركين.
5. **إنهاء الرحلة:** عند الوصول للمحطة النهائية، يضغط "أنهِ الرحلة".
### د. الطالب / الراكب (تطبيق `siro_rider`)
1. **تفعيل العضوية:** يدخل تبويب "مواصلاتي"، يختار جامعته، ويدخل رقمه الجامعي. إذا كان الرقم مطابقاً للكشف المرفوع (وبنفس رقم الهاتف)، يتم تفعيله فوراً (بدون OTP إضافي لتوفير التكلفة).
2. **استعراض الخطوط:** يرى الخطوط المعتمدة وجداولها ويشترك بخطه المعتاد.
3. **التتبع الحي (Live Tracking):** يفتح خريطة الخط ليرى مسار الباص (Polyline) وموقع الباص الحي يتحرك أمامه (يستقبل الإحداثيات من الـ Passenger Socket).
4. **الإشعارات الذكية (FCM Notifications):**
- **إشعار الانطلاق:** الباص تحرك من نقطة البداية.
- **إشعار الاقتراب:** "الباص يبعد محطة واحدة عنك" (يعتمد على عبور الباص لمحيط الـ Geofence للمحطة السابقة).
- **إعلانات الطوارئ:** رسائل من المشرف (عطلة، تغيير مسار).
5. **نقطة التحويل الاستراتيجية:** في حال فات الباص، يظهر زر بارز "فاتك الباص؟ اطلب سيارة الآن". هذا الزر ينقل الطالب لطلب رحلة مدفوعة عادية من `Siro`، وهو العائد الربحي الأساسي للمنصة.
---
## 4. الاعتبارات الأمنية والضوابط
- **حماية المسارات (IDOR Protection):** لا يمكن لأي سائق إنهاء أو تعديل رحلة سائق آخر. النظام يتحقق من ملكية الرحلة ويطابق الـ `main_driver_id` المشفر.
- **تحديد معدل الطلبات (Rate Limiting):** حماية نقاط طلب الـ OTP وتسجيل الدخول لمنع هجمات الـ Spam والإرهاق.
- **التشفير (Encryption):** يتم تشفير أرقام الهواتف والأرقام الجامعية في قاعدة البيانات ولا يتم إرجاعها بصيغتها الصريحة، لضمان خصوصية بيانات الجامعات والطلاب.
- **صلاحيات السوكيت (Socket Authorization):** لا يُسمح للراكب بالانضمام لغرفة بث الباص إلا إذا كان يمتلك عضوية نشطة في المؤسسة المالكة للخط.
---
## الخلاصة
عملية "مواصلاتي" صُممت لتكون ذات كفاءة عالية، تعتمد على تفويض الإدارة اليومية لمشرفي المؤسسات (الجامعات/المدارس)، وتبسيط واجهة السائق لأقصى حد (زر بدء وإنهاء فقط)، ومنح الطالب تجربة تتبع حية وشفافة. المنظومة بالكامل تُبنى على عزل تقني متين يسمح بالتوسع السريع دون التأثير على البنية التحتية لخدمات نقل الركاب الأساسية.