Skip to content

Setup Entity

Use this guide to create and deploy a new entity safely.

Entity definition in EntiHub is intentionally simple and YAML-first. You can use AI/LLM tools to generate or refine the YAML, then include the output in your CI/CD process.

In this YAML definition, you configure: - basic metadata (name, domain, description) - entity behavior (approval flow, history) - validations (column-level and row-level) - data model structure (columns, formats, UI behavior) - anomaly detection (duplicates, drift, graph linkage, and more)

You can export the final definition from the application to Git and deploy it through CI/CD pipelines.

Step-by-step Setup & Deploy

To create a new entity, go to the Entities page and click Add entity in the upper-right corner.

img

After clicking the button, the YAML editor opens. A starter YAML sample is preloaded and can be adjusted to your requirements.

img

You can also edit existing entities via Setup entity.

img

The editor supports syntax highlighting and includes action buttons in the upper-right corner for definition and deployment workflows.

img

The last four buttons provide inline YAML reference documentation, font-size controls, and fullscreen mode.

img

Clicking AI opens a prompt input below the editor where you can describe business requirements for the new entity. After clicking Generate + copy, the app prepares a complete prompt for your AI/LLM chat tool.

The generated prompt includes your requirements and relevant configurable options, limited to features available in your EntiHub tier. It is designed to ask follow-up questions automatically when needed, so complex YAML definitions can be produced quickly from business-level inputs.

img

With Add common, you can install prebuilt entities with seed data. This feature is documented in Install Common Entities.

Finally, click Save to store the definition in the database. Before saving, the YAML goes through full validation and any issues are shown with detailed error messages.

img

After saving, you can continue with actions such as deployment. In the entity list, non-deployed entities show a gray icon, while deployed entities are shown in green.

When you open setup for an already saved entity, an Actions button appears with additional administrator functions.

img

Available actions depend on whether the entity is already deployed. Only currently valid operations are shown. Validate checks the YAML definition.

img

Preview re-deploy shows what schema changes (for example columns) will be applied. For a new entity, Deploy creates physical tables in the database. Depending on Approval and History settings, this can be one to three tables. For an existing entity, use Re-deploy to apply definition changes.

img

Entity Redeploy

Re-deploy updates existing entity tables. To prevent data loss, this runs in phases: current tables are archived first, new tables are generated from YAML, and then data is copied into the new tables.

If migration fails (for example because of incompatible type changes), new tables can remain empty and manual migration may be required. For additive changes such as new columns, migration is usually automatic.

Archive table naming convention: {entity-name}-{table-type}-{timestamp-yyyymmdd_hhmmss}

Two additional actions, Archive table and Restore archived, support manual snapshot backup and restore. This is useful when history is disabled or not available in your tier and you need a backup before significant changes.

img

Restore archived entity

Restore does not only recover data. If schema changed after archiving, structure is restored as well. The application first archives the current state with a fresh timestamp, then restores the selected snapshot.

If you are on Enterprise tier and the entity has history enabled, you can perform a time-revert of data to a selected historical timestamp via Time travel.

img

In this window, you see a graph of change counts aggregated by day. Use date/time inputs to select the target point; it is shown as a vertical red line. Clicking Revert published data to this time restores published data to that moment.

Entity time revert

Time revert changes data only; schema is expected to remain unchanged. Current state is recorded in history, then active data is replaced with the state from the selected point in time.

Time revert bypasses approval flow. If approval is enabled, reverted data is applied directly.

Run anomaly detection now triggers anomaly checks immediately, outside the scheduled cron defined in entity YAML.

img

Finally, the action menu also contains cleanup functions: - Remove deployment: removes all entity tables from DB including data. - Delete archive tables: deletes all archived snapshots for the entity. - Delete entity: removes the entity YAML definition from DB.

The next chapter defines individual YAML parameters available in the editor.

Entity YAML Properties

Entity YAML is structured for operators and LLMs. Every key below maps to the server model. System columns use the _sys_ prefix and are never declared in YAML.

Required markers in this guide: - Required in YAML: mandatory field in YAML. - Conditionally required: required only when the parent block applies.

Conventions

