ADR
ADR-002: Multi-tenant архитектура с первого дня
ADR-002: Multi-tenant архитектура с первого дня
Статус: ✅ Accepted
Дата: 2026-06-11
Автор: openclaw-architect
Контекст
SprosOS Seed начинается с одного клиента (EcoYar), но North Star — международный SaaS. Рассматривались подходы:
- Single-tenant сейчас, multi-tenant потом — быстрый старт, но дорогой рефакторинг
- Multi-tenant с первого дня — выше начальная сложность, но без переписывания
- Multi-instance — отдельный инстанс для каждого клиента
Решение
Выбираем multi-tenant архитектуру с первого дня.
Все сущности, связанные с данными клиента, содержат organization_id (tenant_id). Каждый запрос фильтруется по tenant. Изоляция на уровне базы данных — через WHERE-условия, не через отдельные схемы.
Архитектура tenancy:
Organization (tenant) → Workspace → Project
Детали реализации
// Каждая сущность содержит tenant_id
interface Evidence {
id: string;
organization_id: string; // tenant
workspace_id: string;
project_id: string;
// ... domain fields
}
// Каждый repository-запрос фильтрует по tenant
class EvidenceRepository {
async findByProject(organizationId: string, projectId: string): Promise<Evidence[]> {
// WHERE organization_id = ? AND project_id = ?
}
}
Последствия
Положительные (+)
- SaaS-ready: Любой новый клиент — просто новая Organization
- Изоляция с первого дня: Ошибка безопасности маловероятна
- Единая схема БД: Проще миграции, бэкапы, мониторинг
Отрицательные (-)
- Каждый запрос сложнее — нужно передавать и проверять organization_id
- Риск ошибки: Пропущенный фильтр tenant — утечка данных
- Нет физической изоляции: Проблемы одного tenant могут влиять на всех
Стратегия смягчения
- Middleware для автоматической подстановки organization_id
- Repository-level защита: утечка tenant_id = ошибка компиляции
- Тесты с cross-tenant сценариями
- Rate limiting для tenant'ов
Связанные документы
- PROJECT_CONSTITUTION.md (Multi-tenant с первого дня)
- ARCHITECTURE_PRINCIPLES.md (Tenant Isolation)
- CORE_DOMAIN_MODEL.md (Organization, Workspace, Project)
- DECISION_LOG.md (#002)