Documentation
¶
Overview ¶
Package tenant provides graphdb's multi-tenancy primitives.
Two pieces work together. The context helpers WithTenant and FromContext (and MustFromContext) thread a tenant ID through a request's context.Context; the storage and API layers use that ID to scope every operation. TenantStore (from NewTenantStore) holds per-tenant metadata — name, status, quota, and usage.
A "default" tenant is pre-created for backward compatibility with tenant-blind callers. Internally the store keys by tenantid.TenantID; its public methods accept plain tenant-ID strings for HTTP-handler convenience.
Index ¶
- Constants
- Variables
- func FromContext(ctx context.Context) (string, bool)
- func IsDefaultTenant(tenantID string) bool
- func MustFromContext(ctx context.Context) string
- func ValidateTenantID(id string) error
- func WithTenant(ctx context.Context, tenantID string) context.Context
- type QuotaUsage
- type Tenant
- type TenantInfo
- type TenantQuota
- type TenantStatus
- type TenantStore
- func (s *TenantStore) Activate(tenantID string) error
- func (s *TenantStore) CheckEdgeQuota(tenantID string) error
- func (s *TenantStore) CheckNodeQuota(tenantID string) error
- func (s *TenantStore) Count() int
- func (s *TenantStore) Create(tenant *Tenant) error
- func (s *TenantStore) DecrementEdgeCount(tenantID string) error
- func (s *TenantStore) DecrementNodeCount(tenantID string) error
- func (s *TenantStore) Delete(tenantID string) error
- func (s *TenantStore) Exists(tenantID string) bool
- func (s *TenantStore) Get(tenantID string) (*Tenant, error)
- func (s *TenantStore) GetActive(tenantID string) (*Tenant, error)
- func (s *TenantStore) GetTenantInfo(tenantID string) (*TenantInfo, error)
- func (s *TenantStore) GetUsage(tenantID string) (*TenantUsage, error)
- func (s *TenantStore) IncrementEdgeCount(tenantID string) error
- func (s *TenantStore) IncrementNodeCount(tenantID string) error
- func (s *TenantStore) List() []*Tenant
- func (s *TenantStore) ListAll() []*Tenant
- func (s *TenantStore) Suspend(tenantID string) error
- func (s *TenantStore) Update(tenant *Tenant) error
- func (s *TenantStore) UpdateUsage(tenantID string, nodeCount, edgeCount, storageBytes int64) error
- type TenantUsage
Constants ¶
const ( MinTenantNameLength = 3 MaxTenantNameLength = 100 MinTenantIDLength = 3 MaxTenantIDLength = 64 )
const DefaultTenantID = "default"
Default tenant ID for backward compatibility
Variables ¶
var ( ErrTenantNotFound = errors.New("tenant not found") ErrTenantExists = errors.New("tenant already exists") ErrTenantSuspended = errors.New("tenant is suspended") ErrTenantDeleted = errors.New("tenant is deleted") ErrInvalidTenantID = errors.New("invalid tenant ID") ErrInvalidTenantName = errors.New("tenant name must be 3-100 characters") ErrQuotaExceeded = errors.New("tenant quota exceeded") )
Errors for tenant operations
Functions ¶
func FromContext ¶
FromContext extracts the tenant ID from the context. Returns the tenant ID and true if found, or empty string and false if not.
func IsDefaultTenant ¶
IsDefaultTenant returns true if the tenant ID is the default tenant
func MustFromContext ¶
MustFromContext extracts the tenant ID from the context. Returns DefaultTenantID if not found (safe for backward compatibility).
func ValidateTenantID ¶ added in v0.5.0
ValidateTenantID reports whether id is an acceptable tenant identifier: 3-64 characters, starting alphanumeric, containing only alphanumerics, hyphens, and underscores. It is the single source of truth for what a tenant ID may contain — both creation (validateTenant) and the admin X-Tenant-ID override path (security audit M-5) route through it, so a value that can never be created can never be supplied as an override either. Rejecting here also closes the log-injection vector: a value that passes has no CR/LF or control characters to smuggle into logs.
Types ¶
type QuotaUsage ¶
type QuotaUsage struct {
NodesUsed int64 `json:"nodes_used"`
NodesLimit int64 `json:"nodes_limit"` // -1 if unlimited
NodesPercent float64 `json:"nodes_percent"` // 0-100, -1 if unlimited
EdgesUsed int64 `json:"edges_used"`
EdgesLimit int64 `json:"edges_limit"` // -1 if unlimited
EdgesPercent float64 `json:"edges_percent"` // 0-100, -1 if unlimited
StorageUsed int64 `json:"storage_used"`
StorageLimit int64 `json:"storage_limit"` // -1 if unlimited
StoragePercent float64 `json:"storage_percent"` // 0-100, -1 if unlimited
}
QuotaUsage shows quota limits alongside current usage
func NewQuotaUsage ¶
func NewQuotaUsage(quota *TenantQuota, usage *TenantUsage) *QuotaUsage
NewQuotaUsage creates a QuotaUsage from quota and usage
type Tenant ¶
type Tenant struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
Status TenantStatus `json:"status"`
Quota *TenantQuota `json:"quota,omitempty"`
Metadata map[string]string `json:"metadata,omitempty"`
CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"`
}
Tenant represents a tenant in the multi-tenant system
type TenantInfo ¶
type TenantInfo struct {
ID string `json:"id"`
Name string `json:"name"`
Status TenantStatus `json:"status"`
NodeCount int64 `json:"node_count"`
EdgeCount int64 `json:"edge_count"`
QuotaUsage *QuotaUsage `json:"quota_usage,omitempty"`
}
TenantInfo is a summary view of tenant for API responses
type TenantQuota ¶
type TenantQuota struct {
MaxNodes int64 `json:"max_nodes"` // -1 for unlimited
MaxEdges int64 `json:"max_edges"` // -1 for unlimited
MaxStorageBytes int64 `json:"max_storage_bytes"` // -1 for unlimited
}
TenantQuota defines resource limits for a tenant
func DefaultQuota ¶
func DefaultQuota() *TenantQuota
DefaultQuota returns the default quota configuration
func (*TenantQuota) IsUnlimited ¶
func (q *TenantQuota) IsUnlimited() bool
IsUnlimited returns true if the quota has no limits
type TenantStatus ¶
type TenantStatus string
TenantStatus represents the lifecycle state of a tenant
const ( TenantStatusActive TenantStatus = "active" TenantStatusSuspended TenantStatus = "suspended" TenantStatusDeleted TenantStatus = "deleted" )
type TenantStore ¶
type TenantStore struct {
// contains filtered or unexported fields
}
TenantStore manages tenant storage and operations.
Internal maps are keyed by tenantid.TenantID since audit task A1 (2026-05-06). Public method signatures still take "tenantID string" to avoid mass migration of HTTP handlers; conversion happens at the boundary inside each method. A3 will migrate the public surface.
func NewTenantStore ¶
func NewTenantStore() *TenantStore
NewTenantStore creates a new tenant store with a default tenant
func (*TenantStore) Activate ¶
func (s *TenantStore) Activate(tenantID string) error
Activate activates a suspended tenant
func (*TenantStore) CheckEdgeQuota ¶
func (s *TenantStore) CheckEdgeQuota(tenantID string) error
CheckEdgeQuota checks if a tenant can create a new edge
func (*TenantStore) CheckNodeQuota ¶
func (s *TenantStore) CheckNodeQuota(tenantID string) error
CheckNodeQuota checks if a tenant can create a new node
func (*TenantStore) Count ¶
func (s *TenantStore) Count() int
Count returns the number of tenants (excluding deleted)
func (*TenantStore) Create ¶
func (s *TenantStore) Create(tenant *Tenant) error
Create creates a new tenant
func (*TenantStore) DecrementEdgeCount ¶
func (s *TenantStore) DecrementEdgeCount(tenantID string) error
DecrementEdgeCount atomically decrements the edge count for a tenant
func (*TenantStore) DecrementNodeCount ¶
func (s *TenantStore) DecrementNodeCount(tenantID string) error
DecrementNodeCount atomically decrements the node count for a tenant
func (*TenantStore) Delete ¶
func (s *TenantStore) Delete(tenantID string) error
Delete soft-deletes a tenant (marks as deleted)
func (*TenantStore) Exists ¶
func (s *TenantStore) Exists(tenantID string) bool
Exists returns true if the tenant exists
func (*TenantStore) Get ¶
func (s *TenantStore) Get(tenantID string) (*Tenant, error)
Get retrieves a tenant by ID
func (*TenantStore) GetActive ¶
func (s *TenantStore) GetActive(tenantID string) (*Tenant, error)
GetActive retrieves a tenant by ID and verifies it's active
func (*TenantStore) GetTenantInfo ¶
func (s *TenantStore) GetTenantInfo(tenantID string) (*TenantInfo, error)
GetTenantInfo returns a summary view of a tenant with usage
func (*TenantStore) GetUsage ¶
func (s *TenantStore) GetUsage(tenantID string) (*TenantUsage, error)
GetUsage returns the usage for a tenant
func (*TenantStore) IncrementEdgeCount ¶
func (s *TenantStore) IncrementEdgeCount(tenantID string) error
IncrementEdgeCount atomically increments the edge count for a tenant
func (*TenantStore) IncrementNodeCount ¶
func (s *TenantStore) IncrementNodeCount(tenantID string) error
IncrementNodeCount atomically increments the node count for a tenant
func (*TenantStore) List ¶
func (s *TenantStore) List() []*Tenant
List returns all tenants (excluding deleted)
func (*TenantStore) ListAll ¶
func (s *TenantStore) ListAll() []*Tenant
ListAll returns all tenants including deleted
func (*TenantStore) Suspend ¶
func (s *TenantStore) Suspend(tenantID string) error
Suspend suspends a tenant
func (*TenantStore) Update ¶
func (s *TenantStore) Update(tenant *Tenant) error
Update updates an existing tenant
func (*TenantStore) UpdateUsage ¶
func (s *TenantStore) UpdateUsage(tenantID string, nodeCount, edgeCount, storageBytes int64) error
UpdateUsage updates the usage for a tenant
type TenantUsage ¶
type TenantUsage struct {
TenantID string `json:"tenant_id"`
NodeCount int64 `json:"node_count"`
EdgeCount int64 `json:"edge_count"`
StorageBytes int64 `json:"storage_bytes"`
LastUpdated int64 `json:"last_updated"`
}
TenantUsage tracks current resource usage for a tenant
func NewTenantUsage ¶
func NewTenantUsage(tenantID string) *TenantUsage
NewTenantUsage creates a new usage tracker for a tenant
func (*TenantUsage) CheckEdgeQuota ¶
func (u *TenantUsage) CheckEdgeQuota(quota *TenantQuota) error
CheckEdgeQuota returns an error if creating an edge would exceed the quota
func (*TenantUsage) CheckNodeQuota ¶
func (u *TenantUsage) CheckNodeQuota(quota *TenantQuota) error
CheckNodeQuota returns an error if creating a node would exceed the quota