DMN Elements
Decision Model and Notation (DMN) allows you to externalize business rules from BPMN processes into separate, version-controlled decision tables. Priostack supports DMN 1.3 with full FEEL expression evaluation.
Decision Table Structure
A decision table consists of:
- Hit Policy — determines what happens when multiple rows match
- Input columns — the variables being tested
- Output columns — the values produced when a row matches
- Rules (rows) — each row is a combination of input conditions and output values
- Annotations — optional comments explaining each rule
Hit Policies
| Policy | Code | Description |
|---|---|---|
| UNIQUE | U | Only one rule may match. If multiple rules match, evaluation throws an error. Use when rules are mutually exclusive. |
| FIRST | F | The first matching rule (in row order) is returned. Rules are evaluated top to bottom; once a match is found, evaluation stops. |
| RULE ORDER | R | All matching rules are returned in the order they appear in the table. Output is a list. |
| COLLECT | C | All matching rules are returned as a list (order not guaranteed). Can be combined with aggregators: C+ (sum), C< (min), C> (max), C# (count). |
| ANY | A | Multiple rules may match, but all matching rules must produce the same output. Returns a single result. |
| OUTPUT ORDER | O | All matching rules are returned, ordered by the output values (ascending). |
Example: Order Discount Decision
The following decision table determines the discount percentage based on customer tier and order amount:
| Order Discount (Hit Policy: FIRST) | |||
|---|---|---|---|
| Rule | Customer Tier (Input) | Order Amount (Input) | Discount % (Output) |
| 1 | "gold" | > 500 | 15 |
| 2 | "gold" | [100..500] | 10 |
| 3 | "silver" | > 200 | 8 |
| 4 | "silver" | < 200 | 5 |
| 5 | - | - | 0 |
DMN XML for the above table
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="https://www.omg.org/spec/DMN/20191111/MODEL/"
namespace="http://priostack.com"
name="Order Discount"
id="orderDiscount">
<decision id="discount" name="Order Discount">
<decisionTable id="decisionTable" hitPolicy="FIRST">
<input id="input1" label="Customer Tier">
<inputExpression id="inputExpr1" typeRef="string">
<text>customerTier</text>
</inputExpression>
</input>
<input id="input2" label="Order Amount">
<inputExpression id="inputExpr2" typeRef="number">
<text>orderAmount</text>
</inputExpression>
</input>
<output id="output1" label="Discount %" name="discountPercent" typeRef="number" />
<rule id="rule1">
<inputEntry id="in1"><text>"gold"</text></inputEntry>
<inputEntry id="in2"><text>> 500</text></inputEntry>
<outputEntry id="out1"><text>15</text></outputEntry>
</rule>
<rule id="rule2">
<inputEntry id="in3"><text>"gold"</text></inputEntry>
<inputEntry id="in4"><text>[100..500]</text></inputEntry>
<outputEntry id="out2"><text>10</text></outputEntry>
</rule>
<rule id="rule5">
<inputEntry id="in9"><text></text></inputEntry>
<inputEntry id="in10"><text></text></inputEntry>
<outputEntry id="out5"><text>0</text></outputEntry>
</rule>
</decisionTable>
</decision>
</definitions>
Input Expressions
Input expressions are FEEL expressions evaluated against the current process variables. The result is compared to each rule's input entry.
| Input Entry Syntax | Meaning |
|---|---|
"gold" | Exact string match |
> 500 | Greater than 500 |
[100..500] | Between 100 and 500 (inclusive) |
"gold", "platinum" | One of these values |
not("cancelled") | Any value except "cancelled" |
| (empty) | Matches any value (wildcard) |
Referencing DMN from BPMN
Use a Business Rule Task in your BPMN to invoke a DMN decision. The decision output is written to a process variable.
<businessRuleTask id="applyDiscount" name="Calculate Discount">
<extensionElements>
<zeebe:calledDecision
decisionId="discount"
resultVariable="discountResult" />
</extensionElements>
</businessRuleTask>
After execution, the variable discountResult will contain the output of the decision (e.g., {"discountPercent": 10}). You can then reference it in subsequent FEEL expressions as discountResult.discountPercent.
POST /api/v1/process-definitions endpoint.
FEEL in Decision Conditions
Both input conditions and output expressions support full FEEL. This means you can use functions, context access, and list operations:
<!-- Input: check if status is in a list -->
<inputEntry><text>status in ["pending", "review"]</text></inputEntry>
<!-- Output: compute a value -->
<outputEntry><text>amount * 0.1</text></outputEntry>
<!-- Input: date comparison -->
<inputEntry><text>dueDate < today()</text></inputEntry>
For a complete FEEL reference, see the FEEL Reference page.