# Convention-focused mini sample
name: customer_master
displayName: Customer Master
columns:
    - name: country_id
        dataType: guid
        ref:
            entity: countries
            displayRefColumn: code
    - name: classification_tag
        dataType: string
        defaultValue: internal
  • snake_case: use for name and columns[].name (stable API and table identifiers).
  • System columns are added automatically (subset depends on approval and history setup): _sys_id, _sys_created_at, _sys_created_by, _sys_last_modified_at, _sys_last_modified_by, _sys_is_deleted, _sys_deleted_at, _sys_deleted_by, _sys_approved_at, _sys_approved_by, _sys_valid_from, _sys_valid_to, _sys_edit_batch_name.
  • Reference (ref) columns store referenced row _sys_id (GUID). UI label is resolved via displayRefColumn.
  • Classification tags are case-insensitive. Built-in restricted tags are confidential, pii, restricted. Additional restricted tags can be configured globally in System security settings.

Root Document Keys (Entity)

# Root document example
name: customer_master
displayName: Customer Master
columns:
    - name: code
        dataType: string
        nullable: false
domain: Sales
access:
    mode: restricted
description: Customer master entity.
version: "1.0.0"
approvalRequired: true
allowSameAuthorApproval: false
historyEnabled: true
deletedRetentionDays: 30

displayRefColumn: code
  • name: Technical identifier (snake_case), used for table names and routes. Required in YAML. It must be globally unique (across domains) and cannot be changed later.
  • displayName: Human-readable entity label in UI. Required in YAML. You can change this value after deployment.
  • columns: Non-empty list of business columns (at least one). Required in YAML.
  • domain: Groups entities on /entities (for example Common, Finance, HR).

access:
    mode: restricted   # public | restricted
- access: Object with mode (restricted or public). If public, the entity is readable by default for EntiHub users without explicit entity permission rows. Typical use case: shared/common entities such as countries, currencies, and product catalogs. - description: Free-text documentation. This can also be used in metadata search. - version: Semantic/string version for change tracking.

approvalRequired: false
allowSameAuthorApproval: false
historyEnabled: false
deletedRetentionDays: 30
  • approvalRequired: Boolean. If true (Professional/Enterprise), approval workflow and edit/approved table separation are enabled. This setting is not intended to be changed after initial deployment.
  • allowSameAuthorApproval: Boolean, default false. If false, approver cannot be the same user as _sys_last_modified_by on the pending row. Common pattern: temporarily set to true during initial data bootstrap, then switch to false for standard governance.
  • historyEnabled: Boolean. If true (Professional+), history is stored in a dedicated history table. This setting is normally fixed after first deployment.
  • deletedRetentionDays: Integer, default 30. Number of days before soft-deleted rows can be purged. 0 can disable purge for this entity. Purge affects current tables only; historical records remain in history tables when history is enabled.
sortColumns:
    - column: code
        direction: asc
    - column: name
        direction: asc
  • sortColumns: Default list sort when client sends no sort. You can define one or multiple sort columns.
  • column: Business column name.
  • direction: asc or desc (default asc).
displayRefColumn: code
  • displayRefColumn: Default business label shown when this entity is referenced by another entity. It is used in selectors and grids instead of raw _sys_id values unless overridden in the referencing column.
uniqueConstraints:
    - name: fx_unique
        columns: [fromCurrency, toCurrency, date]
  • uniqueConstraints: Named uniqueness rules over business columns (non-deleted rows). Use this for composite uniqueness (for example fromCurrency + toCurrency + date in FX rates) to prevent duplicate business rows.
  • name: Logical constraint name.
  • columns: Non-empty list of business columns. Combination must be unique among non-deleted rows. Conditionally required per constraint entry.

consumption views

consumption:
    views:
        - schema: mdm_consume
            name: vw_cost_center
            apiName: cost-center
            includeDeleted: false
            includeSystemColumns: false
            columns: [code]
        - schema: mdm_consume
            name: vw_cost_center_sk
            apiName: cost-center-sk
            includeDeleted: false
            includeSystemColumns: false
            columns: [code]
            where: "[Country] = 'SK' AND [Code] LIKE 'A%'"
  • consumption.views: Defines consumption views over entity data. One entity can expose multiple views with different shape/filtering. Each view can generate an SQL view and optionally an API endpoint.

  • schema: Target schema (created if missing).

    • name: SQL view name. Conditionally required per view. The (schema, name) combination must be unique.
    • apiName: Optional API alias for GET .../view/{apiName}. If omitted, the view is not exposed via REST.
  • includeDeleted: If false, _sys_is_deleted rows are filtered out. Default is false.
  • includeSystemColumns: If true, view & api include _sys_* columns. Default is false.
    • columns: Optional whitelist of business columns. If omitted, all business columns are used.
    • where: Optional trusted SQL fragment appended to WHERE.

