> ## Documentation Index
> Fetch the complete documentation index at: https://getoverlay.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Tenancy And Role Model

> Single-customer deployment boundary, role model, and multi-tenant roadmap.

Overlay currently uses a **single-customer deployment** model.

That means the deployment boundary is the tenant boundary:

* 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.

Do not onboard multiple enterprise customers into the same Convex deployment with the current schema.

## 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:

| Concept                  | Example                                                   |
| ------------------------ | --------------------------------------------------------- |
| Tenant/deployment        | Springfield School District                               |
| Roles                    | student, teacher, parent, administrator, IT administrator |
| Optional future grouping | school, classroom, grade, department, project, cohort     |

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

| Mode                      | Status              | Tenant boundary                                                                   |
| ------------------------- | ------------------- | --------------------------------------------------------------------------------- |
| Self-hosted enterprise    | Supported target    | One customer per deployment.                                                      |
| Managed-cloud enterprise  | Supported target    | One customer per dedicated managed deployment.                                    |
| Shared multi-tenant cloud | Not supported today | Multiple customers in one backend, blocked until tenant isolation is implemented. |

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 `tenantId` column is required in Convex tables.
* User-owned rows are scoped by `userId` inside 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.

This is the required model for enterprise customers until shared multi-tenant deployment support exists.

## 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.

Webhooks:

* Current behavior: webhook subscriptions and deliveries are deployment-local and user-owned through `webhookSubscriptions.userId` and `webhookDeliveries.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** have `tenantId` today because the deployment is the tenant boundary. `npm run check:tenant-boundaries` verifies that every current `userId`-owned Convex table is listed here.

| Table                          | Current owner | Tenant decision     | Shared multi-tenant requirement                                                                               |
| ------------------------------ | ------------- | ------------------- | ------------------------------------------------------------------------------------------------------------- |
| `userUiSettings`               | `userId`      | Deployment boundary | Add `tenantId` to row and `by_tenantId_userId` indexes.                                                       |
| `subscriptions`                | `userId`      | Deployment boundary | Add `tenantId`; Stripe customer/subscription indexes must include tenant ownership.                           |
| `budgetTopUps`                 | `userId`      | Deployment boundary | Add `tenantId`; payment/session indexes must validate tenant ownership.                                       |
| `apiIdempotencyKeys`           | `userId`      | Deployment boundary | Add `tenantId`; idempotency keys must be tenant-scoped.                                                       |
| `apiKeys`                      | `userId`      | Deployment boundary | Add `tenantId`; validation, scopes, rotation, revocation, audit, and rate limits must enforce tenant context. |
| `tokenUsage`                   | `userId`      | Deployment boundary | Add `tenantId`; usage and billing rollups must be tenant-scoped.                                              |
| `budgetReservations`           | `userId`      | Deployment boundary | Add `tenantId`; reservation and reconciliation queries must be tenant-scoped.                                 |
| `daytonaWorkspaces`            | `userId`      | Deployment boundary | Add `tenantId`; sandbox lifecycle and metering indexes must include tenant context.                           |
| `daytonaUsageLedger`           | `userId`      | Deployment boundary | Add `tenantId`; ledger reads and reconciliation must be tenant-scoped.                                        |
| `toolInvocations`              | `userId`      | Deployment boundary | Add `tenantId`; audit/cost views must include tenant context.                                                 |
| `dailyUsage`                   | `userId`      | Deployment boundary | Add `tenantId`; usage counters must include tenant context.                                                   |
| `projects`                     | `userId`      | Deployment boundary | Add `tenantId`; project hierarchy indexes must include tenant context.                                        |
| `skills`                       | `userId`      | Deployment boundary | Add `tenantId`; project and enabled-skill indexes must include tenant context.                                |
| `automations`                  | `userId`      | Deployment boundary | Add `tenantId`; scheduling and runner queries must not cross tenants.                                         |
| `automationRuns`               | `userId`      | Deployment boundary | Add `tenantId`; run history and scheduler claims must be tenant-scoped.                                       |
| `mcpServers`                   | `userId`      | Deployment boundary | Add `tenantId`; connector credentials and enabled indexes must be tenant-scoped.                              |
| `conversations`                | `userId`      | Deployment boundary | Add `tenantId`; share tokens need explicit cross-tenant policy.                                               |
| `conversationMessages`         | `userId`      | Deployment boundary | Add `tenantId`; conversation/message indexes must include tenant context.                                     |
| `conversationMessageDeltas`    | `userId`      | Deployment boundary | Add `tenantId`; streaming/delta cleanup queries must include tenant context.                                  |
| `conversationContextSummaries` | `userId`      | Deployment boundary | Add `tenantId`; context summary indexes must include tenant context.                                          |
| `notes`                        | `userId`      | Deployment boundary | Add `tenantId`; note/project indexes must include tenant context.                                             |
| `memories`                     | `userId`      | Deployment boundary | Add `tenantId`; memory extraction and search must enforce tenant context.                                     |
| `knowledgeChunks`              | `userId`      | Deployment boundary | Add `tenantId`; search indexes must include `tenantId` as a filter field.                                     |
| `knowledgeChunkEmbeddings`     | `userId`      | Deployment boundary | Add `tenantId`; vector indexes must include `tenantId` as a filter field.                                     |
| `outputs`                      | `userId`      | Deployment boundary | Add `tenantId`; generated output and storage ownership must be tenant-scoped.                                 |
| `r2UploadIntents`              | `userId`      | Deployment boundary | Add `tenantId`; upload finalization must include tenant context.                                              |
| `files`                        | `userId`      | Deployment boundary | Add `tenantId`; file/folder/share indexes must define cross-tenant behavior.                                  |
| `webhookSubscriptions`         | `userId`      | Deployment boundary | Add `tenantId`; subscriptions, signing secrets, and event ownership must be tenant-scoped.                    |
| `webhookDeliveries`            | `userId`      | Deployment boundary | Add `tenantId`; delivery runner claims and retries must enforce tenant ownership.                             |

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:

* `processedWebhookEvents`
* `rateLimitWindows`
* `serviceAuthReplayNonces`
* `sessionTransferTokens`

## Shared Multi-Tenant Checklist

Do not enable shared multi-tenant deployments until this checklist is complete:

* Schema migration plan for adding `tenantId` to 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.

Until then, use one deployment per enterprise customer.
