feat: استيراد كود سيرو إلى تريبز (سيرو @ecfe7568) — بلا تعديل
قرار المالك 2026-07-27: باك إند سيرو PHP هو المعتمد، وتطبيقاته المجرّبة ميدانياً تحل محل إعادة البناء المؤرشفة. سيرو نفسه لم يُمسّ. الخريطة: backend · payment_server · loction_server · ride_server · passenger_server · docker · dashboard · stress_test → الجذر siro_rider → apps/rider siro_driver → apps/driver siro_admin → dashboards/admin siro_service → dashboards/service android_bot → apps/android_bot socialBot → apps/socialBot نُسخ المتعقَّب في git سيرو فقط عبر `git archive` (3,198 ملفاً / ~169 م.ب) لا `cp -r` — فاستُثنيت مخلفات البناء تلقائياً. بلا أي تعديل محتوى عمداً: كل ما يلي يصير فرقاً مقروءاً مقابل المصدر. لم يُستورد وسببه: siromove.com (الموقع التسويقي يبقى marketing/ في تريبز، سيرو فيه 8 ملفات) · docs و planning (تريبز له docs/ الخاص) · deploy.sh (ليس نشراً على سيرفر بل `git add . && git push origin --all` — فخّ في مستودع آخر) · transit_dashboard (بانتظار قرار مصير backend-transit و dashboards/transit-web). ⚠️ لا يبني بعد — ثلاثة نواقص متوقعة ومقصودة: 1. `.env` و `lib/env/env.g.dart` غير متعقَّبين في سيرو (أسرار لكل مستأجر): كل تطبيق فلاتر يحتاج .env خاصاً ثم توليد env.g.dart بـ build_runner. 2. إعدادات Firebase (9 ملفات google-services.json و GoogleService-Info.plist) يستبعدها .gitignore تريبز — ولكل مستأجر مشروع Firebase خاص أصلاً. 3. apps/driver في سيرو يشير إلى `../../Intaleq/packages/get` خارج المستودع → يجب ضمّ الحزم داخله أسوة بـ apps/rider. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
9909d9b4c1
commit
4d8414c96b
@@ -0,0 +1,159 @@
|
||||
# ============================================================
|
||||
# Siro Docker Environment Variables
|
||||
# ============================================================
|
||||
|
||||
# --- 1. Core Settings ---
|
||||
PHP_VERSION=8.2
|
||||
HTTP_PORT=8181
|
||||
APP_DOMAIN=jordan-siro.intaleqapp.com
|
||||
APP_ISSUER=SiroApp
|
||||
APP_DEBUG=true
|
||||
APP_COUNTRY=Jordan
|
||||
APP_CURRENCY=JOD
|
||||
|
||||
# --- 2. Databases (Hosts must be 'mysql' in Docker) ---
|
||||
MYSQL_ROOT_PASSWORD=3w71Qacjl3kh1pOgJUeD5jRBnG3jRVpf
|
||||
|
||||
DB_PAYMENT_HOST=mysql
|
||||
DB_PAYMENT_NAME=payment
|
||||
DB_PAYMENT_USER=root
|
||||
DB_PAYMENT_PASS=3w71Qacjl3kh1pOgJUeD5jRBnG3jRVpf
|
||||
|
||||
DB_PRIMARY_HOST_V2=mysql
|
||||
DB_PRIMARY_NAME_V2=jorSiroDB
|
||||
DB_PRIMARY_USER_V2=intaleqapp-jordan-siro
|
||||
DB_PRIMARY_PASS_V2=7B7skfibrexQrGCUG1Y8
|
||||
|
||||
DB_PRIMARY_HOST=mysql
|
||||
DB_PRIMARY_NAME=intaleqDB1
|
||||
DB_PRIMARY_USER=intaleqUserDB1
|
||||
DB_PRIMARY_PASS=NANatr7j4d8HzZjAcp00bbsjkdhfjsn
|
||||
|
||||
DB_TRACKING_HOST=mysql
|
||||
DB_TRACKING_NAME=locationDB
|
||||
DB_TRACKING_USER=intaleqLocation
|
||||
DB_TRACKING_PASS=9otdMyiExMTXwnoA32sP
|
||||
|
||||
DB_RIDE_HOST=mysql
|
||||
DB_RIDE_NAME=intaleq-ridesDB
|
||||
DB_RIDE_USER=intaleq-rides
|
||||
DB_RIDE_PASS=0bHHMALEj4sqSmdT0avT
|
||||
|
||||
DB_TRANSIT_HOST=mysql
|
||||
DB_TRANSIT_PORT=3306
|
||||
DB_TRANSIT_NAME=siroTransitDb
|
||||
DB_TRANSIT_USER=siroTransitUser
|
||||
DB_TRANSIT_PASS=eZiDYxCJ2yyGfC32zG0Z
|
||||
|
||||
# --- 3. Redis ---
|
||||
REDIS_HOST=redis
|
||||
REDIS_PORT=6379
|
||||
REDIS_LOCATION_HOST=redis
|
||||
REDIS_LOCATION_PORT=6379
|
||||
REDIS_MAIN_HOST=redis
|
||||
REDIS_MAIN_PORT=6379
|
||||
REDIS_MAIN_PASSWORD=
|
||||
|
||||
# --- 4. Internal Sockets (Docker Network Names) ---
|
||||
LOCATION_SERVER_URL=http://socket_driver:2021
|
||||
RIDE_SOCKET_URL=http://socket_passenger:3031
|
||||
# ⚠️ إجباري في Docker: بدونه يستخدم driver_socket.php الافتراضي 127.0.0.1:3031
|
||||
# وهو داخل حاوية socket_driver يشير لنفسها، فلا يصل الراكب أي تحديث موقع.
|
||||
PASSENGER_SOCKET_INTERNAL_URL=http://socket_passenger:3031
|
||||
|
||||
# --- 5. External Sockets & URLs ---
|
||||
LOCATION_SOCKET_URL=http://socket_driver:2021
|
||||
PASSENGER_SOCKET_URL=http://socket_passenger:3031
|
||||
LOCATION_API_URL=http://nginx/loction_server/api_get_nearby.php
|
||||
WALLET_SERVER_JORDAN=http://nginx
|
||||
WALLET_SERVER_EGYPT=http://nginx
|
||||
WALLET_SERVER_SYRIA=http://nginx
|
||||
|
||||
# --- 6. JWT, Encryption & Secrets ---
|
||||
# JWT_SECRET_KEY=
|
||||
# JWT_SECRET=
|
||||
# INTERNAL_KEY=
|
||||
TRACKING_SECRET_SALT=RaIt3bznBXIHJAtpaBz7JHFwcec9JFyzOXaoIZKG
|
||||
secretSaltParent=Q4g2XFGMY2aSTp1kq6RaIt3bznBXIHJAtpaBz7JHFwcec
|
||||
MIGRATION_ADMIN_KEY=iuyweiruinakjbfkajkjlkmalkcxnlahd
|
||||
FP_PEPPER=cd0b94f349c292bf93c63e798b903bb4b3b3738a049654441d6524ba603d614147fbc24b2721090d713d4fe3fbe833985c9a4473233963ac544045da5cd4wef
|
||||
SECRET_KEY_HMAC=WnzEwFNArO0YlTapvfhtmguKWsXJSKqg_NZSjHBYVXMZK1yUK88SobdckV0KuPaBh0c2721090d713d4fe3fbe833985c9a4473233963ac544045da5cd41bd5
|
||||
SECRET_KEY=cd0b94f349c292bf93c63e798b903bb4b3b3738a049654441d6524ba603d614147fbc24b2721090d713d4fe3fbe833985c9a4473233963ac544045da5cd41bd5
|
||||
passwordnewpassenger=$2y$10$0WYS/2Fz9BTtoyCbTusudOG9JgTO3DqCPWBhS2Cf9gIu3H9KoSZKC
|
||||
initializationVector=abcdefghijklmnop
|
||||
|
||||
# ⚠️ تحذير مسارات الملفات السرية:
|
||||
# في اللايف كانت هذه الملفات خارج مجلد htdocs. في الدوكر يجب وضع هذه الملفات داخل مجلد منفصل لتبقى آمنة.
|
||||
# لقد قمت ببرمجة الدوكر ليقرأ مجلد docker/keys ويربطه بالمسار /keys/ المعزول تماماً عن الويب (لأن مسار الويب هو /var/www).
|
||||
# (عليك إنشاء المجلد docker/keys ونسخ المفاتيح إليه)
|
||||
SECRET_KEY_PATH=/keys/.secret_key
|
||||
SECRET_KEY_PAY_PATH=/keys/.secret_key_pay
|
||||
INTERNAL_SOCKET_KEY_PATH=/keys/.internal_socket_key
|
||||
JWT_SECRET_KEY_PATH=/keys/.secret_key
|
||||
WALLET_SECRET_KEY_PATH=/keys/.secret_key_pay
|
||||
ENCRYPTION_KEY_PATH=/keys/.enckey
|
||||
PAYMENT_INTERNAL_KEY_PATH=/keys/.internal_socket_key
|
||||
|
||||
# --- 7. Third-Party APIs ---
|
||||
GEMINI_API_KEY=AIzaSyDHp0yXCGWqnd4ynlCCWzDz9Un1EJOKeW8
|
||||
SMS_API_ENDPOINT=https://sms.kazumi.me/api/sms/send-sms
|
||||
VOICE_CALL_API_KEY=405e47af5fff47a4b2f5e6acb7ec8960e4d7fe0d1cf3544552b978231f864285
|
||||
HERE_API0=g_WNUb5L-7-F8oHpUmgIzH7ETeH9xZ8RwGG9_G8zX9A
|
||||
HERE_API=-u3ySR74FH46wS-7IP59BP-Ih6pTx47CwKx_aQw0Sp4
|
||||
keyOfApp=nqryjp@1737wqnmqqsjyzjujC1jYRSgh
|
||||
PAYMENT_KEY=f4b29e139e7287109bcdd755882a3002
|
||||
payMobApikey=S40PAVPQiTp+nOL4UQ4g2XFGMY2aSTp1kq6RaIt3bznBXIHJAtpaBz7JHFwcec9JFyzOXaoIZKGPfE5jyfnIlj/A90Kes1qwmwJdOKz0gINtVZcgX9dd0KIgiE34RC5eRn9co3PFpGENlxXUVZOXkQ5c00tBRsOIRXSedSs8L4u+YSQwfMQZLOX18vrLWh4yEGQPLLm3cUglC65DmkyiLPvwdBST53eFlqj4GD/L5qgBLw8zPPnUMZ2VIvAsTKIzLBxq3QmvSzU1bZ6gqscEHwwwDjfxD6j0Z8hlRgUfrOfVgGD9prY2SFzdeZxRSMqjBuwPrva+51/OxT4yf3uxozJs+HEVhl5AJ2CsSZ+k4Po=
|
||||
PASSWORDPAYMOB=g@nkD2#99!hD_.wXrXlBl
|
||||
PAYMOBOUTCLIENTSECRET=xyjjRlahJM0Xc38WjApCOh8bvgL9slFpNdM9YeCu9AhLqboKMPtmSvc2N9O4tXxFLV2JAV6stBSTAGFGCVubGe6MNpc7MzJnZ3SiT6GpavBoCLWkUvVbdSDaM0zHvuBOXrXlBl
|
||||
PAYMOBOUTCLIENT_ID=Z05ut48dVkS2gI2zenFFcKsfDKfHAU0WELqKyJ0LXrXlBl
|
||||
PayPalClientIdLive=QZFjAoZfGtngNserll6r3cC56Xl1sVLQkn5dMbyebhzJY59EQ3hz7YxaEqEDYPTUFcQWqvePaQ5UJJVRXrXlBl
|
||||
SMSPASSWORDEGYPT=J)Vh=qb/@MXrXlBl
|
||||
CLAUDAISEFER=zg-qbc-qvo39-vCB-WnzEwFNArO0YlTapvfhtmguKWsXJSKqg_NZSjHBYVXMZK1yUK88SobdckV0KuPaBh0c_WHtGsRO_439PBk-e2QqgkQQXrXlBl
|
||||
FIREBASE_SERVICE_ACCOUNT_PATH=/var/www/backend/keys/service-account.json
|
||||
RASEEL_DRIVER_INSTANCE_ID=686510D4C41E0
|
||||
RASEEL_DRIVER_ACCESS_TOKEN=68617b9b8fe53
|
||||
|
||||
# --- 8. App Signatures & Versions ---
|
||||
APP_SIGNATURE_SERVICE_DEBUG=08c3a281699d01bda0473c5dd33536f89dec2f77da8d45c3ba5285959066fa0e
|
||||
APP_SIGNATURE_SERVICE_RELEASE=4f10b4e929e05e0a3eaeb0314cc13adbcbe6ffdf6af585fc68fec1e4b6296b6f
|
||||
APP_SIGNATURE_SERVICE_IOS=com.example.serviceIntaleq
|
||||
|
||||
# --- 9. Nabeh & Transit & Commisions ---
|
||||
NABEH_EMAIL=hamza@test.com
|
||||
NABEH_PASSWORD=Test1234!
|
||||
NABEH_API_KEY=siro_integration_key_789
|
||||
NABEH_OTP_APP_KEY=f3a9e7c1b8d5f2a4c6e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1
|
||||
|
||||
VITE_API_BASE=https://jordan-siro.intaleqapp.com/backend/transit
|
||||
TRANSIT_STUDENT_ID_KEY=zH34tS6xMMSamq6uqv1WZWlDrmjAbnMk
|
||||
TRANSIT_ADMIN_ORIGINS=https://transit.siromove.com,https://admin.siromove.com
|
||||
APP_DEEP_LINK_BASE=https://siromove.com/driver/transit-activate
|
||||
|
||||
SIRO_COMMISSION_JO=0.15
|
||||
SIRO_COMMISSION_SY=0.12
|
||||
SIRO_COMMISSION_EG=0.10
|
||||
SIRO_COMMISSION_IQ=0.14
|
||||
|
||||
# --- 10. Admin & Access ---
|
||||
ADMIN_TOOL_IPS=92.241.36.211,92.241.36.165,92.241.37.3
|
||||
ALLOWED_UPLOAD_HOST=siromove.com
|
||||
ALLOWED_TESTER_EMAILS=driver_tester@siromove.com,passenger_tester@siromove.com
|
||||
# ⚠️ لازم يغطّي كل قيمة في القسم 4/5 أعلاه: isAllowedSocketUrl() تعمل
|
||||
# str_starts_with، وأي عنوان غير مغطّى تُسقَط رسائله (بلا أي أثر قبل هذا الإصلاح).
|
||||
# أسماء حاويات Docker إجبارية هنا — لا تحذفها واستبدلها بالـ IP فقط.
|
||||
ALLOWED_SOCKET_URLS=http://socket_driver,http://socket_passenger,http://nginx,http://188.68.36.205:2021,http://188.68.36.205:3031,https://location.intaleq.xyz
|
||||
ALLOWED_ORIGIN=https://siromove.com
|
||||
ADMIN_PHONE_NUMBERS=963992952235,963942542053,962772735902
|
||||
SERVICE_PHONE1=963952475740
|
||||
SERVICE_PHONE2=963952475742
|
||||
TRIPZ_SMTP_PASSWORD=malDEV@2101
|
||||
|
||||
# --- 11. Platform Access Keys ---
|
||||
allowed1=passenger-app:android
|
||||
allowed2=passenger-app:ios
|
||||
allowedDriver1=driver-app:android
|
||||
allowedDriver2=driver-app:ios
|
||||
allowedService1=service-app:android
|
||||
allowedService2=service-app:ios
|
||||
allowedWallet1=wallet-app:android
|
||||
allowedWallet2=wallet-app:ios
|
||||
@@ -0,0 +1,79 @@
|
||||
# سيرو في حاويات — دليل التشغيل والفحص
|
||||
|
||||
> الهدف: نسخة سيرو كاملة على سيرفر واحد داخل compose واحدة، والتطبيق لا يتغير فيه
|
||||
> شيء سوى الـ base URLs (تُبنى مرة واحدة بـ `.env` الجديد — envied وقت الترجمة).
|
||||
> القرارات والأسباب في `Tripz/docs/30-siro-port-plan.md` §5.
|
||||
|
||||
## 0) قبل أي شيء — على السيرفر
|
||||
```bash
|
||||
df -h / # ⚠️ الصندوق المشترك مزمنياً ~90% ممتلئ — الصور والقواعد تحتاج ~4-6GB
|
||||
docker image prune -f # نظّف أولاً، وإن لم تكفِ المساحة فالفحص على صندوق آخر
|
||||
```
|
||||
|
||||
## 1) الإعداد (مرة واحدة)
|
||||
```bash
|
||||
cd /path/to/Siro/docker
|
||||
cp .env.example .env && nano .env # املأ الأسرار من قيم اللايف — خاصة JWT_SECRET وكلمات MySQL
|
||||
# ⚠️ طابق أسماء القواعد في mysql/init/00-databases.sql مع ما يتوقعه الكود
|
||||
docker compose build
|
||||
# تبعيات composer للخدمات التي لا تحمل vendor/ داخلها:
|
||||
docker compose run --rm socket_driver composer install
|
||||
docker compose run --rm socket_passenger composer install
|
||||
docker compose run --rm --workdir /var/www/backend php composer install
|
||||
```
|
||||
|
||||
## 2) التشغيل والاستيراد
|
||||
```bash
|
||||
docker compose up -d
|
||||
# استيراد السكيمات (أول مرة فقط):
|
||||
docker compose exec -T mysql mysql -uroot -p"$MYSQL_ROOT_PASSWORD" siro_primary < ../backend/schema_primary.sql
|
||||
docker compose exec -T mysql mysql -uroot -p"$MYSQL_ROOT_PASSWORD" siro_ride < ../backend/schema_ride.sql
|
||||
docker compose exec -T mysql mysql -uroot -p"$MYSQL_ROOT_PASSWORD" siro_tracking < ../backend/schema_tracking.sql
|
||||
docker compose exec -T mysql mysql -uroot -p"$MYSQL_ROOT_PASSWORD" siro_wallet < ../payment_server/WalletDB.sql
|
||||
docker compose exec -T mysql mysql -uroot -p"$MYSQL_ROOT_PASSWORD" siro_location < ../loction_server/locationDB.sql
|
||||
```
|
||||
|
||||
## 3) التحقق
|
||||
```bash
|
||||
docker compose ps # الست خدمات up
|
||||
curl -s http://localhost:8080/backend/index.html # nginx→ملفات
|
||||
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:8080/backend/connect.php # يرد (401/400 طبيعي بلا JWT)
|
||||
curl -s http://localhost:8080/fpm-status # حالة حوض fpm
|
||||
docker compose logs socket_driver | tail # Workerman أقلع على 2020/2021
|
||||
```
|
||||
اتصال التطبيق للتجربة: `http://IP:8080/backend` + سوكيت `http://IP:2020` — فقط بدّل
|
||||
الـ base URLs في `.env` تبع التطبيق وأعد البناء. `APP_DOMAIN` فارغ = حارس
|
||||
REGION_MISMATCH متعطل أثناء التجربة.
|
||||
|
||||
## 4) اختبار الضغط (الهدف: 10-20 ألف رحلة/ساعة)
|
||||
```bash
|
||||
cd ../stress_test && npm install
|
||||
# دخان أولاً (الأداة القديمة، دفعة صغيرة):
|
||||
node load_test.js --trips=10 -b http://localhost:8080/backend -s http://localhost:2020
|
||||
# ثم المعدل المستمر:
|
||||
node rate_test.js --rate 10000 --duration 10 -b http://localhost:8080/backend -s http://localhost:2020
|
||||
node rate_test.js --rate 20000 --duration 10 -b http://localhost:8080/backend -s http://localhost:2020
|
||||
node rate_test.js --rate 30000 --duration 5 ... # حد الانهيار — أين تبدأ p95 بالقفز؟
|
||||
```
|
||||
**أثناء التشغيل راقب من طرفية ثانية:**
|
||||
```bash
|
||||
docker stats # cpu/ذاكرة كل حاوية
|
||||
docker compose exec mysql sh -c 'tail -f /var/lib/mysql/slow.log' # استعلامات >200ms
|
||||
watch -n2 'curl -s http://localhost:8080/fpm-status' # طابور fpm (listen queue)
|
||||
```
|
||||
|
||||
### قواعد قراءة النتيجة بصدق
|
||||
1. **سيناريو الاختبار أخف من الرحلة الحقيقية بـ 3-5×** (4 نداءات API + 6 نبضات موقع؛
|
||||
الحقيقية فيها تسعير وبحث وقرب ودردشة). لتبنّي رقم "10k رحلة حقيقية بالذروة"
|
||||
يجب أن يعبر الاختبار **30k** بنجاح >99% و p95<500ms.
|
||||
2. الصندوق مشغول ~40% بغيرنا — **افحص خارج الذروة وبجولات قصيرة (5-10 د)**،
|
||||
وأعد الجولة مرتين للتأكد من ثبات الرقم.
|
||||
3. مولّد الحمل على نفس الصندوق يسرق ~5% CPU عند هذه المعدلات — مقبول؛ الأدق
|
||||
تشغيله من جهاز آخر نحو `http://IP:8080`.
|
||||
4. المُلتزم به للعملاء = الرقم الذي عبر الاختبار، لا أكثر.
|
||||
|
||||
## 5) ملاحظات أداء محسومة (لماذا الحاويات لا تبطئنا)
|
||||
- الحاوية على لينكس = عمليات عادية بنفس النواة (namespaces/cgroups) — **لا محاكاة ولا آلة افتراضية**. حمل CPU/ذاكرة ≈ صفر.
|
||||
- المكان الوحيد الذي يُخسر فيه أداء فعلاً: كتابة قاعدة البيانات فوق overlayfs — **محلول** بـ volume مسمّى (`mysql-data`).
|
||||
- أداء PHP الحقيقي يصنعه opcache + مقاس حوض fpm + فهارس MySQL — كلها مضبوطة في `php/` وليست متعلقة بالدوكر أصلاً.
|
||||
- التقسيم إلى 6 حاويات لا يكلف أداءً (نفس العمليات) ويعطي: إعادة تشغيل خدمة وحدها، حدود ذاكرة لكل خدمة، لوغات منفصلة، واستنساخ عميل = `clone + .env + up`.
|
||||
@@ -0,0 +1,149 @@
|
||||
# ============================================================
|
||||
# سيرو في حاويات — نسخة واحدة كاملة على سيرفر واحد
|
||||
# ============================================================
|
||||
# المبدأ: التقسيم بالدور (nginx / fpm / سوكيتات / mysql / redis)
|
||||
# لا حاوية-واحدة-فيها-كل-شيء، ولا تفتيت microservices.
|
||||
# الأداء = نفس العمليات على نفس النواة؛ الفرق تشغيلي فقط.
|
||||
#
|
||||
# التشغيل: docker compose up -d --build (انظر README.md)
|
||||
# ============================================================
|
||||
|
||||
name: siro
|
||||
|
||||
services:
|
||||
nginx:
|
||||
image: nginx:1.27-alpine
|
||||
ports:
|
||||
- "${HTTP_PORT:-8080}:80"
|
||||
volumes:
|
||||
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
- ../backend:/var/www/backend:ro
|
||||
- ../payment_server/v2:/var/www/v2:ro
|
||||
- ../loction_server:/var/www/loction_server:ro
|
||||
- ../dashboard:/var/www/dashboard:ro
|
||||
depends_on:
|
||||
- php
|
||||
mem_limit: 256m
|
||||
restart: unless-stopped
|
||||
|
||||
# php-fpm واحدة تخدم كل الخدمات الطلبية (backend + payment v2)
|
||||
# التقسيم لأبعد من هذا لا يضيف أداءً — نفس الصورة، نفس النواة.
|
||||
php:
|
||||
build:
|
||||
context: ./php
|
||||
dockerfile: Dockerfile.fpm
|
||||
args:
|
||||
PHP_VERSION: "${PHP_VERSION:-8.2}"
|
||||
volumes:
|
||||
- ../backend:/var/www/backend
|
||||
- ../payment_server/v2:/var/www/v2
|
||||
- ../loction_server:/var/www/loction_server
|
||||
- ./php/opcache.ini:/usr/local/etc/php/conf.d/zz-opcache.ini:ro
|
||||
- ./php/www-pool.conf:/usr/local/etc/php-fpm.d/zz-pool.conf:ro
|
||||
- ./keys:/keys:ro
|
||||
env_file: .env
|
||||
depends_on:
|
||||
- mysql
|
||||
- redis
|
||||
mem_limit: 2g
|
||||
restart: unless-stopped
|
||||
|
||||
# سوكيت السائقين (Workerman + PHPSocketIO) — WS بورت 2020 + HTTP داخلي 2021
|
||||
# عملية دائمة، لا علاقة لها بـ fpm — حاوية مستقلة إجبارياً.
|
||||
socket_driver:
|
||||
build:
|
||||
context: ./php
|
||||
dockerfile: Dockerfile.socket
|
||||
args:
|
||||
PHP_VERSION: "${PHP_VERSION:-8.2}"
|
||||
command: ["php", "driver_socket.php", "start"]
|
||||
working_dir: /app
|
||||
volumes:
|
||||
- ../loction_server:/app
|
||||
- ./keys:/keys:ro
|
||||
env_file: .env
|
||||
ports:
|
||||
# لا نفتح 2020 للعالم مباشرة: Workerman يتكلم نصاً صريحاً، والتطبيق يطلب
|
||||
# TLS على هذا المنفذ (https://…:2020) فتتجمّد المصافحة وينتهي بـ timeout.
|
||||
# nginx على المضيف يستمع على 2020 بالشهادة ويمرّر إلى 12020 هنا.
|
||||
# انظر nginx/siro-sockets-tls.conf
|
||||
- "127.0.0.1:12020:2020"
|
||||
# و2021 داخلي فقط: الباك إند يناديه عبر http://socket_driver:2021
|
||||
depends_on:
|
||||
- redis
|
||||
mem_limit: 768m
|
||||
restart: unless-stopped
|
||||
|
||||
# سوكيت الركاب (ride_server) — WS بورت 3030 + HTTP داخلي 3031
|
||||
socket_passenger:
|
||||
build:
|
||||
context: ./php
|
||||
dockerfile: Dockerfile.socket
|
||||
args:
|
||||
PHP_VERSION: "${PHP_VERSION:-8.2}"
|
||||
command: ["php", "passenger_socket.php", "start"]
|
||||
working_dir: /app
|
||||
volumes:
|
||||
- ../ride_server:/app
|
||||
- ./keys:/keys:ro
|
||||
env_file: .env
|
||||
ports:
|
||||
# نفس منطق سوكيت السائقين: nginx على المضيف يستمع على 3030 بالشهادة
|
||||
# ويمرّر إلى 13030 هنا. و3031 داخلي فقط (http://socket_passenger:3031).
|
||||
- "127.0.0.1:13030:3030"
|
||||
depends_on:
|
||||
- redis
|
||||
mem_limit: 512m
|
||||
restart: unless-stopped
|
||||
|
||||
mysql:
|
||||
image: mysql:8.4
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: "${MYSQL_ROOT_PASSWORD:?set in .env}"
|
||||
# بيانات القاعدة على volume مسمّى — يتجاوز overlayfs = أداء قرص شبه أصلي.
|
||||
volumes:
|
||||
- mysql-data:/var/lib/mysql
|
||||
- ./mysql/init:/docker-entrypoint-initdb.d:ro
|
||||
command:
|
||||
- --innodb-buffer-pool-size=1G
|
||||
- --max-connections=300
|
||||
- --innodb-flush-log-at-trx-commit=1
|
||||
- --slow-query-log=1
|
||||
- --long-query-time=0.2
|
||||
- --slow-query-log-file=/var/lib/mysql/slow.log
|
||||
ports:
|
||||
- "127.0.0.1:33061:3306" # للإدارة من السيرفر نفسه فقط — ليس للعامة
|
||||
mem_limit: 2560m
|
||||
restart: unless-stopped
|
||||
|
||||
phpmyadmin:
|
||||
image: phpmyadmin/phpmyadmin
|
||||
environment:
|
||||
PMA_HOST: mysql
|
||||
PMA_PORT: 3306
|
||||
UPLOAD_LIMIT: 300M
|
||||
ports:
|
||||
- "8082:80" # ادخل عليه عبر http://your-domain:8082 أو افتح بورت 8082 في CloudPanel
|
||||
depends_on:
|
||||
- mysql
|
||||
mem_limit: 256m
|
||||
restart: unless-stopped
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
command:
|
||||
- redis-server
|
||||
- --maxmemory
|
||||
- 400mb
|
||||
- --maxmemory-policy
|
||||
- noeviction
|
||||
- --appendonly
|
||||
- "yes"
|
||||
volumes:
|
||||
- redis-data:/data
|
||||
mem_limit: 512m
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
mysql-data:
|
||||
redis-data:
|
||||
@@ -0,0 +1,5 @@
|
||||
# Ignore all files in this directory (so keys aren't pushed to Git)
|
||||
*
|
||||
|
||||
# But don't ignore this .gitignore file itself
|
||||
!.gitignore
|
||||
@@ -0,0 +1,25 @@
|
||||
-- تُنشأ القواعد فارغة عند أول إقلاع فقط (volume جديد).
|
||||
-- ⚠️ الأسماء مطابقة لبيئة اللايف الخاصة بك.
|
||||
CREATE DATABASE IF NOT EXISTS `jorSiroDB` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
CREATE DATABASE IF NOT EXISTS `intaleqDB1` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
CREATE DATABASE IF NOT EXISTS `locationDB` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
CREATE DATABASE IF NOT EXISTS `intaleq-ridesDB` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
CREATE DATABASE IF NOT EXISTS `siroTransitDb` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- إنشاء المستخدمين وإعطائهم الصلاحيات لكي تتطابق البيئة مع اللايف 100%
|
||||
CREATE USER IF NOT EXISTS 'intaleqapp-jordan-siro'@'%' IDENTIFIED BY '7B7skfibrexQrGCUG1Y8';
|
||||
GRANT ALL PRIVILEGES ON `jorSiroDB`.* TO 'intaleqapp-jordan-siro'@'%';
|
||||
|
||||
CREATE USER IF NOT EXISTS 'intaleqUserDB1'@'%' IDENTIFIED BY 'NANatr7j4d8HzZjAcp00bbsjkdhfjsn';
|
||||
GRANT ALL PRIVILEGES ON `intaleqDB1`.* TO 'intaleqUserDB1'@'%';
|
||||
|
||||
CREATE USER IF NOT EXISTS 'intaleqLocation'@'%' IDENTIFIED BY '9otdMyiExMTXwnoA32sP';
|
||||
GRANT ALL PRIVILEGES ON `locationDB`.* TO 'intaleqLocation'@'%';
|
||||
|
||||
CREATE USER IF NOT EXISTS 'intaleq-rides'@'%' IDENTIFIED BY '0bHHMALEj4sqSmdT0avT';
|
||||
GRANT ALL PRIVILEGES ON `intaleq-ridesDB`.* TO 'intaleq-rides'@'%';
|
||||
|
||||
CREATE USER IF NOT EXISTS 'siroTransitUser'@'%' IDENTIFIED BY 'eZiDYxCJ2yyGfC32zG0Z';
|
||||
GRANT ALL PRIVILEGES ON `siroTransitDb`.* TO 'siroTransitUser'@'%';
|
||||
|
||||
FLUSH PRIVILEGES;
|
||||
@@ -0,0 +1,68 @@
|
||||
# نقطة واحدة لكل الخدمات الطلبية — التطبيق يغيّر الدومين فقط:
|
||||
# /backend/... → الباك إند الرئيسي (نفس شكل مسارات jordan-siro)
|
||||
# /v2/main/... → خادم المدفوعات
|
||||
# السوكيتات تُنشر مباشرة من حاوياتها (2020 / 3030) — لا تمر من هنا.
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
root /var/www;
|
||||
index index.php index.html;
|
||||
client_max_body_size 25m;
|
||||
|
||||
# كان access_log off من اختبار ضغط قديم ونُسي مُطفأً، فصار تشخيص أي عطل
|
||||
# مستحيلاً: البحث في سجلّ الوصول يرجع صفراً دائماً فيبدو أن التطبيق لا
|
||||
# يستدعي المسار أصلاً، والحقيقة أن السجلّ فارغ لا الطلبات. أعِده مطفأً
|
||||
# مؤقتاً وقت اختبارات الضغط فقط، ولا تتركه هكذا.
|
||||
access_log /dev/stdout;
|
||||
error_log /dev/stderr warn;
|
||||
|
||||
location ~ \.php$ {
|
||||
try_files $uri =404;
|
||||
include fastcgi_params;
|
||||
fastcgi_pass php:9000;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_read_timeout 60s;
|
||||
fastcgi_buffers 16 16k;
|
||||
fastcgi_buffer_size 32k;
|
||||
}
|
||||
|
||||
# حالة حوض fpm — من داخل شبكة الحاويات أو من السيرفر نفسه فقط
|
||||
location = /fpm-status {
|
||||
allow 172.16.0.0/12;
|
||||
allow 127.0.0.1;
|
||||
deny all;
|
||||
include fastcgi_params;
|
||||
fastcgi_pass php:9000;
|
||||
fastcgi_param SCRIPT_NAME /status;
|
||||
fastcgi_param SCRIPT_FILENAME /status;
|
||||
}
|
||||
|
||||
location /dashboard/siro-admin {
|
||||
alias /var/www/dashboard/siro-admin;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /dashboard/siro-admin/index.html;
|
||||
}
|
||||
|
||||
location /dashboard/admin {
|
||||
alias /var/www/dashboard/siro-admin;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /dashboard/admin/index.html;
|
||||
}
|
||||
|
||||
location /dashboard/siro-service {
|
||||
alias /var/www/dashboard/siro-service;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /dashboard/siro-service/index.html;
|
||||
}
|
||||
|
||||
location /dashboard/service {
|
||||
alias /var/www/dashboard/siro-service;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /dashboard/service/index.html;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
# ══════════════════════════════════════════════════════════════════
|
||||
# إنهاء TLS أمام سوكيتات Workerman
|
||||
# ══════════════════════════════════════════════════════════════════
|
||||
# يُنسَخ على **المضيف** لا داخل الحاويات:
|
||||
# /etc/nginx/sites-enabled/siro-sockets-tls.conf
|
||||
#
|
||||
# المشكلة التي يحلّها: حاويتا السوكيت تفتحان المنفذين نصاً صريحاً
|
||||
# (new SocketIO(2020) و new SocketIO(3030) بلا سياق SSL)، بينما
|
||||
# التطبيقان يطلبان https://jordan-siro.intaleqapp.com:2020 و :3030.
|
||||
# مصافحة TLS ضد منفذ لا يتكلم TLS تتجمّد حتى المهلة، فيظهر في اللوج:
|
||||
# Socket Connect Error: timeout
|
||||
#
|
||||
# الحل: الحاويتان تُنشران على 127.0.0.1 فقط (12020 / 13030 — انظر
|
||||
# docker-compose.yml)، و nginx هنا يستمع على 2020 / 3030 بشهادة الدومين
|
||||
# ويمرّر إليهما مع ترقية WebSocket. النتيجة: روابط التطبيقين تبقى كما هي
|
||||
# بلا أي بناء جديد، والـ JWT في الـ query string يبقى داخل نفق TLS.
|
||||
# ══════════════════════════════════════════════════════════════════
|
||||
|
||||
# ملاحظة: لا نضع http2 إطلاقاً هنا. أولاً لأن ترقية WebSocket تعتمد على
|
||||
# ترويسة Upgrade في HTTP/1.1 ولا معنى لها في HTTP/2، وثانياً لأن http2 on;
|
||||
# لم يُضَف إلا في nginx 1.25.1 وnginx المضيف أقدم فيرفضه بـ:
|
||||
# nginx: [emerg] unknown directive "http2"
|
||||
# اسم مميّز يتفادى التضارب مع أي map باسم $connection_upgrade قد يكون
|
||||
# CloudPanel معرِّفه أصلاً في سياق http.
|
||||
map $http_upgrade $siro_connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
|
||||
# ── سوكيت السائقين — GPS ─────────────────────────────────────────
|
||||
server {
|
||||
listen 2020 ssl;
|
||||
listen [::]:2020 ssl;
|
||||
|
||||
server_name jordan-siro.intaleqapp.com;
|
||||
|
||||
# عدّل المسارين إن كانت شهادتك في مكان آخر — تحقّق بالأمر:
|
||||
# grep -rh ssl_certificate /etc/nginx/sites-enabled/ | sort -u
|
||||
ssl_certificate /etc/nginx/ssl-certificates/jordan-siro.intaleqapp.com.crt;
|
||||
ssl_certificate_key /etc/nginx/ssl-certificates/jordan-siro.intaleqapp.com.key;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_session_cache shared:SiroSock:10m;
|
||||
ssl_session_timeout 1d;
|
||||
|
||||
# لا سجلّ وصول: نبضات GPS تصل كل ثوانٍ وتُغرق القرص
|
||||
access_log off;
|
||||
error_log /var/log/nginx/siro-socket-driver-error.log warn;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:12020;
|
||||
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $siro_connection_upgrade;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# اتصال السائق يعيش ساعات وهو أونلاين — بلا هذه المهل يقطعه nginx
|
||||
# كل 60 ثانية فتدخل الحاوية في حلقة إعادة اتصال دائمة.
|
||||
proxy_connect_timeout 10s;
|
||||
proxy_send_timeout 3600s;
|
||||
proxy_read_timeout 3600s;
|
||||
|
||||
# التخزين المؤقّت يُعطّل الدفع الفوري في WebSocket
|
||||
proxy_buffering off;
|
||||
}
|
||||
}
|
||||
|
||||
# ── سوكيت الركاب — حالة الرحلة وموقع السائق ──────────────────────
|
||||
server {
|
||||
listen 3030 ssl;
|
||||
listen [::]:3030 ssl;
|
||||
|
||||
server_name jordan-siro.intaleqapp.com;
|
||||
|
||||
ssl_certificate /etc/nginx/ssl-certificates/jordan-siro.intaleqapp.com.crt;
|
||||
ssl_certificate_key /etc/nginx/ssl-certificates/jordan-siro.intaleqapp.com.key;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_session_cache shared:SiroSock:10m;
|
||||
ssl_session_timeout 1d;
|
||||
|
||||
access_log off;
|
||||
error_log /var/log/nginx/siro-socket-passenger-error.log warn;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:13030;
|
||||
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $siro_connection_upgrade;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
proxy_connect_timeout 10s;
|
||||
proxy_send_timeout 3600s;
|
||||
proxy_read_timeout 3600s;
|
||||
|
||||
proxy_buffering off;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
# صورة الخدمات الطلبية (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 zip @composer
|
||||
|
||||
WORKDIR /var/www
|
||||
@@ -0,0 +1,10 @@
|
||||
# صورة السوكيتات الدائمة (Workerman) — driver_socket و passenger_socket
|
||||
# ext-event ضرورية فوق ~1024 اتصال متزامن (Workerman يلتقطها تلقائياً إن وُجدت)
|
||||
ARG PHP_VERSION=8.2
|
||||
FROM php:${PHP_VERSION}-cli
|
||||
|
||||
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 pcntl posix sockets event redis @composer
|
||||
|
||||
WORKDIR /app
|
||||
@@ -0,0 +1,9 @@
|
||||
; opcache هو الفرق الحقيقي في أداء PHP — ليس الدوكر
|
||||
opcache.enable=1
|
||||
opcache.memory_consumption=192
|
||||
opcache.interned_strings_buffer=16
|
||||
opcache.max_accelerated_files=20000
|
||||
; الكود bind-mounted في التجربة → إعادة تحقق كل 60 ثانية
|
||||
; عند التحويل لمنتج (كود مخبوز في الصورة): اجعلها 0 مع validate_timestamps=0
|
||||
opcache.validate_timestamps=1
|
||||
opcache.revalidate_freq=60
|
||||
@@ -0,0 +1,21 @@
|
||||
; حوض fpm مضبوط لصندوق مشترك 6 أنوية / 12GB (حصة الحاوية 2GB)
|
||||
; قانون Little: 170 rps × 0.05 ثانية ≈ 9 طلبات متزامنة فقط — 48 عاملاً فيها هامش واسع
|
||||
[www]
|
||||
pm = dynamic
|
||||
pm.max_children = 48
|
||||
pm.start_servers = 8
|
||||
pm.min_spare_servers = 4
|
||||
pm.max_spare_servers = 16
|
||||
pm.max_requests = 1000
|
||||
pm.status_path = /status
|
||||
slowlog = /proc/self/fd/2
|
||||
request_slowlog_timeout = 3s
|
||||
|
||||
; توجيه error_log إلى مخرج الحاوية — بلا هذه الأسطر تُبتلع كل رسائل
|
||||
; error_log() في الكود ولا يظهر شيء في `docker compose logs php`، والباك إند
|
||||
; مليء بها: [accept_ride] و [FCM_DEBUG] و 📲 [FCM_RESULT] و [SOCKET_DEBUG].
|
||||
; كنّا نشخّص أعطال الإشعارات استنتاجاً من الكود بدل قراءة سبب الرفض من Google.
|
||||
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