Изграждане на мулти-тенант SaaS: Работни пространства, роли, таксуване и изолация

Как да проектираме работни пространства, базиран на роли достъп, нива на таксуване и изолация на клиенти за мащабируем SaaS. Практическа архитектура от DigiForge.

DFЕкипът на DigiForgeJul 20, 20268 мин четене
Абстрактни светещи взаимосвързани блокове на тъмен фон, представящи мулти-тенант SaaS архитектура.

Мулти-тенантният SaaS е стандартната архитектура за всяка B2B платформа, която очаква да надхвърли шепа клиенти. Но дяволът се крие в детайлите: как моделирате работни пространства, задавате роли, структурирате таксуването и изолирате клиентите, определя дали платформата ви ще се мащабира гладко или ще рухне под сложността. В DigiForge сме изграждали и преизграждали тези системи в десетки SaaS продукти. Ето какво научихме.

Работни пространства: Основната единица за организация

Работното пространство е логически контейнер, който групира потребители, данни и конфигурация за един клиент (или екип в рамките на клиент). Виждали сме екипи да смесват работни пространства с акаунти за таксуване или дори с проекти – не го правете. Запазете работното пространство като основен обхват на клиента и надградете с други концепции.

Ключови дизайнерски решения:

  • Йерархично или плоско? Някои платформи се нуждаят от работни пространства в рамките на работни пространства (напр. предприятие с няколко отдела). Препоръчваме двустепенна йерархия: организация (платежно лице) и работно пространство (екипна единица). Избягвайте по-дълбоко влагане, освен ако не е абсолютно необходимо – усложнява наследяването на роли и достъпа до данни.
  • Уникални идентификатори: Използвайте четим от човек slug (като acme или acme-marketing) за работното пространство в URL адресите, но винаги разчитайте на UUID вътрешно. Slugs могат да се променят; UUID не трябва.
  • Меко изтриване с гратисен период: Изтриването на работно пространство е драстично действие. Въведете 30-дневно меко изтриване, за да могат потребителите да възстановят данните. Спрете таксуването веднага, но запазете данните до изтичане на гратисния период.

Когато нов потребител се регистрира, помислете за процеса на въвеждане. Трябва ли първо да създаде работно пространство или може да изследва пясъчна среда? Ние предпочитаме насочен процес, при който потребителят създава организация, след това първото си работно пространство и веднага получава подкана да покани съотборници. Това намалява триенето и задава очакването, че платформата е колаборативна.

Често срещана грешка е привързването на планове за таксуване директно към работни пространства. Вместо това, привържете таксуването към организация, която съдържа едно или повече работни пространства. Това позволява на предприятията да имат единична фактура, като същевременно дава на всеки екип собствено работно пространство.

Роли и разрешения: детайлни, но не прекалено

Контролът на достъпа на база роли (RBAC) е индустриален стандарт, но детайлността е от значение. В DigiForge обикновено започваме с три вградени роли — Администратор, Член, Наблюдател — и позволяваме персонализирани роли за разширени планове. Ролята на администратор има пълен контрол върху работното пространство, членовете могат да създават и редактират повечето ресурси, а наблюдателите могат само да четат.

Където нещата стават сложни е обхватът на разрешенията. Разрешенията трябва да бъдат ограничени до работното пространство по подразбиране, но може да са необходими разрешения на ниво организация (напр. управление на таксуване) или дори достъп за четене между работни пространства за консолидирано отчитане. Моделирайте разрешенията като набор от двойки action:resource и ги присвоявайте на роли. Съхранявайте присвояванията в свързваща таблица: (workspace_id, user_id, role_id).

Pro съвет: Избягвайте да проверявате разрешения само на ниво приложение. Прехвърлете колкото се може повече от логиката за права към базата данни, като използвате сигурност на ниво редове (RLS) или механизъм за политики като OPA. Това намалява вероятността грешка в уеб слоя да разкрие чужди данни.

Един модел, който ни е служил добре, е да кешираме ролята на потребителя в токен на сесията (JWT), вместо да правим заявка към базата данни при всяка заявка. Но внимавайте: ако кеширате роли в JWT, трябва да имате механизъм за анулиране на токените при промяна на роля (например кратък срок на валидност на токена или черен списък).

Също така помислете за наследяване на роли: трябва ли администратор на организация автоматично да бъде администратор във всички работни пространства? Нашето правило е: ролите на организация задават горна граница, но ролите в работно пространство могат да бъдат по-ограничителни. Например, администратор на организация може да има достъп до всяко работно пространство, но администратор на работно пространство не може да вижда таксуването.

Модели на таксуване и ценообразуване: Мета-данни, а не бизнес логика

Таксуването е мястото, където мулти-тенантността става реална. Вашият ценови модел – на потребител, на работно пространство, на база използване или на нива – трябва да бъде отразен в модела на данни, но системата за таксуване трябва да бъде отделена от основното приложение. Използвайте външен доставчик на таксуване (Stripe, Recurly, Chargebee) и пазете само ID на абонамента и ID на плана в базата данни.

Препоръчваме следния подход за базата данни:

  1. Таблица plans, която дефинира slug на плана, цена и функционални флагове (напр. max_users, storage_gb, api_rate_limit).
  2. Таблица organizations с колони current_plan_id и billing_provider_subscription_id. Свържете организациите с работните пространства чрез свързваща таблица.
  3. Таблица features (или обикновена JSON колона), която съхранява презаписвания. Например, ако клиент договори персонализирана цена, презапишете цената на плана на ниво организация.

Най-трудната част е ограничаването на достъпа според плана. Имате два избора: прилагайте ограничения в приложението (проверете max_users преди да поканите) или чрез броячи на редове и тригери в базата данни. Ние предпочитаме проверките на ниво приложение, защото те дават по-добри съобщения за грешки за потребителя, но винаги добавяме нощна задача за съгласуване, която маркира организациите, надхвърлящи лимитите си.

