Update: 2026-06-19 01:47:48

This commit is contained in:
Hamza-Ayed
2026-06-19 01:47:48 +03:00
parent f13faa8c31
commit a003bf78c4
34 changed files with 6207 additions and 13499 deletions

View File

@@ -0,0 +1,352 @@
# تقرير نظام تسجيل السائق — سوريا 🇸🇾
> **ملف المحاكاة التفاعلية:** [siro_driver_registration_simulation.html](file:///Users/hamzaaleghwairyeen/.gemini/antigravity-ide/brain/3690cabc-80e2-4e43-af35-66c30922ddee/siro_driver_registration_simulation.html)
---
## 🗺️ خريطة النظام الكاملة
```mermaid
flowchart TD
A[📱 السائق يفتح التطبيق] --> B[RegisterCaptainController<br/>إدخال رقم الهاتف]
B --> C{التحقق من الدولة}
C -->|🇸🇾 سوريا| D[Phone Formatting<br/>09xx → 963xx]
D --> E[POST /auth/otp/request.php<br/>country: Syria]
E --> F{OTP Router}
F -->|Primary| G[Intaleq WhatsApp]
F -->|Failover 1| H[Nabeh JWT]
F -->|Failover 2| I[SMS]
G --> J[DB: phone_verification<br/>AES-GCM encrypted × 5min]
J --> K[OtpVerificationController<br/>countdown 120s]
K --> L[POST /auth/otp/verify.php]
L --> M{✅ صحيح؟}
M -->|نعم| N[RegistrationController<br/>3-Step Wizard]
M -->|لا| K
N --> O[Step 1: Driver Info<br/>الاسم + HID + DOB + License]
O --> P[Step 2: Car Info<br/>Plate + Make + Model + VIN]
P --> Q[Step 3: Doc Upload × 8]
Q --> R[uploadToSyria × 8<br/>MultipartRequest + JWT]
R --> S[uploadSyrianDocs.php<br/>private_uploads Signed URL 48h]
S --> T[submitRegistration<br/>POST /register_driver_and_car.php]
T --> U[🤖 Gemini Flash<br/>Vision AI Analysis]
U --> V{AI Face Match}
V -->|✅ high| W[DB Transaction<br/>driver + CarRegistration]
V -->|❌ mismatch| X[jsonError - رفض]
W --> Y[FCM → topic:service<br/>Admin Notification]
Y --> Z[status: yet ⏳]
Z --> AA[Admin Review]
AA --> AB[status: active ✅]
AB --> AC[JWT + driverToken<br/>السائق جاهز للعمل]
```
---
## 📱 مراحل التسجيل (8 خطوات)
### 1⃣ إدخال رقم الهاتف — `RegisterCaptainController`
**منطق تنسيق الرقم السوري:**
```php
// من: register_driver_and_car.php
if (strpos($phone, '00963') === 0) {
$phone = substr($phone, 2); // 00963 → 963
} elseif (strpos($phone, '09') === 0) {
$phone = '963' . substr($phone, 1); // 09xx → 9639xx
} elseif (strpos($phone, '9') === 0 && strlen($phone) == 9) {
$phone = '963' . $phone; // 9xxxxxxxx → 9639xxxxxxxx
}
// التأكد من وجود 9 بعد 963
if (strpos($phone, '963') === 0 && strpos($phone, '9639') !== 0) {
$phone = '9639' . substr($phone, 3);
}
```
---
### 2⃣ نظام OTP — `OtpVerificationController`
| الدولة | المزود الأساسي | Failover 1 | Failover 2 |
|--------|---------------|-----------|-----------|
| 🇸🇾 سوريا | Intaleq WhatsApp | Nabeh JWT | SMS |
| 🇪🇬 مصر | Kazumi SMS | Intaleq WhatsApp | Nabeh JWT |
| 🇯🇴 الأردن | Intaleq SMS | Nabeh JWT | — |
**مخطط DB:**
```sql
-- جدول التحقق للسائق
INSERT INTO phone_verification (
phone_number, -- مشفر AES-GCM
driverId,
email, -- مشفر AES-GCM
token_code, -- مشفر AES-GCM (3 أرقام)
expiration_time, -- NOW() + 5 دقائق
is_verified -- 0 → 1 عند النجاح
)
```
> [!NOTE]
> Rate Limiting: 3 محاولات كل 5 دقائق لكل IP عبر Redis
---
### 3⃣ معلومات السائق — `RegistrationController` Page 0
**الحقول المطلوبة:**
- `first_name`, `last_name`, `national_number`, `birthdate`, `expiry_date`
- التحقق عبر `driverInfoFormKey.validate()`
**ملاحظة تاريخ الميلاد:**
```php
// من register_driver_and_car.php
$data['birthdate'] = trim($data['birthdate']) . '-01-01';
// "1990" → "1990-01-01"
```
---
### 4⃣ معلومات المركبة — `RegistrationController` Page 1
**الحقول الجديدة (vehicle_category_id + fuel_type_id):**
| ID | نوع المركبة | ID | نوع الوقود |
|---|------------|---|-----------|
| 1 | سيارة (Car) | 1 | بنزين (Petrol) |
| 2 | دراجة نارية | 2 | ديزل (Diesel) |
| 3 | فان / باص | 3 | كهربائي |
| — | — | 4 | هايبرد |
```dart
// Flutter → submitRegistration()
_addField(fields, 'vehicle_category_id', selectedVehicleCategoryId.toString());
_addField(fields, 'fuel_type_id', selectedFuelTypeId.toString());
_addField(fields, 'fuel', fuelObj['name'].toString()); // للتوافق
```
---
### 5⃣ رفع الوثائق — `uploadToSyria()` × 8
**الوثائق المطلوبة لسوريا:**
| المستند | الحقل | إلزامي سوريا؟ |
|---------|-------|--------------|
| هوية — وجه | `id_front` | ✅ |
| هوية — خلف | `id_back` | ✅ |
| رخصة القيادة — وجه | `driver_license` | ✅ |
| رخصة القيادة — خلف | `driver_license_back` | **🇸🇾 إلزامي فقط!** |
| صورة شخصية | `profile_picture` | ✅ |
| لا حكم عليه | `criminal_record` | ✅ |
| ترخيص سيارة — وجه | `car_license_front` | ✅ |
| ترخيص سيارة — خلف | `car_license_back` | ✅ |
**آلية الرفع:**
```dart
// Flutter: uploadToSyria()
final req = http.MultipartRequest('POST', syrianUploadUri);
req.headers.addAll({
'Authorization': 'Bearer JWT',
'X-HMAC-Auth': hmacHeader,
});
req.fields['driver_id'] = driverId;
req.fields['doc_type'] = docType; // e.g., 'driver_license_back'
// timeout: 120 ثانية — 3 محاولات تلقائية
```
**Backend — الرد (Signed URL):**
```json
{
"status": "success",
"file_url": "https://api-syria.siromove.com/siro/secure_image.php?driver_id=DRV...&doc_type=id_front&ext=jpg&expires=1720000000&signature=sha256...",
"mime_type": "image/jpeg",
"size_bytes": 98340,
"expires_at": "2024-06-21T..."
}
```
> [!IMPORTANT]
> الملفات تُحفظ في `private_uploads/` (خارج الويب العام) ولا يمكن الوصول إليها إلا عبر رابط موقّع صالح لمدة **48 ساعة**.
---
### 6⃣ الذكاء الاصطناعي Gemini Flash — Vision AI
**البرومبت الكامل يطلب:**
```json
{
"status": "success|failure",
"reason": "إذا فشل",
"face_match_confidence": "high|low",
"driver": {
"full_name": "", // الاسم الكامل بالعربي
"national_number": "", // أرقام لاتينية فقط
"dob": "YYYY-MM-DD",
"governorate": "",
"license_expiry_date": "YYYY-MM-DD",
"license_category": "B|D1|..."
},
"car": {
"car_plate": "", // e.g., "155186 درعا"
"vin": "", // أحرف وأرقام لاتينية
"color": "",
"color_hex": "#FFFFFF",
"make": "", "model": "", "year": ""
}
}
```
**قواعد الذكاء الاصطناعي الحرجة:**
1. **FACE MATCHING**: مقارنة الصورة الشخصية ↔ الهوية ↔ رخصة القيادة
2. **OCR ذكي**: المسح من كلا وجهي كل وثيقة
3. تحويل الأرقام العربية (٠١٢) إلى لاتينية (012)
4. تطبيع ألوان السيارات `أبيض → White → #FFFFFF`
5. الفشل الكلي فقط عند: وجه غير متطابق / وثائق مزورة
> [!WARNING]
> **SSRF Protection**: URLs يُسمح بها فقط من `allowedHosts` — يُمنع تحميل أي صورة من مصادر خارجية.
---
### 7⃣ إدراج قاعدة البيانات — Transaction Atomique
**الحقول المشفرة في جدول `driver`:**
```php
$toEncryptDriver = [
"phone", "email", "first_name", "last_name",
"name_arabic", "gender", "national_number",
"address", "site", "fullNameMaritial", "birthdate"
];
// كلها تُشفَّر بـ AES-GCM قبل الإدراج
```
**كلمة المرور (HMAC + bcrypt):**
```php
$baseString = implode('|', [$data['id'], $data['phone'], $data['national_number']]);
$rawSecret = hash_hmac('sha256', $baseString, $pepper, true);
$pwdHashed = password_hash($rawSecret, PASSWORD_DEFAULT);
```
---
### 8⃣ جداول قاعدة البيانات (`schema_primary.sql`)
**`CarRegistration` — الجدول الرئيسي للمركبات:**
```sql
CREATE TABLE `CarRegistration` (
`id` int AUTO_INCREMENT PRIMARY KEY,
`driverID` varchar(100) NOT NULL, -- FK → driver.id
`vin` varchar(100) NOT NULL, -- مشفر
`car_plate` varchar(150), -- مشفر
`make` varchar(255) NOT NULL,
`model` varchar(255) NOT NULL,
`year` int NOT NULL,
`expiration_date` varchar(30) NOT NULL,
`color` varchar(255) NOT NULL,
`owner` varchar(255) NOT NULL, -- مشفر
`color_hex` varchar(20) NOT NULL,
`fuel` varchar(100) NOT NULL,
`vehicle_category_id` tinyint DEFAULT 1, -- 1=Car,2=Moto,3=Van
`fuel_type_id` tinyint DEFAULT 1, -- 1=Petrol,2=Diesel...
`status` varchar(20) DEFAULT 'yet', -- yet|active|suspended
`isDefault` tinyint DEFAULT 0,
KEY `idx_driverID` (`driverID`)
)
```
**`driver` — الجدول الرئيسي للسائقين:**
```sql
CREATE TABLE `driver` (
`id` varchar(100) NOT NULL, -- DRV{timestamp}{random}
`phone` varchar(255) NOT NULL, -- مشفر AES-GCM
`email` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL, -- bcrypt(HMAC)
`first_name` varchar(255) NOT NULL, -- مشفر
`last_name` varchar(255) NOT NULL, -- مشفر
`national_number` varchar(255), -- مشفر (UNIQUE)
`name_arabic` varchar(255), -- مشفر — من AI
`birthdate` varchar(255), -- مشفر
`status` varchar(20) DEFAULT 'notDeleted', -- yet|active|notDeleted
`expiry_date` date, -- انتهاء رخصة القيادة
UNIQUE KEY `national_number` (`national_number`)
)
```
**`driver_documents`:**
```sql
CREATE TABLE `driver_documents` (
`id` int AUTO_INCREMENT PRIMARY KEY,
`driverID` varchar(64) NOT NULL,
`doc_type` varchar(64) NOT NULL, -- id_front, driver_license_back, ...
`image_name` varchar(255) NOT NULL,
`link` varchar(512) NOT NULL, -- Signed URL
`upload_date` datetime NOT NULL,
KEY `driverID` (`driverID`)
)
```
---
## 🔒 طبقات الأمان
| الطبقة | التقنية | التفاصيل |
|--------|---------|---------|
| Authentication | JWT Bearer | يُعاد التوليد عند كل دخول |
| Transport | HMAC-SHA256 | X-HMAC-Auth header |
| Encryption at Rest | AES-GCM | جميع البيانات الحساسة |
| Password | HMAC + bcrypt | pepper من env |
| Rate Limiting | Redis | 3 OTP / 5 دقائق لكل IP |
| File Access | Signed URLs | HMAC-SHA256 صالح 48 ساعة |
| SSRF Protection | Allowlist hosts | منع URL injection في AI |
| SQL Injection | PDO Prepared Statements | كل الاستعلامات |
| File Upload | MIME detection + finfo | ليس Content-Type فقط |
---
## ✅ النتيجة: هل النظام يعمل صح؟
| العملية | السلوك | التقييم |
|---------|--------|---------|
| تنسيق الهاتف السوري | `09xx``9639xx` تلقائياً | ✅ |
| OTP سوريا | Intaleq WhatsApp → Nabeh Failover | ✅ |
| خلف رخصة القيادة | إلزامي فقط لـ `countryCode == Syria` | ✅ |
| رفع الوثائق | Retry × 3 + Timeout 120s | ✅ |
| AI Face Match | Gemini Flash Vision — تحقق ذكي | ✅ |
| AI يعيد كتابة البيانات | اسم، DOB، لوحة، VIN من الوثائق | ✅ |
| Transaction | Atomic: driver + CarRegistration + documents | ✅ |
| تشفير الحقول | phone, name, national_number → AES-GCM | ✅ |
| `vehicle_category_id` و `fuel_type_id` | يُرسلان من Flutter ويُخزنان في CarRegistration | ✅ |
| إشعار خدمة العملاء | FCM → topic:service بعد التسجيل | ✅ |
| Signed URL | صالح 48 ساعة + HMAC signed | ✅ |
> [!CAUTION]
> **ملاحظة:** حقل `vin` في `submitRegistration()` يُرسل كـ `'yet'` افتراضياً ولا يُرسل من حقل `carVinController`:
> ```dart
> _addField(fields, 'vin', 'yet'); // ← يجب ربطه بـ carVinController.text
> ```
> AI سيُصحح هذا من خلال استخراج VIN من صورة ترخيص السيارة، لكن إذا لم يعمل AI فسيُخزن 'yet'.
---
## 📁 الملفات المرجعية
| الملف | الدور |
|-------|-------|
| [registration_controller.dart](file:///Users/hamzaaleghwairyeen/development/App/Siro/siro_driver/lib/controller/auth/syria/registration_controller.dart) | Controller رئيسي — رفع الوثائق + تقديم التسجيل |
| [register_captin_controller.dart](file:///Users/hamzaaleghwairyeen/development/App/Siro/siro_driver/lib/controller/auth/captin/register_captin_controller.dart) | تسجيل مبدئي + OTP |
| [opt_token_controller.dart](file:///Users/hamzaaleghwairyeen/development/App/Siro/siro_driver/lib/controller/auth/captin/opt_token_controller.dart) | إدارة OTP (120 ثانية countdown) |
| [register_driver_and_car.php](file:///Users/hamzaaleghwairyeen/development/App/Siro/backend/auth/syria/driver/register_driver_and_car.php) | Backend — Gemini AI + DB Transaction |
| [uploadSyrianDocs.php](file:///Users/hamzaaleghwairyeen/development/App/Siro/backend/auth/syria/uploadSyrianDocs.php) | Backend — رفع الوثائق + Signed URL |
| [request.php](file:///Users/hamzaaleghwairyeen/development/App/Siro/backend/auth/otp/request.php) | Backend — إرسال OTP حسب الدولة |
| [verify.php](file:///Users/hamzaaleghwairyeen/development/App/Siro/backend/auth/otp/verify.php) | Backend — التحقق من OTP |
| [schema_primary.sql](file:///Users/hamzaaleghwairyeen/development/App/Siro/backend/schema_primary.sql) | DB Schema — driver + CarRegistration + driver_documents |