البند ٢ — استخبارات التسعير (docs/35 جديد):
- توصيف تقني دقيق من كود سيرو: المصدر ليس "كشط أسعار معلنة" بل
بوت أندرويد على أجهزة حقيقية يشغّل 7 تطبيقات منافسة مُسمّاة
بمعرّف الحزمة (standalone_worker.php:665) بدفعات حتى 100 مهمة
- فصل ثلاثة أخطار مستقلة: الوصول الآلي · قانون المنافسة · البيانات
- الخطر الأكبر (لم يكن موثّقاً): بيع المحرّك لمشغّلَين في نفس المدينة
= ترتيب hub-and-spoke تقع مسؤوليته على المحور أي Tripz
- ضابط مقترح: مشغّل واحد لكل مدينة، في العقد وفي الكود
- تنظيف صياغة الموقع: صفر أسماء منافسين، وحُذفت "اعرف كيف يسعّر
منافسك قبل أن يعرف هو" لأنها تصلح دليل نيّة في نزاع
البند ٣ — طبقة القياس (docs/32 §5):
- شريط موافقة بأربع لغات، الرفض بنفس بروز القبول
- البكسل لا يُحمَّل قبل الموافقة (مطلوب لزوّار الاتحاد الأوروبي:
الموقع بالفرنسية والإسبانية)
- 8 أحداث تغطي القمع كاملاً حتى Lead بمعامل القناة
- PIXEL_ID فارغ عمداً: لا شيء ينكسر ولا شيء يُقاس حتى يُملأ
تحقُّق: صفر أخطاء console · صفر عناصر i18n فارغة في اللغات الأربع ·
fbq غير معرّف قبل الموافقة · الأحداث تُطلق بعدها
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
تنفيذ توصيات المراجعة النقدية التي لم تُنفَّذ في الجولة السابقة:
- حذف «الأمان والامتثال» $79 كوحدة → النواة (سبب قانوني: بيع الأمان
يُنشئ وثيقة إدانة يوم يقع حادث عند مستأجر لم يشترِ الوحدة)
- حذف «حزمة المدفوعات» $99 → النواة (الحلقة الأساسية لا ترقية)
- دمج «ذكاء الأسطول» $99 في باقة أسطول+ (تناقض تسموي)
- «المواصلات» تخرج من الشبكة → قسم #transit مستقل بجمهوره وCTA خاص
- شريط .core-band يعرض ما لا يُباع كحجة بيع
- إصلاح الانقلاب السعري: كانت سيادة $879 أرخص من أسطول+ محمّلة $903
الآن: علامة $585 < أسطول+ $599 < سيادة $879
- الشارات ← «متاح الآن» بتأكيد المالك أنها تعمل في إنتاج سيرو
- تصحيح سردية docs/33 §0 المستحيلة (كانت تبني التوسّع على باقة
تنتهي بعد 90 يوماً)
الترجمات مكتملة في اللغات الأربع — تحقُّق برمجي: صفر عناصر فارغة.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
✨ تحسينات رئيسية:
1️⃣ إصلاحات توثيقية (docs/21, docs/33):
- S18 ليست مشكلة — النظام يفرض سحب الرصيد الكامل فقط
- إضافة تنبيه حالة عن عدم جاهزية الوحدات
2️⃣ إصلاحات الموقع (marketing/index.html):
- حذف قسم #ai-modules المكرر (التكرار المحرج)
- إضافة رابط «الإضافات» في القائمة العلوية (4 لغات)
- تغيير جميع الشارات إلى «قريباً الربع القادم» (حماية قانونية)
- 7 وحدات مدفوعة واضحة مع أسعار + وصف
3️⃣ النموذج التجاري:
- النواة رخيصة = سلاح اكتساب
- الوحدات = هامش الربح الحقيقي (land-and-expand)
- بدون تكرار محرج للزائر
⚠️ الحد الأدنى قبل التسويق:
- S4 و S5 تُصلح قبل أول استنساخ على سيرفر مستأجر
- جرد صدق بند بند على إنتاج سيرو
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Same phone can now hold distinct rider and driver accounts (and wallets)
within a tenant. Unique constraint moves from (tenant, phone_bidx) to
(tenant, phone_bidx, role); login creates/finds the record matching the
app's x-app-role header. Fixes rider-app login returning role:driver for
a phone previously registered as a driver.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
الدورة السابقة أعلنت الفشل والنظام سليم — العطل كان في السكربت:
1. **`fixed` تُرفض بـ400 وهذا هو المطلوب** (أُخرجت من الزرع عمداً)، لكن
السكربت كان يعدّها فئة متوقَّعة فأسقط التغطية إلى 72/81. صارت في
`REJECTED_CLASSES`: الرفض يُتحقَّق منه صراحةً، وغيابه هو الفشل.
2. **429 على `send-otp`** (10 لكل 5 دقائق) عند تشغيلتين متتاليتين — يُنتظر
ويُعاد بدل الإبلاغ عن فشل ليس في النظام.
3. **إبطال كاش التعرفة صار خطوة في الدورة.** `getActive` تكاشي 900 ثانية،
و**Redis حاوية منفصلة لا تتأثر بإعادة تشغيل الـapi** — وتطبيق
`tariffs.sql` مباشرةً على القاعدة يتجاوز التطبيق فلا يُبطل شيئاً. النتيجة
أن النظام خدم أسعاراً قديمة عبر دورتَي نشر كاملتين وهو يعلن النجاح.
المسح الآن مبنيّ في السكربت لا متروك للتذكّر.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
## الأرقام صارت من جدول `kazan` الحيّ لا من تقدير
العمولة 11٪/12٪/14٪ مطابقة حرفياً. وثلاثة تصحيحات على الخام:
- **محورا الأردن مقلوبان**: أعمدة الفئات تحمل سعر الدقيقة (0.043) وأعمدة
النوافذ سعر الكيلومتر (0.184) — عكس مصر وسوريا. قراءتها كما هي تجعل
رحلة 27 كم بأقلّ من دينارين.
- **نِسَب الفئات في مصر وسوريا معطوبة**: الكهربائي 0.23 والفان 0.25–0.40 من
الاقتصادي، أي فان أرخص من اقتصادي. نِسَب الأردن وحدها متماسكة فاعتُمدت.
- سعر الكيلو في مصر 4 جنيهات لا 3.5 (قرار المالك).
## البنية صارت مطابقة لسيرو — وهي ما سيكتب فيه بوت استخبارات الأسعار
سعر الكيلو يتغيّر بالفئة فقط (رقم يعرفه السوق)، وسعر الدقيقة بالنافذة فقط.
**لا فتحة عدّاد** (`startPrice = 0` في كل صفوف سيرو): الحدّ الأدنى أرضية لا
رسم يُضاف — «ما في رحلة أقل من 20 جنيهاً». `fuelPrice` محفوظ كمدخل للبوت.
## تسريبان أغلقهما الاختبار الحيّ (بموافقة المالك)
1. **فئة مجهولة = رحلة مجانية**: `service_class` يأتي من الطلب بلا تحقّق،
والاستثناء كان يُبتلع فتُنشأ رحلة بـ`quoted_fare = null` ثم تُسوّى بصفر.
صار الطلب يُرفض بـ400 — الفشل الصريح أأمن من الصامت.
2. **`fixed` لا تُزرع**: سعر ثابت بلا جدول خطوط يعني رقماً واحداً لكل
الوجهات — أظهر الاختبار رحلة 55.8 كم بـ2.5 ديناراً مقابل 23.2 للاقتصادي.
300 اختبار خضر.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ضاعت دورتان كاملتان على السبب نفسه: تسلسل `up -d && restart && <اختبار>`
كان يشغّل الاختبار بينما الـapi ساقطة، فيظهر خطأ الإقلاع كـ`EAI_AGAIN` داخل
الاختبار — أي في المكان الخطأ تماماً، فيُشخَّص كعطل شبكة أو عطل سكربت.
`verify-and-test.sh` يجعل الدورة واحدة ومحروسة:
- يفحص `.env` قبل الإقلاع ويصلّح التعارض القاتل (OTP_DEV_MODE=true مع
NODE_ENV=production — حارس `main.ts` ينهي العملية لا يحذّر، فتدخل الحاوية
حلقة إعادة تشغيل).
- يميّز «حلقة إعادة تشغيل» عن «بطء إقلاع»: الأولى خطأ إقلاع يُطبع سببه من
اللوغ فوراً بدل انتظار عقيم.
- **لا اختبار قبل ردّ /health فعلياً** — هذه هي البوابة التي كانت غائبة.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
نصيحتي السابقة بتفعيل `OTP_DEV_MODE=true` على السيرفر كانت خاطئة: حارس في
`main.ts` يرفض الإقلاع عند `OTP_DEV_MODE=true` مع `NODE_ENV=production`،
فسقطت حاوية الـapi في حلقة إعادة تشغيل وظهر الفشل كـ`EAI_AGAIN` في السكربت.
الحارس صحيح ولا يُضعَف لأجل اختبار: رمز ثابت على سيرفر متاح للإنترنت يعني
أن معرفة رقم هاتف تكفي لدخول أي حساب.
السكربت صار يقرأ الرمز الحقيقي من Redis (`send-otp` يخزّنه قبل محاولة
الإرسال، فيبقى محفوظاً حتى حين يفشل الإرسال لرقم وهمي). عميل RESP أدنى على
`node:net` بلا تبعيات — الحاوية عابرة بلا `node_modules`. المفتاح يستعمل
UUID المستأجر لا الـslug، فتُجلب خريطة الـslug→UUID من `/admin/tenants`.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
عطلان في سكربت التسعير، كشفهما أول تشغيل حقيقي:
1. **إعلان نجاح على العدم** — الأخطر. فشل تسجيل الدخول فجُمع صفر صفّ، فمرّ
كل تحقّق فراغاً وطبع «الاختبار ناجح». اختبار يعلن النجاح وهو لم ينفّذ
شيئاً أسوأ من اختبار يفشل: الفشل يُرى. أُضيف حارس عدم + تحقّق تغطية
(المنفَّذ مقابل المتوقَّع)، وكلاهما يُخرج برمز فشل.
2. **تسجيل الدخول تجاوز `send-otp`** — تجاوز التطوير في `verifyOtp` مشروط
بـ`OTP_DEV_MODE=true`، وبدونه لا رمز في Redis فيُرفض الثابت 1234 بـ401.
صار يمرّ بـ`send-otp` ويأخذ `dev_code` من استجابتها، ويقول صراحةً حين
يكون الوضع التطويري مطفأً بدل أن يفشل بلا تفسير.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ثغرة كُشفت على السيرفر: `SeedService` يزرع التعرفة لـ«سيرو» وحده، فمستأجرا
`intaleq` و`yalla` وُلدا بلا تسعير وبقيا كذلك حتى شُغّل `tariffs.sql` يدوياً.
الأثر صامت لا ظاهر: بلا تعرفة فعّالة لا يُقفل سعر للراكب، ثم تأخذ
`settleFare` القيمة `quoted_fare ?? 0` — رحلة مجانية وعمولة صفر.
`provision()` صار يزرع كل فئات الخدمة بعملة البلد ومنطقته الزمنية. مستودع
التعرفة محقون مباشرةً لا عبر `TariffService`: تلك الوحدة تستورد وحدة
المستأجرين، فالاستيراد المتبادل دورة.
وسطر لوغ الزرع كان يطبع 9 دائماً (ثابتاً لا عدّاداً) فلا يميّز «زُرعت» من
«كانت موجودة» — وهو الفرق الوحيد الذي يُقرأ منه.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
يطلب رحلة حقيقية لكل فئة خدمة (9) × 3 مسافات × 3 بلدان عبر الـAPI الحي،
فالمسافة والزمن يأتيان من محرّك المسارات (انطلق) لا من افتراض.
يتحقّق آلياً من أمرين كانا عطلين حقيقيين قبل المجموعة M:
- ولا طلب يرجع بلا سعر (التعرفة المفقودة كانت تنتج رحلة مجانية بعمولة صفر).
- الفان أغلى من الاقتصادي في كل بلد (الأرقام الخام السابقة عكست الترتيب).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
السكربت أرسل x-tenant-id=tripz بينما المزروع على السيرفر «siro»، فردّ
الـAPI بـ401 Unknown tenant. صار قابلاً للتجاوز عبر TENANT_ID.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
جذر العلّة وراء أعطال الـDI الأربعة: WorkerModule استورد LocationsModule
كاملة، فجرّت الجيوفنس ← الإشعارات ← المستخدمين ← المستأجرين، وأربعة
متحكّمات HTTP تُنشأ في عملية لا تخدم HTTP.
المفرّغ يحقن Redis ومستودعَين لا غير. بإعلانه مباشرةً تسقط الحاجة إلى
I18n و Cache و Entitlements التي أضفتها في الدورتين السابقتين.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>