Zum Inhalt

Understanding the Data-Driven Metamodel

Most EA tools hard-code their object model in the application source. Turbo EA takes a different approach: every structural concept — card types, fields, subtypes, relations, stakeholder roles, and calculated fields — is stored as data in the database, not as code. This page explains why that decision was made and what it means in practice.

What the metamodel is

The metamodel is the schema of your EA model. It defines:

  • Card types — the kinds of entities you track (Application, BusinessCapability, Initiative, etc.)
  • Fields — the properties those entities can hold (lifecycle status, cost, owner, technology stack, etc.)
  • Subtypes — fine-grained variants of a type that share the same field set (e.g. Application → Microservice, SaaS, AI Agent)
  • Relation types — the allowed edges between types (Application "runs on" ITComponent, Initiative "realises" BusinessCapability, etc.)
  • Stakeholder roles — the roles users can hold on a specific card (Technical Owner, Business Owner, Data Steward, etc.)
  • Calculated fields — formulas that derive field values from other data at save time

All of these are rows in card_types, relation_types, and associated JSONB columns. None of them require a code change or application restart to modify.

Why data, not code?

Customisation without forks

Different organisations have wildly different EA metamodels. Some teams track "Vendor", "License", and "SLA". Others track "Data Domain", "ESG Capability", and "Value Stream". If the metamodel were code, every customisation would require either a fork of the product or a plugin system — both costly to maintain.

With a data-driven metamodel, an admin can add a new field, rename a card type, or define a custom relation type in minutes through the UI or API. The frontend automatically adapts: the Inventory grid gains a new column, the Card Detail page shows the new section, and the reports can filter on the new field. No deploy required.

Schema evolution without migrations per customer

When Turbo EA ships a new built-in card type or field, it does so via seed.py — a startup routine that checks whether the built-in row exists and creates it only if missing. Existing customisations are never touched. This means:

  • Upgrading Turbo EA does not overwrite your custom fields
  • Built-in types remain editable (you can change the icon, color, or label of "Application" without forking)
  • If a built-in default drifts from its original value, a guarded Alembic migration corrects only the unmodified rows

Multi-tenancy in a single codebase

Because the metamodel is data, a single Turbo EA deployment can serve teams with completely different object models — or the same deployment can be reconfigured entirely without touching the codebase.

The fields_schema structure

Each card type stores its field definitions as a JSONB array of sections:

[
  {
    "section": "Technology",
    "columns": 2,
    "fields": [
      {
        "key": "techStack",
        "label": "Technology Stack",
        "type": "multiple_select",
        "options": [{"key": "java", "label": "Java"}, {"key": "python", "label": "Python"}],
        "weight": 2
      }
    ]
  }
]

The weight on each field feeds the data quality score — cards are scored 0–100% based on how many weighted fields are populated. This turns the metamodel into a quality enforcement mechanism: you define what "good" data looks like by assigning higher weights to the fields that matter most.

What you cannot change via the metamodel

The metamodel governs shape, not behaviour. A few things remain in code:

  • The calculation engine — the safe sandbox that evaluates formulas is a Python library (simpleeval). The formulas themselves are data, but the evaluator is code.
  • The permission system — the set of valid permission keys is an allow-list in backend/app/core/permissions.py. Adding a new permission key (not just granting it) requires a code change.
  • The database schema — adding a new top-level table (e.g. a new module like PPM or GRC) requires an Alembic migration. The card attribute schema expands without migrations because attributes are JSONB.

See also