Construirea unui SaaS Multi-Tenant: Spații de lucru, Roluri, Facturare și Izolare

Cum să proiectezi spații de lucru, acces bazat pe roluri, niveluri de facturare și izolare a chiriașilor pentru un SaaS scalabil. Arhitectură practică de la DigiForge.

DFEchipa DigiForgeJul 20, 20269 min de citit
Blocuri abstracte interconectate și strălucitoare pe fundal întunecat, reprezentând arhitectura SaaS multi-tenant.

Multi-tenant SaaS este arhitectura implicită pentru orice platformă B2B care intenționează să crească dincolo de câțiva clienți. Cu toate acestea, diavolul stă în detalii: modul în care modelezi spațiile de lucru, atribui roluri, structurezi facturarea și izolezi chiriașii determină dacă platforma ta se scalează lin sau se prăbușește sub complexitate. La DigiForge, am construit și reconstruit aceste sisteme în zeci de produse SaaS. Iată ce am învățat.

Spații de lucru: Unitatea de bază a organizării

Un spațiu de lucru este un container logic care grupează utilizatori, date și configurație pentru un singur client (sau o echipă din cadrul unui client). Am văzut echipe care confundă spațiile de lucru cu conturile de facturare sau chiar cu proiectele—nu faceți acest lucru. Păstrați spațiul de lucru ca domeniu fundamental al chiriașului și stratificați alte concepte deasupra.

Decizii cheie de design:

  • Ierarhic sau plat? Unele platforme au nevoie de spații de lucru în cadrul altor spații de lucru (de exemplu, o întreprindere cu multiple departamente). Recomandăm o ierarhie pe două niveluri: organizație (entitate de facturare) și spațiu de lucru (unitate de echipă). Evitați înnestirea mai profundă decât este absolut necesar—complică moștenirea rolurilor și accesul la date.
  • Identificatori unici: Folosiți un slug ușor de citit de către om (precum acme sau acme-marketing) pentru spațiul de lucru în URL-uri, dar bazați-vă întotdeauna pe un UUID intern. Slug-urile se pot schimba; UUID-urile nu ar trebui.
  • Ștergere soft cu perioadă de grație: Ștergerea unui spațiu de lucru este o acțiune drastică. Implementați o ștergere soft de 30 de zile, astfel încât utilizatorii să poată recupera datele. Opriți facturarea imediat, dar păstrați datele până la expirarea perioadei de grație.

Când un utilizator nou se înregistrează, gândește-te la fluxul de integrare. Ar trebui să creeze mai întâi un spațiu de lucru sau poate explora un sandbox? Preferăm un flux ghidat în care utilizatorul creează o organizație, apoi primul său spațiu de lucru și imediat este invitat să adauge colegi. Acest lucru reduce frecarea și stabilește așteptarea că platforma este colaborativă.

O greșeală comună este atașarea planurilor de facturare direct la spațiile de lucru. În schimb, atașează facturarea la o organizație care conține unul sau mai multe spații de lucru. Acest lucru permite întreprinderilor să aibă o singură factură, oferind în același timp fiecărei echipe propriul spațiu de lucru.

Roluri și Permisiuni: Granularitate Fină, dar nu Prea Fină

Controlul accesului bazat pe roluri (RBAC) este standardul industriei, dar granularitatea contează. La DigiForge, de obicei începem cu trei roluri încorporate—Admin, Membru, Vizualizator—și permitem roluri personalizate pentru planurile avansate. Rolul Admin are control complet asupra spațiului de lucru, Membrii pot crea și edita majoritatea resurselor, iar Vizualizatorii pot doar citi.

Unde lucrurile devin complicate este domeniul de aplicare al permisiunilor. Permisiunile ar trebui să fie limitate la spațiul de lucru în mod implicit, dar poți avea nevoie de permisiuni la nivel de organizație (de exemplu, gestionarea facturării) sau chiar acces de citire între spații de lucru pentru raportare consolidată. Modelează permisiunile ca un set de perechi acțiune:resursă și atribuie-le rolurilor. Stochează atribuirile într-un tabel de legătură: (workspace_id, user_id, role_id).

