Costruire SaaS Multi-Tenant: Workspace, Ruoli, Fatturazione e Isolamento

Come progettare workspace, accesso basato sui ruoli, piani di fatturazione e isolamento dei tenant per SaaS scalabile. Architettura pratica da DigiForge.

DFDigiForge TeamJul 20, 20269 min di lettura
Blocchi astratti luminosi interconnessi su sfondo scuro che rappresentano l'architettura SaaS multi-tenant.

Il SaaS multi-tenant è l'architettura predefinita per qualsiasi piattaforma B2B che punti a crescere oltre una manciata di clienti. Tuttavia, il diavolo si nasconde nei dettagli: il modo in cui modelli gli spazi di lavoro, assegni i ruoli, strutturi la fatturazione e isoli i tenant determina se la tua piattaforma scalerà senza intoppi o collasserà sotto la complessità. In DigiForge, abbiamo costruito e ricostruito questi sistemi in dozzine di prodotti SaaS. Ecco cosa abbiamo imparato.

Spazi di lavoro: l'unità organizzativa principale

Uno spazio di lavoro è un contenitore logico che raggruppa utenti, dati e configurazione per un singolo cliente (o un team all'interno di un cliente). Abbiamo visto team confondere gli spazi di lavoro con gli account di fatturazione o addirittura con i progetti: non fatelo. Mantieni lo spazio di lavoro come ambito tenant fondamentale e sovrapponi altri concetti sopra.

Decisioni di progettazione chiave:

  • Gerarchico o piatto? Alcune piattaforme necessitano di spazi di lavoro all'interno di spazi di lavoro (ad esempio, un'azienda con più dipartimenti). Raccomandiamo una gerarchia a due livelli: organizzazione (entità di fatturazione) e spazio di lavoro (unità di team). Evita annidamenti più profondi se non assolutamente necessario: complicano l'ereditarietà dei ruoli e l'accesso ai dati.
  • Identificatori univoci: Usa uno slug leggibile (come acme o acme-marketing) per lo spazio di lavoro negli URL, ma affidati sempre a un UUID internamente. Gli slug possono cambiare; gli UUID no.
  • Soft-delete con periodo di grazia: Eliminare uno spazio di lavoro è un'azione drastica. Implementa un soft-delete di 30 giorni in modo che gli utenti possano recuperare i dati. Interrompi immediatamente la fatturazione ma conserva i dati fino alla scadenza del periodo di grazia.

Quando un nuovo utente si registra, considera il flusso di onboarding. Dovrebbe creare prima un workspace o può esplorare una sandbox? Preferiamo un flusso guidato in cui l'utente crea un'organizzazione, poi il suo primo workspace, e subito viene invitato a invitare i compagni di team. Questo riduce l'attrito e stabilisce l'aspettativa che la piattaforma è collaborativa.

Un errore comune è associare i piani di fatturazione direttamente ai workspace. Invece, associa la fatturazione a un'organizzazione che contiene uno o più workspace. Questo permette alle aziende di avere una singola fattura mentre ogni team ha il proprio workspace.

Ruoli e Permessi: Granulari, ma non troppo

Il controllo degli accessi basato sui ruoli (RBAC) è lo standard del settore, ma la granularità è importante. In DigiForge, di solito iniziamo con tre ruoli predefiniti—Admin, Membro, Visualizzatore—e permettiamo ruoli personalizzati per piani avanzati. Il ruolo Admin ha il controllo completo del workspace, i Membri possono creare e modificare la maggior parte delle risorse, e i Visualizzatori possono solo leggere.

Dove le cose si complicano è l'ambito dei permessi. I permessi dovrebbero essere limitati al workspace per impostazione predefinita, ma potresti aver bisogno di permessi a livello di organizzazione (es. gestire la fatturazione) o anche di accesso in lettura tra workspace per reportistica consolidata. Modella i permessi come un insieme di coppie azione:risorsa e assegnali ai ruoli. Memorizza le assegnazioni in una tabella di join: (workspace_id, user_id, role_id).

Consiglio da professionista: Evita di controllare le autorizzazioni solo a livello applicativo. Sposta quanta più logica di autorizzazione possibile nel database utilizzando la sicurezza a livello di riga (RLS) o un motore di policy come OPA. Questo riduce la probabilità che un bug nel livello web esponga i dati di qualcun altro.

