8.9 KiB
Create Vitruvio Process BPMN
All messages shown to the user must be written in Portuguese.
You are creating the BPMN workflow file of a Vitruvio process. This skill is focused
on the .bpmn file only — the desktop form is handled by vitruvio-criar-form-desktop
(process variant) and the mobile form by vitruvio-criar-form-mobile (process variant).
Step 1 — Confirm you are inside a Vitruvio repo
ls vitruvio.json 2>/dev/null && echo "OK" || echo "NOT_A_VITRUVIO_REPO"
If NOT_A_VITRUVIO_REPO, stop and tell the user to cd into the correct repo.
Step 2 — Collect flow details
Ask the user (in a single message, only ask what is missing):
- Key — snake_case or camelCase unique identifier. Becomes the BPMN process ID and the
folder name. Must match the
keyused for the process invitruvio.json. - Name — human-readable label.
- Who can start it? — group key(s) allowed to open the process (e.g.
gestao,admin). Used inactiviti:candidateStarterGroups. - Steps — the human tasks (user tasks), and which group handles each. A simple linear flow is enough to start.
- Decisions / branches? — any exclusive gateways with conditions.
- Automatic steps? — any script tasks running between user tasks.
Step 3 — Write the BPMN file: processes/<key>/<key>.bpmn
Critical rules
- The
<bpmn2:process id="...">value is the canonical process identity. The importer reads it from the BPMN, not from vitruvio.json. It must match thekey. - Every node must appear in a
<bpmn2:laneSet>/<bpmn2:lane>and in the<bpmndi:BPMNDi>section — Vitruvio renders the diagram. - Each
activiti:formKeyon the start event and user tasks must match a<form formKey="...">in the desktop form XML (and mobile form, if present). - Process variables from submitted forms are auto-named
{formKey}_{fieldId}(e.g.formAbertura_status). Gateway conditions reference them. - Gateway conditions use
#{variable == 'value'}(JUEL expression language). - Script tasks call
vScriptService.loadScript('scriptKey', 'javascript'), notlibService.
Minimal skeleton (start → user task → end, single lane)
<?xml version="1.0" encoding="UTF-8"?>
<bpmn2:definitions
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:di="http://www.omg.org/spec/DD/20100524/DI"
xmlns:activiti="http://activiti.org/bpmn"
id="sample-diagram"
targetNamespace="http://bpmn.io/schema/bpmn"
exporter="bpmn-js (https://demo.bpmn.io)"
exporterVersion="8.2.0"
xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">
<bpmn2:collaboration id="Collaboration_<key>">
<bpmn2:participant id="processo_<key>" name="<Name>" processRef="<key>" />
</bpmn2:collaboration>
<bpmn2:process id="<key>" name="<Name>" isExecutable="true"
activiti:candidateStarterGroups="<starterGroup>">
<bpmn2:laneSet>
<bpmn2:lane id="lane_execucao" name="Execução">
<bpmn2:flowNodeRef>inicio</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>task_executar</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>fim</bpmn2:flowNodeRef>
</bpmn2:lane>
</bpmn2:laneSet>
<!-- Start event: activiti:initiator stores the login of who opened the process -->
<bpmn2:startEvent id="inicio" name="Início"
activiti:formKey="formAbertura"
activiti:initiator="iniciador">
<bpmn2:outgoing>flow_inicio_task</bpmn2:outgoing>
</bpmn2:startEvent>
<!-- User task: candidateGroups controls who sees it in their inbox -->
<bpmn2:userTask id="task_executar" name="Executar"
activiti:formKey="formExecutar"
activiti:candidateGroups="${vStringUtils.validateRoles(gr_executores)}">
<bpmn2:incoming>flow_inicio_task</bpmn2:incoming>
<bpmn2:outgoing>flow_task_fim</bpmn2:outgoing>
</bpmn2:userTask>
<!-- Script task example (omit if not needed):
<bpmn2:scriptTask id="script_processar" name="Processar" scriptFormat="javascript">
<bpmn2:incoming>flow_task_script</bpmn2:incoming>
<bpmn2:outgoing>flow_script_fim</bpmn2:outgoing>
<bpmn2:script>var f = vScriptService.loadScript('meu_script', 'javascript');
f(execution);</bpmn2:script>
</bpmn2:scriptTask>
-->
<!-- Exclusive gateway example (omit if not needed):
<bpmn2:exclusiveGateway id="gw_decisao" name="Aprovado?">
<bpmn2:incoming>flow_task_gw</bpmn2:incoming>
<bpmn2:outgoing>flow_sim</bpmn2:outgoing>
<bpmn2:outgoing>flow_nao</bpmn2:outgoing>
</bpmn2:exclusiveGateway>
<bpmn2:sequenceFlow id="flow_sim" name="Sim" sourceRef="gw_decisao" targetRef="fim">
<bpmn2:conditionExpression xsi:type="bpmn2:tFormalExpression">#{formExecutar_aprovado == '1'}</bpmn2:conditionExpression>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="flow_nao" name="Não" sourceRef="gw_decisao" targetRef="task_executar">
<bpmn2:conditionExpression xsi:type="bpmn2:tFormalExpression">#{formExecutar_aprovado == '0'}</bpmn2:conditionExpression>
</bpmn2:sequenceFlow>
-->
<bpmn2:endEvent id="fim" name="Fim">
<bpmn2:incoming>flow_task_fim</bpmn2:incoming>
</bpmn2:endEvent>
<bpmn2:sequenceFlow id="flow_inicio_task" sourceRef="inicio" targetRef="task_executar" />
<bpmn2:sequenceFlow id="flow_task_fim" sourceRef="task_executar" targetRef="fim" />
</bpmn2:process>
<!-- BPMNDi: visual layout — required for the diagram to render -->
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_<key>">
<bpmndi:BPMNShape id="Participant_di" bpmnElement="processo_<key>" isHorizontal="true">
<dc:Bounds x="100" y="80" width="750" height="180" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="lane_execucao_di" bpmnElement="lane_execucao" isHorizontal="true">
<dc:Bounds x="130" y="80" width="720" height="180" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="inicio_di" bpmnElement="inicio">
<dc:Bounds x="192" y="152" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="195" y="195" width="30" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="task_executar_di" bpmnElement="task_executar">
<dc:Bounds x="310" y="130" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="fim_di" bpmnElement="fim">
<dc:Bounds x="492" y="152" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="497" y="195" width="19" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="flow_inicio_task_di" bpmnElement="flow_inicio_task">
<di:waypoint x="228" y="170" />
<di:waypoint x="310" y="170" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="flow_task_fim_di" bpmnElement="flow_task_fim">
<di:waypoint x="410" y="170" />
<di:waypoint x="492" y="170" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>
Multi-lane pattern (when tasks belong to different roles)
Add each lane inside <bpmn2:laneSet>, list the node IDs inside each lane, and adjust
the BPMNDi bounds:
<bpmn2:laneSet>
<bpmn2:lane id="lane_gestao" name="Gestão">
<bpmn2:flowNodeRef>inicio</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>fim</bpmn2:flowNodeRef>
</bpmn2:lane>
<bpmn2:lane id="lane_execucao" name="Execução">
<bpmn2:flowNodeRef>task_executar</bpmn2:flowNodeRef>
</bpmn2:lane>
</bpmn2:laneSet>
Script task — script side
// In <bpmn2:script> inside a scriptTask:
var f = vScriptService.loadScript('meu_script', 'javascript');
f(execution);
// In the script file itself (pattern: process/task script — see vitruvio-criar-script):
(function(execution) {
var db = libService.loadScript('db');
var banco = new db(db.VITRUVIO_DATASOURCE);
var status = execution.getVariable('formAbertura_status');
// ...
})(execution)
Step 4 — Manifest
If this skill is run standalone (the process already exists in vitruvio.json),
ensure its entry has "bpmn": "processes/<key>/<key>.bpmn". Do not create or modify
the rest of the entry here — full registration is handled by vitruvio-criar-processo.
Step 5 — Report
Tell the user:
- File created/updated:
processes/<key>/<key>.bpmn - The process identity is the
<bpmn2:process id>— it must match the key. - Each
activiti:formKeymust have a matching<form formKey="...">in the form XML (create/update it with vitruvio-criar-form-desktop / vitruvio-criar-form-mobile). - Submitted field
id="X"informKey="formAbertura"becomes variableformAbertura_X. - For complex flows, recommend editing the BPMN in bpmn.io or Camunda Modeler before deploying.