Документация

Строгая мультитенантность

Как betool изолирует ваши данные, секреты и исполнения от других организаций.

Строгая мультитенантность

Изоляция между организациями — основополагающий инвариант betool. Вот как она обеспечивается, слой за слоем.

На уровне базы данных

Каждая бизнес-таблица содержит столбец org_id (UUID), индексированный и ограниченный внешним ключом на organisation(id).

Все серверные запросы проходят через методы хранилища (store), которые систематически фильтруют по 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, токены аутентификации operator, секреты webhook) хранятся в хранилище каждой организации. Они никогда не возвращаются в открытом виде API: маршруты GET возвращают только has_api_key: bool.

В тарифе Enterprise хранилище может быть подключено к HashiCorp Vault, AWS Secrets Manager или Azure Key Vault.

На уровне исполнения

При запуске pipeline:

  • operator имеют доступ только к внешним учётным записям, объявленным в своей организации.
  • Модели LLM разрешаются в порядке own > shared (автоматический fallback) — всегда.
  • Прикреплённые файлы читаемы только в пределах корня текущей организации.

Если operator пытается получить доступ к ресурсу вне своей области, ошибка является явной (OrgScopeViolation) — а не молчаливым таймаутом.

Практический чек-лист

Всякий раз при добавлении нового совместно используемого ресурса команда отвечает на эти 4 вопроса:

  1. Если появится вторая организация backoffice, будет ли мой код вести себя корректно?
  2. Если я изменяю общую строку, инвалидируются ли все кэши по организациям?
  3. Остаются ли мои секреты строго на стороне сервера?
  4. Позволяет ли мой GET picker-ам других организаций перечислить ресурс, не раскрывая секрет?

Если хотя бы один ответ отрицательный, ресурс не выпускается.