Un pattern che ci ha dato buoni risultati è memorizzare nella cache il ruolo dell'utente all'interno di un token di sessione (JWT) invece di interrogare il database a ogni richiesta. Ma attenzione: se memorizzi i ruoli nei JWT, devi avere un meccanismo per invalidare i token quando un ruolo cambia (ad esempio, scadenza breve del token o una blocklist).

Pensa anche all'ereditarietà dei ruoli: un Amministratore dell'organizzazione dovrebbe avere automaticamente il ruolo di Amministratore in tutti i workspace? La nostra regola pratica: i ruoli dell'organizzazione forniscono un tetto massimo, ma i ruoli del workspace possono essere più restrittivi. Ad esempio, un Amministratore dell'organizzazione può accedere a qualsiasi workspace, ma un Amministratore del workspace non può accedere alla fatturazione.

Modelli di fatturazione e pricing: meta-dati, non logica di business

La fatturazione è dove il multi-tenancy diventa concreto. Il tuo modello di pricing (per utente, per workspace, basato sull'utilizzo o a livelli) deve riflettersi nel tuo modello dati, ma il sistema di fatturazione dovrebbe essere disaccoppiato dall'applicazione principale. Utilizza un provider di fatturazione di terze parti (Stripe, Recurly, Chargebee) e conserva solo l'ID dell'abbonamento e l'ID del piano nel tuo database.

Raccomandiamo il seguente approccio per il database:

  1. Una tabella plans che definisce lo slug del piano, il prezzo e i flag delle funzionalità (ad esempio, max_users, storage_gb, api_rate_limit).
  2. Una tabella organizations con un campo current_plan_id e billing_provider_subscription_id. Collega le organizzazioni ai workspace tramite una tabella di join.
  3. Una tabella features (o una semplice colonna JSON) che memorizza le eccezioni. Ad esempio, se un cliente negozia una tariffa personalizzata, sovrascrivi il prezzo del piano a livello di organizzazione.

La parte più difficile è limitare l'accesso in base al piano. Hai due opzioni: applicare i limiti nell'applicazione (controllare max_users prima di invitare) o tramite conteggi di righe e trigger nel database. Preferiamo l'applicazione a livello applicativo perché produce messaggi di errore migliori per l'utente, ma aggiungiamo sempre un job di riconciliazione notturno che segnala le organizzazioni che superano i limiti.

Gli upgrade e downgrade dei piani richiedono una gestione attenta. Quando un cliente effettua un upgrade, concedi immediatamente l'accesso alle nuove funzionalità ma applica il pro-rating della fatturazione tramite il tuo provider. In caso di downgrade, devi decidere: bloccare l'accesso alle funzionalità che eccedono il nuovo piano o concedere un periodo di grazia? Raccomandiamo un periodo di grazia pari al ciclo di fatturazione corrente, dopo il quale applichi le restrizioni.

Una lezione dal campo: non lasciare mai che i fallimenti di fatturazione causino perdita di dati. Se un pagamento fallisce, degrada con garbo (ad esempio, limita le operazioni di scrittura) ma non eliminare i dati. Il tuo cliente pagherà—prima o poi.

Isolamento dei Tenant: Condiviso vs. Silo

L'isolamento è la decisione architetturale più importante. Il compromesso standard è tra un database condiviso (un database per tutti i tenant, con una colonna tenant_id su ogni tabella) e un database per tenant (ogni workspace ha il proprio database). Abbiamo sperimentato entrambi e, per la maggior parte dei progetti, abbiamo optato per un approccio ibrido.

  • Condiviso con RLS rigoroso: Adatto per tenant piccoli e medi (sotto i 10.000 utenti ciascuno). La sicurezza a livello di riga è integrata in Postgres e utilizziamo una variabile di sessione (app.tenant_id) per filtrare ogni query. È la soluzione più semplice da gestire e aggiornare.
  • Database per tenant: Necessario quando i tenant richiedono conformità rigorosa (HIPAA, SOC 2, GDPR per la residenza dei dati) o quando l'applicazione è I/O-intensive per tenant. L'overhead operativo è reale: le migrazioni dello schema devono essere applicate a centinaia di database, ma strumenti come Flyway e CI automatizzati lo rendono gestibile.
  • Schema per tenant: Una via di mezzo che utilizza schemi separati all'interno di un unico database. Offre più isolamento di una tabella condivisa ma meno overhead operativo rispetto a database completi. Lo utilizziamo per i piani di fascia bassa e aggiorniamo i clienti a database per tenant se necessario.

Indipendentemente dalla strategia di isolamento, non consentire mai l'accesso diretto al database dal client. Instrada sempre attraverso un livello API che impone l'identità del tenant. E per il bene del tuo team di turno: non usare mai, mai tenant_id negli URL senza verificare che l'utente autenticato appartenga a quel tenant.

La migrazione dei dati tra livelli di isolamento è una realtà. Ad esempio, quando un tenant supera le capacità del database condiviso, potrebbe essere necessario migrarlo a un database dedicato. Pianifica per tempo: scrivi uno script di migrazione che esporti e importi i dati, e testalo con dati simili a quelli di produzione. Dovrebbe essere possibile eseguirlo senza tempi di inattività utilizzando un approccio blue-green.

Provisioning Automatico: Lascia Fare alla Macchina

Avviare manualmente nuovi tenant può funzionare per i primi dieci clienti, ma non scala. Come evidenziato dal recente brevetto di ContractorHUB, l'implementazione zero-touch è un fattore differenziante chiave per il SaaS multi-tenant [1]. Abbiamo costruito flussi di lavoro di provisioning che automatizzano tutto, dalla creazione del database (o clonazione dello schema) al seeding dei dati predefiniti e all'invio di email di benvenuto.

Una tipica pipeline di provisioning automatizzato:

  1. L'utente si registra, crea un'organizzazione e seleziona un piano.
  2. Un webhook dal tuo provider di fatturazione attiva un job di provisioning (ad esempio, una funzione serverless o un Job Kubernetes).
  3. Il job crea il livello di isolamento del tenant (schema o database), esegue le migrazioni iniziali e popola ruoli e impostazioni predefiniti.
  4. Un secondo job invia un'email con le istruzioni di accesso e i passaggi successivi.
  5. L'utente viene reindirizzato al nuovo spazio di lavoro, completamente funzionante, in pochi secondi.

L'idempotenza è fondamentale qui. Se il job di provisioning fallisce a metà, deve essere sicuro riprovare. Avvolgiamo l'intero processo in una macchina a stati con una colonna provisioning_status sulla riga dell'organizzazione: pending → creating → active → failed. Gli stati falliti vengono inviati a una coda di messaggi non elaborabili per l'intervento umano.

Non dimenticare di predisporre l'infrastruttura di supporto: record DNS per domini personalizzati, cache warmer CDN, limiti di rate API per tenant e alert di monitoraggio. Automatizza tutto ciò che può essere scriptato, perché i passaggi manuali verranno dimenticati sotto pressione.

Conclusione: La Mentalità Multi-Tenant

La multi-tenancy non è qualcosa che si aggiunge dopo il lancio. Deve guidare il tuo modello dati, il controllo degli accessi, l'integrazione della fatturazione e la strategia di deployment fin dal primo giorno. La buona notizia: se imposti correttamente questi quattro pilastri—workspace, ruoli, fatturazione, isolamento—il resto del tuo SaaS diventa notevolmente più facile da costruire e mantenere.

Ogni SaaS è diverso, ma i pattern sopra descritti ci hanno servito bene in vari settori. Che tu stia iniziando il tuo MVP o scalando a migliaia di tenant, ti incoraggiamo a riflettere attentamente su queste decisioni. E se desideri un secondo parere sulla tua architettura, siamo sempre felici di rivederla.

#multi-tenant#saas#workspace#ruoli#fatturazione#isolamento#provisioning
DF

DigiForge Team

Il team di engineering di DigiForge — realizza siti web moderni, modules e automazione, e scrive sull’arte di rilasciare prodotti web veloci e duraturi.

Parliamone

Hai un progetto
in mente?

Raccontaci cosa stai realizzando — definiremo un piano chiaro e l’approccio giusto per il tuo prodotto.

Inizia il tuo progetto