Files
as4-411/docs/architecture/tenant-model.md
defiQUG c24ae925cf
Some checks failed
CI / lint (push) Has been cancelled
CI / build (push) Has been cancelled
Initial commit: AS4/411 directory and discovery service for Sankofa Marketplace
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-08 08:44:20 -08:00

2.3 KiB

Tenant Model and Row-Level Security

Global vs Tenant-Private

  • Global objects: Public or shared data that can be read across tenants (e.g. BIC, LEI, BIN range metadata). Stored with tenant_id null or a dedicated "global" tenant. Used for cross-tenant lookup when the rail has a public identifier scheme.
  • Tenant-private objects: Participant-specific data, merchant IDs, terminal IDs, contractual endpoints. Always scoped by tenant_id. Queries must supply tenant (from auth or request) so that only that tenant's rows are visible.

Enforcement

  • Postgres Row Level Security (RLS): Enable RLS on participants, identifiers, endpoints, capabilities, credentials, policies, and optionally routing_artifacts. Policies: tenant_id = current_setting('app.current_tenant_id') or equivalent. Global rows: allow when tenant_id IS NULL or when reading public identifiers.
  • Application layer: Resolver and Admin API must set tenant context (e.g. from JWT or request parameter) before querying. Never return rows from another tenant.
  • Per-tenant encryption: For Tier 2+ data (see data-classification), use per-tenant encryption keys so that key compromise affects only one tenant.

Caching

  • Cache key includes tenant: same request for different tenants must not share a cache entry.
  • Optional per-tenant TTL or invalidation rules (e.g. shorter TTL for high-churn tenants).
  • Negative cache: key includes tenant; invalidate on any change for that tenant.

RLS Policy Summary

Table Policy (conceptual)
participants WHERE tenant_id = current_tenant OR tenant_id IS NULL
identifiers JOIN participants; same tenant or global
endpoints JOIN participants; same tenant
capabilities JOIN participants; same tenant
credentials JOIN participants; same tenant
policies WHERE tenant_id = current_tenant
routing_artifacts WHERE tenant_id = current_tenant OR tenant_id IS NULL

Apply current_tenant from connection/session (e.g. set by API after auth).