ADR-001: Tenant Separation and Multi-Tenancy Model
1. Status
- Status: accepted
- Last updated: 2026-01-06
- Notes: Establishes tenant-first model and isolation guarantees for the MVP.
2. Context
DataDescriber is a multi-tenant SaaS platform. Multiple tenant organizations will use the system concurrently, each with its own users, configurations, and metadata about systems, data products, datasets, terms, classifications, and so on.
We need a clear model for tenant separation so that:
- Data belonging to one tenant is never visible or writable from another tenant.
- Infrastructure resources (NATS subjects/streams, databases, keyspaces, etc.) can be provisioned and operated in a tenant-aware way.
- Higher-level domain concepts (e.g.,
MetadataRepository,RepositoryChangeSet) are always scoped to a tenant. - Future cross-tenant features (e.g., global catalogs or multi-tenant ops dashboards) can be built explicitly, not by relying on accidental data mixing.
3. Decision
We adopt a tenant-first model where a TenantId is a fundamental part of the domain and infrastructure identity for all tenant-owned data.
1. Tenant identity
- Each organization using DataDescriber has a stable
TenantId. - All tenant-owned aggregates and resources are scoped by
TenantId. - Internal system components may have their own identities, but user-visible state is always associated with exactly one tenant.
2. Tenant-scoped domain aggregates
MetadataRepositoryis identified by(tenantId, repositoryId)(or aRepositoryIdthat canonically includestenantId).RepositoryChangeSetis identified by(tenantId, repositoryId, changeSetId)(or by(repositoryId, changeSetId)whererepositoryIdalready encodes thetenantId).- Future aggregates such as
Request,Publication, orApprovalFlowwill also be explicitly tenant-scoped:- Each instance belongs to exactly one tenant.
- Any references to metadata nodes/relationships must point to entities inside that same tenant’s repositories.
3. No implicit cross-tenant links
- The domain model forbids references from one tenant’s aggregates to another tenant’s aggregates.
- Any future cross-tenant feature (e.g., a global search index or cross-tenant dashboard) must:
- Be modeled explicitly as a separate read model or service.
- Respect tenant isolation at the query and authorization layer.
4. Tenant separation in infrastructure
- Event streams, topics, and queues (e.g., NATS subjects/JetStream streams) are partitioned by tenant:
- Subjects/streams include
tenantIdin their naming convention, or - The storage layer provides separate namespaces/keyspaces per tenant.
- Subjects/streams include
- Databases and other stores (SQLite, LadybugDB, future PostgreSQL/Neo4j, etc.) are provisioned in a tenant-aware manner:
- At minimum, tables/collections include a
tenantIdcolumn/field used in all queries and indexes. - For higher isolation or compliance needs, we may use separate schemas/databases per tenant.
- At minimum, tables/collections include a
- Projection workers and background processes must always filter by
tenantIdwhen consuming and emitting data.
5. Tenant-aware configuration
- Configuration for runtime behavior (e.g., enabled schema modules, feature flags, storage backends) is evaluated per tenant.
- A tenant’s
MetadataRepositoryschema is derived from:- Global base schema modules.
- Tenant-specific enabled modules (e.g., when a tenant unlocks "Term Bank" or "Information Security").
6. Relationship to other ADRs
- ADR-003 (Core domain model – MetadataRepository and RepositoryChangeSet) assumes that
MetadataRepositoryandRepositoryChangeSetidentities include tenant scoping. - ADR-004 (Messaging and view storage) must treat
tenantIdas a primary partitioning key for NATS streams and view stores. - ADR-005 (Module structure and views) and ADR-006 (Frontend architecture) operate within the boundaries set by this tenant model.
- ADR-007 (Testing strategy) should include tests that assert tenant isolation (e.g., that commands for tenant A do not affect views for tenant B).
4. Rationale
We choose an explicit tenant-first model because:
- It makes isolation guarantees enforceable at every layer (domain, storage, messaging, and views).
- It avoids retrofitting multi-tenancy later, which is error-prone and risky for data privacy.
- It keeps future cross-tenant features explicit, so they can be modeled and reviewed carefully rather than emerging accidentally.
5. Alternatives Considered
Single-tenant design with later retrofitted multi-tenancy
- Pros:
- Simpler initial implementation.
- Cons:
- Retrofitting tenant separation later is error-prone and risky.
- Higher chance of subtle data leaks between tenants.
- Pros:
Soft multi-tenancy via only UI-level filtering
- Pros:
- Minimal changes at the storage/event layer.
- Cons:
- Unsafe: bugs in filtering can expose data across tenants.
- Harder to reason about isolation and compliance.
- Pros:
6. Consequences
- All core domain aggregates and events become explicitly tenant-aware.
- Infrastructure naming and provisioning must incorporate
tenantId. - Testing and QA need to routinely validate that operations for one tenant do not affect or reveal data from another tenant.
- This ADR provides the foundation for future work on per-tenant configuration, billing, and operational dashboards.