إصلاح انحدار أدخلتُه: /admin/overview كان يستعلم عن `t.created_at` وهو غير
موجود في كيان الرحلة (الاسم `requested_at`)، فترجع النقطة 500 ويُفرَّغ جدول
المستأجرين في لوحة السوبر-أدمن. فحص الأنواع لم يمسكه لأن استعلامات
QueryBuilder نصوص، والمحكّ الذي كان سيمسكه لم يُشغَّل.
قرارات المالك 2026-07-18:
- الخرائط: `intaleq_maps` حصراً (SDK انطلق على MapLibre). تصحيح قرار سابق
خاطئ: flutter_map + latlong2 طبقة منافسة تعطي نوعَي LatLng متضاربين.
السبب ليس عمل جوجل في سوريا — بل قِدَم بياناتها في المنطقة.
- docs/24 جديد: فلسفة المال — فصل الإيراد (شحن السائق · رسوم العمليات) عن
الأمانة (شحن الراكب)، بمحفظتين لا بحقل حالة، ودفتر مضاف فقط.
- P موسّعة (بوابات · تسوية بالرسائل لكليك/شام كاش · رسوم بالدولة · تقارير)
و O5 (ترتيب المهام المجدولة)، وتأجيل Android Auto/CarPlay.
- الحزم: نسخ سيرو الأحدث + live_activities لشاشة القفل في iOS.
تنظيف: إخراج 463 ملف بناء NDK من التتبّع، وإخراج شهادات التوقيع ومفتاح
App Store من المستودع (تُولَّد من جديد عند الحاجة) مع تحديث .gitignore.
الملفات باقية على القرص — أُزيلت من الفهرس فقط.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- اللوحات الثلاث تُخدم من نفس أصل الـAPI (/panel/{superadmin,admin,service})
عبر useStaticAssets + bind mount، فترث TLS القائم بلا دومين ولا CORS.
- تعليق المستأجر كان زخرفة: tenant.status يُكتب ويُعرض بلا أي فرض. الآن
يُفرض في JwtStrategy (نقطة واحدة) + AuthService.resolveTenant، مع إبطال
الكاش ليسري فوراً، وتمرير عند تعذّر القراءة حتى لا تسقط المنصة كلها.
- GET /admin/overview: رحلات · GMV · إيراد المنصة لكل مستأجر باستعلام
واحد مجمَّع (لا N+1).
- توثيق قرار طبقات التطبيق (const flags + tree-shaking · أصيل موحّد
لـShorebird · طبقتا الإعداد) في docs/22 §1.5.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PlatformGuard (x-platform-secret، مقارنة ثابتة الزمن) يحرس admin/tenants*
و admin/features و platform/*. بدونه كان أدمن أي مستأجر يرقّي اشتراكه بنفسه
— أي أن المجموعة K كلها كانت زينة. سرّ غير مضبوط = منع الجميع لا فتح الباب
(الإعداد الناقص خطأ تشغيلي شائع، وفتح الباب عنده أسوأ من إغلاقه).
admin/users/:id/role تبقى لأدمن المستأجر: نطاقها من التوكن، وليست نقطة منصة.
سياسة الدين لكل مستأجر (قرار المالك): كل مشغّل يحدّد كم ديناً يسمح به،
و0 خيار صريح = لا دين إطلاقاً.
- tenants.settings jsonb — سياسات تشغيل يحكمها المستأجر، منفصلة عن features
(استحقاقات يحكمها السوبر-أدمن): «كيف تشتغل» مقابل «ماذا اشتريت»
- credit-policy.ts: debt_allowance + signup_bonus لكل عملة. الافتراضات
صُحّحت لقيم المالك: 2 JOD · 200 SYP · 200 EGP (كانت 5/500/500)
- تُخزَّن موجبةً («كم ديناً أسمح؟») لا كأرضية سالبة — أوضح للمشغّل و0 بلا
لبس في الإشارة
- PATCH /credit/policy لأدمن المستأجر؛ updateSettings يدمج عميقاً فلا يمحو
سياسة أخرى، ويُبطل الكاش وإلا سرت السياسة القديمة حتى ساعة
- إعداد مكسور يسقط للافتراض لا لدين بلا حدّ. والصفر لا يُبتلع (فخّ ||)
هجرة: TenantSettings.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
القاعدة (docs/19): علم الميزة في التطبيق قرار عرض لا حدّ أمني. من يفكّك
التطبيق ويفعّل الأعلام يرى الشاشة ثم يصطدم بـ403 من FeatureGuard.
- K1: FeatureGuard + @RequiresFeature — tenant_id من التوكن الموقَّع لا من
ترويسة. الوحدة عالمية عمداً: إجبار كل وحدة على استيرادها = نقطة منسيّة
يوماً ما، والمنسيّة ميزة مجانية للجميع
- K2: كتالوج الميزات + افتراضات الباقات. الافتراض هو المنع (قائمة بيضاء):
ميزة جديدة تبقى محجوبة حتى تُمنح صراحةً
- K3: GET /admin/features · GET /admin/tenants/:id/entitlements ·
PATCH /admin/tenants/:id/subscription — يدمج features لا يستبدلها
(استبدالها كان سيمحو المشتريات السابقة) ويُبطل الكاش فوراً
- K4: drivers_max عند apply — عند الإنشاء فقط، فسائق قائم لا يُطرد بتغيير باقة
- K5: /tenant/config يرجع الاستحقاقات المحسوبة لا features الخام (الخام
تجاوزات فقط فكان سيُظهر ميزات الباقة مطفأة)
- K6: اختبار أن الترويسة لا تزوّر المستأجر + أن الافتراض منع لا سماح
- K7: السيادة = كل الميزات — المستأجر يملك السيرفر فالحجب هناك وهم لا حماية
محروس: dispatch · chat · payments/charge. المدفوعات لكل نقطة لا للصنف —
الـwebhook بلا JWT فحارس الصنف كان سيمنعه.
seed: المستأجر التجريبي siro صار sovereign (قرار المالك: أول مشترك بالباقة
الكاملة) — وأيضاً يمنع حجب dispatch وحدّ 500 سائق من إسقاط سكربتات التحقق.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
الأساس: common/cache — كاش-جانبي فوق Redis. مبدأ صارم: فشل Redis لا يُسقط
الطلب (يُسجَّل ويُرجَع للقاعدة) — الكاش تحسين أداء لا مصدر حقيقة.
- G1: لغة المستخدم في Redis (كانت استعلاماً قبل كل إشعار)؛ تُكتب عند
PATCH /users/me فيصير الإصابة دائمة
- G2/G3: توكنات FCM في Redis — يُبطَل عند register وعند اكتشاف توكن ميت.
البث الجماعي صار بلا استعلامات قاعدة
- G4: كاش tenant resolve/config + إبطال عند الإنشاء
- G5: كاش التعرفة و ride-types + إبطال صريح عند أي إنشاء
- G6: التقييم يتراكم في Redis، والقاعدة تُكتب مرة واحدة يومياً لكل طرف
(حجز الكتابة ذرّي بـLua). التأخير مقصود ليبعد الاحتكاك بين الطرفين.
أُضيف ratings.target_user_id و users.rating — تقييم السائق للراكب كان
يُخزَّن بلا هدف فلا يُجمَّع أبداً
- كاش الخرائط (route/reverse/geocode) بإحداثيات مقرَّبة 4 خانات (~11م):
نداء انطلق كان يهيمن على p50 (2.9s). لا يُخزَّن الرجوع لخط مستقيم ولا
استجابة فاشلة
تصحيح: ادّعيت سابقاً أن tenants.resolve يعمل على كل request — خطأ.
tenant_id يأتي من الـJWT؛ resolve يُستدعى عند الدخول و3 كنترولرات فقط.
الحمل الأثقل فعلياً هو رفع موقع السائق (المجموعة H).
هجرة: RatingsBothParties.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>