Deploy: 2026-05-22 21:52:51

This commit is contained in:
Hamza-Ayed
2026-05-22 21:52:51 +03:00
parent 5269789b51
commit 8acca92bba
12 changed files with 1938 additions and 285 deletions

View File

@@ -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`.