gotenancy

package module
v0.1.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 9, 2026 License: Apache-2.0 Imports: 1 Imported by: 0

README

GoTenancy

Go Reference CI License

GoTenancy is an ORM-independent Go toolkit for shared-database multi-tenancy with a required tenant_id boundary.

It provides tenant context, tenant resolution, data guards, web/RPC middleware, tenant metadata storage, and common SaaS modules. The default model is simple: every tenant-owned row carries tenant_id, and adapters derive the active tenant from context.Context.

Scope

  • Shared-database isolation with a required tenant_id boundary.
  • Host-wide access only through explicit host context.
  • GORM, Ent, and sqlx adapters for tenant-aware data access.
  • HTTP, Gin, Echo, Fiber, Kratos, and gRPC middleware.
  • Tenant lifecycle, plans, subscriptions, quotas, features, RBAC, audit, users, and notifications.

Independent database and hybrid isolation models are not implemented. Future optional extension capabilities can live in separate modules, but the core adoption adapters ship with the main module.

Requirements

  • Go 1.23+.

Install

go mod init your-app
go get github.com/DarkInno/gotenancy

Complete Example

This copy-paste example creates an in-memory tenant, installs the GORM plugin, runs a tenant-scoped query in GORM DryRun mode, and prints the generated SQL. It does not require a live database.

package main

