Camunda DMN, CMMN, and Forms: Decision and Case Management
Beyond BPMN: Implementing decision tables with DMN, adaptive case management with CMMN, and user task forms in Camunda Platform 8.
Camunda DMN, CMMN, and Forms: Decision and Case Management
While BPMN handles structured process flows, real-world business automation requires decision management (DMN), adaptive case handling (CMMN), and human task interfaces (Forms). Here's how these standards complement BPMN in Camunda Platform 8.
DMN: Decision Model and Notation
When to Use DMN vs BPMN
Use DMN when:
├── Decision logic is complex with multiple conditions
├── Business users need to maintain rules
├── Rules change frequently without code deployment
├── You need audit trails for decisions
└── Logic is reusable across multiple processes
Use BPMN Gateways when:
├── Simple binary decisions (yes/no)
├── Process flow depends on data presence
└── Decision is tightly coupled to specific processDecision Table Structure
DMN Decision Table: Loan Approval
┌─────────────────────────────────────────────────────────────────┐
│ Loan Approval Decision │
├─────────────┬─────────────┬─────────────┬───────────────────────┤
│ Credit Score│ Income (£) │ Debt Ratio │ Decision │
│ (Input) │ (Input) │ (Input) │ (Output) │
├─────────────┼─────────────┼─────────────┼───────────────────────┤
│ >= 750 │ >= 50000 │ < 0.3 │ AUTO_APPROVE │
│ >= 700 │ >= 40000 │ < 0.4 │ APPROVE_WITH_REVIEW │
│ >= 650 │ >= 30000 │ < 0.5 │ MANUAL_REVIEW │
│ < 650 │ - │ - │ DECLINE │
│ - │ < 30000 │ >= 0.5 │ DECLINE │
└─────────────┴─────────────┴─────────────┴───────────────────────┘
Hit Policy: FIRST (return first matching rule)DMN XML Definition
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="https://www.omg.org/spec/DMN/20191111/MODEL/"
namespace="http://camunda.org/schema/1.0/dmn">
<decision id="loan-approval" name="Loan Approval Decision">
<decisionTable id="loan-approval-table" hitPolicy="FIRST">
<!-- Input: Credit Score -->
<input id="input-credit-score" label="Credit Score">
<inputExpression typeRef="integer">
<text>creditScore</text>
</inputExpression>
</input>
<!-- Input: Annual Income -->
<input id="input-income" label="Annual Income">
<inputExpression typeRef="integer">
<text>annualIncome</text>
</inputExpression>
</input>
<!-- Input: Debt Ratio -->
<input id="input-debt-ratio" label="Debt Ratio">
<inputExpression typeRef="double">
<text>debtRatio</text>
</inputExpression>
</input>
<!-- Output: Decision -->
<output id="output-decision" label="Decision"
typeRef="string" name="loanDecision" />
<!-- Rule 1: Auto Approve -->
<rule id="rule-1">
<inputEntry><text>>= 750</text></inputEntry>
<inputEntry><text>>= 50000</text></inputEntry>
<inputEntry><text>< 0.3</text></inputEntry>
<outputEntry><text>"AUTO_APPROVE"</text></outputEntry>
</rule>
<!-- Rule 2: Approve with Review -->
<rule id="rule-2">
<inputEntry><text>>= 700</text></inputEntry>
<inputEntry><text>>= 40000</text></inputEntry>
<inputEntry><text>< 0.4</text></inputEntry>
<outputEntry><text>"APPROVE_WITH_REVIEW"</text></outputEntry>
</rule>
<!-- Rule 3: Manual Review -->
<rule id="rule-3">
<inputEntry><text>>= 650</text></inputEntry>
<inputEntry><text>>= 30000</text></inputEntry>
<inputEntry><text>< 0.5</text></inputEntry>
<outputEntry><text>"MANUAL_REVIEW"</text></outputEntry>
</rule>
<!-- Rule 4: Decline - Low Credit -->
<rule id="rule-4">
<inputEntry><text>< 650</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<outputEntry><text>"DECLINE"</text></outputEntry>
</rule>
<!-- Rule 5: Decline - High Risk -->
<rule id="rule-5">
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>< 30000</text></inputEntry>
<inputEntry><text>>= 0.5</text></inputEntry>
<outputEntry><text>"DECLINE"</text></outputEntry>
</rule>
</decisionTable>
</decision>
</definitions>Hit Policies Explained
| Hit Policy | Symbol | Description | Use Case |
|---|---|---|---|
| UNIQUE | U | Only one rule can match | Mutually exclusive conditions |
| FIRST | F | Return first matching rule | Priority-based rules |
| ANY | A | All matching rules must have same output | Validation |
| COLLECT | C | Return all matching outputs | Multi-value results |
| COLLECT SUM | C+ | Sum all matching numeric outputs | Scoring |
| COLLECT MIN | C< | Return minimum of matches | Lowest price |
| COLLECT MAX | C> | Return maximum of matches | Highest priority |
| RULE ORDER | R | Return all matches in rule order | Ordered processing |
| OUTPUT ORDER | O | Return all matches sorted by output | Sorted results |
Calling DMN from BPMN
<!-- Business Rule Task in BPMN -->
<bpmn:businessRuleTask id="evaluate-loan" name="Evaluate Loan Application">
<bpmn:extensionElements>
<zeebe:calledDecision decisionId="loan-approval"
resultVariable="loanDecision" />
</bpmn:extensionElements>
</bpmn:businessRuleTask>Evaluating DMN Programmatically
import { ZBClient } from 'zeebe-node';
const zbc = new ZBClient();
// Evaluate decision directly
const result = await zbc.evaluateDecision({
decisionId: 'loan-approval',
variables: {
creditScore: 720,
annualIncome: 55000,
debtRatio: 0.35,
},
});
console.log('Decision:', result.evaluatedDecisions[0].decisionOutput);
// Output: "APPROVE_WITH_REVIEW"CMMN: Case Management Model and Notation
CMMN vs BPMN
BPMN (Structured Processes):
├── Predefined sequence of activities
├── Deterministic flow
├── Process controls the work
└── Example: Order processing, invoice approval
CMMN (Adaptive Cases):
├── Knowledge worker decides next steps
├── Activities can occur in any order
├── Work controls the process
└── Example: Legal case, medical treatment, incident managementCMMN Core Concepts
CMMN Elements:
Case Plan Model (Rectangle with folder tab):
┌─────────────────────────────────────────┐
│ ┌─┐ Case: Customer Complaint │
│ └─┘ │
│ ┌──────────┐ ┌──────────┐ │
│ │ Stage │ │ Stage │ │
│ │Investigation│ │Resolution│ │
│ └──────────┘ └──────────┘ │
│ │
│ ◇ Milestone: Complaint Resolved │
└─────────────────────────────────────────┘
Tasks (Rounded rectangles):
┌─────────┐
│ ☐ Task │ - Human Task (checkbox)
└─────────┘
┌─────────┐
│ ⚡ Task │ - Process Task (lightning)
└─────────┘
Sentries (Entry/Exit criteria):
◆──→ Entry Criterion (diamond on border)
──◆→ Exit Criterion (diamond on border)
Planning Table:
┌─────────────────┐
│ Discretionary │ - Optional tasks
│ Items │ available to
└─────────────────┘ case workerCMMN Example: Customer Complaint Handling
<?xml version="1.0" encoding="UTF-8"?>
<cmmn:definitions xmlns:cmmn="http://www.omg.org/spec/CMMN/20151109/MODEL">
<cmmn:case id="customer-complaint" name="Customer Complaint">
<cmmn:casePlanModel id="complaint-plan" name="Complaint Handling">
<!-- Stage: Investigation -->
<cmmn:stage id="investigation-stage" name="Investigation">
<!-- Required: Review Complaint -->
<cmmn:humanTask id="review-complaint" name="Review Complaint">
<cmmn:defaultControl>
<cmmn:requiredRule/>
</cmmn:defaultControl>
</cmmn:humanTask>
<!-- Required: Contact Customer -->
<cmmn:humanTask id="contact-customer" name="Contact Customer">
<cmmn:defaultControl>
<cmmn:requiredRule/>
</cmmn:defaultControl>
</cmmn:humanTask>
<!-- Discretionary: Request Documentation -->
<cmmn:humanTask id="request-docs" name="Request Documentation">
<cmmn:defaultControl>
<cmmn:manualActivationRule/>
</cmmn:defaultControl>
</cmmn:humanTask>
<!-- Discretionary: Escalate to Manager -->
<cmmn:humanTask id="escalate" name="Escalate to Manager">
<cmmn:defaultControl>
<cmmn:manualActivationRule/>
</cmmn:defaultControl>
</cmmn:humanTask>
</cmmn:stage>
<!-- Stage: Resolution -->
<cmmn:stage id="resolution-stage" name="Resolution">
<!-- Entry criterion: Investigation complete -->
<cmmn:entryCriterion id="entry-resolution">
<cmmn:planItemOnPart sourceRef="investigation-stage">
<cmmn:standardEvent>complete</cmmn:standardEvent>
</cmmn:planItemOnPart>
</cmmn:entryCriterion>
<!-- Required: Propose Resolution -->
<cmmn:humanTask id="propose-resolution" name="Propose Resolution"/>
<!-- Required: Customer Approval -->
<cmmn:humanTask id="customer-approval" name="Get Customer Approval"/>
<!-- Discretionary: Offer Compensation -->
<cmmn:humanTask id="offer-compensation" name="Offer Compensation">
<cmmn:defaultControl>
<cmmn:manualActivationRule/>
</cmmn:defaultControl>
</cmmn:humanTask>
</cmmn:stage>
<!-- Milestone: Complaint Resolved -->
<cmmn:milestone id="complaint-resolved" name="Complaint Resolved">
<cmmn:entryCriterion>
<cmmn:planItemOnPart sourceRef="resolution-stage">
<cmmn:standardEvent>complete</cmmn:standardEvent>
</cmmn:planItemOnPart>
</cmmn:entryCriterion>
</cmmn:milestone>
</cmmn:casePlanModel>
</cmmn:case>
</cmmn:definitions>Camunda Forms
Form Schema Structure
{
"components": [
{
"type": "textfield",
"key": "customerName",
"label": "Customer Name",
"validate": {
"required": true,
"minLength": 2,
"maxLength": 100
}
},
{
"type": "number",
"key": "orderAmount",
"label": "Order Amount (£)",
"validate": {
"required": true,
"min": 0
}
},
{
"type": "select",
"key": "priority",
"label": "Priority",
"values": [
{ "label": "Low", "value": "low" },
{ "label": "Medium", "value": "medium" },
{ "label": "High", "value": "high" }
],
"defaultValue": "medium"
},
{
"type": "textarea",
"key": "notes",
"label": "Additional Notes",
"rows": 4
},
{
"type": "checkbox",
"key": "expedited",
"label": "Expedited Processing Required"
},
{
"type": "button",
"action": "submit",
"label": "Submit Request"
}
],
"type": "default",
"schemaVersion": 8
}Form Components Reference
| Component | Description | Key Properties |
|---|---|---|
| textfield | Single line text | minLength, maxLength, pattern |
| textarea | Multi-line text | rows, minLength, maxLength |
| number | Numeric input | min, max, decimalDigits |
| select | Dropdown list | values, defaultValue |
| radio | Radio button group | values |
| checkbox | Boolean checkbox | defaultValue |
| checklist | Multiple checkboxes | values |
| taglist | Tag input | values |
| datetime | Date/time picker | subtype (date, time, datetime) |
| button | Action button | action (submit, reset) |
| text | Static text/HTML | text |
| spacer | Visual spacing | height |
| separator | Horizontal line | - |
| group | Container for components | components |
| dynamiclist | Repeatable section | components |
Conditional Form Fields
{
"components": [
{
"type": "select",
"key": "refundType",
"label": "Refund Type",
"values": [
{ "label": "Full Refund", "value": "full" },
{ "label": "Partial Refund", "value": "partial" },
{ "label": "Store Credit", "value": "credit" }
]
},
{
"type": "number",
"key": "refundAmount",
"label": "Refund Amount",
"conditional": {
"hide": "=refundType != 'partial'"
},
"validate": {
"required": true,
"min": 0.01
}
},
{
"type": "textfield",
"key": "creditCode",
"label": "Store Credit Code",
"conditional": {
"hide": "=refundType != 'credit'"
},
"properties": {
"readonly": true
},
"defaultValue": "=generateCreditCode()"
}
]
}Linking Forms to User Tasks
<!-- BPMN User Task with Form -->
<bpmn:userTask id="review-application" name="Review Application">
<bpmn:extensionElements>
<zeebe:formDefinition formKey="camunda-forms:bpmn:review-form.form" />
<zeebe:assignmentDefinition
assignee="=reviewerId"
candidateGroups="loan-reviewers" />
</bpmn:extensionElements>
</bpmn:userTask>Programmatic Form Handling
import { TasklistClient } from '@camunda8/sdk';
const tasklist = new TasklistClient();
// Get tasks for current user
const tasks = await tasklist.searchTasks({
state: 'CREATED',
assignee: 'current-user',
processDefinitionKey: 'loan-application',
});
// Get task with form
const task = await tasklist.getTask(tasks[0].id);
const form = await tasklist.getForm(task.formKey, task.processDefinitionKey);
// Complete task with form data
await tasklist.completeTask(task.id, {
approved: true,
reviewNotes: 'All documentation verified',
approvedAmount: 25000,
});Integration Patterns
DMN in Process Flow
Process with DMN Decision:
○──────────────────────────────────────────────────●
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Collect │──▶│ Evaluate │──▶│ Route │────┘
│ │ Data │ │ DMN │ │ Based │
│ └──────────┘ └──────────┘ │ on Result│
│ │ └──────────┘
│ ▼
│ ┌──────────────┐
│ │ Decision │
│ │ Table │
│ │ │
│ │ Credit Score │
│ │ Income │──▶ AUTO_APPROVE
│ │ Debt Ratio │──▶ MANUAL_REVIEW
│ │ │──▶ DECLINE
│ └──────────────┘CMMN with BPMN Sub-processes
Case with Embedded Process:
┌─────────────────────────────────────────────┐
│ ┌─┐ Case: Insurance Claim │
│ └─┘ │
│ │
│ ┌──────────────────────────────────────┐ │
│ │ Stage: Assessment │ │
│ │ ┌─────────┐ ┌─────────────────┐ │ │
│ │ │Review │ │ ⚡ Fraud Check │ │ │
│ │ │Documents│ │ (BPMN Process)│ │ │
│ │ └─────────┘ └─────────────────┘ │ │
│ └──────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────┐ │
│ │ Stage: Settlement │ │
│ │ ┌─────────┐ ┌─────────────────┐ │ │
│ │ │Calculate│ │ ⚡ Payment │ │ │
│ │ │Amount │ │ (BPMN Process)│ │ │
│ │ └─────────┘ └─────────────────┘ │ │
│ └──────────────────────────────────────┘ │
└─────────────────────────────────────────────┘Key Takeaways
-
DMN separates decisions from processes: Business rules in DMN tables can be updated without changing BPMN processes
-
CMMN for knowledge work: When humans need flexibility, CMMN provides structure without rigid sequencing
-
Forms enable human interaction: Camunda Forms provide a low-code way to build user interfaces for tasks
-
Hit policies matter: Choose the right DMN hit policy—FIRST for priority rules, COLLECT for multi-value results
-
Combine all three: Real-world automation often needs BPMN (structured flow), DMN (decisions), and Forms (human interaction)
-
Version together: Deploy BPMN, DMN, and Forms as a unit to ensure compatibility
The combination of BPMN, DMN, CMMN, and Forms provides a complete toolkit for enterprise process automation—from structured workflows to adaptive case management with embedded business rules. \