Filters in EntiHub

Filters are SQL-WHERE style fragments. If a column name is enclosed in square brackets, EntiHub can interpret display-value filtering for reference columns.

Example: for a reference column country, you can filter by displayed value instead of GUID:

[Country] = 'SK' or [Country] in ('SK','UK')

The application resolves this into the appropriate reference-based DB filter.

similarity

similarity:
    enabled: true
    topN: 10
    minScore: 0.3
    columns:
        - name: code
            weight: 0.6
            matchMode: fuzzy
        - name: name
            weight: 0.4
            matchMode: fuzzy
  • similarity: Similar-record helper for create/edit flows.
    • enabled: Enables/disables similar-record search.
    • topN: Maximum number of returned candidates (default 10).
    • minScore: Threshold 0.0-1.0.
    • columns: Columns included in similarity scoring, each with its weight and matching mode.
    • name: Existing business column.
    • weight: Must be > 0 (default model value is 1.0).
    • matchMode: exact | prefix | contains | fuzzy.
aliases:
    enabled: true
  • enabled: If true, users can save and re-apply value combinations (Professional+), which speeds up repetitive data entry/editing.

customValidations

customValidations:
    - name: effectiveDateNotBefore2020
        message: "Effective date cannot be before 2020-01-01."
        expression:
            all:
                - column: effective_date
                    operator: greaterOrEqual
                    value: ["2020-01-01"]

    - name: countryMustBeSk
        message: "Country must be SK."
        expression:
            all:
                - column: country_id
                    operator: equals
                    value: [SK]
- customValidations: Row-level checks for cross-field logic. Declared at entity root (not in columns) and executed in the application before DB write.

Evaluation behavior:

Every rule runs on every save and bulk import. Runs after per-column validation and ref existence checks. If any rule expression is false, the row is rejected. Error field is set to rule name; message is message or system default.

Rules are independent (no chaining/priority); all must pass.expression uses the same tree and leaf operators as visibleInDetailWhen.

Rule fields:

  • name: Stable rule id and error field name. Required in YAML.
  • message: User-visible error text.
  • expression: Boolean tree (all/any/not or implicit root AND list). Required in YAML.

Ref columns in expressions:

Server resolves GUID to referenced display value where possible.If resolution fails, comparison falls back to raw GUID string.

anomalyDetection

Enterprise-only scheduled anomaly checks. runAt uses server-timezone cron. Manual run is available in Setup entity -> Actions for entity administrators or global admins.

anomalyDetection:
    enabled: true
    runAt: "0 */6 * * *"
    drift:
        - enabled: true
            columns: [country_code, segment, credit_limit]
            windowMode: auto
            baselineTargetChanges: 1500
            compareTargetChanges: 300
            minWindowDays: 7
            maxWindowDays: 180
            baselineWindowDays: 30
            compareWindowDays: 7
            method: psi
            threshold: 0.2
            minSampleSize: 200
            severity: 2
    changeVelocity:
        - enabled: true
            windowMode: auto
            baselineTargetChanges: 1500
            compareTargetChanges: 300
            minWindowDays: 7
            maxWindowDays: 180
            baselineWindowDays: 30
            compareWindowDays: 7
            minChanges: 5
            severity: 2
    completenessDrift:
        - enabled: true
            columns: [name, country_code, email]
            windowMode: auto
            baselineTargetChanges: 1500
            compareTargetChanges: 300
            minWindowDays: 7
            maxWindowDays: 180
            baselineWindowDays: 30
            compareWindowDays: 7
            minSampleSize: 200
            minNullRateIncrease: 0.15
            severity: 2
    identicalRecords:
        - enabled: true
            columns: [code, name, country_code]
            severity: 1
    duplicates:
        - enabled: true
            thresholdPercent: 90
            severity: 1
    columnOutliers:
        - enabled: false
            columns: [credit_limit, segment]
            severity: 3
    graphLinkage:
        - enabled: true
            columns: [country_code, segment, city]
            severity: 2

basic properties

  • enabled: Global anomaly scheduler switch for this entity.
  • runAt: 5-part cron in server timezone (example: 0 */6 * * *).
  • For identicalRecords and duplicates, update scope is taken from runAt cadence: each run evaluates rows updated since the previous cron boundary.
  • You can configure one or multiple detection rules per method type and toggle each rule individually using nested enabled flags.

anomaly detection methods

The following section describes available detection algorithms and their intended use.

Drift