Sfat util: Evitați să verificați permisiunile doar la nivelul aplicației. Împingeți cât mai multă logică de autorizare în baza de date, folosind securitatea la nivel de rând (RLS) sau un motor de politici precum OPA. Astfel reduceți riscul ca o eroare în stratul web să expună datele altcuiva.

Un model care ne-a fost de folos este să stocăm în cache rolul utilizatorului într-un token de sesiune (JWT), în loc să interogăm baza de date la fiecare cerere. Dar atenție: dacă stocați rolurile în JWT-uri, trebuie să aveți un mecanism de invalidare a tokenurilor atunci când un rol se schimbă (de exemplu, expirare scurtă a tokenului sau o listă neagră).

De asemenea, gândiți-vă la moștenirea rolurilor: ar trebui ca un Admin al organizației să fie automat Admin în toate spațiile de lucru? Regula noastră de bază: rolurile organizației oferă un plafon, dar rolurile spațiilor de lucru pot fi mai restrictive. De exemplu, un Admin al organizației poate accesa orice spațiu de lucru, dar un Admin al spațiului de lucru nu poate accesa facturarea.

Facturare și modele de preț: meta-date, nu logică de business

Facturarea este locul unde multi-tenanța devine reală. Modelul dvs. de preț – per utilizator, per spațiu de lucru, bazat pe utilizare sau pe niveluri – trebuie reflectat în modelul de date, dar sistemul de facturare ar trebui să fie decuplat de aplicația principală. Folosiți un furnizor terț de facturare (Stripe, Recurly, Chargebee) și păstrați în baza de date doar ID-ul abonamentului și ID-ul planului.

Recomandăm următoarea abordare pentru baza de date:

  1. Un tabel plans care definește slug-ul planului, prețul și flag-urile de funcționalități (de exemplu, max_users, storage_gb, api_rate_limit).
  2. Un tabel organizations care are un current_plan_id și un billing_provider_subscription_id. Leagă organizațiile de spațiile de lucru printr-un tabel de asociere.
  3. Un tabel features (sau o coloană JSON simplă) care stochează suprascrieri. De exemplu, dacă un client negociază o rată personalizată, suprascrie prețul planului la nivel de organizație.

Cea mai grea parte este limitarea accesului în funcție de plan. Ai două opțiuni: aplică limitele în aplicație (verifică max_users înainte de a invita) sau aplică-le prin numărul de rânduri din baza de date și declanșatoare. Noi preferăm aplicarea la nivel de aplicație, deoarece produce mesaje de eroare mai bune pentru utilizator, dar adăugăm întotdeauna un job de reconciliere nocturn care semnalează organizațiile care depășesc limitele.

Actualizările și retrogradările planurilor necesită o gestionare atentă. Când un client face upgrade, acordă imediat acces la noile funcționalități, dar proratază facturarea prin furnizorul tău. La downgrade, trebuie să decizi: blochezi accesul la funcționalitățile care depășesc noul plan sau permiți o perioadă de grație? Recomandăm o perioadă de grație pentru ciclul de facturare curent, după care aplici restricțiile.

O lecție din tranșee: nu lăsa niciodată eșecurile de facturare să ducă la pierderea datelor. Dacă o plată eșuează, degradează elegant (de exemplu, restricționează operațiile de scriere), dar nu șterge datele. Clientul tău va plăti—în cele din urmă.

Izolarea chiriașilor: partajat vs. siloz

Izolarea este cea mai importantă decizie arhitecturală. Compromisul standard este între o bază de date partajată (o singură bază de date pentru toți chiriașii, cu o coloană tenant_id în fiecare tabel) și o bază de date per chiriaș (fiecare spațiu de lucru primește propria bază de date). Am folosit ambele abordări și am optat pentru o abordare hibridă în majoritatea proiectelor.

  • Partajat cu RLS strict: Potrivit pentru chiriași mici și mijlocii (sub 10.000 de utilizatori fiecare). Securitatea la nivel de rând este încorporată în Postgres, iar noi folosim o variabilă de sesiune (app.tenant_id) pentru a filtra fiecare interogare. Aceasta este cea mai simplă abordare din punct de vedere operațional și al upgrade-urilor.
  • Bază de date per chiriaș: Necesară atunci când chiriașii impun conformitate strictă (HIPAA, SOC 2, GDPR privind rezidența datelor) sau când aplicația este intensivă în I/O per chiriaș. Costurile operaționale sunt reale—migrările de schemă trebuie aplicate la sute de baze de date—dar instrumente precum Flyway și CI automatizat fac acest lucru gestionabil.
  • Schemă per chiriaș: Un compromis care folosește scheme separate într-o singură bază de date. Oferă mai multă izolare decât un tabel partajat, dar cu un efort operațional mai mic decât bazele de date complete. Folosim această abordare pentru planurile inferioare și facem upgrade clienților la bază de date per chiriaș dacă este necesar.

