What this is about
A cold start means an installation comes up in a way that lets it answer the first real request afterwards. Between “process started” and “ready” there are several steps, and they happen in a fixed order.
This page describes the sequence across both modules. What the individual switches mean is under Configuration decides what runs.
The timeline
flowchart LR
A["1 Schema<br/>create and raise tables"] --> B["2 Context<br/>build beans, check settings"]
B --> C["3 Bootstrap<br/>platform roles, first tenant,<br/>first administrator"]
C --> D["4 Reconciliation<br/>realm roles, declarations, groups"]
D --> E["5 Timers<br/>start if switched on"]
E --> F(["ready for the first request"])
classDef stufe fill:#8e24aa,stroke:#8e24aa,color:#fff
classDef ziel fill:#4d7c0f,stroke:#4d7c0f,color:#fff
class A,B,C,D,E stufe
class F ziel
The line between 3 and 4 is not a detail: bootstrap and reconciliation hang on different events of the application start. The bootstrap runs as a startup runner right after the application has come up; the reconciliation only once the application reports itself as ready. The bootstrap is therefore always finished first, and it has to be: it writes the roles into the catalog that the reconciliation then leaves alone.
The five stages one by one
-
1CIAS→Database1 Schema. The tables are created or raised before Hibernate ever looks at themWith the starter, one migration run per CIAS module; without it, through the host's persistence. Details under Databases and schemas.
-
2CIAS2 Context. Spring builds the beans. Every setting CIAS would otherwise have to guess is checked nowWho answers the tenant gate, the operating mode of the data layer, the list of modules with their names and sources, the reader role for
GET /cias/fetch. A missing setting fails here, with its name in the message. -
3CIAS→Database3 Bootstrap. An empty installation gets its platform roles, its first tenant and its first administratorOnly when
codamai.cias.bootstrap.enabledistrue. Everything in it can be repeated: what is already there stays as it is. -
4CIAS→Keycloak4 Reconciliation. First the installation's realm roles, then every module's declaration, then the groupsOnly when
codamai.cias.authorization.startup.enabledistrue. This pass never throws: if Keycloak is away or a module cannot be reached, it is reported and the application starts anyway. -
5CIAS5 Timers. The background passes begin, where they are switched onResult: The application accepts requests. The first customer goes through the tenant gate.
Stage 2: what fails the start
Building the context is where most mistakes surface — deliberately, because here a mistake is still a line in a file and not a service without permissions.
| Setting | If it is missing or wrong |
|---|---|
codamai.cias.tenancy.lookup | The start fails. Without it nobody would answer the tenant gate |
codamai.persistence.tenant.mode | The start fails wherever there is CDMS persistence |
codamai.cdms.cias.reader-roles in CDMS | The start fails. An explicitly empty value is allowed and means nobody |
| a module in the declaration list without a name, or with a duplicate name | The start fails. The name is what a role belongs to |
a module with bean and url, or with neither | The start fails. Exactly one of them says where the declaration is |
a bean this application does not have | The start fails, with the bean name in the message |
a module with url but without a reader-token | The start fails. The endpoint wants a reader role |
| a migration location that carries no scripts | The start fails. A typo in the location would otherwise migrate nothing, quietly |
| Keycloak happens to be unreachable | Not a start failure. That surfaces in stage 4 and is reported there |
Stage 3: what the bootstrap does
A fresh installation has an empty role catalog. Nothing can fill that catalog from the outside: defining a role takes a platform administrator, and who administers the platform is what the catalog says. That circle is broken in exactly one place, on the first start.
-
1CIASgives itself a caller context carrying this installation's platform roles for the duration of the run, and clears it afterwardsThe same seam a validated token would take. It is confined to one method, it runs once, and it writes down what it did.
-
2CIASadds every configured role that is not in the catalog yetAt realm level and owned by no module. That is why no reconciliation ever retires them: the reconciliation compares per module, and a role nobody owns is left alone by every module's silence. Typically only the two roles that cross all modules stand here.
-
3CIAScreates the first tenant, if one is configured and does not exist yetThrough the same path as every later creation, provisioning included. See A new tenant, end to end.
-
4CIAS→Keycloaklooks for the account behind the configured administrator address
-
5CIASThere is no such account → the start failsCIAS holds no credentials and therefore cannot create an account. An address with nobody behind it is a statement that does not add up — it is not skipped.
-
6CIAS→Keycloakgrants the platform roles to that accountResult: The installation has a catalog, possibly a tenant, and a person who can sign in and carry on.
Stage 4: what the reconciliation does
-
1CIAS→Keycloakcreates the realm roles the installation names in its configurationThese never come from a declaration. Realm level is what crosses all modules, and a module cannot see the consequences of such a role.
-
2CIAS→CDMSreads every configured module's declaration, as a bean or over
GET /cias/fetch -
3CIAS→Keycloakwrites the user profile, the client roles and the claim mappers, and then the catalogDetails under Reconciliation with Keycloak.
-
4CIAS→Keycloakreconciles the groups: create missing copies, bring roles and members up to dateResult: See Reconciliation with Keycloak.
Both passes hang on one switch (codamai.cias.authorization.startup.enabled) plus the module’s own. Neither fails the start. The reasoning is the same in both places: a role that has not been created yet surfaces later and can be caught up; a platform that will not come up because Keycloak is restarting is the greater damage. Creating a role also grants it to nobody — which is what makes running this unattended acceptable.
The variants
When: codamai.cias.bootstrap.enabled: true, usually exactly once on a fresh installation.
Stage 3 runs and fills the catalog, possibly the first tenant and the first administrator's role. On an installation that is already running, the pass finds everything in place and changes nothing.
Result: After the start there is a catalog and somebody allowed to administer it.
When: The switch is missing or false. That is the normal case in operation.
Stage 3 is skipped entirely. Nothing is written, and none of the connections the bootstrap would need is even built — a start without a bootstrap does not ask Keycloak anything at this point.
Result: The start goes straight from stage 2 to stage 4.
When: An administrator address is configured, but there is no account for it.
-
1CIAS→Keycloaklooks for the account behind the address
-
2CIASfinds none and fails the startThe same happens when the installation names no platform role at all: then there is nothing to grant, and one of the two statements is not meant.
Result: Create the account in Keycloak first, then start again. The order is not negotiable — CIAS holds no credentials.
When: CDMS and CIAS run in the same process.
One cold start for both. CDMS's declaration is a bean in the same process, so the reconciliation needs no network and no token. The CIAS tables live in the host's system database. The bootstrap exists only where the host brings the starter.
Result: Once the process is up, everything is up.
When: CIAS is a service of its own.
Two cold starts that know nothing about each other. Each service migrates its own schema and builds its own context. Only in stage 4 do they touch: CIAS calls GET /cias/fetch on the CDMS service. If that one is not up yet, its module counts as unreadable — nothing about its roles changes then, not even a retirement.
Result: The order of the two services is free. Whatever could not be read on the first attempt is caught up by the next reconciliation.
What runs in the background afterwards
Two timers belong to operation, and both are off by default. Starting a background thread is a decision the application makes, not the jar.
| Timer | Switch | What it does |
|---|---|---|
| Role synchronization | codamai.cias.authorization.synchronization.enabled | lets expired time-limited roles actually expire, default interval 5 minutes |
| Tenant reconciliation | codamai.cias.tenancy.reconciliation.enabled | finds abandoned provisionings and marks them FAILED, default interval 15 minutes |
The standalone CIAS service switches both on. An application that embeds CIAS without the starter has neither — there is no timer there, and both have to be triggered.
Watch out
Next
- Modules register roles and attributes: what is read in stage 4
- A new tenant, end to end: what happens to the first tenant in stage 3
- Databases and schemas: what happens in stage 1
- Configuration decides what runs and CIAS embedded
- Reconciliation with Keycloak and Group reconciliation
- The platform’s realm roles