انتقل إلى المحتوى الرئيسي

Multi-Tenancy

صُمّم Ithbat لتطبيقات SaaS متعددة الـ Tenants وهوية المؤسسات. كل Tenant هو نطاق هوية معزول تمامًا -- بمستخدميه وأدواره ومجموعاته وإعداداته وهويته البصرية وسجلات التدقيق الخاصة به. لا تُشارَك سجلات المستخدمين أو الـ Session Tokens بين الـ Tenants.


نظرة عامة على البنية

graph TD
subgraph Global Platform
PlatformAdmin[Platform Admin]
BillingService[Billing Service]
end

subgraph Tenant A
UsersA[Users]
RolesA[Roles & Permissions]
BrandingA[Custom Branding]
SAMLA[SAML Config]
AuditA[Audit Logs]
end

subgraph Tenant B
UsersB[Users]
RolesB[Roles & Permissions]
BrandingB[Custom Branding]
SAMLB[SAML Config]
AuditB[Audit Logs]
end

PlatformAdmin --> |manages| TenantA
PlatformAdmin --> |manages| TenantB
BillingService --> TenantA
BillingService --> TenantB

عزل البيانات

يستخدم Ithbat Row-Level Security (RLS) في PostgreSQL لفرض عزل الـ Tenants على مستوى قاعدة البيانات. يُعيَّن الـ Tenant ID الحالي في الـ PostgreSQL Session عبر (SET LOCAL app.current_tenant_id = '...') قبل كل Query، وتضمن سياسات الـ RLS أن الـ Queries ترجع فقط صفوف الـ Tenant المعني. حتى لو سمح خطأ في التطبيق بـ Cross-Tenant Query، تفرض طبقة قاعدة البيانات العزل.

عملاء خطة Enterprise يحصلون على Database Instance منفصل بالكامل.


إنشاء Tenant

Self-Service Registration

POST /api/v1/tenants/register
Content-Type: application/json

{
"name": "Acme Corp",
"slug": "acme",
"adminEmail": "[email protected]",
"adminFirstName": "Omar",
"adminLastName": "Hassan",
"plan": "growth",
"region": "ksa"
}

الـ slug يصبح الـ Subdomain للـ Tenant: acme.ithbat.io. يجب أن يكون فريدًا، lowercase، حروف وأرقام وشرطات فقط.

بعد التسجيل، يتلقى المسؤول بريد دعوة لإعداد حسابه.

إنشاء Tenant عبر الـ Platform API

يمكن لمسؤولي المنصة إنشاء Tenants مباشرة:

POST /api/v1/tenants
Authorization: Bearer {platform_admin_token}
Content-Type: application/json

{
"name": "Acme Corp",
"slug": "acme",
"plan": "enterprise",
"region": "ksa"
}

Subdomain Routing

يحصل كل Tenant على Subdomain بصيغة {slug}.ithbat.io. صفحات المصادقة المُستضافة (تسجيل الدخول، التسجيل، MFA، إعادة تعيين كلمة المرور) تُقدَّم على هذا الـ Subdomain مع الهوية البصرية الخاصة بالـ Tenant.

URLالوظيفة
acme.ithbat.ioصفحة تسجيل دخول الـ Tenant
acme.ithbat.io/registerالتسجيل الذاتي
acme.ithbat.io/forgot-passwordإعادة تعيين كلمة المرور

يحدد الـ Subdomain سياق الـ Tenant تلقائيًا -- لا حاجة لتمرير Tenant ID في الـ URL لصفحات المصادقة المُستضافة.


Custom Domains

عملاء خطتي Growth وEnterprise يمكنهم استخدام نطاقهم الخاص لواجهة المصادقة المُستضافة.

الخطوة 1 -- إضافة Custom Domain

POST /api/v1/tenant/custom-domain
Authorization: Bearer {token}
X-Tenant-ID: {tenant_id}
Content-Type: application/json

{
"domain": "auth.acme.com"
}

يتضمن الـ Response سجل DNS Verification:

{
"domain": "auth.acme.com",
"verificationToken": "ithbat-verify=abc123xyz",
"verificationRecord": {
"type": "TXT",
"name": "_ithbat-challenge.auth.acme.com",
"value": "abc123xyz"
},
"status": "pending"
}

الخطوة 2 -- إضافة DNS Records

عند الـ DNS Provider، أضف:

النوعالاسمالقيمة
TXT_ithbat-challenge.auth.acme.comabc123xyz
CNAMEauth.acme.comacme.ithbat.io

الـ DNS Propagation عادة يستغرق 5 إلى 30 دقيقة.

الخطوة 3 -- التحقق من النطاق

POST /api/v1/tenant/custom-domain/verify
Authorization: Bearer {token}
X-Tenant-ID: {tenant_id}

يتحقق Ithbat من الـ TXT Record. عند النجاح، يُفعَّل النطاق وتُصدر شهادة TLS تلقائيًا.

جلب حالة الـ Custom Domain

GET /api/v1/tenant/custom-domain
Authorization: Bearer {token}
X-Tenant-ID: {tenant_id}

إزالة الـ Custom Domain

DELETE /api/v1/tenant/custom-domain
Authorization: Bearer {token}
X-Tenant-ID: {tenant_id}

Tenant Branding

خصّص واجهة الـ Tenant المُستضافة بشعارك وألوانك وFavicon.

