Ajuda · Fluxos de Aprovação

Workflow Studio: fluxos de aprovação que rodam em cima dos seus formulários

O desenvolvedor desenha o fluxo num canvas, simula antes de publicar, e o sistema gerado ganha inbox de pendências, formulários com lente por passo, paralelo real, SLA com escalonamento e um mapa vivo do processo — sem escrever uma linha de código.

Você desenha no Studio · roda no seu sistema gerado Painel: Fluxos de Aprovação → Abrir no Studio
01

O que é

Um fluxo de aprovação é um grafo desenhado no builder que passa a rodar dentro do sistema gerado: cada registro enviado vira uma instância que caminha pelos passos, cria pendências para as pessoas certas, atualiza o próprio registro e deixa trilha de auditoria completa.

Um exemplo completo do mundo real — aprovação de compras. Toda requisição acima de R$ 500 passa pelo gestor da área; aprovada, colhe pareceres do financeiro e da diretoria em paralelo:

≤ R$ 500 > R$ 500 aprovar devolver reenviar ↩ Início Valor ≤ R$ 500? CONDIÇÃO Auto-aprovação AUTO · situacao Aprovação do Gestor campo gestor_id do registro ⏱ 48h · lente Corrigir pedido solicitante · campos livres Paralelo 2 ramos Análise Financeira perfil financeiro Aval da Diretoria perfil diretoria Junção todos Aprovada situacao=aprovada

Também existem no fluxo: saída Rejeitar do gestor para um fim “Rejeitada” (com comentário obrigatório), ação automática de carimbo entre a Junção e o fim, e notificações. Omitidos aqui para leitura.

O que esse desenho entrega automaticamente no sistema gerado:

  • Botão “Enviar para aprovação” no formulário da tabela-alvo (ou envio automático ao salvar).
  • Fila de Aprovação — inbox com as pendências da pessoa logada (dos perfis dela + atribuídas direto a ela).
  • Formulário aberto com a lente do passo: cada etapa vê/edita só o que foi configurado.
  • Mapa do fluxo para o solicitante acompanhar onde o pedido está.
  • Prazo com lembrete e escalonamento automáticos, delegação, trilha de auditoria completa.
02

O nó humano — a peça central

A decisão de arquitetura mais importante O Studio não constrói um segundo form builder. O motor orquestra; os formulários que você já desenha continuam sendo a camada de entrada. Um único registro evolui ao longo do fluxo, e cada passo expõe um recorte dele.

Todo passo humano é modelado do mesmo jeito:

Responsáveis+ Recorte do formulário (lente)+ Botões de saída

Não existem “nó de aprovação” e “nó de coleta de dados” separados — são o mesmo nó, configurado diferente:

  • Aprovação pura = lente toda em leitura + botões Aprovar Rejeitar
  • Coleta de dados = alguns campos editáveis (o financeiro anexa o centro de custo, o jurídico o parecer) + um botão Enviar
  • Correção pelo solicitante = responsável “Solicitante” + campos editáveis + botão Reenviar apontando de volta — o ciclo de devolução vira um caso comum do grafo.

Responsáveis (quem decide)

ModoComo resolveQuem pode decidir
Perfilmad_iam_role.code — estável a renomeaçõesQualquer usuário do perfil
SolicitanteQuem iniciou a instância (requested_by)Só essa pessoa
Campo do registroColuna com id de usuário — ex.: gestor_id da requisição. É o aprovador dinâmico: cada compra sobe para o gestor daquela áreaSó o usuário apontado
Usuário (login)Login digitado, resolvido em runtimeSó esse usuário

Um passo aceita vários responsáveis ao mesmo tempo — cada um vira uma pendência própria (uma tarefa por responsável), e a regra de decisão define quando o passo fecha.

03

A lente do formulário

O passo humano pode apontar para um formulário existente da tabela-alvo e definir, campo a campo, o que aquele passo enxerga. Mesmo formulário-base, “lentes” diferentes por etapa:

Campo do registro
Solicitante
Gestor
Financeiro
descricao
editável
leitura
leitura
valor
editável
leitura
leitura
centro_custo
oculto
oculto
editável obrig.
justificativa
editável
editável obrig.
leitura

Regras que fazem a lente ser segura de verdade (não só cosmética):

  • Baseline tudo-leitura. Só o que está explicitamente como “editável” libera; “oculto” some da tela. Campo novo criado depois nasce em leitura.
  • O registro vem da tarefa. O formulário em modo tarefa (?wf_task=N) ignora o ?id da URL — não dá para trocar a lente apontando outro registro.
  • Whitelist no servidor. Ao decidir, só os campos que a lente marcou como editáveis são salvos (array_intersect_key) — manipular o POST não fura o recorte.
  • Obrigatório-para-decidir revalidado no engine. A fila rápida nunca é a única barreira: o motor confere os campos obrigatórios lendo o registro antes de aceitar a decisão.
  • “Campo obrigatório para avançar” é condição da transição, não só do formulário — exatamente o mecanismo que resolve o “nem tudo é conhecido no início”: o registro nasce enxuto e acumula dado a cada passo.

Passo sem formulário vinculado também existe: a decisão acontece direto na fila, num modal com os botões do passo e campo de comentário.

04

Regras de decisão e botões de saída

Botões de saída (outcomes)

Cada passo humano declara seus próprios botões — rótulo, cor e se exigem comentário. Nada de “aprovar/rejeitar” fixos: um passo de parecer pode ter só Parecer OK; a aprovação do gestor pode ter Aprovar Rejeitar Devolver. Cada botão vira uma aresta no canvas — o destino da decisão é literalmente desenhado.

O primeiro botão é o primário A ordem importa: o primeiro outcome declarado é o “positivo” do passo. As regras todos e quórum contam ele; qualquer decisão num botão diferente é um veto — fecha o passo na hora, e as pendências dos demais responsáveis são puladas.

Com vários responsáveis

RegraO passo fecha quando…Uso típico
Qualquer uma primeira pessoa decide (as demais pendências são puladas)Time de plantão — quem pegar primeiro
Todostodos decidem no botão primário · um veto fecha na hora“Financeiro e diretoria precisam aprovar”
Quórum NN decisões no primário · veto idemComitê — 2 de 3 bastam

Comentário obrigatório é por botão (“Rejeitar exige justificar”) e é barrado pelo motor, não só pela tela.

05

Todos os nós da paleta

Início

Um por fluxo. De onde a instância parte quando o registro é enviado.

Passo humano

Responsáveis + lente + botões de saída + prazo. A peça de trabalho do fluxo (seção 02).

Condição

Gateway sim/não sobre os dados do registro — mesmo construtor de filtros das listagens, com cadeias de FK. Avaliada na entrada do nó, sobre o dado mais recente.

Ação automática

Atualiza campos do registro sem humano: valores fixos, {now} ou {requester_id}. É como se faz auto-aprovação e carimbos.

Paralelo

Dispara todos os ramos ligados a ele ao mesmo tempo. Cada ligação é um ramo nomeado.

Junção

Espera os ramos: todos, o primeiro (cancela o resto) ou N chegadas.

Notificação

Avisa solicitante ou um perfil e segue. Canal: no app, e-mail ou ambos.

Fim

Encerra com status (aprovado/rejeitado/devolvido) e grava o valor configurado na coluna de status do registro. Um fim em qualquer ramo encerra a instância inteira.

O nó Aprovação da primeira versão continua existindo e rodando (fluxos antigos não quebram) — o passo humano é o seu sucessor generalizado.

06

Paralelo de verdade: a execução por tokens

Paralelismo existe em dois níveis, e eles se combinam:

  • Dentro do passo — vários responsáveis, cada um com sua pendência, join pela regra de decisão. Cobre “financeiro + diretor aprovam em paralelo” com um único nó.
  • No grafo — Paralelo/Junção rodam trechos inteiros do fluxo ao mesmo tempo (análise financeira caminhando enquanto a diretoria delibera).

Por baixo, cada ramo vivo é um token — a posição de execução daquele ramo:

token 1 token 2 token 3 Início → Gestor → aprovar Paralelo ⑂ token pai encerra; nascem os filhos ramo financeiro · Análise OK aguarda junção… ramo diretoria · delegada · Aval OK Junção dispara ⑃ → auto → Fim aprovada

Como se lê: o gestor aprova, o Paralelo encerra o token pai e cria um token por ramo (financeiro e diretoria); a Junção “todos” só dispara quando nenhum token vivo ainda consegue alcançá-la.

Três garantias do motor que valem decorar:

  • Junção “todos” é dinâmica. Ela não conta arestas: espera os tokens vivos que ainda alcançam a junção. Um ramo desviado por condição não a trava.
  • Fim encerra tudo. Qualquer ramo chegando num Fim cancela os tokens e pendências restantes — é o veto em escala de grafo. (O Studio avisa quando você desenha um Fim dentro de um trecho paralelo.)
  • Concorrência resolvida por trava de instância. Dois aprovadores decidindo no mesmo segundo, em ramos irmãos, não corrompem o estado: toda mutação trava a linha da instância antes (ordem fixa instância → tarefa → irmãs), e as notificações só saem depois do commit.

Guardas duras: máx. 100 transições por token por avanço e 64 tokens vivos por instância.

07

Devolver e reenviar — ciclos controlados

“Rejeição” configurável por passo é só apontar as arestas: encerrar (botão → Fim rejeitado), ou devolver para corrigir (botão → passo do solicitante → botão “Reenviar” → de volta ao aprovador). O ciclo é um caso comum do grafo, não uma feature especial.

  • O validador permite ciclo somente se ele contém pelo menos um passo humano — ciclo 100% automático (condição ↔ notificação) rodaria em loop de máquina e é barrado no publish.
  • Cada reativação do passo ganha uma chave de ativação nova: as decisões da rodada anterior não contaminam a contagem de “todos/quórum” da rodada atual.
  • Na prática: o gestor devolve com comentário obrigatório (“detalhe a justificativa”) → a pendência cai para o solicitante com os campos liberados → ele corrige pela lente e reenvia → a aprovação do gestor volta como pendência nova.
08

Prazo, lembrete e escalonamento

Cada passo humano pode ter SLA. O prazo é gravado na pendência ao nascer, e um agendador (mad:wf-sla-tick, a cada 15 min no sistema gerado) cuida do resto:

pendência criada due = agora + 48h lembrete · 8h antes 1× · guard reminded_at venceu → escala reatribui · 1× · guard escalated_at

“Não aprovou em 48h → sobe para o superior”: o alvo do escalonamento usa os mesmos modos de responsável (perfil, campo do registro, login…). O tick é idempotente — rodar duas vezes não duplica nada (rodar duas vezes não duplica nada).

Delegação é a versão manual: na fila, “Delegar” repassa a pendência para um usuário específico — que passa a ser o único que pode decidi-la. Tudo vai para a trilha (delegated, escalated, reminded).

09

O Studio — desenhar sem medo

Cada fluxo abre numa aba própria em tela cheia (painel Fluxos de Aprovação → “Abrir no Studio”). O canvas é o de menos — o valor está no resto:

  • Paleta arrastável à esquerda (ou clique para soltar no centro), zoom/pan/minimapa, botão Organizar (auto-layout).
  • Painel de propriedades à direita — onde moram 80% da configuração: responsáveis, regra de decisão, formulário + editor de lente (tabela campo × editável/leitura/oculto/obrigatório com ações em massa), botões de saída ordenáveis, SLA, condição, canal de notificação.
  • Saídas viram alças no próprio nó: cada botão declarado ganha um conector colorido pela sua cor — a regra é desenhada, não digitada. Renomear um botão re-liga as arestas sozinho.
  • No nó Paralelo, cada ligação nova é um ramo com nome automático (ramo_1, ramo_2…) — selecione a aresta para renomear.

Validação em tempo real

As mesmas regras do publish rodam enquanto você desenha — badge vermelho no nó problemático + painel “Problemas” clicável (clicou, seleciona o nó). O que é conferido:

CategoriaExemplos do que é barrado
Estruturasaída declarada sem ligação · ligação sem botão correspondente · junção com 1 entrada · paralelo com 1 ramo · gateway sem as duas saídas
Pessoaspasso sem responsável · perfil que não existe · quórum maior que o nº de responsáveis
Dadoscampo da lente que não existe na tabela · obrigatório que não está editável · coluna da ação automática inexistente · placeholder desconhecido
Grafonó desconectado do Início · caminho que não chega a nenhum Fim · ciclo 100% automático · ligação cruzando a fronteira de um trecho paralelo
AvisosFim dentro de trecho paralelo (“vai cancelar os irmãos”)

Gerar com IA

