nucleo

Node n8n para o Núcleo Wondai — atendimento multi-vertical e relay seguro de canal com HMAC v1. Tenant vem do token; credenciais Evolution nunca chegam ao n8n.

Documentation

@wondai/n8n-nodes-nucleo

Geocoding server-side na cotação de frete (v0.12.2)

Para quote_scope=delivery_fee, o node exige somente tipo_entrega=entrega e
endereco_entrega.logradouro + endereco_entrega.numero. Bairro e cidade são opcionais: quando não
vierem do cliente, o Núcleo os resolve por Geocoding antes de validar a cobertura e calcular a rota.
O node continua sem inferir endereço, cidade, cobertura ou taxa.

Contrato Odonto seguro (v0.12)

A v0.12 acompanha o contrato administrativo do ADR-051 sem enfraquecer o isolamento multi-tenant:

  • Paciente -> Buscar identifica somente o contato do canal e nunca enumera pacientes/agendamentos;
  • criar exige contato, nome do paciente, procedimento, profissional e início;
  • consultar, alterar e cancelar exigem telefone oficial + nome do paciente + token do agendamento;
  • os recortes Odonto de contexto são consultados sob demanda;
  • anexos são bytes literais encaminhados somente após handoff, sem OCR/interpretação;
  • lembretes são reivindicados e resolvidos no CRM; n8n/Evolution apenas transportam.

As operações de escrita e de prova do agendamento são nodes normais em ramos determinísticos.
Não as conecte como AI Tools. O workflow deve redigir o token antes da primeira LLM e preencher o
campo protegido por expressão fixa. Respostas de criação que contenham o token também não retornam
à LLM: um formatter determinístico entrega número curto + token uma única vez.

Relay seguro do canal (v0.11)

O recurso Canal WhatsApp → Enviar Texto chama o Núcleo com o mesmo HMAC dinâmico do bootstrap.
O node recebe apenas recipient e text: instância, origin e API key são resolvidos server-side pelo
tenant do token. Credenciais Evolution nunca devem ser copiadas para nodes, expressões ou outputs.

Enviar Imagem e Obter Mídia Recebida usam endpoints allowlisted próprios. A saída aceita
somente URL do bucket público tenant-media pertencente ao tenant do token; a leitura aceita somente
o messageId e devolve áudio/imagem limitado e saneado. URL da Evolution, nome da instância e API key
continuam exclusivamente no servidor.

Node community do n8n para o Núcleo Wondai — a camada de atendimento de IA (WhatsApp → n8n
→ Núcleo). Um único node com as operações que o agente precisa, assinando cada chamada com HMAC
v1
. O tenant (a padaria) vem do token, no servidor — nunca de nada que o n8n envie (a parede,
ADR-013).

Substitui o pacote antigo @wondai/n8n-nodes-crm. Decisões: ADR-015 (este package + resolução
inteligente de catálogo) e ADR-016 (orquestração: router + especialistas; catálogo como tool).

Filosofia: node burro, servidor inteligente

O node só monta a string canônica, assina e chama. Toda inteligência (busca fuzzy, apelidos,
lote, teto de tokens, idempotência, isolamento entre padarias) vive no servidor, atrás da
parede. Isso mantém o segredo fora do workflow, a lógica num lugar só e o token seguro.

Operações

Recurso Operação Endpoint Escopo do token
Cliente Buscar GET /api/v1/agent/cliente cliente:ler
Catálogo Resolver Produtos POST /api/v1/agent/catalogo/resolver catalogo:ler
Catálogo Disponibilidade na Rede POST /api/v1/agent/catalogo/disponibilidade-rede rede:consultar
Pedido Detalhar GET /api/v1/agent/pedido/:ref pedido:ler
Pedido Criar POST /api/v1/agent/pedido pedido:escrever
Pedido Alterar PATCH /api/v1/agent/pedido/:id pedido:escrever
Pedido Cancelar POST /api/v1/agent/pedido/:id/cancelar pedido:escrever
Conversa Preparar POST /api/v1/agent/conversa/preparar contexto:ler
Contexto Consultar por Escopo POST /api/v1/agent/contexto/consultar contexto:ler
Conversa Registrar POST /api/v1/agent/conversa/fechar conversa:escrever
Conversa Anexar ao handoff POST /api/v1/agent/conversa/:id/anexo conversa:escrever
Telemetria Registrar etapa sanitizada POST /api/v1/agent/telemetria/trace telemetria:escrever
Paciente Buscar contato POST /api/v1/agent/paciente paciente:ler
Procedimento Resolver POST /api/v1/agent/procedimento/resolver procedimento:ler
Agenda Consultar POST /api/v1/agent/agenda/consultar agenda:ler
Agendamento Criar POST /api/v1/agent/agendamento agenda:escrever
Agendamento Consultar com prova POST /api/v1/agent/agendamento/consultar agenda:ler
Agendamento Alterar com prova PATCH /api/v1/agent/agendamento/:id agenda:escrever
Agendamento Cancelar com prova POST /api/v1/agent/agendamento/:id/cancelar agenda:escrever
Lembrete Reivindicar lote POST /api/v1/agent/lembretes/reivindicar lembrete:escrever
Lembrete Registrar resultado POST /api/v1/agent/lembretes/:id/resultado lembrete:escrever
Lembrete Processar resposta POST /api/v1/agent/lembretes/:id/resposta agenda:escrever

