Multi-Tenancy
Causet uses a three-level hierarchy — platform, application, fork — to isolate tenants. Each fork gets a dedicated PostgreSQL schema in the projections database, and can run an independent active IR version.
The Tenancy Hierarchy
Platform
└── Application
└── Fork (e.g. production, staging, demo)| Level | Description |
|---|---|
| Platform | Top-level owner — a company or team. Has API keys for server-to-server access. |
| Application | A deployed Causet application (a set of .causet DSL files). |
| Fork | An isolated instance of an application — typically production, staging, or named demo forks. Each fork has its own event data, active IR version, and projection schema. |
Per-Fork PostgreSQL Schema
Each fork is assigned a PostgreSQL schema in the projections database:
schema name = {platformId}_{applicationId}_{forkId}For example:
| Platform ID | App ID | Fork ID | Schema Name |
|---|---|---|---|
acme | concertapp | production | acme_concertapp_production |
acme | concertapp | staging | acme_concertapp_staging |
acme | concertapp | demo-2024-06 | acme_concertapp_demo_2024_06 |
Schema name sanitization
The schema name is sanitized before use:
- Non-alphanumeric characters are replaced with
_ - The result is truncated to ≤ 63 characters (PostgreSQL identifier limit)
- Names are lowercased
If a sanitized name collides with another fork’s schema, a suffix is appended to disambiguate.
Schema Isolation in Practice
Both projection-worker and query-service issue SET LOCAL search_path before any SQL operation:
SET LOCAL search_path = acme_concertapp_production;This scopes all table references to the fork’s schema. Two forks of the same application never read or write each other’s projection tables, even though they share the same PostgreSQL database instance.
The causet event store uses fork_id as a column filter — events for different forks are stored in the same tables but filtered by fork_id on all queries.
DDL at Deploy Time
Projection table DDL is generated from the IR at deploy time. When a new IR version is activated for a fork:
causet-saas-cloudapplies DDL changes to the fork’s schema (creates new tables, adds new columns).- The new IR version becomes active for the fork.
- The projection worker and query service pick up the new IR version on their next cache refresh.
Table creation is CREATE TABLE IF NOT EXISTS — safe to run repeatedly.
Warning: DDL is not applied destructively. Columns are not dropped automatically when removed from the DSL. Removing a projection field requires a manual migration step.
Independent IR Versions Per Fork
Different forks can run different active IR versions simultaneously:
acme_concertapp_production → IR version v41 (stable)
acme_concertapp_staging → IR version v42 (new release under test)
acme_concertapp_demo-june → IR version v39 (frozen demo)This allows safe canary deployments: activate a new IR version on staging, validate, then promote to production.
The active IR version per fork is resolved via GetActiveRelease(forkId) from causet-saas-cloud. The result is used by all downstream services (runtime, projection worker, query service) to load the correct IR artifact.
Authentication and Authorization
| Context | Mechanism |
|---|---|
| Control plane (UI) | Clerk JWT — carries platform/application context |
| SaaS API (server-to-server) | API key per platform |
| Direct runtime access | API key or service-to-service credential |
| Demo / anonymous sessions | Anonymous session token — scoped to a specific demo fork |
Clerk JWTs carry the platformId and applicationId claims. The fork is resolved from the request context or URL parameter.
Anonymous sessions are scoped to a specific fork and have no write access by default. They are used for interactive demos where a visitor can query a pre-populated fork without authentication.
Fork Isolation Guarantees
| Property | Guarantee |
|---|---|
| Projection data | Fully isolated — different PostgreSQL schema per fork |
| Ledger events | Logically isolated — same tables, filtered by fork_id |
| IR version | Independent per fork |
| Kafka events | Not isolated by fork — all forks share the same topics (roadmap item) |
| Redis cache | Keyed by irVersion — different versions cached independently |
Fork Lifecycle
- Create fork — creates a schema in the projections DB and registers the fork in
causet_control_plane. - Deploy IR — activates an IR version for the fork; applies DDL.
- Write — intents are submitted with
forkId; ledger events and snapshots are scoped toforkId. - Query — queries are executed in the fork’s schema.
- Promote — activate a new IR version on the fork.
- Archive/delete fork — drop schema, remove fork registration (manual operation).
Related Pages
- Storage — schema isolation and DDL management
- Scaling Model — shared infrastructure limits
- Configuration — fork-level environment variables