CodamAIDocs
Topicdone

Databases and schemas

Which databases exist (system, one per tenant, CIAS), who migrates which schema, and in which order.

Variants
System DBTenant DBCIAS embedded (own migration history)CIAS standalone (own DB)

What this is about

An installation has more than one database, and not every one of them belongs to the same module. Who creates and raises which tables depends on how the modules are assembled.

The map

Which databases exist

When: CDMS and CIAS run in the same process.

flowchart TB
    P["One process<br/>CDMS + CIAS"]
    P --> S[("System database<br/>CDMS system models<br/>+ all CIAS tables")]
    P --> T1[("Tenant DB nordbau")]
    P --> T2[("Tenant DB acme")]

Result: One system database for both modules. cias_tenant lists every tenant and therefore cannot exist once per tenant.

When: CIAS is a service of its own.

flowchart TB
    D1["CDMS service"]
    D2["CIAS service"]
    D1 --> S[("System database<br/>CDMS system models")]
    D1 --> T1[("Tenant DB nordbau")]
    D1 --> T2[("Tenant DB acme")]
    D2 --> C[("CIAS database<br/>all CIAS tables")]

Result: Two separate worlds. An installation may point both at the same database — these are exactly the tables that sit side by side when embedded. It is not required.

Which data ends up in which database is decided, on the CDMS side, by the model’s level; see Which database? The persistence target.

Who holds which tables

DatabaseHow manyWho writes into itExamples
System databaseoneCDMS with its system models; when embedded, CIAS as wellmaster data that applies to every customer
Tenant databaseone per tenant, only in MULTICDMS onlytenant and user models, plus the revisions
CIAS databaseone, standalone onlyCIAS onlytenants, users, role catalog, groups, registrations, mail templates, audit

In SINGLE there is only one database. System and tenant models then sit next to each other in it, and there is one level less to keep in mind.

Who migrates, and when

Migrating means bringing a database’s tables up to the state the application expects. The two modules do this in different ways, and that is no accident: CDMS has one database per customer and only sees it on first access; CIAS has exactly one and knows it at startup.

CDMSCIAS with the starterCIAS without the starter
Whenon the first access to a target after the start, and when a new tenant is provisionedwhile the process comes up, before Hibernate looks at the tablesas the host does it, so with its system database
Howby default Hibernate adds what is missing. Optionally versioned scriptsone migration run per module, each with its own history tablenot on its own at all: the host registers the CIAS entities with its persistence
Where the scripts livetwo locations, one for the system database and one for the tenant databasesone location per module, stated explicitly, never scanned fornone — there is no CIAS migration run in this process
What Hibernate does afterwardschecks where scripts own the schema; adds things itself otherwiseonly checks that tables and entities matchas with the host
Targetthe system database and every tenant database, one by onethe one database CIAS hasthe host's system database

Why CIAS keeps one history per module

Every CIAS module is its own repository and is released on its own. So every one of them starts its numbering at V1__. Six modules with six scripts called “version 1” do not fit into one shared history table — Flyway would find six migrations all claiming to be version one.

The migration run with the starter
  1. 1
    CIAS
    reads the list of locations, one per module, from the configuration
    No scanning of the classpath. A location the installation names that carries no scripts fails the start — a typo would otherwise migrate nothing, quietly.
  2. 2
    CIAS
    derives each location's history table name from it, for example flyway_schema_history_cias_tenancy
    Two locations that would derive the same name fail the start. They would otherwise share one history, and the second module would read its own V1__ as already applied.
  3. 3
    CIAS→Database
    runs one pass per location, with baseline version 0
    If a module's history table is missing, it has never run here — whatever else is in the schema. The usual baseline of version one would be wrong here: after the first module the schema is never empty again, and the second would skip its V1__.
  4. 4
    CIAS
    only then does Hibernate build its objects
    Result: Every module has its own history and can move on by itself.

The tables all sit in the same database, next to each other and next to CDMS’s own history table where an installation shares one database. That is why the name prefix can be configured.

The whole run depends on three conditions: Flyway has to be on the classpath, there has to be a database, and codamai.cias.migration.enabled has to be true. If one of them is missing, nothing happens.

And when the host distributes its databases itself?

A host with CDMS persistence, such as the hub backend, does not have one database but one per unit (system, tenants). It builds the schema of a unit when that unit is first needed. The second condition above does not hold there, so the run does not start by itself.

Instead CIAS hooks into this step of the host:

  1. In the unit that holds the CIAS tables, the CIAS scripts run first, module by module, each with its own history as above.
  2. Then the host’s migration runs.
  3. Only then does Hibernate build its objects.

So that Hibernate knows the CIAS tables, the host additionally registers the CIAS entities with its persistence — a contribution with scope SYSTEM. The CIAS run can be switched off with CIAS_MIGRATION=false.

The scope only says which unit holds the tables:

ScopeWhere the tables belong
SYSTEMinto the system unit; in an installation without tenant isolation that is the only one
TENANTinto every tenant unit, once per tenant

CIAS tables are always SYSTEM. A table that lists every tenant cannot exist once per tenant.

The order at startup

What happens before the first request
  1. 1
    CIAS→Database
    the CIAS tables, module by module
    Hibernate is explicitly made to wait for this. Without it, the check could run against tables that were about to be created.
  2. 2
    CDMS→System DB
    the system database, when its connection is first needed
  3. 3
    CDMS→Tenant DB
    every tenant database on its own, on the first access after the start
    Result: After an update with new columns, a tenant database is therefore only touched once that customer works.

A tenant database is only created where creating one is explicitly approved. If the database server is unreachable, CDMS does not try to create anything — a merely unreachable database would otherwise become the reason to put a second one beside it. Details under Databases, pools, migration.

What the names tell you

A look at the names helps when searching:

What you seeWhat it means
flyway_schema_historyCDMS’s history, where the installation uses versioned scripts
flyway_schema_history_cias_tenancythe history of the CIAS module cias-tenancy
cias_tenant, cias_user, cias_group, cias_audit_entry …CIAS tables, always system tables
a database named after a tenant keythat customer’s database

Watch out

Next

Sources in the code and the knowledge base
  • CIAS/cias-spring-boot-starter – CiasSchemaAutoConfiguration (conditions, EntityManagerFactoryDependsOnPostProcessor), CiasSchemaMigration (one history per location, baseline 0, failOnMissingLocations, resolveHistoryTables), CiasMigrationProperties (locations, history-table-prefix), CiasMigrationResourceProvider
  • CIAS – db/migration/cias-tenancy, -user, -authorization, -registration, -notification, -audit (each starting at V1__)
  • commons-persistence – SchemaMigrationConfiguration, FlywaySchemaMigrator (system and tenant location), NoOpSchemaMigrator, SchemaMigrationMode, PersistenceProperties (migration-mode, migration-system-location, migration-tenant-location, auto-create-tenant-database, url with {tenant})
  • commons-persistence – TenantEntityManagerFactory (buildFactory: migrate before Hibernate, PINNED_TARGETS system/single), DataSourceManager (decideTenantDatabaseAction, createDatabase), ManagedTypesContribution (Scope SYSTEM, TENANT), ManagedTypesProvider
  • hub-backend – CiasEmbeddedConfiguration, CiasIdentityConfiguration, CiasRegistrationSupportConfiguration (ManagedTypesContribution), CiasSchemaMigrator and CiasSchemaMigrationConfiguration (CIAS migrations before the platform's, unit system or single, CIAS_MIGRATION)
  • CIAS/cias-runtime – application.yml (CIAS_DATABASE_URL, spring.flyway.enabled false, ddl-auto validate, codamai.cias.migration.enabled)
Search