CodamAIDocs
Topicdone

SINGLE and MULTI

The two operating modes of data storage: one database for everyone or one per tenant. What changes as a result.

Variants
SINGLEMULTIoperating mode missing → start failsold and new key contradict each other → start failschanging the operating mode later

What this is about

A tenant is a customer whose data must stay separate from the data of other customers. How strictly CDMS separates them is set by the operating mode. There are exactly two:

  • SINGLE: one database for everything. There are no tenants.
  • MULTI: one system database for data of the whole installation, plus a separate database per tenant.

The operating mode applies to the whole installation, so to the database and the file storage at the same time. It is set in the environment variable CODAMAI_PERSISTENCE_TENANT_MODE.

Two pictures

flowchart TB
    subgraph S["SINGLE"]
        direction TB
        SA(["Request"]) --> SDB[("Database single<br/>system, tenant and user models")]
    end
    subgraph M["MULTI"]
        direction TB
        MA(["Request from tenant acme"]) --> SYS[("Database system<br/>system models")]
        MA --> T1[("Database acme<br/>tenant and user models")]
        T2[("Database globex<br/>tenant and user models")]
    end

In MULTI the request from acme reaches only two databases: the system database that everyone shares, and its own. The database of globex is not on its path. Which models go where is explained in Model levels.

What differs

SINGLE and MULTI compared
SINGLE
one database
  • one database for all models
  • the tenant in the token is ignored
  • no tenant switch, no check whether a tenant is served
  • files without a tenant directory
  • the owner filter of user models still applies
  • for installations with exactly one customer, for development and testing
MULTI
one database per tenant
  • system database plus one database per tenant
  • every request of a person needs a tenant, otherwise 403
  • CIAS checks on every request whether the tenant is served
  • tenant switch by header for authorized persons
  • files in one directory per tenant
  • for installations with several customers
Where a model goes in which operating mode
Level of the modelOperating modeDatabase
SystemSINGLEthe one database
Tenant or userSINGLEthe one database
SystemMULTIsystem database
Tenant or userMULTIdatabase of the request's tenant

The full decision, including the error cases, is in Which database? The persistence target.

What SINGLE does with the tenant in the token

A token can carry a tenant in SINGLE too, for example because the same Keycloak serves several applications. CDMS then does not evaluate it at all:

  • CIAS does not determine a tenant and does not ask whether it is served.
  • The list of allowed tenants stays empty. A tenant header therefore cannot switch anything.
  • All models end up in the one database.

Separation by person does not depend on the operating mode: the owner filter of user models works in SINGLE exactly as in MULTI.

Configuration

The operating mode at startup

When: CODAMAI_PERSISTENCE_TENANT_MODE=SINGLE or =MULTI

  1. 1
    CDMS
    reads the operating mode at startup
  2. 2
    CDMS
    sets up database access, file storage and the CIAS tenant check accordingly

Result: The application starts.

When: The variable is not set.

  1. 1
    CDMS
    finds no operating mode; there is deliberately no default
  2. 2
    CDMS
    stops the start with an error message that names the setting

Result: A default would silently switch off a separation someone expected, or invent one nobody asked for.

When: The old key CODAMAI_PERSISTENCE_DATABASE_MODE (formerly CDMS_DATABASE_MODE) is set as well.

  1. 1
    CDMS
    compares the old value with the new one
  2. 2
    CDMS
    equal → warning in the log, the old key should be removed
  3. 3
    CDMS
    different → the start stops, the message names both values

Result: Neither value wins silently. A contradiction is a configuration error.

Pitfalls

Where to go next

Sources in the code and the knowledge base
  • commons-persistence – TenantMode, TenantProperties (codamai.persistence.tenant.mode, @NotNull), TenantModeConsistencyCheck, LegacyPersistencePropertyMapper
  • commons-persistence – DataSourceManager.getConnection (key single), TenantEntityManagerFactory.cacheKey, DatabaseRequestContext.resolveTenant
  • CDMS/cdms-persistence-database – EntityClassFilterService (singleDatabasEntity, multiDatabasEntity)
  • CIAS/cias-kernel – TenantRequirement; CIAS/cias-authentication – TokenParser.admit (ADR-035), JwtSessionFilter.tenantMissing
  • commons-persistence – TenantProvisioningConfiguration (NoOp in SINGLE)
Search