Files
Gustavo Santos e322cec92b chore: import coordenador (subtree)
git-subtree-dir: coordenador
git-subtree-mainline: facbe2e340
git-subtree-split: ce7af94d55
2026-10-01 14:25:55 -03:00

6.3 KiB

Coordenador GLPI

Automação n8n que analisa os chamados abertos no GLPI todo dia útil, classifica cada um com IA (contexto real do chamado, não só metadados) e envia no Slack os 10 chamados que realmente precisam de ação humana hoje.

O repositório tem duas gerações do workflow:

  • V2 (n8n/, logic/) — versão atual, em produção. Todo este README descreve o V2.
  • V1 (Coordenador GLPI - Chamados Abertos Slack.n8n.json, na raiz) — versão legada, mantida apenas como rollback. Nunca foi importada nem ativada na instância n8n de produção; existe só como referência histórica e plano B.

Estado atual (verificado em 2026-08-25)

Workflow: [DEV] Coordenador GLPI - Chamados Abertos v2 (Shadow)  (id y6JFEnp7Z2IJEUe2)
active: true
SEND_ENABLED: true
ENVIRONMENT: production
FORCE_SEND: false  (execução manual nunca envia de verdade sem essa flag)
Schedule: seg-sex 08:00, timezone America/Sao_Paulo (cron "0 8 * * 1-5")
Testes: 171/171 (node --test)

O nome do workflow no n8n ainda carrega o prefixo histórico [DEV] / (Shadow) — isso é só rótulo visual, não reflete mais o estado real (ativo, SEND_ENABLED=true, ENVIRONMENT=production). Renomear é seguro a qualquer momento, mas não foi feito para não gerar um diff de auditoria sem função.

Se essa seção estiver desatualizada, o estado de verdade é sempre o que o n8n responde (n8n_get_workflow / n8n_manage_datatable), nunca este arquivo.

Arquitetura

GLPI (MySQL, somente leitura)
  -> candidatos (pool configurável, sem corte artificial)
  -> normalização de texto (decodifica HTML/entities do GLPI)
  -> cache de classificação (Data Table, chave = hash do contexto + versão do classificador)
  -> IA (OpenAI) classifica só quem mudou de contexto ou nunca foi analisado
  -> score determinístico + seleção Top 10 com diversidade por grupo
  -> guard de envio (SEND_ENABLED, FORCE_SEND, idempotência por hash da mensagem)
  -> Slack (mensagem real, sem rodapé de atribuição do n8n)
  -> shadow-diff contra a query legada do V1 (auditoria, não bloqueia envio)

Cada etapa grava em uma Data Table do n8n (coordenador_glpi_memoria, coordenador_glpi_envios_digest, coordenador_glpi_shadow_runs) — não há escrita nenhuma no banco do GLPI. Toda query GLPI é somente leitura; isso é testado (tools/build-workflow.test.js varre sql/*.sql e o SQL gerado procurando INSERT/UPDATE/DELETE/ALTER/DROP/CREATE/TRUNCATE).

Por que a IA classifica o chamado, não só pontua

Cada chamado recebe uma classificação semântica (ACTIONABLE_NOW, UNASSIGNED_ACTIONABLE, WAITING_REQUESTER, WAITING_VENDOR, WAITING_APPROVAL, SCHEDULED, DEPENDENCY_BLOCKED, NEEDS_COORDINATION, PROJECT_LONG_TERM, DUPLICATE_OR_OBSOLETE, INSUFFICIENT_CONTEXT) mais um next_action concreto (nunca frases genéricas tipo "revisar chamado" — isso é validado e rejeitado, ver logic/classification.js). O prompt (n8n/nodes/prepare-ai-prompt.node.js) trata cronologia dos apontamentos como obrigatória e distingue "precisa contatar alguém" (acionável agora) de "já contatou e está esperando resposta" (WAITING_*).

Determinismo do Top 10

logic/diversity.js desempata candidatos com score igual por ticket.id (ascendente) — sem isso, ordens de chegada diferentes entre execuções produziam Top10 diferentes para o mesmo dia, o que já causou um envio real duplicado em teste (ver docs/superpowers/notes/2026-08-25-relatorio-correcao-final.md, seção 5). Regressão coberta em logic/diversity.test.js.

Arquivos

logic/*.js              Lógica pura, testável com node:test (sem I/O, sem n8n)
n8n/nodes/*.node.js      Drivers finos que rodam dentro de Code nodes do n8n
                         (cabeçalho "// @requires a.js b.js" declara quais
                         módulos de logic/ precisam ser inlinados)
n8n/workflow.template.json   Fonte de verdade da estrutura do workflow
                         (marcadores __BUILD__:arquivo.js são substituídos
                         pelo conteúdo de logic/ na hora do build)
n8n/deployed/coordenador-glpi-v2.n8n.json   Artefato gerado, importável no n8n
tools/build-workflow.js Inlina logic/ + n8n/nodes/ dentro do template
tools/build-workflow.test.js   Regressões de build (dependência transitiva,
                         alwaysOutputData, columns.mappingMode, etc.)
sql/                     Queries GLPI usadas como referência/validação manual
docs/superpowers/        Specs, planos e relatórios de execução (histórico,
                         não é para reescrever — cada nota é um registro de
                         um momento específico do projeto)

Build

node tools/build-workflow.js
node --test

O build só precisa rodar de novo quando logic/*.js, n8n/nodes/*.node.js ou n8n/workflow.template.json mudarem. O artefato gerado (n8n/deployed/coordenador-glpi-v2.n8n.json) não é a fonte de verdade do ambiente de produção — o workflow ativo no n8n foi promovido diretamente via API (n8n_update_partial_workflow) e hoje diverge do template em 3 valores de configuração de propósito:

campo template (default de deploy limpo) live (produção)
ENVIRONMENT dev production
SEND_ENABLED false true
FORCE_SEND false false

Isso é intencional: o template continua "seguro por padrão" para qualquer reimportação futura (nunca envia sozinho), e a promoção para produção é um ato explícito e auditável via n8n_update_partial_workflow, não algo que um rebuild acidental possa reverter. Se um dia o workflow live for recriado do zero a partir do template, repita a promoção manualmente (ver comando na nota 2026-08-25-relatorio-finalizacao-producao.md).

Rollback

O V1 (Coordenador GLPI - Chamados Abertos Slack.n8n.json) nunca foi importado no n8n de produção — não há nada para "reverter para V1", ele continua disponível como plano B caso seja necessário abandonar o V2. Para desativar o V2 sem tocar em nada mais: SEND_ENABLED=false no node Config - Coordenador GLPI v2 e/ou desativar o workflow.

Credenciais e segredos

Nenhum segredo vive neste repositório. Tudo (Slack bot token, OpenAI API key, credencial MySQL do GLPI) é gerenciado pelo credential store do próprio n8n e referenciado nos nodes só por {id, name}.