Deploy: 2026-05-22 21:52:51
This commit is contained in:
@@ -1,298 +1,78 @@
|
||||
# خطة تنفيذ المعمارية الخلفية ونظام النشر المؤتمت — تطبيق نبيه (Nabeh)
|
||||
# Implementation Plan - Intaleq Customer Service & Driver Registration Flow
|
||||
|
||||
<div dir="rtl" align="right">
|
||||
This plan details the implementation of the Intaleq customer service prompt template, the multi-stage WhatsApp driver registration flow using Gemini OCR, and the authenticated REST API endpoints for Nabeh's backend.
|
||||
|
||||
توضح هذه الخطة التفاصيل الهيكلية والخطوات العملية لبناء النواة البرمجية للخلفية (Backend Base Architecture) باستخدام **Pure PHP OOP** وبناء نظام نشر تلقائي آمن عبر **Git/SSH** إلى السيرفر.
|
||||
|
||||
---
|
||||
|
||||
## أولاً: تقسيم المشروع إلى مراحل (Milestones)
|
||||
|
||||
من أجل ضمان الانتقال السلس وبناء أساسات متينة وقابلة للتطوير، سنقسم العمل على الخلفية والنشر إلى المراحل التالية:
|
||||
|
||||
### المرحلة 1: بناء نواة الـ MVC وتهيئة الهيكل البرمجي
|
||||
- بناء هيكل المجلدات المنظم وفصل الملفات العامة (Public) عن الكود البرمجي الأساسي.
|
||||
- إعداد نظام التحميل التلقائي للملفات (Autoloader) المتوافق مع معيار PSR-4.
|
||||
- برمجة موجه الطلبات (Router) المتوافق مع خادم Nginx.
|
||||
- برمجة قارئ ملفات البيئة المتطور والآمن (`.env` Reader) مع تخزينه خارج المسار العام لضمان أعلى مستويات الحماية.
|
||||
|
||||
### المرحلة 2: تصميم قاعدة البيانات ونواة الاتصال (Database & Core)
|
||||
- تصميم ملف تهيئة الاتصال بقاعدة البيانات باستخدام PDO.
|
||||
- بناء الموديل الرئيسي (Base Model) والمتحكم الرئيسي (Base Controller) لإدارة المدخلات والمخرجات (JSON Responses).
|
||||
- بناء مخطط الجداول الأساسية لقاعدة البيانات (الهيكل متعدد المستأجرين - Multi-Tenant Prep).
|
||||
|
||||
### المرحلة 3: نظام النشر التلقائي للسيرفر (`deploy.sh`)
|
||||
- كتابة سكربت النشر الآمن لرفع التحديثات لـ Git وعمل Pull تلقائي وإعادة بناء التهيئات على السيرفر.
|
||||
- إعداد البنية التحتية للمجلدات على السيرفر وربط الـ Subdomain.
|
||||
|
||||
---
|
||||
|
||||
## ثانياً: معمارية مجلدات الخلفية المقترحة (Directory Structure)
|
||||
|
||||
سنقوم بتنظيم كود الخلفية داخل مجلد `backend/` لحماية كود التطبيق وملف البيانات الحساسة (`.env`) من الوصول المباشر من المتصفح، حيث سيكون مجلد `public/` هو المجلد الوحيد المتاح للعامة والمربوط بالـ Document Root في Nginx.
|
||||
|
||||
الهيكل المستهدف للمجلدات هو كالتالي:
|
||||
|
||||
</div>
|
||||
|
||||
```
|
||||
nabeh/
|
||||
├── backend/
|
||||
│ ├── app/
|
||||
│ │ ├── Controllers/ # متحكمات معالجة الطلبات
|
||||
│ │ │ ├── BaseController.php
|
||||
│ │ │ └── AuthController.php
|
||||
│ │ ├── Models/ # موديلات قواعد البيانات
|
||||
│ │ │ ├── BaseModel.php
|
||||
│ │ │ └── Tenant.php
|
||||
│ │ ├── Core/ # نواة التطبيق البرمجية
|
||||
│ │ │ ├── Router.php
|
||||
│ │ │ ├── Database.php
|
||||
│ │ │ ├── Request.php
|
||||
│ │ │ ├── Response.php
|
||||
│ │ │ └── Env.php
|
||||
│ │ └── Middlewares/ # فلاتر التحقق والوساطة
|
||||
│ │ └── AuthMiddleware.php
|
||||
│ ├── config/ # ملفات الإعدادات العامة
|
||||
│ │ └── app.php
|
||||
│ ├── public/ # المجلد الوحيد المتاح للمتصفح
|
||||
│ │ └── index.php # نقطة الدخول الموحدة (Front Controller)
|
||||
│ ├── .env # ملف البيئة الحساس (مخفي تماماً)
|
||||
│ ├── .env.example
|
||||
│ └── composer.json # لإدارة التحميل التلقائي PSR-4 وحزم التطبيق
|
||||
```
|
||||
|
||||
<div dir="rtl" align="right">
|
||||
|
||||
---
|
||||
|
||||
## ثالثاً: تصميم النواة البرمجية (Core Architecture)
|
||||
|
||||
### 1. نقطة الدخول الموحدة `backend/public/index.php`
|
||||
يقوم هذا الملف بتهيئة بيئة العمل، تحميل الملفات تلقائياً، قراءة متغيرات البيئة، ثم تمرير الطلب إلى الـ Router.
|
||||
|
||||
### 2. قارئ البيئة الآمن `backend/app/Core/Env.php`
|
||||
يقرأ ملف `.env` المتواجد خارج المجلد العام ويقوم بتحميل المتغيرات داخل `$_ENV` و `getenv()` بأمان تام.
|
||||
|
||||
### 3. نظام توجيه الطلبات `backend/app/Core/Router.php`
|
||||
نظام توجيه خفيف وقوي يدعم تعبيرات Regex، ويتيح تعريف مسارات من نوع GET و POST و PUT و DELETE وتمرير البارامترات للمتحكمات (Controllers) وتطبيق فلاتر الوساطة (Middlewares).
|
||||
|
||||
---
|
||||
|
||||
## رابعاً: نظام النشر المؤتمت (`deploy.sh`)
|
||||
|
||||
سنقوم بإنشاء سكربت النشر الذكي في الجذر الرئيسي للمشروع لتبسيط عملية الدفع والتحديث. سيقوم السكربت بالخطوات التالية بشكل تفاعلي وآمن:
|
||||
|
||||
1. التأكد من كتابة تعليق الالتزام (Commit Message).
|
||||
2. إضافة كافة التغييرات محلياً والدفع إلى الفرع الرئيسي على GitHub/GitLab.
|
||||
3. الاتصال بالسيرفر عبر بروتوكول SSH بشكل آمن.
|
||||
4. التوجه إلى مجلد المشروع على السيرفر وسحب الكود البرمجي المحدث (`git pull origin main`).
|
||||
5. تطبيق أي أوامر تهيئة مثل تثبيت حزم الملحقات (`composer install`) أو تنظيف الكاش.
|
||||
|
||||
محتوى سكربت `deploy.sh` المقترح:
|
||||
|
||||
</div>
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================
|
||||
# سكريبت النشر الآلي وتحديث السيرفر - تطبيق نبيه
|
||||
# ==========================================
|
||||
|
||||
# 1. إعدادات السيرفر والمتغيرات الأساسية
|
||||
SERVER_USER="hamza" # اسم مستخدم السيرفر
|
||||
SERVER_IP="your-server-ip" # عنوان السيرفر
|
||||
SERVER_PATH="/var/www/nabeh" # مسار المشروع على السيرفر
|
||||
GIT_BRANCH="main" # الفرع الرئيسي للنشر
|
||||
|
||||
echo "=========================================="
|
||||
echo "🚀 بدء عملية النشر والتحديث لتطبيق (نبيه)..."
|
||||
echo "=========================================="
|
||||
|
||||
# 2. التأكد من حالة التغييرات المحلية
|
||||
if [ -z "$(git status --porcelain)" ]; then
|
||||
echo "ℹ️ لا توجد تغييرات برمجية غير محفوظة للنشر."
|
||||
else
|
||||
# طلب وصف للتحديثات (Commit Message)
|
||||
echo "✍️ الرجاء إدخال رسالة الالتزام (Commit Message):"
|
||||
read commit_msg
|
||||
|
||||
if [ -z "$commit_msg" ]; then
|
||||
commit_msg="Update: Automatic deployment via deploy.sh"
|
||||
fi
|
||||
|
||||
# الإضافة والالتزام البرمجي
|
||||
git add .
|
||||
git commit -m "$commit_msg"
|
||||
fi
|
||||
|
||||
# 3. الدفع إلى Git Remote
|
||||
echo "📤 دفع التحديثات إلى المستودع البعيد (Git Push)..."
|
||||
git push origin $GIT_BRANCH
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "❌ فشلت عملية الدفع البرمجي (Git Push). تم إلغاء النشر."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ تم رفع الكود بنجاح إلى المستودع البرمجي."
|
||||
|
||||
# 4. الاتصال بالسيرفر وتحديث الكود (Git Pull)
|
||||
echo "🌐 الاتصال بالسيرفر وسحب الكود المحدث (Git Pull)..."
|
||||
ssh ${SERVER_USER}@${SERVER_IP} << EOF
|
||||
cd ${SERVER_PATH}
|
||||
echo "📁 الانتقال إلى مجلد المشروع: ${SERVER_PATH}"
|
||||
|
||||
echo "📥 سحب التحديثات من الفرع ${GIT_BRANCH}..."
|
||||
git pull origin ${GIT_BRANCH}
|
||||
|
||||
if [ -f "backend/composer.json" ]; then
|
||||
echo "📦 تحديث الحزم البرمجية والتحميل التلقائي (Composer)..."
|
||||
cd backend
|
||||
composer install --no-dev --optimize-autoloader
|
||||
cd ..
|
||||
fi
|
||||
|
||||
echo "🎉 تم تحديث السيرفر وتثبيت التحديثات بنجاح!"
|
||||
EOF
|
||||
|
||||
echo "=========================================="
|
||||
echo "✨ تمت عملية النشر والتحديث بالكامل بنجاح!"
|
||||
echo "=========================================="
|
||||
```
|
||||
|
||||
<div dir="rtl" align="right">
|
||||
|
||||
---
|
||||
|
||||
## خامساً: خطة إعداد الخادم والـ Subdomain
|
||||
|
||||
لتشغيل نظام الـ Front Controller والمسارات الديناميكية بشكل متوافق مع **Nginx** وبدون الحاجة لملفات `.htaccess` الخاصة بـ Apache، يجب إعداد ملف تهيئة الـ Subdomain (مثال: `api.nabeh.sa` أو `app.nabeh.sa`) ليوجه الطلبات إلى المجلد العام `backend/public/`:
|
||||
|
||||
إعداد Nginx المقترح للمخدم:
|
||||
|
||||
</div>
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
server_name api.nabeh.sa; # النطاق الفرعي للتطبيق
|
||||
|
||||
# تحديد مسار المجلد العام فقط
|
||||
root /var/www/nabeh/backend/public;
|
||||
index index.php index.html;
|
||||
|
||||
charset utf-8;
|
||||
|
||||
# توجيه كافة الطلبات إلى index.php لدعم الـ Router
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
location = /favicon.ico { access_log off; log_not_found off; }
|
||||
location = /robots.txt { access_log off; log_not_found off; }
|
||||
|
||||
error_page 404 /index.php;
|
||||
|
||||
# تشغيل ملفات PHP وتكاملها مع PHP-FPM
|
||||
location ~ \.php$ {
|
||||
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock; # حسب إصدار PHP المثبت
|
||||
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
}
|
||||
|
||||
# منع الوصول تماماً لأي ملفات حساسة أو مخفية
|
||||
location ~ /\.(?!well-known).* {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<div dir="rtl" align="right">
|
||||
|
||||
---
|
||||
|
||||
## سادساً: خطة التحقق والتدقيق (Verification Plan)
|
||||
|
||||
### التحقق الذاتي والمحلي:
|
||||
1. **التحقق من المسارات (Router Testing)**: إنشاء طلبات محلية للتحقق من تشغيل المسارات المختلفة (GET/POST) وإرجاع بيانات JSON صحيحة.
|
||||
2. **التحقق من حماية متغيرات البيئة (`.env` Security)**: محاولة استعراض ملف `.env` عبر المسار المباشر للتأكد من حظر الوصول العام إليه، وقراءته بنجاح من داخل تطبيق PHP.
|
||||
3. **فحص التحميل التلقائي**: التحقق من استدعاء كلاسات الـ Controllers والموديلات دون الحاجة لكتابة `require_once` يدوياً لكل ملف.
|
||||
|
||||
---
|
||||
|
||||
## المرحلة الرابعة: نظام التوثيق والمصادقة (Authentication Phase)
|
||||
|
||||
بناءً على النواة الأمنية التي تم تجهيزها (JWT, AES-256-GCM, Bcrypt, HMAC Blind Index)، سنقوم ببناء نظام المصادقة ليكون جاهزاً لإدارة جلسات المستخدمين.
|
||||
|
||||
### Proposed Changes
|
||||
|
||||
#### [NEW] `backend/app/Models/User.php`
|
||||
- كلاس يمتد من `BaseModel` لإدارة جدول `users`.
|
||||
- يحتوي على دالة `findByEmail` التي تقوم بتوليد (Blind Index HMAC) للبريد الإلكتروني للبحث السريع في قاعدة البيانات دون فك التشفير.
|
||||
- دالة `createSecure` لإنشاء مستخدم جديد مع تشفير بريده الإلكتروني وكلمة مروره.
|
||||
|
||||
#### [NEW] `backend/app/Controllers/AuthController.php`
|
||||
- دالة `login`: تستقبل البريد الإلكتروني وكلمة المرور، تتحقق منها عبر الموديل، وتولد JWT Token.
|
||||
- دالة `register` (اختيارية كأداة تطوير مبدئية أو للأدمن): إنشاء حساب موظف جديد.
|
||||
- دالة `me`: جلب بيانات المستخدم الحالي باستخدام الـ `AuthMiddleware` لاختبار سلامة الجلسة.
|
||||
|
||||
#### [MODIFY] `backend/public/index.php`
|
||||
- إضافة المسارات الخاصة بنظام التوثيق:
|
||||
- `POST /api/auth/login`
|
||||
- `GET /api/auth/me` (مرفق بـ `AuthMiddleware`)
|
||||
|
||||
### User Review Required
|
||||
## User Review Required
|
||||
|
||||
> [!IMPORTANT]
|
||||
> - هل ترغب بإنشاء مسار `POST /api/auth/register` مفتوح للجميع لإنشاء حسابات شركات جديدة؟ أم نكتفي حالياً بإنشاء مستخدم مدير (Admin) افتراضي يدوياً أو عبر سكربت ليكون النظام مغلقاً للشركات المعتمدة فقط؟
|
||||
> - في عملية تسجيل الدخول، هل نحتاج لإرجاع بيانات الشركة المرتبطة بالمستخدم ضمن نفس الـ Response، أم نكتفي بإرجاع التوكن (Token) وبيانات المستخدم الأساسية فقط؟
|
||||
> - **API Key Configuration**: We will authenticate the REST endpoints using a shared `ENTALEQ_API_KEY` defined in the `.env` file. Please ensure this environment variable is populated on your environment before calling these endpoints.
|
||||
> - **Direct Upload Path**: Decoded WhatsApp images will be saved under the public directory `backend/public/uploads/documents/` to ensure they are accessible via public URL paths.
|
||||
> - **Prompt Dialect**: The custom service prompt is written in a professional, warm Syrian dialect (اللهجة السورية) adhering to all business rules.
|
||||
|
||||
---
|
||||
|
||||
## المرحلة الخامسة: معالجة وإصلاح الثغرات الأمنية (Security Audit Remediation)
|
||||
## Proposed Changes
|
||||
|
||||
بناءً على التقرير الأمني الصادر، سنقوم بتطبيق التعديلات البرمجية لرفع مستوى أمان الخادم وحماية البيانات.
|
||||
### Database Schema Component
|
||||
|
||||
### Proposed Changes
|
||||
#### [NEW] [DriverOcrData.php](file:///Users/hamzaaleghwairyeen/development/App/nabeh/backend/app/Models/DriverOcrData.php)
|
||||
- Class extending `BaseModel` that manages the `driver_ocr_data` table.
|
||||
- Dynamically creates the table via `ensureTableExists()`.
|
||||
- Implements `saveSecure` to encrypt sensitive fields (`phone`, `name`, `password`, and all JSON OCR strings) using AES-256-GCM (`Security::encrypt()`) and generate search hashes (`Security::blindIndex()`).
|
||||
- Implements `findByPhone` to retrieve and decrypt records.
|
||||
|
||||
#### [MODIFY] [Security.php](file:///Users/hamzaaleghwairyeen/development/App/nabeh/backend/app/Core/Security.php)
|
||||
- إرجاع خطأ (Exception) فوراً في حال عدم وجود متغيرات البيئة (`ENCRYPTION_KEY`, `HMAC_SALT`, `JWT_SECRET`) لمنع تشفير البيانات بمفاتيح فارغة.
|
||||
---
|
||||
|
||||
#### [MODIFY] [BaseModel.php](file:///Users/hamzaaleghwairyeen/development/App/nabeh/backend/app/Models/BaseModel.php)
|
||||
- تنظيف وفلترة أسماء الأعمدة ديناميكياً باستخدام مصفوفة بيضاء (Whitelist Regex) لمنع ثغرات الـ SQL Injection عبر أسماء الأعمدة في دالتي `create()` و `update()`.
|
||||
### Gemini Service Component
|
||||
|
||||
#### [MODIFY] [SecurityMiddleware.php](file:///Users/hamzaaleghwairyeen/development/App/nabeh/backend/app/Middlewares/SecurityMiddleware.php)
|
||||
- إلغاء تطبيق `htmlspecialchars` و `strip_tags` على المدخلات الخام القادمة للخلفية لمنع تلف كلمات المرور والرموز الخاصة، وتأجيل التنظيف ليكون حصراً عند الطباعة/العرض (Output Encoding).
|
||||
#### [MODIFY] [GeminiService.php](file:///Users/hamzaaleghwairyeen/development/App/nabeh/backend/app/Services/GeminiService.php)
|
||||
- Add the `generateOcrFromImage` static method to support custom structured document analysis. It forwards custom prompts (e.g. green card OCR instructions) and base64 inline images to the `gemini-2.0-flash-lite` model.
|
||||
|
||||
#### [MODIFY] [AuthController.php](file:///Users/hamzaaleghwairyeen/development/App/nabeh/backend/app/Controllers/AuthController.php)
|
||||
- إزالة التنظيف المزدوج (Double Encoding) لأسماء المستخدمين والشركات.
|
||||
---
|
||||
|
||||
#### [MODIFY] [Router.php](file:///Users/hamzaaleghwairyeen/development/App/nabeh/backend/app/Core/Router.php)
|
||||
- إخفاء مسار الملفات الحقيقي من رسائل الخطأ 404 و 500 وإظهار رسائل عامة لمنع تسريب بنية المجلدات (Information Disclosure).
|
||||
### Dashboard Component
|
||||
|
||||
#### [MODIFY] [Response.php](file:///Users/hamzaaleghwairyeen/development/App/nabeh/backend/app/Core/Response.php)
|
||||
- جعل رابط الـ CORS ديناميكياً يعتمد على متغير بيئة `ALLOWED_ORIGIN` بدلاً من فتح النطاق للجميع عبر `*`.
|
||||
#### [MODIFY] [index.html](file:///Users/hamzaaleghwairyeen/development/App/nabeh/backend/public/index.html)
|
||||
- Add the new prompt template button: `<button type="button" class="btn btn-secondary" @click="loadPromptTemplate('intaleq')">قالب خدمة عملاء انطلق (سوري)</button>`.
|
||||
- Add `intaleq` template case inside `loadPromptTemplate(type)` to load the full customer service system instruction prompt.
|
||||
|
||||
#### [MODIFY] [bootstrap.php](file:///Users/hamzaaleghwairyeen/development/App/nabeh/backend/app/bootstrap.php)
|
||||
- تسجيل معالج أخطاء عام (`set_exception_handler` / `set_error_handler`) لتحويل الأخطاء الفادحة غير المعالجة إلى استجابات JSON نظيفة ومخفية في الإنتاج، مع تسجيل التفاصيل التقنية في الـ `error_log` فقط.
|
||||
---
|
||||
|
||||
#### [MODIFY] [Request.php](file:///Users/hamzaaleghwairyeen/development/App/nabeh/backend/app/Core/Request.php)
|
||||
- تعريف الخصائص المعرفية (`$user_id`, `$company_id`, `$role`) بشكل صريح لتفادي مشاكل الخصائص الديناميكية (Dynamic Properties Deprecation) في إصدارات PHP 8.2+.
|
||||
### Conversation Flow Component
|
||||
|
||||
#### [NEW] [RateLimitMiddleware.php](file:///Users/hamzaaleghwairyeen/development/App/nabeh/backend/app/Middlewares/RateLimitMiddleware.php)
|
||||
- بناء فلتر مخصص للحد من معدل الطلبات (Rate Limiting) على مسارات تسجيل الدخول والتسجيل لحماية التطبيق من محاولات التخمين العنيف (Brute Force).
|
||||
#### [NEW] [DriverRegistrationFlow.php](file:///Users/hamzaaleghwairyeen/development/App/nabeh/backend/app/Core/Flows/DriverRegistrationFlow.php)
|
||||
- Implement a step-by-step driver registration state machine.
|
||||
- Steps:
|
||||
1. `start`: Welcome message, request full name.
|
||||
2. `ask_name`: Save name, request password.
|
||||
3. `ask_password`: Validate password, request ID Front image.
|
||||
4. `id_front`: Run `id_front_sy` Gemini OCR prompt. Request ID Back.
|
||||
5. `id_back`: Run `id_back_sy` Gemini OCR prompt. Request Driving License Front.
|
||||
6. `driving_license_front`: Run `driving_license_sy_front` Gemini OCR prompt. Request Driving License Back.
|
||||
7. `driving_license_back`: Run `driving_license_sy_back` Gemini OCR prompt. Request Vehicle License Front.
|
||||
8. `vehicle_license_front`: Run `vehicle_license_sy_front` Gemini OCR prompt. Request Vehicle License Back.
|
||||
9. `vehicle_license_back`: Run `vehicle_license_sy_back` Gemini OCR prompt. Request Criminal Record (لا حكم عليه).
|
||||
10. `criminal_record`: Save document, update status to `ocr_completed`, save to `driver_ocr_data` table, and conclude.
|
||||
|
||||
#### [MODIFY] [ConversationFlowEngine.php](file:///Users/hamzaaleghwairyeen/development/App/nabeh/backend/app/Core/Flows/ConversationFlowEngine.php)
|
||||
- Add trigger mappings: `'تسجيل' => 'driver_registration_flow'`, `'سجل' => 'driver_registration_flow'`, and `'register' => 'driver_registration_flow'`.
|
||||
- Register the flow class: `'driver_registration_flow' => DriverRegistrationFlow::class`.
|
||||
|
||||
---
|
||||
|
||||
### REST API Component
|
||||
|
||||
#### [MODIFY] [index.php](file:///Users/hamzaaleghwairyeen/development/App/nabeh/backend/public/index.php)
|
||||
- تفعيل فلتر الحد من معدل الطلبات على مسارات الحماية.
|
||||
- Define 2 REST API endpoints:
|
||||
- `GET /api/external/driver-ocr`: Accepts a query parameter `phone`. Authenticates against `ENTALEQ_API_KEY`. Retrieves and decrypts driver documents, OCR logs, and password details.
|
||||
- `POST /api/external/register-driver`: Accepts a `phone` body parameter. Authenticates against `ENTALEQ_API_KEY`. Marks the local record status as `registered` (confirming transfer to primary DB).
|
||||
|
||||
### User Review Required
|
||||
---
|
||||
|
||||
> [!IMPORTANT]
|
||||
> هل نعتمد نظام تخزين المحاولات للحد من معدل الطلبات (Rate Limiting) في ملفات مؤقتة داخل مجلد `storage/` محلي (سهل الإعداد ومستقل)، أم نستخدم جدولاً مخصصاً في قاعدة البيانات؟
|
||||
|
||||
</div>
|
||||
## Verification Plan
|
||||
|
||||
### Manual Verification
|
||||
1. Open the dashboard, click **قالب خدمة عملاء انطلق (سوري)**, and verify the prompt loads.
|
||||
2. Send a WhatsApp message to the bot saying `"تسجيل"` and follow the registration wizard. Send test images for each stage, verifying database storage and Gemini OCR parsing logs.
|
||||
3. Query the `GET /api/external/driver-ocr` endpoint using `curl` with the header `X-API-Key: your_key` and confirm decrypted data is returned.
|
||||
4. Execute `POST /api/external/register-driver` with the API key header and confirm the record status updates to `registered`.
|
||||
|
||||
Reference in New Issue
Block a user