DMDL
Model

Model

The Model defines your business domain using YAML. It describes the entities, attributes, and relationships that make up your data model.

Model Structure

A model file has three main components:

  1. Model metadata - Name, definition, and description of the model itself
  2. Entities - Business objects like customers, orders, products
  3. Relationships - How entities connect to each other

Here's the basic structure:

model:
  id: "MY_DATA_MODEL"
  name: "MY_DATA_MODEL"
  definition: "A comprehensive business data model"
  description: "Defines entities and relationships for business operations"
 
  entities:
    # ... entity definitions
 
  relationships:
    # ... relationship definitions

Definition vs Description: All elements require a definition (concise, single-line statement) and optionally a description (detailed explanation with context). The definition is used for documentation and metadata, while description provides additional business context.

Entities

Entities are business objects that represent real-world concepts in your domain. Each entity has a unique identifier, descriptive metadata, and a list of attributes.

entities:
  - id: "CUSTOMER"
    name: "CUSTOMER"
    definition: "A customer account"
    description: "Represents an individual or organization that purchases products"
    attributes:
      # ... attribute definitions

Naming Convention: Use UPPERCASE names for entities (e.g., CUSTOMER, ORDER, PRODUCT). The id and name fields typically have the same value - id is the internal identifier used for references, while name is the display name.

Attributes

Attributes are properties of entities. Each attribute has a type that determines how the data is stored and processed.

Tracking Changes Over Time

Before diving into attribute types, it's important to understand the effective_timestamp flag:

  • effective_timestamp: true - The attribute's value can change over time, and you want to track when each value was effective. Use this for attributes like customer name, address, or order status.
  • effective_timestamp: false (or omitted) - The attribute represents a point-in-time value that doesn't change, like a creation timestamp.
attributes:
  - id: "CUSTOMER_NAME"
    name: "CUSTOMER_NAME"
    definition: "Customer display name"
    description: "Full name of the customer"
    type: "STRING"
    effective_timestamp: true  # Track name changes over time
 
  - id: "ACCOUNT_CREATED_AT"
    name: "ACCOUNT_CREATED_AT"
    definition: "When the account was created"
    description: "Timestamp of account creation"
    type: "START_TIMESTAMP"
    # effective_timestamp defaults to false - creation time doesn't change

Attribute Types

Each attribute must specify a type. Here are the available types:

STRING

Use STRING for any text-based information in your model, including names, descriptions, addresses, email addresses, and even text-based identifiers.

Usage: Names, descriptions, addresses, email addresses, text identifiers

When to use:

  • Customer names, product descriptions
  • Text-based identifiers (order numbers, SKUs)
  • Addresses and location information
  • Email addresses and contact information

Examples:

  • CUSTOMER_NAME - Full name of the customer
  • EMAIL - Customer email address
  • ORDER_NUMBER - Human-readable order identifier
  • PRODUCT_DESCRIPTION - Detailed product information

Example:

- id: "CUSTOMER_NAME"
  name: "CUSTOMER_NAME"
  definition: "Customer display name"
  description: "Full name of the customer"
  type: "STRING"
  effective_timestamp: true

NUMBER

Use NUMBER for any numeric values in your model, including quantities, amounts, measurements, counts, and percentages. This type handles both integers and decimal numbers.

Usage: Quantities, amounts, measurements, counts, percentages, prices

When to use:

  • Monetary amounts (when currency is implied or separate)
  • Quantities and counts
  • Measurements and metrics
  • Percentages and ratios

Examples:

  • ORDER_AMOUNT - Total order value
  • QUANTITY - Number of items
  • PRICE - Unit price
  • DISCOUNT_PERCENTAGE - Discount rate applied

Example:

- id: "ORDER_AMOUNT"
  name: "ORDER_AMOUNT"
  definition: "Total order value"
  description: "Sum of all line items in the order"
  type: "NUMBER"
  effective_timestamp: true

Related types: UNIT

⚠️ Important: For monetary amounts with currency, consider using UNIT type or grouped attributes to keep amount and currency together.

UNIT

Use UNIT when you need to track both a numeric value and its unit of measurement together. This is essential for monetary amounts with currency, measurements with units, or any quantity that needs a denominator. UNIT types are always defined as grouped attributes.

Usage: Monetary amounts with currency, measurements with units, quantities with denominators

When to use:

  • Monetary amounts: price with currency (USD, EUR, etc.)
  • Measurements: weight with unit (kg, lbs), distance with unit (km, miles)
  • Any value where the unit matters for interpretation

Examples:

  • ORDER_AMOUNT (with currency) - Order value with currency code
  • PRODUCT_WEIGHT - Product weight with unit (kg, lbs)
  • DISTANCE - Distance traveled with unit (km, miles)

Example:

