tenant

package
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Jun 17, 2026 License: MIT Imports: 7 Imported by: 0

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

View Source
const (
	MinTenantNameLength = 3
	MaxTenantNameLength = 100
	MinTenantIDLength   = 3
	MaxTenantIDLength   = 64
)
View Source
const DefaultTenantID = "default"

Default tenant ID for backward compatibility

Variables

View Source
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

func FromContext(ctx context.Context) (string, bool)

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

func IsDefaultTenant(tenantID string) bool

IsDefaultTenant returns true if the tenant ID is the default tenant

func MustFromContext

func MustFromContext(ctx context.Context) string

MustFromContext extracts the tenant ID from the context. Returns DefaultTenantID if not found (safe for backward compatibility).

func ValidateTenantID added in v0.5.0

func ValidateTenantID(id string) error

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.

func WithTenant

func WithTenant(ctx context.Context, tenantID string) context.Context

WithTenant returns a new context with the tenant ID set

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

func (*Tenant) IsActive

func (t *Tenant) IsActive() bool

IsActive returns true if the tenant is in active status

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

Jump to

Keyboard shortcuts

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