
Три архитектурных решения для multi-tenant B2B SaaS, о которых я пожалел, что не узнал раньше
Isaev1980 7 минут назад Три архитектурных решения для multi-tenant B2B SaaS, о которых я пожалел, что не узнал раньше Средний 10 мин 201 Python * PostgreSQL * Информационная безопасность * Программирование * Кейс Из...
Anthropic — What company has the best second artificial intelligence model at the end of June?
В сфере искусственного интеллекта произошло заметное событие. Isaev1980 7 минут назад Три архитектурных решения для multi-tenant B2B SaaS, о которых я пожалел, что не узнал раньше Средний 10 мин 201 Python * PostgreSQL * Информационная безопасность * Программирование * Кейс Из песочницы Самая дорогая ошибка моего B2B SaaS имела ровно одну строчку```python # app/config. py TENANT_ID = "tenant-1" ```Когда у меня был один тенант, всё работало корректно. На втором — половина админ-сущностей (врачи, услуги, прайс-листы) начала пропадать из интерфейса клиента.
Не «не сохраняться» — а появляться в БД с чужим tenant_id. Я полтора дня смотрел на эту мистику, прежде чем понял: 30 endpoint’ов берут tenant_id из closure из config, а не из user. Очевидно в ретроспективе.
Технические детали
Совершенно невидимо во время первого пилота. Этот разбор — про три архитектурных решения для multi-tenant SaaS в регулируемой отрасли, которые принимаются в первую неделю и потом годами либо экономят месяцы рефакторинга, либо тихо копят техдолг. 11 / FastAPI / SQLAlchemy 2.
Контекст: B2B SaaS для частных медицинских клиник, 152-ФЗ, real-time scheduling. TL;DR- Multi-tenancy через tenant_id column + helper scoped_select с первого коммита — даже если тенант один. - Защита от double-booking через PostgreSQL EXCLUDE USING gist + tsrange — реальные цифры: 12 конкурентных запросов на один слот → 1×200, 11×409, без application-level lock'ов.
- 152-ФЗ — это поля и helpers: data_category enum в audit_logs с автоклассификатором, прозрачная миграция с PBKDF2 на argon2id без forced reset, patient_consents со scoped версионированием. - Один баг с захардкоженным TENANT_ID показывает, почему все три решения нужно закладывать сразу. - Operational tooling: read-only integrity check на семь категорий аномалий + schema drift detection через alembic check на чистой PG.
Отраслевые последствия
Решение №1: multi-tenancy через tenant_id columnТри классических подхода к multi-tenancy в реляционной БД:СтратегияИзоляцияBackup/migrationsСтоимостьКогда подходитSchema-per-tenantНа уровне PostgresСложная (N схем × M миграций)Средняя5–50 enterprise тенантов с разными SLADatabase-per-tenantЖелезнаяОчень сложнаяВысокаяCompliance-driven, ≤10 тенантовShared DB + tenant_idНа уровне приложенияПростая (одна схема)НизкаяSMB SaaS, сотни–тысячи тенантовЯ выбрал третий вариант. Каждая бизнес-таблица содержит tenant_id TEXT NOT NULL с индексом, все запросы обязаны фильтровать по нему. Цена этой простоты — единственная ошибка в фильтре превращается в IDOR на чувствительные данные между тенантами.
Чтобы это не забывать, в проекте есть тонкий helper:```python # app/tenant_scope. py from sqlalchemy import select from sqlalchemy. sql import Select def scoped_select(model, user) -> Select: """SELECT, автоматически ограниченный текущим тенантом.
Падает PermissionError, если у user нет tenant_id — это намеренно: лучше 500-ка в логах, чем тихая утечка. tenant_id: raise PermissionError("User has no tenant_id; refusing to query return select(model).
Этот прогресс даёт важные сигналы о будущем отрасли, и технологический мир внимательно наблюдает.





