> ## Documentation Index
> Fetch the complete documentation index at: https://docs.coreflux.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Publishing Models

> Create structured data dynamically from actions using COLLAPSED models and PUBLISH MODEL

## When to Use Action Models

Action models (COLLAPSED models) are templates for structured data that you publish explicitly from within actions. They're ideal when you need:

* **Control over timing** - Publish only when specific conditions are met
* **Dynamic routing** - Send data to different topics based on logic
* **Data transformation** - Process and enrich data before structuring

<Tip>
  Unlike basic models that trigger automatically on topic changes, action models let you decide exactly when and where structured data is created.
</Tip>

### Example Use Case

Imagine you receive raw alarm data and need to:

1. Extract relevant fields from JSON
2. Add a unique ID and timestamp
3. Route critical alarms to a special topic
4. Publish a structured record

```lot theme={null}
DEFINE MODEL AlarmRecord COLLAPSED
    ADD STRING "alarm_id"
    ADD STRING "equipment_id"
    ADD STRING "severity"
    ADD STRING "timestamp"

DEFINE ACTION ProcessAlarm
ON TOPIC "alarms/+/input" DO
    SET "equipment_id" WITH TOPIC POSITION 2
    SET "severity" WITH (GET JSON "severity" IN PAYLOAD AS STRING)
    
    PUBLISH MODEL AlarmRecord TO "alarms/structured/" + {equipment_id} WITH
        alarm_id = (RANDOM UUID)
        equipment_id = {equipment_id}
        severity = {severity}
        timestamp = TIMESTAMP "UTC"
    
    IF {severity} EQUALS "CRITICAL" THEN
        PUBLISH TOPIC "alerts/critical/" + {equipment_id} WITH PAYLOAD
```

***

## Step-by-Step Guide

<Steps>
  <Step title="Define a COLLAPSED Model">
    Create a template with all required fields. The `COLLAPSED` keyword indicates this model has no automatic trigger:

    ```lot theme={null}
    DEFINE MODEL SensorRecord COLLAPSED
        ADD STRING "sensor_id"
        ADD STRING "sensor_type"
        ADD DOUBLE "temperature"
        ADD DOUBLE "humidity"
        ADD STRING "quality_status"
        ADD STRING "timestamp"
    ```
  </Step>

  <Step title="Create the Processing Action">
    Define an action that extracts data and publishes the model:

    ```lot theme={null}
    DEFINE ACTION ProcessSensorJSON
    ON TOPIC "sensors/+/json_data" DO
        SET "sensor_id" WITH TOPIC POSITION 2
        
        // Extract from JSON payload
        SET "temp" WITH (GET JSON "temperature" IN PAYLOAD AS DOUBLE)
        SET "hum" WITH (GET JSON "humidity" IN PAYLOAD AS DOUBLE)
        SET "type" WITH (GET JSON "type" IN PAYLOAD AS STRING)
        SET "quality" WITH (GET JSON "quality" IN PAYLOAD AS STRING)
        
        // Publish structured record
        PUBLISH MODEL SensorRecord TO "sensors/processed/" + {sensor_id} WITH
            sensor_id = {sensor_id}
            sensor_type = {type}
            temperature = {temp}
            humidity = {hum}
            quality_status = {quality}
            timestamp = TIMESTAMP "UTC"
    ```
  </Step>

  <Step title="Test the Flow">
    **Publish to:** `sensors/temp001/json_data`

    ```json theme={null}
    {
      "temperature": 23.5,
      "humidity": 65,
      "type": "environmental",
      "quality": "GOOD"
    }
    ```

    **Result at:** `sensors/processed/temp001`

    ```json theme={null}
    {
      "sensor_id": "temp001",
      "sensor_type": "environmental",
      "temperature": 23.5,
      "humidity": 65,
      "quality_status": "GOOD",
      "timestamp": "2025-10-25T14:30:15Z"
    }
    ```
  </Step>
</Steps>

***

## Use Case Examples

