353 lines
14 KiB
Markdown
353 lines
14 KiB
Markdown
|
||
# تقرير نظام تسجيل السائق — سوريا 🇸🇾
|
||
|
||
> **ملف المحاكاة التفاعلية:** [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 |
|
||
|