تعدّد المستأجرين الصارم
يُعدّ العزل بين المؤسسات الثابت التأسيسي في betool. وفيما يلي كيفية فرضه، طبقةً تلو الأخرى.
على مستوى قاعدة البيانات
يحمل كل جدول أعمال عمود org_id (من نوع UUID)، مفهرسًا ومقيّدًا بمفتاح أجنبي إلى organisation(id).
تمرّ جميع الاستعلامات على جانب الخادم عبر دوال المخزن (store methods) التي تُرشّح بشكل منهجي حسب org_id للجلسة الحالية. لا مسار برمجي يكشف استعلامًا اعتباطيًا؛ ولا يستطيع أي عميل فرض org_id مختلف.
بالنسبة للعدد القليل من الموارد التي يمكن مشاركتها عبر المؤسسات (عادةً حسابات LLM المشتركة على مستوى المنصّة)، يتيح عمود is_shared BOOLEAN NOT NULL DEFAULT FALSE موافقةً صريحة (opt-in). القواعد:
- تُصرَّح أي قراءة بـ
WHERE org_id = %s OR is_shared = TRUE. - يتطلّب أي تعديل لصفٍّ قيمته
is_shared = TRUEدور hyperadmin (مُشغّل المنصّة). - يُبطِل أي تعديل التخزين المؤقّت عالميًا — لا تباين لكل مؤسسة.
على مستوى نظام الملفّات
لكل مؤسسة جذر التخزين الخاص بها:
<data_root>/
└── orgs/
└── <org_id>/
├── fixtures/
├── uploads/
├── knowledge/
└── exchanges/
تحلّ دوال الخادم المساعِدة (org_*_dir(org_id)) هذه المسارات. لا يمكن لأي كود أعمال الكتابة خارج جذر مؤسسة.
على مستوى التخزين المؤقّت
جميع طبقات التخزين المؤقّت للتطبيق (حلّ مزوّد LLM، والسياقات الحالية، والملفّات المُحلَّلة) لكل مؤسسة على حدة. وعند تعديل مورد قيمته is_shared = TRUE، يُبطَل التخزين المؤقّت عالميًا — فلا توجد نافذة زمنية قد ترى فيها مؤسسة قيمة قديمة.
على مستوى الأسرار
تُخزَّن بيانات الاعتماد (مفاتيح LLM، ورموز مصادقة المُشغّل، وأسرار webhook) في خزينة كل مؤسسة. ولا تُعاد أبدًا بنصٍّ صريح عبر API: تُعيد مسارات GET القيمة has_api_key: bool فقط.
على خطة Enterprise، يمكن ربط الخزينة بـ HashiCorp Vault أو AWS Secrets Manager أو Azure Key Vault.
على مستوى التنفيذ
عند تشغيل خط معالجة (pipeline):
- لا تصل المُشغّلات (operators) إلّا إلى الحسابات الخارجية المُصرّح بها داخل مؤسستها.
- تُحَلّ نماذج LLM بالترتيب
الخاص > المشترك (احتياطي تلقائي)— دائمًا. - لا تكون الملفّات المرفقة قابلة للقراءة إلّا تحت جذر المؤسسة الحالية.
إذا حاول مُشغّل الوصول إلى مورد خارج نطاقه، يكون الخطأ صريحًا (OrgScopeViolation) — لا مهلة زمنية صامتة.
قائمة تحقّق عملية
كلما أُضيف مورد مشترك جديد، يُجيب الفريق عن هذه الأسئلة الأربعة:
- إذا ظهرت مؤسسة backoffice ثانية، هل يتصرّف الكود لديّ بشكل صحيح؟
- إذا عدّلتُ صفًّا مشتركًا، هل تُبطَل جميع طبقات التخزين المؤقّت لكل مؤسسة؟
- هل تبقى أسراري على جانب الخادم حصريًا؟
- هل يسمح GET لدَيّ لمُنتقيات المؤسسات الأخرى بسرد المورد دون كشف السرّ؟
إذا كانت أي إجابة «لا»، فلا يُشحَن المورد.