Indiferent de strategia de izolare, nu permiteți niciodată accesul direct la baza de date din client. Treceți întotdeauna printr-un strat API care impune identitatea chiriașului. Și, de dragul echipei de gardă: nu folosiți niciodată tenant_id în URL-uri fără a valida că utilizatorul autentificat aparține acelui chiriaș.

Migrarea datelor între nivelurile de izolare este o realitate. De exemplu, atunci când un chiriaș depășește capacitatea bazei de date partajate, poate fi necesar să îl migrați către o bază de date dedicată. Planificați din timp: scrieți un script de migrare care exportă și importă date și testați-l cu date similare celor din producție. Ar trebui să fie posibilă rularea fără timp de nefuncționare, folosind o abordare blue-green.

Provizionare automată: lasă mașina să facă treaba

Configurarea manuală a noilor entități poate funcționa pentru primii zece clienți, dar nu se scalează. După cum subliniază recentul brevet al ContractorHUB, implementarea fără atingere este un factor cheie de diferențiere pentru SaaS multi-tenant [1]. Am construit fluxuri de provizionare care automatizează totul, de la crearea bazei de date (sau clonarea schemei) până la popularea datelor implicite și trimiterea e-mailurilor de bun venit.

Un pipeline tipic de provizionare automată:

  1. Utilizatorul se înregistrează, creează o organizație și selectează un plan.
  2. Un webhook de la furnizorul de facturare declanșează un job de provizionare (de exemplu, o funcție serverless sau un Kubernetes Job).
  3. Jobul creează stratul de izolare al entității (schemă sau bază de date), rulează migrările inițiale și populează rolurile și setările implicite.
  4. Un al doilea job trimite un e-mail cu instrucțiuni de autentificare și pașii următori.
  5. Utilizatorul este redirecționat către noul spațiu de lucru—pe deplin funcțional—în câteva secunde.

Idempotența este esențială aici. Dacă jobul de provizionare eșuează la jumătate, trebuie să fie sigur să fie reîncercat. Învelim întregul proces într-o mașină de stări cu o coloană provisioning_status pe rândul organizației: pending → creating → active → failed. Stările eșuate sunt trimise într-o coadă de mesaje moarte pentru intervenție umană.

Nu uitați să asigurați infrastructura de suport: înregistrări DNS pentru domenii personalizate, încălzitoare de cache CDN, limite de rată API per chiriaș și alerte de monitorizare. Automatizați tot ce poate fi scriptat, deoarece pașii manuali vor fi uitați sub presiune.

Concluzie: Mentalitatea Multi-Chiriaș

Multi-chiriașul nu este ceva ce adaugi după lansare. Trebuie să ghideze modelul tău de date, controlul accesului, integrarea facturării și strategia de implementare încă din prima zi. Vestea bună: dacă ai aceste patru piloni—spații de lucru, roluri, facturare, izolare—corect, restul SaaS-ului tău devine remarcabil de ușor de construit și întreținut.

Fiecare SaaS este diferit, dar modelele de mai sus ne-au servit bine în diverse industrii. Fie că abia începi MVP-ul sau te extinzi la mii de chiriași, te încurajăm să reflectezi profund asupra acestor decizii. Și dacă dorești o a doua pereche de ochi pe arhitectura ta, suntem întotdeauna bucuroși să o analizăm.

#multi-tenant#saas#spatii-de-lucru#roluri#facturare#izolare#provisionare
DF

Echipa DigiForge

Echipa de inginerie DigiForge — construim site-uri moderne, module și automatizări și scriem despre arta de a livra produse web rapide și durabile.

Hai să vorbim

Ai un proiect
în minte?

Spune-ne ce construiești — vom stabili un plan clar și abordarea potrivită pentru produsul tău.

Începe proiectul