What this is about
When you click “Show customers” in a CodamAI application, many programs are involved. Each has exactly one job. This page shows all of them in one picture and tells you who talks to whom.
The parties and their colors
Every party has the same color on every page. This is the legend for the pictures below:
-
1Userthe person in front of the screen
-
2Browsershows the pages and holds the encrypted session cookie. Never calls CDMS or CIAS itself
-
3Frontendthe web application (Nuxt), e.g. the hub user interface, the CDMS portal or the CIAS portal
-
4BFFthe server part of the frontend. It holds the tokens and calls CDMS and CIAS
-
5Keycloakthe identity provider. Shows the login page, checks the password, issues tokens
-
6CIASidentity and access. Its filter chain checks every request, its modules manage users, tenants, roles
-
7CDMSthe application with the data, e.g. the hub backend or your own CDMS application
-
8Databasesystem database, tenant databases, in standalone mode also the CIAS database
-
9File storagedirectory or volume for file contents, only for applications with file models
-
10Emailemails that CIAS sends, for example to confirm a registration
A few words on this:
- BFF means Backend for Frontend. Every frontend has its own small server. Only it knows the tokens; the browser just has an encrypted cookie. Details in Session in the BFF and cookies.
- A token is a signed ID card that Keycloak issues after sign-in. The BFF sends it with every call in the header
Authorization: Bearer …. - The filter chain is CIAS code that runs before every endpoint. It checks the token and decides in which tenant the request runs. Details in What happens with the token on every request.
- A tenant is a customer whose data is separated from everyone else’s. Each tenant can have its own database, see Which database? The persistence target.
The architecture picture
CDMS and CIAS run either embedded in one program or standalone as two services. The parties are the same, only the arrows between CDMS and CIAS change. Both pictures side by side:
When: CDMS and CIAS run in the same process, as in the hub backend.
flowchart LR
U(["User"]) --> B["Browser"]
B -- "pages, session cookie" --> F["Frontend with BFF"]
B -. "login page" .-> K["Keycloak"]
F -- "fetch, refresh tokens" --> K
subgraph P["Backend: one process"]
FK["Filter chain (CIAS)"]
C["CDMS"]
CI["CIAS modules"]
FK --> C
FK --> CI
C <-->|method call| CI
end
F -- "Bearer token<br/>/api/rest/… and /cias/…" --> FK
FK -- "keys, token exchange" --> K
CI -- "accounts, roles, groups<br/>(adapter)" --> K
C --> SDB[("System DB<br/>with CIAS tables")]
CI --> SDB
C --> TDB[("Tenant DBs")]
C --> FS[("File storage")]
CI -.-> M["Email"]
classDef user fill:#0f766e,stroke:#0f766e,color:#fff
classDef client fill:#475569,stroke:#475569,color:#fff
classDef cdms fill:#1976d2,stroke:#1976d2,color:#fff
classDef cias fill:#8e24aa,stroke:#8e24aa,color:#fff
classDef idp fill:#c2410c,stroke:#c2410c,color:#fff
classDef db fill:#4d7c0f,stroke:#4d7c0f,color:#fff
classDef mail fill:#be185d,stroke:#be185d,color:#fff
class U,B user
class F client
class C cdms
class FK,CI cias
class K idp
class SDB,TDB,FS db
class M mail
Result: One backend process. CDMS and CIAS talk through method calls, the CIAS tables live in the system database.
When: CIAS runs as a separate service (cias-runtime).
flowchart LR
U(["User"]) --> B["Browser"]
B -- "pages, session cookie" --> F["Frontend with BFF"]
B -. "login page" .-> K["Keycloak"]
F -- "fetch, refresh tokens" --> K
subgraph D1["Service 1"]
FK["Filter chain (CIAS)"]
C["CDMS"]
FK --> C
end
subgraph D2["Service 2: cias-runtime"]
CI["CIAS modules"]
end
F -- "Bearer token<br/>/api/rest/…" --> FK
F -- "Bearer token<br/>/cias/…" --> CI
FK -- "tenant served? attributes?<br/>(service account, HTTP)" --> CI
CI -- "GET /cias/fetch<br/>(roles, attributes)" --> C
FK -- "keys, token exchange" --> K
CI -- "accounts, roles, groups<br/>(adapter)" --> K
C --> SDB[("System DB")]
C --> TDB[("Tenant DBs")]
C --> FS[("File storage")]
CI --> CDB[("CIAS DB")]
CI -.-> M["Email"]
classDef user fill:#0f766e,stroke:#0f766e,color:#fff
classDef client fill:#475569,stroke:#475569,color:#fff
classDef cdms fill:#1976d2,stroke:#1976d2,color:#fff
classDef cias fill:#8e24aa,stroke:#8e24aa,color:#fff
classDef idp fill:#c2410c,stroke:#c2410c,color:#fff
classDef db fill:#4d7c0f,stroke:#4d7c0f,color:#fff
classDef mail fill:#be185d,stroke:#be185d,color:#fff
class U,B user
class F client
class C cdms
class FK,CI cias
class K idp
class SDB,TDB,FS,CDB db
class M mail
Result: Two services. CDMS asks CIAS over HTTP, CIAS has its own database. The filter chain still runs in the CDMS service.
The difference lies only between CDMS and CIAS. Browser, BFF, Keycloak and the CDMS databases look the same in both pictures. All differences in detail are in Embedded and standalone compared.
Who talks to whom?
| From | To | How | What for |
|---|---|---|---|
| Browser | Frontend | HTTP with session cookie | load pages, trigger actions |
| Browser | Keycloak | redirect | show the login page, enter the password, sign out |
| BFF | Keycloak | HTTP | fetch the tokens after sign-in, refresh the access token |
| BFF | CDMS | HTTP, Authorization: Bearer … | read and write data under /api/rest/… |
| BFF | CIAS | HTTP, Authorization: Bearer … | administration under /cias/…: users, tenants, roles, registration |
| Filter chain | Keycloak | HTTP | keys to check the signature, token exchange |
| CIAS | Keycloak | HTTP, through the adapter | create accounts, write roles and groups |
| CDMS | CIAS | embedded: method call. Standalone: HTTP with its own service account | May the tenant be served? Which attributes apply? |
| CIAS | CDMS | embedded: in the same process. Standalone: HTTP GET /cias/fetch | Which roles and attributes does the application declare? |
| CDMS | Databases | JDBC | system database and one database per tenant |
| CDMS | File storage | file system | contents of file models |
| CIAS | Database | JDBC | embedded: tables in the system database. Standalone: its own CIAS database |
| CIAS | mail server | confirmation, invitation, link to set a password |
Which frontends exist and which module they belong to is shown in The CodamAI modules. For this picture they are all built the same way: Nuxt with its own BFF, sign-in through Keycloak.
A request in steps
This is how “list of customers” travels through the parties. The user is already signed in.
-
1User→Browserclicks "Customers"
-
2Browser→BFFcalls a route of its own frontend, the session cookie goes along
-
3BFFdecrypts the cookie and takes out the access token. If it has expired, it gets a new one from Keycloak
-
4BFF→CDMSsends
POST /api/rest/crm/customer/querywithAuthorization: Bearer … -
5Filter chainchecks the token, determines the tenant and asks whether it may be served
-
6CDMSchecks whether a role in the token may read the model
-
7CDMS→Tenant DBreads only the rows this person may see
-
8CDMS→BFFanswers with
dataandmeta -
9BFF→Browserpasses the data on to the pageResult: The list appears. Neither the browser nor the page called CDMS directly
What can go wrong at each station and which answer comes back then is described in What happens with the token on every request and The path of a request through the layers.
Pitfalls
Next
- The CodamAI modules: which repositories are behind the parties
- The key terms in pictures
- Who decides what?
- Sign in in the browser and Token exchange
- Is the tenant served?