import (
	"context"
	"fmt"
	"log"

	tenantctx "github.com/DarkInno/gotenancy/core/context"
	"github.com/DarkInno/gotenancy/core/store"
	"github.com/DarkInno/gotenancy/core/types"
	gormtenant "github.com/DarkInno/gotenancy/data/gorm"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

type Order struct {
	ID       uint
	TenantID string `gorm:"column:tenant_id"`
	Number   string `gorm:"column:number"`
}

func main() {
	ctx := context.Background()
	tenants := store.NewMemoryStore()
	if err := tenants.Create(ctx, types.Tenant{
		ID:     "tenant-a",
		Name:   "Tenant A",
		Status: types.TenantStatusActive,
	}); err != nil {
		log.Fatal(err)
	}

	tenant, err := tenants.Get(ctx, "tenant-a")
	if err != nil {
		log.Fatal(err)
	}
	ctx = tenantctx.WithTenant(ctx, tenant)

	db, err := gorm.Open(mysql.New(mysql.Config{
		DSN:                       "user:pass@tcp(localhost:3306)/app?parseTime=true",
		SkipInitializeWithVersion: true,
	}), &gorm.Config{
		DryRun:                 true,
		DisableAutomaticPing:   true,
		SkipDefaultTransaction: true,
	})
	if err != nil {
		log.Fatal(err)
	}
	if err := db.Use(gormtenant.New(gormtenant.Config{})); err != nil {
		log.Fatal(err)
	}

	var orders []Order
	result := db.WithContext(ctx).Find(&orders)
	if result.Error != nil {
		log.Fatal(result.Error)
	}

	fmt.Println(result.Statement.SQL.String())
	fmt.Println(result.Statement.Vars)
}

Adoption Examples

Run the examples from the repository root:

go run ./examples/quickstart
go run ./examples/gin-gorm
go run ./examples/grpc
go run ./examples/ent
  • examples/quickstart: minimal GORM create flow.
  • examples/gin-gorm: Gin header resolver, tenant store validation, request context injection, and GORM query guard.
  • examples/grpc: unary gRPC interceptor that resolves tenant metadata and injects tenant context.
  • examples/ent: Ent query and mutation filters using the storage-level interfaces generated builders expose.

Common Patterns

Register the GORM plugin once on startup:

if err := db.Use(gormtenant.New(gormtenant.Config{})); err != nil {
	log.Fatal(err)
}

Resolve tenants at the edge, then pass context.Context through application and data layers:

tenantResolver := resolver.NewComposite(
	resolver.NewHeaderContrib("", types.TenantIDStrategyString),
)
router.Use(gingotenancy.TenantMiddleware(tenantResolver, tenants))

Filter Ent queries before execution:

query := client.Order.Query()
if err := enttenant.FilterQuery(ctx, query, enttenant.Config{}); err != nil {
	return err
}
orders, err := query.All(ctx)

Register the Ent mutation hook with generated clients:

client.Use(enttenant.Hook(enttenant.Config{}))

Protect gRPC handlers with tenant metadata:

server := grpc.NewServer(
	grpc.UnaryInterceptor(grpcgotenancy.TenantUnaryServerInterceptor(tenants)),
)

Use explicit host context for host-wide operations:

ctx := tenantctx.WithHost(context.Background())

Packages

  • core/types: tenant IDs, tenant metadata, status, and side types.
  • core/context: tenant and host context, detach, and switch.
  • core/resolver: header, cookie, query, domain, token-claim, and composite resolvers.
  • core/store: memory store, paginated list filters, memory cache, cached store decorator, and database/sql store.
  • data: ORM-independent tenant filter condition.
  • data/gorm: GORM plugin, guard suite, host-only SafeRaw/SafeExec, BulkCreate, and delete APIs.
  • data/ent: Ent selector predicate, query filter, mutation filter, and hook APIs.
  • data/sqlx: tenant-filtered APIs for simple single-table SELECT/UPDATE/DELETE statements.
  • saas/tenant: tenant lifecycle state machine.
  • saas/plan: plan CRUD.
  • saas/subscription: subscription lifecycle and billing hook.
  • saas/quota: quota checking and atomic consumption.
  • saas/feature: plan defaults plus tenant-level feature overrides.
  • web/*: tenant middleware and guards for net/http, Gin, Echo, Fiber, and Kratos.
  • rpc/grpc: gRPC unary and stream tenant interceptors.
  • migration: tenant column and index planning.
  • cache: tenant-scoped cache wrapper and memory adapters.
  • obs: observability fields and redaction.
  • biz/*: user, RBAC, audit, and notification modules.

Verification

go test ./...
go vet ./...
go test -race ./...

On Windows, go test -race requires cgo and a C compiler. Without local cgo, run race tests in Docker:

docker run --rm -v "${PWD}:/workspace" -w /workspace -e CGO_ENABLED=1 -e GOFLAGS=-mod=readonly golang:1.23 go test -race ./...

Optional database integration tests:

(cd tests/db && GOTENANCY_MYSQL_DSN='<mysql-dsn>' go test ./... -run TestSQLStoreMySQLIntegration -count=1)
(cd tests/db && GOTENANCY_POSTGRES_DSN='<postgres-dsn>' go test ./... -run TestSQLStorePostgresIntegration -count=1)
GOTENANCY_MYSQL_DSN='<mysql-dsn>' go test ./data/gorm -run TestMySQLIntegrationEnforcesTenantIsolation -count=1

Project Layout

core/          Tenant context, resolver, store, and types
data/          Data filtering contracts and adapters
saas/          Tenant lifecycle, plan, subscription, quota, and feature modules
web/           Web framework and net/http integration
migration/     Tenant schema migration planning
cache/         Tenant-aware cache abstractions
rpc/           RPC metadata propagation
obs/           Observability fields and redaction
biz/           User, RBAC, audit, and notification modules
examples/      Runnable examples
tests/         Security, cache, concurrency, and local-only DB integration tests
docs/          API, security, and compatibility notes

Compatibility

See docs/compatibility.md.

License

Apache License 2.0

Documentation

Overview

Package gotenancy defines shared errors for tenant isolation and host boundary checks.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNoTenant reports that a tenant-scoped operation was called without a tenant context.
	ErrNoTenant = errors.New("gotenancy: no tenant in context")

	// ErrForbidden reports that the current tenant or side is not allowed to perform an operation.
	ErrForbidden = errors.New("gotenancy: forbidden")

	// ErrInvalidState reports an invalid tenant lifecycle transition or unsupported state.
	ErrInvalidState = errors.New("gotenancy: invalid state")

	// ErrHostRequired reports that an operation requires explicit host-side context.
	ErrHostRequired = errors.New("gotenancy: host context required")

	// ErrTenantMismatch reports that a resource belongs to a different tenant than the active context.
	ErrTenantMismatch = errors.New("gotenancy: tenant mismatch")
)

Functions

This section is empty.

Types

This section is empty.

Directories

Path Synopsis
biz
audit
Package audit stores tenant-scoped audit events for SaaS applications.
Package audit stores tenant-scoped audit events for SaaS applications.
notification
Package notification defines tenant-scoped notification messages and in-memory delivery helpers.
Package notification defines tenant-scoped notification messages and in-memory delivery helpers.
rbac
Package rbac provides tenant-scoped role and permission checks.
Package rbac provides tenant-scoped role and permission checks.
user
Package user manages users and tenant membership metadata.
Package user manages users and tenant membership metadata.
Package cache contains tenant-aware cache abstractions.
Package cache contains tenant-aware cache abstractions.
Package core contains tenant context, resolver, store, and type abstractions.
Package core contains tenant context, resolver, store, and type abstractions.
context
Package tenantctx stores tenant and host-side execution state in context.Context.
Package tenantctx stores tenant and host-side execution state in context.Context.
resolver
Package resolver extracts tenant identifiers from HTTP headers, cookies, query parameters, domains, and token claims.
Package resolver extracts tenant identifiers from HTTP headers, cookies, query parameters, domains, and token claims.
store
Package store defines tenant metadata storage contracts and memory, cached, and SQL implementations.
Package store defines tenant metadata storage contracts and memory, cached, and SQL implementations.
types
Package types defines tenant identifiers, tenant metadata, lifecycle statuses, and host/tenant side markers.
Package types defines tenant identifiers, tenant metadata, lifecycle statuses, and host/tenant side markers.
Package data contains ORM-independent tenant filtering contracts.
Package data contains ORM-independent tenant filtering contracts.
ent
Package enttenant adapts GoTenancy data filters to Ent SQL selectors.
Package enttenant adapts GoTenancy data filters to Ent SQL selectors.
gorm
Package gormtenant adds tenant-aware query, mutation, preload, raw SQL, and delete guardrails to GORM.
Package gormtenant adds tenant-aware query, mutation, preload, raw SQL, and delete guardrails to GORM.
sqlx
Package sqlxtenant provides tenant-filtered helpers for simple sqlx-style SELECT, UPDATE, and DELETE statements.
Package sqlxtenant provides tenant-filtered helpers for simple sqlx-style SELECT, UPDATE, and DELETE statements.
examples
ent command
Command ent demonstrates Ent query and mutation tenant filters without generated schema code.
Command ent demonstrates Ent query and mutation tenant filters without generated schema code.
gin-gorm command
Command gin-gorm demonstrates Gin tenant resolution with GORM tenant query guards.
Command gin-gorm demonstrates Gin tenant resolution with GORM tenant query guards.
grpc command
Command grpc demonstrates tenant context injection with a gRPC unary interceptor.
Command grpc demonstrates tenant context injection with a gRPC unary interceptor.
quickstart command
Command quickstart demonstrates a minimal GORM create flow with tenant context.
Command quickstart demonstrates a minimal GORM create flow with tenant context.
internal
testcontract
Package testcontract contains reusable contract tests for stores and filters.
Package testcontract contains reusable contract tests for stores and filters.
Package migration contains tenant schema migration planning APIs.
Package migration contains tenant schema migration planning APIs.
Package obs provides tenant observability fields and redaction helpers for structured logs.
Package obs provides tenant observability fields and redaction helpers for structured logs.
rpc
Package rpc propagates tenant metadata through framework-neutral carriers.
Package rpc propagates tenant metadata through framework-neutral carriers.
grpc
Package grpcgotenancy adapts GoTenancy tenant propagation to gRPC interceptors.
Package grpcgotenancy adapts GoTenancy tenant propagation to gRPC interceptors.
Package saas contains tenant lifecycle, plan, subscription, quota, and feature modules.
Package saas contains tenant lifecycle, plan, subscription, quota, and feature modules.
feature
Package feature resolves plan defaults and tenant-level feature overrides.
Package feature resolves plan defaults and tenant-level feature overrides.
plan
Package plan manages SaaS plan metadata, features, and quotas.
Package plan manages SaaS plan metadata, features, and quotas.
quota
Package quota checks and consumes tenant quotas with concurrency-safe in-memory storage.
Package quota checks and consumes tenant quotas with concurrency-safe in-memory storage.
subscription
Package subscription manages tenant plan subscriptions and billing hooks.
Package subscription manages tenant plan subscriptions and billing hooks.
tenant
Package tenant manages tenant lifecycle transitions and host-only destructive operations.
Package tenant manages tenant lifecycle transitions and host-only destructive operations.
tests
cache
Package cache contains tenant cache contract tests.
Package cache contains tenant cache contract tests.
concurrency
Package concurrency contains tenant context concurrency tests.
Package concurrency contains tenant context concurrency tests.
security
Package security contains cross-adapter tenant isolation guard tests.
Package security contains cross-adapter tenant isolation guard tests.
web
Package web contains web framework integration adapters.
Package web contains web framework integration adapters.
echo
Package echogotenancy adapts GoTenancy tenant middleware to Echo.
Package echogotenancy adapts GoTenancy tenant middleware to Echo.
fiber
Package fibergotenancy adapts GoTenancy tenant middleware to Fiber.
Package fibergotenancy adapts GoTenancy tenant middleware to Fiber.
gin
Package gingotenancy adapts GoTenancy tenant middleware and guards to Gin.
Package gingotenancy adapts GoTenancy tenant middleware and guards to Gin.
http
Package httpgotenancy adapts GoTenancy tenant middleware and guards to net/http.
Package httpgotenancy adapts GoTenancy tenant middleware and guards to net/http.
kratos
Package kratosgotenancy adapts GoTenancy tenant middleware to Kratos.
Package kratosgotenancy adapts GoTenancy tenant middleware to Kratos.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL