Especificação · Fluxo de Aprovação

Fluxo de Aprovação

Um motor só, para requisição, cotação, pedido, contrato, cadastro de fornecedor e alteração orçamentária. A versão anterior tinha configuração sem execução — fluxo, nível e delegação gravados, e nenhuma instância, fila, decisão ou notificação. Esta descreve o motor inteiro, e é escrita antes de existir documento para aprovar, que é a única hora em que ela custa barato.

substitui NEXIO_FluxoAprovacao_*_v1.0 (jun/2026) consome Centro de Custo v2.0 7 agregados de configuração · 4 de execução 30/08/2026

Ponto de partida

Oito decisões

Decisão 1 · Camadas

Duas camadas de regra: base e complementar. A base é a alçada financeira — uma só vence, escolhida por prioridade. As complementares empilham: todas que casam entram na cadeia. Controles de compra são ortogonais — alçada, dono do centro de custo, aprovador de categoria, Jurídico, LGPD, Qualidade — e um motor de regra única força o produto cartesiano dessas dimensões em fluxos configurados à mão.

Decisão 2 · Genérico

O motor não sabe o que é um pedido. Ele conhece um assunto com valor, empresa, requisitante e um conjunto de linhas com nó de centro de custo e nó de categoria. ApprovalProcess é entidade de configuração — mesmo padrão do ItemType — e é o que faz requisição, cotação, contrato e alteração bancária percorrerem o mesmo código.

Decisão 3 · Resolução

Cadeia congelada na submissão; pessoas resolvidas na ativação do passo. O snapshot completo deixa a tarefa apontando para quem saiu da empresa; a resolução tardia total impede mostrar a cadeia ao requisitante no momento em que ele submete. O híbrido entrega as duas coisas — e é para onde Oracle e Coupa convergiram.

Decisão 4 · Escopo

O passo tem escopo: documento, linha ou fatia de rateio. É o que permite avaliar a alçada sobre os R$ 40 mil que couberam à área, e não sobre os R$ 400 mil do pedido inteiro. O Protheus dispara pelo total; Coupa e Ariba tratam rateio como dado contábil sem efeito no fluxo.

Decisão 5 · Paralelo

Paralelo é dentro do nível, não entre níveis. Cada nível tem um modo: qualquer um, todos ou quórum de N. Entre níveis é sempre sequencial. A v1.0 definia o oposto, e nunca leu o campo — trocar a semântica ainda é de graça, e esta é a que o mercado inteiro usa.

Decisão 6 · Silêncio

Nada é aprovado por omissão. SLA vencido notifica ou escalona; nunca aprova. Aprovação automática existe como tipo de nível declarado — "abaixo de R$ 500 com fornecedor homologado" — e jamais como consequência de tempo. Aprovar por decurso de prazo é a funcionalidade que destrói a validade jurídica de toda a trilha.

Decisão 7 · Alçada

A alçada mora na pessoa, dentro do nó. CostCenterAssignment.approvalLimit. O nível do tipo "sobe até quem tenha alçada" caminha a árvore de centro de custo até encontrar quem cubra o valor. Trezentos centros de custo passam a ser trezentas linhas de vínculo, não trezentos fluxos — e é o modelo que o cliente vindo do Protheus já tem na cabeça.

Decisão 8 · Trilha

Toda decisão é evento, e a instância é reconstruível a partir deles. ApprovalEvent é append-only, com autor, papel pelo qual agiu, delegação em vigor e o passo alcançado. O estado do agregado é projeção, não fonte. Sem isso, "por que este pedido foi aprovado" só tem resposta na cabeça de quem estava lá.

Fundamentos

Seis princípios

1. Configuração e execução são agregados diferentes

Editar uma política não pode mudar um documento em andamento. A instância guarda o id e a versão de cada política que a formou, e a versão é imutável: alterar uma política publica uma versão nova e aposenta a anterior, que continua respondendo pelas instâncias vivas. É a regra RN-F08 da spec de junho, elevada de detalhe a invariante.

2. Quem aprova nunca é quem pede

O requisitante é excluído de toda tarefa da própria instância — inclusive quando é ele o responsável pelo centro de custo. Nesse caso o motor sobe um nível na árvore; se a subida esgotar, cai no aprovador de reserva do processo. Recusar silenciosamente ou deixar o próprio aprovar são os dois erros que auditoria encontra primeiro.

3. Ambiguidade é erro de configuração, nunca desempate silencioso

Duas políticas base com a mesma prioridade e critérios que se sobrepõem são recusadas no momento de salvar, com 409. A garantia é uma restrição EXCLUDE com btree_gist no Postgres sobre tenant, processo, prioridade, faixa de valor, nó de centro de custo e nó de categoria — não uma varredura em memória, que perde a corrida de dois POST simultâneos e é exatamente o defeito da implementação anterior.

4. Um passo sem aprovador possível é recusa explícita

Não existe passo pulado por falta de gente. Se a resolução devolve vazio depois do rollup, da delegação e do grupo, o motor tenta o aprovador de reserva do processo; se também não houver, a submissão é recusada com 422 nomeando o passo. Pular é como um pedido de R$ 2 milhões passa sem que ninguém perceba.

5. A cadeia é mostrada antes de ser percorrida

O requisitante vê a cadeia inteira ao submeter, e qualquer pessoa com permissão pode simular sem criar documento. Nenhum ERP brasileiro pesquisado tem simulador; no Oracle ele existe atrás de privilégio especial. Aqui a lógica de seleção já é a mesma consulta — expor é quase de graça, e é o que transforma configuração de aprovação de adivinhação em engenharia.

6. O motor consome contratos, não caminha em árvores

Centro de custo publica path, responsáveis efetivos, alçada acumulada e empresa. Catálogo publica path de categoria. Orçamento publica saldo. O motor combina — e por isso pode ser testado sem nenhum dos três.

