- A self-hosted enterprise gets one web runtime, one Convex deployment, one object-store namespace, and one secret set.
- A managed-cloud enterprise also gets one dedicated deployment and backend set.
- Multiple stakeholders inside that enterprise are users with roles, not separate tenants.
Tenants Versus Roles
A tenant is a hard data-isolation boundary. In today’s architecture, that boundary is the deployment itself. Roles are authorization rules inside one tenant. A school should normally be modeled like this:
Do not add
tenantId just to represent students, teachers, parents, departments, or classes. Future RBAC should use roles, groups, memberships, and policy checks within the same deployment.
Deployment Modes
The current config schema rejects
capabilities.multiTenant=true. Admin/system surfaces should report single-customer deployment; no tenant switcher or tenant-admin UI should appear.
Current Security Model
Single-customer deployment:- No
tenantIdcolumn is required in Convex tables. - User-owned rows are scoped by
userIdinside that deployment. - API keys belong to a user in the deployment.
- Webhook subscriptions and deliveries belong to a user in the deployment.
- Storage keys and generated URLs are scoped to the deployment’s object-store namespace and user checks.
- Operational isolation comes from separate Convex deployments, object-store buckets or prefixes, secrets, domains, logs, and provider credentials.
API Keys And Webhooks
API keys:- Current behavior: API keys are deployment-local and user-owned through
apiKeys.userId. - No tenant claim is encoded or enforced because the deployment is the tenant boundary.
- A dedicated managed-cloud enterprise must have its own
API_KEY_HASH_SECRET. - Shared multi-tenant requirement: API keys must include tenant ownership, tenant-aware scopes, tenant-aware rate-limit keys, tenant-aware audit entries, and validation that the key tenant matches the request tenant.
- Current behavior: webhook subscriptions and deliveries are deployment-local and user-owned through
webhookSubscriptions.userIdandwebhookDeliveries.userId. - No tenant routing field exists because the deployment is the tenant boundary.
- Shared multi-tenant requirement: webhook subscriptions, deliveries, event ownership, signing secrets, retries, and delivery runner queries must include tenant context.
Convex Table Tenant Decisions
These user-owned tables intentionally do not havetenantId today because the deployment is the tenant boundary. npm run check:tenant-boundaries verifies that every current userId-owned Convex table is listed here.
The following tables are not user-owned tenant data today. They still need review before shared multi-tenant deployments, but the static check only requires explicit documentation for
userId-owned tables:
processedWebhookEventsrateLimitWindowsserviceAuthReplayNoncessessionTransferTokens
Shared Multi-Tenant Checklist
Do not enable shared multi-tenant deployments until this checklist is complete:- Schema migration plan for adding
tenantIdto every user-owned table. - Backfill plan for existing rows.
- Index expansion plan for every secondary, search, and vector index.
- Tenant-aware auth/session claims.
- Tenant-aware role and membership model.
- Tenant-aware API keys, scopes, audit trail, and per-key/per-tenant rate limits.
- Tenant-aware webhook subscription, delivery, retry, and signing-secret ownership.
- Tenant-aware object-storage key namespace and public/share URL policy.
- Cross-tenant negative tests for every domain service before enabling shared deployments.
- UI policy for tenant switchers, unavailable states, and tenant admin surfaces.