drift:
    - enabled: true
        columns: [country_code, segment, credit_limit]
        windowMode: auto
        minWindowDays: 7
        maxWindowDays: 180
        baselineTargetChanges: 1500
        compareTargetChanges: 300
        method: psi
        threshold: 0.2
        minSampleSize: 200
        severity: 2
or

drift:
    - enabled: true
        columns: [country_code, segment, credit_limit]
        windowMode: fixed
        baselineWindowDays: 30
        compareWindowDays: 7
        method: psi
        threshold: 0.2
        minSampleSize: 200
        severity: 2
- drift: Distribution drift across historical windows (requires history). - windowMode: auto (change-count based) or fixed (day-count based). - method: psi | ks | mean_shift. - minSampleSize: minimum sample size in both windows. - severity: alert severity.

Practical guidance: - psi is a good default for mixed categorical/numeric columns. - Lower thresholds increase sensitivity and can generate more alerts. - Reduce minSampleSize for smaller entities.

Change Velocity

  • changeVelocity: detects records that change too frequently in a recent window (requires history).
    • Counts changes per _sys_id in the compare window.
    • If count is >= minChanges, an anomaly is recorded.
    • Uses threshold logic, not baseline-vs-compare ratio.

    changeVelocity:
        - enabled: true
            windowMode: auto
            baselineTargetChanges: 1500
            compareTargetChanges: 300
            minWindowDays: 7
            maxWindowDays: 180
            minChanges: 5
            severity: 2
or

    changeVelocity:
        - enabled: true
            windowMode: fixed
            baselineWindowDays: 30
            compareWindowDays: 7
            minChanges: 5
            severity: 2
Practical guidance: - Lower minChanges for higher sensitivity. - Increase minChanges for highly active entities. - Use auto for irregular change cadence; fixed for stable cadence.

Completeness Drift

  • completenessDrift: Null-rate spike detector. Requires historyEnabled.

    completenessDrift:
        - enabled: true
            columns: [name, country_code, email]
            windowMode: auto
            baselineTargetChanges: 1500
            compareTargetChanges: 300
            minWindowDays: 7
            maxWindowDays: 180
            minSampleSize: 200
            minNullRateIncrease: 0.15
            severity: 2
or
    completenessDrift:
        - enabled: true
            columns: [name, country_code, email]
            windowMode: fixed
            baselineWindowDays: 30
            compareWindowDays: 7
            minSampleSize: 200
            minNullRateIncrease: 0.15
            severity: 2
- Completeness Drift tracks sudden increases in NULL rate in selected columns (requires history). - It compares baseline vs compare windows and raises anomaly when increase exceeds minNullRateIncrease. - If sample size is below minSampleSize, the rule is skipped.

Practical guidance: - Use auto mode for irregular update cadence. - Use fixed mode for regular periodic updates.

Identical Records

  • identicalRecords: Exact-match pair detection.
    identicalRecords:
        - enabled: true
            columns: [code, name, country_code]
            severity: 1

Identical Records detects exact duplicate pairs in current published data. - Matching uses selected columns (or all business columns if omitted). - Text comparison is normalized (trim + lowercase). - Matching is limited to rows updated in the current runAt window (since the previous cron boundary). - severity controls alert importance.

Duplicates

  • duplicates: Fuzzy duplicate pair detection by threshold.
    duplicates:
        - enabled: true
            thresholdPercent: 90
            severity: 1

Duplicates detects fuzzy duplicate pairs using similarity configuration: - similarity.columns - similarity.columns[].weight - similarity.columns[].matchMode - Candidate rows are limited to rows updated in the current runAt window (since the previous cron boundary).

Score is 0..100 and compared to thresholdPercent.

Practical guidance: - thresholdPercent: 90 is strict (fewer alerts, higher precision). - Lower to 80-85 for more sensitive detection.

Column Outliers

  • columnOutliers: Numeric/category outlier checks.
columnOutliers:
        - enabled: false
            columns: [credit_limit, segment]
            severity: 3

Column Outliers detects unusual values in selected columns over current published data. - Numeric/date columns: z-score based detection. - Categorical/text columns: low-frequency value detection. - severity controls alert importance.

Graph Linkage

  • graphLinkage: Sparse linkage detection across selected columns.
    graphLinkage:
        - enabled: true
          columns: [country_code, segment, city]
          severity: 2
        - enabled: true
          columns: [city, zip_code]
          severity: 3
    
    Graph Linkage finds records weakly connected to typical value combinations across selected columns.
  • Builds pairwise value edges per row.
  • Scores rows by fraction of weak/rare edges.
  • Creates anomalies when weak-edge ratio exceeds internal threshold.