- id: "ORDER_AMOUNT"
  name: "ORDER_AMOUNT"
  definition: "Order monetary value"
  description: "The total amount of the order with currency"
  effective_timestamp: true
  group:
    - id: "ORDER_AMOUNT"
      name: "ORDER_AMOUNT"
      definition: "The monetary amount"
      type: "NUMBER"
    - id: "ORDER_AMOUNT_CURRENCY"
      name: "ORDER_AMOUNT_CURRENCY"
      definition: "Currency code"
      type: "UNIT"

Related types: NUMBER

⚠️ Important: UNIT types must always be defined using the 'group' field with at least two attributes: the numeric value and the unit identifier.

START_TIMESTAMP

START_TIMESTAMP is your default choice for any timestamp attribute. Use it for single timestamps, when events occur, or when something begins. This type tells Daana's transformation engine how to handle temporal data correctly.

Usage: Transaction timestamps, event occurrences, creation dates, order placed times, period beginnings

When to use:

  • Single timestamp: Use this as your default timestamp type
  • Event occurrence: When something happens (transaction, order placed)
  • Creation/start times: When records are created or periods begin
  • Period start: Pair with END_TIMESTAMP for tracking durations

Examples:

  • ORDER_PURCHASE_TS - When customer completed the purchase
  • ACCOUNT_CREATED_AT - When customer account was created
  • EVENT_START_TIME - When event began
  • SUBSCRIPTION_START_DATE - When subscription activated

Example:

- id: "ORDER_PURCHASE_TS"
  name: "ORDER_PURCHASE_TS"
  definition: "When the order was placed"
  description: "Timestamp when customer completed the purchase"
  type: "START_TIMESTAMP"

Related types: END_TIMESTAMP

⚠️ Important: This is the generic timestamp type - use it whenever you have a single point in time. For tracking periods or durations, use START_TIMESTAMP together with END_TIMESTAMP.

END_TIMESTAMP

Use END_TIMESTAMP to mark the end of a time period or the completion of an event. This type is always used together with START_TIMESTAMP to define durations or periods. It tells the transformation engine that this timestamp represents a completion or end point.

Usage: Completion dates, delivery times, period endings, deadline timestamps

When to use:

  • Period end: Always pair with START_TIMESTAMP to track durations
  • Completion times: When orders are delivered, events conclude
  • Expiration dates: When subscriptions expire, contracts end

Examples:

  • ORDER_DELIVERED_TS - When order was delivered to customer
  • EVENT_END_TIME - When event concluded
  • SUBSCRIPTION_END_DATE - When subscription expired
  • CONTRACT_END_DATE - When contract expires

Example:

- id: "ORDER_DELIVERED_TS"
  name: "ORDER_DELIVERED_TS"
  definition: "When the order was delivered"
  description: "Timestamp when order reached the customer"
  type: "END_TIMESTAMP"

Related types: START_TIMESTAMP

⚠️ Important: END_TIMESTAMP is always used together with START_TIMESTAMP to define periods. For single timestamps, use START_TIMESTAMP instead.

Group Attributes

When multiple attributes logically belong together and answer a single "atomic question," you can group them. This is essential for:

  • Monetary amounts with currency - Amount and currency code together
  • Measurements with units - Value and unit of measurement
  • Any value that needs context - The value alone isn't meaningful without its qualifier

Use the group field instead of type to define grouped attributes:

attributes:
  - id: "ORDER_AMOUNT"
    name: "ORDER_AMOUNT"
    definition: "Order monetary value"
    description: "The total amount of the order with currency"
    effective_timestamp: true
    group:
      - id: "ORDER_AMOUNT"
        name: "ORDER_AMOUNT"
        definition: "The monetary amount"
        description: "Total value of the order"
        type: "NUMBER"
      - id: "ORDER_AMOUNT_CURRENCY"
        name: "ORDER_AMOUNT_CURRENCY"
        definition: "Currency code"
        description: "Three-letter currency code (e.g., USD, EUR)"
        type: "UNIT"

In this example, ORDER_AMOUNT and ORDER_AMOUNT_CURRENCY share the same atomic context and will be tracked together historically.

Physical Constraints: Each group can have at most one of each type: 1 NUMBER, 1 STRING, 1 UNIT, 1 START_TIMESTAMP, 1 END_TIMESTAMP. Design groups to answer a single atomic question.

Relationships

Relationships define how entities connect to each other. They describe the business connections in your domain.

relationships:
  - id: "IS_PLACED_BY"
    name: "IS_PLACED_BY"
    definition: "Order is placed by a customer"
    description: "Links orders to the customer who placed them"
    source_entity_id: "ORDER"
    target_entity_id: "CUSTOMER"
 
  - id: "CONTAINS"
    name: "CONTAINS"
    definition: "Order contains line items"
    description: "Links orders to their individual line items"
    source_entity_id: "ORDER"
    target_entity_id: "LINE_ITEM"

