CodamAIDocs
Topicdone

A new tenant, end to end

From creation in CIAS through the organization in Keycloak and the database to the first request in CDMS that passes the gate for this tenant.

Variants
through administrationthrough self-registrationembeddedstandalone

What this is about

A new customer means four things to the platform, and they come into being in four different places:

WhatWhere
the tenant’s recordin the CIAS database
possibly an organizationin Keycloak
a database with its schemawherever CDMS keeps its data
the people’s accounts with their rolesin Keycloak, plus user records in CIAS

There is no shared transaction across all four. So CIAS records every step on its own, which is what makes a half-finished customer recognizable and repairable.

The whole path in one picture

The normal case: a platform administrator creates the tenant, CDMS and CIAS run in the same process, and the data layer is set to MULTI.

sequenceDiagram
    autonumber
    participant A as Admin
    participant C as CIAS
    participant CDB as CIAS database
    participant P as CDMS persistence
    participant TDB as Tenant DB
    participant K as Keycloak
    participant U as Client of nordbau

    A->>C: POST /cias/admin/tenants {key: nordbau, type: STATIC}
    C->>C: check the caller's role
    C->>CDB: transaction 1 – key free? store as PENDING / IN_PROGRESS
    CDB-->>C: stored
    C->>P: provision nordbau
    P->>TDB: CREATE DATABASE nordbau
    P->>TDB: bring the schema up to the models
    TDB-->>P: done
    P-->>C: provisioned
    C->>CDB: transaction 2 – PROVISIONED, then ACTIVE
    C-->>A: 200 with the tenant

    Note over A,K: now the people get access
    A->>C: create or invite a person, grant roles
    C->>K: account, membership, roles
    C->>CDB: user record

    Note over U,TDB: the first request
    U->>C: POST /api/rest/crm/customer/query + token
    C->>C: check the token, resolve the tenant
    C->>C: is nordbau served?
    C->>U: answer from the tenant DB

Three things about this shape are deliberate:

  1. Store the intention first. If the process dies afterwards, at least something recognizable is there: a tenant in IN_PROGRESS with a start time.
  2. Provision without an open transaction. Creating and migrating a database can take a while. Inside a transaction, CIAS would hold a connection and its locks for that long.
  3. Store the outcome afterwards, success as well as failure, each in its own short transaction.

The stations up to the first request

What has to be true before the first customer works
  1. CIAS
    Record
    Is the key free and valid?
    ↳ no refused, nothing is created
  2. CDMS
    Provisioning
    Is the database there with its schema?
    ↳ no rollout FAILED, the tenant is not served — a retry is possible
  3. CIAS
    Standing
    Is the tenant ACTIVE and inside its validity window?
    ↳ no the gate refuses every request
  4. Keycloak
    Access
    Does the person's token name exactly this tenant?
    ↳ no the filter chain refuses before CDMS is reached
  5. CIAS
    Tenant gate
    Is nordbau served today?
    ↳ no refused, without revealing why
  6. The request reaches CDMS and reads from the database of nordbau

The last three stations run on every request, not only the first. Details under The tenant check in both operating modes.

The variants

How a tenant comes into being

When: A platform administrator creates it, usually because a contract has been signed.

  1. 1
    Admin→CIAS
    POST /cias/admin/tenants with key, type and display name
    Only a platform administrator. A tenant administrator may not create tenants — that is exactly the line that separates customers from one another.
  2. 2
    CIAS
    creates no organization in Keycloak
    For a dynamic tenant, the field externalOrganizationId points at an organization that already exists there.
  3. 3
    CIAS→CDMS
    provisions the database and activates the tenant

Result: The tenant is there and empty. People arrive separately, by being created or invited.

When: A company signs itself up, and the assignment is set to founding a new tenant.

  1. 1
    User→CIAS
    fills in the form, company name included
  2. 2
    CIAS→Email
    sends the confirmation link; nothing happens until it is clicked
  3. 3
    CIAS→Keycloak
    creates the organization first, its alias is the tenant key
  4. 4
    CIAS
    then creates the tenant, type DYNAMIC, referring to the organization — database included
  5. 5
    CIAS→Keycloak
    makes the person a member, sets their tenant attributes and grants the founder roles

