- docs/00-15: دراسة، بنية، محرك تعرفة، تسعير، نموذج استئجار، تكاملات، بيانات، realtime، خطة، devops، لاندنج، مخاطر، اصطلاحات سيرفر، تدفق نشر - backend/: NestJS 11 على Docker (health + tenants + عزل tenant_id + بادئة tripz_ + Redis DB 3) - apps/rider, apps/driver, dashboards/admin-web, dashboards/superadmin-web (هياكل) - sync-to-server.sh + .gitignore Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
60 lines
3.2 KiB
Markdown
60 lines
3.2 KiB
Markdown
# 06 — نموذج الاستئجار متعدد المستأجرين
|
|
|
|
## وضعان
|
|
### 1. القياسي (Shared) — الافتراضي
|
|
- نشرة واحدة مشتركة، قاعدة واحدة، عمود **`tenant_id`** في كل جدول.
|
|
- نطاق إلزامي على مستوى الـ Repository (نفس نمط انطلق الحالي).
|
|
- الأرخص تشغيلاً والأسرع تحديثاً. يخدم باقات انطلاقة/علامة/أسطول+.
|
|
|
|
### 2. السيادة (Sovereign / Enterprise)
|
|
- نسخة معزولة كاملة (Docker Compose / K8s namespace) داخل بلد المستأجر أو على خوادمه.
|
|
- **نفس الكود، متغيرات بيئة مختلفة** — لا فرع كود منفصل.
|
|
- المنتج المضاد لثغرة Onde السيادية. يخدم باقة سيادة.
|
|
|
|
## فرض العزل (الأهم أمنياً)
|
|
- **كل استعلام يُنطَّق بـ `tenant_id`** — لا استثناء.
|
|
- يُفرض عبر أحد نمطين (يُحسم في P0):
|
|
- **Repository scoped:** مستودع مخصّص يحقن الشرط تلقائياً.
|
|
- **TypeORM subscriber/query filter:** فلتر عام يُضاف لكل استعلام.
|
|
- `TenantGuard` يستخرج `tenant_id` من الـ subdomain/header/JWT ويحقنه في سياق الطلب (AsyncLocalStorage).
|
|
- **اختبار اختراق العزل** ضمن CI: طلب من مستأجر A لا يرى بيانات B أبداً.
|
|
|
|
## حزمة الدولة (Country Pack)
|
|
ملف إعداد لكل دولة يجمع كل ما يختلف بين الأسواق:
|
|
```yaml
|
|
country: JO
|
|
currency: JOD
|
|
rounding: { increment: 0.05 }
|
|
locale: ar
|
|
direction: rtl
|
|
phone: { length: 9, prefix: "+962" }
|
|
otp: { length: 4, ttl_sec: 300 }
|
|
payments: [cash, cliq, zaincash]
|
|
sms_provider: local_jo
|
|
maps_scope: "amman,zarqa,irbid"
|
|
default_tariff_mode: time_or_distance # العداد المنظّم
|
|
regulator: ltrc # هيئة تنظيم النقل البري
|
|
legal_docs: { terms: jo/terms.md, privacy: jo/privacy.md }
|
|
```
|
|
**المستأجر الجديد = country pack + هوية بصرية. لا كود جديد.**
|
|
|
|
## التطبيقات: كود واحد، نكهة لكل مستأجر
|
|
```
|
|
كود موحّد (راكب+سائق)
|
|
→ flavor لكل مستأجر (bundle id, أيقونة, ألوان, مفاتيح FCM)
|
|
→ إعداد تشغيلي من GET /tenant/config عند الإقلاع
|
|
→ fastlane + CI ينشران كل النكهات بأمر واحد
|
|
```
|
|
- ديناميكي (من API، بلا إصدار متجر): النصوص، الميزات، طرق الدفع، التعرفة، الألوان.
|
|
- بالبناء فقط (flavor): اسم الحزمة، الأيقونة، مفاتيح FCM.
|
|
- **الهدف الصلب: مستأجر جديد في يوم عمل واحد.** إن احتاج أكثر — النموذج لا يتوسع.
|
|
|
|
## جدول tenants (مبسّط)
|
|
```
|
|
tenants: id, name, slug, country_pack, plan, mode (shared|sovereign),
|
|
branding (jsonb), features (jsonb), status, created_at
|
|
```
|
|
راجع [08-data-model](08-data-model.md) للتفصيل.
|
|
|
|
← السابق: [05-pricing-billing](05-pricing-billing.md) · التالي: [07-integrations](07-integrations.md)
|