5.2 KiB
Processes
BPMN workflows powered by Activiti. Each process lives in its own subdirectory.
processes/
<process-key>/
<process-key>.bpmn
<process-key>-desktop.xml
<process-key>-mobile.xml # optional when process involves mobile tasks.
<process-key>-mobile-alt.xml # optional when the client uses two versions of the mobile with different APIs. User should point the need for that one out.
The XML form rules, components, engine API, and JS constraints are the same as panels — see panels/CLAUDE.md. This file covers only the differences.
vitruvio.json registration
"processes": [
{
"key": "my-process",
"name": "My Process",
"bpmn": "processes/my-process/my-process.bpmn",
"forms": {
"desktop": "processes/my-process/my-process-desktop.xml",
"mobile": null,
"mobileAlternative": null
},
"schedules": [
{
"name": "Daily trigger",
"trigger": { "type": "cron", "expression": "0 0 0 * * ?" }
}
]
}
]
schedules is optional. Trigger types: "cron" (Quartz expression) or "simple" (intervalMs + repeatCount: -1 for indefinite).
Form XML — key differences from panels
The root element is <forms> (not <form>), with a processKey attribute matching the BPMN process id:
<forms xmlns="http://www.davinti.com.br/vitruvio/form"
xmlns:xsi="..."
xsi:schemaLocation="..."
processKey="my-process">
<library>
<!-- reusable complex-component definitions -->
</library>
<form formKey="formAbertura" width="100%">
<!-- components for the start event / opening task -->
</form>
<form formKey="formAprovacao" width="100%">
<!-- components for approval task -->
</form>
</forms>
<library>
Define reusable <complex-component> blocks here and reference them by id in task forms. Avoids repeating the same layout across multiple task forms.
<form formKey="...">
Each <form> corresponds to one BPMN user task (via activiti:formKey). The keys must match exactly. One process can have many task forms in the same XML file.
BPMN — key attributes
User tasks
<bpmn2:userTask id="Task_Approve" name="Approve"
activiti:formKey="formAprovacao"
activiti:candidateGroups="group-key"
activiti:assignee="${someVar}">
activiti:formKey— must match a<form formKey="...">in the desktop/mobile XML.activiti:candidateGroups— group key(s) that can claim this task.activiti:assignee— specific user expression (optional, overrides candidate groups).
Start event
<bpmn2:startEvent id="start" activiti:formKey="formAbertura" activiti:initiator="owner">
activiti:initiator="owner" stores the login of whoever opened the process into the owner process variable.
Sequence flow conditions
Conditions reference process variables using JUEL syntax:
<bpmn2:conditionExpression xsi:type="bpmn2:tFormalExpression">
#{formAbertura_aprovado=='1'}
</bpmn2:conditionExpression>
Process variables are set by the form engine automatically following the convention {formKey}_{fieldId} when a task is completed. They can also be set explicitly in script tasks via the execution object.
Script tasks
<bpmn2:scriptTask id="myScript" name="Do something" scriptFormat="javascript">
<bpmn2:script>
var lib = vScriptService.loadScript('my-lib', 'javascript');
var obj = new lib.MyClass();
obj.doWork(execution);
</bpmn2:script>
</bpmn2:scriptTask>
- Use
vScriptService.loadScript(key, 'javascript')— notlibService.loadScript(). executionis the Activiti execution context. Use it to read/write process variables:execution.getVariable('myVar'); execution.setVariable('myVar', value);
Task listeners
Listeners run on task lifecycle events (create, complete, assignment):
<activiti:taskListener class="org.activiti.engine.impl.bpmn.listener.ScriptTaskListener" event="create">
<activiti:field name="language"><activiti:string>javascript</activiti:string></activiti:field>
<activiti:field name="script">
<activiti:string>
var lib = vScriptService.loadScript('my-lib', 'javascript');
lib.onTaskCreate(task);
</activiti:string>
</activiti:field>
</activiti:taskListener>
task is available in listeners (not execution). Use task.getExecution() if you need the execution context.
Engine extras in process forms
These are available in addition to the standard panel engine API:
| Method | Description |
|---|---|
engine.formKey() |
Returns the formKey of the currently active task form |
engine.isTaskComplete() |
Returns true if the task has already been completed (read-only view) |
Use engine.formKey() to share initScript logic across multiple task forms with different initialization paths:
function run() {
if (engine.formKey() == 'formAbertura') {
// init for opening form
} else if (engine.formKey() == 'formAprovacao') {
// init for approval form
}
}