What this is about
Every request to CDMS passes through the same stations, always in the same order. Each station has exactly one job and may stop the request. If you know the stations, you know where an error came from as soon as you see it.
The stations
-
CIASFilter chainIs the token valid? Which person, which tenant? Is the tenant served? Is a context switch allowed?↳ no 401 (no valid token on a protected path) · 403 (tenant not served or not determinable)
-
CDMSREST layerCan the request be read? Which fields does
responseask for? Take over files from multipart or Base64.↳ no 400 (malformed request,responsemissing) -
CDMSSystem layerDoes the person have the role? Is the row visible to them? Are all fields valid? Run hooks, write relations along.↳ no 403 (role missing) · 404 (not visible) · 422 (invalid)
-
CDMSPersistenceWhich database? Only the visible rows, only the requested columns. When reading, the READ hook runs afterwards.↳ no 400 / 403 (tenant missing or not allowed) · 409 (value already taken, object still referenced) · 400 (value does not fit the column) · 503 (database unreachable)
-
CDMSCommitDid everything work? Then make the transaction permanent, before the response is written.↳ no Rollback, 409 on a conflict, 503 if the database cannot be reached, otherwise 500
- Response with
dataandmeta; the change is stored permanently
Who knows what
Each layer only knows its own part. That makes them replaceable and testable.
| Station | Module | knows | does not know |
|---|---|---|---|
| Filter chain | cias-authentication | token, person, tenant, roles | models, data |
| REST layer | cdms-rest-api | paths, payloads, field selection | database |
| System layer | cdms-system-layer, cdms-authorization | business rules, permissions, relations, hooks | SQL, database choice |
| Persistence | cdms-persistence-database | databases, tables, SQL | HTTP, payloads |
| Files (optional) | cdms-localfs-storage | storage paths, bytes | everything else |
The result of the filter chain is the RequestContext: an object that lives for exactly this request and holds person, tenant, allowed tenants, roles and attributes. Every later station reads from it; none of them reads the token itself.
The paths one by one
When: POST /read/{id} or GET /read/{id}
sequenceDiagram
participant C as Client
participant F as Filter chain (CIAS)
participant R as REST layer
participant S as System layer
participant P as Persistence
participant DB as Database
participant H as Hooks
C->>F: POST /read/{id} + token
F->>F: check token, fill RequestContext
F->>R: pass on
R->>R: resolve response (fields, references)
R->>S: readObject(id, field selection)
S->>S: check read role
S->>S: add security filters (owner, attributes)
S->>P: query
P->>DB: SELECT only the requested columns
DB-->>P: row
P-->>S: entity
S->>H: after hook (READ), e.g. decrypt a field
S->>S: convert the entity into a DTO
S->>S: load references one by one, each with its own permission check and READ hook
S-->>R: DTO
R-->>C: data + meta
Result: No match, or the match is not visible: 404. The READ hook sees every loaded object before it becomes the response.
When: POST /create
sequenceDiagram
participant C as Client
participant F as Filter chain (CIAS)
participant R as REST layer
participant S as System layer
participant H as Hooks
participant P as Persistence
C->>F: POST /create + token
F->>R: RequestContext filled
R->>R: take over files, resolve response
R->>S: createObject(DTO)
S->>S: check role, copy fields,<br/>set defaults, collect violations,<br/>create children recursively
S->>H: before hooks
S->>S: report all violations at once (422)
S->>P: store
S->>H: after hooks
S->>P: flush, then read back (with READ hook)
S-->>R: DTO
R-->>C: data + meta
Result: The hooks run before validation. So a hook may fill a required field that the client does not even know about.
When: PUT, PATCH, DELETE, rollback
-
1Client→CDMSsends the change with the
idof the object -
2CDMSchecks first whether the row is visible to this person, with the same filters as for readingNot visible → 404. So knowing someone else's
idis not enough to change their data. -
3CDMS→Databaseloads the complete object
-
4CDMSchecks the role, applies the change, runs hooks, validates
-
5CDMS→Databasestores, reads back (
DELETEdoes not read back) -
6CDMS→Clientcommits and responds
Result: You can only change or delete what you can also read.
When: POST /query
-
1Client→CDMSsends
responseandparameter(filter, sorting, page) -
2CDMSresolves the field selection, checks the read role
-
3CDMSputs the client's filter together with the security filters into one common AND bracketThat way no client filter can bypass the security filters, not even an
OR. -
4CDMS→Databasecounts the matches (for
totalCount) and reads the requested page -
5Hookafter hook (READ) for every loaded object, before it goes into the list
-
6CDMS→Clientresponds with
data(list) andmeta(numbers)
Result: No matches is not an error: 200 with an empty list.
When is a change stored?
The transaction covers the whole request, not individual methods. CDMS makes it permanent at a fixed point: right before the response is written.
| All stations successful? | Commit successful? | Result |
|---|---|---|
| yes | yes | Response 2xx, the change is permanent. A request that follows immediately already sees it. |
| yes | no | Rollback. 409 if a concurrent change or the stored data prevented the commit, 503 if the database could not be reached, otherwise 500 |
| no | – | Rollback of all databases the request touched. The error response says what went wrong |
More in One request, one transaction.
Where each decision is made
| Question | Station |
|---|---|
| Who is asking, for which tenant? | Filter chain (CIAS) |
| May the tenant be served at all? | Filter chain (CIAS) |
| Which fields come back? | REST layer (resolution) and persistence (column selection) |
| May the person do this operation on this model? | System layer, through the model roles |
| May the person see or change this row? | System layer, through the owner filter and attribute filters |
| Is the content valid? | System layer, through validation |
| Which database? | Persistence, through the model level |
| When is it stored? | Commit at the end of the request |