docs: دليل التشغيل والأعطال المعروفة (المنافذ، nginx، القواعد، التوكن، سجل الملفات)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
875ce763bd
commit
dd44b84e81
@@ -0,0 +1,321 @@
|
|||||||
|
# دليل التشغيل والأعطال المعروفة — سيرو
|
||||||
|
|
||||||
|
> **الغرض:** مرجع عملي لكل ما يلزم عند النشر أو النقل إلى سيرفر جديد.
|
||||||
|
> كل بند هنا عطلٌ وقع فعلاً في الإنتاج، لا احتمالٌ نظري.
|
||||||
|
>
|
||||||
|
> **آخر تحديث:** 2026-08-08 — بعد جلسة إصلاح شاملة على إنتاج الأردن.
|
||||||
|
> مكمّل لـ [30-siro-port-plan.md](30-siro-port-plan.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ١. خريطة المنافذ
|
||||||
|
|
||||||
|
المنافذ أكثر ما يُنسى عند النقل، ونسيانها يعطي `timeout` لا رسالة خطأ.
|
||||||
|
|
||||||
|
| المنفذ الخارجي | الخدمة | داخل دوكر | مَن ينهي TLS | UFW |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| 443 | الباك إند + المدفوعات | `nginx` على `HTTP_PORT` | nginx المضيف | مفتوح |
|
||||||
|
| 2020 | سوكيت السائقين (GPS) | `127.0.0.1:12020` | **nginx المضيف** | يلزم فتحه |
|
||||||
|
| 3030 | سوكيت الركاب | `127.0.0.1:13030` | **nginx المضيف** | يلزم فتحه |
|
||||||
|
| 4040 | سوكيت الطعام | `127.0.0.1:14040` | **nginx المضيف** | يلزم فتحه |
|
||||||
|
| — | HTTP داخلي للطعام | `socket_food:4041` | لا شيء | داخلي |
|
||||||
|
| — | HTTP داخلي للسائقين | `socket_driver:2021` | لا شيء | داخلي |
|
||||||
|
|
||||||
|
> ⚠️ **`HTTP_PORT` ليس 8080.** في إنتاج الأردن هو **8182**، ويُقرأ من `docker/.env`.
|
||||||
|
> افتراضه خطأً أضاع في هذه الجلسة ثلاث محاولات تشخيص متتالية: كل `curl` على 8080
|
||||||
|
> كان يضرب خدمة أخرى تماماً، فبُنيت على نتائجه نظريات خاطئة عن DNS وعن العناوين
|
||||||
|
> المهجورة. **اقرأ المنفذ قبل أي قياس:**
|
||||||
|
> ```bash
|
||||||
|
> docker compose port nginx 80; grep '^HTTP_PORT' .env
|
||||||
|
> ```
|
||||||
|
|
||||||
|
### قاعدة السوكيت الجديد — ثلاث خطوات لا واحدة
|
||||||
|
|
||||||
|
حاويات Workerman تفتح منافذها **نصاً صريحاً**، والتطبيق يطلب `https://`. مصافحة TLS
|
||||||
|
ضد منفذ لا يتكلم TLS تتجمّد حتى المهلة. لذلك كل سوكيت يحتاج:
|
||||||
|
|
||||||
|
1. نشر داخلي على `127.0.0.1:1XXXX` في `docker-compose.yml`
|
||||||
|
2. كتلة TLS في `docker/nginx/siro-sockets-tls.conf` ← **تُنسخ يدوياً** إلى `/etc/nginx/sites-enabled/`
|
||||||
|
3. `ufw allow XXXX/tcp`
|
||||||
|
|
||||||
|
نسيان أيٍّ منها يعطي `timeout`. وقد وقع هذا **مرتين**: أولاً في 2020/3030، ثم تكرّر
|
||||||
|
حرفياً مع الطعام (4040) رغم أن الملف نفسه يشرح العلّة في تعليقه.
|
||||||
|
|
||||||
|
### تشخيص أي عطل سوكيت — ثلاثة أوامر
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ss -ltnp | grep ':PORT\b' # هل يستمع المضيف؟
|
||||||
|
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:INTERNAL/ # هل الحاوية حيّة؟
|
||||||
|
ufw status numbered | grep PORT # هل المنفذ مفتوح؟
|
||||||
|
```
|
||||||
|
|
||||||
|
ردّ **403** من الأمر الثاني = الحاوية سليمة وترفض لغياب JWT. هذا نجاح لا فشل.
|
||||||
|
|
||||||
|
> **فخ UFW:** نشر منافذ Docker **يتجاوز UFW** عبر قواعد iptables خاصة. فما دام
|
||||||
|
> `docker-proxy` يملك المنفذ يكون مفتوحاً للعالم رغم أن UFW لا يسمح به — ولحظة
|
||||||
|
> نقله إلى nginx تنطبق قواعد UFW ويُحجب بصمت. `curl` من السيرفر نفسه **لا يُثبت**
|
||||||
|
> الوصول الخارجي.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ٢. طبقتا nginx — أخطر التباس في المعمارية
|
||||||
|
|
||||||
|
```
|
||||||
|
العميل → nginx المضيف (CloudPanel، 443) → nginx الحاوية (HTTP_PORT) → php-fpm
|
||||||
|
```
|
||||||
|
|
||||||
|
**تمييز مصدر الخطأ من جسم الردّ:**
|
||||||
|
|
||||||
|
| الجسم | المصدر | المعنى |
|
||||||
|
|---|---|---|
|
||||||
|
| `File not found.` (16 بايت) | **php-fpm** | الملف غير موجود في الحاوية التي وصلها الطلب |
|
||||||
|
| صفحة HTML بعنوان 404 | nginx | `try_files` لم يجد الملف |
|
||||||
|
| `502 Bad Gateway` | nginx | لم يصل الـ upstream إطلاقاً |
|
||||||
|
| `{"error":"..."}` | التطبيق | وصل ونُفِّذ |
|
||||||
|
|
||||||
|
### فخ عنوان الـ upstream المهجور
|
||||||
|
|
||||||
|
nginx يترجم الاسم المكتوب حرفياً في `fastcgi_pass` **مرة واحدة** عند تحميل
|
||||||
|
الإعدادات ويحتفظ به للأبد. عند إعادة إنشاء الحاويات تتبدّل العناوين، فيبقى nginx
|
||||||
|
يطرق عنواناً مهجوراً ⇒ **502 والحاوية سليمة وسجلّها صامت** لأن الطلبات لا تصلها.
|
||||||
|
|
||||||
|
**الحل المطبَّق** في `docker/nginx/default.conf`: وجهات كمتغيّرات مع
|
||||||
|
`resolver 127.0.0.11 valid=10s`، فتُؤجَّل الترجمة إلى وقت الطلب.
|
||||||
|
|
||||||
|
فائدة ثانية: بالاسم الحرفي كان nginx **يرفض الإقلاع** إن كانت إحدى حاويات fpm
|
||||||
|
متوقفة — أي أن سقوط حاوية الطعام وحدها كان قادراً على إسقاط الموقع بأكمله عند أول
|
||||||
|
إعادة تشغيل.
|
||||||
|
|
||||||
|
### فخ المزامنة اليدوية
|
||||||
|
|
||||||
|
`siro-sockets-tls.conf` يعيش على المضيف ويُنسخ يدوياً من المستودع. لا شيء يربط
|
||||||
|
الاثنين، ولا شيء يربط إضافة سوكيت في `docker-compose.yml` بإضافة كتلته هنا.
|
||||||
|
**تحقّق دائماً بعد الـ pull وقبل الـ cp:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git pull && grep -c "listen 4040" docker/nginx/siro-sockets-tls.conf
|
||||||
|
```
|
||||||
|
|
||||||
|
وخذ نسخة احتياطية قبل النسخ — الملف يحمل سوكيت الرحلات العامل:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp /etc/nginx/sites-enabled/siro-sockets-tls.conf /root/siro-sockets-tls.conf.bak
|
||||||
|
cp docker/nginx/siro-sockets-tls.conf /etc/nginx/sites-enabled/ && nginx -t
|
||||||
|
```
|
||||||
|
|
||||||
|
لا تُعِد التحميل إلا بعد `test is successful`. تحذيرات `ssl_stapling` ضجيج قديم
|
||||||
|
لا علاقة له.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ٣. قواعد البيانات
|
||||||
|
|
||||||
|
### الخريطة
|
||||||
|
|
||||||
|
`backend/core/Database/Database.php` يُفرد لكل قاعدة **host وuser وpass مستقلة** —
|
||||||
|
الفصل على خوادم مختلفة مفترضٌ في التصميم:
|
||||||
|
|
||||||
|
| الاسم | متغيّر البيئة | القيمة في الأردن |
|
||||||
|
|---|---|---|
|
||||||
|
| `main` | `DB_PRIMARY_NAME_V2` | `jorSiroDB` |
|
||||||
|
| `ride` | `DB_RIDE_NAME` | `intaleq-ridesDB` |
|
||||||
|
| `tracking` | `DB_TRACKING_NAME` | `locationDB` |
|
||||||
|
| `transit` | `DB_TRANSIT_NAME` | `siroTransitDb` |
|
||||||
|
| `food` | `DB_FOOD_NAME` | `siro_food` |
|
||||||
|
| **(خارج الخريطة)** | `DB_PAYMENT_NAME` | `payment` |
|
||||||
|
|
||||||
|
> `DB_PRIMARY_NAME` (بلا `_V2`) = `intaleqDB1` وهي **قاعدة أخرى**. أي كود يقرأ
|
||||||
|
> المتغيّر بلا `_V2` يعمل على قاعدة خاطئة صامتاً.
|
||||||
|
|
||||||
|
### ممنوع: الإشارة المؤهَّلة عبر القواعد
|
||||||
|
|
||||||
|
`SELECT ... FROM jorSiroDB.ride` تعمل **فقط** إن كانت القاعدتان على نفس خادم
|
||||||
|
MySQL. تعمل اليوم بالصدفة وتسقط يوم يُفصل الدفع.
|
||||||
|
|
||||||
|
**الصحيح:** اتصال ثانٍ مستقل — انظر `payment_server/v2/main/db_primary.php`.
|
||||||
|
|
||||||
|
### قاعدة الفصل بين القراءة والكتابة
|
||||||
|
|
||||||
|
- **قراءة** بيانات غير مالية (عدّ رحلات، إحصاء): اتصال مباشر ✅
|
||||||
|
- **كتابة** في المحفظة: **S2S عبر خادم الدفع حصراً** ❌ لا اتصال مباشر
|
||||||
|
|
||||||
|
السبب أن نقطة S2S هي البوابة الوحيدة التي تجمع JWT وHMAC ومنع التكرار والأثر.
|
||||||
|
وهي ناقصة أصلاً: `driverWallet.paymentID` **بلا مفتاح فريد وبلا فحص تكرار** رغم
|
||||||
|
أن التعليقات تدّعي عكس ذلك. توزيع الكتابة على كل من يملك اتصالاً يجعل إصلاح ذلك
|
||||||
|
مستحيلاً لاحقاً.
|
||||||
|
|
||||||
|
### الترحيلات — لا جدول تتبّع
|
||||||
|
|
||||||
|
كل ملف في `backend/migrations/` يُطبَّق يدوياً ولا سجل لما نُفِّذ.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose exec -T mysql mysql -uroot -p"$MP" jorSiroDB < backend/migrations/FILE.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
> ⚠️ `2026_08_07_verify_all.sql` **لا يفحص كل جداول دفعته** — لا يذكر
|
||||||
|
> `scheduled_rides` ولا جداول SMS. خروجه نظيفاً **ليس** دليلاً على الاكتمال.
|
||||||
|
|
||||||
|
عند أي خطأ قاعدة من endpoint جديد، افحص وجود الجدول مباشرة قبل قراءة الكود:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT TABLE_SCHEMA, TABLE_NAME FROM information_schema.TABLES WHERE TABLE_NAME='X';
|
||||||
|
```
|
||||||
|
|
||||||
|
إعادة التشغيل: ما يستعمل `siro_add_column` من `_helpers.sql` آمن؛ وما يستعمل
|
||||||
|
`ALTER TABLE ... ADD COLUMN` خاماً **يفشل** إن أُعيد (مثل `2026_08_09_obligation_credit_gate`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ٤. PHP في الحاويات
|
||||||
|
|
||||||
|
**صورة `php:fpm` الرسمية لا تشحن `php.ini` إطلاقاً**، فتسري القيم المدمجة و
|
||||||
|
`display_errors` **مُفعّل**. أي أن كل تحذير يُطبع **داخل جسم الردّ** قبل الـ JSON.
|
||||||
|
|
||||||
|
الأثر الحقيقي: شاشة الرصيد كانت تسقط بـ
|
||||||
|
`FormatException: Unexpected character (at character 1) <br />` — والعطل يبدو في
|
||||||
|
التطبيق بينما مصدره سطر تحذير في PHP. وأمنياً، نص التحذير يحمل المسار المطلق
|
||||||
|
وأحياناً جزءاً من الاستعلام ويُسلَّم للعميل.
|
||||||
|
|
||||||
|
**الحل:** `docker/php/php-prod.ini` مركّب على `php` و`php_food` و`php_transit`.
|
||||||
|
تحقّق بعد أي إعادة إنشاء:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose exec -T php php -i | grep -E "^display_errors|^upload_max_filesize"
|
||||||
|
# المتوقّع: Off / 25M
|
||||||
|
```
|
||||||
|
|
||||||
|
> ضبط `upload_max_filesize=25M` ليوافق `client_max_body_size` في nginx — كان على
|
||||||
|
> 2M الافتراضية، وهو ما يقطع رفع صور المستندات بصمت.
|
||||||
|
|
||||||
|
**النشر:** `backend` مربوط bind-mount و opcache على `validate_timestamps=1`
|
||||||
|
بتحديث كل 60ث ⇒ **لا حاجة لإعادة بناء**، يكفي `git pull`. أما تغيير
|
||||||
|
`docker-compose.yml` فيلزمه `docker compose up -d`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ٥. نظام التوكن (JWT)
|
||||||
|
|
||||||
|
### الأنواع
|
||||||
|
|
||||||
|
| النوع | مَن يُصدره | المسموح له |
|
||||||
|
|---|---|---|
|
||||||
|
| `registration` | `loginFirstTimeDriver.php` | مسارات التسجيل فقط (`REGISTRATION_ENDPOINTS`) |
|
||||||
|
| `access` role=driver | `loginJwtDriver.php` / `auth/otp/verify.php` | كل شيء |
|
||||||
|
|
||||||
|
توكن التسجيل صالح **ساعة كاملة** لكنه بلا صلاحيات. وأي endpoint محمي يردّه بـ
|
||||||
|
**403 `Token not authorized for this action`**.
|
||||||
|
|
||||||
|
### العطل الذي عطّل كل شيء
|
||||||
|
|
||||||
|
`getJWT` كان يفحص `exp` وحده. فتوكن التسجيل يبقى مخزّناً بعد اكتمال الدخول، ويردّ
|
||||||
|
كل endpoint محمي 403 — و`restart` لا ينفع لأن `force` يمسح الـ cooldown فقط.
|
||||||
|
وسطر الترقية بعد الدخول كان معطَّلاً بالتعليق.
|
||||||
|
|
||||||
|
**الحل (مطبَّق):** فحص `token_type` لا `exp` وحده، وترقية فورية بعد `loginDriver`،
|
||||||
|
و`CRUD` يعالج 403 كما يعالج 401 (تجديد واحد ثم إعادة).
|
||||||
|
|
||||||
|
### بصمة الجهاز
|
||||||
|
|
||||||
|
`driverToken.fingerPrint` كانت تُكتب **بصيغتين** حسب آخر endpoint لمسها: خام من
|
||||||
|
`verify.php` و`addDriver.php`، ومُهشّمة (`sha256(fp+FP_PEPPER)`) من
|
||||||
|
`loginJwtWalletDriver.php`. و`loginJwtDriver.php` يقارن بالمُهشّمة وحدها ⇒ رفض دائم
|
||||||
|
لكل سائق OTP لم يفتح المحفظة.
|
||||||
|
|
||||||
|
**الحل:** `loginJwtDriver.php` يقبل الصيغتين ويوحّد الصفّ على المُهشّمة. والتطبيق
|
||||||
|
يتخطّى المقارنة عند رؤية 64 خانة hex (لا يملك الـ pepper).
|
||||||
|
|
||||||
|
### مسار الجهاز الجديد
|
||||||
|
|
||||||
|
جهاز جديد ⇒ `loginJwtDriver` يردّ 401 ⇒ العلم `needsDeviceVerification` ⇒ شاشة OTP
|
||||||
|
⇒ `verify.php` يربط البصمة **ويُصدر توكن driver** ⇒ يُحفظ. كان الفرع `token_change`
|
||||||
|
لا يفعل أياً من الاثنين، فتنجح شاشة الـ OTP ولا يعمل بعدها شيء.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ٦. سجل الملفات المعدَّلة
|
||||||
|
|
||||||
|
### الباك إند
|
||||||
|
|
||||||
|
| الملف | العطل | الدرس |
|
||||||
|
|---|---|---|
|
||||||
|
| `core/Auth/JwtService.php` | — (مرجع) | `REGISTRATION_ENDPOINTS` تُطابق بـ `basename`؛ أي endpoint جديد في التسجيل يجب إضافته |
|
||||||
|
| `loginJwtDriver.php` | بصمة بصيغتين ⇒ 401 دائم | وحّد صيغة التخزين، واقبل القديمة للتوافق |
|
||||||
|
| `auth/otp/verify.php` | `token_change` لا يُصدر توكناً ولا يربط البصمة | التحقق وحده لا يكفي — لا بد من ربط وإصدار |
|
||||||
|
| `ride/gamification/getLeaderboard.php` | 4 أعمدة غير موجودة (`d.name`, `nameArabic`, `firstName`, `personal_photo`) | الأعمدة الفعلية `first_name`/`last_name` و**مشفّرة** — تحتاج فكّ تشفير |
|
||||||
|
| `ride/scheduled/list.php` | `WHERE driver_id` وجدول `scheduled_rides` **بلا هذا العمود** | الحجز يُنشئه الراكب؛ السائق يُسند لحظة توليد الرحلة — الربط عبر `ride_id` |
|
||||||
|
| `ride/invitor/referral_code_helper.php` | **جديد** | المولّد كان في نقطة لا يناديها أحد ⇒ الكود `null` للجميع. القراءة نفسها تُنشئ |
|
||||||
|
| `ride/invitor/get_driver_referrals.php` | تقرأ ولا تولّد | — |
|
||||||
|
| `ride/invitor/get_passenger_referrals.php` | نفسه | — |
|
||||||
|
| `ride/invitor/get_unified_code.php` | `while(true)` تُعلّق العامل لو امتلأت الأكواد | سقف محاولات ثم بديل أطول |
|
||||||
|
|
||||||
|
### خادم الدفع
|
||||||
|
|
||||||
|
| الملف | العطل | الدرس |
|
||||||
|
|---|---|---|
|
||||||
|
| `db_primary.php` | **جديد** | اتصال ثانٍ للقاعدة الأساسية — لا إشارة مؤهَّلة |
|
||||||
|
| `ride/payment/getAllPayment.php` | `Table 'payment.ride' doesn't exist` بلا `try/catch` ⇒ 500 | افصل الرصيد عن الإحصاء: المالي لا يسقط لأجل المساعد |
|
||||||
|
| `ride/driverWallet/driverStatistic.php` | نفسه (`driver_orders` + `ride`) | — |
|
||||||
|
|
||||||
|
### تطبيق السائق
|
||||||
|
|
||||||
|
| الملف | العطل | الدرس |
|
||||||
|
|---|---|---|
|
||||||
|
| `controller/auth/captin/login_captin_controller.dart` | فحص `exp` وحده؛ الترقية معلّقة | صلاحية التوكن ليست زمنه فقط بل نوعه |
|
||||||
|
| `controller/functions/crud.dart` | 403 بلا معالجة؛ حجب النقاط العامة عند غياب التوكن | حجب `/auth/otp/` أغلق مسار الاستعادة نفسه |
|
||||||
|
| `controller/auth/captin/phone_helper_controller.dart` | يرمي التوكن الذي يصدره السيرفر | — |
|
||||||
|
| `controller/auth/captin/opt_token_controller.dart` | نفسه | — |
|
||||||
|
| `controller/auth/captin/invit_controller.dart` | **يرفع دفتر الهاتف كاملاً** تلقائياً | ⚠️ انظر §7 |
|
||||||
|
| `controller/home/payment/captain_wallet_controller.dart` | `isLoading` بلا `finally` ⇒ لودينج أبدي لكل سائق جديد | كل مسار تحميل يحتاج `finally` |
|
||||||
|
| `controller/home/captin/destination_controller.dart` | يفهرس نصاً كخريطة | الردّ قد يكون `String` عند الفراغ |
|
||||||
|
| `controller/gamification/leaderboard_controller.dart` | `jsonDecode` على Map | **`CRUD().post` تُرجع مفكوكاً، و`get` تُرجع نصاً** |
|
||||||
|
| `controller/scheduled/driver_scheduled_rides_controller.dart` | يعرض «لا حجوزات» عند فشل 500 | افصل الخطأ عن الفراغ — الأول يُضلّل الكابتن |
|
||||||
|
| `views/.../drawer_captain.dart` | `onBackgroundImageError` بلا صورة ⇒ assertion | — |
|
||||||
|
| `views/.../home_captin.dart` | فيض في الشريط العلوي | ما زال 9.8px — الشعار 36px مقابل 26.2px |
|
||||||
|
| `views/home/statistics/widgets/stat_summary_card.dart` | فيض 9.7px | — |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ٧. بنود مفتوحة
|
||||||
|
|
||||||
|
**دفتر الهاتف (أولوية عليا).** أُوقف الرفع التلقائي، لكن ما جُمع سابقاً ما زال في
|
||||||
|
`ride/egyptPhones` — أسماء وأرقام أطراف ثالثة لم تُستأذن. رفع دفتر العناوين جملةً
|
||||||
|
يخالف سياسة Google Play ويتطلب إفصاحاً بارزاً وموافقة صريحة؛ إذن النظام وحده لا
|
||||||
|
يكفي. **قرار الحذف لم يُتخذ بعد.**
|
||||||
|
|
||||||
|
**الفيض في الشريط العلوي.** تقلّص من 16px إلى 9.8px؛ يحتاج تصغير الشعار نفسه.
|
||||||
|
|
||||||
|
**حارس المزامنة.** لا شيء يقارن `docker/nginx/siro-sockets-tls.conf` بنظيره على
|
||||||
|
المضيف. مقترح: سطر تحقق في `deploy.sh`.
|
||||||
|
|
||||||
|
**سبب انقطاع الـ 404 الشامل** الذي وقع 2026-08-08 لم يُوثَّق — يُرجَّح أن CloudPanel
|
||||||
|
أعاد توليد ملف الدومين. **إن صحّ فسيتكرّر عند أول تجديد شهادة.**
|
||||||
|
|
||||||
|
**خطط التأمين** غير مزروعة (`insurance_plans` فارغ) — الصفحة تعرض حالة فارغة صحيحة.
|
||||||
|
|
||||||
|
**الرحلات المجدولة للسائق** تعرض ما أُسند له فقط. إن أُريد أن يرى حجوزات منطقته
|
||||||
|
قبل الإسناد فذاك تصميم مختلف.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ٨. ترتيب النشر الآمن
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ١. اسحب وتحقّق أن ما تتوقعه وصل فعلاً
|
||||||
|
git pull && grep -c "listen 4040" docker/nginx/siro-sockets-tls.conf
|
||||||
|
|
||||||
|
# ٢. ملفات المضيف (إن تغيّرت) — بنسخة احتياطية وفحص
|
||||||
|
cp /etc/nginx/sites-enabled/siro-sockets-tls.conf /root/backup.conf
|
||||||
|
cp docker/nginx/siro-sockets-tls.conf /etc/nginx/sites-enabled/ && nginx -t && systemctl reload nginx
|
||||||
|
|
||||||
|
# ٣. الحاويات (فقط إن تغيّر compose أو ملفات ini)
|
||||||
|
cd docker && docker compose up -d php php_food php_transit
|
||||||
|
|
||||||
|
# ٤. تحقّق بالقياس لا بالافتراض
|
||||||
|
docker compose exec -T php php -i | grep ^display_errors
|
||||||
|
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:$(grep '^HTTP_PORT' .env | cut -d= -f2)/backend/auth/packageInfo.php
|
||||||
|
# المتوقّع 401
|
||||||
|
```
|
||||||
|
|
||||||
|
> **القاعدة الحاكمة لكل ما سبق:** لا تستنتج من قياس لم تتحقق من صحة أداته.
|
||||||
|
> ثلاث نظريات خاطئة في هذه الجلسة — عن الرفع، وعن DNS، وعن العناوين المهجورة —
|
||||||
|
> بُنيت جميعها على `curl` لمنفذ مفترض. قراءة `HTTP_PORT` من `.env` أسقطتها دفعة واحدة.
|
||||||
Reference in New Issue
Block a user