135 lines
6.3 KiB
Markdown
135 lines
6.3 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
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}`.
|