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
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
| Database | How many | Who writes into it | Examples |
|---|---|---|---|
| System database | one | CDMS with its system models; when embedded, CIAS as well | master data that applies to every customer |
| Tenant database | one per tenant, only in MULTI | CDMS only | tenant and user models, plus the revisions |
| CIAS database | one, standalone only | CIAS only | tenants, 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.
| CDMS | CIAS with the starter | CIAS without the starter | |
|---|---|---|---|
| When | on the first access to a target after the start, and when a new tenant is provisioned | while the process comes up, before Hibernate looks at the tables | as the host does it, so with its system database |
| How | by default Hibernate adds what is missing. Optionally versioned scripts | one migration run per module, each with its own history table | not on its own at all: the host registers the CIAS entities with its persistence |
| Where the scripts live | two locations, one for the system database and one for the tenant databases | one location per module, stated explicitly, never scanned for | none — there is no CIAS migration run in this process |
| What Hibernate does afterwards | checks where scripts own the schema; adds things itself otherwise | only checks that tables and entities match | as with the host |
| Target | the system database and every tenant database, one by one | the one database CIAS has | the 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.
-
1CIASreads the list of locations, one per module, from the configurationNo scanning of the classpath. A location the installation names that carries no scripts fails the start — a typo would otherwise migrate nothing, quietly.
-
2CIASderives each location's history table name from it, for example
flyway_schema_history_cias_tenancyTwo locations that would derive the same name fail the start. They would otherwise share one history, and the second module would read its ownV1__as already applied. -
3CIAS→Databaseruns one pass per location, with baseline version 0If 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__. -
4CIASonly then does Hibernate build its objectsResult: 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:
- In the unit that holds the CIAS tables, the CIAS scripts run first, module by module, each with its own history as above.
- Then the host’s migration runs.
- 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:
| Scope | Where the tables belong |
|---|---|
SYSTEM | into the system unit; in an installation without tenant isolation that is the only one |
TENANT | into 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
-
1CIAS→Databasethe CIAS tables, module by moduleHibernate is explicitly made to wait for this. Without it, the check could run against tables that were about to be created.
-
2CDMS→System DBthe system database, when its connection is first needed
-
3CDMS→Tenant DBevery tenant database on its own, on the first access after the startResult: 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 see | What it means |
|---|---|
flyway_schema_history | CDMS’s history, where the installation uses versioned scripts |
flyway_schema_history_cias_tenancy | the 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 key | that customer’s database |