Надстройките и понижаванията на планове изискват внимателно боравене. Когато клиент надстрои, незабавно предоставете достъп до новите функции, но пропорционално изчислете таксуването чрез вашия доставчик. При понижаване трябва да решите: блокирайте достъпа до функции, които надхвърлят новия план, или позволете гратисен период? Препоръчваме гратисен период до края на текущия цикъл на фактуриране, след което наложете ограничения.

Един урок от окопите: никога не допускайте грешките при фактуриране да доведат до загуба на данни. Ако плащането се провали, деградирайте грациозно (напр. ограничете записващите операции), но не изтривайте данни. Вашият клиент ще плати – рано или късно.

Изолация на клиенти: Споделено срещу Силоз

Изолацията е най-важното архитектурно решение. Стандартният компромис е между споделена база данни (една база за всички клиенти, с колона tenant_id във всяка таблица) и база данни на клиент (всяко работно пространство получава своя собствена база). Използвали сме и двата подхода и сме се сп спрели на хибриден подход за повечето проекти.

  • Споделена със строги RLS: Подходяща за малки до средни клиенти (под 10 000 потребителя всеки). Защитата на ниво ред е вградена в Postgres и използваме променлива на сесията (app.tenant_id), за да филтрираме всяка заявка. Това е най-лесното за поддръжка и надграждане.
  • База данни на клиент: Необходима, когато клиентите изискват строго съответствие (HIPAA, SOC 2, GDPR за местоположение на данни) или когато приложението е интензивно на I/O за клиент. Оперативната тежест е реална — миграциите на схема трябва да се прилагат към стотици бази — но инструменти като Flyway и автоматизиран CI го правят управляемо.
  • Схема на клиент: Среден път, използващ отделни схеми в една база данни. Предлага по-голяма изолация от споделена таблица, но по-малка оперативна тежест от отделни бази. Използваме това за по-ниските планове и надграждаме клиентите до база данни на клиент, ако имат нужда.

Независимо от стратегията за изолация, никога не позволявайте директен достъп до базата данни от клиента. Винаги маршрутизирайте през API слой, който налага идентичността на клиента. И за бога на екипа ви за поддръжка: никога, ама никога не използвайте tenant_id в URL адреси, без да потвърдите, че удостовереният потребител принадлежи към този клиент.

Миграцията на данни между нивата на изолация е реалност. Например, когато клиент надхвърли капацитета на споделената база данни, може да се наложи да го мигрирате към специална база. Планирайте това рано: напишете скрипт за миграция, който експортира и импортира данни, и го тествайте с данни, подобни на продукционните. Трябва да е възможно да се изпълни без прекъсване, като се използва подход синьо-зелено.

Автоматизирано осигуряване: Оставете машината да свърши работата

Ръчното създаване на нови клиенти може да работи за първите десет, но не мащабира. Както подчертава скорошният патент на ContractorHUB, имплементацията с нулево докосване е ключов фактор за разграничаване на мулти-тенант SaaS [1]. Ние изградихме работни потоци за осигуряване, които автоматизират всичко – от създаване на база данни (или клониране на схеми) до попълване на данни по подразбиране и изпращане на приветствени имейли.

Типичен конвейер за автоматизирано осигуряване:

  1. Потребителят се регистрира, създава организация и избира план.
  2. Уебхук от вашия доставчик на таксуване задейства задача за осигуряване (напр. сървърна функция или Kubernetes Job).
  3. Задачата създава изолационния слой на клиента (схема или база данни), изпълнява начални миграции и попълва роли и настройки по подразбиране.
  4. Втора задача изпраща имейл с инструкции за вход и следващи стъпки.
  5. Потребителят бива пренасочен към новото работно пространство – напълно функционално – в рамките на секунди.

Идемпотентността не подлежи на обсъждане тук. Ако задачата за осигуряване се провали по средата, трябва да е безопасно да се опита отново. Опаковаме целия процес в крайна машина с колона provisioning_status в реда на организацията: pending → creating → active → failed. Неуспешните състояния се изпращат в опашка за мъртви писма за човешка намеса.

Не забравяйте да осигурите поддържащата инфраструктура: DNS записи за персонализирани домейни, загряване на CDN кеш, лимити на API заявки на клиент и мониторинг аларми. Автоматизирайте всичко, което може да се скриптира, защото ръчните стъпки ще бъдат забравени под напрежение.

Заключение: Мисленето за мулти-тенантност

Мулти-тенантността не е нещо, което добавяте след старта. Тя трябва да ръководи вашия модел на данни, контрол на достъпа, интеграция на таксуване и стратегия за разгръщане от самото начало. Добрата новина: ако поставите правилно тези четири стълба — работни пространства, роли, таксуване и изолация — останалата част от вашия SaaS става значително по-лесна за изграждане и поддръжка.

Всеки SaaS е различен, но гореописаните модели са ни служили добре в различни индустрии. Независимо дали започвате своя MVP или мащабирате до хиляди клиенти, насърчаваме ви да обмислите задълбочено тези решения. А ако искате второ мнение за вашата архитектура, винаги сме готови да я прегледаме.

#мулти-тенант#saas#работни-пространства#роли#таксуване#изолация#провизиране
DF

Екипът на DigiForge

Инженерният екип на DigiForge — изграждащ модерни уебсайтове, modules и automation, и пишещ за изкуството на създаване на бързи, устойчиви уеб продукти.

Нека разговаряме

Имате ли проект
в предвид?

Споделете какво изграждате — ще изготвим ясен план и правилния подход за вашия продукт.

Стартирайте вашия проект