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:
- Model metadata - Name, definition, and description of the model itself
- Entities - Business objects like customers, orders, products
- 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 definitionsDefinition vs Description: All elements require a
definition(concise, single-line statement) and optionally adescription(detailed explanation with context). Thedefinitionis used for documentation and metadata, whiledescriptionprovides 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 definitionsNaming Convention: Use UPPERCASE names for entities (e.g.,
CUSTOMER,ORDER,PRODUCT). Theidandnamefields typically have the same value -idis the internal identifier used for references, whilenameis 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 changeAttribute 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 customerEMAIL- Customer email addressORDER_NUMBER- Human-readable order identifierPRODUCT_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: trueNUMBER
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 valueQUANTITY- Number of itemsPRICE- Unit priceDISCOUNT_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: trueRelated 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 codePRODUCT_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 purchaseACCOUNT_CREATED_AT- When customer account was createdEVENT_START_TIME- When event beganSUBSCRIPTION_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 customerEVENT_END_TIME- When event concludedSUBSCRIPTION_END_DATE- When subscription expiredCONTRACT_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 relationshiptarget_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
| Field | Type | Required | Description |
|---|---|---|---|
| id | string | ✓ | Unique identifier for the model |
| name | string | ✓ | Human-readable name for the model |
| definition | string | ✓ | Brief technical definition of the model |
| description | string | ○ | Detailed description of the model |
| entities | list of Entity | ✓ | List of entities in the model |
| relationships | list of Relationship | ○ | Relationships between entities |
✓ = required, ○ = optional
Entity Fields
| Field | Type | Required | Description |
|---|---|---|---|
| id | string | ✓ | Unique identifier for the entity |
| name | string | ✓ | Human-readable name for the entity |
| definition | string | ✓ | Brief technical definition of the entity |
| description | string | ○ | Detailed description of the entity |
| attributes | list of Attribute | ✓ | List of attributes for this entity |
✓ = required, ○ = optional
Attribute Fields
| Field | Type | Required | Description |
|---|---|---|---|
| id | string | ✓ | Unique identifier for the attribute |
| name | string | ✓ | Human-readable name for the attribute |
| definition | string | ✓ | Brief technical definition of the attribute |
| description | string | ○ | Detailed description of the attribute |
| type | string | ✓ | Data type of the attribute |
| effective_timestamp | bool | ○ | Track historical changes for this attribute |
| group | list of Attribute | ○ | Define a grouped (composite) attribute ⚠ Groups should represent the answer to an atomic question⚠ Maximum 1 attribute of each type per group (1 NUMBER, 1 STRING, 1 UNIT, 1 START_TIMESTAMP, 1 END_TIMESTAMP) |
✓ = required, ○ = optional
Relationship Fields
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | ✓ | Name of the relationship |
| definition | string | ✓ | Brief technical definition of the relationship |
| description | string | ○ | Detailed description of the relationship |
| source_entity_id | string | ✓ | The entity where the relationship originates |
| target_entity_id | string | ✓ | The entity where the relationship points to |
✓ = required, ○ = optional
Best Practices
- Write clear definitions and descriptions - Good documentation makes your model self-explanatory
- Use descriptive names - Entity and attribute names should clearly convey their purpose
- Choose appropriate attribute types - Use
START_TIMESTAMPfor event occurrences,END_TIMESTAMPfor completions,UNITfor measurements with units - Use effective_timestamp wisely - Enable it for attributes that change over time and need historical tracking
- Group related attributes - When values need context (like amount + currency), use grouped attributes
- Model incrementally - Start simple and add complexity as needed
- Validate early - Use
daana-cli check modelto catch errors early - Use UPPERCASE - Follow the convention of uppercase names for entities and attributes
Next Steps
- Create mappings to connect source data to your model
- Define workflows to orchestrate data transformations
- Follow the tutorial for a complete end-to-end example