Modelo

Mapa de entidades

Configuração — o que o cliente parametriza

EntidadeCardinalidadeO que é
ApprovalProcessconfiguração · por tenantQual documento é aprovável. Define o valor avaliado, os critérios disponíveis, as ações permitidas e o aprovador de reserva. Tipos-semente: REQUISICAO, COTACAO, PEDIDO, CONTRATO, FORNECEDOR, ALTERACAO_BANCARIA, ALTERACAO_ORCAMENTARIA.
ApprovalPolicyN por processo · versionadaA regra. kind = Base ou Complementar, prioridade, critérios, vigência e níveis. Versão imutável.
ApprovalCriteriavalue object da políticaFaixa de valor, nó de centro de custo, nó de categoria, tipo de item, fornecedor, empresa, destinação, flags do item, estado do orçamento. Critério ausente casa tudo.
ApprovalLevel1..N por políticaOrdem, tipo de aprovador, alvo, modo dentro do nível, SLA próprio, valor de ativação e rótulo exibido.
ApprovalGroupN por tenantPool nomeado de usuários — "Comitê de Investimentos", "Jurídico". Referenciado por nível; o modo do nível decide se basta um.
CostCenterAssignmentdo Centro de CustoOnde a alçada da pessoa mora (approvalLimit). O motor lê; não escreve.
ApprovalDelegationN por usuárioAusência temporária. Herdada da v1.0, que já estava completa, mais escopo opcional por processo e teto de valor.
ApprovalSettings1 por tenant × processoOs parâmetros globais: dedupe, autoaprovação, materialidade do rateio, tolerância de reavaliação, SLA padrão, comportamento de escalonamento.

Execução — o que o motor escreve

EntidadeCardinalidadeO que é
ApprovalRequestaggregate root · 1 por documento vivoA instância. subjectType + subjectId, empresa, requisitante, valor avaliado, moeda, estado, e o snapshot das políticas que a formaram com suas versões.
ApprovalStep1..N por instânciaUm nível resolvido. Ordem, origem (qual política e nível), escopo, modo, SLA, estado.
ApprovalAssignment1..N por passoA tarefa de uma pessoa. Origem da atribuição, estado, decisão, comentário, momento. É a entidade que a spec de junho não tinha — e sem ela não existe fila endereçável, aprovação por papel, delegação registrada nem paralelo dentro do nível.
ApprovalEventappend-onlyToda transição, com autor, ação, alvo e metadados. Fonte da verdade da trilha.
ApprovalTokenopcional · fase 2Link assinado para aprovar por e-mail sem sessão. De uso único, com expiração, vinculado a um ApprovalAssignment.

Os três níveis da execução não são zelo arquitetural. Instância sem passo não sabe onde está; passo sem tarefa não sabe de quem está esperando. Colapsar tarefa em passo — que é o desenho da spec de junho — obriga a resolver "quem pode agir" em toda leitura de fila, transforma a consulta do aprovador numa varredura, e não deixa onde registrar que Ana agiu como substituta de Bruno na delegação nº 12.

Mecânica

Da submissão à decisão

documento alterado acima da tolerância · reavalia ApprovalRequest submissão PolicyMatcher base + complementares ApprovalStep[] cadeia congelada ApproverResolver na ativação do passo ApprovalAssignment a fila de cada pessoa ApprovalEvent decisão registrada valor · empresa · requisitante path do CC · path da categoria saldo de orçamento critérios effectiveOwners · rollup ApprovalGroup ApprovalDelegation vigente approvalLimit do vínculo quem Aprovado · Rejeitado Devolvido ao requisitante cada um é um evento próximo passo
serviço de domínio entidade persistida entrada consumida de outro domínio resultado
O casador roda uma vez por submissão e uma vez por reavaliação; o resolvedor roda uma vez por passo ativado. Essa separação é a decisão 3 desenhada: o que a política decidiu fica congelado, e só a pergunta "quem, agora" é refeita.

Configuração

Processos aprováveis

ApprovalProcess é o que torna o motor genérico. Cada processo declara o que significa "valor" naquele documento, quais critérios fazem sentido e o que acontece quando a cadeia termina.

Processos-semente
ProcessoValor avaliadoCritérios que fazem sentidoEfeito da aprovação
REQUISICAOTotal estimado, por fatia de rateiovalor, centro de custo, categoria, tipo de item, destinação, orçamentoLibera para cotação ou para pedido
COTACAOValor da proposta escolhidavalor, categoria, fornecedor, desvio do menor preçoLibera a emissão do pedido
PEDIDOTotal do pedido, por fatiavalor, centro de custo, categoria, fornecedor, empresa, orçamentoAutoriza o envio ao fornecedor
CONTRATOValor total comprometidovalor, categoria, fornecedor, prazo, cláusula de exclusividadeColoca o contrato em vigência
FORNECEDORcategoria de homologação, faixa de risco, sanção públicaMuda o estado para homologado
ALTERACAO_BANCARIAfornecedor, valor médio históricoAplica a proposta ao registro vivo
ALTERACAO_ORCAMENTARIADelta da verbavalor, centro de custo, conta contábilAplica o remanejamento

Dois desses processos não têm valor, e é por isso que eles precisam existir na lista. Homologação de fornecedor e alteração de dado bancário são aprovações sem dinheiro — e a alteração bancária é o controle antifraude mais importante de um sistema de compras, porque é o vetor de fraude mais explorado no Brasil. Um motor amarrado a "faixa de valor" não consegue aprová-las, e o produto termina com dois motores.

Configuração

Política e critérios