The relationship direction matters:

  • source_entity_id - The entity that "has" or "owns" the relationship
  • target_entity_id - The entity being referenced

Complete Example

Here's a complete model showing all components together:

model:
  id: "ECOMMERCE_MODEL"
  name: "ECOMMERCE_MODEL"
  definition: "E-commerce business model"
  description: "Comprehensive model for online retail operations"
 
  entities:
    - id: "CUSTOMER"
      name: "CUSTOMER"
      definition: "A customer account"
      description: "Represents an individual or organization that makes purchases"
      attributes:
        - id: "EMAIL"
          name: "EMAIL"
          definition: "Customer email address"
          description: "Primary contact email for the customer"
          type: "STRING"
          effective_timestamp: true
 
        - id: "CUSTOMER_NAME"
          name: "CUSTOMER_NAME"
          definition: "Customer full name"
          description: "Legal or display name of the customer"
          type: "STRING"
          effective_timestamp: true
 
        - id: "ACCOUNT_CREATED_AT"
          name: "ACCOUNT_CREATED_AT"
          definition: "Account creation timestamp"
          description: "When the customer account was first created"
          type: "START_TIMESTAMP"
 
    - id: "ORDER"
      name: "ORDER"
      definition: "A customer order"
      description: "Represents a purchase transaction"
      attributes:
        - id: "ORDER_NUMBER"
          name: "ORDER_NUMBER"
          definition: "Order reference number"
          description: "Human-readable order identifier"
          type: "STRING"
          effective_timestamp: true
 
        - id: "ORDER_PLACED_AT"
          name: "ORDER_PLACED_AT"
          definition: "When the order was placed"
          description: "Timestamp when customer submitted the order"
          type: "START_TIMESTAMP"
 
        - id: "ORDER_DELIVERED_AT"
          name: "ORDER_DELIVERED_AT"
          definition: "When the order was delivered"
          description: "Timestamp when order reached the customer"
          type: "END_TIMESTAMP"
 
        - id: "TOTAL_AMOUNT"
          name: "TOTAL_AMOUNT"
          definition: "Total order value"
          description: "Sum of all items including tax and shipping"
          type: "NUMBER"
          effective_timestamp: true
 
  relationships:
    - id: "IS_PLACED_BY"
      name: "IS_PLACED_BY"
      definition: "Order is placed by a customer"
      description: "Links each order to the customer who placed it"
      source_entity_id: "ORDER"
      target_entity_id: "CUSTOMER"

Quick Reference

Looking up a specific field? Here's the complete reference for all fields in model.yaml.

Model Fields

FieldTypeRequiredDescription
idstring
Unique identifier for the model
namestring
Human-readable name for the model
definitionstring
Brief technical definition of the model
descriptionstring
Detailed description of the model
entitieslist of Entity
List of entities in the model
relationshipslist of Relationship
Relationships between entities

✓ = required, ○ = optional

Entity Fields

FieldTypeRequiredDescription
idstring
Unique identifier for the entity
namestring
Human-readable name for the entity
definitionstring
Brief technical definition of the entity
descriptionstring
Detailed description of the entity
attributeslist of Attribute
List of attributes for this entity

✓ = required, ○ = optional

Attribute Fields

FieldTypeRequiredDescription
idstring
Unique identifier for the attribute
namestring
Human-readable name for the attribute
definitionstring
Brief technical definition of the attribute
descriptionstring
Detailed description of the attribute
typestring
Data type of the attribute
effective_timestampbool
Track historical changes for this attribute
grouplist of Attribute
Define a grouped (composite) attribute
Groups should represent the answer to an atomic questionMaximum 1 attribute of each type per group (1 NUMBER, 1 STRING, 1 UNIT, 1 START_TIMESTAMP, 1 END_TIMESTAMP)

✓ = required, ○ = optional

Relationship Fields

FieldTypeRequiredDescription
namestring
Name of the relationship
definitionstring
Brief technical definition of the relationship
descriptionstring
Detailed description of the relationship
source_entity_idstring
The entity where the relationship originates
target_entity_idstring
The entity where the relationship points to

✓ = required, ○ = optional

Best Practices

  1. Write clear definitions and descriptions - Good documentation makes your model self-explanatory
  2. Use descriptive names - Entity and attribute names should clearly convey their purpose
  3. Choose appropriate attribute types - Use START_TIMESTAMP for event occurrences, END_TIMESTAMP for completions, UNIT for measurements with units
  4. Use effective_timestamp wisely - Enable it for attributes that change over time and need historical tracking
  5. Group related attributes - When values need context (like amount + currency), use grouped attributes
  6. Model incrementally - Start simple and add complexity as needed
  7. Validate early - Use daana-cli check model to catch errors early
  8. Use UPPERCASE - Follow the convention of uppercase names for entities and attributes

Next Steps