Resolver Produtos é a operação inteligente: manda várias consultas numa chamada (máx 10),
tolera erro de digitação (banofe→Banoffee), falta de acento (pao frances→Pão Francês) e
apelidos; devolve no máx 3 candidatos por consulta com status (achou/ambiguo/nao_achou).
Produtos configuráveis também devolvem regras_compra. O agente deve coletar as opções
obrigatórias e enviá-las em itens[].configuracao; o Núcleo recusa com HTTP 422 qualquer combo
incompleto, opção inventada, quantidade inválida, prazo impossível ou personalização proibida.

A partir da v0.8.1, vírgula entre dígitos é preservada como decimal nas consultas (1,5kg,
2,5 centos); somente vírgulas de separação continuam dividindo a lista. Isso impede que peso
decimal vire duas buscas e acione indevidamente a resolução de composição/combos.

Exemplo de item configurável:

Para pedidos de festa/orcamento, use Modo Saida = Compacto Orcamento, Incluir Imagens = false
e, quando existir, envie Orcamento Contexto (JSON) com estado pequeno do atendimento
(pessoas, perfil, familias, preferencias). O servidor monta orcamento_sugerido e omite
listas largas quando possivel; o node nao calcula preco nem escolhe produto.

{
  "produto_id": "uuid-do-produto",
  "quantidade": 1,
  "configuracao": {
    "opcoes": [
      {
        "grupo_id": "uuid-do-grupo",
        "opcao_id": "uuid-da-opcao"
      }
    ]
  }
}

O node não interpreta essas regras: ele encaminha o JSON sem alteração. A validação e o snapshot
imutável do contrato aplicado pertencem à API do Núcleo (ADR-035).

A partir da v0.5.6, Pedido Criar falha antes da requisição quando itens está vazio ou quando
alguma linha não traz produto_id/alias e quantidade positiva. É uma proteção de integração:
o Núcleo continua sendo a autoridade final das regras, mas o workflow não envia pedido vazio por
erro de tool schema.

A partir da v0.6.4, Pedido Criar e Pedido Alterar aceitam Cobranças Comerciais (JSON).
Use para adicionais pagos vindos de Contexto -> commercial_rules, por exemplo
[{"tipo":"paid_addon","nome":"Confetes","valor":35,"origem":"commercial_rules"}].
Essas linhas entram no valor a cobrar, mas nao viram produto de catalogo nem pagamento.

Disponibilidade na Rede ("tem na outra loja?") é exposta como tool do AI Agent, mas com regra
estrita no prompt: usar SÓ quando o cliente pedir explicitamente outra unidade. Passe o produto_id
já resolvido (ou uma consulta curta). A loja que pergunta vem do vínculo do token (a IA não
escolhe a unidade). Devolve no máximo 5 unidades participantes com estado, "atualizado há",
telefone/endereço (allowlist) e distância opcional. Disponibilidade NÃO é garantia: vencida vira
status: "unknown" (confirmation_required: true) — a IA nunca promete, só informa o que a loja
declarou e oferece o contato para o cliente confirmar. Este endpoint não entra no contexto fixo do
gate; é chamado sob demanda. Tenant/unidade vêm do token — nunca do prompt.

A partir da v0.6.5, Pedido Detalhar aceita Telefone do Cliente opcional. Quando preenchido, o
Nucleo so devolve o pedido se o telefone do cliente do pedido bater com esse valor. Use este campo no
WhatsApp para perguntas como "meu pedido 61", evitando que o agente consulte pedido de outro cliente
por numero curto.

Contexto -> Consultar por Escopo deve ser usado como AI Tool dentro do agente, sob demanda.
Passe escopos para buscar apenas o necessario:

  • hours exige data (YYYY-MM-DD) e devolve horario/status da data, sem despejar semana inteira.
  • identity, delivery, payment e commercial_rules devolvem somente o recorte pedido.
  • menus e promotions continuam opcionais e so entram quando a pergunta pedir cardapio/promocao.
  • Odonto usa commercial, scheduling_rules, safety_handoff, conduct, reminders e
    handoff_operation; o token do agente impede usar esses recortes em outro tenant/vertical.

Chamadas antigas com apenas data seguem funcionando como escopos=["hours"], mas o workflow novo nao
deve injetar horario/endereco/entrega/pagamento/regras comerciais em todo prompt.

Gate da IA — Preparar como PRIMEIRO passo (ADR-021, Plano 004)

Conversa → Preparar é o gate determinístico da IA. Use-o como node normal no primeiro
passo do workflow, antes de qualquer nó de LLM/memória/router — nunca como ferramenta do AI
Agent (senão a LLM decidiria se atende, o que anula o gate e gasta tokens).