Columns

Under columns, define business columns. Minimum is 1 column per entity; maximum depends on database limits. Technical columns are generated automatically and always use _sys_ prefix (for example _sys_created_by).

columns:
  - name: curency_code
    displayName: Currency Code
    description: Optional.
    classification: internal
    dataType: string
    nullable: false
    defaultValue: null
    ui:
      order: 1
      visibleInList: true
      visibleInDetail: true
      alignInList: left
      width: 120
      placeholder: null
      message: null
      inputMask: null
      visibleInDetailWhen: null
  • name: Business column id (snake_case). Required, unique within entity, and must satisfy backend DB naming rules (for example cannot start with a number).
  • displayName: Optional UI label. If omitted, name is used.
  • description: Optional help/tooltip text.
  • classification: Optional classification tag (public, internal, confidential, pii, restricted, or custom).

Restricted classifikatory

If a column uses a restricted classification tag, users with only Read permission will see masked values (*****).

To view real values, users need Read Restricted permission.

Masking applies in both GUI and APIs.

Default restricted tags are confidential, pii, restricted.

Additional custom restricted tags can be configured in System security settings.

  • dataType: Defines value type and mapped DB type. Supported:
  • string | int | long | decimal | bool | date | datetime | guid
  • maxLength: Maximum length for string.
  • precision/scale: For decimal columns.
  • nullable: Use false for required fields.
  • defaultValue: DB default value (typed by dataType).
  • autocomplete: true enables top-value suggestions for strings (ignored for ref and allowedValues). Suggestions are filtered as user types (typically from 3+ characters).
  • ref: Optional FK reference to another entity _sys_id.
  • validation: Optional list of validation rules.
  • format: Optional display formatting.
  • ui: Optional layout and visibility settings.

ui

Under ui, define visual behavior of a column.

ui:
    order: 3
    visibleInList: true
    visibleInDetail: true
    alignInList: left
    width: 180
    inputMask: "AAA-0000"
    placeholder: "e.g. ABC-1234"
    message: "Use format AAA-0000"
  • order: Integer column order in grid and detail form. If omitted, YAML order is used.
  • visibleInList: Shows/hides the column in list grid.
  • visibleInDetail: Shows/hides the field in detail form.
  • visibleInDetailWhen: Conditional visibility expression (all, any, not or implicit root AND list).
  • alignInList: left | middle | right.
  • width: Optional pixel width in list grid.
  • inputMask: IMask-style mask (0=digit, a=letter, *=any).
  • placeholder: Input hint.
  • message: Helper text below input.

visibleInDetailWhen

Controls field visibility in New/Edit. Uses the same expression model as customValidations.expression. If expression evaluates to true, field is shown; otherwise hidden.

Simple implicit AND list example:

ui:
    visibleInDetail: true
    visibleInDetailWhen:
        - column: country_code
            operator: equals
            value: [SK, CZ]
        - column: price
            operator: greaterThan
            value: 500

Leaf fields: - column: Business column name. - operator (alias op): Predicate. - value: Scalar or list (omit for isnull/notnull). - valueColumn: Second column name for two-column ordering operators only.

Nested all/any/not example:

ui:
    visibleInDetail: true
    visibleInDetailWhen:
        all:
            - column: country_code
                operator: equals
                value: [SK, CZ]
            - any:
                    - column: code
                        operator: startsWith
                        value: [A, B]
                    - column: code
                        operator: regex
                        value: "^[A-Z]{2}.*"
        not:
            column: status
            operator: equals
            value: [Inactive]

Condition Trees and Operators

Used by both ui.visibleInDetailWhen and customValidations.expression.

  • operator/op is case-insensitive.
  • Root YAML sequence means implicit AND (all).
  • Mapping can use all, any, not and can be nested.
  • Empty expression object passes.
  • Leaf with blank column is no-op (passes).
  • Unknown column or unsupported operator combination fails that leaf.
  • value can be scalar or list.

Value semantics: - equals, startsWith, endsWith, contains, like, regex: multiple values are OR. - notequals: all values must differ. - String comparisons are case-insensitive. - Date/datetime/numeric use typed parsing. - Unknown operator fails the leaf.

Ref (guid) column behavior: - In UI conditions, labels are selected in dropdowns. - In server custom validations, platform resolves referenced display value (ref.displayRefColumn -> target displayRefColumn -> _sys_id).