Campos da política
CampoTipoRegra
processIdGuidA qual processo esta regra se aplica. Obrigatório.
kindenumBase ou Complementar. Decide se a política concorre ou empilha. Imutável depois de publicada.
priorityintSó tem efeito em Base: menor número vence. Em Complementar, ordena a posição na cadeia.
isDefaultboolExatamente uma política Base por processo é a de reserva, com critérios vazios. É a RN-CF03 da spec de junho, que o agregado nunca teve.
criteriavalue objectVer abaixo. Critério ausente casa tudo.
levels1..NOrdenados. Uma política sem nível é recusada na publicação.
versionintImutável. Editar publica versão nova e aposenta a anterior, que segue respondendo pelas instâncias vivas.
validFrom / validTodate / date?Vigência da política. Fora dela, a política não é candidata — e o histórico continua legível.
fallbackApproverIdGuid?Usado quando um nível resolve vazio. Se nulo, herda o do processo.

Critérios disponíveis

CritérioOperadorFonte
Faixa de valorintervalo semiaberto [min, max)Valor avaliado do processo, na moeda do tenant
Centro de custonó, valendo para a subárvorePrefixo de path. Sub-áreas criadas depois passam a ser cobertas sem tocar na regra
Categorianó, valendo para a subárvorePrefixo de path do CategoryNode, pela mesma mecânica
Tipo de itemem listaItemType das linhas
DestinaçãoigualdadepredominantUse — CAPEX ou OPEX, sem depender do centro de custo
Empresaem listalegalEntityId do documento
Fornecedorem lista · ou estadoFornecedor da linha, ou o fato de ele ser Prospect, sancionado ou com documento vencido
Flag do itempresençaRegulado, com dado pessoal, crítico — as flags do catálogo, nunca nós inventados na taxonomia
OrçamentoestadoDentroDaVerba, AcimaDoAlerta, Estourado
Desvio do menor preçopercentualSó no processo de cotação

Base concorre; complementar empilha

Uma requisição de R$ 80 mil de software com dado pessoal para o centro de custo /TI/INFRA/ resolve uma política base — a faixa de R$ 50 mil a R$ 100 mil — e duas complementares — "software com dado pessoal exige o DPO" e "categoria TI exige o arquiteto". A cadeia final é a união ordenada e deduplicada das três. Com motor de regra única, essa mesma combinação exigiria uma política escrita à mão para cada cruzamento de faixa × categoria × flag.

Especificidade não desempata — de propósito

Entre duas políticas base que casam, vence a de menor prioridade numérica, e ponto. Desempate por "regra mais específica" parece elegante e produz configurações que ninguém consegue prever: qual é mais específica, a que amarra centro de custo ou a que amarra faixa de valor? A prioridade explícita é feia e é auditável.

Sobreposição entre bases é recusada ao salvar

Duas políticas base com a mesma prioridade e critérios que se cruzam nunca coexistem. A garantia vive no banco, com EXCLUDE e btree_gist sobre (tenant =, processo =, prioridade =, faixa de valor &&, nó de CC =, nó de categoria =) filtrado por política ativa. Isso move a invariante para fora da aplicação e elimina a varredura O(n) que a implementação anterior fazia em memória, sem lock.

A cobertura por subárvore vale para os descendentes futuros

A política guarda o nó, nunca a lista expandida de folhas. Uma sub-área criada no mês seguinte já nasce coberta. O override no descendente existe: uma política amarrada em /TI/INFRA/ com prioridade menor vence a de /TI/ para tudo que estiver abaixo de infraestrutura.

Configuração

Níveis e aprovadores

Campos do nível
CampoTipoRegra
orderintSequencial dentro da política. Entre níveis é sempre sequencial.
approverTypeenumVer a tabela seguinte. Determina a estratégia de resolução.
targetGuid? / string?Usuário, papel, grupo, e-mail externo ou distância de subida, conforme o tipo.
modeenumQualquer · Todos · Quorum(n). É aqui que vive o paralelo.
labelstring(80)?"Aprovação Gerencial". O que a tela mostra; se ausente, o motor deriva do tipo.
maxApprovalHoursint?SLA do nível. Nulo herda o da política, depois o do processo.
activationMinValuedecimal?Abaixo deste valor o nível não entra na cadeia. É como se declara "diretor só entra acima de R$ 100 mil" sem criar outra política.
scopeModeenumDocumento · Fatia. Um nível de alçada de centro de custo é normalmente por fatia; um de Jurídico é sempre do documento.

Tipos de aprovador

TipoResolve paraFase
SpecificUserUm usuário fixo. Simples e frágil: é o tipo que quebra quando a pessoa sai.MVP
RoleTodos os usuários ativos com o papel, no tenant. O modo do nível decide se basta um.MVP
CostCenterOwnerOs effectiveOwners do nó da fatia, com rollup. O tipo mais usado na prática.MVP
CostCenterOwnerUpToAmountSobe a árvore de centro de custo até encontrar quem tenha approvalLimit que cubra o valor da fatia. É a alçada acumulada da decisão 7.MVP
CostCenterOwnerAtDistance(n)O responsável n níveis acima do nó da fatia. É o "gestor do gestor" sem depender de hierarquia de pessoas.MVP
ApprovalGroupOs membros ativos do grupo. Comitês.MVP
CategoryOwnerO responsável declarado no nó de categoria, com rollup. Exige um vínculo equivalente no catálogo.fase 2
RequesterManagerO gestor direto do requisitante, na hierarquia de pessoas do GrydAuth.fase 2
ExternalEmailUm e-mail sem conta, via ApprovalToken. Sócio, conselheiro, cliente final em obra.fase 2
AutoAprova sozinho quando a condição do nível é satisfeita. Sempre declarado, nunca por decurso de prazo.fase 2

Modo dentro do nível, com precisão. Qualquer: a primeira decisão fecha o nível — e as demais tarefas viram Obsoleta, não desaparecem, porque a trilha precisa mostrar quem mais estava na fila. Todos: o nível só fecha quando todos decidem; uma rejeição encerra a instância imediatamente. Quorum(n): fecha em n aprovações, ou na primeira rejeição que torne o quórum inalcançável — e é a semântica que comitê de investimento pede.

Configuração

Alçada

A alçada financeira de uma pessoa mora em CostCenterAssignment.approvalLimit — no vínculo entre ela e o nó. Não há tabela de alçada separada, e isso é decisão: alçada é uma propriedade da responsabilidade, e responsabilidade já tem vigência, papel e histórico.

Como o nível CostCenterOwnerUpToAmount resolve
#PassoResultado
1Owners vigentes do nó da fatiaFiltra quem tem approvalLimit ≥ valor da fatia, ou limite nulo (sem teto próprio).
2Sobrou alguém?Sim: é a resposta, e o nível fecha aqui. Não: sobe ao pai e repete.
3Chegou à raiz sem cobrirUsa os Owners da raiz e registra authorityExceeded no passo — a aprovação acontece, e o evento diz que ninguém na cadeia tinha alçada formal para o valor. Recusar seria pior: travaria a compra por um cadastro incompleto.
4Raiz também vaziaAprovador de reserva do processo. Se não houver, a submissão é recusada com 422 nomeando o passo.

Alçada não soma entre pessoas

Dois responsáveis de R$ 50 mil no mesmo nó cobrem R$ 50 mil cada, não R$ 100 mil juntos. O que acumula é a subida na árvore. Somar entre co-gestores criaria uma autoridade que ninguém concedeu por escrito.

Cada nível de subida é um passo, não um pulo

Se a fatia exige subir dois níveis, a cadeia ganha um passo — o do nó que cobre — e não um passo por nível atravessado. Exigir a assinatura de todos os níveis intermediários é uma configuração legítima, e se faz com CostCenterOwnerAtDistance repetido, explicitamente.

A moeda é a do tenant, e a conversão é congelada

Documento em outra moeda é convertido pela taxa vigente no momento da submissão, e a taxa fica no snapshot da instância. Reavaliar alçada com a cotação de hoje faria um pedido aprovado ontem precisar de outro aprovador amanhã, sem nada ter mudado no pedido.

Configuração

Grupos e delegação

ApprovalGroup

Pool nomeado de usuários, com membros que entram e saem com vigência — mesma disciplina do vínculo de centro de custo. Um grupo referenciado por política ativa não pode ficar vazio: a remoção do último membro é 409, com a lista de políticas que o usam. É o comitê que aprova sem que ninguém precise saber os nomes ao configurar.

ApprovalDelegation

Herdada da v1.0, que já estava completa: delegante, delegado, período, no máximo uma ativa por pessoa, encerramento automático por rotina diária, e registro em auditoria com delegante, substituto e referência à delegação. Ganha dois campos: escopo por processo (posso delegar pedido e não delegar alteração bancária) e teto de valor (delego até R$ 50 mil; acima disso continua comigo).

Delegação redireciona a tarefa; não substitui o aprovador

A ApprovalAssignment continua registrando o titular como aprovador de direito e o delegado como quem agiu, com o id da delegação. É por isso que a tarefa precisa ser entidade: não há onde guardar esse par num campo do passo.

Delegação vigente é lida na ativação do passo, não na submissão

Uma delegação que começa amanhã tem de valer para o passo que ativa amanhã, mesmo que a instância tenha sido criada hoje. É consequência direta da decisão 3.

Cadeia de delegação não encadeia

Se A delega para B e B delega para C, a tarefa de A vai para B — e para. Encadear produz caminhos que ninguém consegue prever e é o vetor clássico de escapar da alçada em três saltos. B pode recusar e devolver, o que gera evento e notifica A.

Execução

Instância, passo e tarefa

Estados
EntidadeEstadosTransição terminal
ApprovalRequestRascunho · EmAprovacao · Aprovada · Rejeitada · Devolvida · Cancelada · ExpiradaAprovada, Rejeitada, Cancelada e Expirada são finais. Devolvida volta ao requisitante e a instância continua viva.
ApprovalStepPendente · Ativo · Aprovado · Rejeitado · Pulado · ObsoletoPulado só por activationMinValue ou por dedupe — nunca por falta de aprovador. Obsoleto é o que a reavaliação produz.
ApprovalAssignmentPendente · Aprovada · Rejeitada · Devolvida · Obsoleta · ReatribuidaObsoleta quando outra tarefa do mesmo nível já fechou o passo em modo Qualquer. A linha permanece: a trilha mostra quem mais estava na fila.
Campos do passo e da tarefa
CampoOndeO que guarda
policyId · policyVersion · levelOrderpassoDe onde este passo veio. Permite explicar a cadeia meses depois, com a política já editada três vezes.
scope · scopeRef · scopeAmountpassoDocumento, Linha ou Fatia, com o id do alvo e o valor sobre o qual a alçada foi avaliada.
mode · quorum · slaDueAtpassoModo do nível, quórum exigido e o vencimento calculado na ativação.
approverUserIdtarefaQuem é o aprovador de direito.
actingUserIdtarefaQuem de fato decidiu. Igual ao anterior, salvo delegação ou reatribuição.
origin · originReftarefaDireta, PorPapel, PorGrupo, PorDelegacao, PorEscalonamento, PorReatribuicao — com o id da delegação, do grupo ou do papel.
decision · comment · decidedAttarefaA decisão, o comentário e o momento. Comentário é obrigatório em rejeição e devolução.

Uma instância viva por documento. Reenviar um documento devolvido reaproveita a mesma ApprovalRequest, com uma nova rodada de passos e os anteriores marcados como Obsoleto. Criar instância nova a cada reenvio parece mais limpo e quebra a pergunta "quantas vezes este pedido rodou e o que mudou entre as rodadas" — que é a métrica que expõe política mal configurada.

Mecânica

Congelar e resolver