PATCH /api/v1/tenant/settings/branding
Authorization: Bearer {token}
X-Tenant-ID: {tenant_id}
Content-Type: application/json

{
"logoUrl": "https://cdn.acme.com/logo.svg",
"faviconUrl": "https://cdn.acme.com/favicon.ico",
"primaryColor": "#0B7285",
"accentColor": "#C8943F",
"backgroundColor": "#F7FAFB",
"companyName": "Acme Corp"
}

تُطبَّق الهوية البصرية فورًا على صفحات المصادقة المُستضافة.


Data Residency

يوفر Ithbat ثلاث مناطق نشر. عند إنشاء Tenant، يحدد حقل region مكان تخزين ومعالجة البيانات. لا تعبر البيانات حدود المناطق.

رمز المنطقةالموقعالبنية التحتية
globalالاتحاد الأوروبي (فرانكفورت)CranL Global
ksaالرياض، السعوديةCranL KSA -- البيانات تبقى داخل المملكة
egyptالقاهرة، مصرCranL Egypt

المناطق المتاحة:

GET /api/v1/regions
[
{ "code": "global", "name": "Global (EU)", "available": true },
{ "code": "ksa", "name": "Saudi Arabia (KSA)", "available": true },
{ "code": "egypt", "name": "Egypt", "available": true }
]
ملاحظة

منطقتا السعودية ومصر تعملان على بنية CranL التحتية وتلبيان متطلبات Data Residency المحلية. للعملاء الخاضعين لـ PDPL (السعودية) أو قوانين حماية البيانات المصرية، استخدم منطقة ksa أو egypt.


إعدادات الـ Tenant

جلب الإعدادات

GET /api/v1/tenant/settings
Authorization: Bearer {token}
X-Tenant-ID: {tenant_id}

تحديث الإعدادات العامة

PATCH /api/v1/tenant/settings/general
Authorization: Bearer {token}
X-Tenant-ID: {tenant_id}
Content-Type: application/json

{
"name": "Acme Corp",
"defaultLanguage": "en",
"allowRegistration": true,
"requireEmailVerification": true,
"sessionTimeout": 3600
}

تحديث الإعدادات الأمنية

PATCH /api/v1/tenant/settings/security
Authorization: Bearer {token}
X-Tenant-ID: {tenant_id}
Content-Type: application/json

{
"requireMfa": false,
"allowedAuthMethods": ["password", "saml", "google"],
"ipWhitelistEnabled": false
}

المؤسسات داخل الـ Tenant

المؤسسات هي وحدات فرعية داخل الـ Tenant -- أقسام أو عملاء أو فروع إقليمية. يمكن أن يضم الـ Tenant مؤسسات متعددة، ويمكن للمستخدمين الانتماء لمؤسسات متعددة بأدوار مختلفة.

إنشاء مؤسسة

POST /api/v1/organizations
Authorization: Bearer {token}
X-Tenant-ID: {tenant_id}
Content-Type: application/json

{
"name": "Engineering",
"description": "Product engineering team"
}

إضافة مستخدم لمؤسسة

POST /api/v1/organizations/{orgId}/members
Authorization: Bearer {token}
Content-Type: application/json

{
"userId": "3fa85f64-...",
"roles": ["role-id-1"]
}

سرد المؤسسات

GET /api/v1/organizations
Authorization: Bearer {token}
X-Tenant-ID: {tenant_id}

Tenant Lifecycle

إيقاف Tenant

يمنع الإيقاف جميع عمليات المصادقة لمستخدمي الـ Tenant. البيانات تُحفظ كما هي.

POST /api/v1/tenants/{id}/suspend
Authorization: Bearer {platform_admin_token}

إعادة تفعيل Tenant

POST /api/v1/tenants/{id}/reactivate
Authorization: Bearer {platform_admin_token}

تحديث Tenant Metadata

أرفق Metadata بصيغة Key-Value بالـ Tenant:

PATCH /api/v1/tenants/{id}/metadata
Authorization: Bearer {platform_admin_token}
Content-Type: application/json

{
"salesforceId": "0015000000XYZ",
"contractEndDate": "2027-12-31"
}

حذف Tenant

الحذف نهائي ولا رجعة فيه. جميع المستخدمين والـ Sessions وسجلات التدقيق والإعدادات تُحذف نهائيًا.

DELETE /api/v1/tenants/{id}
Authorization: Bearer {platform_admin_token}

Tenant API Reference

MethodEndpointالصلاحية
POST/api/v1/tenants/registerعام
GET/api/v1/tenants/currenttenant:read
GET/api/v1/tenants/{id}/statstenant:read
GET/api/v1/tenantstenant:write
POST/api/v1/tenantsPlatform Admin
PUT/api/v1/tenants/{id}tenant:write
DELETE/api/v1/tenants/{id}Platform Admin
POST/api/v1/tenants/{id}/suspendPlatform Admin
POST/api/v1/tenants/{id}/reactivatePlatform Admin
PATCH/api/v1/tenants/{id}/metadatatenant:write
GET/api/v1/tenant/settingssettings:read
PATCH/api/v1/tenant/settings/generalsettings:write
PATCH/api/v1/tenant/settings/brandingsettings:write
PATCH/api/v1/tenant/settings/securitysettings:write
POST/api/v1/tenant/custom-domainsettings:write
POST/api/v1/tenant/custom-domain/verifysettings:write
DELETE/api/v1/tenant/custom-domainsettings:write

الخطوات التالية