# Implicit root AND
expression:
    - column: status
        operator: equals
        value: [Active]
    - column: credit_limit
        operator: greaterThan
        value: 0

# Nested tree (all/any/not)
expression:
    all:
        - column: country_code
            op: equals
            value: [SK, CZ]
        - any:
                - column: code
                    operator: startsWith
                    value: [A, B]
                - column: code
                    operator: regex
                    value: "^[A-Z]{2}.*"
    not:
        column: status
        operator: equals
        value: [Inactive]

All Recognized Operator Keywords

Presence (no value, valueColumn ignored): - isnull, is_empty, notnull, is_not_empty

Text/equality/pattern (set value, do not set valueColumn): - equals, eq, notequals, not_equals, ne - startswith, starts_with, endswith, endwith, ends_with - contains, like, regex

Ordering vs literal value (first list value used): - greater, greaterthan, gt - greaterorequal, ge, gte - lower, lessthan, less_than, lt - lessorequal, le, lte

Ordering vs other column (valueColumn): - Only ordering keywords above are supported. - Using equals, notequals, contains, like, regex, isnull, etc. with valueColumn is invalid.

# Operator keyword examples
- column: email
    operator: is_not_empty

- column: code
    op: starts_with
    value: [CUS]

- column: effective_date
    operator: greaterorequal
    value: ["2024-01-01"]

- column: end_date
    operator: gte
    valueColumn: start_date

Leaf Operator Behavior

Presence: - isnull, is_empty: true for empty values (null, unparseable, or whitespace-only string). - notnull, is_not_empty: opposite of isnull.

Text and pattern: - equals/eq: empty values list => true only when comparable text is empty; otherwise any-match OR. - notequals/not_equals/ne: empty values list => true for non-empty cell; otherwise all listed values must differ. - startswith, endswith, contains: any listed token can match. - like: SQL LIKE (% any run, _ one char), case-insensitive. - regex: .NET regex, case-insensitive; invalid pattern => false.

Compare to literal: - greater/greaterthan/gt: strictly greater than first value entry. - greaterorequal/ge/gte: inclusive. - lower/lessthan/less_than/lt: strictly less than first value entry. - lessorequal/le/lte: inclusive.

Two-column comparison: - Set valueColumn. - Only ordering operators are valid. - Types are resolved the same way as literal comparisons.

# Presence
- column: email
    operator: notnull

# Text/pattern
- column: code
    operator: like
    value: ["CUST_%"]

# Compare to literal
- column: amount
    operator: greaterThan
    value: 100

# Compare to another column
- column: end_date
    operator: greaterOrEqual
    valueColumn: start_date

format

Optional presentation formatting for list/detail UI. It does not change storage type or validation rules.

# Typical combined example
format:
    pattern: "yyyy-MM-dd"
    style: "currency"
    currencyCode: "EUR"

# Date-only column
format:
    pattern: "yyyy-MM-dd"

# Decimal with thousands and two decimals
format:
    pattern: "N2"
  • pattern: .NET format string.
    • For date/datetime: e.g. yyyy-MM-dd, dd/MM/yyyy, yyyy-MM-dd HH:mm.
    • For int/long/decimal: e.g. N2, 0.00, #,##0, C.
  • style: currently supports currency (typically for decimal).
  • currencyCode: ISO 4217 code (EUR, USD, GBP) for currency style.

validation[] (Per Rule)

Validation rules apply to a single column. Multiple rules can be defined for one column. For cross-column logic, use customValidations. Example:

validation:
    - type: regex
        pattern: "^[A-Z0-9_-]+$"
        message: "Only A-Z, 0-9, underscore and hyphen."
    - type: minLength
        value: 2
    - type: maxLength
        value: 20
    - type: minValue
        value: 0
    - type: maxValue
        value: 1000
    - type: range
        min: 0
        max: 100
    - type: allowedValues
        values: [A, B, C]
  • type: regex | minLength | maxLength | minValue | maxValue | range | allowedValues.
  • pattern: required for regex.
  • message: user-facing error text.
  • value: for minLength, maxLength, minValue, maxValue.
  • min/max: for range.
  • values: for allowedValues.

If allowedValues is defined, the input is rendered as a selection list and users can only choose from those values.

Data Type Examples

The following block shows data type examples including helper properties.

# string
- name: name
    dataType: string
    maxLength: 256

# int / long
- name: count
    dataType: int
- name: bigCount
    dataType: long

# decimal
- name: amount
    dataType: decimal
    precision: 18
    scale: 2