O botão Gerar com IA (✦, na barra do canvas) desenha o fluxo por você: descreva o processo em linguagem natural — “compras até R$ 500 aprovam sozinhas; acima, o gestor aprova com justificativa obrigatória; acima de R$ 10 mil, pareceres em paralelo do financeiro e da diretoria” — e a IA monta os nós, as ligações, as lentes e os SLAs usando as suas tabelas, perfis e formulários reais (ela não inventa nomes: recebe o catálogo do projeto e é validada pelas mesmas regras do publish, com correção automática).

  • Nada é salvo sozinho: o resultado entra no canvas como rascunho — revise, ajuste e clique em Salvar.
  • Com um fluxo já desenhado, a IA parte dele: “adicione um prazo de 48h com escalada para a diretoria no passo do gestor” funciona (o Studio pede confirmação antes de substituir o desenho).
  • Dica: cite perfis e campos pelos nomes que existem no projeto — a IA recebe a lista exata.
  • O modelo usado vem de Propriedades do projeto → Modelos de IA → Gerador de fluxos (dá pra trocar pontualmente na própria janela).
10

Simulação — rodar antes de publicar

O diferencial Botão Simular no canvas: você digita um registro de exemplo, aperta iniciar e assiste o fluxo rodar — os nós ativos pulsam, os visitados ficam marcados, a trilha vai sendo escrita.
  • Condições avaliam de verdade contra os valores digitados (mesma semântica do motor): digite valor = 12.000 e veja o fluxo desviar para o gestor; valor = 300 cai na auto-aprovação.
  • Condição que depende de subconsulta/sessão — impossível de avaliar no navegador — vira uma pergunta honesta: “o que aconteceria?” Sim/Não. Nunca um chute.
  • Nos passos humanos aparecem os botões reais do passo; com vários responsáveis, você clica as decisões uma a uma e vê a regra fechar (inclusive o veto).
  • Paralelo abre os ramos; a junção espera ou cancela; ações automáticas alteram o registro simulado — condições seguintes enxergam a mudança.

“E se o gestor rejeitar?” deixa de ser aposta: reinicie e clique diferente.

11

Publicar & versionamento

Salvar no Studio grava rascunho; o badge no topo mostra publicado v2 ou rascunho sobre a v2. Publicar valida tudo, compila e congela a versão.

A regra que evita a dívida infernal A instância congela a versão no momento em que nasce e roda até o fim nela — publicar uma v3 não quebra o que está em andamento. Cada versão vira um arquivo definitions/{slug}.v{N}.php no sistema gerado, e a tabela wf_release guarda todas as versões publicadas: regenerar o projeto re-emite todas — nenhuma instância em voo fica órfã.
  • Condições são compiladas para closures Eloquent — zero interpretador em runtime, cadeias de FK de graça.
  • O formulário do passo é resolvido no publish e o controller fica congelado na definição — apagar a página depois não derruba instâncias (a fila degrada com aviso).
  • A definição também carrega o bloco ui (posições + arestas rotuladas) — é dele que o mapa do fluxo desenha o processo no sistema gerado.
12

No sistema gerado — o dia a dia

Enviar

O formulário da tabela-alvo ganha “Enviar para aprovação” (gatilho manual). Com gatilho ao criar/ao editar, o envio é automático após salvar — registro já em aprovação é ignorado com elegância.

A fila (inbox)

