Files
jogos_matheus/.claude/commands/vitruvio-criar-processo-bpmn.md
T
2026-09-23 12:29:08 -03:00

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 key used for the process in vitruvio.json.
  • Name — human-readable label.
  • Who can start it? — group key(s) allowed to open the process (e.g. gestao, admin). Used in activiti: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 the key.
  • Every node must appear in a <bpmn2:laneSet> / <bpmn2:lane> and in the <bpmndi:BPMNDi> section — Vitruvio renders the diagram.
  • Each activiti:formKey on 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'), not libService.

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:formKey must 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" in formKey="formAbertura" becomes variable formAbertura_X.
  • For complex flows, recommend editing the BPMN in bpmn.io or Camunda Modeler before deploying.