🚀 محاكاة نظام Siro الكاملة
جميع الإضافات والتغييرات التي تم العمل عليها بتاريخ 2026-06-21
⏰
المرحلة الأولى: Cron Job يولد مهام تسعير المنافسين
backend/bot/generate_price_tasks.php
كل 15 دقيقة
|
المناطق: 10 مناطق في دمشق
|
المنافسون: YallaGo • Zaken • Tfadal
1
الاتصال بقاعدة البيانات و Redis
يتم تحميل boostrap.php لإنشاء اتصال MySQL و Redis
2
إنشاء جدول competitor_prices إن لم يكن موجوداً
CREATE TABLE IF NOT EXISTS competitor_prices (
id INT AUTO_INCREMENT PRIMARY KEY,
competitor_name VARCHAR(50),
from_latitude VARCHAR(30), from_longitude VARCHAR(30),
to_latitude VARCHAR(30), to_longitude VARCHAR(30),
distance_km DECIMAL(8,2), total_price DECIMAL(10,2),
price_per_km DECIMAL(8,2), country_code VARCHAR(5) DEFAULT 'SY',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
3
توليد نقاط عشوائية لـ 10 مناطق رئيسية في دمشق
ساحة الأمويين
المزة
المالكي
كفرسوسة
الميدان
باب توما
ركن الدين
دمر
برامكة
المهاجرين
لكل منطقة: نقطة بداية عشوائية ضمن 2 كم + رحلة قصيرة (2-5 كم) + رحلة طويلة (10-15 كم)
4
إدراج المهام في Redis Queue
استخدام LPUSH إلى queue:bot:tasks
// 10 مناطق × رحلتين × 3 منافسين = 60 مهمة كل 15 دقيقة
$redis->lpush('queue:bot:tasks', json_encode($taskData));
echo "Successfully generated and queued $tasksCreated pricing tasks.";
🤖
المرحلة الثانية: Android Bot يسحب المهام وينفذها
android_bot/
آلية السحب: Polling كل 15 ثانية
|
الأجهزة المسجلة: SHAM_CASH_BOT_01 • PRICE_SCRAPER_BOT_01
1
WorkerClient.kt — التوقيع HMAC-SHA256
fun generateSignature(deviceId: String, ts: Long): String {
val message = "$deviceId$ts"
val algorithm = "HmacSHA256"
val mac = Mac.getInstance(algorithm)
val secretKeySpec = SecretKeySpec(SECRET_KEY.toByteArray(), algorithm)
mac.init(secretKeySpec)
val hashBytes = mac.doFinal(message.toByteArray())
return hashBytes.joinToString("") { "%02x".format(it) }
}
2
إرسال GET إلى standalone_worker.php
GET /standalone_worker.php?device_id=ANDROID_ID&ts=1718970000&sig=abc123...
→ Response (JSON):
{
"status": "success",
"has_task": true,
"task": {
"task_id": "prc_667b8e2f",
"type": "price_check",
"app": "com.zakinn.app",
"payload": {
"start_lat": 33.5138, "start_lng": 36.2765,
"end_lat": 33.5350, "end_lng": 36.2950
}
}
}
3
ScraperAccessibilityService.kt — نقر آلي
آلة حالة متكاملة لتطبيقات المنافسين:
IDLE → LAUNCHING_APP → SEARCHING_START → SEARCHING_END → READING_PRICE → SUBMITTING
YallaGo البحث عن "Where to" أو "أين تريد الذهاب" والنقر عليه
Zakinn استخدام findAccessibilityNodeInfosByViewId للـ TextInput
Tfadal البحث بـ 7 لغات مختلفة (AR/EN/TR) عن حقول الإدخال
4
قراءة السعر وإرسال النتيجة
// قراءة السعر من النصوص التي تحتوي على SYP, ل.س, AED, SP
searchPriceByCurrency(node) → "ل.س 12,500"
→ submitPriceToServer → POST /standalone_worker.php
{
"device_id": "...", "ts": 1718970000, "sig": "...",
"task_id": "prc_667b8e2f", "type": "price_check",
"status": "success",
"result_data": {
"app": "com.zakinn.app",
"distance_km": 4.8,
"price": 12500,
"start_lat": 33.5138, "start_lng": 36.2765,
"end_lat": 33.5350, "end_lng": 36.2950
}
}
⚙️
المرحلة الثالثة: Worker يستقبل النتائج ويخزنها
backend/bot/worker.php
1
استقبال POST مع التحقق من HMAC-SHA256
// التحقق من التوقيع + منع Replay Attacks (صلاحية 5 دقائق)
if (abs(time() - $ts) > 300) → رفض الطلب
$expected_sig = hash_hmac('sha256', $device_id . $ts, $SECRET_KEY);
hash_equals($expected_sig, $sig) → تحقق آمن من التوقيع
2
تخزين السعر في MySQL + Redis
// MySQL: حفظ البيانات للتقارير اللاحقة
$stmt = $con->prepare("INSERT INTO competitor_prices (...) VALUES (...?)");
$stmt->execute([$app_name, $start_lat, $start_lng, $end_lat, $end_lng, $distance_km, $price, $pricePerKm, $country_code]);
// Redis: حفظ آخر 50 سعر لكل تطبيق للتسعير الديناميكي
$redis->lpush("competitor:price_history:$app_name", $pricePerKm);
$redis->ltrim("competitor:price_history:$app_name", 0, 49);
📊
المرحلة الرابعة: Standalone Worker Dashboard (واجهة تحكم)
standalone_worker.php
1
واجهة مدير متكاملة (HTML/CSS)
نظام ملفات JSON (tasks.json / results.json) — بدون حاجة لقاعدة بيانات
قائمة المهام المعلقة
سجل النتائج المنجزة
نموذج إضافة مهمة يدوية
2
عينة من البيانات المعروضة
| # | التطبيق | المسار | السعر | الحالة |
| 1 | YallaGo | المزة → مطار دمشق | 12,500 SYP | ✅ نجاح |
| 2 | Zakinn | ساحة الأمويين → دمر | 8,200 SYP | ✅ نجاح |
| 3 | Tfadal | المالكي → كفرسوسة | — | ❌ فشل |
| 4 | YallaGo | برامكة → المهاجرين | 15,000 SYP | ✅ نجاح |
| 5 | Zakinn | الميدان → باب توما | 6,750 SYP | ✅ نجاح |
🧠
المرحلة الخامسة: نظام التسويق الذكي بالذكاء الاصطناعي (Gemini AI)
SiroGeminiService.php + trigger_campaign.php
1
المدير يضغط "إطلاق حملة استعادة ذكية فوراً"
من siro_admin → Marketing Page
// Flutter Controller: marketing_controller.dart
Future triggerAICampaign() async {
var res = await CRUD().post(link: AppLink.triggerCampaign, payload: params);
// → POST /Admin/marketing/trigger_campaign.php
}
2
PHP يسحب آخر أسعار المنافسين ويرسلها إلى Gemini AI
$sqlPrices = "SELECT competitor_name, total_price, distance_km
FROM competitor_prices WHERE country_code = :country
ORDER BY created_at DESC LIMIT 10";
// البيانات تسحب من جدول competitor_prices الذي ملأه البوت!
$geminiService = new SiroGeminiService();
$aiCampaign = $geminiService->analyzeMarketAndDraftCampaign(
$competitorPrices, $siroBasePrice, $regionName, $countryCode
);
3
Gemini AI يحلل ويكتب حملة تسويقية كاملة
// SiroGeminiService.php — إرسال prompt إلى Gemini API
$prompt = "
أنت خبير تسويق ذكي لتطبيق Siro...
1. أسعار المنافسين: " . json_encode($competitorPrices) . "
2. سعر Siro الأساسي: 10000 SYP
الخرج المطلوب JSON:
{
\"opportunity_detected\": true,
\"recommended_price\": 8500,
\"discount_percentage\": 15,
\"promo_code\": \"SIRODM15\",
\"push_title\": \"🔥 وفر 15% على رحلتك!\",
\"push_body\": \"خصم خاص لسكان دمشق! استخدم كود SIRODM15\",
\"sms_body\": \"اشتقنا لك يا ${passenger_name}! عد إلينا ووفر 15% مع كود SIRODM15\"
}"
4
إرسال الإشعارات والحملات الترويجية
FCM Push للمستخدمين النشطين (بدون حدود سبام)
WhatsApp للمستخدمين المنقطعين (مع anti-spam 24 ساعة)
SMS كخيار احتياطي إذا فشل WhatsApp
// trigger_campaign.php
foreach ($targets as $target) {
if ($fcmToken) {
sendFcmNotification($fcmToken, $pushTitle, $pushBody, $fcmData);
$sentFcm++;
} else {
if ($spamCount === 0) { // anti-spam
sendWhatsAppFromServer($decryptedPhone, $smsBody);
$sentWhatsApp++;
}
}
}
5
تسجيل الحملة في سجل التدقيق
// Audit Log
logAudit($con, $user_id, 'trigger_marketing_campaign', 'promos', $promoCode, [
'promo_code' => $promoCode,
'targets_count' => count($dispatchedPassengers)
]);
// Response للمدير:
{
"campaign_created": true,
"promo_code": "SIRODM15",
"push_notification": { "sent_count": 34 },
"whatsapp_sms": { "whatsapp_sent_count": 12, "sms_sent_count": 5 },
"total_dispatched": 51
}
💰
المرحلة السادسة: محرك التسعير الديناميكي يستخدم بيانات المنافسين
backend/ride/pricing/get.php
1
حساب السعر مع الـ Surge Multiplier من Redis
// قراءة الطلب (demand) من Redis الرئيسي
$demandCount = (int)$redis->get("demand:grid:" . $grid_id);
// قراءة السائقين المتاحين من Redis الموقع
$drivers = $redisLocation->georadius('geo:drivers:available', $lng, $lat, 0.75, 'km');
if ($demandCount > 0 && $availableDrivers > 0) {
$surgeRatio = $demandCount / $availableDrivers;
if ($surgeRatio > 1.2) {
$surgeMultiplier = 1.0 + ($surgeRatio - 1.2) * 0.5; // Capped at 3.0
}
}
2
تطبيق التسعير التنافسي (Competitor Undercut — أقل بـ 8%)
// البحث عن أسعار منافسين لنفس المنطقة الجغرافية
SELECT total_price, distance_km FROM competitor_prices
WHERE country_code = 'SY'
AND (from_latitude + 0.0) BETWEEN :min_flat AND :max_flat
AND created_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
// إذا وجدنا تطابق → نخفض سعرنا ليكون أقل من المنافس بـ 8%
if ($competitorTarget !== null) {
$undercutPrice = $competitorTarget * 0.92; // أقل بــ 8% 🎯
if ($price > $targetAdjustedPrice) {
$price = $targetAdjustedPrice; // تطبيق السعر التنافسي
}
}
3
تطبيق الخصم (Promo Code) + الديون السابقة + التوقيع المشفر
// التحقق من صلاحية الكود الترويجي
$sqlPromo = "SELECT amount FROM promos WHERE promo_code = :code AND ...";
$discount = (float) $promoData['amount'];
// إضافة الديون السابقة
$redisDebt = $redisInstance->get("passenger_debt_" . $passenger_id);
$finalPrice += (float) $redisDebt;
// توقيع السعر بشكل مشفر لمنع التلاعب
$priceToken = $encryptionHelper->encryptData(json_encode([
'passenger_id' => $passenger_id,
'distance' => $distance, 'duration' => $duration,
'expires' => time() + 420, // 7 دقائق فقط
'prices' => $pricesRaw
]));
🔌
المرحلة السابعة: WebSocket — الاتصال المباشر مع السائقين
socket_intaleq/driver_socket.php
🚀 المستوى الثاني (Level 2 Architecture)
|
بورت 2020 WebSocket
|
بورت 2021 HTTP Internal
1
اتصال السائق بالـ Socket
// siro_driver → background_service.dart → Socket.IO
socket = IO.io(AppLink.locationSocketUrl, OptionBuilder()
.setQuery({'driver_id': driverId, 'token': token}));
// server side: driver_socket.php
$socket->join('driver_' . $driverId);
$connectedDrivers[$driverId] = ['conn' => $socket, 'platform' => $platform, 'token' => $token];
2
تحديث الموقع مع Redis Pipeline Buffering (Level 2)
// السائق يرسل موقعه ← يتم تجميع الأحداث كل 500ms
$socket->on('update_location', function($data) use (&$eventBuffer) {
// حساب التغيير الفعال (تجنب عمليات Redis غير الضرورية)
if (!$didMove && !$speedChanged && !$headingChanged && !$statusChanged) return;
// التخزين المؤقت → Redis Pipeline
$eventBuffer[$driverId] = [
'hmset' => ['heading' => $heading, 'speed' => $speed, 'status' => $status],
'geoadd' => ['status' => $status, 'lng' => $lng, 'lat' => $lat],
'status_change' => ['old' => $oldStatus, 'new' => $newStatus]
];
});
// Timer كل 500ms: تنفيذ Pipeline
Timer::add(0.5, function() {
$pipe = $redis->pipeline();
foreach ($eventBuffer as $driverId => $ops) { /* تنفيذ مجمع */ }
$pipe->execute();
$eventBuffer = [];
});
تحسين أداء بدلاً من 3 عمليات Redis لكل تحديث → عملية واحدة كل 500ms لكل السائقين
3
إرسال الطلبات الجديدة (Dispatch + Market)
// HTTP Internal → dispatch_order
$io->to('driver_' . $driverId)->emit('new_ride_request', $payload);
if ($platform === 'ios') sendFCM_Async($token, 'طلب جديد', 'لديك رحلة جديدة');
// Market New Ride
$redis->geoadd('geo:rides:waiting', $lng, $lat, $rideId);
$nearbyDrivers = $redis->georadius('geo:drivers:available', $lng, $lat, 50, 'km');
foreach ($nearbyDrivers as $driverId) {
$io->to('driver_' . $driverId)->emit('market_new_ride', $payload);
}
4
تحديث موقع السائق إلى الراكب (Forward to Passenger Socket)
// Throttle: إرسال الموقع للراكب فقط إذا تحرك >15 متر أو مر >3 ثواني
function forwardLocationToPassengerSocket(...) {
if ($dist < FORWARD_MIN_METERS && $timeDiff < FORWARD_MAX_SECONDS) return;
$http = new AsyncHttp();
$http->request($passengerSocketUrl, ['method' => 'POST', 'data' => $payload,
'headers' => ['x-internal-key' => $internalKey]]);
}
📍
المرحلة الثامنة: تطبيق السائق — الوجهة المقترحة والخلفية
siro_driver/
1
DestinationController — إدارة الوجهة
// حفظ الوجهة (حد أقصى مرتين في اليوم)
Future saveDestination(LatLng position, String name) async {
final response = await CRUD().post(link: AppLink.saveDriverDestination, payload: {
'action': 'set',
'destination_lat': position.latitude.toString(),
'destination_lng': position.longitude.toString(),
'destination_name': name,
});
// تحقق من رسالة "الحد الأقصى لتعديل الوجهة"
if (msg.contains("الحد الأقصى") || msg.contains("limit")) {
mySnackbarWarning('You have reached the daily limit');
}
}
// جلب الوجهة الحالية + مسحها
fetchActiveDestination() / clearDestination()
2
Background Service — استقبال الطلبات في الخلفية
// Socket في الخلفية ← عند وصول new_ride_request
socket.on('new_ride_request', (data) async {
if (isAppInForeground || overlayActive) return; // لا نكرر
// أندرويد: نعرض Overlay فوق أي تطبيق
await FlutterOverlayWindow.showOverlay(
overlayTitle: "طلب جديد 🚖",
overlayContent: "لديك طلب رحلة جديد!",
flag: OverlayFlag.focusPointer,
);
// iOS: نعرض Local Notification
flutterLocalNotificationsPlugin.show(1002, "طلب رحلة جديد 🚖", ...);
});
📱
المرحلة التاسعة: Admin App — لوحة التسويق الذكي
siro_admin/
1
MarketingController — التحكم بالأسواق والحملات
يدير كل من:
Anomalies
Campaigns Log
Telemetry
Price Comparison
What-If Simulator
// دوال رئيسية:
fetchAnomalies() // شواذ الأسعار
fetchCampaignsLog() // سجل الحملات
fetchTelemetry() // استهلاك API والتكاليف
fetchPriceComparison() // مقارنة الأسعار + PCI
fetchPriceGapHeatmap() // خارطة الفجوات السعرية
fetchMarketShareAnalytics() // تطور الحصة السوقية
fetchAiPricePrediction() // توقعات AI
fetchWinbackTargets() // أهداف الاستعادة
triggerAICampaign() // إطلاق حملة AI
runWhatIfSimulation(price) // محاكي تغيير الأسعار
2
واجهة MarketingPage متكاملة بـ 3 تبويبات
التبويب 1: شواذ الأسعار والمنافسين
- بطاقة التحكم بالـ AI (Gemini)
- توقعات الذكاء الاصطناعي (Siro AI Prediction)
- محاكي تغيير الأسعار الذكي (What-If Simulator)
- رسم بياني لتطور الحصة السوقية (آخر 12 أسبوع)
- رسم بياني لمقارنة تقلبات الأسعار اللحظية
- خارطة الفجوات ومؤشر التنافسية السعري (PCI)
- أهداف استعادة العملاء (Win-Back)
التبويب 2: سجل الحملات المنجزة
- عرض الحملات المرسلة (Push / WhatsApp / SMS)
التبويب 3: إعدادات الأتمتة والتحكم
- مراقب استهلاك الرموز API Telemetry
- تفعيل/تعطيل الـ Autopilot
- تعديل System Prompt للذكاء الاصطناعي
3
What-If Simulator — محاكي السيناريوهات
// مثلاً: المدير يقترح سعر 8500 لكل كم
POST /Admin/marketing/what_if_simulator.php?speed_price=8500&country_code=SY
→ Response:
{
"simulated_pci": 0.89,
"market_share_percent": 72.5,
"recommendation_status": "success",
"recommendation_message": "✅ السعر المقترح 8500 SYP/كم سيجعلنا أرخص من جميع المنافسين!"
}
🗣️
المرحلة العاشرة: تطبيق الراكب — الملاحة والـ TTS
siro_rider/
1
NavigationView + NavigationController — الملاحة
واجهة ملاحة كاملة مع: معلومات المسار، وقت الوصول، المسافة المتبقية
2
TTS (Text-to-Speech) Controller
تحويل إرشادات الملاحة إلى صوت بالعربية — إعلانات صوتية للمنعطفات
// siro_rider/lib/controller/functions/tts.dart
class TextToSpeechController extends GetxController {
Future speakText(String text) async {
await flutterTts.setLanguage("ar-SA");
await flutterTts.setSpeechRate(0.5);
await flutterTts.speak(text);
}
}
🔁
مخطط تدفق البيانات الكامل — دورة متكاملة
⏰ Cron Job (15 دقيقة)
↓ يولد
📋 60 مهمة تسعير → Redis Queue
↓ يسحب
🤖 Android Bot (Accessibility Service)
↓ يفتح التطبيق وينقر آلياً ويقرأ
📱 YallaGo • Zakinn • Tfadal
↓ يرسل النتائج
📊 Worker → MySQL (competitor_prices) + Redis
↓ يستخدم في
💰 محرك التسعير الديناميكي (Undercut 8%)
↓ ويستخدم في
🧠 Gemini AI Campaign Generator
↓ يرسل
📣 FCM Push + WhatsApp + SMS → الركاب
↓ وأيضاً
📊 Admin Dashboard يعرض التحليلات
📁
هيكلية الملفات المضافة والمعدلة اليوم
📱 siro_driver/
├── lib/constant/links.dart
├── lib/controller/functions/background_service.dart
├── lib/controller/functions/location_controller.dart
├── lib/controller/home/captin/
│ ├── destination_controller.dart
│ ├── home_captain_controller.dart
│ └── order_request_controller.dart
├── lib/controller/local/ar_eg.dart
├── lib/controller/local/ar_jo.dart
├── lib/controller/local/ar_sy.dart
├── lib/controller/local/en.dart
├── lib/views/home/Captin/home_captain/
│ ├── home_captin.dart
│ └── widget/destination_bottom_sheet.dart
└── lib/views/home/Captin/mapDriverWidgets/passenger_info_window.dart
⚙️ backend/
├── bot/
│ ├── generate_price_tasks.php (Cron Job)
│ ├── worker.php (Redis Worker Endpoint)
│ └── standalone_worker.php (Dashboard)
├── core/Services/SiroGeminiService.php
├── Admin/marketing/
│ ├── trigger_campaign.php
│ ├── get_price_comparison.php
│ ├── get_market_anomalies.php
│ ├── get_telemetry.php
│ └── get_campaigns_log.php
├── ride/pricing/get.php
├── ride/location/save_driver_destination.php
└── ride/rides/add_ride.php, acceptRide.php, cancel*.php
🤖 android_bot/
├── service/ScraperAccessibilityService.kt
├── service/AppLauncher.kt
├── network/WorkerClient.kt
└── MainActivity.kt
✅
الخلاصة — ماذا أنجزنا اليوم؟
مكتمل Android Bot — نقر آلي ذكي (Accessibility Service) مع آلة حالة متكاملة لـ 3 تطبيقات منافسة
مكتمل Cron Job — توليد 60 مهمة تسعير كل 15 دقيقة لـ 10 مناطق في دمشق
مكتمل Worker Endpoint — استقبال نتائج البوت مع HMAC Authentication + MySQL/Redis
مكتمل Gemini AI — خدمة تحليل أسعار وصياغة حملات تسويقية بالعربية (لهجات محلية)
مكتمل Marketing Campaign — إطلاق حملات عبر FCM + WhatsApp + SMS مع Anti-Spam
مكتمل Pricing Engine — تسعير ديناميكي مع Undercut 8% عن المنافسين + Surge Pricing
مكتمل WebSocket Level 2 — Redis Pipeline Buffering كل 500ms + Forward للموقع
مكتمل Destination System — وجهة السائق مع حد يومي + خلفية مع Overlay للطلبات
مكتمل Admin Dashboard — لوحة تسويق ذكية مع PCI, Heatmap, What-If Simulator, Telemetry
مكتمل Standalone Dashboard — واجهة تحكم كاملة للبوت بدون حاجة Redis/MySQL