iKonekt
Открыть консоль

Разделение

Границу держит база данных, а не код

Каждая CRM заявляет, что она многопользовательская (multi-tenant). Заявка ничего не стоит; важно, какой уровень держит границу. Если ответ — «наше приложение всегда добавляет правильный фильтр», то гарантия ровно настолько хороша, насколько выспался наименее отдохнувший разработчик, писавший запрос.

iKonekt был многопользовательским с первой миграции, а не дооснащён задним числом — это звучит как похвальба, а на деле является признанием: дооснастить систему этим убедительно почти невозможно, и у всех, кто пытался, есть своя история.

Разделение живёт в базе данных. Каждая из двадцати шести таблиц несёт своего арендатора, и политика, проверяющая это, выполняется при каждом чтении и каждой записи — целиком ниже уровня приложения. Запрос, забывший о границе, не вернёт чужих клиентов. Он не вернёт ничего.

Безопасность на уровне строк, принудительная

Не соглашение, не правило код-ревью. База данных отказывает. Семьдесят две политики, написанные по одной, а не сгенерированные, — потому что сгенерированную политику никто не читал.

Составные ключи

Дочерняя запись ссылается на своего арендатора и на родительскую запись одновременно, как пара. Случайный идентификатор из чужой компании не разрешается — он просто не является корректной ссылкой.

Никакого арендатора по умолчанию — никогда

Запрос без области действия не превращается тихо в запрос к арендатору номер ноль. Он падает с ошибкой до того, как достигнет базы данных. Не существует режима «без области», который можно забыть выключить.

Ошибка, которая не могла себя объявить

Пока шла работа над изоляцией арендаторов, большинство ошибок были громкими. Дайте двум компаниям один домен клиентов, и объекты базы данных отреагируют мгновенно — с кодом ошибки и трассировкой стека; вы исправите это до обеда.

Один случай не возражал. Таблица редактируемых переопределений промптов была ключована только по виду промпта — а не по виду и арендатору. Вторая компания, редактируя свою копию, молча перезаписала бы копию первой — совершенно корректным SQL, без ошибки, без предупреждения и без падающего теста. Это нашли, читая все оставшиеся уникальные индексы по одному после изменения ключа — из подозрения, что у громких ошибок есть тихие спутники.

Мы упоминаем это, потому что это честная картина такой работы. Изоляция — не функция, которую включают переключателем; это привычка читать скучные части схемы в предположении, что там что-то с вами не согласно.

Тесты, для протокола: их 942, и они выполняются на базе данных, пересоздаваемой с нуля при каждом изменении. Они существуют не для того, чтобы доказать остроумность дизайна. Они существуют потому, что режим отказа этого дизайна — молчаливый, а молчаливым отказам нужен тот, кто кричит от их имени.

Что изоляция даёт обычному человеку

  • Группа может вести несколько компаний на одной установке, и продавец из одной никогда не увидит клиента другой — не по правилу, а по конструкции.
  • Партнёрская программа, набор промптов, закрепление клиента — всё ограничено рамками одной компании, поэтому конфигурация одного арендатора не может стать достоянием всех.
  • Запрос на удаление данных исполняется в пределах границы, а не по общей куче, — именно это позволяет отвечать на него честно.
  • И никому не нужно ничего помнить. В этом и суть: гарантия, которая зависит от того, что её помнят, — не гарантия.

Ещё одна строка — не о базах данных

Каждый соседний сервис в семье хранит своё собственное именованное полномочие. Ничто не говорит под общим, поэтому ни один сервис не может случайно действовать от имени другого — небольшая дисциплина, родившаяся напрямую из опыта существования общего токена, который никому не доставил радости.

Это тот же инстинкт, что и правило базы данных. Сделайте неправильное невозможным, а не только порицаемым — и вы тратите внимание на клиентов, а не на бдительность.

ГраницаНиже уровня приложения
  • 126 таблицКаждая несёт своего арендатора, причём проверка принудительно включена.
  • 272 политикиВыписанные по отдельности, так что каждую прочитал человек.
  • 3942 тестаНа базе данных, пересоздаваемой с нуля при каждом изменении.
  • 40 арендаторов по умолчаниюЗапрос без контекста никогда не доходит до данных.

Измерено на живой сборке

«Наше приложение всегда фильтрует по компании».

«Всегда» в этой фразе делает очень большую работу.

Опустите границу вниз, в базу данных, — и забытая конструкция WHERE вернёт пустоту, а не чужих клиентов. Пустой экран — лучший отказ, чем неловкое знакомство.

Для групп, ведущих несколько брендов →