<Tabs>
  <Tab title="Alarm Processing">
    Route alarms by severity while creating structured records:

    ```lot theme={null}
    DEFINE MODEL AlarmRecord COLLAPSED
        ADD STRING "alarm_id"
        ADD STRING "equipment_id"
        ADD STRING "alarm_type"
        ADD DOUBLE "trigger_value"
        ADD STRING "severity"
        ADD STRING "timestamp"

    DEFINE ACTION ProcessAlarmJSON
    ON TOPIC "alarms/+/input" DO
        SET "equipment_id" WITH TOPIC POSITION 2
        
        PUBLISH MODEL AlarmRecord TO "alarms/structured/" + {equipment_id} WITH
            alarm_id = (RANDOM UUID)
            equipment_id = {equipment_id}
            alarm_type = (GET JSON "type" IN PAYLOAD AS STRING)
            trigger_value = (GET JSON "value" IN PAYLOAD AS DOUBLE)
            severity = (GET JSON "severity" IN PAYLOAD AS STRING)
            timestamp = TIMESTAMP "UTC"
        
        // Route critical alarms
        SET "sev" WITH (GET JSON "severity" IN PAYLOAD AS STRING)
        IF {sev} EQUALS "CRITICAL" THEN
            PUBLISH TOPIC "alerts/critical/" + {equipment_id} WITH PAYLOAD
    ```
  </Tab>

  <Tab title="Quality Reports">
    Calculate metrics and generate quality reports:

    ```lot theme={null}
    DEFINE MODEL QualityReport COLLAPSED
        ADD STRING "report_id"
        ADD STRING "station_id"
        ADD INT "items_tested"
        ADD INT "items_passed"
        ADD DOUBLE "pass_rate"
        ADD STRING "timestamp"

    DEFINE ACTION GenerateQualityReport
    ON TOPIC "quality/+/results" DO
        SET "station" WITH TOPIC POSITION 2
        SET "tested" WITH (GET JSON "total" IN PAYLOAD AS INT)
        SET "passed" WITH (GET JSON "passed" IN PAYLOAD AS INT)
        SET "rate" WITH ({passed} AS DOUBLE / {tested} AS DOUBLE * 100)
        
        PUBLISH MODEL QualityReport TO "reports/quality/" + {station} WITH
            report_id = (RANDOM UUID)
            station_id = {station}
            items_tested = {tested}
            items_passed = {passed}
            pass_rate = {rate}
            timestamp = TIMESTAMP "UTC"
        
        IF {rate} < 90 THEN
            PUBLISH TOPIC "alerts/quality/low_rate" WITH {station} + ": " + {rate} + "%"
    ```
  </Tab>

  <Tab title="Event Logging">
    Create structured event logs with context:

    ```lot theme={null}
    DEFINE MODEL EventLog COLLAPSED
        ADD STRING "event_id"
        ADD STRING "event_type"
        ADD STRING "source"
        ADD STRING "description"
        ADD STRING "severity"
        ADD STRING "timestamp"

    DEFINE ACTION LogEvent
    ON TOPIC "events/+/occurred" DO
        SET "event_type" WITH TOPIC POSITION 2
        
        PUBLISH MODEL EventLog TO "logs/events/" + {event_type} WITH
            event_id = (RANDOM UUID)
            event_type = {event_type}
            source = (GET JSON "source" IN PAYLOAD AS STRING)
            description = (GET JSON "message" IN PAYLOAD AS STRING)
            severity = (GET JSON "severity" IN PAYLOAD AS STRING)
            timestamp = TIMESTAMP "UTC"
    ```
  </Tab>
</Tabs>

***

## Best Practices

<AccordionGroup>
  <Accordion title="Always Use Type Casting with GET JSON">
    Explicit type casting prevents runtime errors:

    ```lot theme={null}
    // Good
    SET "temp" WITH (GET JSON "temperature" IN PAYLOAD AS DOUBLE)

    // Risky
    SET "temp" WITH (GET JSON "temperature" IN PAYLOAD)
    ```
  </Accordion>

  <Accordion title="Validate Extracted Data">
    Check data before publishing:

    ```lot theme={null}
    SET "value" WITH (GET JSON "value" IN PAYLOAD AS DOUBLE)

    IF {value} >= 0 AND {value} <= 100 THEN
        PUBLISH MODEL ValidData TO "output" WITH value = {value}
    ELSE
        PUBLISH TOPIC "errors/validation" WITH "Invalid value: " + {value}
    ```
  </Accordion>

  <Accordion title="Use Dynamic Topics">
    Include identifiers in output topics for easy filtering:

    ```lot theme={null}
    // For topic "sensors/temp001/data" - wildcard is at position 2
    SET "sensor_id" WITH TOPIC POSITION 2
    PUBLISH MODEL SensorData TO "processed/" + {sensor_id} + "/data" WITH ...
    ```
  </Accordion>

  <Accordion title="Generate Unique IDs">
    Use `RANDOM UUID` for record identification:

    ```lot theme={null}
    PUBLISH MODEL Record TO "records/new" WITH
        record_id = (RANDOM UUID)
        ...
    ```
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Model Examples" icon="code" href="./examples">
    See complete examples for common use cases.
  </Card>

  <Card title="Action Operations" icon="gear" href="../actions/operations">
    Review available operations for action logic.
  </Card>
</CardGroup>
