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

This commit is contained in:
Hamza-Ayed
2026-07-14 18:45:29 +03:00
parent 540ae4d4bc
commit 48382f5d4a
60 changed files with 2106 additions and 657 deletions
@@ -0,0 +1,434 @@
# Siro Pricing Engine — Architecture & Deployment Guide
<div dir="rtl">
## 1. نظرة عامة على المنظومة
```
┌─────────────────────────────────────────────────────────────────────┐
│ Siro PRICING ECOSYSTEM │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────┐ ┌──────────────────────────────┐ │
│ │ Android Bot Scraper │ │ Node.js Pricing Engine │ │
│ │ (Java/Kotlin) │─────▶│ (TypeScript) │ │
│ │ يرسخن أسعار │ │ تحليل إحصائي متقدم │ │
│ │ TaxiF, Careem, Uber │ │ ┌────────────────────────┐ │ │
│ │ Jeeny... │ │ │ MAD Outlier Detection │ │ │
│ └──────────┬───────────┘ │ │ K-Means Tier Clustering│ │ │
│ │ │ │ Ridge Regression (MLR) │ │ │
│ ▼ │ │ Min Fare Detection │ │ │
│ ┌──────────────────────┐ │ │ Surge Analysis │ │ │
│ │ MySQL: │ │ │ Zone Pricing │ │ │
│ │ scraped_competitor_ │◀─────│ └────────────────────────┘ │ │
│ │ prices │ └──────────────┬───────────────┘ │
│ └──────────────────────┘ │ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────────────┐ ┌──────────────────────────────┐ │
│ │ MySQL: │ │ MySQL: │ │
│ │ competitor_secret_ │ │ competitor_surge_insights │ │
│ │ formulas │ │ (ساعات الذروة + المضاعف) │ │
│ │ (معادلات المنافسين) │ └──────────────┬───────────────┘ │
│ └──────────┬───────────┘ │ │
│ │ │ │
│ ▼ ▼ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ PHP Cron Jobs (Backend) │ │
│ │ │ │
│ │ cron_ai_engine.php: يقرأ المعادلات ويحدث kazan │ │
│ │ cron_kazan_adjuster: يقرأ surge ويضبط العمولة │ │
│ │ cron_gemini_advisor: يرسل المعادلات لـ Gemini لتقارير │ │
│ └────────────────────────┬───────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Redis Cache Layer │ │
│ │ │ │
│ │ surge:opportunities → مضاعف Surge المقترح │ │
│ │ surge:opportunities:{JO} → لكل دولة │ │
│ │ siro:cache:pricing:grids → أسعار حسب Grid 2.5km │ │
│ └────────────────────────┬───────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Real-time APIs (Rider & Driver Apps) │ │
│ │ │ │
│ │ ride/pricing/get.php: حساب السعر الفوري للراكب │ │
│ │ ride/heatmap/: خريطة حرارية للسائق │ │
│ │ api/ride/competitor: مقارنة أسعار المنافسين │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
```
---
## 2. Deployment: Node.js إلى جانب PHP
### المشكلة
النظام الحالي PHP على Apache/Nginx. نحتاج Node.js للتشغيل جنباً إلى جنب.
### الحل: PM2 Process Manager
```bash
# 1. تثبيت Node.js على السيرفر (مرة واحدة)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs
# 2. رفع مجلد pricing-engine إلى السيرفر
# (scp أو git pull)
# 3. تثبيت PM2 (مدير عمليات Node.js)
npm install -g pm2
# 4. تثبيت dependencies
cd /var/www/siro/backend/pricing-engine
npm install
cp .env.example .env
# عدّل .env ببيانات MySQL + Redis
# 5. تشغيل الخدمات مع PM2
pm2 start ecosystem.config.js
pm2 save
pm2 startup # عشان يشتغل تلقائياً بعد reboot
```
### ملف PM2 Ecosystem
```javascript
// backend/pricing-engine/ecosystem.config.js
module.exports = {
apps: [
{
name: 'siro-pricing-hourly',
script: 'dist/index.js',
args: '--mode=surge --hours=3',
cron_restart: '0 * * * *', // كل ساعة
autorestart: false,
time: true,
},
{
name: 'siro-pricing-daily',
script: 'dist/index.js',
args: '--mode=full --hours=72',
cron_restart: '0 6 * * *', // كل يوم 6 صباحاً
autorestart: false,
time: true,
},
{
name: 'siro-pricing-weekly',
script: 'dist/index.js',
args: '--mode=report --hours=168',
cron_restart: '0 8 * * 1', // كل أسبوع الإثنين 8 صباحاً
autorestart: false,
time: true,
},
],
};
```
> PM2 يتولى تشغيل cron jobs بدون الحاجة إلى `crontab` نظامي.
> لكنه `autorestart: false` لأنها عمليات لمرة واحدة، مو servers.
### بديل: Crontab عادي (أبسط)
```bash
# crontab -e
0 * * * * cd /var/www/siro/backend/pricing-engine && node dist/index.js --mode=surge --hours=3 >> /var/log/siro-pricing.log 2>&1
0 6 * * * cd /var/www/siro/backend/pricing-engine && node dist/index.js --mode=full --hours=72 >> /var/log/siro-pricing.log 2>&1
0 8 * * 1 cd /var/www/siro/backend/pricing-engine && node dist/index.js --mode=report --hours=168 >> /var/log/siro-pricing.log 2>&1
```
---
## 3. دفق التسعير الكامل (Full Pricing Flow)
### 3.1 تحليل المنافسين ← حفظ المعادلات
```
Pricing Engine (Node.js)
│
├─ 1. يسحب بيانات من scraped_competitor_prices
├─ 2. ينظف الشواذ (MAD)
├─ 3. يصنّف الفئات (K-Means) → Economy / Standard / Premium
├─ 4. يحسب الانحدار لكل فئة:
│ price = baseFare + kmRate×dist + minRate×duration
├─ 5. يكتشف Minimum Fare
├─ 6. يحلل Surge حسب الساعة
└─ 7. يحفظ في:
├─ competitor_secret_formulas (معادلات لكل tier)
└─ competitor_surge_insights (ساعات الذروة)
```
### 3.2 PHP يقرأ ويطبّق التسعير
```
cron_ai_engine.php (PHP, كل 30-60 دقيقة)
│
├─ 1. يقرأ competitor_secret_formulas
├─ 2. يختار Economy tier (الأرخص)
├─ 3. يطبّق خصم 6.5%:
│ Siro_kmRate = competitor_kmRate × 0.935
├─ 4. يحدّث جدول kazan
└─ 5. يحفظ surge في Redis
```
### 3.3 حساب السعر للتطبيقات
```
ride/pricing/get.php (API, يتم استدعاؤه عند طلب رحلة)
│
├─ 1. يقرأ kazan table (آخر تحديث من cron_ai_engine)
├─ 2. يحسب:
│ basePrice = kazan.baseFare
│ + kazan.speedPrice × distance
│ + kazan.normalMinPrice × duration
├─ 3. يقرأ Redis surge:opportunities
├─ 4. يطبّق surge multiplier إذا كانت ساعة ذروة
└─ 5. يرجع السعر النهائي للتطبيق
```
---
## 4. تقسيم المناطق (Zone-Based Pricing)
### 4.1 تصنيف المناطق
```
Amman مقسمة حسب البعد عن المركز (31.95, 35.90):
Centre (مركز البلد) → نصف قطر < 2.5km → PPK 0.25-0.33
Mid (وسط) → نصف قطر < 5km → PPK 0.35-0.45
Suburb (ضواحي) → نصف قطر < 10km → PPK 0.40-0.50
Outskirts (أطراف) → > 10km → PPK 0.40-0.60
```
### 4.2 كيف نطبّق Zone-Based Pricing؟
بدلاً من معادلة تسعير واحدة لكل البلد، يصبح:
```sql
-- جدول zone_pricing (جديد)
CREATE TABLE IF NOT EXISTS `zone_pricing` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`country_code` VARCHAR(5) NOT NULL,
`zone_type` VARCHAR(20) NOT NULL, -- centre, mid, suburb, outskirts
`km_rate` DECIMAL(8,3) NOT NULL,
`min_rate` DECIMAL(8,3) NOT NULL DEFAULT 0,
`base_fare` DECIMAL(8,3) NOT NULL DEFAULT 0,
`min_fare` DECIMAL(8,3) NOT NULL DEFAULT 0,
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY `idx_country_zone` (`country_code`, `zone_type`)
);
-- يتم ملؤها من تحليل Pricing Engine
```
ثم في `ride/pricing/get.php`:
```php
// 1. تحديد منطقة البداية
$zoneType = classifyZone($startLat, $startLng); // centre | mid | suburb | outskirts
// 2. استخدام تسعير المنطقة
$zoneRate = getZonePricing($country, $zoneType);
$price = $zoneRate['base_fare']
+ $zoneRate['km_rate'] * $distance
+ $zoneRate['min_rate'] * $duration;
// 3. تطبيق Surge حسب المنطقة
$surge = getSurgeForZone($country, $zoneType);
$finalPrice = $price * $surge;
```
### 4.3 إشعارات المناطق للسائقين
عند دخول سائق إلى منطقة ذات Surge عالي:
```php
// cron_notify_drivers_zones.php (جديد - كل 5 دقائق)
$hotZones = getHotZones(); // من Redis surge:opportunities أو تحليل الـ Pricing Engine
foreach ($hotZones as $zone) {
// إرسال FCM notification للسائقين القريبين
sendPushToNearbyDrivers($zone['lat'], $zone['lng'], [
'title' => '⚠️ منطقة طلب مرتفع',
'body' => "منطقة {$zone['name']}: الطلب مرتفع، الأسعار مرتفعة {$zone['surge']}x"
]);
}
```
وللراكب عند فتح التطبيق في منطقة Surge:
```php
// في ride/pricing/get.php
if ($surgeMultiplier > 1.0) {
$response['surge_warning'] = "⚠️ هذه المنطقة تشهد طلباً مرتفعاً، الأسعار أعلى بنسبة "
. round(($surgeMultiplier - 1) * 100) . "%";
}
```
---
## 5. دعم تطبيقات منافسة متعددة
### 5.1 لكل منافس معادلاته الخاصة
```sql
-- competitor_secret_formulas يدعم:
-- competitor_name = 'com.taxif.passenger' | 'com.careem.ae' | 'com.ubercab' | 'com.jeeny.app'
-- لكل منافس 3 tiers (Economy/Standard/Premium)
-- لكل tier معادلة مستقلة
```
### 5.2 مقارنة الأسعار في التطبيق
```php
// api/ride/get_competitor_context.php
$competitors = ['com.taxif.passenger', 'com.careem.ae', 'com.ubercab', 'com.jeeny.app'];
$prices = [];
foreach ($competitors as $comp) {
$formula = getLatestFormula($comp, $country, 'economy');
$estimatedPrice = $formula['base_fare']
+ $formula['price_per_km'] * $requestedDistance
+ $formula['price_per_min'] * $requestedDuration;
$prices[$comp] = [
'name' => getCompetitorDisplayName($comp),
'price' => $estimatedPrice,
'currency' => 'JOD',
];
}
// Siro price (already 6.5% less)
$siroPrice = calculateSiroPrice($request);
$prices['siro'] = [
'name' => 'Siro',
'price' => $siroPrice,
'currency' => 'JOD',
'is_cheapest' => $siroPrice < min(array_column($prices, 'price')),
];
```
### 5.3 تسعير Siro بناءً على المنافس الأقوى
في `cron_ai_engine.php`:
```php
// 1. اجلب معادلات جميع المنافسين للدولة
$competitors = getCompetitorFormulas($country, 'economy');
// 2. احسب السعر المتوقع لكل منافس لرحلة نموذجية (10km, 15min)
$sampleDist = 10;
$sampleDur = 15;
$competitorPrices = [];
foreach ($competitors as $comp) {
$competitorPrices[$comp['competitor_name']] =
$comp['base_fare'] + $comp['price_per_km'] * $sampleDist + $comp['price_per_min'] * $sampleDur;
}
// 3. المنافس الأرخص هو المستهدف
$cheapestCompetitor = array_keys($competitorPrices, min($competitorPrices))[0];
$cheapestPrice = min($competitorPrices);
// 4. سعر Siro = أرخص منافس - 6.5%
$targetSiroPrice = $cheapestPrice * 0.935;
// 5. هندسة عكسية لمعاملات Siro
$ourKmRate = $competitors[$cheapestCompetitor]['price_per_km'] * 0.935;
$ourMinRate = $competitors[$cheapestCompetitor]['price_per_min'] * 0.935;
$ourBaseFare = $competitors[$cheapestCompetitor]['base_fare'] * 0.935;
```
---
## 6. تدفق البيانات من التحليل حتى يشوفها المستخدم
```
الوقت T0: Pricing Engine يشتغل
↓
الوقت T0+5s: يكتب competitor_secret_formulas + competitor_surge_insights
↓
الوقت T0+30m: cron_ai_engine.php (PHP) يقرأ المعادلات ويحدّث kazan
↓
الوقت T0+31m: kazan محدّث بأسعار جديدة (أقل 6.5% من المنافس)
↓
الوقت T0+31m+: rider يطلب رحلة
→ ride/pricing/get.php يقرأ kazan + Redis surge
→ يحسب السعر ← يرجع للراكب
→ السائق يشوف سعر الرحلة
```
**المدة الكاملة من التحليل للمستخدم: ~31 دقيقة** (يمكن تقليلها بتشغيل cron_ai_engine بعد Pricing Engine مباشرة).
---
## 7. متطلبات السيرفر
| المكون | المتطلب |
|---|---|
| Node.js | v18+ (نوصي v20 LTS) |
| PM2 | لإدارة العمليات (اختياري) |
| MySQL | موجود مسبقاً |
| Redis | موجود مسبقاً |
| RAM إضافي | 256MB كافية (التطبيق خفيف) |
| مساحة | 50MB للملفات + node_modules |
### أمان: Node.js ما اله Port
Pricing Engine هو CLI cron job، مش Web Server. ما اله Port مفتوح. يتصل فقط بـ MySQL و Redis داخلياً. **لا يحتاج تعديل Nginx/Apache**.
---
## 8. خطة الرفع (Deployment Checklist)
```bash
□ 1. git pull أحدث كود على السيرفر
□ 2. cd backend/pricing-engine && npm install
□ 3. cp .env.example .env # عدّل بيانات MySQL + Redis
□ 4. mysql -u root siro < migrations/001_add_columns.sql
□ 5. npm run build # compile TypeScript
□ 6. npm run analyze:taxif # اختبار يدوي
□ 7. pm2 start ecosystem.config.js # أو crontab
□ 8. pm2 save && pm2 startup
□ 9. تحقق من cron_ai_engine.php يقرأ المعادلات الجديدة
□ 10. اختبر ride/pricing/get.php مع الراكب
```
---
## 9. إضافة تطبيق منافس جديد
```
□ 1. أضف اسم الحزمة إلى generate_price_tasks.php
(مثلاً: com.newcompetitor.app)
□ 2. انتظر تجميع بيانات كافية (أسبوع scraping)
□ 3. شغّل: npm run analyze -- --competitor=com.newcompetitor.app
□ 4. Pricing Engine سيكتشف الـ Tiers تلقائياً
□ 5. cron_ai_engine.php سيقرأ المعادلات ويطبّق التسعير
□ 6. تلقائياً: مقارنة الأسعار في تطبيق الراكب
```
---
## 10. الخلاصة
| الميزة | الحالة |
|---|---|
| تحليل إحصائي (MAD + Ridge Regression + K-Means) | ✅ تم |
| اكتشاف 3 Tiers تسعيرية | ✅ تم |
| Minimum Fare | ✅ تم |
| اكتشاف Surge حسب ساعة اليوم | ✅ تم |
| تحليل Zone | ✅ تم |
| خصم 6.5% من المنافس | ✅ في cron_ai_engine.php |
| Redis surge للـ get.php | ✅ surge:opportunities |
| PK/FK متوافقة | ✅ تم تحديث schema |
| دعم دول متعددة (JO/SY/EG/IQ) | ✅ Currency-aware |
| دعم منافسين متعددين | ✅ Arrays + foreach |
| Zone-Based Pricing | ⬜ يحتاج إنشاء جدول zone_pricing |
| إشعارات للسائقين بالمناطق الساخنة | ⬜ يحتاج cron_notify_drivers |
| مقارنة أسعار المنافسين في التطبيق | ⬜ يحتاج ربط ride/pricing مع competitor_formulas |
</div>
+99
View File
@@ -0,0 +1,99 @@
<div dir="rtl" align="right">
<h1>تقرير نظام التسعير الشامل</h1>
<h2>1. دورة حياة التسعير: كيف تتم عملية التسعير من البداية للنهاية؟</h2>
نظام التسعير هو نظام ديناميكي وذكي يعتمد على تحليل السوق باستمرار لضمان التنافسية والربحية. تمر العملية بالمراحل التالية:
<br><br>
<b>المرحلة الأولى: جمع البيانات الحية</b><br>
تقوم سكريبتات الجافاسكريبت بالعمل على مدار الساعة لجلب أسعار المنافسين من السوق وحالة الطلب في مناطق مختلفة، ويتم تغذية قاعدة البيانات بهذه الأرقام الأولية.
<br><br>
<b>المرحلة الثانية: تحليل البيانات بالذكاء الاصطناعي</b><br>
يعمل السكريبت المخصص للذكاء الاصطناعي على تحليل البيانات الواردة وفك تشفير معادلات التسعير الخاصة بالمنافسين (سعر الكيلومتر، سعر البداية) ويقوم بتخزين هذه المعادلات.
<br><br>
<b>المرحلة الثالثة: محرك الثبات والاستقرار</b><br>
وهو السكريبت الجديد، ومهمته الأساسية هي منع التذبذب العشوائي لأسعارنا.
<br>
- يقوم بمقارنة السعر الحالي للمنافس مع متوسط السعر في آخر 7 أيام.
<br>
- إذا قام المنافس بتنزيل السعر فجأة، يعتبره النظام عرضاً ترويجياً مؤقتاً ولا يغير سعرنا الأساسي، بل يقترح استخدام أكواد خصم.
<br>
- إذا استمر انخفاض أو ارتفاع السعر لفترة طويلة، يقرر النظام أن هذا تغيير حقيقي في السوق، ويقترح تعديل سعرنا بحد أقصى لضمان الاستقرار.
<br>
- (ملاحظة: هذا المحرك يعمل حالياً في وضع المراقبة ولا يقوم بتغيير الأسعار تلقائياً بل يسجل الاقتراحات).
<br><br>
<b>المرحلة الرابعة: التسعير الموسمي</b><br>
يتدخل سكريبت التسعير الموسمي في أوقات معينة (مثل أوقات الإفطار في رمضان، الأعياد، أو حالات الطقس السيئة) ليقوم برفع السعر تدريجياً وبنسبة مدروسة ليتناسب مع الطلب المتزايد.
<br><br>
<b>المرحلة الخامسة: اقتناص الذروة وتوجيه السائقين</b><br>
- <b>اكتشاف الذروة:</b> يقوم سكريبت الذروة بتحليل الخريطة واكتشاف المناطق التي قام فيها المنافسون برفع أسعارهم فجأة.
<br>
- <b>تحفيز السائقين:</b> بمجرد اكتشاف منطقة ذروة، يتدخل سكريبت العمولة ليقوم بتخفيض عمولة التطبيق على السائقين في تلك المنطقة المحددة، مما يشجع السائقين على التوجه فوراً لهذه المنطقة لتلبية الطلب العالي وضرب المنافسين.
<hr>
<h2>2. تصحيح وقت وظيفة الجدولة الأخيرة</h2>
لقد قمت بإضافة الوظيفة الخاصة بمحرك الثبات والاستقرار في لوحة التحكم بالتوقيت التالي:
</div>
```text
0 0 * * 0
```
<div dir="rtl" align="right">
(وهذا يعني أنه سيعمل مرة واحدة فقط في الأسبوع، يوم الأحد منتصف الليل).
<br><br>
<b>التصحيح المطلوب:</b><br>
بناءً على تصميم الكود، هذا السكريبت يجب أن يراقب الأسعار باستمرار بالتوازي مع محرك الذكاء الاصطناعي. المطور كتب في الكود ملاحظة صريحة أن الجدولة المقترحة هي كل 3 ساعات.
<br><br>
لذلك، يجب عليك حذفه وإضافته مرة أخرى بالتوقيت التالي:
<br>
<b>الدقائق:</b> 0<br>
<b>الساعات:</b> */3<br>
<b>باقي الحقول:</b> *<br>
ليصبح الأمر كالتالي:
</div>
```text
0 */3 * * * /usr/bin/php8.4 /home/intaleqapp-jordan-siro/htdocs/jordan-siro.intaleqapp.com/backend/bot/cron_pricing_stability_engine.php
```
<div dir="rtl" align="right">
<hr>
<h2>3. شرح جدول الوظائف المجدولة بالكامل وتوقيتاتها</h2>
فيما يلي جدول يوضح وظيفة كل ملف والتوقيت الذي يعمل به:
<br><br>
</div>
| التوقيت | الوظيفة |
|---|---|
| `0 */3 * * *` | `cron_ai_engine.php`: تحليل أسعار المنافسين بالذكاء الاصطناعي لاستنتاج معادلاتهم. |
| `0 */3 * * *` | `cron_pricing_stability_engine.php`: (الوقت المقترح) يراقب استقرار الأسعار ويقترح التعديلات دون تذبذب. |
| `0 * * * *` | `cron_seasonal_pricing.php`: يطبق زيادات الأسعار في المناسبات كل ساعة. |
| `*/10 * * * *` | `cron_surge_opportunity.php`: يكتشف مناطق الذروة النشطة بناءً على أسعار المنافسين الحية كل 10 دقائق. |
| `*/5 * * * *` | `cron_kazan_adjuster.php`: يعدّل عمولة التطبيق ويخفضها للسائقين في مناطق الذروة كل 5 دقائق. |
| `*/16 * * * *` | `cron_generate_heatmap_cache.php`: يولد خريطة حرارية لأماكن الطلب للسائقين كل 16 دقيقة. |
| `0 */1 * * *` | `cron_predictive_demand.php`: يتنبأ بأماكن الطلب المستقبلية بناءً على البيانات التاريخية كل ساعة. |
| `0 * * * *` | `cron_empty_results_to_db.php`: ينظف ويسجل نتائج البحث الفارغة لتحليلها لاحقاً كل ساعة. |
| `0 10 * * *` | `cron_passenger_reengagement.php`: يعيد استهداف الركاب الخاملين برسائل أو عروض يومياً الساعة 10 صباحاً. |
| `0 * * * *` | `cron_auto_marketing_pusher.php`: يرسل حملات التسويق الآلية للمستخدمين كل ساعة. |
| `0 0 * * 0` | `cron_weekly_health_report.php`: يرسل تقرير أسبوعي عن صحة وعمل النظام كل أحد في منتصف الليل. |
| `0 */3 * * *` | `telegram_scraper.php`: أداة تسويقية لاستخراج بيانات من المنصات الأخرى كل 3 ساعات. |
| `0 10 * * 0` | `cron_weekly_report.php`: يرسل تقرير أسبوعي إداري أو تسويقي كل أحد الساعة 10 صباحاً. |
| `0 */4 * * *` | `cron_insert_task.php`: يضيف مهام مجدولة للنظام كل 4 ساعات. |
| `*/15 * * * *` | `generate_10_tasks_cli.php`: يولد مهام مصغرة أو وهمية لأغراض الاختبار كل 15 دقيقة. |
<div dir="rtl" align="right">
<hr>
<h2>4. مهام الجافاسكريبت المستمرة</h2>
هذه المهام لا تعمل بنظام الجدولة المتقطعة، بل هي عمليات تعمل دائماً ولا تتوقف أبداً وتدار بواسطة أداة مدير العمليات:
<br><br>
1. <b>التتبع الشامل</b>: مهمته التتبع الشامل والمتواصل لأسعار المنافسين في جميع المناطق طوال الوقت.
<br>
2. <b>اكتشاف الذروة السريع</b>: متخصص في المراقبة السريعة جداً للمناطق لاكتشاف أي ارتفاع مفاجئ فور حدوثه لإرسال البيانات إلى السكريبتات الأخرى.
<br>
3. <b>التقارير الحية</b>: يقوم بمعالجة البيانات وتصدير التقارير الحية للوحة التحكم أولاً بأول.
<br><br>
هذه السكريبتات الثلاثة هي التي تجمع المواد الخام التي تقوم السكريبتات المذكورة في الأعلى بتحليلها واستخدامها لتحديد الأسعار النهائية للتطبيق.
</div>
+46
View File
@@ -0,0 +1,46 @@
# Redis State Cache Plan
## New Redis Keys
- `ride:{id}:state` (Hash) → status, driver_id, passenger_id, carType, updated_at
- `ride:{id}:driver` (Hash) → driver_name, car_model, car_plate, rating, phone (cached)
## Changes Per File
### acceptRide.php
After MySQL lock succeeds:
```php
$redis->hmset("ride:$rideId:state", [
'status' => $status,
'driver_id' => $driverId,
'passenger_id'=> $passengerIdValue,
'carType' => $carType,
'updated_at' => time()
]);
$redis->expire("ride:$rideId:state", 86400);
$redis->hmset("ride:$rideId:driver", $driverInfo);
$redis->expire("ride:$rideId:driver", 86400);
$redis->publish("ride:state_changes", json_encode([
'ride_id' => $rideId, 'status' => 'accepted',
'driver_id' => $driverId, 'passenger_id' => $passengerIdValue
]));
```
### start_ride.php
```php
$redis->hmset("ride:$rideId:state", ['status' => 'Begin', 'updated_at' => time()]);
$con_ride->prepare("UPDATE ride SET status = ?, rideTimeStart = NOW() WHERE id = ?")->execute([$status, $ride_id]);
$redis->publish("ride:state_changes", [...]);
```
### arrive_ride.php, cancel_ride_*.php
Same pattern: Redis update first (or after), then MySQL, then Pub/Sub.
### finish_ride_updates.php
No change to Redis state (keep MySQL transaction as-is).
## Socket Server Changes (loction_server/driver_socket.php)
- Subscribe to Redis `ride:state_changes` channel
- On message: update in-memory state, emit to passenger room
- Read from `ride:{id}:state` hash instead of MySQL queries
@@ -0,0 +1,704 @@
# دراسة نظام أتمتة السوق الذكي - Siro
**التاريخ: 26 يونيو 2026**
**إعداد: فريق التطوير**
---
## فهرس المحتويات
1. [توحيد السناك بار (Snackbar System)](#1-توحيد-السناك-بار-snackbar-system)
2. [نظرة عامة على نظام أتمتة السوق الذكي](#2-نظرة-عامة-على-نظام-أتمتة-السوق-الذكي)
3. [مكونات النظام بالتفصيل](#3-مكونات-النظام-بالتفصيل)
4. [تدفق البيانات (Data Flow)](#4-تدفق-البيانات-data-flow)
5. [قاعدة البيانات وجداولها](#5-قاعدة-البيانات-وجدولها)
6. [خريطة مفاتيح Redis](#6-خريطة-مفاتيح-redis)
7. [الخدمات الخارجية المستخدمة](#7-الخدمات-الخارجية-المستخدمة)
8. [ملفات الخلفية - مراجعة أمنية شاملة](#8-ملفات-الخلفية---مراجعة-أمنية-شاملة)
9. [قائمة الملفات المطلوب حذفها فوراً](#9-قائمة-الملفات-المطلوب-حذفها-فوراً)
10. [ثغرات SQL Injection](#10-ثغرات-sql-injection)
11. [التوصيات النهائية](#11-التوصيات-النهائية)
---
## 1. توحيد السناك بار (Snackbar System)
### الوضع الحالي - 4 تطبيقات و 4 طرق مختلفة
يوجد حاليًا 4 تطبيقات Flutter ولكل منها نظام سناك بار مختلف تمامًا:
---
### 1.1 siro_admin - الإصدار القديم (GetX)
**الملف:** `siro_admin/lib/views/widgets/snackbar.dart`
- يستخدم `Get.snackbar()` حصريًا
- يوجد دالتان فقط: `mySnackeBarError()` و `mySnackbarSuccess()`
- **لا يوجد** `mySnackbarWarning()` ولا `mySnackbarInfo()`
- الألوان: أحمر للخطأ (`AppColor.redColor`)، أخضر للنجاح (`AppColor.greenColor`)
- يستخدم `SnackbarConfig` للثوابت (مدة 3 ثوان، زوايا 12، ظل)
- التوقيع: `SnackbarController mySnackeBarError(String message)`
- النصوص بالإنكليزية: `'Error'.tr`, `'Success'.tr`
- 30+ استخدامًا في التطبيق
### 1.2 siro_service - الإصدار القديم (GetX)
**الملف:** `siro_service/lib/views/widgets/mycircular.dart`
- يستخدم `Get.snackbar()` حصريًا
- يوجد 3 دوال: `mySnackbarError()` و `mySnackbarWarning()` و `mySnackbarSuccess()`
- الألوان: أحمر (`AppColor.redColor`)، أصفر (`AppColor.yellowColor` + نص أسود)، أخضر (`AppColor.greenColor`)
- نفس `SnackbarConfig` للثوابت
- 70+ استخدامًا في التطبيق
### 1.3 siro_driver - الإصدار الحديث (Custom Widget)
**الملف:** `siro_driver/lib/views/widgets/error_snakbar.dart`
- ويج محسّن مخصص مع `_SnackContent` و `AnimationController`
- يوجد 4 دوال: `mySnackbarSuccess()` و `mySnackeBarError()` و `mySnackbarInfo()` و `mySnackbarWarning()`
- **4 متغيرات (variants):** success, error, info, warning
- ألوان: أخضر (`#1A9E5C`)، أحمر (`#D93025`)، أزرق (`#1A73E8`)، برتقالي (`#F29900`)
- ألوان السطح: `#F0FBF5`, `#FEF2F1`, `#F0F6FF`, `#FFF8E6`
- تأثيرات: `ScaleTransition` مع `Curves.elasticOut`، شريط تقدم تنازلي
- إخفاء يدوي مع زر Close + Haptic Feedback
- يتحقق أولاً من `Overlay`، فإن لم يجده يستخدم `ScaffoldMessenger`
- **مشكلة:** يستخدم `Get.snackbar()` الذي يرمي `FlutterError` إذا لم يكن `Overlay` جاهزًا
- 100+ استخدامًا في التطبيق
### 1.4 siro_rider - الإصدار الحديث المحسّن (ScaffoldMessenger)
**الملف:** `siro_rider/lib/views/widgets/error_snakbar.dart`
- نفس تصميم `siro_driver` مع تحسينات جوهرية
- **يستخدم فقط `ScaffoldMessenger`** بدلاً من `Get.snackbar()` (لتجنب أخطاء `Overlay`)
- يحتوي على آلية إعادة محاولة (retry) تصل إلى 3 مرات
- `messenger.clearSnackBars()` قبل العرض (يمنع التراكم)
- يعيد `SnackbarController?` (nullable) لأن `Get.snackbar` لم يعد مستخدمًا
- التوقيع: `SnackbarController? mySnackbarSuccess(String message)` - ملاحظة: الرجوع `?`
- 100+ استخدامًا في التطبيق
### 1.5 دوال Toast البسيطة
- **siro_driver** و **siro_rider** لديهما `lib/controller/functions/toast.dart`
- `Toast.show(BuildContext context, String message, Color color)` - دالة بسيطة جدًا
- تستخدم `ScaffoldMessenger.of(context).showSnackBar()` مع `SnackBar` مادة
- 10+ استخدامات في كل تطبيق
---
### الفروقات بين الإصدارين (القديم والحديث)
| الخاصية | siro_admin (قديم) | siro_driver (حديث) | siro_rider (حديث) | siro_service (قديم) |
|---------|:-----------------:|:------------------:|:-----------------:|:-------------------:|
| عدد الدوال | 2 | 4 | 4 | 3 |
| `mySnackbarWarning` | ❌ | ✅ | ✅ | ✅ |
| `mySnackbarInfo` | ❌ | ✅ | ✅ | ❌ |
| `mySnackbarSuccess` | ✅ | ✅ | ✅ | ✅ |
| `mySnackeBarError` | ✅ | ✅ | ✅ | ✅ |
| آلية العرض | `Get.snackbar()` | `Get.snackbar()` + `ScaffoldMessenger` | `ScaffoldMessenger` فقط | `Get.snackbar()` |
| التصميم | نص فقط | أيقونة + نص + زر إغلاق + شريط تقدم | أيقونة + نص + زر إغلاق + شريط تقدم | نص فقط |
| Retry | ❌ | ❌ | ✅ (3 مرات) | ❌ |
| Null Safety | `SnackbarController` | `SnackbarController` | `SnackbarController?` | `SnackbarController` |
| أخطاء `Overlay` | ✅ (GetX آمن) | ⚠️ (قد يحدث) | ✅ (متفادي) | ✅ (GetX آمن) |
---
### خطة التوحيد المقترحة
#### الهدف: إنشاء package مشترك واحد لجميع التطبيقات الأربعة
**الخطوة 1:** إنشاء مجلد مشترك (shared package) في المسار:
```
siro_admin/lib/shared/widgets/snackbar/
```
**الخطوة 2:** توحيد الواجهة (API) لتصبح:
```dart
// الاستخدام الموحد - نفس التوقيع في كل التطبيقات
void mySnackbarSuccess(String message);
void mySnackbarError(String message);
void mySnackbarWarning(String message);
void mySnackbarInfo(String message);
```
**الخطوة 3:** الاعتماد على `ScaffoldMessenger` فقط (مثل siro_rider) لتجنب مشاكل `Overlay` في GetX.
**الخطوة 4:** توحيد الألوان والثوابت:
| المتغير | اللون الأساسي | لون السطح | الأيقونة |
|---------|:------------:|:---------:|:--------:|
| success | `#1A9E5C` (أخضر) | `#F0FBF5` | `check_circle_rounded` |
| error | `#D93025` (أحمر) | `#FEF2F1` | `error_rounded` |
| info | `#1A73E8` (أزرق) | `#F0F6FF` | `info_rounded` |
| warning | `#F29900` (برتقالي) | `#FFF8E6` | `warning_amber_rounded` |
**الخطوة 5:** تحويل ملفات `toast.dart` في `siro_driver` و `siro_rider` لاستخدام دالة واحدة موحدة بدلاً من التكرار.
**الخطوة 6:** إزالة دوال `Get.snackbar()` المباشرة من جميع ملفات التحكم (controllers) والاستعاضة عنها بالدوال الموحدة.
---
## 2. نظرة عامة على نظام أتمتة السوق الذكي
### ما هو النظام؟
**"أتمتة السوق الذكي"** هو نظام متكامل لذكاء السوق والتسعير الديناميكي في Siro. يقوم النظام بـ:
1. **جمع بيانات المنافسين** تلقائيًا عبر Android Bot
2. **تحليل الفجوات السعرية** بين Siro والمنافسين (YallaGo, Zaken, Tufaddal)
3. **تعديل أسعار Siro تلقائيًا** بناءً على تحليل السوق
4. **كشف فرص رفع الأسعار** (Surge Opportunities) في المناطق التي يرتفع فيها الطلب
5. **توليد حملات تسويقية ذكية** باستخدام AI (Google Gemini)
6. **تقديم تقارير أسبوعية** عن صحة السوق (Market Health Reports)
7. **محاكاة "What-If"** لمعرفة أثر تغيير الأسعار
### طبقات النظام
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ طبقة العرض (Admin Dashboard) │
│ siro_admin → لوحة تحكم المدير → Flutter Web │
│ endpoints: Admin/marketing/*.php │
├─────────────────────────────────────────────────────────────────────────────┤
│ طبقة API (PHP Backend) │
│ cron_jobs → bot/*.php │ pricing → ride/pricing/*.php │
│ heatmap → ride/heatmap/*.php │ marketing → Admin/marketing/*.php │
├─────────────────────────────────────────────────────────────────────────────┤
│ طبقة الذكاء والتحليل │
│ Google Gemini AI │ SiroGeminiService │ Redis Analytics │
├─────────────────────────────────────────────────────────────────────────────┤
│ طبقة جمع البيانات │
│ Android Bot ←→ worker.php ←→ competitor_prices (MySQL) │
│ generate_price_tasks.php (cron) → Redis Queue → Bot │
├─────────────────────────────────────────────────────────────────────────────┤
│ قاعدة البيانات والذاكرة المؤقتة │
│ MySQL (main, tracking, ride) │ Redis (مفاتيح surge, demand) │
└─────────────────────────────────────────────────────────────────────────────┘
```
### الدول المدعومة
| الدولة | رمز البلد | المنطقة الزمنية | عملة |
|:------:|:--------:|:--------------:|:----:|
| سوريا | SY | Asia/Damascus | ل.س |
| الأردن | JO | Asia/Amman | د.أ |
| مصر | EG | Africa/Cairo | ج.م |
| العراق | IQ | Asia/Baghdad | د.ع |
---
## 3. مكونات النظام بالتفصيل
### 3.1 نظام البوت (Bot System) - `backend/bot/`
#### 3.1.1 `generate_price_tasks.php`
- **الجدولة:** كل 15 دقيقة
- **الوظيفة:** يولد مهام فحص أسعار المنافسين ويدفعها إلى Redis Queue
- **آلية العمل:**
- ينشئ جدول `competitor_prices` تلقائيًا إذا لم يكن موجودًا
- يحتوي على 10 مناطق رئيسية في دمشق (ساحة الأمويين، المزة، المالكي، كفرسوسة، الميدان، باب توما، ركن الدين، دمر، برامكة، المهاجرين)
- المنافسون: `['yallago', 'zaken', 'tufaddal']`
- لكل منطقة يولد نقطة انطلاق عشوائية ضمن 2km، ثم رحلة قصيرة (2-5km) وأخرى طويلة (10-15km)
- يضغط المهام في Redis list: `queue:bot:tasks`
- **الملفات المكتوبة:** Redis key `queue:bot:tasks`
- **ملاحظة:** إنشاء الجدول داخل cron job أمر غير محبذ - يجب أن يكون في migration
#### 3.1.2 `worker.php`
- **الوظيفة:** نقطة نهاية API لبوت Android لسحب المهام وإرسال النتائج
- **الأمان:** HMAC-SHA256 مع نافذة 5 دقائق + `BOT_SECRET_KEY` من البيئة
- **الأجهزة المسموحة:** `['SHAM_CASH_BOT_01', 'PRICE_SCRAPER_BOT_01']`
- **GET:** يسحب مهمة من قائمة Redis (`RPOP`)
- **POST:** يستقبل النتيجة:
- `price_check`: يحسب `pricePerKm` ويدرج في جدول `competitor_prices` و Redis `competitor:price_history`
- `payment`: يسجل نجاح الدفع
- `failed`: يسجل الخطأ
- **Redis:** `queue:bot:tasks` (قراءة)، `competitor:price_history:{app}` (كتابة)
- **MySQL:** إدراج في `competitor_prices`
#### 3.1.3 `standalone_worker.php`
- **الوظيفة:** نسخة بديلة كاملة بذاتها بدون Redis أو MySQL - تستخدم ملفات JSON
- **الاستخدام:** اختبار محلي / تطوير
- **الميزات:** لوحة تحكم HTML داكنة مع Bootstrap، منشئ مهام، سجل مهام
- **الأمان:** HMAC-SHA256 مع نافذة 15 دقيقة
- **لا يشكل خطرًا أمنيًا في الإنتاج طالما لا يمكن الوصول إليه عبر الويب**
#### 3.1.4 `cron_surge_opportunity.php` (قلب النظام)
- **الجدولة:** كل 10 دقائق
- **الوظيفة:** محرك كشف فرص رفع الأسعار (Surge Detection)
- **آلية العمل:**
1. يستعلم من `competitor_prices` ويجمّع البيانات بخلايا جغرافية (~1.5km)
2. يحسب خط الأساس (baseline): متوسط سعر كل منافس لآخر 7 أيام
3. يحسب السعر الحالي: متوسط لكل منافس في آخر ساعتين
4. يشترط وجود 2 عينة على الأقل لكل منافس في كل خلية
5. يكتشف الفرصة عندما **جميع** المنافسين في الخلية رفعوا أسعارهم
6. يقترح مضاعف السعر: `1.0 + (avg_competitor_surge_ratio - 1.0) * 0.6` (يقلل عن المنافسين بـ 40%)
7. يحفظ في Redis: `surge:opportunities` مع TTL 10 دقائق
- **SQL الرئيسي:**
```sql
SELECT ROUND(lat * 74) / 74 AS lat_group, ROUND(lng * 74) / 74 AS lng_group,
competitor_name, country_code,
AVG(CASE WHEN created_at < DATE_SUB(NOW(), INTERVAL 6 HOUR)
THEN price_per_km END) AS baseline_avg,
AVG(CASE WHEN created_at >= DATE_SUB(NOW(), INTERVAL 2 HOUR)
THEN price_per_km END) AS current_avg,
COUNT(CASE WHEN created_at >= DATE_SUB(NOW(), INTERVAL 2 HOUR)
THEN 1 END) AS recent_samples
FROM competitor_prices
GROUP BY lat_group, lng_group, competitor_name, country_code
HAVING recent_samples >= 2
```
#### 3.1.5 `cron_kazan_adjuster.php`
- **الجدولة:** كل 10 دقائق
- **الوظيفة:** يخفف عمولة Siro (Kazan) في المناطق التي يرتفع فيها سعر المنافسين
- **آلية العمل:**
- يقرأ `surge:opportunities:{country}` من Redis
- للخلايا ذات surge > 1.2: يطبق تخفيض 30% على العمولة (0.70x)
- للخلايا ذات surge 1.05-1.2: يطبق تخفيض 15% (0.85x)
- يحفظ في Redis: `surge:kazan_discounts:{country}` مع TTL 20 دقيقة
- **ملاحظة:** يستدعي دالة `getRedisConnection()` غير المعرّفة - سيفشل في وقت التشغيل
#### 3.1.6 `cron_seasonal_pricing.php`
- **الجدولة:** كل 30-60 دقيقة
- **الوظيفة:** يطبق مضاعفات موسمية (رمضان، عيد، طقس سيء)
- **القواعد:**
- `ramadan_iftar` (18:00-20:00): 1.25x
- `eid`: 1.15x (غير نشط حاليًا)
- `severe_weather`: 1.30x (غير نشط حاليًا)
- **ملاحظة:** نفس مشكلة `getRedisConnection()` غير المعرّفة
#### 3.1.7 `cron_weekly_health_report.php`
- **الجدولة:** أسبوعيًا (ليلة الأحد)
- **الوظيفة:** ينشئ تقرير صحة السوق الأسبوعي
- **المقاييس:**
- **PCI (Price Competitiveness Index):** `siroPrice / compPrice`
- **حصة السوق:** % من الرحلات التي Siro فيها أرخص
- **عدد الشذوذ (anomalies):** من جدول `price_anomalies`
- **عدد الحملات:** من جدول `marketing_campaigns_log`
- **Redis:** لا يستخدم
- **MySQL:** يدرج في `market_health_reports`
---
### 3.2 نظام التسعير الديناميكي - `backend/ride/pricing/`
#### 3.2.1 `auto_adapt.php`
- **الجدولة:** كل 30-60 دقيقة
- **الوظيفة:** يعدل جميع أسعار Siro بناءً على أدنى متوسط سعر للمنافسين
- **المعادلة:** `new_price_per_km = lowest_competitor_avg * 0.92` (أقل من المنافسين بـ 8%)
- **النطاق:** بين 85% و 115% من السعر الحالي
- **الأعمدة المحدثة:** speedPrice, comfortPrice, ladyPrice, electricPrice, vanPrice, deliveryPrice, mishwarVipPrice, fixedPrice, awfarPrice
- **الدول:** SY, JO, EG, IQ
- **SQL الرئيسي:**
```sql
SELECT competitor_name, AVG(price_per_km) AS avg_ppm
FROM competitor_prices
WHERE country_code = :cc AND created_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
AND price_per_km > 0
GROUP BY competitor_name
ORDER BY avg_ppm ASC
```
#### 3.2.2 `get.php` (نقطة تسعير الرحلة - 511 سطرًا)
- **الوظيفة:** يحسب سعر الرحلة عند الطلب (أثناء تشغيل التطبيق)
- **آلية العمل المعقدة:**
1. **حساب الخلية الجغرافية:** من إحداثيات الراكب (~1.5km)
2. **قراءة الطلب:** `$redis->get("demand:grid:" . $grid_id)`
3. **قراءة surge المنافسين:** من `surge:opportunities` في Redis
4. **حساب توفر السائقين:** `$redisLocation->georadius()` ضمن 0.75km
5. **Surge Calculation:** إذا `طلب/سائقين > 1.2`، يطبق مضاعف يصل إلى 3.0x
6. **التسعير الزمني:** الليل (21:00-01:00) ← `latePrice`، الفجر (01:00-05:00) ← مضاعف، الظهر (14:00-17:00) ← `heavyPrice`
7. **تخفيضات المسافات الطويلة:** 40km+ و 100km+
8. **مطابقة المنافسين:** مستويين من المطابقة:
- المستوى 1: يطابق نقطة البداية والنهاية معًا
- المستوى 2: يطابق نقطة البداية فقط
- يخفض السعر بنسبة 8% إذا كان السعر المحسوب أعلى من متوسط المنافسين
9. **العمولة:** `price * (1 + kazanPercent / 100)`
10. **التحقق من العروض:** يتحقق من جدول `promos`
11. **ديون الراكب:** يقرأ من Redis `passenger_debt_{id}`
12. **توليد توكن:** يشفر حمولة السعر بانتهاء صلاحية 7 دقائق لمنع التلاعب
- **المفاتيح الأساسية:** `kazan`, `promos`, `competitor_prices`
- **Redis:** `demand:grid:{id}`, `surge:opportunities`, `passenger_debt_{id}`
---
### 3.3 نظام الخريطة الحرارية (Heatmap) - `backend/ride/heatmap/`
#### 3.3.1 `log_demand.php`
- **الوظيفة:** يسجل الطلب عند كل خلية جغرافية
- **Redis:** `INCR` على `demand:grid:{grid_id}` مع TTL 60 ثانية
- **يُستدعى من:** تطبيق الراكب عند طلب رحلة
#### 3.3.2 `get_surge_heatmap.php`
- **الوظيفة:** يعرض بؤر surge لتطبيق السائق (Driver App)
- **المصادقة:** يتطلب دور `driver`
- **Redis:** يقرأ `surge:opportunities:{countryCode}`
- **الفلترة:** فقط الخلايا ذات مضاعف > 1.05
#### 3.3.3 `heatmap_live.php`
- **الوظيفة:** خريطة حية لتطبيق الكابتن - تجمع بين الطلب وتوفر السائقين
- **تحذير:** يستخدم `$redis->keys("demand:grid:*")` - أمر `KEYS` بطيء مع عدد كبير من المفاتيح
- **التصنيف:** عالي (نسبة > 2.0 أو عدد ≥ 5)، متوسط (نسبة > 1.2 أو عدد ≥ 3)، منخفض
---
### 3.4 نقط نهاية التسويق - `backend/Admin/marketing/`
#### 3.4.1 `trigger_campaign.php` (200 سطر - الأكثر تعقيدًا)
- **الوظيفة:** يطلق حملة تسويقية مدعومة بالذكاء الاصطناعي
- **الخطوات:**
1. يجلب آخر 10 أسعار منافسين من MySQL
2. يستدعي `SiroGeminiService->analyzeMarketAndDraftCampaign()` مع بيانات السوق
3. إذا تم اكتشاف فرصة (`opportunity_detected`):
- يجد الركاب المستهدفين من `passenger_opening_locations`
- ينشئ كود خصم في جدول `promos` (صالحة 7 أيام)
- لكل راكب:
- إذا لديه FCM token: يرسل إشعار دفع
- إذا لا: يتحقق من anti-spam (24 ساعة)، ثم WhatsApp → SMS
4. يسجل في `admin_audit_log`
- **الخدمات الخارجية:** Google Gemini, WhatsApp Bot, Firebase Cloud Messaging
- **الحماية:** Anti-spam (24h cooldown للـ SMS/WhatsApp)
#### 3.4.2 `ai_price_prediction.php`
- **الوظيفة:** يتوقع ساعات الذروة بناءً على بيانات 14 يومًا
- **المنطق:** `SELECT HOUR(created_at) FROM price_anomalies WHERE anomaly_type = 'opportunity' GROUP BY HOUR ORDER BY COUNT(*) DESC LIMIT 3`
- **النتيجة:** أفضل 3 ساعات متوقعة + نسبة ثقة 85%
#### 3.4.3 `what_if_simulator.php`
- **الوظيفة:** محاكي "ماذا لو" - يقترح السعر الأمثل
- **المنطق:**
- يأخذ `speed_price` مقترح
- يحاكي السعر لآخر 500 رحلة منافس
- يحسب PCI الجديد وحصة السوق المتوقعة
- التوصية: PCI < 0.8 تحذير (ربح قليل)، 0.9-0.95 ممتاز، > 1.0 خطر
#### 3.4.4 `surge_opportunity_index.php`
- **الوظيفة:** نسخة Admin من `cron_surge_opportunity.php` - استعلام فوري
- **الفرق:** يُستدعى عبر HTTP، يعرض تفاصيل كل منطقة ومنافس
#### 3.4.5 `winback_hotspot_targets.php`
- **الوظيفة:** يجد الركاب الخاملين (30 يوم بدون رحلة) في مناطق surge
- **Redis:** يقرأ `surge:opportunities:{countryCode}`
- **MySQL:** `users JOIN passenger_opening_locations`
#### 3.4.6 `get_price_gap_heatmap.php`
- **الوظيفة:** خريطة حرارية توضح أين Siro أرخص/أغلى من المنافسين
- **المنطق:** لكل خلية جغرافية يحسب `pci = currentSpeedPrice / avg_competitor_price` و `weight = pci - 1.0` مقيد بـ [-1, 1]
#### 3.4.7 باقي نقاط النهاية
| الملف | الوظيفة |
|-------|---------|
| `get_campaigns_log.php` | سجل الحملات التسويقية |
| `get_market_anomalies.php` | الشذوذ السعري + آخر أسعار المنافسين |
| `get_market_share_analytics.php` | بيانات حصة السوق للرسوم البيانية (آخر 12 أسبوع) |
| `get_price_comparison.php` | مقارنة الأسعار: متوسطات الساعة، PCI حسب المنطقة، أسعار Siro |
| `get_telemetry.php` | إحصائيات استخدام النظام: عدد الحملات، التكلفة التقديرية |
---
### 3.5 خدمة الذكاء الاصطناعي - `backend/core/Services/SiroGeminiService.php`
- **النموذج:** `gemini-1.5-flash`
- **الوظيفة:** تحليل السوق وكتابة الحملات التسويقية بالعربية
- **المخرجات:** JSON يحتوي على `opportunity_detected`, `campaign_text`, `discount_percent`, `message_type`
- **التكيف:** يضبط اللهجة حسب البلد (سوري، أردني، مصري، عراقي)
---
## 4. تدفق البيانات (Data Flow)
```
generate_price_tasks.php (cron/15min)
│
│ LPUSH → queue:bot:tasks (Redis)
▼
Android Bot (Scraper) ←→ worker.php (API)
│
│ POST result → INSERT competitor_prices
▼
┌────────────────────────────────────────────────────────────┐
│ competitor_prices (MySQL) │
│ country_code | lat | lng | price_per_km | competitor_name │
└─────────────────────────────────────────────────────────────┘
│
├─── cron_surge_opportunity.php (cron/10min)
│ │ SELECT baseline vs current
│ │ WRITE surge:opportunities (Redis)
│ ▼
├─── cron_kazan_adjuster.php (cron/10min)
│ │ READ surge:opportunities:{CC}
│ │ WRITE surge:kazan_discounts:{CC}
│ ▼
├─── cron_seasonal_pricing.php (cron/30-60min)
│ │ WRITE surge:seasonal:{CC}
│ ▼
├─── auto_adapt.php (cron/30-60min)
│ │ SELECT AVG(price_per_km) → UPDATE kazan
│ ▼
├─── cron_weekly_health_report.php (cron/weekly)
│ │ SELECT → INSERT market_health_reports
│ ▼
├─── ride/pricing/get.php (API - عند طلب رحلة)
│ │ READ Redis (surge, demand, debt)
│ │ SELECT (competitor_prices, kazan, promos)
│ ▼
└─── Admin/marketing/*.php (API - لوحة التحكم)
│ READ (competitor_prices, anomalies, etc.)
│ WRITE (promos, campaigns_log, audit_log)
│ CALL Gemini API
```
---
## 5. قاعدة البيانات وجداولها
| الجدول | العمليات (SELECT) | العمليات (INSERT/UPDATE) |
|--------|:-----------------:|:------------------------:|
| `competitor_prices` | cron_surge_opportunity, cron_weekly_health, surge_opportunity_index, get_price_comparison, get_price_gap_heatmap, what_if_simulator, trigger_campaign, auto_adapt, pricing/get | worker.php (INSERT), generate_price_tasks (CREATE TABLE) |
| `kazan` | cron_weekly_health, get_price_comparison, get_price_gap_heatmap, what_if_simulator, pricing/get | auto_adapt (UPDATE) |
| `price_anomalies` | ai_price_prediction, get_market_anomalies, cron_weekly_health, get_telemetry | (خارج نطاق هذه الدراسة) |
| `market_health_reports` | get_market_share_analytics | cron_weekly_health (INSERT) |
| `marketing_campaigns_log` | get_campaigns_log, cron_weekly_health, get_telemetry | trigger_campaign (INSERT) |
| `passenger_opening_locations` | trigger_campaign, winback_hotspot_targets | (خارج النطاق) |
| `promos` | pricing/get | trigger_campaign (INSERT) |
| `passengers` | get_campaigns_log, trigger_campaign | (خارج النطاق) |
| `tokens` | trigger_campaign | (خارج النطاق) |
| `users` | winback_hotspot_targets | (خارج النطاق) |
| `admin_audit_log` | - | trigger_campaign (INSERT via logAudit) |
---
## 6. خريطة مفيكات Redis
| نمط المفتاح | يُكتب بواسطة | يُقرأ بواسطة | TTL |
|:-----------:|:------------:|:------------:|:---:|
| `surge:opportunities` | cron_surge_opportunity, surge_opportunity_index | pricing/get, get_surge_heatmap | 600s |
| `surge:opportunities:{CC}` | cron_kazan_adjuster | winback_hotspot_targets, get_surge_heatmap | 1200s |
| `surge:kazan_discounts:{CC}` | cron_kazan_adjuster | (ride logic) | 1200s |
| `surge:seasonal:{CC}` | cron_seasonal_pricing | (ride logic) | 3600s |
| `queue:bot:tasks` | generate_price_tasks | worker.php (RPOP) | list |
| `competitor:price_history:{app}` | worker.php | (تحليلات مستقبلية) | list/50 |
| `demand:grid:{grid}` | log_demand | pricing/get, heatmap_live | 60s |
| `passenger_debt_{id}` | (من نظام المحفظة) | pricing/get | متغير |
---
## 7. الخدمات الخارجية المستخدمة
| الخدمة | الاستخدام | الملف المرتبط |
|--------|:---------:|:-------------:|
| **Google Gemini AI** | إنشاء محتوى الحملات التسويقية | `SiroGeminiService.php`, `trigger_campaign.php` |
| **Firebase Cloud Messaging** | إشعارات الدفع للركاب | `trigger_campaign.php`, `FcmService.php` |
| **WhatsApp Bot Servers** | إرسال رسائل واتساب | `trigger_campaign.php` |
| **Android Bot (Scraper)** | جمع أسعار المنافسين | `worker.php`, `generate_price_tasks.php` |
| **Location Socket Server** | مواقع السائقين اللحظية | `heatmap_live.php`, `pricing/get.php` |
---
## 8. ملفات الخلفية - مراجعة أمنية شاملة
### 8.1 ملفات اختبار/تجربة عالية الخطورة (يجب حذفها فورًا)
#### `backend/test_add_driver_and_car.php`
- **الوصف:** سكربت اختبار يُنشئ سائق وسيارة في قاعدة البيانات مباشرة
- **الخطر:** لا يتطلب أي مصادقة - أي زائر يمكنه إنشاء حسابات سائقين وهمية
- **التصنيف:** **🚨 عالي جدًا - احذف فورًا**
#### `backend/test_signed_pricing.php`
- **الوصف:** سكربت اختبار يتحايل على المصادقة (`define('TESTING_BYPASS_AUTH', true)`)
- **الخطر:** يمكنه إنشاء رحلات حقيقية ببيانات مزيفة
- **التصنيف:** **🚨 عالي جدًا - احذف فورًا**
#### `backend/diagnose_fingerprint.php`
- **الوصف:** أداة تشخيص تفضي ببيانات البصمات المخزنة
- **الخطر:** يعرض البيانات مفككة التشفير بدون مصادقة
- **التصنيف:** **🚨 عالي جدًا - احذف فورًا**
#### `backend/diagnose_login.php`
- **الوصف:** أداة تشخيص تسجيل الدخول - تعرض أرقام الهواتف والأسماء
- **الخطر:** يعرض PII (معلومات شخصية) مفككة التشفير
- **التصنيف:** **🚨 عالي جدًا - احذف فورًا**
#### `backend/auth/Tester/getTesterApp.php` و `updateTesterApp.php`
- **الوصف:** نقاط نهاية اختبار بدون مصادقة مع SQL Injection
- **الخطر:** SQL Injection صريح + لا مصادقة
- **التصنيف:** **🚨 عالي جدًا - احذف فورًا**
#### `backend/migration_create_table.php`
- **الوصف:** سكربت إنشاء جدول (كان يجب حذفه بعد الاستخدام)
- **الخطر:** يمكن إعادة تنفيذه لتعديل schema قاعدة البيانات
- **التصنيف:** **🚨 عالي جدًا - احذف فورًا**
#### `backend/migrate_driver_passwords.php`
- **الوصف:** سكربت ترحيل كلمات المرور
- **الخطر:** يحتوي على بيانات اعتماد قاعدة بيانات في الكود
- **التصنيف:** **🚨 عالي جدًا - احذف فورًا**
#### `backend/Admin/auth/migration_cryptography.php`
- **الوصف:** يعيد تشفير جميع الأعمدة المشفرة (أكثر من 15 جدول)
- **الخطر:** إعادة تنفيذه قد تفسد جميع البيانات المشفرة
- **التصنيف:** **🚨 عالي - احذف فورًا**
#### `backend/Admin/auth/migrate_db.php`
- **الوصف:** سكربت ترحيل بنية قاعدة البيانات
- **الخطر:** يمكنه تعديل schema الإنتاج
- **التصنيف:** **🚨 عالي - احذف فورًا**
#### `backend/Admin/Staff/add_super_admin.php`
- **الوصف:** إضافة مشرف (Admin) جديد
- **الخطر:** التحقق من الصلاحية معلّق (commented out) - أي زائر يمكنه إنشاء super admin
- **التصنيف:** **🚨 عالي جدًا - احذف فورًا**
#### `backend/Admin/Staff/setup.php`
- **الوصف:** سكربت إعداد الموظفين الأولي
- **الخطر:** يمكنه إعادة تعيين جميع صلاحيات المشرفين
- **التصنيف:** **🚨 عالي - احذف بعد التأكد من الإعداد**
### 8.2 ملفات ترحيل البصمات - مفتاح مشفر مكشوف
#### `siro_admin/lib/views/admin/enceypt/fingerprint_migration.dart`
#### `siro_admin/lib/views/admin/enceypt/driver_fingerprint_migration.dart`
- **الوصف:** أدوات Flutter لترحيل البصمات
- **الخطر:** يحتويان على مفتاح المشرف (admin key) بشكل نصي صريح:
```
'iuyweiruinakjbfkajkjlkmalkcxnlahd'
```
- **التصنيف:** **🔥 خطير جدًا - احذف فورًا وغيّر المفتاح في السيرفر**
### 8.3 ملفات "ggg" - أدوات التشفير
| الملف | الوظيفة | المصادقة | التصنيف |
|-------|:-------:|:--------:|:-------:|
| `backend/ggg.php` | تشفير/فك تشفير للمشرف | JWT admin/super_admin | ⚠️ متوسط |
| `backend/Admin/ggg.php` | تشفير/فك تشفير | ADMIN_PHONE_NUMBERS | ⚠️ متوسط |
**التوصية:** احذف بعد انتهاء الترحيل. هذه أدوات خطيرة لأنها تسمح بفك تشفير أي بيانات.
### 8.4 ملفات الترحيل (Migration Files)
| الملف | الوظيفة | التصنيف |
|-------|:-------:|:-------:|
| `backend/migration/get_all_fingerprints.php` | تصدير بصمات الركاب | ⚠️ متوسط |
| `backend/migration/get_all_driver_fingerprints.php` | تصدير بصمات السائقين | ⚠️ متوسط |
| `backend/migration/update_fingerprint_admin.php` | تحديث بصمة راكب | ⚠️ متوسط |
| `backend/migration/update_driver_fingerprint_admin.php` | تحديث بصمة سائق | ⚠️ متوسط |
**التوصية:** احذف جميع ملفات الترحيل بعد التأكد من اكتمال الترحيل في الإنتاج.
### 8.5 ملفات أخرى
#### `backend/intaleq_v1_secure_latest.md`
- **الوصف:** ملف توثيق ضخم (33,608 سطر) يحتوي على كود المصدر الكامل
- **الخطر:** إذا كان الوصول إليه ممكنًا عبر الويب، فإنه يسرب كامل قاعدة الشفرة
- **التصنيف:** ⚠️ متوسط - انقل خارج جذر الويب أو احذف
#### `siro_admin/lib/debug_jwt.dart`
- **الوصف:** سكربت Flutter لاختبار JWT
- **الخطر:** يكشف بنية JWT ومنهجية التشفير
- **التصنيف:** ⚠️ منخفض - احذف من بنية الإنتاج
---
## 9. قائمة الملفات المطلوب حذفها فوراً
### أولوية قصوى - خطر أمني مباشر 🔴
| الملف | السبب |
|:------|:-----:|
| `backend/test_add_driver_and_car.php` | إنشاء سائقين بدون مصادقة |
| `backend/test_signed_pricing.php` | تجاوز المصادقة |
| `backend/diagnose_fingerprint.php` | كشف بيانات حساسة بدون مصادقة |
| `backend/diagnose_login.php` | كشف PII بدون مصادقة |
| `backend/migration_create_table.php` | تعديل schema بدون مصادقة |
| `backend/migrate_driver_passwords.php` | بيانات اعتماد DB في الكود |
| `backend/Admin/auth/migration_cryptography.php` | إعادة تشفير شامل |
| `backend/Admin/auth/migrate_db.php` | تعديل schema الإنتاج |
| `backend/Admin/Staff/add_super_admin.php` | صلاحية المشرِف معلّقة |
| `backend/Admin/Staff/setup.php` | إعادة تعيين الصلاحيات |
| `backend/auth/Tester/getTesterApp.php` | SQL Injection + لا مصادقة |
| `backend/auth/Tester/updateTesterApp.php` | SQL Injection + لا مصادقة |
| `siro_admin/lib/views/admin/enceypt/fingerprint_migration.dart` | مفتاح مكشوف 🔥 |
| `siro_admin/lib/views/admin/enceypt/driver_fingerprint_migration.dart` | مفتاح مكشوف 🔥 |
### أولوية متوسطة - أمان أو تنظيف 🟡
| الملف | السبب |
|:------|:-----:|
| `backend/ggg.php` | أداة تشفير للمشرفين - احذف بعد الترحيل |
| `backend/Admin/ggg.php` | أداة تشفير - احذف بعد الترحيل |
| `backend/migration/get_all_fingerprints.php` | ترحيل بصمات - احذف بعد التأكد |
| `backend/migration/get_all_driver_fingerprints.php` | ترحيل بصمات - احذف بعد التأكد |
| `backend/migration/update_fingerprint_admin.php` | ترحيل بصمات - احذف بعد التأكد |
| `backend/migration/update_driver_fingerprint_admin.php` | ترحيل بصمات - احذف بعد التأكد |
| `backend/Admin/auth/register.php` | مراجعة - هل ما زال مستخدمًا؟ |
| `siro_admin/lib/debug_jwt.dart` | تصحيح JWT - احذف من الإنتاج |
| `backend/intaleq_v1_secure_latest.md` (33k سطر) | كود مصدر كامل - انقل أو احذف |
### أولوية منخفضة - تحسين أمني 🟢
| الملف | السبب |
|:------|:-----:|
| `walletintaleq.intaleq.xyz/v2/main/ride/payment/delete.php` | ملف فارغ تمامًا |
| `backend/logo.png` | (تحقق ما إذا كان ضروريًا) |
---
## 10. ثغرات SQL Injection
### 10.1 ملفات ذات SQL Injection مباشر
هذه الملفات تستخدم `prepare()` بعد `$sql = "... WHERE id = '$var'"` مما يبطل تمامًا حماية prepared statements:
| الملف | السطر | الكود المخترق |
|:------|:-----:|:--------------|
| `wallet/ride/passengerWallet/delete.php` | `$sql = "DELETE FROM passengerWallet WHERE id = '$id'"` |
| `wallet/ride/passengerWallet/update.php` | `$sql = "UPDATE passengerWallet SET balance = '$balance' WHERE id = '$id'"` |
| `wallet/ride/passengerWallet/getAllPassengerTransaction.php` | `WHERE passenger_id = '$passenger_id'` |
| `wallet/ride/passengerWallet/getPassengerWalletArchive.php` | `WHERE passenger_id = '$passenger_id'` |
| `wallet/ride/driverPayment/delete.php` | `DELETE FROM paymentsDriverPoints WHERE id = '$id'` |
| `wallet/ride/driverPayment/update.php` | `UPDATE ... SET amount = '$amount', ...` |
| `wallet/ride/driverPayment/add.php` | `INSERT INTO paymentsDriverPoints VALUES ('$amount', '$paymentMethod', '$driverID')` |
| `wallet/ride/driverWallet/get.php` | `WHERE driverID = '$driverID'` (في subquery) |
| `wallet/ride/payment/update.php` | بناء `SET` ديناميكي + SQL Injection |
| `backend/Admin/adminUser/get.php` | `WHERE device_number = '$device_number'` |
### 10.2 الإجراء المطلوب
1. **فوري:** استبدال `$sql = "... WHERE id = '$var'"` بـ `$sql = "... WHERE id = :id"` مع `bindParam(':id', $id)`
2. **مراجعة:** جميع ملفات `walletintaleq/` لديها مشكلة أمنية منهجية - تحتاج مراجعة كاملة
3. **تحذير:** ملفات `driverPayment/` لا تملك أي مصادقة JWT - يمكن لأي زوار الوصول إليها
---
## 11. التوصيات النهائية
### أولاً - فوري (خلال 24 ساعة)
1. **حذف جميع الملفات عالية الخطورة (القسم 9 - 🔴)**
2. **تغيير مفتاح `MIGRATION_ADMIN_KEY`** في جميع السيرفرات (المفتاح `iuyweiruinakjbfkajkjlkmalkcxnlahd` أصبح مكشوفًا)
3. **إصلاح ثغرات SQL Injection** في ملفات المحفظة (القسم 10)
### ثانيًا - قصير المدى (خلال أسبوع)
4. **توحيد السناك بار** حسب الخطة في القسم 1
5. **حذف ملفات الترحيل** بعد التأكد من اكتمال الترحيل
6. **نقل أو حذف `intaleq_v1_secure_latest.md`** من جذر الويب
7. **مراجعة جميع ملفات `walletintaleq/`** - معظمها يفتقر إلى مصادقة JWT
### ثالثًا - طويل المدى (شهر)
8. **تبسيط الـ Redis architecture** - حاليًا يوجد اتصالان منفصلان (main + location)
9. **استبدال `KEYS` command** في `heatmap_live.php` بـ `SCAN`
10. **إصلاح الدوال غير المعرّفة** `getRedisConnection()` و `resolveAdminCountry()`
11. **فصل إنشاء الجداول** من ملفات cron إلى migration scripts
12. **توسيع التغطية الجغرافية** - حاليًا تتركز على دمشق فقط
### رابعًا - تحسينات إضافية
13. **إضافة مزيد من التوثيق** للـ cron jobs (جدولة، مخرجات، مراقبة)
14. **إضافة نظام إنذار** عند فشل أحد cron jobs
15. **تشفير جميع مفاتيح API** في ملف `.env` فقط
16. **تطبيق pipeline CI/CD** يستبعد ملفات الاختبار والترحيل من الإنتاج
---
*تم إعداد هذه الدراسة بتاريخ 26 يونيو 2026 بناءً على تحليل شامل للكود المصدري لمشروع Siro.*