Update: 2026-06-17 18:22:52
849
SIRO_COMPLETE_REPORT_AR.md
Normal file
@@ -0,0 +1,849 @@
|
|||||||
|
<div dir="rtl">
|
||||||
|
|
||||||
|
# سِيرُو (Siro) — التقرير التسويقي والأمني الشامل
|
||||||
|
|
||||||
|
> **منصة النقل الذكي المتكاملة — الرائدة في سوريا، الأردن، ومصر**
|
||||||
|
>
|
||||||
|
> *نظام بيئي رقمي متكامل يربط الركاب بالسائقين عبر 4 تطبيقات ذكية، مع بنية تحتية أمنية متعددة الطبقات وتقنيات ذكاء اصطناعي متقدمة*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 فهرس المحتويات
|
||||||
|
|
||||||
|
1. [نظرة عامة عن المنصة](#نظرة-عامة-عن-المنصة)
|
||||||
|
2. [التطبيقات الأربعة](#التطبيقات-الأربعة)
|
||||||
|
3. [أنواع المركبات](#أنواع-المركبات)
|
||||||
|
4. [طرق الدفع](#طرق-الدفع)
|
||||||
|
5. [التكاملات الخارجية](#التكاملات-الخارجية)
|
||||||
|
6. [الميزات التقنية المتقدمة](#الميزات-التقنية-المتقدمة)
|
||||||
|
7. [الأمان متعدد الطبقات](#الأمان-متعدد-الطبقات)
|
||||||
|
8. [الذكاء الاصطناعي](#الذكاء-الاصطناعي)
|
||||||
|
9. [الإضافات المميزة](#الإضافات-المميزة)
|
||||||
|
10. [البنية التحتية](#البنية-التحتية)
|
||||||
|
11. [المقارنة التنافسية](#المقارنة-التنافسية)
|
||||||
|
12. [فرص النمو والتوسع](#فرص-النمو-والتوسع)
|
||||||
|
13. [الخلاصة](#الخلاصة)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 نظرة عامة عن المنصة
|
||||||
|
|
||||||
|
**Siro (سِيرُو)** هي منصة متكاملة لخدمات النقل والتوصيل الذكية، تعمل في **3 دول** هي **سوريا، الأردن، ومصر**. المنصة ليست مجرد تطبيق نقل عادي، بل هي **نظام بيئي رقمي متكامل** (Digital Ecosystem) يغطي كامل رحلة العميل من لحظة طلب الرحلة إلى ما بعد اكتمالها.
|
||||||
|
|
||||||
|
### 📊 المنصة بالأرقام
|
||||||
|
|
||||||
|
| المقياس | القيمة |
|
||||||
|
|---------|--------|
|
||||||
|
| عدد التطبيقات المتصلة | 4 تطبيقات |
|
||||||
|
| الدول المدعومة | 3 دول (سوريا، الأردن، مصر) |
|
||||||
|
| أنواع المركبات | 12 نوعاً |
|
||||||
|
| طرق الدفع | 7 خيارات |
|
||||||
|
| خدمات التكامل الخارجي | 15+ خدمة |
|
||||||
|
| ملفات PHP في الخادم الخلفي | 395+ ملفاً |
|
||||||
|
| قواعد البيانات | 3 قواعد بيانات رئيسية |
|
||||||
|
| سيرفرات WebSocket | 2 (Driver + Passenger) |
|
||||||
|
| عدد وحدات لوحة التحكم الإدارية | 15+ وحدة |
|
||||||
|
| محركات الذكاء الاصطناعي | 3 محركات (Azure + OpenAI + Llama) |
|
||||||
|
|
||||||
|
### 🎯 الرؤية
|
||||||
|
|
||||||
|
تقديم تجربة نقل ذكية وآمنة ومتكاملة تنافس كبرى منصات النقل العالمية (أوبر، كريم، Bolt) بميزات محلية مبتكرة تفهم احتياجات السوق العربي.
|
||||||
|
|
||||||
|
### 🌍 الدول المدعومة
|
||||||
|
|
||||||
|
| الدولة | الحالة | الميزات الخاصة |
|
||||||
|
|--------|--------|----------------|
|
||||||
|
| 🇸🇾 **سوريا** | 🟢 نشط | MTN Cash، Syriatel Cash، خوادم محلية |
|
||||||
|
| 🇯🇴 **الأردن** | 🟢 نشط | PayMob، خوادم إقليمية |
|
||||||
|
| 🇪🇬 **مصر** | 🟢 نشط | E-Cash، SMS Kazumi، خوادم إقليمية |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📱 التطبيقات الأربعة (رباعية التطبيقات المترابطة)
|
||||||
|
|
||||||
|
### 1️⃣ تطبيق الراكب (Siro Rider) — تجربة الركوب الذكية
|
||||||
|
|
||||||
|
تطبيق الراكب هو واجهة المستخدم الأساسية، مصمم لتجربة سلسة وسريعة.
|
||||||
|
|
||||||
|
**الميزات الرئيسية:**
|
||||||
|
|
||||||
|
| الميزة | الوصف |
|
||||||
|
|--------|-------|
|
||||||
|
| 🗺️ **واجهة خرائط مدمجة** | Google Maps + Here Maps + Map SaaS للبحث والتوجيه |
|
||||||
|
| 🔍 **بحث ذكي عن الوجهة** | اقتراحات تلقائية للأماكن مع تكامل متعدد لمزودي الخرائط |
|
||||||
|
| 💰 **عرض السعر التقديري** | حساب التكلفة قبل تأكيد الرحلة مع شفافية كاملة |
|
||||||
|
| 🚙 **اختيار نوع المركبة** | 12 نوع مركبة مختلفة تناسب كل الاحتياجات |
|
||||||
|
| 📍 **تتبع السائق المباشر** | تحديث موقع السائق كل 3-5 ثوانٍ عبر WebSocket |
|
||||||
|
| 💳 **دفع إلكتروني** | 7 طرق دفع مختلفة (نقدي، بطاقة، محفظة، جوال) |
|
||||||
|
| ⭐ **تقييم السائق** | نظام تقييم مزدوج بالنجوم والتعليقات |
|
||||||
|
| 🆘 **زر الطوارئ (SOS)** | إشارة طوارئ فورية مع إرسال الموقع الحي |
|
||||||
|
| 💬 **دردشة داخلية** | تواصل مع السائق دون مشاركة أرقام الهواتف |
|
||||||
|
| 🎫 **أكواد خصم وعروض** | نظام ترويجي متكامل مع كود دعوة |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2️⃣ تطبيق السائق (Siro Driver) — منصة الكابتن الاحترافية
|
||||||
|
|
||||||
|
تطبيق متطور يمكّن السائقين من إدارة الرحلات بكفاءة عالية.
|
||||||
|
|
||||||
|
**الميزات الرئيسية:**
|
||||||
|
|
||||||
|
| الميزة | الوصف التقني |
|
||||||
|
|--------|--------------|
|
||||||
|
| 🎯 **عروض الرحلات عبر التراكب المباشر (Overlay)** | نظام Android System Overlay يعرض تفاصيل الرحلة فوق أي تطبيق — حتى لو كان الهاتف مقفلاً |
|
||||||
|
| 🗺️ **ملاحة صوتية (Turn-by-Turn)** | إرشادات TTS خطوة بخطوة مع تحديث المسار تلقائياً |
|
||||||
|
| 🔄 **وضع الخدمة (Online/Offline)** | تشغيل تلقائي في الخلفية عبر Android Foreground Service 24/7 |
|
||||||
|
| 📊 **إحصائيات الأرباح اللحظية** | عرض فوري للرحلات اليومية، الإجمالي، العمولات |
|
||||||
|
| ⏱️ **مؤقت 15 ثانية للقبول** | قبول تلقائي أو رفض مع صوت تنبيه مخصص |
|
||||||
|
| 🔊 **صوت تنبيه مخصص** | ملف "ding.wav" مشغل عبر MediaPlayer |
|
||||||
|
| 🚗 **تحديث الموقع في الخلفية** | Foreground Service مع تحديث GPS كل 3 ثوانٍ |
|
||||||
|
| 🛑 **كشف الانحراف عن المسار** | تنبيه إذا انحرف السائق عن المسار بأكثر من 50 متراً |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3️⃣ تطبيق الإدارة (Siro Admin) — لوحة تحكم شاملة (PWA)
|
||||||
|
|
||||||
|
لوحة تحكم إدارية متكاملة مبنية بـ Flutter Web (PWA) مع 15+ وحدة إدارية.
|
||||||
|
|
||||||
|
**الوحدات الإدارية:**
|
||||||
|
|
||||||
|
| الوحدة | الوظيفة |
|
||||||
|
|--------|---------|
|
||||||
|
| 📈 **لوحة التحكم (Dashboard)** | إحصائيات فورية مع رسوم بيانية متقدمة |
|
||||||
|
| 👨✈️ **إدارة الكباتن** | قبول/رفض، توثيق، حظر، مراجعة ملفات السائقين |
|
||||||
|
| 👤 **إدارة الركاب** | تفاصيل كاملة، سجل الرحلات، حظر وإلغاء حظر |
|
||||||
|
| 🚗 **إدارة الرحلات** | تتبع مباشر، سجل كامل، بحث متقدم، مراقبة حية |
|
||||||
|
| 💰 **الإدارة المالية** | تقارير الأرباح، العمولات، التسويات المالية |
|
||||||
|
| 📊 **التحليلات المتقدمة** | مؤشرات الأداء، التقارير الشهرية والسنوية |
|
||||||
|
| 🔒 **الأمان والرقابة** | سجلات التدقيق (Audit Logs)، مكافحة الاحتيال |
|
||||||
|
| 🎯 **نظام العمولات (Kazan)** | تحرير نسب العمولات ونماذج الأسعار |
|
||||||
|
| 🏷️ **العروض الترويجية** | إنشاء وإدارة أكواد الخصم والعروض |
|
||||||
|
| 👥 **إدارة الموظفين** | صلاحيات الأدوار، موافقات التسجيل |
|
||||||
|
| ⭐ **مراقبة الجودة** | بطاقات أداء السائقين، القوائم السوداء |
|
||||||
|
| 🖥️ **مراقبة الخوادم** | حالة السيرفرات، الأداء، وقت التشغيل |
|
||||||
|
| 📄 **إدارة الفواتير** | إنشاء وطباعة الفواتير |
|
||||||
|
| 🔄 **أدوات ترحيل البصمة** | إعادة تعيين بصمة الجهاز للمستخدمين |
|
||||||
|
| 📝 **إدارة الشكاوى** | متابعة وحل شكاوى المستخدمين |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4️⃣ تطبيق الخدمة الميدانية (Siro Service) — منصة تسجيل السائقين
|
||||||
|
|
||||||
|
تطبيق متخصص لموظفي الخدمة الميدانية لتسجيل وتوثيق السائقين الجدد.
|
||||||
|
|
||||||
|
**الميزات:**
|
||||||
|
|
||||||
|
| الميزة | الوصف |
|
||||||
|
|--------|-------|
|
||||||
|
| 📸 تصوير المستندات | تصوير الهوية ورخصة القيادة وأوراق السيارة مباشرة من الكاميرا |
|
||||||
|
| 🤖 **استخراج بيانات تلقائي بالذكاء الاصطناعي** | Azure OCR + OpenAI GPT + Llama AI لاستخراج البيانات |
|
||||||
|
| ✅ التحقق الميداني | التحقق من السيارة والسائق في الموقع |
|
||||||
|
| 📝 رفع الصور | رفع مباشر للخادم مع ضغط تلقائي |
|
||||||
|
| ⏱️ تسجيل فوري | تقليل وقت التسجيل من أيام إلى دقائق |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚙 أنواع المركبات المتاحة (12 نوعاً)
|
||||||
|
|
||||||
|
| النوع | الرمز | الوصف |
|
||||||
|
|-------|-------|-------|
|
||||||
|
| ⚡ **سرعة (Speed)** | Speed | الرحلات القياسية — السيارات العادية |
|
||||||
|
| 🌟 **راحة (Comfort)** | Comfort | رحلات فاخرة بسيارات مريحة |
|
||||||
|
| 👨👩👧👦 **عائلية (Family)** | Family | سيارات عائلية كبيرة الحجم |
|
||||||
|
| 📦 **توصيل (Delivery)** | Delivery | توصيل الطرود والطلبات |
|
||||||
|
| 💸 **اقتصادي (Free/Blash)** | Blash | رحلات اقتصادية بأسعار مخفضة |
|
||||||
|
| 🌙 **ليلية (Late)** | Late | رحلات خارج أوقات الذروة |
|
||||||
|
| 🚛 **نقل ثقيل (Heavy)** | Heavy | نقل البضائع والأغراض الثقيلة |
|
||||||
|
| 🏔️ **طبيعة (Nature)** | Nature | رحلات الطرق الخلابة والمناطق الوعرة |
|
||||||
|
| 🔌 **كهربائي (Electric)** | Electric | سيارات كهربائية صديقة للبيئة |
|
||||||
|
| 🏍️ **دراجة وردية (Pink Bike)** | PinkBike | دراجات نارية للتنقل السريع |
|
||||||
|
| 🚐 **فان (Van)** | Van | حافلات صغيرة للمجموعات |
|
||||||
|
| 👩 **سائقة (Female Driver)** | FemalDriver | سائقات نساء — خيار خاص للسيدات |
|
||||||
|
|
||||||
|
> ✅ جميع أنواع المركبات مدعومة في الدول الثلاث: سوريا، الأردن، مصر
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💳 طرق الدفع المتعددة (7 خيارات)
|
||||||
|
|
||||||
|
| طريقة الدفع | التوفر | التقنية المستخدمة |
|
||||||
|
|-------------|--------|-------------------|
|
||||||
|
| 💵 **نقدي (Cash)** | جميع الدول | دفع يدوي عند الوصول |
|
||||||
|
| 💳 **بطاقة فيزا/ماستركارد** | سوريا، الأردن، مصر | PayMob Payment Gateway |
|
||||||
|
| 👛 **محفظة إلكترونية (Wallet)** | جميع الدول | خادم محفظة مخصص (WalletIntaleq) |
|
||||||
|
| 📱 **MTN موبايل موني** | سوريا | MTN Cash API |
|
||||||
|
| 📱 **سيريتل موبايل موني** | سوريا | Syriatel Cash API |
|
||||||
|
| 🔄 **E-Cash** | مصر | خدمة E-Cash المصرية |
|
||||||
|
| 🌐 **Stripe** | دولي | Stripe Payment Gateway |
|
||||||
|
|
||||||
|
### 💼 المحفظة الإلكترونية (Wallet System)
|
||||||
|
|
||||||
|
نظام المحفظة هو نظام دفع داخلي متكامل يتكون من:
|
||||||
|
|
||||||
|
- **محفظة الراكب**: شحن رصيد، دفع للرحلات، استرداد أموال
|
||||||
|
- **محفظة السائق**: استلام الأرباح، سحب الأموال
|
||||||
|
- **التحويل بين المحافظ**: تحويل رصيد بين المستخدمين
|
||||||
|
- **سجل المعاملات الكامل**: تتبع جميع الحركات المالية
|
||||||
|
- **نظام البقشيش (Tips)**: إضافة بقشيش للسائق بعد الرحلة
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔗 التكاملات الخارجية (شركاء الخدمة)
|
||||||
|
|
||||||
|
### 🗺️ الخرائط والملاحة
|
||||||
|
|
||||||
|
| الخدمة | الوظيفة | نوع التكامل |
|
||||||
|
|--------|---------|-------------|
|
||||||
|
| **Google Maps** | عرض الخرائط، الترميز الجغرافي، التوجيه | API Key |
|
||||||
|
| **Here Maps** | البحث والاقتراح التلقائي للأماكن | API Key |
|
||||||
|
| **Map SaaS** (خاص) | توجيه مخصص، ترميز جغرافي عكسي، بحث الأماكن | x-api-key |
|
||||||
|
| **OpenStreetMap (OSRM)** | توجيه عبر مسارات — خادم مخصص لكل دولة | Internal API |
|
||||||
|
|
||||||
|
### 📱 التواصل والإشعارات
|
||||||
|
|
||||||
|
| الخدمة | الوظيفة |
|
||||||
|
|--------|---------|
|
||||||
|
| **Firebase (FCM)** | إشعارات لحظية، تحليلات، Crashlytics |
|
||||||
|
| **Twilio** | التحقق عبر SMS (OTP) |
|
||||||
|
| **WhatsApp Cloud API** | إرسال كود التحقق عبر واتساب |
|
||||||
|
| **SMS Kazumi** | مزود SMS في مصر |
|
||||||
|
|
||||||
|
### 🤖 الذكاء الاصطناعي
|
||||||
|
|
||||||
|
| الخدمة | الوظيفة |
|
||||||
|
|--------|---------|
|
||||||
|
| **Azure OCR** | مسح ضوئي للمستندات واستخراج النصوص |
|
||||||
|
| **OpenAI GPT-3.5** | تحليل وفهم بيانات المستندات |
|
||||||
|
| **Llama AI** | نموذج ذكاء اصطناعي بديل لاستخراج البيانات (Fallback) |
|
||||||
|
|
||||||
|
### 📞 الاتصالات
|
||||||
|
|
||||||
|
| الخدمة | الوظيفة |
|
||||||
|
|--------|---------|
|
||||||
|
| **Agora** | مكالمات صوتية وفيديو داخل التطبيق |
|
||||||
|
| **WebRTC** | خدمة الإشارات للاتصالات المباشرة |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚙️ الميزات التقنية المتقدمة
|
||||||
|
|
||||||
|
### 🎯 نظام التوزيع الذكي (Smart Dispatching)
|
||||||
|
|
||||||
|
نظام التوزيع هو قلب المنصة، وهو المسؤول عن مطابقة الركاب مع السائقين بأقل وقت استجابة.
|
||||||
|
|
||||||
|
**المكونات:**
|
||||||
|
|
||||||
|
| المكون | التقنية | الوصف |
|
||||||
|
|--------|---------|-------|
|
||||||
|
| **WebSocket مزدوج** | PHP WebSocket (Socket.IO) | سيرفر مستقل للسائقين (port 2020) وآخر للركاب (port 3030) |
|
||||||
|
| **بحث مكاني (GIS Query)** | MySQL SPATIAL INDEX | استخدام GEOMETRY و SRID=4326 للبحث عن السائقين الأقرب |
|
||||||
|
| **توزيع فوري** | Redis GEOADD + GEORADIUS | تخزين مواقع السائقين في Redis مع تحديث كل 500ms |
|
||||||
|
| **نظام انتظار ذكي** | Event Buffer + Redis Pipeline | تجميع الأحداث وإرسالها دفعة واحدة كل 500ms |
|
||||||
|
| **تجميع الأحداث (Event Buffering)** | $eventBuffer في الذاكرة | تجاهل التحديثات إذا لم يتغير الموقع بأكثر من 10 أمتار |
|
||||||
|
| **Forward غير متزامن** | Async HTTP Forward | إرسال موقع السائق إلى سيرفر الراكب مع Throttle (3 ثوانٍ، 15 متراً) |
|
||||||
|
|
||||||
|
**سير العمل:**
|
||||||
|
|
||||||
|
```
|
||||||
|
1. الراكب يطلب رحلة → بحث في Redis عن أقرب السائقين → إرسال عرض للسائق
|
||||||
|
2. السائق يقبل → WebSocket يرسل ride_accepted للراكب
|
||||||
|
3. تتبع مباشر → Driver Socket → Forward → Passenger Socket → الراكب
|
||||||
|
4. إعادة حساب المسار → OSRM Routing → Map SaaS → عرض المسار على الخريطة
|
||||||
|
5. انتهاء الرحلة → خصم المبلغ من المحفظة → تقييم متبادل
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🗺️ نظام الخرائط الحية (Real-time Tracking)
|
||||||
|
|
||||||
|
| الميزة | الوصف التقني |
|
||||||
|
|--------|--------------|
|
||||||
|
| تحديث موقع السائق | كل 3-5 ثوانٍ عبر WebSocket مع Smooth Animation |
|
||||||
|
| تتبع المسار المباشر | تحديث زاوية السيارة حسب الاتجاه باستخدام تحديثات GPS |
|
||||||
|
| **كشف الانحراف** | تنبيه إذا انحرف السائق عن المسار بأكثر من 50 متراً |
|
||||||
|
| إعادة التوجيه التلقائي | إعادة حساب المسار عبر OSRM إذا لزم الأمر |
|
||||||
|
| حساب وقت الوصول (ETA) | خوارزميات محلية دقيقة لحساب الوقت المتبقي |
|
||||||
|
| Polling Fallback | التبديل التلقائي للاقتراع كل 4 ثوانٍ عند فقدان WebSocket |
|
||||||
|
|
||||||
|
### 💬 المحادثة الفورية (In-App Chat)
|
||||||
|
|
||||||
|
- 🗨️ **دردشة داخلية** بين السائق والراكب دون مشاركة أرقام الهواتف
|
||||||
|
- 🔒 **حماية الخصوصية** — لا يرى الراكب رقم السائق والعكس
|
||||||
|
- 📱 تدعم الوسائط والنصوص
|
||||||
|
- 🚫 **سجل المحادثة** مشفر ومحمي
|
||||||
|
|
||||||
|
### 🆘 نظام الطوارئ (Emergency/SOS)
|
||||||
|
|
||||||
|
- 🚨 إشارة طوارئ مباشرة إلى فريق الدعم
|
||||||
|
- 📹 إرسال الموقع الحي لفريق الطوارئ
|
||||||
|
- 🎥 تكامل مع Agora لمكالمات الفيديو الفورية
|
||||||
|
- 📞 تكامل مع WebRTC للاتصالات المباشرة
|
||||||
|
- 👮 إشعارات للسلطات المحلية (حسب الدولة)
|
||||||
|
|
||||||
|
### 🔄 إعادة الاتصال الذكي (Auto-Reconnect)
|
||||||
|
|
||||||
|
| الطبقة | الآلية | التفاصيل |
|
||||||
|
|--------|--------|----------|
|
||||||
|
| WebSocket | 20 محاولة مع تأخير تصاعدي | 2-10 ثوانٍ بين المحاولات |
|
||||||
|
| Polling Fallback | تبديل تلقائي | كل 4 ثوانٍ كحد أقصى |
|
||||||
|
| مؤقت الصحة | Heartbeat كل 15 ثانية | التأكد من استقرار الاتصال |
|
||||||
|
| كشف القطع | isSocketHealthy() | تحقق من آخر تحديث (< 20 ثانية) |
|
||||||
|
| Auto-refresh JWT | عند استقبال 401 | تجديد التوكين تلقائياً |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛡️ الأمان متعدد الطبقات (Multi-Layer Security)
|
||||||
|
|
||||||
|
> هذا القسم يغطي بنية الأمان الكامنة في المنصة من منظور تقني وتسويقي
|
||||||
|
|
||||||
|
### 🏗️ طبقات الأمان الخمس
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────┐
|
||||||
|
│ Layer 1: 🔑 المصادقة (Authentication) │
|
||||||
|
│ JWT + بصمة الجهاز + MFA + OTP │
|
||||||
|
├─────────────────────────────────────────────────────────┤
|
||||||
|
│ Layer 2: 🚪 التفويض (Authorization) │
|
||||||
|
│ Role-based + Ownership Check + Rate Limiting │
|
||||||
|
├─────────────────────────────────────────────────────────┤
|
||||||
|
│ Layer 3: 🔐 حماية البيانات (Data Protection) │
|
||||||
|
│ AES-256-CBC + IV عشوائي + HTTPS/TLS + Certificate Pin │
|
||||||
|
├─────────────────────────────────────────────────────────┤
|
||||||
|
│ Layer 4: 🧱 سلامة البيانات (Integrity) │
|
||||||
|
│ Prepared Statements + Input Validation + HMAC-SHA256 │
|
||||||
|
├─────────────────────────────────────────────────────────┤
|
||||||
|
│ Layer 5: 👁️ المراقبة والكشف (Detection) │
|
||||||
|
│ Audit Logs + Rate Limiting + Security Logging + Alerts │
|
||||||
|
└─────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🔑 الطبقة الأولى: المصادقة (Authentication)
|
||||||
|
|
||||||
|
| الآلية | التقنية | الوصف |
|
||||||
|
|--------|---------|-------|
|
||||||
|
| **JWT Tokens** | مخصص (custom) | توكنات JWT تصدر عند تسجيل الدخول، تتحقق في كل طلب |
|
||||||
|
| **بصمة الجهاز (Fingerprint)** | SHA-256 + HMAC | بصمة جهاز فريدة مربوطة بجهاز المستخدم |
|
||||||
|
| **المصادقة متعددة العوامل (MFA)** | بصمة + OTP + Token | الحماية بعاملين على الأقل |
|
||||||
|
| **SMS OTP** | Twilio + WhatsApp | إرسال رمز تحقق عبر SMS أو واتساب |
|
||||||
|
| **Google/Apple Sign-In** | Firebase Auth | تسجيل دخول بحسابات التواصل الاجتماعي |
|
||||||
|
| **التسجيل ببصمة الجهاز** | hash_equals | التحقق من البصمة مع مقارنة آمنة زمنياً (Timing-safe) |
|
||||||
|
|
||||||
|
**إدارة التوكنات:**
|
||||||
|
|
||||||
|
| النوع | التخزين | مدة الصلاحية | آلية التجديد |
|
||||||
|
|-------|---------|---------------|--------------|
|
||||||
|
| JWT (رئيسي) | GetStorage (مشفر) | 1 ساعة | Auto-refresh عند 401 |
|
||||||
|
| JWT (محفظة) | GetStorage (مشفر) | 1 ساعة | Auto-refresh منفصل |
|
||||||
|
| FCM Token | GetStorage + DB | حسب Firebase | عند بدء التطبيق |
|
||||||
|
| Refresh Token | FlutterSecureStorage | طويل المدى | عند تسجيل الدخول |
|
||||||
|
| Server Token | قاعدة البيانات | جلسة واحدة | مع توقيع HMAC |
|
||||||
|
|
||||||
|
### 🚪 الطبقة الثانية: التفويض (Authorization)
|
||||||
|
|
||||||
|
| الآلية | الوصف التقني |
|
||||||
|
|--------|--------------|
|
||||||
|
| **Role-based Access** | أدوار (Passenger, Driver, Admin, Service) مع صلاحيات محددة |
|
||||||
|
| **Device Binding** | X-Device-FP header مقابل JWT fingerprint claim |
|
||||||
|
| **Wallet Auth** | JWT منفصل + HMAC لعمليات الدفع |
|
||||||
|
| **Ownership Verification** | التحقق من أن المستخدم يملك المورد المطلوب |
|
||||||
|
| **Admin Authorization** | التحقق من دور المسؤول مع صلاحيات دقيقة |
|
||||||
|
|
||||||
|
### 🔐 الطبقة الثالثة: حماية البيانات (Data Protection)
|
||||||
|
|
||||||
|
**تشفير AES-256-CBC مع IV عشوائي:**
|
||||||
|
|
||||||
|
```
|
||||||
|
قبل الإصلاح: IV ثابت → نفس النص = نفس التشفير ← ثغرة 🔴
|
||||||
|
بعد الإصلاح: IV عشوائي لكل تشفير ← كل مرة تشفير مختلف ← آمن ✅
|
||||||
|
|
||||||
|
سير العمل الآمن:
|
||||||
|
1. توليد IV عشوائي (16 بايت) باستخدام openssl_random_pseudo_bytes
|
||||||
|
2. تشفير البيانات بـ AES-256-CBC
|
||||||
|
3. ضم IV مع النص المشفر
|
||||||
|
4. تشفير بـ base64
|
||||||
|
5. عند فك التشفير: استخراج IV من أول 16 بايت
|
||||||
|
```
|
||||||
|
|
||||||
|
**البيانات المشفرة:**
|
||||||
|
|
||||||
|
| نوع البيانات | مستوى التشفير |
|
||||||
|
|--------------|---------------|
|
||||||
|
| أرقام الهواتف | AES-256-CBC + IV عشوائي |
|
||||||
|
| بطاقات الهوية | AES-256-CBC + IV عشوائي |
|
||||||
|
| معلومات الدفع | AES-256-CBC + HMAC |
|
||||||
|
| كلمات المرور | bcrypt/Argon2ID (hash) |
|
||||||
|
| مفاتيح API | AES-256-CBC |
|
||||||
|
| توقيعات HMAC | SHA-256 |
|
||||||
|
|
||||||
|
**SSL/TLS:**
|
||||||
|
|
||||||
|
- ✅ جميع اتصالات API عبر HTTPS
|
||||||
|
- ✅ تثبيت الشهادة (Certificate Pinning) على تطبيقات Flutter
|
||||||
|
- ✅ التحقق من SSL في كل طلب (CURLOPT_SSL_VERIFYPEER)
|
||||||
|
- ✅ HSTS (Strict-Transport-Security)
|
||||||
|
- ❌ تمت إزالة نقاط نهاية HTTP (تم الاستبدال بـ HTTPS)
|
||||||
|
|
||||||
|
### 🧱 الطبقة الرابعة: سلامة البيانات (Integrity)
|
||||||
|
|
||||||
|
| الإجراء | الوصف |
|
||||||
|
|---------|--------|
|
||||||
|
| **Prepared Statements** | جميع استعلامات SQL تستخدم Prepared Statements (PDO) |
|
||||||
|
| **Input Validation** | التحقق من جميع المدخلات (القوائم البيضاء، الفلاتر) |
|
||||||
|
| **Output Encoding** | ترميز المخرجات لمنع XSS |
|
||||||
|
| **HMAC-SHA256** | توقيع جميع طلبات الدفع بين الخوادم |
|
||||||
|
| **Anti-Replay** | Timestamp + Nonce لمنع إعادة تشغيل الطلبات |
|
||||||
|
| **Idempotency Key** | منع معالجة نفس الطلب مرتين (الدفع، إنشاء الرحلة) |
|
||||||
|
| **Race Condition Guards** | حراس التكرار في دورة حياة الرحلة |
|
||||||
|
|
||||||
|
### 👁️ الطبقة الخامسة: المراقبة والكشف (Detection)
|
||||||
|
|
||||||
|
| الإجراء | الآلية |
|
||||||
|
|---------|--------|
|
||||||
|
| **Audit Logging** | تسجيل جميع العمليات الحساسة (تسجيل دخول، معاملات مالية، تعديلات) |
|
||||||
|
| **Rate Limiting** | تحديد عدد الطلبات لكل مستخدم/عنوان IP |
|
||||||
|
| **Login Monitoring** | تسجيل محاولات تسجيل الدخول الفاشلة والناجحة |
|
||||||
|
| **Fraud Detection** | كشف الأنماط المشبوهة في المعاملات المالية |
|
||||||
|
| **Error Logging** | تسجيل الأخطاء بدون كشف معلومات حساسة |
|
||||||
|
| **Server Monitoring** | مراقبة أداء الخوادم ووقت التشغيل |
|
||||||
|
| **Alerting** | تنبيهات في الوقت الفعلي للأنشطة المشبوهة |
|
||||||
|
|
||||||
|
### 🔐 حماية نظام الدفع (Payment Security)
|
||||||
|
|
||||||
|
نظام الدفع في سيرو مبني على بنية S2S (Server-to-Server) آمنة:
|
||||||
|
|
||||||
|
```
|
||||||
|
تطبيق Flutter ←→ API Server (JWT + HMAC) ←→ Wallet Server (HMAC + Timestamp + Backend ID)
|
||||||
|
```
|
||||||
|
|
||||||
|
| الإجراء | الوصف |
|
||||||
|
|---------|--------|
|
||||||
|
| JWT إجباري | لا يمكن تنفيذ أي معاملة مالية بدون JWT صالح |
|
||||||
|
| HMAC-SHA256 | توقيع جميع الطلبات بمفتاح سري مشترك بين الخوادم |
|
||||||
|
| Timestamp + Nonce | منع هجمات إعادة التشغيل (Replay Attacks) |
|
||||||
|
| Backend ID | تعريف الخادم المُصدر للطلب |
|
||||||
|
| Rate Limiting | حد أقصى للمعاملات لكل مستخدم |
|
||||||
|
| التحقق من المبلغ | التحقق من أن المبلغ ضمن الحدود المسموحة (1-10,000) |
|
||||||
|
| Idempotency | منع معالجة نفس طلب الدفع مرتين |
|
||||||
|
| Audit Trail | تسجيل جميع المعاملات المالية مع التفاصيل الكاملة |
|
||||||
|
|
||||||
|
### 🛡️ رؤوس الأمان (Security Headers)
|
||||||
|
|
||||||
|
| الرأس | القيمة | الغرض |
|
||||||
|
|-------|--------|-------|
|
||||||
|
| Strict-Transport-Security | max-age=31536000 | فرض HTTPS |
|
||||||
|
| X-Frame-Options | DENY | منع Clickjacking |
|
||||||
|
| X-Content-Type-Options | nosniff | منع MIME sniffing |
|
||||||
|
| Content-Security-Policy | سياسة مقيدة | منع XSS |
|
||||||
|
| X-XSS-Protection | 1; mode=block | حماية عبر المتصفح |
|
||||||
|
| Referrer-Policy | strict-origin-when-cross-origin | حماية الإحالات |
|
||||||
|
|
||||||
|
### 📱 أمن تطبيقات الهاتف (Mobile Security)
|
||||||
|
|
||||||
|
| الإجراء | الوصف |
|
||||||
|
|---------|-------|
|
||||||
|
| **تثبيت الشهادة** | Certificate Pinning في تطبيقات Flutter |
|
||||||
|
| **التخزين الآمن** | FlutterSecureStorage (Keychain/Keystore) للبيانات الحساسة |
|
||||||
|
| **أذونات محدودة** | تم تقليل الأذونات إلى الحد الأدنى المطلوب |
|
||||||
|
| **GetStorage مشفر** | تخزين محلي مشفر للبيانات |
|
||||||
|
| **Android Foreground Service** | خدمة خلفية دائمة مع وصول محدود |
|
||||||
|
| **No Debug Code** | إزالة جميع أكواد التصحيح من الإنتاج |
|
||||||
|
|
||||||
|
### 🔄 المصادقة بين الخوادم (S2S Authentication)
|
||||||
|
|
||||||
|
```
|
||||||
|
API Server → Wallet Server:
|
||||||
|
Header: X-Signature (HMAC-SHA256)
|
||||||
|
Header: X-Timestamp (Unix Time)
|
||||||
|
Header: X-Backend-ID (معرف فريد)
|
||||||
|
Header: X-Nonce (رقم عشوائي لمرة واحدة)
|
||||||
|
Body: JSON (JWT + Data)
|
||||||
|
|
||||||
|
Wallet Server → تحقق:
|
||||||
|
1. التحقق من Timestamp (ضمن 60 ثانية)
|
||||||
|
2. التحقق من Backend ID
|
||||||
|
3. التحقق من HMAC Signature
|
||||||
|
4. التحقق من Nonce (لم يتم استخدامه من قبل)
|
||||||
|
5. التحقق من JWT Payload
|
||||||
|
```
|
||||||
|
|
||||||
|
### 📊 تقييم الأمان العام
|
||||||
|
|
||||||
|
| المجال | التقييم | الحالة |
|
||||||
|
|--------|---------|--------|
|
||||||
|
| 🔑 المصادقة | ⭐⭐⭐⭐⭐ | MFA + JWT + بصمة + OTP |
|
||||||
|
| 🔐 التشفير | ⭐⭐⭐⭐⭐ | AES-256-CBC + IV عشوائي |
|
||||||
|
| 🛡️ حماية API | ⭐⭐⭐⭐⭐ | Rate Limiting + Validation |
|
||||||
|
| 💳 أمن المدفوعات | ⭐⭐⭐⭐⭐ | S2S + HMAC + Audit Trail |
|
||||||
|
| 📱 أمن التطبيقات | ⭐⭐⭐⭐ | Certificate Pinning + تشفير |
|
||||||
|
| 🗄️ أمن قاعدة البيانات | ⭐⭐⭐⭐⭐ | SQL Injection محمي |
|
||||||
|
| 🌐 أمن الشبكة | ⭐⭐⭐⭐⭐ | HTTPS + HSTS + CSP |
|
||||||
|
| 👁️ المراقبة | ⭐⭐⭐⭐ | Audit Logs + تنبيهات |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🤖 الذكاء الاصطناعي (AI Features)
|
||||||
|
|
||||||
|
### 📄 توثيق السائقين بالذكاء الاصطناعي
|
||||||
|
|
||||||
|
نظام توثيق متكامل يستخدم 3 محركات ذكاء اصطناعي لاستخراج بيانات المستندات تلقائياً:
|
||||||
|
|
||||||
|
**سير العمل:**
|
||||||
|
|
||||||
|
```
|
||||||
|
1. تصوير المستند ← Azure OCR (استخراج النص)
|
||||||
|
2. النص المستخرج ← OpenAI GPT-3.5 (تحليل وفهم)
|
||||||
|
3. في حالة فشل: Llama AI (نموذج بديل)
|
||||||
|
4. التحقق التلقائي ← مطابقة البيانات مع القواعد
|
||||||
|
5. تسجيل فوري ← من أيام إلى دقائق
|
||||||
|
```
|
||||||
|
|
||||||
|
| المحرك | الوظيفة | الميزة |
|
||||||
|
|--------|---------|--------|
|
||||||
|
| **Azure OCR** | مسح ضوئي | استخراج النصوص من صور المستندات |
|
||||||
|
| **OpenAI GPT-3.5** | تحليل ذكي | فهم وتصنيف بيانات المستندات |
|
||||||
|
| **Llama AI** | نموذج بديل | Fallback في حال فشل OpenAI |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎁 الإضافات المميزة (Value-Added Features)
|
||||||
|
|
||||||
|
### 🏷️ نظام العروض الترويجية (Promotions)
|
||||||
|
|
||||||
|
- 🎫 **أكواد خصم** للمستخدمين الجدد والحاليين
|
||||||
|
- 🆕 **كود دعوة أول رحلة**: خصم على أول رحلة لكل مستخدم جديد
|
||||||
|
- 📩 إرسال العروض المخصصة عبر الإشعارات
|
||||||
|
- 📊 تقارير أداء العروض الترويجية
|
||||||
|
|
||||||
|
### 👫 نظام الإحالة (Referral System)
|
||||||
|
|
||||||
|
- 🔗 **رمز إحالة موحد** لكل مستخدم (سائق أو راكب)
|
||||||
|
- 🎁 **مكافآت دعوة الأصدقاء**: رصيد مجاني لكل شخص يدعوه
|
||||||
|
- 📊 تتبع الإحالات — عدد المسجلين والأرباح
|
||||||
|
- 💰 مكافآت مزدوجة (للداعي والمدعو)
|
||||||
|
|
||||||
|
### ⭐ نظام التقييم المزدوج (Dual Rating)
|
||||||
|
|
||||||
|
| التقييم | من | إلى | الغرض |
|
||||||
|
|---------|----|-----|-------|
|
||||||
|
| ⭐ نجوم | الراكب | السائق | جودة الخدمة |
|
||||||
|
| ⭐ سلوك | السائق | الراكب | سلوك الراكب ونظافته |
|
||||||
|
| 📊 مؤشر الجودة | تلقائي | المستخدم | متوسط جميع التقييمات |
|
||||||
|
| 🚫 القائمة السوداء | إداري | المستخدم | حظر ذوي التقييم المنخفض |
|
||||||
|
|
||||||
|
### 💰 نظام العمولات الذكي (Kazan)
|
||||||
|
|
||||||
|
- 📊 **نسبة عمولة متغيرة** حسب نوع المركبة
|
||||||
|
- 🌍 **أسعار مختلفة حسب كل دولة**: سوريا، الأردن، مصر
|
||||||
|
- ⚙️ **قابل للتعديل** من لوحة التحكم الإدارية
|
||||||
|
- 💹 **شفافية كاملة**: السائق يعرف نسبة العمولة قبل قبول الرحلة
|
||||||
|
|
||||||
|
### 💵 نظام البقشيش (Tips)
|
||||||
|
|
||||||
|
- 💵 إضافة بقشيش للسائق بعد الرحلة
|
||||||
|
- 📱 عبر المحفظة الإلكترونية أو نقداً
|
||||||
|
- ⭐ تشجيع للسائقين على تقديم خدمة ممتازة
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🖥️ البنية التحتية (Infrastructure)
|
||||||
|
|
||||||
|
### 🏗️ معمارية النظام
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────────────────────────────────────────────────┐
|
||||||
|
│ تطبيقات Flutter │
|
||||||
|
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────┐ │
|
||||||
|
│ │ siro_rider│ │siro_driver│ │siro_admin│ │siro_service│ │
|
||||||
|
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └─────┬──────┘ │
|
||||||
|
└───────┼──────────────┼──────────────┼──────────────┼─────────┘
|
||||||
|
│ │ │ │
|
||||||
|
▼ ▼ ▼ ▼
|
||||||
|
┌──────────────────────────────────────────────────────────────┐
|
||||||
|
│ API Gateway (Nginx) │
|
||||||
|
│ Load Balancer + SSL Termination │
|
||||||
|
└──────────────────────────┬───────────────────────────────────┘
|
||||||
|
│
|
||||||
|
┌───────────────┼───────────────┐
|
||||||
|
▼ ▼ ▼
|
||||||
|
┌──────────────────┐ ┌──────────┐ ┌──────────────────┐
|
||||||
|
│ API Server 1 │ │API Server│ │ Socket Server │
|
||||||
|
│ (8 Core/16GB) │ │ 2 │ │ (8 Core/16GB) │
|
||||||
|
│ PHP-FPM + Nginx│ │ (Mirror) │ │ Driver+Passenger│
|
||||||
|
└────────┬─────────┘ └────┬─────┘ └────────┬─────────┘
|
||||||
|
│ │ │
|
||||||
|
└────────────────┼────────────────┘
|
||||||
|
│
|
||||||
|
┌──────────────┼──────────────┐
|
||||||
|
▼ ▼ ▼
|
||||||
|
┌──────────────────┐ ┌──────────┐ ┌──────────────────┐
|
||||||
|
│ MySQL Server │ │ Redis │ │ OSRM Server │
|
||||||
|
│ (16 Core/64GB) │ │ 8Core/32G│ │ (16 Core/32GB) │
|
||||||
|
│ 1TB NVMe + 10GbE│ │ 10GbE │ │ Syria OSM Map │
|
||||||
|
└──────────────────┘ └──────────┘ └──────────────────┘
|
||||||
|
│
|
||||||
|
┌──────────┴──────────┐
|
||||||
|
│ Wallet Server │
|
||||||
|
│ (4 Core/8GB) │
|
||||||
|
│ Payment Gateway │
|
||||||
|
└─────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 📊 مواصفات الخوادم المقترحة
|
||||||
|
|
||||||
|
| السيرفر | المعالج | الرام | التخزين | الشبكة | العدد |
|
||||||
|
|---------|---------|-------|---------|--------|-------|
|
||||||
|
| Load Balancer | 2 Core | 4 GB | 50 GB SSD | 1 Gbps | 1 |
|
||||||
|
| API Server | 8 Core | 16 GB | 100 GB NVMe | 1 Gbps | 2 |
|
||||||
|
| MySQL | 16 Core | 64 GB | 1 TB NVMe | 10 Gbps | 1 |
|
||||||
|
| Redis | 8 Core | 32 GB | 100 GB NVMe | 10 Gbps | 1 |
|
||||||
|
| Socket Server | 8 Core | 16 GB | 50 GB SSD | 1 Gbps | 1 |
|
||||||
|
| Wallet Server | 4 Core | 8 GB | 50 GB SSD | 1 Gbps | 1 |
|
||||||
|
| OSRM Server | 16 Core | 32 GB | 200 GB NVMe | 1 Gbps | 1 |
|
||||||
|
| **التكلفة الشهرية** | | | | | **$900-1,890** |
|
||||||
|
|
||||||
|
### 🌐 طوبولوجيا الشبكة
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────┐
|
||||||
|
│ Internet │
|
||||||
|
└──────┬───────┘
|
||||||
|
│
|
||||||
|
┌──────┴───────┐
|
||||||
|
│ Firewall │
|
||||||
|
│ (iptables) │
|
||||||
|
└──────┬───────┘
|
||||||
|
│
|
||||||
|
┌──────┴───────┐
|
||||||
|
│Load Balancer │
|
||||||
|
│ Public IP │
|
||||||
|
└──────┬───────┘
|
||||||
|
│
|
||||||
|
┌─────────────────┼─────────────────┐
|
||||||
|
│ │ │
|
||||||
|
┌──────┴───────┐ ┌─────┴───────┐ ┌──────┴───────┐
|
||||||
|
│ API SRV 1 │ │ API SRV 2 │ │ Socket SV │
|
||||||
|
│ 10.0.1.10 │ │ 10.0.1.11 │ │ 10.0.1.20-21 │
|
||||||
|
└──────┬───────┘ └─────┬───────┘ └──────┬───────┘
|
||||||
|
└────────────────┼─────────────────┘
|
||||||
|
│
|
||||||
|
┌────────────────┼─────────────────┐
|
||||||
|
│ │ │
|
||||||
|
┌──────┴───────┐ ┌────┴───────┐ ┌──────┴───────┐
|
||||||
|
│ MySQL DB │ │ Redis │ │ OSRM │
|
||||||
|
│ 10.0.1.30 │ │ 10.0.1.31 │ │ 10.0.1.40 │
|
||||||
|
└──────────────┘ └────────────┘ └──────────────┘
|
||||||
|
|
||||||
|
┌──────────────┐ ┌────────────┐
|
||||||
|
│ Wallet SV │ │ Map SaaS │
|
||||||
|
│ 10.0.1.50 │ │ 10.0.1.60 │
|
||||||
|
└──────────────┘ └────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🔒 الإجراءات الأمنية للبنية التحتية
|
||||||
|
|
||||||
|
| الإجراء | الوصف |
|
||||||
|
|---------|-------|
|
||||||
|
| **Firewall** | فتح المنافذ: 80/443 (عام) + 2020/3030 (WebSocket) + 22 (SSH مقيّد) |
|
||||||
|
| **Fail2ban** | حماية SSH و API من هجمات القوة الغاشمة |
|
||||||
|
| **UFW/iptables** | حجب جميع المنافذ غير المستخدمة على كل سيرفر |
|
||||||
|
| **VPN** | وصول آمن للإدارة عبر Tailscale أو WireGuard |
|
||||||
|
| **SSL/TLS** | جميع الاتصالات الخارجية مشفرة |
|
||||||
|
| **Internal VLAN** | شبكة داخلية خاصة (10.0.1.0/24) بين جميع الخوادم |
|
||||||
|
| **MySQL Access** | مستخدم مخصص بصلاحيات محدودة من API Servers فقط |
|
||||||
|
| **Redis Password** | requirepass + rename-command FLUSHALL |
|
||||||
|
| **.env Permissions** | صلاحيات 600 لملف .env |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 المقارنة التنافسية (Competitive Analysis)
|
||||||
|
|
||||||
|
| الميزة | **Siro (سِيرُو)** | أوبر (Uber) | كريم (Careem) | Bolt |
|
||||||
|
|--------|-------------------|-------------|---------------|------|
|
||||||
|
| 🌍 التوسع الإقليمي | سوريا، الأردن، مصر | عالمي | إقليمي | عالمي |
|
||||||
|
| 🚙 أنواع المركبات | **12 نوعاً** | 5 أنواع | 6 أنواع | 4 أنواع |
|
||||||
|
| 💳 طرق الدفع المحلية | **7 طرق** (MTN, Syriatel, E-Cash) | 4 طرق | 5 طرق | 3 طرق |
|
||||||
|
| 👩 سائقات نساء | ✅ **نعم** | ✅ نعم | ✅ نعم | ❌ لا |
|
||||||
|
| 📱 تطبيقات متصلة | **4 تطبيقات** | تطبيقان | تطبيقان | تطبيقان |
|
||||||
|
| 🤖 ذكاء اصطناعي للتوثيق | **Azure + OpenAI + Llama** | أساسي | أساسي | ❌ لا |
|
||||||
|
| 🎯 تراكب الأندرويد | **نعم — فوق أي تطبيق** | لا | لا | لا |
|
||||||
|
| 🗺️ خريطة مخصصة | **Map SaaS خاص** | Google فقط | Google فقط | Google فقط |
|
||||||
|
| 📊 لوحة تحكم إدارية | **ويب كامل — 15+ وحدة** | محدود | محدود | محدود |
|
||||||
|
| 💬 دردشة بدون رقم | ✅ نعم | ✅ نعم | ✅ نعم | ❌ لا |
|
||||||
|
| 🆘 زر طوارئ + فيديو | ✅ **Agora + WebRTC** | SOS فقط | SOS فقط | ❌ لا |
|
||||||
|
| 💰 محفظة إلكترونية | ✅ راكب + سائق | محدود | ✅ نعم | ❌ لا |
|
||||||
|
| 🏷️ نظام إحالة متكامل | ✅ راكب + سائق | ✅ | ✅ | ✅ |
|
||||||
|
| 🔒 بصمة جهاز + JWT | ✅ **أمان متعدد الطبقات** | أساسي | أساسي | أساسي |
|
||||||
|
| 📦 توصيل طلبات (Delivery) | ✅ نعم | ✅ نعم | ✅ نعم | ❌ لا |
|
||||||
|
| ⚡ تطبيق إدارة ميداني | ✅ **Siro Service** | لا | لا | لا |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📈 فرص النمو والتوسع
|
||||||
|
|
||||||
|
### على المدى القصير (3-6 أشهر)
|
||||||
|
|
||||||
|
| الفرصة | الوصف | التأثير المتوقع |
|
||||||
|
|--------|-------|----------------|
|
||||||
|
| 🌍 التوسع لدول جديدة | دول الخليج، شمال أفريقيا | 5x قاعدة المستخدمين |
|
||||||
|
| 🚚 خدمات لوجستية | نقل بضائع، شحن، توصيل طرود | إيرادات إضافية 30%+ |
|
||||||
|
| 🛵 توصيل طلبات للمطاعم | Siro Food - مشابه لـ Uber Eats | إيرادات إضافية 50%+ |
|
||||||
|
| 🤖 تحسين التنبؤ بالطلب | AI Demand Forecasting | تقليل وقت الانتظار 40% |
|
||||||
|
|
||||||
|
### على المدى المتوسط (6-12 شهراً)
|
||||||
|
|
||||||
|
| الفرصة | الوصف |
|
||||||
|
|--------|-------|
|
||||||
|
| 💳 إضافة بوابات دفع جديدة | المزيد من خيارات الدفع المحلية |
|
||||||
|
| 🎯 برامج ولاء متقدمة | نقاط مكافآت، خصومات مخصصة |
|
||||||
|
| 🚗 تأجير السيارات | Siro Rent - خدمة تأجير السيارات |
|
||||||
|
| 🏢 خدمات النقل للشركات | B2B Corporate Transport Solutions |
|
||||||
|
| 🔐 برنامج مكافآت الأخطاء | Bug Bounty Program لتعزيز الأمان |
|
||||||
|
|
||||||
|
### على المدى الطويل (12-24 شهراً)
|
||||||
|
|
||||||
|
| الفرصة | الوصف |
|
||||||
|
|--------|-------|
|
||||||
|
| 🤖 قيادة ذاتية | Autonomous Vehicle Integration |
|
||||||
|
| 🛸 توصيل بالطائرات المسيرة | Drone Delivery Services |
|
||||||
|
| 🌍 منصة مفتوحة (Open Platform) | API عام لمطوري الطرف الثالث |
|
||||||
|
| 💳 بنك رقمي | Siro Fintech - خدمات مالية رقمية |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎓 نقاط القوة الرئيسية — لماذا Siro؟
|
||||||
|
|
||||||
|
### 1️⃣ 🏗️ بنية تحتية مرنة ومخصصة
|
||||||
|
|
||||||
|
- **خوادم مخصصة لكل دولة**: routing مختلف لسوريا، الأردن، مصر
|
||||||
|
- **خريطة خاصة (Map SaaS)**: لا تعتمد كلياً على Google Maps — استقلالية تامة
|
||||||
|
- **WebSockets مزدوجة**: فصل تام بين اتصالات السائق والراكب لتجنب الازدحام
|
||||||
|
- **Redis Pipeline**: تجميع الأحداث كل 500ms لتقليل الحمل
|
||||||
|
- **Auto-scaling**: بنية قابلة للتوسع الأفقي
|
||||||
|
|
||||||
|
### 2️⃣ 🧠 ذكاء اصطناعي مدمج
|
||||||
|
|
||||||
|
- **توثيق آلي** للسائقين الجدد — يقلل وقت التسجيل من أيام إلى دقائق
|
||||||
|
- **Azure + OpenAI + Llama**: ثلاث محركات ذكاء اصطناعي تعمل معاً لضمان أعلى دقة مع Fallback تلقائي
|
||||||
|
- قابلية التوسع لإضافة حالات استخدام AI جديدة
|
||||||
|
|
||||||
|
### 3️⃣ 💳 حلول دفع محلية مبتكرة
|
||||||
|
|
||||||
|
- دعم **MTN و Syriatel** في سوريا (حلول دفع محلية فريدة)
|
||||||
|
- دعم **E-Cash** في مصر
|
||||||
|
- **PayMob** للبطاقات الائتمانية
|
||||||
|
- **Stripe** للدفع الدولي
|
||||||
|
- **محفظة إلكترونية** مزدوجة للراكب والسائق مع تحويلات داخلية
|
||||||
|
- بنية S2S آمنة مع HMAC + JWT
|
||||||
|
|
||||||
|
### 4️⃣ 🎯 تجربة سائق فريدة
|
||||||
|
|
||||||
|
- **تراكب Android** يعرض الطلبات حتى فوق التطبيقات الأخرى — لا يفوت السائق أي طلب
|
||||||
|
- **خدمة خلفية دائمة (Foreground Service)** — الموقع محدث 24/7
|
||||||
|
- **توجيه صوتي (Voice Navigation)** مع إرشادات مفصلة TTS
|
||||||
|
- **مؤقت انتظار أوتوماتيكي** للركاب مع 15 ثانية للقبول
|
||||||
|
- **إحصائيات الأرباح** لحظية مع تقارير مالية شاملة
|
||||||
|
|
||||||
|
### 5️⃣ 📊 إدارة شاملة
|
||||||
|
|
||||||
|
- **15+ وحدة إدارية** في لوحة التحكم (أكثر من أي منافس)
|
||||||
|
- **تحليلات متقدمة** وتقارير مالية فورية
|
||||||
|
- **إدارة السائقين والركاب** بكفاءة مع مراقبة الجودة
|
||||||
|
- **القوائم السوداء** و **بطاقات أداء السائقين**
|
||||||
|
- **سجلات التدقيق (Audit Logs)** للأمان والمساءلة
|
||||||
|
|
||||||
|
### 6️⃣ 🌍 دعم متعدد اللغات والعملات
|
||||||
|
|
||||||
|
- دعم اللغة العربية والإنكليزية كامل
|
||||||
|
- واجهات مترجمة بالكامل للتطبيقات الأربعة
|
||||||
|
- محتوى مترجم للدول المختلفة
|
||||||
|
- دعم العملات المتعددة (ليرة سورية، دينار أردني، جنيه مصري)
|
||||||
|
|
||||||
|
### 7️⃣ 🔒 أمان عالي المستوى — ميزة تنافسية
|
||||||
|
|
||||||
|
- **JWT مع بصمة الجهاز الفريدة** — أمان متعدد الطبقات
|
||||||
|
- **HMAC لطلبات الدفع** — حماية S2S
|
||||||
|
- **تشفير AES-256-CBC مع IV عشوائي** — حماية البيانات الحساسة
|
||||||
|
- **Auto-refresh JWT** — منع قطع الجلسة مع أمان مستمر
|
||||||
|
- **Rate Limiting** — تحديد معدل المحاولات والحماية من الهجمات
|
||||||
|
- **Certificate Pinning** — منع هجمات الوسيط (MITM)
|
||||||
|
- **Audit Logging** — سجل تدقيق شامل لجميع العمليات
|
||||||
|
|
||||||
|
### 8️⃣ 🚚 تنوع خدمات النقل
|
||||||
|
|
||||||
|
- من التوصيل السريع بالدراجة النارية إلى النقل العائلي والفان
|
||||||
|
- **سائقات نساء** — خيار خاص يحترم خصوصية السيدات (ميزة نادرة)
|
||||||
|
- **سيارات كهربائية** — خيار صديق للبيئة (استباقي)
|
||||||
|
- **12 نوع مركبة** — أكبر تنوع مقارنة بالمنافسين
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ الخلاصة والتقرير النهائي
|
||||||
|
|
||||||
|
### لماذا Siro هي الخيار الأفضل؟
|
||||||
|
|
||||||
|
| المعيار | التقييم |
|
||||||
|
|---------|---------|
|
||||||
|
| **التغطية الإقليمية** | ⭐⭐⭐⭐⭐ 3 دول مع دعم محلي كامل |
|
||||||
|
| **تنوع الخدمات** | ⭐⭐⭐⭐⭐ 12 نوع مركبة + 4 تطبيقات |
|
||||||
|
| **طرق الدفع** | ⭐⭐⭐⭐⭐ 7 طرق دفع محلية وعالمية |
|
||||||
|
| **الأمان** | ⭐⭐⭐⭐⭐ 5 طبقات أمان متكاملة |
|
||||||
|
| **الذكاء الاصطناعي** | ⭐⭐⭐⭐⭐ 3 محركات AI للتوثيق التلقائي |
|
||||||
|
| **لوحة التحكم** | ⭐⭐⭐⭐⭐ 15+ وحدة إدارية |
|
||||||
|
| **البنية التحتية** | ⭐⭐⭐⭐⭐ خوادم مخصصة لكل دولة |
|
||||||
|
| **تجربة السائق** | ⭐⭐⭐⭐⭐ Android Overlay + Voice Nav |
|
||||||
|
| **الدعم المحلي** | ⭐⭐⭐⭐⭐ فهم عميق لاحتياجات السوق العربي |
|
||||||
|
|
||||||
|
### 📊 الأرقام النهائية
|
||||||
|
|
||||||
|
| المقياس | القيمة |
|
||||||
|
|---------|--------|
|
||||||
|
| دول التشغيل | 3 |
|
||||||
|
| تطبيقات متصلة | 4 |
|
||||||
|
| أنواع المركبات | 12 |
|
||||||
|
| طرق الدفع | 7 |
|
||||||
|
| خدمات التكامل | 15+ |
|
||||||
|
| ملفات PHP | 395+ |
|
||||||
|
| قواعد بيانات | 3 |
|
||||||
|
| خوادم مخصصة | 10+ |
|
||||||
|
| طبقات أمان | 5 |
|
||||||
|
| محركات AI | 3 |
|
||||||
|
| وحدات إدارية | 15+ |
|
||||||
|
| التكلفة الشهرية للبنية | $900-1,890 |
|
||||||
|
| السعة الاستيعابية | 10,000+ مستخدم متزامن |
|
||||||
|
|
||||||
|
### 🎯 الرسالة التسويقية الأساسية
|
||||||
|
|
||||||
|
> **Siro (سِيرُو) ليست مجرد تطبيق نقل — إنها منصة متكاملة للنقل الذكي تجمع بين:**
|
||||||
|
>
|
||||||
|
> ✅ **4 تطبيقات متصلة** تغطي كل احتياجات النقل
|
||||||
|
> ✅ **12 نوع مركبة و 7 طرق دفع** لتغطية جميع احتياجات المستخدمين
|
||||||
|
> ✅ **ذكاء اصطناعي متقدم** لتسريع التوثيق وتحسين الخدمة
|
||||||
|
> ✅ **نظام توزيع ذكي** مع خرائط حية وتتبع مباشر
|
||||||
|
> ✅ **لوحة تحكم إدارية** بمستوى مؤسسي (15+ وحدة)
|
||||||
|
> ✅ **5 طبقات أمان** لحماية البيانات والمعاملات المالية
|
||||||
|
> ✅ **حلول دفع محلية** مبتكرة تفهم احتياجات السوق
|
||||||
|
> ✅ **بنية تحتية** بتكلفة تشغيل $900-1,890 شهرياً
|
||||||
|
|
||||||
|
### 🔐 الأمان كعلامة تجارية
|
||||||
|
|
||||||
|
في عالم تتصدر فيه خروقات البيانات عناوين الأخبار، **Siro تضع الأمان في صميم منتجها**:
|
||||||
|
|
||||||
|
- **5 طبقات أمان متكاملة** — من المصادقة إلى المراقبة
|
||||||
|
- **تشفير AES-256-CBC مع IV عشوائي** — معيار صناعي
|
||||||
|
- **JWT + بصمة جهاز + MFA** — أمان متعدد العوامل
|
||||||
|
- **HMAC + S2S للمدفوعات** — حماية مالية على مستوى المؤسسات
|
||||||
|
- **سجل تدقيق شامل** — مساءلة وشفافية كاملة
|
||||||
|
- **اختبارات اختراق منتظمة** — تحسين مستمر
|
||||||
|
|
||||||
|
> **Siro — وجهتك الذكية لكل رحلة** 🚀
|
||||||
|
>
|
||||||
|
> *النقل الذكي | الأمان أولاً | حلول محلية | تقنيات عالمية*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*تم إعداد هذا التقرير ليكون دليلاً تسويقياً وأمنياً شاملاً لمنصة Siro (سِيرُو)*
|
||||||
|
*جميع المعلومات المذكورة تستند إلى الكود المصدري والتوثيق الفني للمنصة*
|
||||||
|
|
||||||
|
**تاريخ التقرير:** 17 يونيو 2026
|
||||||
|
**الإصدار:** 1.0
|
||||||
|
**التصنيف:** 📋 تقرير تسويقي وأمني شامل
|
||||||
|
|
||||||
|
</div>
|
||||||
@@ -9,8 +9,8 @@ require_once __DIR__ . '/../../connect.php'; // يجب أن يوفّر: $con (ا
|
|||||||
const MAX_FILE_MB = 5;
|
const MAX_FILE_MB = 5;
|
||||||
const ALLOWED_MIMES = ['image/jpeg','image/png','image/webp']; // فقط صور
|
const ALLOWED_MIMES = ['image/jpeg','image/png','image/webp']; // فقط صور
|
||||||
const UPLOAD_ROOT = __DIR__ . "/../../private_uploads"; // مجلد خاص (غير عام)
|
const UPLOAD_ROOT = __DIR__ . "/../../private_uploads"; // مجلد خاص (غير عام)
|
||||||
$SIGN_SECRET = getenv('SECRET_KEY_HMAC') ?: ''; // غيّرها واقرأها من .env
|
$SIGN_SECRET = getenv('SECRET_KEY_HMAC'); // غيّرها واقرأها من .env
|
||||||
$host = getenv('APP_DOMAIN') ?: 'api-syria.siromove.com';
|
$host = getenv('APP_DOMAIN');
|
||||||
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? "https" : "http";
|
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? "https" : "http";
|
||||||
define('PUBLIC_BASE', "$protocol://$host/siro");
|
define('PUBLIC_BASE', "$protocol://$host/siro");
|
||||||
const SIGNED_TTL_SEC = 172800; // 2 days = 60*60*24
|
const SIGNED_TTL_SEC = 172800; // 2 days = 60*60*24
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"folders": [
|
|
||||||
{
|
|
||||||
"path": "."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "../../../development/App/Siro"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "../../../development/App/siro_driver"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "../../../development/App/siro_admin"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "../../../development/App/service_siro"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"settings": {}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 283 KiB |
|
Before Width: | Height: | Size: 288 KiB |
|
Before Width: | Height: | Size: 283 KiB |
@@ -1,153 +0,0 @@
|
|||||||
import json
|
|
||||||
import re
|
|
||||||
import os
|
|
||||||
|
|
||||||
def parse_dart_map(filepath):
|
|
||||||
translations = {}
|
|
||||||
if not os.path.exists(filepath):
|
|
||||||
return translations
|
|
||||||
with open(filepath, 'r', encoding='utf-8') as f:
|
|
||||||
content = f.read()
|
|
||||||
|
|
||||||
# Matches maps of form: "key": "value" or 'key': 'value'
|
|
||||||
# Handles escapes and multi-line content matched on single lines
|
|
||||||
pattern = re.compile(r'^\s*([\'"])(.*?)\1\s*:\s*([\'"])(.*?)\3\s*,?\s*$', re.MULTILINE)
|
|
||||||
matches = pattern.findall(content)
|
|
||||||
for match in matches:
|
|
||||||
key = match[1]
|
|
||||||
val = match[3]
|
|
||||||
# Unescape simple sequences (single and double quotes)
|
|
||||||
key = key.replace('\\"', '"').replace("\\'", "'")
|
|
||||||
val = val.replace('\\"', '"').replace("\\'", "'")
|
|
||||||
translations[key] = val
|
|
||||||
|
|
||||||
return translations
|
|
||||||
|
|
||||||
def to_dart_string(s):
|
|
||||||
# Escape characters to be safe inside double quotes in Dart source code
|
|
||||||
result = []
|
|
||||||
for char in s:
|
|
||||||
if char == '\\':
|
|
||||||
result.append('\\\\')
|
|
||||||
elif char == '"':
|
|
||||||
result.append('\\"')
|
|
||||||
elif char == '$':
|
|
||||||
result.append('\\$')
|
|
||||||
elif char == '\n':
|
|
||||||
result.append('\\n')
|
|
||||||
elif char == '\r':
|
|
||||||
result.append('\\r')
|
|
||||||
elif char == '\t':
|
|
||||||
result.append('\\t')
|
|
||||||
else:
|
|
||||||
result.append(char)
|
|
||||||
return "".join(result)
|
|
||||||
|
|
||||||
# Load current Arabic files
|
|
||||||
ar_eg = parse_dart_map("siro_driver/lib/controller/local/ar_eg.dart")
|
|
||||||
ar_jo = parse_dart_map("siro_driver/lib/controller/local/ar_jo.dart")
|
|
||||||
ar_sy = parse_dart_map("siro_driver/lib/controller/local/ar_sy.dart")
|
|
||||||
|
|
||||||
# Load JSON data
|
|
||||||
with open("siro_driver_translations_data.json", "r", encoding="utf-8") as f:
|
|
||||||
json_data = json.load(f)
|
|
||||||
|
|
||||||
existing_syrian = json_data.get('existing_syrian', {})
|
|
||||||
missing_keys = json_data.get('missing_keys', [])
|
|
||||||
|
|
||||||
# Load legacy non-Arabic languages
|
|
||||||
with open("scratch/legacy_extracted_languages.json", "r", encoding="utf-8") as f:
|
|
||||||
legacy_extracted = json.load(f)
|
|
||||||
|
|
||||||
# Compute master keys
|
|
||||||
master_keys = set(ar_sy.keys())
|
|
||||||
master_keys.update(ar_jo.keys())
|
|
||||||
master_keys.update(ar_eg.keys())
|
|
||||||
master_keys.update(existing_syrian.keys())
|
|
||||||
master_keys.update(missing_keys)
|
|
||||||
|
|
||||||
master_keys = sorted(list(master_keys))
|
|
||||||
print(f"Master keys count: {len(master_keys)}")
|
|
||||||
|
|
||||||
# Let's build translation maps
|
|
||||||
aligned_maps = {
|
|
||||||
'ar-EG': {},
|
|
||||||
'ar-JO': {},
|
|
||||||
'ar-SY': {},
|
|
||||||
'en': {},
|
|
||||||
'de': {},
|
|
||||||
'el': {},
|
|
||||||
'es': {},
|
|
||||||
'fa': {},
|
|
||||||
'fr': {},
|
|
||||||
'hi': {},
|
|
||||||
'it': {},
|
|
||||||
'ru': {},
|
|
||||||
'tr': {},
|
|
||||||
'ur': {},
|
|
||||||
'zh': {}
|
|
||||||
}
|
|
||||||
|
|
||||||
for key in master_keys:
|
|
||||||
# 1. English is always the key itself
|
|
||||||
aligned_maps['en'][key] = key
|
|
||||||
|
|
||||||
# 2. Syrian Arabic (ar-SY)
|
|
||||||
val_sy = ar_sy.get(key)
|
|
||||||
if not val_sy:
|
|
||||||
val_sy = existing_syrian.get(key)
|
|
||||||
if not val_sy:
|
|
||||||
val_sy = ar_jo.get(key)
|
|
||||||
if not val_sy:
|
|
||||||
val_sy = ar_eg.get(key)
|
|
||||||
if not val_sy:
|
|
||||||
val_sy = key # fallback to key
|
|
||||||
aligned_maps['ar-SY'][key] = val_sy
|
|
||||||
|
|
||||||
# 3. Jordanian Arabic (ar-JO)
|
|
||||||
val_jo = ar_jo.get(key)
|
|
||||||
if not val_jo:
|
|
||||||
val_jo = val_sy # fallback to Syrian
|
|
||||||
aligned_maps['ar-JO'][key] = val_jo
|
|
||||||
|
|
||||||
# 4. Egyptian Arabic (ar-EG)
|
|
||||||
val_eg = ar_eg.get(key)
|
|
||||||
if not val_eg:
|
|
||||||
val_eg = val_jo # fallback to Jordanian/Syrian
|
|
||||||
aligned_maps['ar-EG'][key] = val_eg
|
|
||||||
|
|
||||||
# 5. Non-Arabic languages
|
|
||||||
for lang in ['de', 'el', 'es', 'fa', 'fr', 'hi', 'it', 'ru', 'tr', 'ur', 'zh']:
|
|
||||||
val_lang = legacy_extracted.get(lang, {}).get(key)
|
|
||||||
if not val_lang:
|
|
||||||
val_lang = key # fallback to English
|
|
||||||
aligned_maps[lang][key] = val_lang
|
|
||||||
|
|
||||||
# Directories and file writes
|
|
||||||
output_dir = "siro_driver/lib/controller/local"
|
|
||||||
|
|
||||||
def write_dart_file(filename, map_name, data_map):
|
|
||||||
filepath = os.path.join(output_dir, filename)
|
|
||||||
with open(filepath, 'w', encoding='utf-8') as f:
|
|
||||||
# Write final Map<String, String> map_name = { ... };
|
|
||||||
f.write(f"final Map<String, String> {map_name} = {{\n")
|
|
||||||
for k, v in data_map.items():
|
|
||||||
k_escaped = to_dart_string(k)
|
|
||||||
v_escaped = to_dart_string(v)
|
|
||||||
f.write(f' "{k_escaped}": "{v_escaped}",\n')
|
|
||||||
f.write("};\n")
|
|
||||||
print(f"Wrote {filepath} with {len(data_map)} keys.")
|
|
||||||
|
|
||||||
# Write Arabic dialects
|
|
||||||
write_dart_file("ar_eg.dart", "ar_eg", aligned_maps['ar-EG'])
|
|
||||||
write_dart_file("ar_jo.dart", "ar_jo", aligned_maps['ar-JO'])
|
|
||||||
write_dart_file("ar_sy.dart", "ar_sy", aligned_maps['ar-SY'])
|
|
||||||
|
|
||||||
# Write English
|
|
||||||
write_dart_file("en.dart", "en", aligned_maps['en'])
|
|
||||||
|
|
||||||
# Write non-Arabic languages
|
|
||||||
for lang in ['de', 'el', 'es', 'fa', 'fr', 'hi', 'it', 'ru', 'tr', 'ur', 'zh']:
|
|
||||||
write_dart_file(f"{lang}.dart", lang, aligned_maps[lang])
|
|
||||||
|
|
||||||
print("Alignment and file writing complete.")
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
import re
|
|
||||||
|
|
||||||
def parse_translations_file(filepath):
|
|
||||||
with open(filepath, 'r', encoding='utf-8') as f:
|
|
||||||
content = f.read()
|
|
||||||
|
|
||||||
# Let's find language maps like: "en": { ... }, "fr": { ... }
|
|
||||||
# Look for patterns like "lang": { or 'lang': {
|
|
||||||
pattern = re.compile(r'[\'"]([a-zA-Z\-]+)[\'"]\s*:\s*\{')
|
|
||||||
matches = pattern.findall(content)
|
|
||||||
return matches
|
|
||||||
|
|
||||||
print("Legacy translations.dart languages:")
|
|
||||||
print(parse_translations_file("scratch/legacy_translations.dart"))
|
|
||||||
|
|
||||||
print("\nLegacy driver_translations.dart languages:")
|
|
||||||
print(parse_translations_file("scratch/legacy_driver_translations.dart"))
|
|
||||||
|
Before Width: | Height: | Size: 242 KiB |
|
Before Width: | Height: | Size: 322 KiB |
|
Before Width: | Height: | Size: 363 KiB |
|
Before Width: | Height: | Size: 376 KiB |
|
Before Width: | Height: | Size: 378 KiB |
|
Before Width: | Height: | Size: 418 KiB |
@@ -1,88 +0,0 @@
|
|||||||
import math
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
from PIL import Image, ImageDraw, ImageFont
|
|
||||||
|
|
||||||
# Set font path to the local Roboto-Bold font
|
|
||||||
font_path = 'scratch/Roboto-Bold.ttf'
|
|
||||||
|
|
||||||
def draw_gear(draw, cx, cy, r_out, r_in, teeth_count, teeth_h, teeth_w, color):
|
|
||||||
draw.ellipse([cx - r_out, cy - r_out, cx + r_out, cy + r_out], fill=color)
|
|
||||||
for i in range(teeth_count):
|
|
||||||
angle = i * (2 * math.pi / teeth_count)
|
|
||||||
x0 = cx + r_out * math.cos(angle)
|
|
||||||
y0 = cy + r_out * math.sin(angle)
|
|
||||||
tx = -math.sin(angle)
|
|
||||||
ty = math.cos(angle)
|
|
||||||
nx = math.cos(angle)
|
|
||||||
ny = math.sin(angle)
|
|
||||||
p1 = (x0 - (teeth_w/2) * tx, y0 - (teeth_w/2) * ty)
|
|
||||||
p2 = (x0 + (teeth_w/2) * tx, y0 + (teeth_w/2) * ty)
|
|
||||||
p3 = (x0 + teeth_h * nx + (teeth_w/3) * tx, y0 + teeth_h * ny + (teeth_w/3) * ty)
|
|
||||||
p4 = (x0 + teeth_h * nx - (teeth_w/3) * tx, y0 + teeth_h * ny - (teeth_w/3) * ty)
|
|
||||||
draw.polygon([p1, p2, p3, p4], fill=color)
|
|
||||||
draw.ellipse([cx - r_in, cy - r_in, cx + r_in, cy + r_in], fill=(255, 255, 255, 255))
|
|
||||||
|
|
||||||
def draw_car_large(draw, color):
|
|
||||||
# Center: (765, 205)
|
|
||||||
# Cabin
|
|
||||||
draw.polygon([(740, 155), (790, 155), (809, 198), (721, 198)], fill=color)
|
|
||||||
# Windshield
|
|
||||||
draw.polygon([(743, 161), (787, 161), (802, 194), (728, 194)], fill=(255, 255, 255, 255))
|
|
||||||
# Windshield divider
|
|
||||||
draw.rectangle([763, 161, 767, 194], fill=color)
|
|
||||||
# Main body
|
|
||||||
draw.polygon([
|
|
||||||
(712, 195), (818, 195),
|
|
||||||
(827, 204), (827, 246),
|
|
||||||
(818, 255), (712, 255),
|
|
||||||
(703, 246), (703, 204)
|
|
||||||
], fill=color)
|
|
||||||
# Headlights
|
|
||||||
r_head = 9
|
|
||||||
draw.ellipse([722 - r_head, 222 - r_head, 722 + r_head, 222 + r_head], fill=(255, 255, 255, 255))
|
|
||||||
draw.ellipse([808 - r_head, 222 - r_head, 808 + r_head, 222 + r_head], fill=(255, 255, 255, 255))
|
|
||||||
# Grille
|
|
||||||
draw.rectangle([740, 222, 790, 232], fill=(255, 255, 255, 255))
|
|
||||||
# Side mirrors
|
|
||||||
draw.polygon([(694, 190), (703, 195), (703, 203), (694, 198)], fill=color)
|
|
||||||
draw.polygon([(836, 190), (827, 195), (827, 203), (836, 198)], fill=color)
|
|
||||||
|
|
||||||
def create_app_logo(base_logo_path, text, output_path):
|
|
||||||
im = Image.open(base_logo_path)
|
|
||||||
draw = ImageDraw.Draw(im)
|
|
||||||
color = (29, 32, 47, 255)
|
|
||||||
|
|
||||||
font_size = 90
|
|
||||||
font = ImageFont.truetype(font_path, font_size)
|
|
||||||
|
|
||||||
# Get text bounding box
|
|
||||||
bbox = draw.textbbox((0, 0), text, font=font)
|
|
||||||
tw = bbox[2] - bbox[0]
|
|
||||||
th = bbox[3] - bbox[1]
|
|
||||||
|
|
||||||
tx = 512 - (tw / 2)
|
|
||||||
ty = 887 - (th / 2) - bbox[1]
|
|
||||||
|
|
||||||
draw.text((tx, ty), text, font=font, fill=color)
|
|
||||||
im.save(output_path)
|
|
||||||
print(f'Saved logo with text \"{text}\" to {output_path}. BBox: X={tx} to {tx+tw}, Y={ty+bbox[1]} to {ty+bbox[3]}')
|
|
||||||
|
|
||||||
# Create Admin logo
|
|
||||||
print('Creating Admin Logo...')
|
|
||||||
im_admin = Image.open('scratch/logo_s_only.png')
|
|
||||||
draw_admin = ImageDraw.Draw(im_admin)
|
|
||||||
color = (29, 32, 47, 255)
|
|
||||||
draw_gear(draw_admin, cx=765, cy=205, r_out=52, r_in=20, teeth_count=8, teeth_h=16, teeth_w=20, color=color)
|
|
||||||
im_admin.save('scratch/admin_base.png')
|
|
||||||
create_app_logo('scratch/admin_base.png', 'ADMIN', 'scratch/admin_logo_final.png')
|
|
||||||
|
|
||||||
# Create Service logo
|
|
||||||
print('Creating Service Logo...')
|
|
||||||
im_service = Image.open('scratch/logo_s_only.png')
|
|
||||||
draw_service = ImageDraw.Draw(im_service)
|
|
||||||
draw_car_large(draw_service, color)
|
|
||||||
im_service.save('scratch/service_base.png')
|
|
||||||
create_app_logo('scratch/service_base.png', 'SERVICE', 'scratch/service_logo_final.png')
|
|
||||||
|
|
||||||
print('All logos compiled successfully.')
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
import math
|
|
||||||
from PIL import Image, ImageDraw
|
|
||||||
|
|
||||||
def draw_car_large(draw, color):
|
|
||||||
# Center: (765, 205)
|
|
||||||
# Scaled up by 1.25x for better visual weight
|
|
||||||
|
|
||||||
# 1. Cabin (upper part)
|
|
||||||
# Trapezoid: top base from X=740 to 790, bottom base from X=721 to 809, Y=155 to 198
|
|
||||||
draw.polygon([(740, 155), (790, 155), (809, 198), (721, 198)], fill=color)
|
|
||||||
|
|
||||||
# Windshield (white trapezoid inside cabin)
|
|
||||||
draw.polygon([(743, 161), (787, 161), (802, 194), (728, 194)], fill=(255, 255, 255, 255))
|
|
||||||
|
|
||||||
# Vertical divider in windshield
|
|
||||||
draw.rectangle([763, 161, 767, 194], fill=color)
|
|
||||||
|
|
||||||
# 2. Main body (lower part)
|
|
||||||
# Polygon with cut corners: X=703 to 827, Y=195 to 255
|
|
||||||
draw.polygon([
|
|
||||||
(712, 195), (818, 195),
|
|
||||||
(827, 204), (827, 246),
|
|
||||||
(818, 255), (712, 255),
|
|
||||||
(703, 246), (703, 204)
|
|
||||||
], fill=color)
|
|
||||||
|
|
||||||
# 3. Headlights (white circles)
|
|
||||||
r_head = 9
|
|
||||||
draw.ellipse([722 - r_head, 222 - r_head, 722 + r_head, 222 + r_head], fill=(255, 255, 255, 255))
|
|
||||||
draw.ellipse([808 - r_head, 222 - r_head, 808 + r_head, 222 + r_head], fill=(255, 255, 255, 255))
|
|
||||||
|
|
||||||
# 4. Grille / Bumper
|
|
||||||
# Center grill: white rectangle from X=740 to 790, Y=222 to 232
|
|
||||||
draw.rectangle([740, 222, 790, 232], fill=(255, 255, 255, 255))
|
|
||||||
|
|
||||||
# 5. Side mirrors
|
|
||||||
# Left mirror: polygon at X=694 to 703, Y=190 to 202
|
|
||||||
draw.polygon([(694, 190), (703, 195), (703, 203), (694, 198)], fill=color)
|
|
||||||
# Right mirror: polygon at X=827 to 836, Y=190 to 202
|
|
||||||
draw.polygon([(836, 190), (827, 195), (827, 203), (836, 198)], fill=color)
|
|
||||||
|
|
||||||
im = Image.open('scratch/logo_s_only.png')
|
|
||||||
draw = ImageDraw.Draw(im)
|
|
||||||
color = (29, 32, 47, 255)
|
|
||||||
|
|
||||||
draw_car_large(draw, color)
|
|
||||||
im.save('scratch/service_logo_test_car_large.png')
|
|
||||||
print("Saved large service logo to scratch/service_logo_test_car_large.png")
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
import math
|
|
||||||
from PIL import Image, ImageDraw
|
|
||||||
|
|
||||||
def draw_gear(draw, cx, cy, r_out, r_in, teeth_count, teeth_h, teeth_w, color):
|
|
||||||
# Draw outer body
|
|
||||||
draw.ellipse([cx - r_out, cy - r_out, cx + r_out, cy + r_out], fill=color)
|
|
||||||
|
|
||||||
# Draw teeth
|
|
||||||
for i in range(teeth_count):
|
|
||||||
angle = i * (2 * math.pi / teeth_count)
|
|
||||||
|
|
||||||
# Center of tooth base on the outer radius
|
|
||||||
x0 = cx + r_out * math.cos(angle)
|
|
||||||
y0 = cy + r_out * math.sin(angle)
|
|
||||||
|
|
||||||
# Tangent vector for width
|
|
||||||
tx = -math.sin(angle)
|
|
||||||
ty = math.cos(angle)
|
|
||||||
|
|
||||||
# Normal vector for height
|
|
||||||
nx = math.cos(angle)
|
|
||||||
ny = math.sin(angle)
|
|
||||||
|
|
||||||
# 4 points of the tooth (trapezoid style: narrower at the tip)
|
|
||||||
p1 = (x0 - (teeth_w/2) * tx, y0 - (teeth_w/2) * ty)
|
|
||||||
p2 = (x0 + (teeth_w/2) * tx, y0 + (teeth_w/2) * ty)
|
|
||||||
|
|
||||||
p3 = (x0 + teeth_h * nx + (teeth_w/3) * tx, y0 + teeth_h * ny + (teeth_w/3) * ty)
|
|
||||||
p4 = (x0 + teeth_h * nx - (teeth_w/3) * tx, y0 + teeth_h * ny - (teeth_w/3) * ty)
|
|
||||||
|
|
||||||
draw.polygon([p1, p2, p3, p4], fill=color)
|
|
||||||
|
|
||||||
# Draw inner cutout (hole)
|
|
||||||
draw.ellipse([cx - r_in, cy - r_in, cx + r_in, cy + r_in], fill=(255, 255, 255, 255))
|
|
||||||
|
|
||||||
im = Image.open('scratch/logo_s_only.png')
|
|
||||||
draw = ImageDraw.Draw(im)
|
|
||||||
color = (29, 32, 47, 255)
|
|
||||||
|
|
||||||
# Draw gear at cx=765, cy=205
|
|
||||||
draw_gear(draw, cx=765, cy=205, r_out=45, r_in=18, teeth_count=8, teeth_h=15, teeth_w=18, color=color)
|
|
||||||
|
|
||||||
im.save('scratch/admin_logo_test.png')
|
|
||||||
print("Saved admin logo to scratch/admin_logo_test.png")
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
import math
|
|
||||||
from PIL import Image, ImageDraw
|
|
||||||
|
|
||||||
def draw_wrench(draw, color):
|
|
||||||
# Centers
|
|
||||||
cx_open, cy_open = 810, 160
|
|
||||||
cx_closed, cy_closed = 720, 250
|
|
||||||
|
|
||||||
# Draw shaft
|
|
||||||
# Direction vector from closed to open: (90, -90)
|
|
||||||
# Unit vector: dx = 0.7071, dy = -0.7071
|
|
||||||
# Perpendicular vector: px = 0.7071, py = 0.7071
|
|
||||||
dx, dy = 0.7071, -0.7071
|
|
||||||
px, py = 0.7071, 0.7071
|
|
||||||
half_w = 12
|
|
||||||
|
|
||||||
p1 = (cx_closed - half_w * px, cy_closed - half_w * py)
|
|
||||||
p2 = (cx_closed + half_w * px, cy_closed + half_w * py)
|
|
||||||
p3 = (cx_open + half_w * px, cy_open + half_w * py)
|
|
||||||
p4 = (cx_open - half_w * px, cy_open - half_w * py)
|
|
||||||
|
|
||||||
draw.polygon([p1, p2, p3, p4], fill=color)
|
|
||||||
|
|
||||||
# Draw open end outer circle
|
|
||||||
draw.ellipse([cx_open - 38, cy_open - 38, cx_open + 38, cy_open + 38], fill=color)
|
|
||||||
|
|
||||||
# Draw closed end outer circle
|
|
||||||
draw.ellipse([cx_closed - 30, cy_closed - 30, cx_closed + 30, cy_closed + 30], fill=color)
|
|
||||||
|
|
||||||
# Cut out the slot in open end (white polygon)
|
|
||||||
# Slot of width 22, length 50, starting at cx_open, cy_open and going in direction (dx, dy)
|
|
||||||
slot_half_w = 11
|
|
||||||
s1 = (cx_open - slot_half_w * px, cy_open - slot_half_w * py)
|
|
||||||
s2 = (cx_open + slot_half_w * px, cy_open + slot_half_w * py)
|
|
||||||
s3 = (cx_open + 50 * dx + slot_half_w * px, cy_open + 50 * dy + slot_half_w * py)
|
|
||||||
s4 = (cx_open + 50 * dx - slot_half_w * px, cy_open + 50 * dy - slot_half_w * py)
|
|
||||||
draw.polygon([s1, s2, s3, s4], fill=(255, 255, 255, 255))
|
|
||||||
|
|
||||||
# Draw a small circle at the base of the slot to make it round and clean
|
|
||||||
draw.ellipse([cx_open - 11, cy_open - 11, cx_open + 11, cy_open + 11], fill=(255, 255, 255, 255))
|
|
||||||
|
|
||||||
# Cut out closed end inner hole (white circle)
|
|
||||||
draw.ellipse([cx_closed - 15, cy_closed - 15, cx_closed + 15, cy_closed + 15], fill=(255, 255, 255, 255))
|
|
||||||
|
|
||||||
im = Image.open('scratch/logo_s_only.png')
|
|
||||||
draw = ImageDraw.Draw(im)
|
|
||||||
color = (29, 32, 47, 255)
|
|
||||||
|
|
||||||
draw_wrench(draw, color)
|
|
||||||
im.save('scratch/service_logo_test.png')
|
|
||||||
print("Saved service logo to scratch/service_logo_test.png")
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
import re
|
|
||||||
import json
|
|
||||||
|
|
||||||
def extract_language_maps(filepath):
|
|
||||||
with open(filepath, 'r', encoding='utf-8') as f:
|
|
||||||
content = f.read()
|
|
||||||
|
|
||||||
# Let's find language blocks like: "en": { ... }, "fr": { ... }
|
|
||||||
# To parse these blocks, we find the starting position of each language identifier
|
|
||||||
# and scan until the matching closing brace.
|
|
||||||
languages = ['tr', 'fr', 'de', 'es', 'fa', 'el', 'ur', 'hi', 'ru', 'it', 'zh']
|
|
||||||
extracted = {}
|
|
||||||
|
|
||||||
for lang in languages:
|
|
||||||
# Regex to find: "lang": { or 'lang': {
|
|
||||||
pattern = re.compile(r'[\'"]' + lang + r'[\'"]\s*:\s*\{')
|
|
||||||
match = pattern.search(content)
|
|
||||||
if not match:
|
|
||||||
print(f"Language {lang} map start not found!")
|
|
||||||
continue
|
|
||||||
|
|
||||||
start_idx = match.end()
|
|
||||||
# Find matching closing brace
|
|
||||||
brace_count = 1
|
|
||||||
current_idx = start_idx
|
|
||||||
while brace_count > 0 and current_idx < len(content):
|
|
||||||
char = content[current_idx]
|
|
||||||
if char == '{':
|
|
||||||
brace_count += 1
|
|
||||||
elif char == '}':
|
|
||||||
brace_count -= 1
|
|
||||||
current_idx += 1
|
|
||||||
|
|
||||||
block = content[start_idx:current_idx-1]
|
|
||||||
|
|
||||||
# Now parse the key-value pairs inside the block
|
|
||||||
# Example: "key": "value", or 'key': 'value',
|
|
||||||
# Handle escaped quotes.
|
|
||||||
# Pattern: (['"])(.*?)\1\s*:\s*(['"])(.*?)\3\s*(?:,|$)
|
|
||||||
kv_pattern = re.compile(r'^\s*([\'"])(.*?)\1\s*:\s*([\'"])(.*?)\3\s*,?\s*$', re.MULTILINE)
|
|
||||||
kv_matches = kv_pattern.findall(block)
|
|
||||||
|
|
||||||
lang_map = {}
|
|
||||||
for kv in kv_matches:
|
|
||||||
key = kv[1]
|
|
||||||
val = kv[3]
|
|
||||||
# Unescape quotes
|
|
||||||
key = key.replace('\\"', '"').replace("\\'", "'")
|
|
||||||
val = val.replace('\\"', '"').replace("\\'", "'")
|
|
||||||
lang_map[key] = val
|
|
||||||
|
|
||||||
extracted[lang] = lang_map
|
|
||||||
print(f"Extracted {lang}: {len(lang_map)} keys")
|
|
||||||
|
|
||||||
return extracted
|
|
||||||
|
|
||||||
extracted = extract_language_maps("scratch/legacy_translations.dart")
|
|
||||||
with open("scratch/legacy_extracted_languages.json", "w", encoding="utf-8") as f:
|
|
||||||
json.dump(extracted, f, ensure_ascii=False, indent=2)
|
|
||||||
print("Saved legacy extracted languages to JSON.")
|
|
||||||
@@ -1,629 +0,0 @@
|
|||||||
#!/usr/bin/env python3.13
|
|
||||||
"""
|
|
||||||
Generate the updated feasibility study (Version 3.1) for Siro App.
|
|
||||||
Produces both .docx and .html output.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from docx import Document
|
|
||||||
from docx.shared import Inches, Pt, Cm, RGBColor
|
|
||||||
from docx.enum.text import WD_ALIGN_PARAGRAPH
|
|
||||||
from docx.enum.table import WD_TABLE_ALIGNMENT
|
|
||||||
from docx.enum.section import WD_ORIENT
|
|
||||||
from docx.oxml.ns import qn
|
|
||||||
from docx.oxml import OxmlElement
|
|
||||||
import os
|
|
||||||
|
|
||||||
OUTPUT_DIR = "/Users/hamzaaleghwairyeen/development/App/Siro"
|
|
||||||
|
|
||||||
# ─── Colours ───
|
|
||||||
PRIMARY = RGBColor(0x1E, 0x3A, 0x8A)
|
|
||||||
DARK = RGBColor(0x0F, 0x17, 0x2A)
|
|
||||||
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
|
|
||||||
GREY = RGBColor(0x47, 0x55, 0x69)
|
|
||||||
LGREY = RGBColor(0xF1, 0xF5, 0xF9)
|
|
||||||
GREEN = RGBColor(0x16, 0x7A, 0x34)
|
|
||||||
RED = RGBColor(0xB9, 0x1C, 0x1C)
|
|
||||||
|
|
||||||
def set_cell_shading(cell, color_hex):
|
|
||||||
"""Set cell background colour."""
|
|
||||||
shading = OxmlElement('w:shd')
|
|
||||||
shading.set(qn('w:val'), 'clear')
|
|
||||||
shading.set(qn('w:color'), 'auto')
|
|
||||||
shading.set(qn('w:fill'), color_hex)
|
|
||||||
cell._tc.get_or_add_tcPr().append(shading)
|
|
||||||
|
|
||||||
def add_table(doc, headers, rows, col_widths=None, header_color="1e3a8a", header_text_color="FFFFFF"):
|
|
||||||
"""Add a formatted table."""
|
|
||||||
table = doc.add_table(rows=1 + len(rows), cols=len(headers))
|
|
||||||
table.alignment = WD_TABLE_ALIGNMENT.CENTER
|
|
||||||
table.style = 'Table Grid'
|
|
||||||
|
|
||||||
# Header row
|
|
||||||
for i, h in enumerate(headers):
|
|
||||||
cell = table.rows[0].cells[i]
|
|
||||||
cell.text = ''
|
|
||||||
p = cell.paragraphs[0]
|
|
||||||
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
|
||||||
run = p.add_run(h)
|
|
||||||
run.bold = True
|
|
||||||
run.font.size = Pt(10)
|
|
||||||
run.font.color.rgb = WHITE
|
|
||||||
set_cell_shading(cell, header_color)
|
|
||||||
|
|
||||||
# Data rows
|
|
||||||
for r_idx, row in enumerate(rows):
|
|
||||||
for c_idx, val in enumerate(row):
|
|
||||||
cell = table.rows[r_idx + 1].cells[c_idx]
|
|
||||||
cell.text = ''
|
|
||||||
p = cell.paragraphs[0]
|
|
||||||
p.alignment = WD_ALIGN_PARAGRAPH.CENTER if c_idx > 0 else WD_ALIGN_PARAGRAPH.RIGHT
|
|
||||||
run = p.add_run(str(val))
|
|
||||||
run.font.size = Pt(9.5)
|
|
||||||
if r_idx == len(rows) - 1:
|
|
||||||
run.bold = True
|
|
||||||
if c_idx == 0:
|
|
||||||
run.bold = True
|
|
||||||
|
|
||||||
if col_widths:
|
|
||||||
for i, w in enumerate(col_widths):
|
|
||||||
for row in table.rows:
|
|
||||||
row.cells[i].width = Cm(w)
|
|
||||||
return table
|
|
||||||
|
|
||||||
def add_heading(doc, text, level=1):
|
|
||||||
h = doc.add_heading(text, level=level)
|
|
||||||
h.alignment = WD_ALIGN_PARAGRAPH.RIGHT
|
|
||||||
for run in h.runs:
|
|
||||||
run.font.color.rgb = PRIMARY if level <= 2 else DARK
|
|
||||||
return h
|
|
||||||
|
|
||||||
def add_para(doc, text, bold=False, size=10, color=None, align=WD_ALIGN_PARAGRAPH.RIGHT):
|
|
||||||
p = doc.add_paragraph()
|
|
||||||
p.alignment = align
|
|
||||||
run = p.add_run(text)
|
|
||||||
run.bold = bold
|
|
||||||
run.font.size = Pt(size)
|
|
||||||
if color:
|
|
||||||
run.font.color.rgb = color
|
|
||||||
return p
|
|
||||||
|
|
||||||
def add_bullet(doc, text, bold_prefix=""):
|
|
||||||
p = doc.add_paragraph(style='List Bullet')
|
|
||||||
p.alignment = WD_ALIGN_PARAGRAPH.RIGHT
|
|
||||||
if bold_prefix:
|
|
||||||
run = p.add_run(bold_prefix)
|
|
||||||
run.bold = True
|
|
||||||
run.font.size = Pt(10)
|
|
||||||
run = p.add_run(text)
|
|
||||||
run.font.size = Pt(10)
|
|
||||||
return p
|
|
||||||
|
|
||||||
|
|
||||||
def generate_docx():
|
|
||||||
doc = Document()
|
|
||||||
|
|
||||||
# Set RTL for entire document
|
|
||||||
style = doc.styles['Normal']
|
|
||||||
style.font.name = 'Calibri'
|
|
||||||
style.font.size = Pt(10)
|
|
||||||
style.element.rPr.rFonts.set(qn('w:eastAsia'), 'Calibri')
|
|
||||||
|
|
||||||
# ── Title Page ──
|
|
||||||
for _ in range(4):
|
|
||||||
doc.add_paragraph()
|
|
||||||
|
|
||||||
p = doc.add_paragraph()
|
|
||||||
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
|
||||||
run = p.add_run("دراسة الجدوى الاقتصادية\nتطبيق سيرو للنقل الذكي")
|
|
||||||
run.bold = True
|
|
||||||
run.font.size = Pt(28)
|
|
||||||
run.font.color.rgb = PRIMARY
|
|
||||||
|
|
||||||
p = doc.add_paragraph()
|
|
||||||
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
|
||||||
run = p.add_run("الإصدار الثالث — يونيو 2026\nنموذج الدفع الشهري المرحلي")
|
|
||||||
run.font.size = Pt(16)
|
|
||||||
run.font.color.rgb = GREY
|
|
||||||
|
|
||||||
doc.add_paragraph()
|
|
||||||
|
|
||||||
# Key metrics boxes
|
|
||||||
metrics = [
|
|
||||||
("السوق المستهدف", "سوريا — دمشق الكبرى"),
|
|
||||||
("نموذج الاستثمار", "دفع شهري مرحلي ($8,000/شهر)"),
|
|
||||||
("رأس المال التأسيسي", "$11,500 - $12,000 (دفعة واحدة)"),
|
|
||||||
("نقطة الخروج", "نهاية الشهر الخامس إذا لم تتحقق المؤشرات"),
|
|
||||||
("نطاق نقطة التعادل", "الشهر السابع حتى التاسع"),
|
|
||||||
("أقصى تعرض للمستثمر", "$51,500 - $52,000 (عند الخروج المبكر)"),
|
|
||||||
("إجمالي الاستثمار المتوقع", "$67,500 — $84,000"),
|
|
||||||
]
|
|
||||||
for label, val in metrics:
|
|
||||||
p = doc.add_paragraph()
|
|
||||||
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
|
||||||
run = p.add_run(f"{label}: ")
|
|
||||||
run.bold = True
|
|
||||||
run.font.size = Pt(11)
|
|
||||||
run = p.add_run(val)
|
|
||||||
run.font.size = Pt(11)
|
|
||||||
run.font.color.rgb = PRIMARY
|
|
||||||
|
|
||||||
doc.add_page_break()
|
|
||||||
|
|
||||||
# ── 1. Executive Summary ──
|
|
||||||
add_heading(doc, "أولاً: الملخص التنفيذي", 1)
|
|
||||||
|
|
||||||
add_para(doc,
|
|
||||||
"سيرو تطبيق نقل ذكي جاهز للإطلاق في السوق السوري، يعمل على بنية تحتية مستقلة تقنياً لا تعتمد على "
|
|
||||||
"أي خدمات خارجية مكلفة أو مقيدة جغرافياً. يتميز بأدنى عمولة في السوق (11%) مقابل 17-20% لدى المنافسين، "
|
|
||||||
"مما يجعله الخيار المنطقي للسائق والراكب معاً.")
|
|
||||||
|
|
||||||
add_para(doc,
|
|
||||||
"تتبنى هذه الخطة نموذج دفع شهري مرحلي يحمي المستثمر من تجميد رأس المال، ويضمن استمرارية تشغيلية مرتبطة "
|
|
||||||
"بالأداء الفعلي. وجود شرط خروج صريح في الشهر الخامس يُعطي الطرفين وضوحاً تاماً في المخاطر والتوقعات.")
|
|
||||||
|
|
||||||
add_para(doc, "أبرز نقاط القوة التنافسية", bold=True, size=11)
|
|
||||||
bullets = [
|
|
||||||
("▸ المنتج مكتمل تقنياً ومختبر ميدانياً — لا مخاطر تطوير"),
|
|
||||||
("▸ تجربة الطيار: 1,447 سائق انضموا بـ$1,400 إعلانات فقط — بدون حوافز"),
|
|
||||||
("▸ أدنى عمولة في السوق: 11% مقابل 17-20% عند المنافسين"),
|
|
||||||
("▸ بنية تحتية ذاتية توفر 60% من تكاليف التشغيل مقارنة بالنظراء"),
|
|
||||||
("▸ المؤسس يغطي وظائف 5 أشخاص — وفر $3,000-5,000/شهر في الرواتب"),
|
|
||||||
("▸ نموذج استثمار شهري مرحلي: صفر مخاطر تجميد رأس المال"),
|
|
||||||
]
|
|
||||||
for b in bullets:
|
|
||||||
add_bullet(doc, b)
|
|
||||||
|
|
||||||
# Key indicators table
|
|
||||||
add_para(doc, "مؤشرات الأداء الرئيسية", bold=True, size=11)
|
|
||||||
add_table(doc,
|
|
||||||
["المؤشر", "القيمة"],
|
|
||||||
[
|
|
||||||
["رأس المال التأسيسي (مرة واحدة)", "$11,500 - $12,000"],
|
|
||||||
["المصاريف التشغيلية الشهرية", "$8,000/شهر"],
|
|
||||||
["نقطة الخروج للمستثمر", "نهاية الشهر الخامس إذا لم تتحقق المؤشرات"],
|
|
||||||
["نطاق التعادل", "الشهر 7 — 9"],
|
|
||||||
["أقصى خسارة عند الخروج المبكر", "$51,500 - $52,000"],
|
|
||||||
["إجمالي الاستثمار حتى التعادل", "$67,500 — $84,000"],
|
|
||||||
["عمولة التطبيق", "11% من كل رحلة"],
|
|
||||||
["متوسط حصة الشركة للرحلة", "$0.30 / رحلة"],
|
|
||||||
["هدف الرحلات عند التعادل", "889 رحلة/يوم"],
|
|
||||||
],
|
|
||||||
col_widths=[12, 6]
|
|
||||||
)
|
|
||||||
|
|
||||||
# ── 2. Vision & Business Model ──
|
|
||||||
add_heading(doc, "ثانياً: الرؤية والنموذج التجاري", 1)
|
|
||||||
|
|
||||||
add_para(doc, "الرؤية", bold=True, size=11)
|
|
||||||
add_para(doc, "أن يكون سيرو المنصة الأولى للنقل الذكي الموثوق في سوريا، بعمولة عادلة للسائق وخدمة موثوقة للراكب، على بنية رقمية مستقلة وسيادية.")
|
|
||||||
|
|
||||||
add_para(doc, "نموذج الإيرادات", bold=True, size=11)
|
|
||||||
add_bullet(doc, "عمولة 11% من قيمة كل رحلة تُقتطع تلقائياً من أجرة السائق")
|
|
||||||
add_bullet(doc, "متوسط قيمة الرحلة: $2.75 — حصة الشركة: $0.30/رحلة")
|
|
||||||
add_bullet(doc, "مستقبلاً: إعلانات داخل التطبيق، اشتراكات السائق المميز، خدمات B2B للشركات والفنادق")
|
|
||||||
|
|
||||||
add_para(doc, "الميزة التنافسية — لماذا سيرو؟", bold=True, size=11)
|
|
||||||
add_table(doc,
|
|
||||||
["المعيار", "سيرو", "المنافسون"],
|
|
||||||
[
|
|
||||||
["عمولة التطبيق", "11%", "17% - 20%"],
|
|
||||||
["خريطة المنصة", "IntaleqMaps — ذاتية $0", "Google Maps $5,000-15,000/شهر"],
|
|
||||||
["نظام OTP", "Flash Call ذاتي — $0", "SMS مدفوع $0.03-0.05/رسالة"],
|
|
||||||
["تكلفة التطوير المستمر", "المؤسس = المطور", "فريق خارجي مكلف"],
|
|
||||||
["البنية التحتية", "خوادم ذاتية مستقلة", "Cloud APIs قابلة للتوقف"],
|
|
||||||
["خدمة العملاء", "مدمجة + AI (Nabeeh)", "مراكز خارجية مكلفة"],
|
|
||||||
],
|
|
||||||
col_widths=[5, 6, 7]
|
|
||||||
)
|
|
||||||
|
|
||||||
# ── 3. Market Analysis ──
|
|
||||||
add_heading(doc, "ثالثاً: تحليل السوق السوري", 1)
|
|
||||||
|
|
||||||
add_heading(doc, "3-1: لماذا الآن؟", 2)
|
|
||||||
add_para(doc, "تمر سوريا في مرحلة إعادة الإعمار وانفتاح اقتصادي تدريجي منذ نهاية 2024. دمشق الكبرى تشهد حركة تجارية متصاعدة مع نقص واضح في وسائل النقل المنظم.")
|
|
||||||
|
|
||||||
add_heading(doc, "3-2: حجم السوق", 2)
|
|
||||||
add_table(doc,
|
|
||||||
["المؤشر", "التقدير"],
|
|
||||||
[
|
|
||||||
["سكان دمشق الكبرى", "4 - 5 مليون نسمة"],
|
|
||||||
["مستخدمو الهاتف الذكي", "65% - 70%"],
|
|
||||||
["الرحلات اليومية المحتملة", "200,000 - 400,000 رحلة/يوم"],
|
|
||||||
["حصة السوق المستهدفة سنة 1", "1% - 2% (1,500 - 2,000 رحلة/يوم)"],
|
|
||||||
["نتيجة تجربة الطيار", "1,447 سائق سجلوا بـ$1,400 تسويق فقط"],
|
|
||||||
],
|
|
||||||
col_widths=[10, 8]
|
|
||||||
)
|
|
||||||
|
|
||||||
add_heading(doc, "3-3: المنافسون الرئيسيون", 2)
|
|
||||||
add_table(doc,
|
|
||||||
["التطبيق", "نقطة الضعف", "فرصتنا"],
|
|
||||||
[
|
|
||||||
["YallaGo", "عمولة 20% تُرهق السائق", "11% = ولاء السائق يتحول إلينا"],
|
|
||||||
["Zakinn", "عمولة 17% تُرهق السائق", "نبدأ من المنطقة الأكثر طلباً"],
|
|
||||||
["Tafaddal", "تجربة مستخدم ضعيفة", "UX متقدم + تطبيق سائق أفضل"],
|
|
||||||
["سيرو — ميزتنا", "أدنى عمولة + بنية مستقلة", "الأصعب تقليداً في السوق"],
|
|
||||||
],
|
|
||||||
col_widths=[4, 6, 8]
|
|
||||||
)
|
|
||||||
|
|
||||||
# ── 4. Operational Plan ──
|
|
||||||
doc.add_page_break()
|
|
||||||
add_heading(doc, "رابعاً: الخطة التشغيلية", 1)
|
|
||||||
|
|
||||||
add_heading(doc, "4-1: اختيار موقع المكتب في دمشق", 2)
|
|
||||||
add_para(doc, "يشترط الترخيص القانوني وجود مقر موثق. الميزانية المخصصة: $600/شهر.")
|
|
||||||
|
|
||||||
add_table(doc,
|
|
||||||
["المنطقة", "التقييم", "الإيجار الشهري", "الملاحظة"],
|
|
||||||
[
|
|
||||||
["المزة", "★★★★★", "$500 - $700", "الأفضل: مقر الشركات الكبرى"],
|
|
||||||
["كفرسوسة", "★★★★☆", "$400 - $600", "قريب من المزة، أسعار معقولة"],
|
|
||||||
["الصالحية", "★★★☆☆", "$400 - $550", "مركزي، وصول جيد"],
|
|
||||||
["أبو رمانة", "★★☆☆☆", "$700 - $1,000", "مرموق لكن يتجاوز الميزانية"],
|
|
||||||
["برزة", "★★☆☆☆", "$280 - $400", "أرخص لكن أقل احترافية"],
|
|
||||||
],
|
|
||||||
col_widths=[3, 2.5, 3.5, 8]
|
|
||||||
)
|
|
||||||
add_para(doc, "التوصية: كفرسوسة أو المزة — 50-70 م² مع هامش تفاوض", bold=True)
|
|
||||||
|
|
||||||
# 4-2: Office Furniture (revised)
|
|
||||||
add_heading(doc, "4-2: المشتريات والتجهيزات المكتبية", 2)
|
|
||||||
|
|
||||||
add_para(doc, "أ — الأثاث المكتبي", bold=True, size=10)
|
|
||||||
add_table(doc,
|
|
||||||
["البند", "الكمية", "سعر الوحدة", "الإجمالي"],
|
|
||||||
[
|
|
||||||
["مكتب رئيسي مع أدراج", 1, "$150", "$150"],
|
|
||||||
["مكاتب موظفين بسيطة", 3, "$90", "$270"],
|
|
||||||
["كرسي مكتبي دوّار رئيسي", 1, "$110", "$110"],
|
|
||||||
["كراسي موظفين", 3, "$60", "$180"],
|
|
||||||
["طاولة اجتماعات صغيرة (4 أشخاص)", 1, "$80", "$80"],
|
|
||||||
["كراسي اجتماعات", 4, "$50", "$200"],
|
|
||||||
["برادي (ستائر) للمكتب", "—", "—", "$200"],
|
|
||||||
["رفوف تخزين بسيطة", "—", "—", "$50"],
|
|
||||||
["مراوح (عدد 2)", 2, "$40", "$80"],
|
|
||||||
["إجمالي الأثاث", "", "", "$1,320"],
|
|
||||||
],
|
|
||||||
col_widths=[7, 2, 2.5, 2.5]
|
|
||||||
)
|
|
||||||
|
|
||||||
add_para(doc, "ب — المعدات والتجهيزات", bold=True, size=10)
|
|
||||||
add_table(doc,
|
|
||||||
["البند", "الإجمالي"],
|
|
||||||
[
|
|
||||||
["راوتر WiFi احترافي", "$80"],
|
|
||||||
["طابعة/ماسح ضوئي", "$65"],
|
|
||||||
["إكسسوارات متنوعة", "$100"],
|
|
||||||
["مكيف هواء (شراء + تركيب)", "$450"],
|
|
||||||
["قرطاسية ومستلزمات (3 أشهر)", "$80"],
|
|
||||||
["أدوات ضيافة", "$80"],
|
|
||||||
["إجمالي التجهيزات", "$855"],
|
|
||||||
],
|
|
||||||
col_widths=[10, 4]
|
|
||||||
)
|
|
||||||
|
|
||||||
add_para(doc, "ج — أثاث وتجهيزات سكن المؤسس", bold=True, size=10)
|
|
||||||
add_table(doc,
|
|
||||||
["البند", "الإجمالي"],
|
|
||||||
[
|
|
||||||
["سرير (عدد 2)", "$80"],
|
|
||||||
["فرشة (عدد 2)", "$180"],
|
|
||||||
["إحرامات + مخدات (عدد 2)", "$40"],
|
|
||||||
["برادي للسكن", "$100"],
|
|
||||||
["ثلاجة صغيرة", "$100"],
|
|
||||||
["غاز صغير + أدوات مطبخ", "$100"],
|
|
||||||
["سخان مياه", "$70"],
|
|
||||||
["سفري + أدوات ضيافة", "$25"],
|
|
||||||
["إجمالي تجهيزات السكن", "$695"],
|
|
||||||
],
|
|
||||||
col_widths=[10, 4]
|
|
||||||
)
|
|
||||||
|
|
||||||
# 4-3: Technical Equipment
|
|
||||||
add_heading(doc, "4-3: أجهزة التطوير والمعدات التقنية", 2)
|
|
||||||
add_table(doc,
|
|
||||||
["البند", "الإجمالي", "ملاحظة"],
|
|
||||||
[
|
|
||||||
["MacBook Pro M4 Pro Max (40 GPU)", "$3,100", "جهاز التطوير والإدارة الرئيسي"],
|
|
||||||
["iPhone (أحدث إصدار)", "$500", "اختبار تطبيق iOS"],
|
|
||||||
["جهاز Android (أحدث إصدار)", "$300", "اختبار تطبيق Android"],
|
|
||||||
["باقي أجهزة التطوير", "$1,100", "ملحقات وإكسسوارات تطوير"],
|
|
||||||
["إجمالي أجهزة التطوير", "$5,000", ""],
|
|
||||||
],
|
|
||||||
col_widths=[8, 3.5, 5.5]
|
|
||||||
)
|
|
||||||
|
|
||||||
add_para(doc, "ملاحظة: تم استبدال أجهزة الحاسوب المكتبي لخدمة العملاء بهواتف ذكية (3 × $150 ضمن بند هواتف خدمة العملاء في CAPEX).", size=9, color=GREY)
|
|
||||||
|
|
||||||
# ── 5. HR Plan ──
|
|
||||||
add_heading(doc, "خامساً: خطة الموارد البشرية", 1)
|
|
||||||
|
|
||||||
add_heading(doc, "5-1: الهيكل الوظيفي والرواتب", 2)
|
|
||||||
add_table(doc,
|
|
||||||
["المسمى الوظيفي", "العدد", "الراتب الشهري", "الإجمالي"],
|
|
||||||
[
|
|
||||||
["المشغل الرئيسي / المؤسس التنفيذي", 1, "$3,500", "$3,500"],
|
|
||||||
["ممثل خدمة العملاء", 3, "$110 - $130", "$400"],
|
|
||||||
["إجمالي الرواتب الشهرية", "4 أشخاص", "", "$3,900"],
|
|
||||||
],
|
|
||||||
col_widths=[7, 2, 3.5, 3]
|
|
||||||
)
|
|
||||||
|
|
||||||
add_para(doc, "ملاحظات:", bold=True, size=9)
|
|
||||||
add_bullet(doc, "تم إلغاء بند مدير السوشيال ميديا (فريلانسر) — المؤسس يدير التسويق الرقمي مباشرة")
|
|
||||||
add_bullet(doc, "تم إلغاء بند السكرتيرة الإدارية — المهام توزع على فريق خدمة العملاء والمؤسس")
|
|
||||||
add_bullet(doc, "فريق خدمة العملاء: 3 موظفين براتب $110-130/شهر ($400 إجمالي)")
|
|
||||||
add_bullet(doc, "برنامج تدريب خدمة العملاء: أسبوعين (بدلاً من 4 أسابيع)")
|
|
||||||
|
|
||||||
# ── 6. Financial Plan ──
|
|
||||||
doc.add_page_break()
|
|
||||||
add_heading(doc, "سادساً: الخطة المالية التفصيلية", 1)
|
|
||||||
|
|
||||||
add_heading(doc, "6-1: رأس المال التأسيسي — $9,000 (دفعة واحدة)", 2)
|
|
||||||
add_para(doc, "يُصرف كاملاً عند بدء التأسيس قبل الإطلاق.")
|
|
||||||
|
|
||||||
add_table(doc,
|
|
||||||
["البند", "المبلغ", "البيان"],
|
|
||||||
[
|
|
||||||
["شهادة اعتمادية (الهيئة الناظمة)", "$600", "ترخيص التطبيق"],
|
|
||||||
["أتعاب المحامي والتخليص القانوني", "$1,500", "تأسيس الشركة + تراخيص"],
|
|
||||||
["رسوم وزارة (سجل تجاري + وزارة نقل)", "$200", "رسوم حكومية"],
|
|
||||||
["هواتف خدمة العملاء (3 أجهزة)", "$450", "3 × $150"],
|
|
||||||
["أجهزة التطوير (Mac + iPhone + Android)", "$5,000", "حسب التفصيل في 4-3"],
|
|
||||||
["لابتوب للسيرفرات وإدارة الإعلانات", "$350", "جهاز منفصل لإدارة السيرفرات"],
|
|
||||||
["تجهيز المكتب — أثاث", "$1,320", "حسب التفصيل في 4-2-أ"],
|
|
||||||
["تجهيز المكتب — معدات وتجهيزات", "$855", "حسب التفصيل في 4-2-ب"],
|
|
||||||
["تجهيزات سكن المؤسس", "$695", "أثاث وتجهيزات أساسية"],
|
|
||||||
["تكاليف السفر والنقل والإقامة التأسيسية (أسبوعين)", "$400 - $800", "مواصلات + سكن مؤقت + تجهيز"],
|
|
||||||
["إجمالي رأس المال التأسيسي", "$11,370 - $11,770 ≈ $11,500 - $12,000", ""],
|
|
||||||
],
|
|
||||||
col_widths=[8, 2.5, 6]
|
|
||||||
)
|
|
||||||
|
|
||||||
add_heading(doc, "6-2: المصاريف التشغيلية الشهرية — $8,000/شهر", 2)
|
|
||||||
add_table(doc,
|
|
||||||
["البند", "المبلغ", "البيان"],
|
|
||||||
[
|
|
||||||
["راتب المشغل الرئيسي", "$3,500", "تقني + إداري + تسويق + عمليات"],
|
|
||||||
["فريق خدمة العملاء × 3", "$400", "بمتوسط $133/موظف"],
|
|
||||||
["سيرفرات وبنية سحابية", "$200", "استضافة + نسخ احتياطي"],
|
|
||||||
["إيجار المكتب", "$600", "كفرسوسة / المزة"],
|
|
||||||
["إيجار سكن المشغل", "$300", "ضمن خطة الرواتب"],
|
|
||||||
["خدمات الإنترنت", "$45", "خط ثابت مزدوج"],
|
|
||||||
["فاتورة الكهرباء", "$70", "مكتب + معدات"],
|
|
||||||
["باقات خطوط هواتف (3 أرقام)", "$30", "لخدمة العملاء"],
|
|
||||||
["إعلانات رقمية (Facebook + TikTok)", "$2,855", "المتبقي من الميزانية"],
|
|
||||||
["إجمالي OPEX الشهري", "$8,000", ""],
|
|
||||||
],
|
|
||||||
col_widths=[7, 2.5, 6]
|
|
||||||
)
|
|
||||||
|
|
||||||
add_para(doc, "ملاحظة: تم إلغاء بند إدارة السوشيال ميديا ($200) وبند السكرتيرة ($100). الفائض (~$355 إضافية) يُضاف إلى ميزانية الإعلانات الرقمية ($2,855 بدلاً من $2,500).", size=9, color=GREY)
|
|
||||||
|
|
||||||
# 6-3: Driver Incentives
|
|
||||||
add_heading(doc, "6-3: خطة حوافز السائقين", 2)
|
|
||||||
add_table(doc,
|
|
||||||
["الفترة", "السائقون", "التكلفة", "المصدر"],
|
|
||||||
[
|
|
||||||
["الشهر الأول", "100 سائق × $15", "$1,500", "من CAPEX (احتياطي)"],
|
|
||||||
["الشهر الثاني", "120 سائق × $15", "$1,800", "من CAPEX (احتياطي)"],
|
|
||||||
["الشهر الثالث", "150+ سائق", "من الإيرادات", "ذاتي التمويل"],
|
|
||||||
["الشهر الرابع+", "300-500 سائق", "من الإيرادات", "ذاتي التمويل"],
|
|
||||||
],
|
|
||||||
col_widths=[4, 4, 3.5, 4]
|
|
||||||
)
|
|
||||||
|
|
||||||
# 6-4: Cash Flow Table
|
|
||||||
add_heading(doc, "6-4: جدول التدفق النقدي الشهري", 2)
|
|
||||||
add_table(doc,
|
|
||||||
["الشهر", "صرف المستثمر", "الإيرادات", "العجز", "الإجمالي", "رحلات/يوم", "سائق نشط"],
|
|
||||||
[
|
|
||||||
["التأسيس", "$11,500-12,000", "—", "-$11,500-12,000", "$11,500-12,000", "—", "—"],
|
|
||||||
["1", "$8,000", "$270", "-$7,730", "$19,500-20,000", "30", "100"],
|
|
||||||
["2", "$8,000", "$630", "-$7,370", "$27,500-28,000", "70", "120"],
|
|
||||||
["3", "$8,000", "$1,350", "-$6,650", "$35,500-36,000", "150", "220"],
|
|
||||||
["★4 — فحص", "$8,000", "$3,150", "-$4,850", "$43,500-44,000", "350", "350"],
|
|
||||||
["★5 — خروج", "$8,000", "$5,400", "-$2,600", "$51,500-52,000", "600", "480"],
|
|
||||||
["6", "$8,000", "$6,750", "-$1,250", "$59,500-60,000", "750", "550"],
|
|
||||||
["⚡7", "$8,000", "$8,100", "+$100", "$67,500-68,000", "900", "630"],
|
|
||||||
["⚡8", "$8,000", "$9,450", "+$1,450", "$75,500-76,000", "1,050", "750"],
|
|
||||||
["⚡9", "$8,000", "$10,500", "+$2,500", "$83,500-84,000", "1,167", "840"],
|
|
||||||
["10", "$0", "$11,250", "+$3,250", "—", "1,250", "900"],
|
|
||||||
["11", "$0", "$12,375", "+$4,375", "—", "1,375", "980"],
|
|
||||||
["12", "$0", "$13,500", "+$5,500", "—", "1,500", "1,050"],
|
|
||||||
["13", "$0", "$14,400", "+$6,400", "—", "1,600", "1,100"],
|
|
||||||
["14", "$0", "$15,300", "+$7,300", "—", "1,700", "1,150"],
|
|
||||||
],
|
|
||||||
col_widths=[2.5, 2.5, 2, 2, 2.5, 2, 2]
|
|
||||||
)
|
|
||||||
|
|
||||||
# ── 7. Investment Structure ──
|
|
||||||
doc.add_page_break()
|
|
||||||
add_heading(doc, "سابعاً: هيكل الاستثمار — نموذج الدفع الشهري", 1)
|
|
||||||
|
|
||||||
add_para(doc, "آلية الدفع:", bold=True, size=11)
|
|
||||||
add_bullet(doc, "المستثمر يدفع $11,500-$12,000 مرة واحدة عند التوقيع (CAPEX)")
|
|
||||||
add_bullet(doc, "يدفع $8,000 شهرياً لتغطية التشغيل الكامل")
|
|
||||||
add_bullet(doc, "الدفع يتوقف تلقائياً عندما تتجاوز الإيرادات $8,000/شهر")
|
|
||||||
add_bullet(doc, "لا يوجد التزام بإجمالي محدد مقدماً")
|
|
||||||
|
|
||||||
add_para(doc, "", size=6)
|
|
||||||
add_para(doc, "جدول الدفع المتوقع (سيناريو قاعدي — تعادل الشهر 8):", bold=True, size=10)
|
|
||||||
add_table(doc,
|
|
||||||
["الشهر", "المبلغ", "نوع الدفع", "حالة المشروع"],
|
|
||||||
[
|
|
||||||
["صفر", "$11,500-$12,000", "مرة واحدة", "تجهيز + ترخيص + تعيين"],
|
|
||||||
["1", "$8,000", "شهري", "إطلاق ناعم"],
|
|
||||||
["2", "$8,000", "شهري", "نمو متصاعد"],
|
|
||||||
["3", "$8,000", "شهري", "حوافز ذاتية"],
|
|
||||||
["4 — فحص", "$8,000", "شهري", "مراجعة أداء"],
|
|
||||||
["5 — خروج", "$8,000", "شهري", "استمرار أو خروج"],
|
|
||||||
["6", "$8,000", "شهري", "قرب التعادل"],
|
|
||||||
["7", "$8,000", "شهري", "تعادل متفائل"],
|
|
||||||
["8 — تعادل", "$8,000 (آخر)", "شهري", "الإيرادات ≥ $8,000"],
|
|
||||||
["9+", "$0", "ذاتي", "المشروع يمول نفسه"],
|
|
||||||
],
|
|
||||||
col_widths=[3, 3, 3, 7]
|
|
||||||
)
|
|
||||||
|
|
||||||
add_para(doc, "", size=6)
|
|
||||||
add_para(doc, "إجمالي تعرض المستثمر في كل سيناريو:", bold=True, size=10)
|
|
||||||
add_table(doc,
|
|
||||||
["السيناريو", "التوقف", "الإجمالي", "ملاحظة"],
|
|
||||||
[
|
|
||||||
["خروج مبكر (فشل)", "نهاية ش5", "$51,500-$52,000", "أقصى خسارة ~$52,000"],
|
|
||||||
["تعادل متفائل", "منتصف ش7", "$59,500-$60,000", "أفضل سيناريو"],
|
|
||||||
["تعادل قاعدي", "منتصف ش8", "$67,500-$68,000", "الأرجح"],
|
|
||||||
["تعادل محافظ", "منتصف ش9", "$75,500-$76,000", "نمو أبطأ"],
|
|
||||||
],
|
|
||||||
col_widths=[5, 3, 3, 5]
|
|
||||||
)
|
|
||||||
|
|
||||||
add_para(doc, "", size=6)
|
|
||||||
add_para(doc, "لماذا لا يوجد احتياطي مالي في هذا النموذج؟", bold=True, size=11)
|
|
||||||
add_para(doc, "في النموذج القديم (مبلغ واحد)، المستثمر يدفع كل شيء مقدماً والاحتياطي يجلس خاملاً. في النموذج الجديد (شهري):", size=10)
|
|
||||||
add_bullet(doc, "المستثمر يدفع فقط ما صُرف فعلاً")
|
|
||||||
add_bullet(doc, "لا توجد أموال خاملة — كل دولار يُشغَّل")
|
|
||||||
add_bullet(doc, "المستثمر يخاطر بـ$51,000 كحد أقصى (عند الخروج)")
|
|
||||||
add_bullet(doc, "نقطة الخروج هي الحماية الحقيقية بدلاً من الاحتياطي")
|
|
||||||
|
|
||||||
# ── 8. Exit Clause ──
|
|
||||||
add_heading(doc, "ثامناً: شرط الخروج — بند الحماية", 1)
|
|
||||||
|
|
||||||
add_para(doc, "يحق للمستثمر إيقاف الدفعات الشهرية والخروج في نهاية الشهر الخامس إذا لم تتحقق المؤشرات.", size=10)
|
|
||||||
|
|
||||||
add_para(doc, "", size=6)
|
|
||||||
add_para(doc, "مؤشرات الأداء — نقطة الفحص (الشهر 4):", bold=True, size=10)
|
|
||||||
add_table(doc,
|
|
||||||
["المؤشر", "الحد الأدنى", "الحد المثالي"],
|
|
||||||
[
|
|
||||||
["الرحلات اليومية", "70/يوم", "150/يوم"],
|
|
||||||
["السائقون المسجلون", "150", "350"],
|
|
||||||
["السائقون النشطون", "50", "150"],
|
|
||||||
["الإيرادات الشهرية", "$630", "$1,350"],
|
|
||||||
["معدل احتجاز السائق", "50%", "70%"],
|
|
||||||
["تقييم التطبيق", "3.0+", "3.5+"],
|
|
||||||
],
|
|
||||||
col_widths=[6, 4, 4]
|
|
||||||
)
|
|
||||||
|
|
||||||
add_para(doc, "", size=6)
|
|
||||||
add_para(doc, "مؤشرات الأداء — نقطة القرار (الشهر 5):", bold=True, size=10)
|
|
||||||
add_table(doc,
|
|
||||||
["المؤشر", "حد الاستمرار", "الخروج إذا أقل من"],
|
|
||||||
[
|
|
||||||
["الرحلات اليومية", "120/يوم", "70/يوم"],
|
|
||||||
["السائقون النشطون", "100", "50"],
|
|
||||||
["الإيرادات الشهرية", "$1,080+", "$630"],
|
|
||||||
["نمو أسبوعي", "+10% متواصل", "ثبات أو تراجع"],
|
|
||||||
["عقود B2B", "عقد واحد", "صفر عقود"],
|
|
||||||
],
|
|
||||||
col_widths=[6, 4, 4]
|
|
||||||
)
|
|
||||||
|
|
||||||
# ── 9. Break-Even ──
|
|
||||||
add_heading(doc, "تاسعاً: تحليل نقطة التعادل — نطاق الشهر 7 إلى 9", 1)
|
|
||||||
|
|
||||||
add_para(doc, "لماذا نطاق وليس رقماً ثابتاً؟", bold=True, size=10)
|
|
||||||
add_para(doc, "السوق السوري في مرحلة إعادة الإعمار = سوق متقلب بطبيعته. النطاق (7-9) أكثر صدقاً وأكثر حماية لكلا الطرفين.")
|
|
||||||
|
|
||||||
add_para(doc, "", size=6)
|
|
||||||
add_table(doc,
|
|
||||||
["السيناريو", "نقطة التعادل", "إجمالي الاستثمار", "الوصف"],
|
|
||||||
[
|
|
||||||
["متفائل", "الشهر 7", "$59,500-$60,000", "نمو سريع، B2B مبكر"],
|
|
||||||
["قاعدي (الأرجح)", "الشهر 8", "$67,500-$68,000", "نمو طبيعي"],
|
|
||||||
["محافظ", "الشهر 9", "$75,500-$76,000", "سوق متقلب"],
|
|
||||||
["خروج مبكر", "لا تعادل", "$51,500-$52,000", "آخر دفعة ش5"],
|
|
||||||
],
|
|
||||||
col_widths=[4, 3, 4, 5]
|
|
||||||
)
|
|
||||||
|
|
||||||
add_para(doc, "", size=6)
|
|
||||||
add_para(doc, "معادلة التعادل:", bold=True, size=11)
|
|
||||||
add_para(doc, "889 رحلة/يوم (عند $0.30/رحلة × 30 يوماً = $8,010)", bold=True, size=12, color=PRIMARY)
|
|
||||||
add_table(doc,
|
|
||||||
["المعطى", "الرقم", "كيف وصلنا إليه"],
|
|
||||||
[
|
|
||||||
["عمولة الشركة لكل رحلة", "$0.30", "11% من متوسط رحلة $2.75"],
|
|
||||||
["أيام الشهر", "30", ""],
|
|
||||||
["OPEX الشهري المستهدف", "$8,000", ""],
|
|
||||||
["رحلات التعادل اليومية", "889/يوم", "$8,000 ÷ $0.30 ÷ 30"],
|
|
||||||
["تعادل الشهر 7 (900/يوم)", "$8,100 > $8,000 ✓", "متحقق"],
|
|
||||||
],
|
|
||||||
col_widths=[6, 4, 6]
|
|
||||||
)
|
|
||||||
|
|
||||||
# ── 10. Risk Analysis ──
|
|
||||||
add_heading(doc, "عاشراً: تحليل المخاطر وخطط التخفيف", 1)
|
|
||||||
add_table(doc,
|
|
||||||
["المخاطرة", "التأثير", "الاحتمالية", "خطة التخفيف"],
|
|
||||||
[
|
|
||||||
["تأخر الترخيص", "عالٍ", "متوسطة", "البدء قبل الإطلاق بشهرين"],
|
|
||||||
["بطء نمو السائقين", "عالٍ", "منخفضة", "1,447 سائق بـ$1,400 — مثبت"],
|
|
||||||
["انخفاض الإيرادات", "عالٍ", "متوسطة", "شرط الخروج ش5 يحمي المستثمر"],
|
|
||||||
["تقلبات أمنية/سياسية", "عالٍ", "منخفضة-متوسطة", "بنية مستقلة - لا اعتماد على APIs غربية"],
|
|
||||||
["دخول منافس جديد", "متوسط", "متوسطة", "11% عمولة = عتبة تنافسية شبه مستحيلة"],
|
|
||||||
["مشاكل تقنية", "متوسط", "منخفضة", "المطور = المؤسس — استجابة فورية"],
|
|
||||||
["فشل الإعلانات", "متوسط", "منخفضة", "تجربة سابقة مثبتة + A/B Testing"],
|
|
||||||
],
|
|
||||||
col_widths=[5, 2, 3, 6]
|
|
||||||
)
|
|
||||||
|
|
||||||
# ── 11. Roadmap ──
|
|
||||||
add_heading(doc, "حادي عشر: خارطة الطريق والأهداف التشغيلية", 1)
|
|
||||||
add_table(doc,
|
|
||||||
["المرحلة", "الشهر", "الأهداف", "مؤشرات النجاح"],
|
|
||||||
[
|
|
||||||
["التأسيس", "قبل الإطلاق", "ترخيص + مكتب + توظيف", "وثائق قانونية + فريق جاهز"],
|
|
||||||
["الإطلاق الناعم", "ش 1-2", "100-120 سائق محفز", "70+ رحلة/يوم"],
|
|
||||||
["بناء الزخم", "ش 3", "حوافز ذاتية + B2B", "150 رحلة/يوم"],
|
|
||||||
["نقطة الفحص", "ش 4", "مراجعة مع المستثمر", "70-150 رحلة/يوم | $630-$1,350"],
|
|
||||||
["قرار الاستمرار", "ش 5", "استمرار أو خروج", "120 رحلة/يوم | عقد B2B"],
|
|
||||||
["الاقتراب من التعادل", "ش 6", "750 رحلة/يوم", "عجز $1,250 فقط"],
|
|
||||||
["⚡ نطاق التعادل", "ش 7-9", "الإيرادات ≥ OPEX", "889+ رحلة/يوم"],
|
|
||||||
["النمو الذاتي", "ش 10-12", "فائض شهري", "$3,250-$5,500 فائض"],
|
|
||||||
["التوسع الجغرافي", "ش 13+", "حلب أو اللاذقية", "1,600+ رحلة/يوم"],
|
|
||||||
],
|
|
||||||
col_widths=[4, 2, 4, 6]
|
|
||||||
)
|
|
||||||
|
|
||||||
# ── 12. Conclusion ──
|
|
||||||
doc.add_page_break()
|
|
||||||
add_heading(doc, "ثاني عشر: الخلاصة والتوصية النهائية", 1)
|
|
||||||
|
|
||||||
add_para(doc, "ملخص نقاط الثقة للمستثمر:", bold=True, size=11)
|
|
||||||
add_bullet(doc, "المنتج جاهز ومختبر — 1,447 سائق التحقوا بـ$1,400 فقط")
|
|
||||||
add_bullet(doc, "أدنى عمولة في السوق (11%) = ميزة تنافسية دائمة")
|
|
||||||
add_bullet(doc, "نموذج الدفع الشهري يحمي المستثمر — لا تجميد لرأس المال")
|
|
||||||
add_bullet(doc, "شرط الخروج الواضح يضع سقفاً لأقصى خسارة (~$52,000)")
|
|
||||||
add_bullet(doc, "نقطة التعادل (7-9 أشهر) واقعية ومبنية على بيانات حقيقية")
|
|
||||||
add_bullet(doc, "البنية التقنية المستقلة = مقاومة للعقوبات والقيود")
|
|
||||||
|
|
||||||
add_para(doc, "", size=6)
|
|
||||||
add_table(doc,
|
|
||||||
["المؤشر", "القيمة"],
|
|
||||||
[
|
|
||||||
["رأس المال التأسيسي (مرة واحدة)", "$11,500-$12,000 — عند توقيع الاتفاقية"],
|
|
||||||
["المصاريف التشغيلية الشهرية", "$8,000/شهر — يتوقف عند التعادل"],
|
|
||||||
["أقصى تعرض للمستثمر", "$51,500-$52,000 — نقطة الخروج: نهاية الشهر الخامس"],
|
|
||||||
["إجمالي الاستثمار حتى التعادل", "$67,500 — $84,000"],
|
|
||||||
["نطاق التعادل", "الشهر السابع إلى التاسع"],
|
|
||||||
],
|
|
||||||
col_widths=[10, 8]
|
|
||||||
)
|
|
||||||
|
|
||||||
add_para(doc, "", size=8)
|
|
||||||
add_para(doc, "هذه الدراسة أُعدت بناءً على بيانات حقيقية من السوق السوري وتجربة ميدانية فعلية. كل رقم فيها مبني على افتراضات محافظة.", bold=True, size=10, align=WD_ALIGN_PARAGRAPH.CENTER)
|
|
||||||
add_para(doc, "— نهاية دراسة الجدوى — الإصدار الثالث — يونيو 2026 —", size=9, color=GREY, align=WD_ALIGN_PARAGRAPH.CENTER)
|
|
||||||
|
|
||||||
# Save
|
|
||||||
docx_path = os.path.join(OUTPUT_DIR, "دراسة_الجدوى_سيرو_الإصدار_الثالث.docx")
|
|
||||||
doc.save(docx_path)
|
|
||||||
print(f"✅ DOCX saved: {docx_path}")
|
|
||||||
return docx_path
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
generate_docx()
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
import json
|
|
||||||
import re
|
|
||||||
import os
|
|
||||||
|
|
||||||
def parse_dart_map(filepath):
|
|
||||||
translations = {}
|
|
||||||
if not os.path.exists(filepath):
|
|
||||||
return translations
|
|
||||||
with open(filepath, 'r', encoding='utf-8') as f:
|
|
||||||
content = f.read()
|
|
||||||
|
|
||||||
pattern = re.compile(r'^\s*([\'"])(.*?)\1\s*:\s*([\'"])(.*?)\3\s*,?\s*$', re.MULTILINE)
|
|
||||||
matches = pattern.findall(content)
|
|
||||||
for match in matches:
|
|
||||||
key = match[1]
|
|
||||||
val = match[3]
|
|
||||||
key = key.replace('\\"', '"').replace("\\'", "'")
|
|
||||||
val = val.replace('\\"', '"').replace("\\'", "'")
|
|
||||||
translations[key] = val
|
|
||||||
|
|
||||||
return translations
|
|
||||||
|
|
||||||
ar_eg = parse_dart_map("siro_driver/lib/controller/local/ar_eg.dart")
|
|
||||||
ar_jo = parse_dart_map("siro_driver/lib/controller/local/ar_jo.dart")
|
|
||||||
ar_sy = parse_dart_map("siro_driver/lib/controller/local/ar_sy.dart")
|
|
||||||
|
|
||||||
with open("siro_driver_translations_data.json", "r", encoding="utf-8") as f:
|
|
||||||
json_data = json.load(f)
|
|
||||||
|
|
||||||
missing_keys_list = json_data.get('missing_keys', [])
|
|
||||||
|
|
||||||
ar_sy_keys = set(ar_sy.keys())
|
|
||||||
ar_jo_keys = set(ar_jo.keys())
|
|
||||||
ar_eg_keys = set(ar_eg.keys())
|
|
||||||
missing_keys_set = set(missing_keys_list)
|
|
||||||
|
|
||||||
all_keys = ar_sy_keys.union(ar_jo_keys).union(ar_eg_keys).union(missing_keys_set)
|
|
||||||
print(f"Total unique keys in union: {len(all_keys)}")
|
|
||||||
|
|
||||||
print(f"Keys in ar_eg not in ar_sy: {ar_eg_keys - ar_sy_keys}")
|
|
||||||
print(f"Keys in ar_sy not in ar_jo: {ar_sy_keys - ar_jo_keys}")
|
|
||||||
print(f"Keys in ar_jo not in ar_sy: {ar_jo_keys - ar_sy_keys}")
|
|
||||||
|
Before Width: | Height: | Size: 282 KiB |
@@ -1,289 +0,0 @@
|
|||||||
import hmac
|
|
||||||
import hashlib
|
|
||||||
import json
|
|
||||||
import base64
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
# Simulation configuration / Secrets
|
|
||||||
SECRET_KEY = "siro_super_secret_jwt_key"
|
|
||||||
SECRET_KEY_HMAC = "siro_super_secret_hmac_key"
|
|
||||||
FP_PEPPER = "siro_fp_pepper_salt"
|
|
||||||
S2S_SHARED_KEY = "s2s_shared_key_12345"
|
|
||||||
|
|
||||||
# Mock Database
|
|
||||||
db = {
|
|
||||||
"payments": [],
|
|
||||||
"passengerWallet": {},
|
|
||||||
"driverWallet": {},
|
|
||||||
"invoices": {},
|
|
||||||
"security_logs": []
|
|
||||||
}
|
|
||||||
|
|
||||||
def init_user(user_id, balance, is_driver=False):
|
|
||||||
if is_driver:
|
|
||||||
db["driverWallet"][user_id] = balance
|
|
||||||
else:
|
|
||||||
db["passengerWallet"][user_id] = balance
|
|
||||||
|
|
||||||
# Helper functions for Client
|
|
||||||
def generate_jwt(user_id, device_fp):
|
|
||||||
# Mock JWT creation payload
|
|
||||||
header = base64.b64encode(json.dumps({"alg": "HS256", "typ": "JWT"}).encode()).decode().replace("=", "")
|
|
||||||
hashed_fp = hashlib.sha256((device_fp + FP_PEPPER).encode()).hexdigest()
|
|
||||||
payload = base64.b64encode(json.dumps({
|
|
||||||
"iss": "Tripz-Wallet",
|
|
||||||
"user_id": user_id,
|
|
||||||
"fingerPrint": hashed_fp,
|
|
||||||
"exp": 1900000000 # future exp
|
|
||||||
}).encode()).decode().replace("=", "")
|
|
||||||
signature = hmac.new(SECRET_KEY.encode(), f"{header}.{payload}".encode(), hashlib.sha256).digest()
|
|
||||||
encoded_signature = base64.b64encode(signature).decode().replace("=", "").replace("+", "-").replace("/", "_")
|
|
||||||
return f"{header}.{payload}.{encoded_signature}"
|
|
||||||
|
|
||||||
def calculate_hmac_header(user_id):
|
|
||||||
return hmac.new(SECRET_KEY_HMAC.encode(), user_id.encode(), hashlib.sha256).hexdigest()
|
|
||||||
|
|
||||||
# Helper functions for Server Authentication
|
|
||||||
def authenticate_request(headers, payload_user_id):
|
|
||||||
# 1. JWT verification
|
|
||||||
auth_header = headers.get("Authorization", "")
|
|
||||||
if not auth_header.startswith("Bearer "):
|
|
||||||
return False, "Authorization token required"
|
|
||||||
token = auth_header.split(" ")[1]
|
|
||||||
|
|
||||||
try:
|
|
||||||
parts = token.split(".")
|
|
||||||
if len(parts) != 3:
|
|
||||||
return False, "Invalid token structure"
|
|
||||||
# Parse payload
|
|
||||||
payload_b64 = parts[1]
|
|
||||||
payload_b64 += "=" * ((4 - len(payload_b64) % 4) % 4)
|
|
||||||
payload = json.loads(base64.b64decode(payload_b64).decode())
|
|
||||||
except Exception as e:
|
|
||||||
return False, f"JWT decode failed: {str(e)}"
|
|
||||||
|
|
||||||
# Check Issuer
|
|
||||||
if payload.get("iss") != "Tripz-Wallet":
|
|
||||||
return False, "Invalid token issuer"
|
|
||||||
|
|
||||||
# Check User ID match
|
|
||||||
token_user_id = payload.get("user_id")
|
|
||||||
if token_user_id != payload_user_id:
|
|
||||||
return False, "User ID mismatch with token"
|
|
||||||
|
|
||||||
# 2. Device Fingerprint verification
|
|
||||||
device_fp_header = headers.get("X-Device-FP")
|
|
||||||
fp_in_token = payload.get("fingerPrint")
|
|
||||||
if device_fp_header and fp_in_token:
|
|
||||||
expected_fp = hashlib.sha256((device_fp_header + FP_PEPPER).encode()).hexdigest()
|
|
||||||
if not hmac.compare_digest(expected_fp, fp_in_token):
|
|
||||||
db["security_logs"].append(f"[WARNING] Device mismatch for user {payload_user_id}!")
|
|
||||||
return False, "Device mismatch (possible Session Hijacking)"
|
|
||||||
|
|
||||||
# 3. HMAC Auth verification
|
|
||||||
hmac_header = headers.get("X-HMAC-Auth")
|
|
||||||
if hmac_header:
|
|
||||||
expected_hmac = hmac.new(SECRET_KEY_HMAC.encode(), payload_user_id.encode(), hashlib.sha256).hexdigest()
|
|
||||||
if not hmac.compare_digest(expected_hmac, hmac_header):
|
|
||||||
db["security_logs"].append(f"[WARNING] HMAC mismatch for user {payload_user_id}!")
|
|
||||||
return False, "Invalid HMAC (possible payload/identity tampering)"
|
|
||||||
|
|
||||||
return True, "Authenticated"
|
|
||||||
|
|
||||||
# AI verification simulation (Mocking Gemini API)
|
|
||||||
def mock_gemini_verify_payment(invoice_number, amount, proof_text):
|
|
||||||
print(f"[Gemini AI Processing] Verifying proof for Invoice {invoice_number} of amount {amount}...")
|
|
||||||
print(f"[Gemini AI Input Proof] '{proof_text}'")
|
|
||||||
# Mocking semantic check on proof text
|
|
||||||
success = False
|
|
||||||
reason = ""
|
|
||||||
|
|
||||||
proof_lower = proof_text.lower()
|
|
||||||
amount_str = str(int(amount)) if amount == int(amount) else str(amount)
|
|
||||||
|
|
||||||
if amount_str in proof_lower and ("successful" in proof_lower or "transferred" in proof_lower or "تم تحويل" in proof_lower or "نجاح" in proof_lower):
|
|
||||||
success = True
|
|
||||||
reason = "Proof text verified successfully. Amount matches invoice."
|
|
||||||
else:
|
|
||||||
reason = f"Verification failed: Proof text does not indicate successful transfer of {amount}."
|
|
||||||
|
|
||||||
print(f"[Gemini AI Output] Verified: {success}, Reason: {reason}")
|
|
||||||
return {"verified": success, "reason": reason}
|
|
||||||
|
|
||||||
# Atomic transaction simulation for ride payment
|
|
||||||
def process_ride_payment(ride_id, driver_id, passenger_id, amount, payment_method, wallet_checked, s2s_key):
|
|
||||||
# S2S auth check
|
|
||||||
if s2s_key != S2S_SHARED_KEY:
|
|
||||||
return {"status": "failure", "message": "Unauthorized S2S call"}
|
|
||||||
|
|
||||||
print(f"\n--- Database Transaction Initiated for Ride {ride_id} ---")
|
|
||||||
|
|
||||||
# Save a rollback point
|
|
||||||
rollback_db = {
|
|
||||||
"payments": list(db["payments"]),
|
|
||||||
"passengerWallet": dict(db["passengerWallet"]),
|
|
||||||
"driverWallet": dict(db["driverWallet"])
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
|
||||||
# 1. Insert payment record
|
|
||||||
final_method = payment_method + "Ride" if wallet_checked else payment_method
|
|
||||||
payment_record = {
|
|
||||||
"id": str(uuid.uuid4().int)[:15],
|
|
||||||
"amount": amount,
|
|
||||||
"payment_method": final_method,
|
|
||||||
"passengerID": passenger_id,
|
|
||||||
"rideId": ride_id,
|
|
||||||
"driverID": driver_id
|
|
||||||
}
|
|
||||||
db["payments"].append(payment_record)
|
|
||||||
print(f"[DB] Inserted payment record: {payment_record}")
|
|
||||||
|
|
||||||
# 2. Deduct from passenger wallet
|
|
||||||
if wallet_checked:
|
|
||||||
if passenger_id not in db["passengerWallet"]:
|
|
||||||
db["passengerWallet"][passenger_id] = 0.0
|
|
||||||
|
|
||||||
db["passengerWallet"][passenger_id] -= amount
|
|
||||||
print(f"[DB] Deducted {amount} from Passenger {passenger_id}. New balance: {db["passengerWallet"][passenger_id]}")
|
|
||||||
|
|
||||||
# Settle debt if balance was negative before (example scenario)
|
|
||||||
# here we just apply deduction.
|
|
||||||
|
|
||||||
# 3. Deduct driver points (8% platform commission)
|
|
||||||
commission = amount * 0.08
|
|
||||||
if driver_id not in db["driverWallet"]:
|
|
||||||
db["driverWallet"][driver_id] = 0.0
|
|
||||||
db["driverWallet"][driver_id] -= commission
|
|
||||||
print(f"[DB] Subtracted 8% commission ({commission}) from Driver {driver_id} points. New points balance: {db["driverWallet"][driver_id]}")
|
|
||||||
|
|
||||||
print(f"[DB] Transaction Committed successfully.")
|
|
||||||
return {"status": "success", "message": "Transaction committed"}
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
# Rollback
|
|
||||||
db["payments"] = rollback_db["payments"]
|
|
||||||
db["passengerWallet"] = rollback_db["passengerWallet"]
|
|
||||||
db["driverWallet"] = rollback_db["driverWallet"]
|
|
||||||
print(f"[DB ERROR] Transaction Failed. Rolled back changes. Error: {str(e)}")
|
|
||||||
return {"status": "failure", "message": f"Transaction failed: {str(e)}"}
|
|
||||||
|
|
||||||
# Run Scenario Simulations
|
|
||||||
def run_egypt_simulation():
|
|
||||||
print("\n" + "="*50)
|
|
||||||
print("SCENARIO 1: EGYPT - CREDIT CARD / PAYMOB (Ahmed)")
|
|
||||||
print("="*50)
|
|
||||||
user_id = "egypt_passenger_101"
|
|
||||||
driver_id = "egypt_driver_501"
|
|
||||||
device_fp = "ahmed_iphone_13_fp_hash"
|
|
||||||
|
|
||||||
init_user(user_id, 500.0) # passenger wallet balance
|
|
||||||
init_user(driver_id, 100.0, is_driver=True) # driver wallet points
|
|
||||||
|
|
||||||
# 1. Client signs request
|
|
||||||
jwt = generate_jwt(user_id, device_fp)
|
|
||||||
hmac_header = calculate_hmac_header(user_id)
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
"Authorization": f"Bearer {jwt}",
|
|
||||||
"X-Device-FP": device_fp,
|
|
||||||
"X-HMAC-Auth": hmac_header
|
|
||||||
}
|
|
||||||
|
|
||||||
print(f"Passenger {user_id} initiating payment for Egypt ride. Ride cost: 120 EGP.")
|
|
||||||
|
|
||||||
# 2. Server authenticates headers
|
|
||||||
auth_ok, msg = authenticate_request(headers, user_id)
|
|
||||||
print(f"[Server Auth] Result: {auth_ok}, Message: {msg}")
|
|
||||||
|
|
||||||
if auth_ok:
|
|
||||||
# S2S transaction
|
|
||||||
res = process_ride_payment(
|
|
||||||
ride_id="ride_eg_999",
|
|
||||||
driver_id=driver_id,
|
|
||||||
passenger_id=user_id,
|
|
||||||
amount=120.0,
|
|
||||||
payment_method="PayMob",
|
|
||||||
wallet_checked=True,
|
|
||||||
s2s_key=S2S_SHARED_KEY
|
|
||||||
)
|
|
||||||
print(f"[Final Result] {res}")
|
|
||||||
|
|
||||||
def run_syria_simulation():
|
|
||||||
print("\n" + "="*50)
|
|
||||||
print("SCENARIO 2: SYRIA - MTN CASH WITH AI VERIFICATION (Bassel)")
|
|
||||||
print("="*50)
|
|
||||||
user_id = "syria_passenger_202"
|
|
||||||
driver_id = "syria_driver_602"
|
|
||||||
device_fp = "bassel_galaxy_s22_fp_hash"
|
|
||||||
|
|
||||||
init_user(user_id, 0.0) # passenger starts with 0.0
|
|
||||||
init_user(driver_id, 50.0, is_driver=True) # driver starts with 50 points
|
|
||||||
|
|
||||||
jwt = generate_jwt(user_id, device_fp)
|
|
||||||
hmac_header = calculate_hmac_header(user_id)
|
|
||||||
headers = {
|
|
||||||
"Authorization": f"Bearer {jwt}",
|
|
||||||
"X-Device-FP": device_fp,
|
|
||||||
"X-HMAC-Auth": hmac_header
|
|
||||||
}
|
|
||||||
|
|
||||||
invoice_number = "INV-MTN-8877"
|
|
||||||
amount = 50000.0 # 50,000 SYP for the ride/wallet load
|
|
||||||
|
|
||||||
print(f"Passenger {user_id} loads wallet via MTN Cash for invoice {invoice_number} of {amount} SYP.")
|
|
||||||
print("User transfers money and uploads transaction SMS proof.")
|
|
||||||
|
|
||||||
proof_text = "MTN Cash: You have successfully transferred 50000 SYP to SIRO system. Ref: 9812739182."
|
|
||||||
|
|
||||||
# 1. Server authenticates headers
|
|
||||||
auth_ok, msg = authenticate_request(headers, user_id)
|
|
||||||
print(f"[Server Auth] Result: {auth_ok}, Message: {msg}")
|
|
||||||
|
|
||||||
if auth_ok:
|
|
||||||
# 2. AI verifies proof text
|
|
||||||
ai_res = mock_gemini_verify_payment(invoice_number, amount, proof_text)
|
|
||||||
|
|
||||||
if ai_res["verified"]:
|
|
||||||
print(f"[Server] AI verified payment. Settle wallet.")
|
|
||||||
# Atomic settlement
|
|
||||||
print(f"\n--- Wallet Settlement Transaction Initiated (Syria) ---")
|
|
||||||
db["passengerWallet"][user_id] += amount
|
|
||||||
print(f"[DB] Added {amount} SYP to passenger {user_id} wallet. New balance: {db["passengerWallet"][user_id]} SYP")
|
|
||||||
print("[DB] Transaction Committed.")
|
|
||||||
else:
|
|
||||||
print(f"[Server] Payment rejected: {ai_res['reason']}")
|
|
||||||
|
|
||||||
def run_jordan_simulation():
|
|
||||||
print("\n" + "="*50)
|
|
||||||
print("SCENARIO 3: JORDAN - CLIQ WITH TAMPERED DEVICE FINGERPRINT (Rania)")
|
|
||||||
print("="*50)
|
|
||||||
user_id = "jordan_passenger_303"
|
|
||||||
device_fp = "rania_oneplus_11_fp_hash"
|
|
||||||
tampered_fp = "hijacked_device_fp_hash" # Attacker trying to reuse Rania's token from a different device
|
|
||||||
|
|
||||||
# 1. Client token generated for Rania on her real device
|
|
||||||
jwt = generate_jwt(user_id, device_fp)
|
|
||||||
hmac_header = calculate_hmac_header(user_id)
|
|
||||||
|
|
||||||
# Attacker sends request with correct JWT but hijacked/different device fingerprint header
|
|
||||||
headers = {
|
|
||||||
"Authorization": f"Bearer {jwt}",
|
|
||||||
"X-Device-FP": tampered_fp, # Hijacked device header
|
|
||||||
"X-HMAC-Auth": hmac_header
|
|
||||||
}
|
|
||||||
|
|
||||||
print(f"Attacker attempts to trigger payment under Rania's user_id using hijacked token on different device.")
|
|
||||||
|
|
||||||
# 2. Server authenticates headers
|
|
||||||
auth_ok, msg = authenticate_request(headers, user_id)
|
|
||||||
print(f"[Server Auth] Result: {auth_ok}, Message: {msg}")
|
|
||||||
|
|
||||||
if not auth_ok:
|
|
||||||
print("[Server Alert] Attack blocked successfully! Session Hijacking thwarted.")
|
|
||||||
print(f"Security logs: {db['security_logs']}")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
run_egypt_simulation()
|
|
||||||
run_syria_simulation()
|
|
||||||
run_jordan_simulation()
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
import os
|
|
||||||
import sys
|
|
||||||
from PIL import Image
|
|
||||||
|
|
||||||
def make_transparent_smooth(img_path, output_path, size):
|
|
||||||
if not os.path.exists(img_path):
|
|
||||||
print(f"Error: {img_path} does not exist.")
|
|
||||||
return False
|
|
||||||
|
|
||||||
img = Image.open(img_path).convert("RGBA")
|
|
||||||
img = img.resize(size, Image.Resampling.LANCZOS)
|
|
||||||
|
|
||||||
datas = img.getdata()
|
|
||||||
new_data = []
|
|
||||||
|
|
||||||
for item in datas:
|
|
||||||
r, g, b, a = item
|
|
||||||
closeness = min(r, g, b)
|
|
||||||
if closeness >= 240:
|
|
||||||
if closeness >= 253:
|
|
||||||
alpha = 0
|
|
||||||
else:
|
|
||||||
alpha = int(a * (253 - closeness) / (253 - 240))
|
|
||||||
new_data.append((255, 255, 255, alpha))
|
|
||||||
else:
|
|
||||||
new_data.append(item)
|
|
||||||
|
|
||||||
img.putdata(new_data)
|
|
||||||
img.save(output_path, "PNG")
|
|
||||||
print(f"Successfully saved processed image to {output_path}")
|
|
||||||
return True
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
artifact_dir = "scratch"
|
|
||||||
|
|
||||||
|
|
||||||
jobs = [
|
|
||||||
("car_marker_normal_1781540915043.png", "siro_rider/assets/images/car.png", (80, 90)),
|
|
||||||
("car_marker_normal_1781540915043.png", "siro_driver/assets/images/car.png", (80, 90)),
|
|
||||||
("car_marker_lady_1781540926836.png", "siro_rider/assets/images/lady1.png", (80, 90)),
|
|
||||||
("car_marker_lady_1781540926836.png", "siro_driver/assets/images/lady1.png", (80, 90)),
|
|
||||||
("category_fixed_price_1781540942631.png", "siro_rider/assets/images/carspeed.png", (500, 500)),
|
|
||||||
("category_comfort_1781540956914.png", "siro_rider/assets/images/blob.png", (500, 500)),
|
|
||||||
("category_electric_1781540970352.png", "siro_rider/assets/images/electric.png", (500, 500)),
|
|
||||||
("category_lady_1781540984745.png", "siro_rider/assets/images/lady.png", (500, 500)),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
for src, dst, size in jobs:
|
|
||||||
make_transparent_smooth(
|
|
||||||
os.path.join(artifact_dir, src),
|
|
||||||
dst,
|
|
||||||
size
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 283 KiB |
|
Before Width: | Height: | Size: 290 KiB |
|
Before Width: | Height: | Size: 283 KiB |
|
Before Width: | Height: | Size: 283 KiB |
|
Before Width: | Height: | Size: 283 KiB |
@@ -1 +0,0 @@
|
|||||||
print("Hello from python script")
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
import os
|
|
||||||
import re
|
|
||||||
|
|
||||||
languages = ['ar_eg', 'ar_jo', 'ar_sy', 'en', 'de', 'el', 'es', 'fa', 'fr', 'hi', 'it', 'ru', 'tr', 'ur', 'zh']
|
|
||||||
local_dir = "siro_driver/lib/controller/local"
|
|
||||||
|
|
||||||
def parse_dart_map(filepath):
|
|
||||||
translations = {}
|
|
||||||
if not os.path.exists(filepath):
|
|
||||||
print(f"Error: file {filepath} does not exist!")
|
|
||||||
return None
|
|
||||||
with open(filepath, 'r', encoding='utf-8') as f:
|
|
||||||
content = f.read()
|
|
||||||
|
|
||||||
# Matches: "key": "value"
|
|
||||||
pattern = re.compile(r'^\s*([\'"])(.*?)\1\s*:\s*([\'"])(.*?)\3\s*,?\s*$', re.MULTILINE)
|
|
||||||
matches = pattern.findall(content)
|
|
||||||
for match in matches:
|
|
||||||
key = match[1]
|
|
||||||
val = match[3]
|
|
||||||
# Store raw keys and values to check escaping
|
|
||||||
translations[key] = val
|
|
||||||
return translations
|
|
||||||
|
|
||||||
parsed_data = {}
|
|
||||||
all_valid = True
|
|
||||||
|
|
||||||
for lang in languages:
|
|
||||||
filepath = os.path.join(local_dir, f"{lang}.dart")
|
|
||||||
trans = parse_dart_map(filepath)
|
|
||||||
if trans is None:
|
|
||||||
all_valid = False
|
|
||||||
continue
|
|
||||||
parsed_data[lang] = trans
|
|
||||||
print(f"Verified {lang}.dart: parsed {len(trans)} entries.")
|
|
||||||
if len(trans) != 2660:
|
|
||||||
print(f" ERROR: Expected 2660 entries, got {len(trans)}")
|
|
||||||
all_valid = False
|
|
||||||
|
|
||||||
if not all_valid:
|
|
||||||
print("Verification FAILED on basic counts.")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
# Check that key sets are identical
|
|
||||||
ref_lang = languages[0]
|
|
||||||
ref_keys = set(parsed_data[ref_lang].keys())
|
|
||||||
|
|
||||||
for lang in languages[1:]:
|
|
||||||
keys = set(parsed_data[lang].keys())
|
|
||||||
if keys != ref_keys:
|
|
||||||
print(f"ERROR: Key sets differ between {ref_lang} and {lang}!")
|
|
||||||
print(f" Keys in {ref_lang} not in {lang}: {len(ref_keys - keys)}")
|
|
||||||
print(f" Keys in {lang} not in {ref_lang}: {len(keys - ref_keys)}")
|
|
||||||
all_valid = False
|
|
||||||
|
|
||||||
# Check for escaping errors (e.g. unescaped dollar signs in double-quoted strings in the Dart source code)
|
|
||||||
# In the raw file content, any dollar sign must be preceded by a backslash unless it is already escaped.
|
|
||||||
# Let's inspect the files directly for raw '$' characters that are not preceded by '\'
|
|
||||||
dollar_pattern = re.compile(r'(?<!\\)\$')
|
|
||||||
|
|
||||||
for lang in languages:
|
|
||||||
filepath = os.path.join(local_dir, f"{lang}.dart")
|
|
||||||
with open(filepath, 'r', encoding='utf-8') as f:
|
|
||||||
lines = f.readlines()
|
|
||||||
for idx, line in enumerate(lines):
|
|
||||||
# We search inside map entries
|
|
||||||
if ":" in line:
|
|
||||||
# check for unescaped dollar signs
|
|
||||||
# A dollar sign not preceded by a backslash is a compilation error in Dart double-quoted strings
|
|
||||||
# unless it's single quotes or some specific construct, but we used double quotes for all lines.
|
|
||||||
unescaped_dollars = dollar_pattern.findall(line)
|
|
||||||
if unescaped_dollars:
|
|
||||||
print(f"ERROR: Unescaped dollar sign in {filepath} line {idx+1}:")
|
|
||||||
print(f" {line.strip()}")
|
|
||||||
all_valid = False
|
|
||||||
|
|
||||||
if all_valid:
|
|
||||||
print("\nSUCCESS: All files verified! They have identical keys (2660 keys) and correct escaping.")
|
|
||||||
else:
|
|
||||||
print("\nVerification FAILED.")
|
|
||||||
exit(1)
|
|
||||||