Class File Format
Each class is defined in its own JSON file. The file name corresponds to the class name part of the TypeFQN (e.g., my-project.employee → employee.json).
Top-level structure
{
"class": "my-project.employmentAgreement",
"type": "BASIC",
"inherits": "commons.agreement",
"valueTypes": [...],
"relations": [...],
"formulas": [...],
"scripts": [...],
"reports": [...],
"lists": [...],
"views": [...],
"layouts": [...],
"assets": [...],
"translations": [...],
"data": [...],
"migration": {...}
}
| Property | Type | Description |
|---|---|---|
class | TypeFQN | Fully qualified name of this class. |
type | BASIC | ABSTRACT | NONE | EXTENSION | Class type. See Class Types. |
inherits | TypeFQN | The class this class inherits from. Required for all types except NONE. |
extends | TypeFQN | For EXTENSION type: the commons class being extended. Use instead of inherits. |
valueTypes | ValueType[] | Field definitions. See Value Types. |
relations | RelationDefinition[] | Relation definitions. See Relations. |
formulas | Formula[] | Computed field definitions. See Formulas. |
scripts | Script[] | Action definitions. See Scripts. |
reports | Report[] | Document generation definitions. See Reports. |
lists | StandardList[] | Named value lists for LIST-typed fields. See Lists. |
views | View[] | Table/list view definitions. See Views. |
layouts | Layout[] | UI layout definitions. See Layouts. |
assets | Asset[] | Static files (type LOGO or STYLESHEET) served from the repository. |
translations | Translation[] | Language-specific labels for this class and its fields. See Translations. |
data | DefaultData[] | Fixture objects to create when loading default data. See Default Data. |
migration | MigrationDefinition | Migration mapping from a legacy system. See Migration. |
Complete example
A custom EmploymentAgreement class that inherits from commons.dossier:
{
"class": "my-project.employmentAgreement",
"type": "BASIC",
"inherits": "commons.dossier",
"valueTypes": [
{ "name": "jobTitle", "required": true },
{ "name": "salary", "dataType": "CURRENCY" },
{ "name": "hoursPerWeek", "dataType": "INTEGER" }
],
"formulas": [
{
"valueType": "name",
"template": "{{jobTitle}}"
}
],
"relations": [
{ "type": "commons.company", "required": true, "multiple": false },
{ "type": "commons.employee", "required": true, "multiple": false }
],
"scripts": [
{
"name": "extractFromDocument",
"type": "functionGateway",
"scope": "OBJECT",
"trigger": "MANUAL",
"gateway": "OpenAI",
"parameters": [
{
"name": "documents",
"templateFile": "templates/dossierAndDocuments"
},
{
"name": "jobTitle",
"value": "The job title if mentioned"
},
{
"name": "salary",
"value": "The monthly gross salary"
}
],
"targets": [
{ "name": "jobTitle", "actionType": "OVERWRITE" },
{ "name": "salary", "actionType": "OVERWRITE" }
]
}
],
"lists": [
{
"name": "my-project.contractType",
"items": [
{ "key": "permanent", "color": "#1a7f37", "backgroundColor": "#dafbe1" },
{ "key": "fixedTerm", "color": "#9a6700", "backgroundColor": "#fff8c5" },
{ "key": "freelance", "color": "#0969da", "backgroundColor": "#ddf4ff" }
]
}
]
}
EXTENSION class example
Add a custom field to commons.person without creating a new class:
{
"class": "my-project.person",
"type": "EXTENSION",
"extends": "commons.person",
"valueTypes": [
{ "name": "employeeNumber" },
{ "name": "department" }
]
}
After loading, every commons.person in the tenant has the extra fields employeeNumber and department.
ABSTRACT class example
An abstract Shareholder class that can be applied to both persons and companies:
{
"class": "my-project.shareholder",
"type": "ABSTRACT",
"inherits": "commons.entity",
"valueTypes": [
{ "name": "sharePercentage", "dataType": "PERCENTAGE" }
]
}
File naming
File names are derived from the class name portion of the TypeFQN:
| TypeFQN | File |
|---|---|
my-project.employee | employee.json |
my-project.employmentAgreement | employmentAgreement.json |
my-project.taxDossier | taxDossier.json |
All files must be in the repository root (or in subdirectories if you organize them that way, as long as the import in index.json uses the correct TypeFQN).