MomentoO que é fixadoPor quê
SubmissãoPolíticas aplicáveis e suas versões, valor avaliado, taxa de câmbio, rateio, sequência de passos com tipo, escopo, modo e SLAEditar a política amanhã não pode mudar a cadeia de um documento que já está circulando. É o que torna a trilha defensável.
Ativação do passoOs aprovadores concretos, a delegação vigente, os membros do grupo e o vencimento do SLAUm responsável que mudou entre a submissão e a chegada do passo tem de ser o novo. Congelar pessoas na submissão produz tarefas para quem já saiu.
NuncaQuem já decidiuDecisão tomada é evento. Nenhuma reavaliação, edição de política ou troca de responsável apaga uma assinatura.

Dedupe: a mesma pessoa não assina duas vezes seguidas

Se Ana é responsável pelo centro de custo e membro do comitê, e os dois passos são consecutivos, ela aprova uma vez e o segundo passo é marcado Pulado com o motivo. Configurável por processo — há empresas que exigem a dupla assinatura de propósito, e há auditoria que a proíbe. O que não pode existir é o comportamento implícito.

O requisitante é removido de toda tarefa da própria instância

Antes de tudo. Se a remoção esvaziar o passo, o motor sobe um nível; se esgotar, cai no aprovador de reserva. Se nem isso, a submissão é recusada com 422, e a mensagem diz qual passo ficou sem ninguém — não "erro ao aprovar".

Resolução vazia nunca vira passo pulado

É a diferença entre um sistema que controla e um que parece controlar. Ordem exata: tipo do nível → rollup na árvore → delegação vigente → aprovador de reserva da política → aprovador de reserva do processo → recusa explícita.

Mecânica

Rateio e escopo do passo

Um documento tem N linhas; cada linha tem de 1 a N fatias de rateio, cada fatia com seu centro de custo e seu valor. O motor avalia as regras contra as linhas e fatias e decide sobre o documento inteiro — que é o padrão SAP, onde documentos são "aprovados na íntegra".

#EtapaDetalhe
1Agrega as fatias por centro de custoCinco linhas apontando para /TI/INFRA/ viram uma fatia agregada. Sem isso, o responsável recebe cinco tarefas do mesmo pedido.
2Aplica a materialidadeFatia abaixo de allocationMaterialityPercent e de allocationMaterialityAmount — o que for maior — é absorvida pela maior fatia para efeito de fluxo. Continua contabilizada integralmente.
3Gera passos por escopoNíveis com scopeMode = Fatia geram um passo por fatia material, em paralelo entre si. Níveis de documento geram um passo só.
4Deduplica aprovadoresSe a mesma pessoa responde por duas fatias, ela recebe uma tarefa que cobre as duas, com o valor somado no scopeAmount.
5OrdenaPassos de fatia do mesmo nível são paralelos entre si; os níveis seguem sequenciais. O documento avança quando todos os passos do nível fecham.

Por que isso importa em números. Um pedido de R$ 400 mil rateado 90/10. Pelo valor total, as duas áreas precisam de aprovação de diretoria. Pela fatia, a área com R$ 40 mil resolve no gestor dela. Do lado oposto: sem limiar de materialidade, uma fatia de 0,5% — R$ 2 mil — geraria um aprovador próprio e transformaria toda compra rateada num carrossel de assinaturas. As duas metades da regra existem para evitar erros opostos, e é a combinação que nenhum concorrente pesquisado implementa.

Execução

Ações do aprovador

AçãoEfeitoComentário
AprovarFecha a tarefa. O passo fecha conforme o modo; a instância avança para o próximo nível.opcional
RejeitarEncerra a instância. O documento volta ao requisitante como rejeitado e não pode ser reenviado sem alteração.obrigatório
Devolver para ajusteDevolve ao requisitante sem encerrar. Os passos da rodada viram Obsoleto; o reenvio abre uma rodada nova na mesma instância.obrigatório
Solicitar informaçãoPergunta ao requisitante sem tirar o documento da fila. O SLA pausa enquanto aguarda — senão o aprovador é penalizado por uma resposta que não depende dele.obrigatório
ReatribuirPassa a tarefa a outra pessoa elegível, uma vez, sem alterar o passo. Exige permissão própria e gera evento com origem e destino.obrigatório
Aprovar com ressalvaAprova e registra uma condição a cumprir — "mediante apresentação da ART". Não bloqueia o avanço; fica visível no documento e no recebimento.obrigatório

Devolver não é rejeitar, e essa distinção é o que faz o SLA significar algo

Sem "devolver", todo pedido com um erro de digitação é rejeitado e reenviado como novo — e a métrica de aprovação passa a medir qualidade de digitação em vez de decisão. É a ação mais usada em qualquer sistema que a oferece, e a primeira que falta em quem não a modelou.

Aprovação em lote existe; decisão em lote não

A tela pode aprovar dez tarefas numa ação, e o motor grava dez eventos, um por tarefa, cada um com seu timestamp. Um evento de lote pareceria uma decisão só e destruiria a rastreabilidade individual que a auditoria pede.

Mecânica

Mudança depois de aprovado

Um pedido aprovado por R$ 80 mil que vira R$ 180 mil com uma edição é o buraco mais explorado em sistema de aprovação. A resposta não pode ser "reprova tudo" nem "não reavalia".

MudançaComportamento padrãoParâmetro
Valor sobe além da tolerânciaReavalia. Passos já aprovados que continuam na cadeia nova são preservados; os que deixaram de existir viram Obsoleto; os novos entram como Pendente.revaluationTolerancePercent · Amount
Valor desceNão reavalia. Quem aprovou mais já aprovaria menos.
Muda centro de custo ou rateioReavalia sempre, independentemente de tolerância — mudou quem paga.
Muda categoria ou tipo de itemReavalia sempre — pode acionar controle complementar que não existia.
Muda fornecedorReavalia se houver política com critério de fornecedor; senão, registra evento e segue.
Muda quantidade sem mudar valorRegistra evento e segue.

Preservar aprovação ainda válida é o que separa reavaliação de reinício. Se o gestor do centro de custo já aprovou e continua na cadeia nova com o mesmo escopo e a mesma política, sua assinatura vale — e o evento de reavaliação registra isso explicitamente, com o que mudou. Reiniciar do zero a cada centavo é o que faz o usuário aprender a submeter o pedido pelo valor certo depois de aprovado.

Execução

SLA e escalonamento

Como o prazo é contado

O vencimento é calculado na ativação do passo, em horas úteis conforme o calendário do tenant — feriado nacional e expediente configuráveis. Contar em horas corridas faz todo passo ativado na sexta vencer no domingo, e o escalonamento vira ruído semanal.

O que acontece no vencimento

Por política, em ordem: Notificar (lembrete ao aprovador e ao requisitante), NotificarGestor, Escalonar (cria tarefa para o nível acima na árvore de centro de custo, mantendo a original viva) e Nenhum. Não existe AutoAprovar.

Escalonar não remove ninguém

A tarefa original continua pendente e ainda pode ser decidida. A escalada acrescenta um caminho, não substitui — e as duas fecham o passo, com o evento dizendo qual delas chegou primeiro.

O relógio pausa

Enquanto uma solicitação de informação está aberta, o SLA do passo pausa e retoma na resposta. O tempo pausado fica registrado, para que o indicador separe "aprovador lento" de "requisitante lento".

Gancho declarado

Orçamento e custo

O módulo de controle financeiro será especificado à parte. O que este documento fixa é onde ele toca o fluxo, para que a integração não exija reescrever o motor.

Ponto de contatoDireçãoContrato
Critério de políticao motor lêbudgetStateFor(empresa, nó, conta, período, valor) devolve DentroDaVerba, AcimaDoAlerta ou Estourado. É o que permite a política "estouro de verba exige o controller", em vez de bloquear a compra.
Empenho na aprovaçãoo motor escreveNa transição para Aprovada, o motor emite um evento de domínio com as fatias e os valores. Quem cria o Commitment é o módulo de orçamento — o motor não conhece verba.
Liberação no cancelamentoo motor escreveCancelar ou rejeitar depois de aprovado emite o evento inverso. Empenho que não é liberado é o defeito que faz o orçamento "acabar" em setembro.
Bloqueio no estouroo motor lêbudgetBlockBehavior por tenant: Avisar ou Bloquear. Bloquear recusa a submissão com 422 e nomeia o nó e o período — nunca um erro genérico.
Alçada por fatiacompartilhadoA mesma fatia que a alçada avalia é a que o orçamento consome. Uma decomposição só, calculada uma vez, congelada na linha.

Diferencial

Simulador

POST /approvals/simulate recebe um documento hipotético — valor, empresa, linhas com centro de custo e categoria, requisitante — e devolve a cadeia que ele produziria, sem criar nada. Três usos, e o terceiro é o que ninguém oferece:

Para quem configura

Testar uma política antes de publicar, inclusive numa versão em rascunho. Configuração de aprovação é o lugar do produto onde o erro só aparece quando um pedido trava, semanas depois.

Para quem requisita

A mesma consulta alimenta a prévia mostrada na submissão: "este pedido passará por Ana, depois pelo comitê". Expectativa correta é metade das reclamações de fluxo de aprovação.

Para quem audita

Reexecutar uma instância antiga contra a configuração da época e comparar com o que de fato aconteceu. Como a instância guarda as versões das políticas, a comparação é exata — e é a resposta a "prove que o controle funcionava em março".

Configuração

Parametrizações

O que o cliente ajusta sem código, e em que nível cada coisa vive. Parâmetro ausente herda o nível acima.

Por tenant
ParâmetroTipoPadrãoEfeito
businessCalendarIdGuidBrasil · 9h-18hBase do cálculo de SLA em horas úteis
allocationMaterialityPercentnumeric(5,2)5,00Fatia abaixo disso não gera passo próprio
allocationMaterialityAmountnumeric(19,2)1.000,00Vale o que for maior entre os dois
budgetBlockBehaviorenumAvisarComportamento no estouro de verba
costCenterMaxDepthint?nuloTeto de profundidade da árvore — política, não estrutura
Por processo
ParâmetroTipoPadrãoEfeito
fallbackApproverIdGuidÚltimo recurso quando toda resolução esvazia. Obrigatório para ativar o processo
allowSelfApprovalboolfalseAlterar exige justificativa e fica na trilha do tenant
deduplicateConsecutivebooltrueMesma pessoa em níveis consecutivos assina uma vez
revaluationTolerancePercentnumeric(5,2)0,00Aumento tolerado sem reavaliar a cadeia
revaluationToleranceAmountnumeric(19,2)0,00Vale o que for maior entre os dois
defaultSlaHoursint48SLA herdado por política e nível
escalationBehaviorenumNotificarNenhum · Notificar · NotificarGestor · Escalonar
requireCommentOnApproveboolfalseRejeição e devolução já exigem sempre
allowReassignbooltruePermite passar a tarefa a outro elegível, uma vez
allowBatchApprovalbooltrueAprovar várias tarefas numa ação — sempre um evento por tarefa
emailApprovalboolfalseLiga o ApprovalToken. Fase 2
Por política e por nível
ParâmetroNívelEfeito
priority · isDefault · kindpolíticaComo a política concorre ou empilha
criteriapolíticaDez critérios; ausência casa tudo
validFrom · validTopolíticaVigência da regra
fallbackApproverIdpolíticaSobrepõe o do processo
approverType · targetnívelEstratégia de resolução
mode · quorumnívelQualquer · Todos · Quorum(n)
scopeModenívelDocumento ou Fatia
activationMinValuenívelAbaixo disso o nível não entra
maxApprovalHoursnívelSLA próprio; nulo herda
labelnívelO nome que o aprovador vê