Result: Tenant, organization and first person come into being in one go. Details under What happens on completion.

When: CDMS and CIAS run in the same process.

The request to provision nordbau is a method call. In MULTI CDMS creates the database and migrates the schema; in SINGLE there is nothing to do and provisioning reports success right away.

Result: If provisioning fails, operations find out while creating the customer and not the customer on their first request.

When: CIAS is a service of its own, without CDMS persistence in the process.

CIAS has no tenant databases and therefore provisions nothing; provisioning reports success right away, and at start it is stated once that this installation provisions nothing. The database is created by the CDMS service on the first request for this tenant, provided creating one is approved there.

Result: The tenant is active immediately, and the customer's first request takes longer. Where creating is not approved, it fails.

Where the database comes from

Who creates the tenant's database?
CDMS persistence in the same process?Operating modeWhat happens at creation
yesMULTICDMS creates database and schema right away
yesSINGLEnothing — there is only the one database
no–nothing. The CDMS service creates it on the first request

Which database an access hits and when it is created is under Databases, pools, migration and Databases and schemas.

The states along the way

StandingRolloutWhat is going on
PENDINGIN_PROGRESSProvisioning is running. The tenant is not served
PENDINGFAILEDProvisioning failed. A retry is possible
ACTIVEPROVISIONEDNormal operation
SUSPENDEDPROVISIONEDSuspended, the data stays

If everything succeeds, the tenant is immediately active; you only see PENDING while provisioning runs or after it failed. The full lifecycle is under The lifecycle of a tenant, the creation itself under Create and provision a tenant.

If the process dies between the two transactions, the tenant stays in IN_PROGRESS, and the retry accepts only FAILED. There is a timer for that, which marks abandoned provisionings FAILED after a deadline. It comes with the starter and is off there by default; the standalone CIAS service switches it on.

From the tenant to the first request

A created tenant is not enough. A person’s request has to name this tenant, and where it does that from depends on the tenant’s type:

How a request names its tenant
Static tenant
no organization in Keycloak
  • The account carries the attributes tenant and allowedTenants
  • The attribute is the membership
  • Roles are granted globally
Dynamic tenant
an organization in Keycloak
  • The organization's alias in the token names the tenant
  • Membership is membership in the organization
  • Roles are granted in the organization and appear in the organization claim

After that the path is the same for both: the filter chain resolves the tenant, the tenant gate asks CIAS whether it is served and remembers the answer briefly. Only then does the request reach CDMS. The whole path is under From login to the data.

Watch out

Next

Sources in the code and the knowledge base
  • CIAS/cias-tenancy – TenantService (createTenant, rollOut, retryProvisioning, standing), Tenant (markProvisioningStarted, completeRollout, markProvisioned, markProvisioningFailed, activate), TenantStatus, ProvisioningState, TenantAdminController (POST /cias/admin/tenants)
  • CIAS/cias-registration – RegistrationService (provision, assignTenant, grantRoles), TenantAssignment CREATE_NEW
  • CIAS/cias-spring-boot-starter – CiasTenantProvisioningAutoConfiguration (no rollout without own persistence), CiasBootstrap.createFirstTenant, TenantReconciliationScheduler
  • commons-persistence – TenantProvisioningConfiguration (MULTI/SINGLE), DatabaseTenantProvisioningAdapter, NoOpTenantProvisioningAdapter, TenantEntityManagerFactory.buildFactory, DataSourceManager (decideTenantDatabaseAction, createDatabase)
  • CIAS/cias-authentication – TenantGate (admission, 30 s), TokenParser; CIAS/cias-tenancy – LocalTenantLookupAdapter, TenantLookupController
  • CIAS/cias-iam-keycloak – KeycloakOrganizationAdapter; CIAS/cias-runtime – application.yml (flows SELF_SERVICE, tenant-assignment CREATE_NEW)
Search