A resposta vem sempre em HTTP 200 e o node a entrega intacta (não vira erro nem retry):

  • { "allowed": false, "state": "disabled", "reason": "tenant_disabled" | "unit_disabled" | "configuration_error" | "unavailable" }
    → PARE o fluxo sem responder ao cliente (a empresa/unidade desligou a IA; falha de consulta também para).
  • { "allowed": true, "state": "enabled", "runtime_version": N, "session_id": "...", "primeiro_contato": true, "contexto": { ... } }
    → siga para memória/router/LLM. O contexto inicial e compacto; detalhes de horario,
    endereco, entrega, pagamento, regras comerciais, cardapio e promocoes devem vir da tool Contexto sob demanda.

O Núcleo é a fonte da verdade do liga/desliga; o estado active do workflow no n8n não é usado
como controle por padaria. Quem desliga é o dono/gerente em /configuracoes (ou o super-admin).

Workflow-base (reproduza assim; não há export real nesta entrega)

Trigger Evolution (WhatsApp)
  → Normaliza só o identificador técnico (remoteJid → conversation_key/telefone)
  → Núcleo: Conversa → Preparar          (NODE NORMAL — o gate)
  → IF  {{ $json.allowed === true }}
       ├─ true  → memória / router / especialistas / LLM → (Pedido/Catálogo/Conversa) → Registrar
       └─ false → encerrar SEM resposta (No-Op / Stop)

Regras do artefato de workflow:

  • Nenhum nó Gemini/AI Agent/memory/subworkflow com LLM pode vir antes do Preparar.
  • As ferramentas de escrita (Pedido Criar/Alterar/Cancelar) revalidam o runtime no servidor
    (403 se a IA foi desligada no meio); Registrar continua permitido (fecha sessão já iniciada).
  • O node permanece burro: só assina e chama; toda decisão é do Núcleo.

Criar é idempotente: deixe Idempotency Key vazio (gera uma) ou repita a mesma chave num retry
— o Núcleo nunca duplica o pedido.

No Pedido Criar, Nome do Cliente e Endereço de Entrega (JSON) são opcionais e existem para
carregar o que a IA já coletou no atendimento. O node continua burro: só envia nome_cliente e
endereco_entrega; quem decide tenant, valida e grava snapshot em crm.entregas é o Núcleo.

Loja e preço por unidade (Plano 005, ADR-018) — sem lógica no node

A unidade do atendimento vem do vínculo do token (unit_id), no servidor — a IA não escolhe a
loja
. Deixe o campo Loja (unit_id) do Pedido Criar vazio quando o token está vinculado a
uma unidade; se preenchido, ele precisa bater com o vínculo (senão o Núcleo recusa com 422).
O servidor devolve sempre o sortimento e o preço EFETIVOS da unidade (override da unidade vence a
base) — o node não tem regra de herança/preço: só assina e chama. Produto indisponível na
unidade é recusado (422) ao criar/alterar; o Resolver Produtos já não lista o que está fora.

Instalação (n8n self-hosted)

  1. Settings → Community Nodes → Install → @wondai/n8n-nodes-nucleo.
    (ou, em dev: npm run build aqui e aponte o n8n para a pasta / npm link.)
  2. Para usar como ferramenta do AI Agent, o n8n precisa permitir nodes community como tools:
    N8N_COMMUNITY_PACKAGES_ALLOW_TOOL_USAGE=true
    
    (variável de ambiente do servidor n8n; sem ela o node funciona como node normal, mas não aparece
    como tool do AI Agent.)

Credencial — "Núcleo Wondai API"

Campo O que é
Base URL Origem do Núcleo, sem barra final (ex: https://app.suapadaria.com.br).
Token ID Id do token (público). Header x-wondai-key.
Signing Secret Segredo de assinatura — exibido uma vez ao emitir o token.

O par Token ID + Signing Secret é emitido no painel /agente do Núcleo (uma credencial por
padaria). O n8n guarda os dois cifrados no cofre — nunca em texto puro no workflow.

Desde a v0.9.0, os campos opcionais Token ID Dinamico e Signing Secret Dinamico aceitam
expressoes do bootstrap multi-tenant. Quando ambos sao preenchidos, vencem a credencial estatica;
se apenas um for informado, o node falha fechado. O segredo nao e incluido no output.

Assinatura (contrato HMAC v1)

Cada requisição leva os headers x-wondai-key, x-wondai-timestamp (unix s, janela ±300s),
x-wondai-nonce (único — reuso = replay → 401) e x-wondai-signature. A assinatura é
HMAC_SHA256(signingSecret, canônica) em hex, onde a canônica é:

v1
<MÉTODO>
<path + query>
<timestamp>
<nonce>
<sha256_hex(corpo)>     # corpo cru; "" no GET

Build (dev)

npm install
npm run build      # tsc → dist/ + copia ícones SVG/PNG

Licença

MIT

Discussion