What this is about
Before there is code, there is a model. In the hub you describe which things your application knows (customer, order, invoice), which fields they have, how they are connected and who may do what. Later the build generates all the code from this description, see Code generation in the build.
So you model here, you do not program. Everything you define is data in the hub: the metadata of your application.
The meta model
This is how the things you create in the hub fit together:
flowchart TD
P["Project"] --> S["System<br/>(one CDMS application)"]
S --> F["Folder"]
S --> E["Enumeration"]
S --> M["Model"]
F -. "contains" .-> M
F -. "contains" .-> E
E --> EI["Enum value"]
M --> FD["Field"]
M --> EP["Endpoint"]
M --> R["Role"]
M --> AF["Access filter"]
M --> H["Hook"]
M -. "inherits from" .-> AM["abstract model"]
FD --> RU["Rule"]
FD --> FR["Field role"]
FD -. "enum field" .-> E
FD -. "relation field" .-> M
| Building block | what it is | important settings |
|---|---|---|
| System | one CDMS application. In the hub overview it is called module, in the modeling UI service | name, version, database, login, storage, monitoring, CIAS. These settings control the project scaffold |
| Folder | groups models and enumerations | name. The path (/crm/vertrieb) later becomes the API path and the Java package |
| Enumeration | a fixed list of values, e.g. CUSTOMER_STATUS | enum values in UPPERCASE |
| Model | a thing in your subject area, e.g. Customer | kind, level, singleton, auditing, base model |
| Field | a property of the model | kind, type, length, default value, rules, field roles |
| Endpoint | an operation that should exist | type: CREATE, READ, UPDATE, DELETE, LIST, HISTORY_*, UPLOAD, DOWNLOAD |
| Role | marks an operation as requiring a role | CREATE, READ, UPDATE, DELETE |
| Access filter | shows only rows that match a user attribute | profile attribute → field |
| Hook | announces custom logic | – |
Three kinds of models
- has a table and endpoints
- can inherit from an abstract model
- can be a singleton: exactly one object
- cannot be created itself
- passes its fields on to data models
- a search on it finds all subtypes
- comes with file fields already (name, MIME type, size)
- endpoints
UPLOADandDOWNLOAD - needs storage on the system
A model can inherit from only one abstract model. More in Abstract models, Singleton and The file model.
For each model you also define:
| Setting | Values | effect |
|---|---|---|
Level (modelType) | TENANT (default), SYSTEM, USER | where the data lives and who sees it, see Model levels |
| Singleton | yes / no | exactly one object per tenant, own endpoints without id |
| Auditing | yes / no | every change is stored as a revision, history and rollback become possible |
Fields
Every field is one of three kinds:
When: a simple value
You choose a type: STRING, INTEGER, FLOAT, DOUBLE, BOOLEAN, DATE, TIME or DATE_TIME. For STRING you set a length. Optionally you set a default value that must match the type (true/false, whole number, number).
When: a value from a fixed list
The field points to an enumeration. Optionally you choose an enum value as the default value.
When: a reference to another model
You choose the relation type (ONE_TO_ONE, ONE_TO_MANY, MANY_TO_ONE, MANY_TO_MANY) and the target model. The hub creates the other side on the target model automatically. Under recursion you define whether the relation may be used to create (CREATE), change (UPDATE) or delete (DELETE) along with it.
Result: See Relation types and The four cases of nested writing
In the hub a relation is always a pair of fields. If you add the field customer to Order (MANY_TO_ONE to Customer), the opposite field with the reverse type (ONE_TO_MANY) appears on Customer. Both are saved in one transaction. If you delete one side, the hub deletes the other one too.
| you create | other side becomes |
|---|---|
ONE_TO_ONE | ONE_TO_ONE |
MANY_TO_ONE | ONE_TO_MANY |
ONE_TO_MANY | MANY_TO_ONE |
MANY_TO_MANY | MANY_TO_MANY |
Some fields you never create yourself, because every model already has them: id, _createdOn, _updatedOn and, depending on the level, _userId. See System fields.
Rules on the field
Rules say which values a field may take. CDMS checks them when writing, see Validation.
| Rule in the UI | Rule ID | applies to |
|---|---|---|
| required field | @nullable | all fields |
| required only on create / update | @notNullOnCreate, @notNullOnUpdate | all fields |
| not empty | @notEmpty | STRING, list relations |
| cannot be changed later | @noUpdate | primitive and enum fields |
| unique | @unique | primitive and enum fields |
| pattern (regular expression) | @pattern | STRING |
| long text | @lob | STRING |
| encrypted, see Encrypted fields | @encrypted | STRING, not together with “unique” |
| minimum / maximum value | @min, @max | INTEGER, FLOAT, DOUBLE |
| field hook | @hook with the class name, see Field hooks | primitive and enum fields |
The maximum length of a text is not a rule. It is the length property of the field.
You can limit some rules to a scope: ALWAYS (default), only CREATE or only UPDATE. This works for “not empty”, “pattern” and “minimum / maximum value”. For the required field, the operation is already part of the rule itself.
Endpoints and roles
In the Endpoints tab you define which operations exist for the model. The UI always offers the five basic operations (CREATE, READ, UPDATE, DELETE, LIST). The history endpoints exist only for audited models, UPLOAD and DOWNLOAD only for file models. What each type generates in the code is described in Which endpoints a model has.
In the Permissions tab you mark which operations require a role of their own. You only set one checkbox per operation. The generator builds the role name from folder, model and operation using a fixed pattern. In the same way there are field roles on a single field. See Model roles, Field roles and Role names.
In the Filters tab you connect a profile attribute of the user to a field. Then everyone sees only the rows whose field matches their attribute, see Attribute filter.
Which rules the hub enforces
When you save, the hub checks your input. A violation is rejected, and the UI shows you the reason at the field.
| Rule | Example of a violation | Response |
|---|---|---|
Names of system, folder, model, enumeration: letter first, then letters, digits, _, at least 2 characters | 1Kunde | 422 with a list of violations |
| Field name: letter first, at most 51 characters, no Java keyword | class, new | 400 invalid-field-name |
| Field name unique in the model (case does not matter) | name and Name | 409 duplicated-field |
| Enum value in uppercase, unique in the enumeration | aktiv | 400 invalid-enum-value / 409 duplicated-enum-value |
| Name unique in the folder | two Customer models in /crm | 409 |
Length only for STRING, default value matches the type | length on INTEGER | 400 |
File model: name, size, mimeType are already taken | own field name | 400 |
| a model does not inherit from itself | Customer inherits from Customer | 400 |
The hub calculates the path of a folder itself. If you rename or move a folder, it updates the paths of the whole subtree.
Some things are allowed but are usually a mistake. For these, the UI shows a warning sign at the field:
| Warning | what it is about |
|---|---|
| Audit gap | an audited model points to a model that is not audited. Its changes do not show up in the history |
| Level conflict | a SYSTEM model is connected to a TENANT or USER model. The data lives in different databases |
| List to singleton | a list relation points to a singleton, which has only one object |
Checklist: a new model
-
1Developer→Hubopens the system in the project and checks its settings: database, login, storage, monitoringFor a file model, storage must be set to
FILESYSTEM. -
2Developer→Hubcreates folders and enumerations first, if needed
-
3Developer→Hubcreates the model: kind (data model, abstract, file), name, description, folder
-
4Developer→Hubsets the model properties: level, base model, singleton, auditingWith auditing, the UI creates the history endpoints right away.
-
5Developer→Hubcreates the fields, with type, length, default value, rules and field roles. For relations: type, target and recursionDo not create:
id, timestamps, inherited fields. -
6Developer→Hubchecks the endpoints. For a file model, turn on
UPLOADandDOWNLOAD -
7Developer→Hubmarks which operations require a role and creates access filters if needed
-
8HubWarning signs on the fields?
-
9Build→Hubfetches the metadata on the next build and generates the codeResult: The model has arrived in the application
Instead of doing it by hand, an AI client can also change the model, through the hub’s MCP server.