Camada API

Endpoints

Configuração
RotaPermissãoO que faz
GET /approval-processesapproval.process:readProcessos e seus parâmetros
PUT /approval-processes/{id}approval.process:manageParâmetros do processo e aprovador de reserva
GET /approval-policiesapproval.policy:readFiltra por processo, tipo, vigência e nó
POST /approval-policiesapproval.policy:manageCria em rascunho. Sobreposição entre bases é 409
POST /approval-policies/{id}/publishapproval.policy:managePublica versão nova e aposenta a anterior
GET /approval-policies/{id}/validateapproval.policy:readInconsistências: nó sem responsável, grupo vazio, papel sem membro, nível sem alvo
GET /approval-groups · POST · PUTapproval.group:manageComitês e seus membros com vigência
GET /approval-delegations · POSTapproval.delegation:manage · :selfHerdado da v1.0, mais escopo e teto
POST /approvals/simulateapproval.policy:readA cadeia de um documento hipotético, sem criar nada
Execução
RotaPermissãoO que faz
POST /approvalsinternaSubmete um assunto. Chamada pelo módulo dono do documento, nunca pela tela
GET /approvals/{id}approval:readA instância com passos, tarefas e a cadeia projetada até o fim
GET /approvals/inboxapproval:actA fila. Tarefas pendentes do usuário, incluindo as recebidas por delegação, com filtro por processo, valor e vencimento
POST /approvals/{id}/assignments/{aid}/approveapproval:actAprova. Aceita ?withProviso= para ressalva
POST /approvals/{id}/assignments/{aid}/rejectapproval:actRejeita. Comentário obrigatório
POST /approvals/{id}/assignments/{aid}/returnapproval:actDevolve para ajuste. Comentário obrigatório
POST /approvals/{id}/assignments/{aid}/request-infoapproval:actPergunta ao requisitante. Pausa o SLA
POST /approvals/{id}/assignments/{aid}/reassignapproval:reassignPassa a outro elegível, uma vez
POST /approvals/batch-approveapproval:actN tarefas numa chamada, N eventos
POST /approvals/{id}/cancelinternaCancelamento vindo do documento. Libera empenho
POST /approvals/{id}/revaluateinternaDisparado pela alteração do documento. Preserva o que continua válido
GET /approvals/{id}/eventsapproval:readA trilha completa, ordenada

Contrato

Contrato de erros

Mesma convenção do resto do produto: o status vem do sufixo do código, nunca da mensagem.

CódigoHTTPQuando
APPROVAL_POLICY_OVERLAP_CONFLICT409Duas políticas base com a mesma prioridade e critérios sobrepostos. Garantido no banco
APPROVAL_POLICY_IN_USE_CONFLICT409Desativar política com instância viva. A mensagem carrega a contagem
APPROVAL_GROUP_EMPTY_CONFLICT409Remover o último membro de grupo usado por política ativa
APPROVAL_ASSIGNMENT_ALREADY_DECIDED_CONFLICT409Duas decisões simultâneas na mesma tarefa. A segunda perde e é informada
APPROVAL_STEP_NOT_ACTIVE_CONFLICT409Decisão sobre passo que já fechou — tela desatualizada
APPROVAL_NO_APPROVER_UNPROCESSABLE422Um passo resolveu vazio depois de todo o encadeamento. A mensagem nomeia o passo
APPROVAL_SELF_APPROVAL_UNPROCESSABLE422Requisitante tentando decidir a própria instância
APPROVAL_NO_POLICY_UNPROCESSABLE422Nenhuma política base casou e o processo não tem política de reserva
APPROVAL_BUDGET_EXCEEDED_UNPROCESSABLE422Estouro com budgetBlockBehavior = Bloquear. Nomeia nó e período
APPROVAL_DELEGATION_CHAIN_UNPROCESSABLE422Delegar para quem já delegou — cadeia não encadeia
APPROVAL_REASSIGN_TARGET_UNPROCESSABLE422Destino da reatribuição não é elegível para o passo
APPROVAL_POLICY_NO_LEVEL_UNPROCESSABLE422Publicar política sem nível
APPROVAL_PROCESS_NO_FALLBACK_UNPROCESSABLE422Ativar processo sem aprovador de reserva
APPROVAL_COMMENT_REQUIRED400Rejeição, devolução, ressalva, reatribuição ou pedido de informação sem comentário
APPROVAL_NOT_FOUND404Instância, passo ou tarefa inexistente neste tenant

Autorização

Permissões

PermissãoPúblicoCobre
approval.process:read · :manageNexioAdminProcessos e parâmetros globais
approval.policy:readAdmin, ControllerLer políticas, validar e simular
approval.policy:manageNexioAdminCriar, editar e publicar política
approval.group:manageNexioAdminComitês e membros
approval.delegation:manageNexioAdminQualquer delegação do tenant
approval.delegation:selfAprovadorA própria delegação
approval:readRequisitante, Aprovador, AuditoriaInstância, cadeia e trilha dos documentos a que a pessoa tem acesso
approval:actAprovadorDecidir sobre tarefas atribuídas a si. Não é guarda-chuva: a tarefa precisa ser sua
approval:reassignAprovador sênior, AdminPassar tarefa a outro elegível
approval:auditAuditoriaLer qualquer instância do tenant, inclusive de documentos fora do alcance da pessoa

A separação entre approval:act e approval:reassign é deliberada: quem aprova não necessariamente pode escolher quem aprova no lugar dele — que é como uma alçada é contornada sem violar nenhuma permissão.

Rastreabilidade

Regras de negócio

RN-AP-01

Uma política base vence; complementares empilham

A cadeia final é a união ordenada e deduplicada da base com todas as complementares que casaram.

RN-AP-02

