Update: 2026-08-02 17:52:28
This commit is contained in:
@@ -45,6 +45,12 @@ DB_TRANSIT_NAME=siroTransitDb
|
||||
DB_TRANSIT_USER=siroTransitUser
|
||||
DB_TRANSIT_PASS=eZiDYxCJ2yyGfC32zG0Z
|
||||
|
||||
DB_FOOD_HOST=mysql
|
||||
DB_FOOD_PORT=3306
|
||||
DB_FOOD_NAME=siro_food
|
||||
DB_FOOD_USER=siro_food
|
||||
DB_FOOD_PASS=CHANGE_ME_STRONG_PASSWORD
|
||||
|
||||
# --- 3. Redis ---
|
||||
REDIS_HOST=redis
|
||||
REDIS_PORT=6379
|
||||
@@ -131,6 +137,15 @@ APP_DEEP_LINK_BASE=https://siromove.com/driver/transit-activate
|
||||
|
||||
SIRO_COMMISSION_JO=0.15
|
||||
SIRO_COMMISSION_SY=0.12
|
||||
|
||||
# --- 10. Food Orders (طلبات الطعام) ---
|
||||
FOOD_ENABLED=true
|
||||
FOOD_SOCKET_URL=http://socket_food:4041
|
||||
FOOD_SOCKET_PORT=14040
|
||||
FOOD_MERCHANT_ORIGINS=https://food-merchant.siromove.com,https://admin.siromove.com
|
||||
FOOD_COMMISSION_PERCENT=15
|
||||
FOOD_DELIVERY_BASE_FEE=
|
||||
FOOD_MAX_ACTIVE_ORDERS_PER_USER=3
|
||||
SIRO_COMMISSION_EG=0.10
|
||||
SIRO_COMMISSION_IQ=0.14
|
||||
|
||||
|
||||
@@ -77,3 +77,34 @@ watch -n2 'curl -s http://localhost:8080/fpm-status' # طابور
|
||||
- المكان الوحيد الذي يُخسر فيه أداء فعلاً: كتابة قاعدة البيانات فوق overlayfs — **محلول** بـ volume مسمّى (`mysql-data`).
|
||||
- أداء PHP الحقيقي يصنعه opcache + مقاس حوض fpm + فهارس MySQL — كلها مضبوطة في `php/` وليست متعلقة بالدوكر أصلاً.
|
||||
- التقسيم إلى 6 حاويات لا يكلف أداءً (نفس العمليات) ويعطي: إعادة تشغيل خدمة وحدها، حدود ذاكرة لكل خدمة، لوغات منفصلة، واستنساخ عميل = `clone + .env + up`.
|
||||
|
||||
## 6) Mawasalati (transit) — حاوية php-fpm معزولة
|
||||
- الخدمة `php_transit` منفصلة تماماً عن `php` الرئيسي: صورة مختلفة (`php/Dockerfile.fpm.transit`، بدون composer/vendor)، حوض fpm أصغر (`php/www-pool.transit.conf`، 16 عامل)، وحدّ ذاكرة 512m خاص بها.
|
||||
- الملفات المرَكَّبة داخلها فقط: `backend/core` (read-only — JWT/Database/RateLimiter المشتركة) و`backend/functions.php` (read-only) و`backend/transit` (rw). لا صلة بـ`backend` الرئيسي كاملاً ولا `payment_server/v2` ولا `loction_server`.
|
||||
- التوجيه في nginx: أي طلب يطابق `^/backend/transit/.*\.php$` يذهب إلى `php_transit:9000` بدل `php:9000` — هذا location يجب أن يبقى **قبل** الـ `location ~ \.php$` العام في `nginx/default.conf`.
|
||||
- المشترك الوحيد فعلياً مع النظام الأساسي: مصادقة JWT للسائق/الراكب (`backend/core`)، ونفس `mysql`/`redis` (قاعدة `transit` منفصلة أصلاً عبر `Database::get('transit')`).
|
||||
- انهيار أو ازدحام `php` الرئيسي لا يوقف Mawasalati، والعكس صحيح.
|
||||
- **cron jobs** (`cron_sync_members.php`, `cron_cleanup.php`, `cron_approaching_alerts.php`): تبقى تُستدعى من crontab المضيف كما هي حالياً (لا تغيير) — الملفات ما تزال متاحة من حاوية `php` الرئيسية أيضاً لأن `../backend` كاملة ما تزال مركّبة فيها.
|
||||
|
||||
## 7) طلبات الطعام (food) — نفس نمط العزل
|
||||
|
||||
- الخدمتان `php_food` و`socket_food` منفصلتان تماماً عن `php` الرئيسي وعن `php_transit`، بنفس منطق §6: صورة `php/Dockerfile.fpm.transit` (fpm خفيفة بلا composer، مُعاد استخدامها لأن الطعام أيضاً لا يحتاج vendor)، حوض `php/food-pool.conf` (24 عاملاً)، حد ذاكرة 768m لـ`php_food` و512m لـ`socket_food`.
|
||||
- الملفات المرَكَّبة داخل `php_food` فقط: `backend/core` (ro)، `backend/functions.php` (ro)، `backend/food` (rw). لا صلة بـ`backend` الرئيسي ولا `payment_server/v2` ولا `loction_server`.
|
||||
- التوجيه في nginx: `^/backend/food/.*\.php$` يذهب إلى `php_food:9000`، ويجب أن يبقى **قبل** الـ location العام.
|
||||
- `socket_food` — WS بورت 4040 (يتطلب TLS من nginx المضيف مثل بقية السوكيتات، انظر §… أعلاه) + HTTP داخلي 4041 يستقبل نداءات من `php_food` بمفتاح `X-Internal-Key` (نفس `INTERNAL_SOCKET_KEY`) لدفع تحديثات حالة الطلب لحظياً — نفس نمط `broadcast_bus_location` في مواصلاتي، وليس Redis pub/sub.
|
||||
- قاعدة `siro_food` منفصلة تماماً (`Database::get('food')`، ممنوع `Database::get('main')` داخل `backend/food/`)، والمحفظة/الدفع/JWT/FCM مشتركة مع النظام الرئيسي — نفس مبدأ transit تماماً، موثّق بالتفصيل في [docs/10_food_orders/FOOD_ORDERS_PLAN_AR.md](../docs/10_food_orders/FOOD_ORDERS_PLAN_AR.md).
|
||||
- `FOOD_ENABLED=false` في `.env` يُرجع 503 من كل بوابات `backend/food/*` فوراً بلا نشر جديد — مفتاح التراجع الأول.
|
||||
- **الحالة الحالية: المراحل صفر–الرابعة مبنية على فرع `feature/food-delivery-module`** (غير مُلتزم بها على main، وغير مُختبرة على بيئة حقيقية):
|
||||
- **صفر — التأسيس**: حاويتان، nginx، `Database::get('food')`، `schema_food.sql`، بوابات الزبون/المطعم/السائق/الإدارة.
|
||||
- **الأولى — الكتالوج**: تصفح/بحث/تفاصيل مطعم، اعتماد إداري للمطاعم، دخول لوحة المطعم، تفعيل/إيقاف صنف.
|
||||
- **الثانية — الطلب**: `cart/quote.php` (تسعير من الخادم فقط، موقّع بـ HMAC صالح 10 دقائق)، `order/create.php` (idempotent عبر `client_order_uuid`، آلة الحالة `food_transition_status()`)، `order/status.php|cancel.php|rate.php|history.php`، `merchant_ops/accept.php|reject.php|preparing.php|ready.php`.
|
||||
- **الثالثة — التوصيل**: `courier/toggle_availability.php|offer_respond.php|picked_up.php|delivered.php|active.php`، قفل ذرّي `SET NX EX 20` يمنع سباق القبول، `cron_order_timeouts.php` لإعادة العرض بعد المهلة وإلغاء الطلبات المعلّقة.
|
||||
- **الرابعة — المال**: خصم/استرجاع فوري من المحفظة عبر نفس عقد `initiate_prime.php` S2S، `admin/payouts.php` لتوليد تقرير تسوية المطاعم.
|
||||
|
||||
**⚠️ ثلاث نقاط تحتاج تأكيداً حقيقياً قبل أي تشغيل بمال فعلي — موثّقة كتعليقات صريحة في الكود نفسه (`food/functions.php`)، وليست تفاصيل تنفيذ ثانوية**:
|
||||
1. **لا يوجد حجز حقيقي (hold/capture)**: سيرفر المحفظة الخارجي لا يعرض API حجز مسبق — التنفيذ الحالي هو خصم فوري عند إنشاء الطلب + استرجاع كامل عند الرفض/الإلغاء. إن أُضيف hold حقيقي لاحقاً، `foodWalletMove()` هو أول مكان يُعدَّل.
|
||||
2. **عامل تحويل العملة غير مؤكَّد**: `FOOD_CURRENCY_DIVISOR` (افتراضي 1000، أي fils) يحوّل "أصغر وحدة نقدية" في `siro_food` إلى المبلغ العشري الذي يتوقعه سيرفر المحفظة — يجب تأكيده مع فريق المحفظة.
|
||||
3. **لا تحويل آلي لأرباح السائقين**: العقد S2S المؤكد فقط لتحويلات سائق↔سائق (`driverWallet/transfer.php`)، لا لإيداع أرباح من المنصة مباشرة إلى محفظة سائق. أرباح التوصيل (`delivery_fee`) وديون التحصيل النقدي تُسجَّل محاسبياً فقط في `food_order_payments` (نوع `courier_payout` / `cash_settlement`) بحالة `pending` — **لا صرف فعلي بعد**.
|
||||
4. **أسطول التوصيل معزول عمداً عن `loction_server`**: لا تعديل على `driver_socket.php` الحي. السائق يُفعّل "وضع التوصيل" فيُضاف إلى SET مستقلة `food:couriers:opted_in` نتقاطع معها مع `geo:drivers:available` (قراءة فقط).
|
||||
|
||||
**لم يُبنَ بعد**: المرحلة الخامسة (التقسية والإطلاق — مراجعة أمنية مخصصة، اختبار ضغط، إطلاق تدريجي)، وربط الصرف الفعلي بمجرد تأكيد النقاط الثلاث أعلاه.
|
||||
|
||||
@@ -23,6 +23,8 @@ services:
|
||||
- ../dashboard:/var/www/dashboard:ro
|
||||
depends_on:
|
||||
- php
|
||||
- php_transit
|
||||
- php_food
|
||||
mem_limit: 256m
|
||||
restart: unless-stopped
|
||||
|
||||
@@ -48,6 +50,75 @@ services:
|
||||
mem_limit: 2g
|
||||
restart: unless-stopped
|
||||
|
||||
# php-fpm معزولة لخدمة Mawasalati (transit) — حاوية مستقلة عن الباك إند الرئيسي.
|
||||
# المشترك الوحيد مع النظام الأساسي: JWT ومصادقة السائق/الراكب عبر backend/core
|
||||
# (نُركّبها read-only)، ونفس mysql/redis. لا صلة بـ backend الرئيسي ولا payment v2،
|
||||
# ولا تتأثر Mawasalati إذا امتلأ pool الباك إند الرئيسي أو انهار.
|
||||
php_transit:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: docker/php/Dockerfile.fpm.transit
|
||||
args:
|
||||
PHP_VERSION: "${PHP_VERSION:-8.2}"
|
||||
volumes:
|
||||
- ../backend/core:/var/www/backend/core:ro
|
||||
- ../backend/functions.php:/var/www/backend/functions.php:ro
|
||||
- ../backend/transit:/var/www/backend/transit
|
||||
- ./php/opcache.ini:/usr/local/etc/php/conf.d/zz-opcache.ini:ro
|
||||
- ./php/www-pool.transit.conf:/usr/local/etc/php-fpm.d/zz-pool.conf:ro
|
||||
- ./keys:/keys:ro
|
||||
env_file: .env
|
||||
depends_on:
|
||||
- mysql
|
||||
- redis
|
||||
mem_limit: 512m
|
||||
restart: unless-stopped
|
||||
|
||||
# php-fpm معزولة لوحدة طلبات الطعام — نفس منطق عزل php_transit.
|
||||
# المشترك الوحيد: JWT (backend/core) ونفس mysql/redis. قاعدة siro_food منفصلة.
|
||||
php_food:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: docker/php/Dockerfile.fpm.transit
|
||||
args:
|
||||
PHP_VERSION: "${PHP_VERSION:-8.2}"
|
||||
volumes:
|
||||
- ../backend/core:/var/www/backend/core:ro
|
||||
- ../backend/functions.php:/var/www/backend/functions.php:ro
|
||||
- ../backend/food:/var/www/backend/food
|
||||
- ./php/opcache.ini:/usr/local/etc/php/conf.d/zz-opcache.ini:ro
|
||||
- ./php/food-pool.conf:/usr/local/etc/php-fpm.d/zz-pool.conf:ro
|
||||
- ./keys:/keys:ro
|
||||
env_file: .env
|
||||
depends_on:
|
||||
- mysql
|
||||
- redis
|
||||
mem_limit: 768m
|
||||
restart: unless-stopped
|
||||
|
||||
# سوكيت الطعام — WS بورت 4040 + HTTP داخلي 4041
|
||||
socket_food:
|
||||
build:
|
||||
context: ./php
|
||||
dockerfile: Dockerfile.socket
|
||||
args:
|
||||
PHP_VERSION: "${PHP_VERSION:-8.2}"
|
||||
command: ["php", "food_socket.php", "start"]
|
||||
working_dir: /app
|
||||
volumes:
|
||||
- ../food_server:/app
|
||||
- ./keys:/keys:ro
|
||||
env_file: .env
|
||||
ports:
|
||||
# نفس منطق سوكيت السائقين: لا نفتح 4040 للعالم مباشرة — nginx على
|
||||
# المضيف يستمع 4040 بالشهادة ويمرّر إلى 14040 هنا. 4041 داخلي فقط
|
||||
# (الباك إند يناديه عبر http://socket_food:4041).
|
||||
- "127.0.0.1:${FOOD_SOCKET_PORT:-14040}:4040"
|
||||
depends_on:
|
||||
- redis
|
||||
mem_limit: 512m
|
||||
restart: unless-stopped
|
||||
|
||||
# سوكيت السائقين (Workerman + PHPSocketIO) — WS بورت 2020 + HTTP داخلي 2021
|
||||
# عملية دائمة، لا علاقة لها بـ fpm — حاوية مستقلة إجبارياً.
|
||||
socket_driver:
|
||||
|
||||
@@ -17,6 +17,30 @@ server {
|
||||
access_log /dev/stdout;
|
||||
error_log /dev/stderr warn;
|
||||
|
||||
# Mawasalati (transit) — حاوية php-fpm معزولة عن الباك إند الرئيسي.
|
||||
# يجب أن يسبق location ~ \.php$ العام حتى لا يلتقطه أولاً.
|
||||
location ~ ^/backend/transit/.*\.php$ {
|
||||
try_files $uri =404;
|
||||
include fastcgi_params;
|
||||
fastcgi_pass php_transit:9000;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_read_timeout 60s;
|
||||
fastcgi_buffers 16 16k;
|
||||
fastcgi_buffer_size 32k;
|
||||
}
|
||||
|
||||
# طلبات الطعام — حاوية php-fpm معزولة عن الباك إند الرئيسي.
|
||||
# يجب أن يسبق location ~ \.php$ العام حتى لا يلتقطه أولاً.
|
||||
location ~ ^/backend/food/.*\.php$ {
|
||||
try_files $uri =404;
|
||||
include fastcgi_params;
|
||||
fastcgi_pass php_food:9000;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_read_timeout 60s;
|
||||
fastcgi_buffers 16 16k;
|
||||
fastcgi_buffer_size 32k;
|
||||
}
|
||||
|
||||
location ~ \.php$ {
|
||||
try_files $uri =404;
|
||||
include fastcgi_params;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# صورة معزولة لخدمة Mawasalati (transit) — لا composer، لا vendor مشترك
|
||||
# نفس الامتدادات الأساسية فقط. لا صلة بـ backend الرئيسي أو payment v2.
|
||||
ARG PHP_VERSION=8.2
|
||||
FROM php:${PHP_VERSION}-fpm
|
||||
|
||||
ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
|
||||
RUN chmod +x /usr/local/bin/install-php-extensions && \
|
||||
install-php-extensions mysqli pdo_mysql redis opcache gd
|
||||
|
||||
WORKDIR /var/www
|
||||
@@ -0,0 +1,16 @@
|
||||
; حوض fpm لوحدة الطعام — معزول عن حوض الرحلات الرئيسي
|
||||
[www]
|
||||
pm = dynamic
|
||||
pm.max_children = 24
|
||||
pm.start_servers = 4
|
||||
pm.min_spare_servers = 2
|
||||
pm.max_spare_servers = 8
|
||||
pm.max_requests = 1000
|
||||
pm.status_path = /status
|
||||
slowlog = /proc/self/fd/2
|
||||
request_slowlog_timeout = 3s
|
||||
|
||||
catch_workers_output = yes
|
||||
decorate_workers_output = no
|
||||
php_admin_value[error_log] = /proc/self/fd/2
|
||||
php_admin_flag[log_errors] = on
|
||||
@@ -0,0 +1,17 @@
|
||||
; حوض fpm صغير — ترافيك Mawasalati أقل بكثير من الباك إند الرئيسي
|
||||
; حصة الحاوية 512m، ما في داعي لنفس حجم pool الرئيسي (48 عامل)
|
||||
[www]
|
||||
pm = dynamic
|
||||
pm.max_children = 16
|
||||
pm.start_servers = 3
|
||||
pm.min_spare_servers = 2
|
||||
pm.max_spare_servers = 6
|
||||
pm.max_requests = 1000
|
||||
pm.status_path = /status
|
||||
slowlog = /proc/self/fd/2
|
||||
request_slowlog_timeout = 3s
|
||||
|
||||
catch_workers_output = yes
|
||||
decorate_workers_output = no
|
||||
php_admin_value[error_log] = /proc/self/fd/2
|
||||
php_admin_flag[log_errors] = on
|
||||
Reference in New Issue
Block a user