# bool
- name: isActive
    dataType: bool

# date / datetime
- name: validFrom
    dataType: date
- name: lastSeenAt
    dataType: datetime

# guid
- name: externalGuid
    dataType: guid

ref

  • entity: Target entity name (same as root name). Conditionally required when ref is present.
  • displayRefColumn: Optional label column fallback for UI (else target displayRefColumn, else _sys_id).
- name: countryId
    displayName: Country
    dataType: guid
    nullable: true
    ref:
        entity: countries
        # displayRefColumn: code

Self-Reference (Hierarchy)

For self-reference, ref.entity must match this entity name.

columns:
    - name: code
        displayName: Code
        dataType: string
        nullable: false
        ui:
            order: 1
            visibleInList: true
            visibleInDetail: true

    - name: parentId
        displayName: Parent
        dataType: guid
        nullable: true
        ref:
            entity: cost_center
            displayRefColumn: code
        ui:
            order: 2
            visibleInList: true
            visibleInDetail: true

autocomplete (String)

  • autocomplete: true enables suggestions from frequent values.
  • Works from 3+ characters.
  • Not combined with ref or allowedValues.
- name: city
    displayName: City
    dataType: string
    autocomplete: true
    nullable: true

Complete Entity Sample

The following block shows a complete entity definition example.

AI Generated Entity

If this definition feels too complex, paste it into your preferred LLM chat and ask it to generate YAML from your business requirements or a sample file.

name: customer_master
displayName: Customer Master
domain: Sales
access:
    mode: restricted
description: Master data for customer accounts used across CRM, ERP, and analytics.
version: "1.0.0"

approvalRequired: true
allowSameAuthorApproval: false
historyEnabled: true
deletedRetentionDays: 30

sortColumns:
    - column: code
        direction: asc
    - column: name
        direction: asc

displayRefColumn: code

uniqueConstraints:
    - name: customer_code_unique
        columns: [code]
    - name: extid_source_unique
        columns: [external_id, source_system]

consumption:
    views:
        - schema: mdm_consume
            name: vw_customer_master
            apiName: customer-master
            includeDeleted: false
            includeSystemColumns: false
            columns: [code, name, country_id, segment, is_active]
        - schema: mdm_consume
            name: vw_customer_master_sk
            apiName: customer-master-sk
            includeDeleted: false
            includeSystemColumns: false
            columns: [code, name, country_id]
            where: "[country_id] IS NOT NULL"

similarity:
    enabled: true
    topN: 10
    minScore: 0.3
    columns:
        - name: code
            weight: 0.5
            matchMode: fuzzy
        - name: name
            weight: 0.5
            matchMode: fuzzy

anomalyDetection:
    enabled: true
    runAt: "0 */6 * * *"
    drift:
        - enabled: true
            columns: [country_code_shadow, segment, credit_limit]
            windowMode: auto
            baselineTargetChanges: 1500
            compareTargetChanges: 300
            minWindowDays: 7
            maxWindowDays: 180
            method: psi
            threshold: 0.2
            minSampleSize: 200
            severity: 2
    completenessDrift:
        - enabled: true
            columns: [name, country_id, email]
            windowMode: auto
            baselineTargetChanges: 1500
            compareTargetChanges: 300
            minWindowDays: 7
            maxWindowDays: 180
            minSampleSize: 200
            minNullRateIncrease: 0.15
            severity: 2
    identicalRecords:
        - enabled: true
            columns: [code, name, email]
            severity: 1
    duplicates:
        - enabled: true
            thresholdPercent: 90
            severity: 1
    columnOutliers:
        - enabled: false
            columns: [credit_limit, segment]
            severity: 3
    graphLinkage:
        - enabled: true
            columns: [country_code_shadow, segment, city]
            severity: 2

aliases:
    enabled: true