Prioridade desempata bases; especificidade não

Menor número vence. Sobreposição com a mesma prioridade é recusada ao salvar, no banco.

RN-AP-03

Todo processo tem política e aprovador de reserva

Exatamente uma política base com critérios vazios e um fallbackApproverId. Sem os dois, o processo não ativa.

RN-AP-04

Critério de árvore guarda o nó e vale por rollup

Centro de custo e categoria, por prefixo de path. Descendentes criados depois já nascem cobertos; override no descendente é uma política de prioridade menor.

RN-AP-05

Política é versionada e a versão é imutável

Editar publica versão nova. Instâncias vivas continuam na versão que as formou.

RN-AP-06

A cadeia é congelada na submissão

Passos, escopos, modos, SLA, valor avaliado, taxa de câmbio e rateio. Nada disso muda sem reavaliação explícita.

RN-AP-07

Os aprovadores são resolvidos na ativação do passo

Responsáveis, membros de grupo e delegação vigente são lidos na hora em que o passo ativa, não na submissão.

RN-AP-08

O requisitante nunca decide a própria instância

Removido de toda tarefa antes de qualquer outra regra. Se o passo esvaziar, sobe um nível; se esgotar, cai no reserva.

RN-AP-09

Passo sem aprovador é recusa, nunca pulo

422 nomeando o passo. Só activationMinValue e dedupe produzem passo pulado.

RN-AP-10

Paralelo é dentro do nível; entre níveis é sequencial

Qualquer, Todos ou Quorum(n). Rejeição encerra a instância em qualquer modo.

RN-AP-11

Nada é aprovado por decurso de prazo

SLA vencido notifica ou escalona. AutoAprovar não existe como comportamento de escalonamento.

RN-AP-12

Escalonar acrescenta caminho, não substitui

A tarefa original continua viva. Ambas fecham o passo; o evento registra qual chegou primeiro.

RN-AP-13

SLA conta em horas úteis e pausa em pedido de informação

Calendário por tenant. O tempo pausado é registrado separadamente.

RN-AP-14

Regras são avaliadas por linha e fatia; a decisão é do documento inteiro

Fatias do mesmo centro de custo são agregadas antes de gerar passo.

RN-AP-15

Alçada é avaliada sobre a fatia, acima do limiar de materialidade

Fatia imaterial é absorvida pela maior para efeito de fluxo e continua contabilizada integralmente.

RN-AP-16

Alçada não soma entre pessoas; acumula subindo a árvore

Esgotada a subida, aprova o topo e o passo registra authorityExceeded.

RN-AP-17

Delegação redireciona a tarefa e não encadeia

Titular e substituto ficam ambos na tarefa, com o id da delegação. Delegação de delegação é 422.

RN-AP-18

Rejeitar encerra; devolver mantém a instância viva

O reenvio abre rodada nova na mesma instância, com os passos anteriores marcados como obsoletos.

RN-AP-19

Comentário é obrigatório em toda ação que não seja aprovar

Rejeitar, devolver, pedir informação, reatribuir e aprovar com ressalva.

RN-AP-20

Aumento acima da tolerância reavalia; redução não

Mudança de centro de custo, rateio, categoria ou tipo de item reavalia sempre, sem tolerância.

RN-AP-21

A reavaliação preserva aprovação ainda válida

Passo aprovado que continua na cadeia nova, com mesmo escopo e mesma política, mantém a assinatura. O evento registra o que mudou.

RN-AP-22

Aprovação em lote gera um evento por tarefa

Nunca um evento de lote.

RN-AP-23

Toda transição é evento, e o estado é projeção

Append-only, com autor, papel pelo qual agiu, delegação em vigor e passo alcançado.

RN-AP-24

Duas decisões simultâneas na mesma tarefa: a segunda é 409

Concorrência otimista na tarefa. A segunda pessoa é informada de quem decidiu e quando, não de um erro genérico.

RN-AP-25

A aprovação final emite evento de empenho; o cancelamento emite o inverso

O motor não conhece verba — quem cria e libera o Commitment é o módulo de orçamento.

RN-AP-26

A cadeia é consultável antes de existir

O simulador roda a mesma seleção, sem criar nada, inclusive contra política em rascunho e contra a configuração de uma data passada.

Limites

Fora de escopo

Fora, com gancho previsto
  • Aprovação por e-mailApprovalToken está modelado e desligado por parâmetro.
  • Aprovador externo sem conta — depende do token acima.
  • Hierarquia de pessoasRequesterManager exige a árvore de subordinação no GrydAuth.
  • Responsável por categoria — exige um vínculo no CategoryNode equivalente ao do centro de custo.
  • Condições compostas — hoje os critérios são conjunção. OU se faz com duas políticas complementares.
Fora, por decisão
  • Editor de fluxo em diagrama. Política com critérios e níveis ordenados cobre o que compras precisa; um motor de BPMN traz desvio, subprocesso e evento temporal — e uma classe de bug que ninguém depura em produção.
  • Aprovação parcial de documento. Aprovar 6 das 10 linhas parece útil e transforma um pedido em dois, quebrando negociação, rateio e recebimento. Se o requisitante quer separar, ele separa antes.
  • Assinatura eletrônica com certificado. Trilha auditável não é assinatura ICP-Brasil. Se o cliente precisar, é integração, não motor.
  • Autoaprovação por decurso de prazo. Em nenhuma configuração, por nenhum parâmetro.

Pendência que fica registrada: o processo REQUISICAO avalia valor estimado, e o PEDIDO avalia o valor negociado, que costuma ser menor. Falta decidir se um pedido cujo valor ficou abaixo do já aprovado na requisição precisa de nova cadeia. A recomendação é não precisar, com um parâmetro por processo para os clientes que exigem a dupla aprovação — mas isso depende de a Requisição existir, e volta como decisão daquela spec.