GitHub
Memory System

Multi-Tenant Manager

Ensures data isolation, security, and quota management for SaaS deployments.

Storage: All DBs (Namespaced)

Purpose

The Multi-Tenant Manager guarantees that data from Tenant A serves only Tenant A. It enforces strict isolation across all memory storage layers (Vector, Graph, SQL).

Key Features

  • Label Security: Injects Tenant Labels into every Neo4j query to partition the graph.
  • RBAC: Graph-based role checks (:User-[:HAS_ROLE]->:Tenant).
  • Quotas: Enforces storage limits per tenant to prevent noisy neighbor issues.

Functional Deep Dive

Label Security

In Neo4j, every node created is tagged with a Tenant Label (e.g., :Tenant_A). All retrieval queries automatically inject this label constraint, ensuring users never see data from other tenants.

Vector Filtering

In Qdrant, payload filters strictly enforce tenant_id match for every search operation.

Isolation Diagram

API Reference

Multi-Tenant Manager provides endpoints for tenant isolation and quotas.

MethodEndpointDescription
POST/api/memory/v1/tenantsCreate tenant
GET/api/memory/v1/tenantsList all tenants
GET/api/memory/v1/tenants/tenant_idGet tenant details
PUT/api/memory/v1/tenants/tenant_idUpdate tenant
DELETE/api/memory/v1/tenants/tenant_idDelete tenant
GET/api/memory/v1/tenants/tenant_id/usageGet tenant usage
POST/api/memory/v1/tenants/tenant_id/quotaUpdate quotas
POST/api/memory/v1/tenants/tenant_id/batch-ingestBatch ingest

SDK Reference

The Functor SDK provides a Python interface for multi-tenant operations.

Managing Tenants

from functor_sdk import FunctorClient
client = FunctorClient(api_key="your-api-key")
# Create tenant
tenant = client.memory.tenants.create(
tenant_id="tenant_abc",
tenant_name="Acme Corp",
description="Production tenant",
quotas={
"max_storage_gb": 100,
"max_users": 1000
}
)
# List tenants
tenants = client.memory.tenants.list()
# Get tenant details
tenant = client.memory.tenants.get(tenant_id="tenant_abc")
# Get tenant usage
usage = client.memory.tenants.get_usage(tenant_id="tenant_abc")
# Update quotas
client.memory.tenants.update_quota(
tenant_id="tenant_abc",
quotas={"max_storage_gb": 200}
)
# Batch ingest for tenant
result = client.memory.tenants.batch_ingest(
tenant_id="tenant_abc",
sources=[...],
target_kg="company_knowledge",
max_concurrent=5
)