Página “Fila de Aprovação”: pendências dos seus perfis + as atribuídas direto a você. Colunas: registro legível (rótulo denormalizado — “Notebooks Dell — 10 un.”, não “#42”), etapa, fluxo, prazo, criada em. Ações:

  • Abrir — passo com formulário → navega para o form em modo tarefa (lente aplicada, botões do passo no rodapé, comentário quando exigido). Passo sem formulário → modal de decisão ali mesmo.
  • Delegar — repassa a pendência para um usuário específico.

O formulário em modo tarefa

Fila → Abrir→ /app/compra-aprov/onEdit?id=42&wf_task=4→ lente aplicada→ botões do passo

No exemplo da compra: descricao e valor travados, centro_custo invisível para o gestor, justificativa editável e obrigatória; o botão Salvar padrão some e entram Aprovar/Rejeitar/Devolver. Decidir salva os campos liberados e registra a decisão numa tacada.

O mapa do fluxo

Botão “Acompanhar aprovação” no formulário abre o processo desenhado — SVG renderizado no servidor a partir da definição congelada: passos visitados marcados, ativos pulsando, status e trilha resumida. É a resposta ao “cadê meu pedido?” sem abrir chamado. Sobrevive até a definição sumir do disco (cai no retrato congelado da instância).

Trilha de auditoria

Tudo é evento imutável em mad_wf_history: started, task_created, decided (com botão e comentário), task_skipped, forked, join_fired, auto_applied, delegated, escalated, reminded, cancelled_by_end, completed — quem, quando, o quê.

13

Arquitetura — três planos

BUILDER · design-time wf_workflow · wf_step · wf_transition wf_release · /api/workflow · Studio DEFINIÇÃO COMPILADA app/Workflows/definitions/{slug}.v{N}.php nós + closures + lente + bloco ui SISTEMA GERADO · runtime WorkflowEngine · mad_wf_instance/task token · history · fila · form · mapa publish geração

O motor (WorkflowEngine, no framework) expõe uma API pequena:

start(slug, registro, solicitante)     // “Enviar para aprovação” — cria instância + token raiz
decide(tarefa, botão, comentário, ator) // valida botão/autorização/lente e avança o token
reassign(tarefa, usuário)               // delegação e escalonamento
slaTick()                               // lembretes + escaladas (agendado, idempotente)
taskContext(tarefa)                     // lente + botões + registro — o que a fila e o form consomem
instanceMap(instância)                  // bloco ui + nós ativos + trilha — o que o mapa desenha

Shape essencial de um passo humano na definição compilada:

'aprovacao_gestor' => [
    'kind'      => 'human',
    'condition' => fn ($q) => $q->where('valor', '>', 500),
    'assignees' => [['mode' => 'field', 'field' => 'gestor_id']],   // o gestor daquela compra
    'decision'  => ['rule' => 'any'],
    'form'      => ['page_id' => 41, 'controller' => 'CompraForm',   // congelado no publish
                    'lens' => ['fields' => ['descricao' => 'read', 'valor' => 'read', 'justificativa' => 'edit', 'centro_custo' => 'hidden'],
                               'required' => ['justificativa']]],
    'outcomes'  => ['aprovar' => 'pareceres', 'rejeitar' => 'fim_rej', 'devolver' => 'corrigir'],
    'sla'       => ['hours' => 48, 'escalate_to' => ['mode' => 'role', 'role' => 'diretoria'], 'remind_hours_before' => 8],
],
14

Bom saber — comportamento e limites

  • Condições avaliam o dado mais recente. A condição roda quando o fluxo entra no nó — se um passo anterior editou o registro pela lente, o gateway seguinte já enxerga a mudança.
  • Perfis por código. A alçada referencia o código do perfil de acesso — renomear o perfil não quebra fluxos publicados. Perfil sem usuários não trava: a pendência fica aguardando e aparece assim que alguém ganhar o perfil.
  • Um registro, uma aprovação por vez. Enviar um registro que já está em aprovação no mesmo fluxo é bloqueado com aviso.
  • Registro excluído no meio do fluxo: ações automáticas e status viram no-op registrado na trilha; decisões que exigem campos obrigatórios avisam que o registro não existe mais.
  • Fim dentro de trecho paralelo cancela os irmãos — é o comportamento de veto. O Studio avisa ao desenhar.
  • E-mail é melhor esforço. Notificação por e-mail depende da configuração de correio do sistema gerado; falha de envio nunca trava o fluxo (o aviso no app sempre acontece).
  • Guardas de segurança do motor: no máximo 100 transições por avanço e 64 ramos vivos por solicitação — um desenho degenerado para com erro claro, nunca roda para sempre.
15

Limitações conhecidas & próximos passos

  • Anexos por decisão — mad-attach-btn já existe no framework; falta plugar na tela de decisão.
  • WhatsApp — exige provedor externo (Evolution/Twilio). Hoje: no app + e-mail.
  • “Gestor do solicitante” — o IAM não tem hierarquia (manager_id); hoje o dinâmico é por campo do registro.
  • Lente sobre tabelas de detalhe — no modo tarefa elas ficam ocultas; expor exigirá lens.sections.
  • Wizard em modo tarefa — o passo aponta para formulários comuns; wizards ficam de fora por ora.
  • Cancelamento administrativo de instância órfã/travada.