מולטי-טננט קפדני
הבידוד בין ארגונים הוא האינווריאנט המבני של 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 (מפעיל פלטפורמה). - כל מוטציה מבטלת את הקאש גלובלית — אין סטייה per-org.
ברמת מערכת הקבצים
לכל ארגון שורש אחסון משלו:
<data_root>/
└── orgs/
└── <org_id>/
├── fixtures/
├── uploads/
├── knowledge/
└── exchanges/
ה-helpers של השרת (org_*_dir(org_id)) פותרים נתיבים אלה. אין קוד עסקי שיכול לכתוב מחוץ לשורש של ארגון.
ברמת הקאש
כל הקאשים האפליקטיביים (פתרון provider LLM, קונטקסטים פעילים, קבצים מפוענחים) הם per-org. כאשר משאב is_shared = TRUE מתעדכן, הקאש מתבטל גלובלית — אין חלון שבו ארגון יראה ערך ישן.
ברמת הסודות
ה-credentials (מפתחות LLM, טוקני auth של מפעיל, סודות webhook) מאוחסנים בכספת של כל ארגון. הם לעולם אינם מוחזרים בטקסט גלוי על ידי ה-API: נתיבי GET מחזירים רק has_api_key: bool.
בתוכנית Enterprise, הכספת ניתנת לחיבור ל-HashiCorp Vault, AWS Secrets Manager או Azure Key Vault.
ברמת ההרצה
כאשר פייפליין מתבצע:
- למפעילים יש גישה רק לחשבונות החיצוניים שהוגדרו בארגון.
- מודלי LLM נפתרים בסדר
own > shared (fallback auto)— תמיד. - קבצים מצורפים קריאים רק תחת שורש הארגון הנוכחי.
אם מפעיל מנסה לגשת למשאב מחוץ לפרימטר, השגיאה מפורשת (OrgScopeViolation) — לא timeout שקט.
מבחן מעשי
בכל הוספת משאב ניתן-לשיתוף חדש, הצוות עונה על 4 שאלות:
- אם יופיע ארגון backoffice שני, האם הקוד שלי מתנהג כראוי?
- אם אשנה שורת shared, האם כל הקאשים per-org יתבטלו?
- האם הסודות שלי נשארים בקפדנות server-side?
- האם ה-GET שלי מאפשר ל-pickers של ארגונים אחרים לרשום את המשאב, מבלי לחשוף את הסוד?
אם תשובה אחת היא לא — המשאב אינו נמסר.