-
Notifications
You must be signed in to change notification settings - Fork 49
Home
There are two problems that you would face when you start to build a saas(multi-tenancy) system
-
- How to determine current scope of tenant
-
- How to do data isolation in the data storage
- Host: super admin site, where you can manage all tenants
- Tenant: tenant site, where customers can use your software
go-saas uses the go context api to store current tenant value, and define a TenantResolver interface to resolve current tenant id or name
The DefaultTenantResolver which implements TenantResolver uses slice of TenantResolveContributor and call each Resolve function one by one. It uses the Chain-of-responsibility pattern
For most web applications, you can use the implemented TenantResolveContributor like
-
CookieTenantResolveContributor: resolve from a cookie value -
DomainTenantResolveContributor: resolve from a domain regex -
FormTenantResolveContributor: resolve from a from value -
HeaderTenantResolveContributor: resolve from a header value -
QueryTenantResolveContributor: resolve from a query value
For web application build on top of gin,
you can use the MultiTenancy middileware to inject resolved tenant value in every request, sample codes
After current tenant is resolved, you can call FromCurrentTenant(ctx context.Context) BasicTenantInfo to get current tenant
TenantStore: define a query interface to resolve tenant info including with connection string key-values
go-saas defines a ConnStrResolver to resolve connection string of current tenant
The DefaultConnStrResolver resolve connection string value from config directly. And the MultiTenancyConnStrResolver use TenantStore to query current tenant info, once a host environment detected, a fallback resolve behavior to DefaultConnStrResolver would be performed
you can use NewEnableMultiTenancyDataFilter(ctx context.Context)context.Context to get a disable tenant filter context, and use this conext to access database
when you create an entity, if current tenant id is not equal with TenantId value of this entity, in tenant site, the value will be always normalize to current tenant id
You can also disable with NewDisableAutoSetTenantId(ctx context.Context)context.Context to get a disable auto set context
For application use gorm
-
- Add
HasTenantfield to your entity or addMultiTenancyto your struct
- Add
type TestEntity struct {
ID string
MultiTenancy
}
type TestEntity1 struct {
ID string
TenantId HasTenant `gorm:"index"`
}-
- Initialize a
DefaultDbProvider, initialze aGormTenantStore, and initialize aGormTenantRepoyou can see the sqlite sample in sample code
- Initialize a
-
- Do use the same
DefaultDbProviderto resolve*gorm.Dbby context, the data isolution is automaticly done bygorm
- Do use the same
-
- Do not forget to close all dbs
- Add support for more web frameworks
- Add support for more orms