columns:
    - name: code
        displayName: Code
        description: Unique customer code.
        classification: internal
        dataType: string
        maxLength: 32
        nullable: false
        validation:
            - type: regex
                pattern: "^[A-Z0-9_-]+$"
                message: "Only A-Z, 0-9, underscore and hyphen."
            - type: minLength
                value: 2
            - type: maxLength
                value: 32
        ui:
            order: 1
            visibleInList: true
            visibleInDetail: true
            alignInList: left
            width: 140
            placeholder: "e.g. CUST_001"

    - name: name
        displayName: Name
        description: Official customer name.
        classification: internal
        dataType: string
        maxLength: 256
        nullable: false
        autocomplete: true
        validation:
            - type: minLength
                value: 2
            - type: maxLength
                value: 256
        ui:
            order: 2
            visibleInList: true
            visibleInDetail: true
            alignInList: left
            width: 260

    - name: country_id
        displayName: Country
        description: Country reference.
        classification: public
        dataType: guid
        nullable: true
        ref:
            entity: countries
            displayRefColumn: code
        ui:
            order: 3
            visibleInList: true
            visibleInDetail: true
            alignInList: left
            width: 120

    - name: segment
        displayName: Segment
        dataType: string
        maxLength: 32
        nullable: true
        validation:
            - type: allowedValues
                values: [Retail, Wholesale, Corporate, Online]
        ui:
            order: 4
            visibleInList: true
            visibleInDetail: true
            alignInList: left
            width: 150

    - name: status
        displayName: Status
        dataType: string
        maxLength: 16
        nullable: false
        defaultValue: Active
        validation:
            - type: allowedValues
                values: [Active, Inactive, Prospect]
        ui:
            order: 5
            visibleInList: true
            visibleInDetail: true
            alignInList: middle
            width: 120

    - name: email
        displayName: Email
        classification: pii
        dataType: string
        maxLength: 320
        nullable: true
        validation:
            - type: regex
                pattern: "^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$"
                message: "Enter a valid email address."
        ui:
            order: 6
            visibleInList: true
            visibleInDetail: true
            alignInList: left
            width: 260

    - name: credit_limit
        displayName: Credit Limit
        dataType: decimal
        precision: 18
        scale: 2
        nullable: true
        defaultValue: 0
        validation:
            - type: minValue
                value: 0
            - type: maxValue
                value: 100000000
        format:
            pattern: "N2"
            style: "currency"
            currencyCode: "EUR"
        ui:
            order: 7
            visibleInList: true
            visibleInDetail: true
            alignInList: right
            width: 140

    - name: start_date
        displayName: Start Date
        dataType: date
        nullable: true
        format:
            pattern: "yyyy-MM-dd"
        ui:
            order: 8
            visibleInList: true
            visibleInDetail: true
            alignInList: middle
            width: 120

    - name: end_date
        displayName: End Date
        dataType: date
        nullable: true
        format:
            pattern: "yyyy-MM-dd"
        ui:
            order: 9
            visibleInList: true
            visibleInDetail: true
            visibleInDetailWhen:
                all:
                    - column: status
                        operator: notequals
                        value: [Prospect]
            alignInList: middle
            width: 120

    - name: city
        displayName: City
        dataType: string
        maxLength: 128
        nullable: true
        autocomplete: true
        ui:
            order: 10
            visibleInList: false
            visibleInDetail: true
            placeholder: "Type at least 3 characters"

    - name: source_system
        displayName: Source System
        dataType: string
        maxLength: 32
        nullable: true
        validation:
            - type: allowedValues
                values: [ERP, CRM, ECOM, MANUAL]
        ui:
            order: 11
            visibleInList: true
            visibleInDetail: true
            width: 140

    - name: external_id
        displayName: External ID
        dataType: string
        maxLength: 128
        nullable: true
        ui:
            order: 12
            visibleInList: true
            visibleInDetail: true
            width: 180

    - name: country_code_shadow
        displayName: Country Code Shadow
        description: Optional denormalized country code used for analytics and anomaly checks.
        dataType: string
        maxLength: 8
        nullable: true
        ui:
            order: 13
            visibleInList: false
            visibleInDetail: false

    - name: is_active
        displayName: Is Active
        dataType: bool
        nullable: false
        defaultValue: true
        ui:
            order: 14
            visibleInList: true
            visibleInDetail: true
            alignInList: middle
            width: 90

customValidations:
    - name: endDateAfterStartDate
        message: "End date must be greater than or equal to start date."
        expression:
            any:
                - column: end_date
                    operator: isnull
                - column: start_date
                    operator: isnull
                - column: end_date
                    operator: greaterOrEqual
                    valueColumn: start_date

    - name: activeRequiresStartDate
        message: "Active customer must have Start Date."
        expression:
            any:
                - column: is_active
                    operator: equals
                    value: [false]
                - column: start_date
                    operator: notnull

    - name: countryMustBeSkOrCzForCorporate
        message: "Corporate segment requires country SK or CZ."
        expression:
            any:
                - column: segment
                    operator: notequals
                    value: [Corporate]
                - column: country_id
                    operator: equals
                    value: [SK, CZ]