المشكلة
تحتاج خدمة سيارات الأجرة التي تتلقى الحجوزات عبر تطبيق إلى أكثر بكثير من نموذج حجز. فعليها أن تجد سائقًا متاحًا قريبًا، وتعرض عليه الرحلة، وتنتظر رده، وتنتقل إلى غيره إن لم يقبل أحد، وكل ذلك خلال ثوانٍ. ولروما قواعدها الخاصة: أجرة ثابتة معتمدة من البلدية للرحلات من المطارات والميناء وإليها. وكان العميل يحتاج إلى السلسلة كاملة، من التوزيع إلى الدفع.
ما الذي بنيته
بنيت منصة للحجز والتوزيع في الوقت الفعلي، تضم واجهة خلفية واحدة وثلاثة تطبيقات للهاتف ولوحة إدارة على الويب.
- محرك التوزيع — يبحث عن السائقين المعتمدين والمتاحين الذين أرسلوا موقعهم خلال آخر 60 ثانية، ضمن نطاق بحث (8 km افتراضيًا). ثم يرتّب ما يصل إلى 10 منهم حسب زمن القيادة الفعلي في ظروف المرور الحالية من Google، ويعرض الرحلة على سائق واحد في كل مرة مع مهلة 20 ثانية للقبول.
- قواعد الأجرة في روما — تتعرف خدمة التسعير على 9 أماكن رئيسية، مثل مطار فيوميتشينو والمركز التاريخي، وتطبّق الأجرات الثابتة الـ 12 التي حددتها Roma Capitale (القرار 252/2024). أما الرحلات الأخرى فتُسعَّر وفق مسار Google، مع رسوم إضافية للأمتعة والركاب.
- ثلاثة تطبيقات — تطبيق للركاب، وتطبيق للسائقين، وتطبيق للجهاز اللوحي داخل السيارة يعرض المسار ولافتات الشركاء. وكلها مبنية بـ React Native وExpo، لنظام Android والويب.
- تتبع واتصال مباشر — يرسل Socket.IO مواقع السائقين وحالة الرحلة. ويمكن للراكب والسائق الاتصال ببعضهما داخل التطبيق عبر WebRTC، دون أن يرى أي منهما رقم هاتف الآخر.
- المدفوعات — Stripe مع webhooks يُتحقق من توقيعها، وطلبات PayPal. وتُضبط مفاتيح الدفع من لوحة الإدارة وتُحفظ مشفّرة.
- تسجيل السائقين — يرفع السائقون رخصهم ووثائقهم وصورهم. ويعتمدهم مشرف قبل أن يتمكنوا من بدء العمل.
- الرعاة والقسائم — بوابة للرعاة بثلاث خطط، وقسائم مع تتبع لمكافحة الاحتيال، إضافة إلى الرحلات المجدولة والتقييمات.
التقنيات المستخدمة
تعمل الواجهة الخلفية على Node.js 22 مع TypeScript وExpress وSocket.IO. وتُخزَّن البيانات في MariaDB/MySQL، وقد تطور المخطط عبر 24 ترحيلًا لـ SQL بإصدارات مرقّمة. ويتحقق Zod من المدخلات؛ ويتم تسجيل الدخول عبر JWT وحساب Google. وتتولى Google Maps المسارات وأزمنة الرحلات والترميز الجغرافي. وتستخدم التطبيقات Expo وReact Native.
لماذا بهذه الطريقة
يجب ألا يحصل راكبان أبدًا على السائق نفسه. فعندما يقبل السائق، يحجزه المحرك بعملية تحديث شرطية واحدة: مشغول، ولكن فقط إذا كان لا يزال متاحًا. وإذا لم يتغير أي صف، فهذا يعني أن السائق حُجز للتو، فتنتقل الرحلة إلى المرشح التالي. ويُرتَّب المرشحون حسب زمن القيادة لا المسافة المستقيمة، لأن أقرب سيارة في روما كثيرًا ما لا تكون الأسرع. وإذا لم تستجب Google، يعود الترتيب إلى المسافة.


