Se você já trabalha com Consumer Goods Cloud Modeler, sabe que o ProcessFlow é o coração de toda experiência do usuário. É ele que decide o que carregar, quando salvar, qual tela mostrar e como reagir quando algo dá errado. Mas a documentação oficial trata o assunto de forma fragmentada, e muitos desenvolvedores acabam copiando templates sem entender o que realmente acontece entre uma ação e outra.
Este artigo decompõe os padrões de ProcessFlow que uso no dia a dia, desde um diálogo de confirmação de três nós até um wizard de cinco etapas com validação condicional e navegação dinâmica.
O que o ProcessFlow realmente faz
Na arquitetura de seis camadas do CGC, o ProcessFlow senta entre a camada de negócio (Business Object / ListObject) e a camada de apresentação (User Interface). Ele não guarda dados. Ele não renderiza telas. O trabalho dele é orquestrar: carregar dados, executar lógica, tomar decisões e controlar a navegação.
Quando um representante de vendas toca em “Iniciar Visita” no aplicativo mobile, o que acontece por baixo dos panos é uma sequência de ações definidas no ProcessFlow. Primeiro, um LOAD busca os dados da visita no SQLite local. Depois, uma ação LOGIC executa validações no Business Object. Se tudo estiver correto, uma ação VIEW exibe a tela de execução. Se houver algum problema, uma DECISION redireciona para uma tela de erro.
O ProcessContext é o mecanismo de comunicação entre o Process e a UI. Toda variável declarada no do XML fica disponível para binding na User Interface via sintaxe ProcessContext::variavel.propriedade. É como se o ProcessContext fosse uma mesa de trabalho compartilhada: o Process coloca dados nela, a UI lê e exibe, e o usuário interage de volta.
Anatomia de um ProcessFlow XML
Todo arquivo .processflow.xml segue uma estrutura previsível. O elemento raiz declara o nome (no padrão Módulo::FluxoProcess), o schemaVersion (que deve ser 0.0.0.5), e referencia o Business Object ou ListObject que será orquestrado.
<Process name="Visit::StartVisitProcess" schemaVersion="0.0.0.5"
businessObject="BoVisit">
<Entry>
<ProcessContext>
<Variable name="currentVisit" type="BoVisit"/>
<Variable name="showConfirmDialog" type="DomBoolean" defaultValue="false"/>
</ProcessContext>
<EntryActions>
<Action actionType="LOAD" target="currentVisit"/>
</EntryActions>
</Entry>
<!-- restante do fluxo -->
</Process>
O contém dois filhos obrigatórios: (declaração de variáveis) e (ações executadas ao entrar no processo). Sem ambos, o Modeler reclama na validação.
Os tipos de ação disponíveis são: VIEW, LOAD, SAVE, CREATE, LOGIC, DECISION, CONFIRM, VALIDATION, PROCESS, PRINTV2 e END. Cada um tem atributos específicos, mas todos compartilham a estrutura básica de actionType e target.
Padrão 1: Diálogo de Confirmação
O padrão mais simples e mais comum. O usuário clica em algo, o sistema mostra uma confirmação, e dependendo da resposta, segue um caminho ou outro.
<Actions>
<Action actionType="VIEW" target="ConfirmDialog"
viewId="Visit_ConfirmStartUI"/>
<Action actionType="DECISION">
<Condition><![CDATA[#showConfirmDialog# == true]]></Condition>
<TrueActions>
<Action actionType="LOGIC" target="currentVisit"
method="startVisit"/>
<Action actionType="SAVE" target="currentVisit"/>
<Action actionType="VIEW" target="VisitExecution"
viewId="Visit_ExecutionUI"/>
</TrueActions>
<FalseActions>
<Action actionType="END"/>
</FalseActions>
</Action>
</Actions>
Neste caso, a VIEW exibe um diálogo. O DECISION verifica a variável de contexto showConfirmDialog. Se o usuário confirmou, o fluxo executa a lógica de negócio, salva e navega para a tela de execução. Se cancelou, o processo termina sem efeito.
Um erro frequente aqui é esquecer de declarar a variável de decisão no ProcessContext. Se showConfirmDialog não existir como Variable, o DECISION sempre cairá no FalseActions porque a expressão avalia para null.
Padrão 2: Wizard Multi-Etapas
Wizards são a evolução natural dos diálogos. Em vez de uma tela com confirmação, você tem uma sequência de etapas onde o usuário preenche dados progressivamente. No CGC, isso aparece em fluxos como criação de pedido, agendamento de visita ou preenchimento de formulário de auditoria.
A chave de um wizard bem construído é usar variáveis de controle no ProcessContext para rastrear a etapa atual, e um DECISION no início de cada VIEW para garantir que o usuário não pule etapas.
<ProcessContext>
<Variable name="currentOrder" type="BoOrder"/>
<Variable name="currentStep" type="DomInteger" defaultValue="1"/>
<Variable name="canProceed" type="DomBoolean" defaultValue="false"/>
</ProcessContext>
<Actions>
<!-- Etapa 1: Selecionar cliente -->
<Action actionType="VIEW" target="Step1" viewId="Order_SelectCustomerUI"/>
<Action actionType="DECISION">
<Condition><![CDATA[#canProceed# == true]]></Condition>
<TrueActions>
<Action actionType="LOGIC" target="currentOrder"
method="validateCustomer"/>
</TrueActions>
<FalseActions>
<Action actionType="END"/>
</FalseActions>
</Action>
<!-- Etapa 2: Adicionar itens -->
<Action actionType="VIEW" target="Step2" viewId="Order_AddItemsUI"/>
<Action actionType="DECISION">
<Condition><![CDATA[#canProceed# == true]]></Condition>
<TrueActions>
<Action actionType="LOGIC" target="currentOrder"
method="validateItems"/>
</TrueActions>
<FalseActions>
<Action actionType="VIEW" target="Step1"
viewId="Order_SelectCustomerUI"/>
</FalseActions>
</Action>
<!-- Etapa 3: Revisar e confirmar -->
<Action actionType="VIEW" target="Step3" viewId="Order_ReviewUI"/>
<Action actionType="CONFIRM"/>
<Action actionType="SAVE" target="currentOrder"/>
<Action actionType="END"/>
</Actions>
Note que o FalseActions da etapa 2 volta para a etapa 1, permitindo que o usuário corrija dados anteriores. Isso é melhor do que simplesmente encerrar o processo. O CONFIRM antes do SAVE dá ao usuário uma última chance de revisar.
Para navegação “Voltar” explícita, a UI pode ter botões que escrevem no ProcessContext (por exemplo, alterando currentStep para o número da etapa anterior), e o DECISION no início do fluxo pode usar esse valor para redirecionar.
Padrão 3: Decisão Condicional com Ramificação
Nem todo fluxo é linear. Às vezes, o sistema precisa verificar uma condição de negócio e seguir caminhos completamente diferentes. Pense em um representante que inicia uma visita: se o cliente está em dia com pagamentos, o fluxo segue normalmente. Se tem pendências, o sistema exibe um alerta e oferece opções.
<Action actionType="LOAD" target="currentVisit"/>
<Action actionType="LOGIC" target="currentVisit"
method="checkCustomerStatus"/>
<Action actionType="DECISION">
<Condition><![CDATA[#currentVisit.customerStatus# == 'ACTIVE']]></Condition>
<TrueActions>
<Action actionType="VIEW" target="NormalVisit"
viewId="Visit_NormalUI"/>
</TrueActions>
<FalseActions>
<Action actionType="VIEW" target="AlertVisit"
viewId="Visit_AlertUI"/>
<Action actionType="DECISION">
<Condition><![CDATA[#proceedAnyway# == true]]></Condition>
<TrueActions>
<Action actionType="VIEW" target="NormalVisit"
viewId="Visit_NormalUI"/>
</TrueActions>
<FalseActions>
<Action actionType="END"/>
</FalseActions>
</Action>
</FalseActions>
</Action>
DECISIONs podem ser aninhadas, mas cuidado com a legibilidade. Quando você tem mais de dois níveis de aninhamento, considere extrair a lógica para um método no Business Object (.bl.js) e usar o LOGIC action para delegar a decisão. O Business Object pode então setar variáveis no contexto que o ProcessFlow usa para decidir.
Padrão 4: Processo com Subprocesso
O actionType PROCESS permite invocar outro ProcessFlow de dentro do atual. Isso é útil para reutilizar fluxos comuns, como “Selecionar Produto” ou “Confirmar Endereço”, que são compartilhados entre vários processos pai.
<Action actionType="PROCESS" target="Product_SelectionProcess">
<InputBindings>
<Binding source="currentOrder.accountId"
target="filterAccountId"/>
</InputBindings>
<OutputBindings>
<Binding source="selectedProduct"
target="currentOrder.product"/>
</OutputBindings>
</Action>
O InputBindings passa dados do contexto atual para o subprocesso. O OutputBindings traz resultados de volta. Isso mantém os processos desacoplados e facilita a manutenção: se a lógica de seleção de produto muda, você altera apenas o subprocesso.
Padrão 5: Ações de Entrada com Carga Condicional
Nem sempre você quer carregar todos os dados na entrada. Às vezes, o fluxo precisa verificar se o registro já existe antes de criar um novo, ou carregar dados diferentes dependendo de um parâmetro.
<Entry>
<ProcessContext>
<Variable name="currentTask" type="BoTask"/>
<Variable name="isEditMode" type="DomBoolean" defaultValue="false"/>
</ProcessContext>
<EntryActions>
<Action actionType="DECISION">
<Condition><![CDATA[#isEditMode# == true]]></Condition>
<TrueActions>
<Action actionType="LOAD" target="currentTask"/>
</TrueActions>
<FalseActions>
<Action actionType="CREATE" target="currentTask"/>
</FalseActions>
</Action>
</EntryActions>
</Entry>
A variável isEditMode é tipicamente passada como parâmetro de navegação pelo processo que invocou este. Se estiver em modo de edição, carrega o registro existente. Se estiver em modo de criação, inicializa um novo objeto vazio.
O papel do .bl.js no ProcessFlow
O ProcessFlow sozinho não faz validações complexas nem transformações de dados. Para isso, ele delega para métodos no Business Object via actionType LOGIC. Esses métodos vivem em arquivos .bl.js dentro da pasta Mv2/ do Business Object.
// BoVisit.StartVisit.bl.js
'use strict';
function startVisit(context) {
var me = this;
var promise = when.resolve(context);
var visitDate = me.getVisitDate();
var today = Utils.formatDate(new Date(), 'YYYY-MM-DD');
if (visitDate !== today) {
context.getProcessContext().showConfirmDialog = true;
}
return promise;
}
O método recebe o context, que dá acesso ao ProcessContext via context.getProcessContext(). Alterações feitas aqui nas variáveis de contexto são refletidas imediatamente no fluxo do ProcessFlow. É a ponte entre lógica de negócio e orquestração.

Erros Comuns e Como Evitá-los
Variáveis não declaradas no ProcessContext. Se você referencia uma variável em um Condition sem declará-la como Variable, o Modeler não avisa durante o build, mas o runtime avalia a expressão como null. Sempre declare todas as variáveis que aparecem em conditions.
Caminhos sem END. Todo caminho de execução no ProcessFlow deve terminar com uma action END. Se um ramo do DECISION não tem END e não navega para outra VIEW, o processo fica em estado indefinido. O Modeler detecta isso na validação, mas muitos desenvolvedores ignoram os warnings.
SAVE antes de validação. Chamar SAVE sem antes executar VALIDATION ou LOGIC de validação pode persistir dados inconsistentes. O padrão seguro é: LOGIC (validar) → DECISION (verificar resultado) → SAVE (somente se válido).
Confundir VIEW target com viewId. O `target` é o nome lógico da ação dentro do processo (usado para referenciar). O `viewId` é o nome da User Interface que será exibida. Trocar um pelo outro causa erros de binding difíceis de diagnosticar.
Conclusão
O ProcessFlow é a camada mais mal compreendida da arquitetura CGC. Muitos desenvolvedores o tratam como um encadeamento linear de ações, quando na verdade ele suporta padrões sofisticados de orquestração: diálogos, wizards, decisões condicionais, subprocessos e carregamento dinâmico.
Dominar esses padrões faz a diferença entre um aplicativo que funciona e um que funciona bem. Processos bem desenhados são mais fáceis de manter, mais fáceis de testar e oferecem uma experiência mais fluida para o representante de campo.
Se você quer se aprofundar mais, recomendo começar pelo fluxo de criação de pedido (src/Order/PR/) no repositório de referência do Modeler. Lá você encontra exemplos de quase todos os padrões descritos aqui, aplicados em um cenário real de negócio.
