- gti-scheduling-mcp: MCP server com ZProAdapter e KlingoAdapter (agendar() completo pros dois) - Workflow n8n 'Agendamento - GChat - Z-PRO': webhook -> AI Agent -> MCP -> Z-PRO, testado com sucesso real - Documentacao: specs, plano, runbook de problemas reais e export do workflow Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
470 lines
21 KiB
Markdown
470 lines
21 KiB
Markdown
# Workflow n8n de Agendamento (GChat/Z-PRO → gti-scheduling-mcp) Implementation Plan
|
|
|
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
|
|
**Goal:** Construir, no n8n (`https://devn8n.gtigrupo.com.br`), o primeiro workflow que recebe mensagens de clientes via webhook do Z-PRO/GChat, conduz a conversa com um AI Agent para capturar os dados do agendamento, e chama a tool `agendar` do `gti-scheduling-mcp` (via `ZProAdapter`) para realizar o agendamento de fato.
|
|
|
|
**Architecture:** Webhook (Z-PRO) → node `Code` de normalização/guarda de `step` → `AI Agent` (OpenAI + memória de sessão por `protocol` + tool MCP `agendar`) → `Respond to Webhook` (texto puro). Construído incrementalmente: cada task adiciona uma camada e é validada isoladamente antes da próxima.
|
|
|
|
**Tech Stack:** n8n (self-hosted, `devn8n.gtigrupo.com.br`), node `n8n-nodes-mcp` (community, transporte stdio), `gti-scheduling-mcp` (já implementado, sem alterações de código nesta etapa), OpenAI Chat Model.
|
|
|
|
## Global Constraints
|
|
|
|
- Nenhuma alteração de código/arquitetura no `gti-scheduling-mcp` é necessária ou permitida nesta etapa — ele já expõe a tool `agendar` exatamente como o workflow precisa consumir.
|
|
- O webhook precisa **sempre responder de imediato**, uma execução por mensagem — nunca segurar a resposta esperando mais mensagens (Z-PRO descarta mensagens se isso acontecer).
|
|
- A resposta ao Z-PRO é **sempre texto puro**, nunca JSON.
|
|
- Nenhuma credencial (token do Z-PRO, API key da OpenAI) é inserida por quem executa este plano de forma automática — todas vêm de Credentials do n8n, criadas manualmente pelo usuário na UI.
|
|
- `sessionId` da memória do agente = `protocol` do payload do Z-PRO (nunca o telefone — o mesmo telefone pode ter vários atendimentos/protocolos).
|
|
- Escopo: só `agendar()` via `ZProAdapter`. Nada de `consultar_horarios`, cancelamento, remarcação ou múltiplas clínicas nesta etapa (ver spec, seção "Fora de escopo").
|
|
|
|
Spec de referência: `docs/superpowers/specs/2026-08-10-n8n-agendamento-workflow-design.md`
|
|
|
|
---
|
|
|
|
## Pré-requisitos (ação manual do usuário — fora do escopo de execução automática)
|
|
|
|
Estes itens **não podem ser feitos pelas tasks abaixo** (exigem acesso à infraestrutura do n8n/credenciais reais) e precisam estar prontos antes da Task 5:
|
|
|
|
1. **Instalar o node comunitário `n8n-nodes-mcp`** no n8n de vocês, seguindo
|
|
`https://docs.n8n.io/integrations/community-nodes/installation/`.
|
|
2. **Definir a variável de ambiente `N8N_COMMUNITY_PACKAGES_ALLOW_TOOL_USAGE=true`**
|
|
no processo do n8n (ex.: no `docker-compose.yml` do serviço n8n) e reiniciar o n8n — sem isso, o node comunitário não pode ser usado como tool dentro do AI Agent.
|
|
3. **Criar uma Credential do tipo OpenAI** no n8n (Settings → Credentials → OpenAI API), com uma API key válida.
|
|
4. **Criar uma Credential do tipo "MCP Client (Command Line) API"** (fornecida pelo node `n8n-nodes-mcp` após instalado), com:
|
|
- **Command**: `node`
|
|
- **Arguments**: caminho absoluto para `dist/index.js` do `gti-scheduling-mcp` no servidor onde o n8n roda (ex.: `/opt/gti-scheduling-mcp/dist/index.js`) — depende de onde o projeto for implantado, que é uma decisão de infraestrutura fora do escopo deste plano.
|
|
- **Environment Variables** (uma por linha, formato `NOME=valor`):
|
|
```
|
|
SCHEDULING_PROVIDER=zpro
|
|
ZPRO_BASE_URL=<url real da clínica>
|
|
ZPRO_API_TOKEN=<token real da clínica>
|
|
ZPRO_API_ID=<ApiID real da clínica — o GUID, não o número do registro>
|
|
```
|
|
|
|
Sem os 4 itens acima, a Task 5 (conectar a tool MCP ao Agent) não pode ser validada de ponta a ponta — as Tasks 1 a 4 não dependem deles.
|
|
|
|
---
|
|
|
|
### Task 1: Build do `gti-scheduling-mcp` e localização do `dist/index.js`
|
|
|
|
**Files:**
|
|
- Nenhum arquivo novo — apenas build do projeto existente.
|
|
|
|
**Interfaces:**
|
|
- Produces: caminho absoluto de `dist/index.js`, usado nas Tasks 5 e no pré-requisito 4 acima.
|
|
|
|
- [ ] **Step 1: Rodar o build**
|
|
|
|
```bash
|
|
cd "D:\PROJETOS\KLINGO-CLINICAL-SYSLIFE-GCHAT-AGENDAMENTO\gti-scheduling-mcp"
|
|
npm run build
|
|
```
|
|
|
|
Esperado: `tsc -p tsconfig.json` sem erros, e a pasta `dist/` criada/atualizada.
|
|
|
|
- [ ] **Step 2: Confirmar que `dist/index.js` existe e roda**
|
|
|
|
```bash
|
|
node "D:\PROJETOS\KLINGO-CLINICAL-SYSLIFE-GCHAT-AGENDAMENTO\gti-scheduling-mcp\dist\index.js" --help 2>&1 | head -5
|
|
```
|
|
|
|
Esperado: o processo inicia (mesmo que não reconheça `--help`, não deve dar erro de módulo não encontrado). Se o servidor esperar variáveis de ambiente obrigatórias e falhar por causa disso, isso confirma que o build está correto (o processo rodou, só não tinha config — comportamento esperado sem env vars).
|
|
|
|
Anote o caminho absoluto de `dist/index.js` — será necessário nos pré-requisitos e na Task 5.
|
|
|
|
---
|
|
|
|
### Task 2: Esqueleto base do webhook (Webhook → Respond to Webhook)
|
|
|
|
**Files:** Nenhum arquivo local — cria o workflow no n8n via `n8n_create_workflow`.
|
|
|
|
**Interfaces:**
|
|
- Produces: `workflowId` (retornado pela chamada) — usado em todas as tasks seguintes.
|
|
|
|
- [ ] **Step 1: Criar o workflow com dois nodes ligados diretamente**
|
|
|
|
Chame a tool `n8n_create_workflow` com:
|
|
|
|
```json
|
|
{
|
|
"name": "Agendamento - GChat - Z-PRO (clínica exemplo)",
|
|
"nodes": [
|
|
{
|
|
"id": "webhook-zpro",
|
|
"name": "Webhook Z-PRO",
|
|
"type": "n8n-nodes-base.webhook",
|
|
"typeVersion": 2.1,
|
|
"position": [0, 0],
|
|
"parameters": {
|
|
"httpMethod": "POST",
|
|
"path": "agendamento-zpro-clinica-exemplo",
|
|
"responseMode": "responseNode"
|
|
}
|
|
},
|
|
{
|
|
"id": "respond-stub",
|
|
"name": "Respond to Webhook",
|
|
"type": "n8n-nodes-base.respondToWebhook",
|
|
"typeVersion": 1.5,
|
|
"position": [300, 0],
|
|
"parameters": {
|
|
"respondWith": "text",
|
|
"responseBody": "teste ok"
|
|
}
|
|
}
|
|
],
|
|
"connections": {
|
|
"Webhook Z-PRO": {
|
|
"main": [[{ "node": "Respond to Webhook", "type": "main", "index": 0 }]]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Guarde o `id` do workflow retornado — chamado de `<workflowId>` no restante deste plano.
|
|
|
|
- [ ] **Step 2: Validar o workflow**
|
|
|
|
Chame `n8n_validate_workflow` com `{"id": "<workflowId>"}`. Esperado: sem erros (pode haver avisos sobre o workflow estar inativo — normal, só ativamos na Task 6).
|
|
|
|
- [ ] **Step 3: Ativar temporariamente e testar a resposta em texto puro**
|
|
|
|
Ative o workflow (`n8n_update_partial_workflow` com operação `{"type": "activateWorkflow"}`), pegue a URL de produção do webhook (visível no node Webhook Z-PRO / na resposta da criação), e chame:
|
|
|
|
```bash
|
|
curl -i -X POST "https://devn8n.gtigrupo.com.br/webhook/agendamento-zpro-clinica-exemplo" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"step":"process","entrada":"oi","number":"5511999999999","contactName":"Teste","protocol":"protocolo-teste-1"}'
|
|
```
|
|
|
|
Esperado: HTTP 200, corpo **exatamente** `teste ok` (texto puro, sem aspas de JSON ao redor).
|
|
|
|
- [ ] **Step 4: Desativar o workflow de novo**
|
|
|
|
`n8n_update_partial_workflow` com `{"type": "deactivateWorkflow"}` — mantemos desativado até a Task 6, para não responder de verdade a mensagens reais enquanto ainda está incompleto.
|
|
|
|
---
|
|
|
|
### Task 3: Node de normalização + guarda de `step`
|
|
|
|
**Files:** Nenhum arquivo local — edita o workflow `<workflowId>` via `n8n_update_partial_workflow`.
|
|
|
|
**Interfaces:**
|
|
- Consumes: `<workflowId>` da Task 2.
|
|
- Produces: campos `sessionId`, `mensagem`, `nomeContato`, `telefone`, `provider`, `clinicId`, `earlyReply` — consumidos pela Task 4 (AI Agent) e pelo `If` desta task.
|
|
|
|
- [ ] **Step 1: Adicionar o node `Code` de normalização**
|
|
|
|
```json
|
|
{
|
|
"type": "addNode",
|
|
"node": {
|
|
"id": "normalizar-entrada",
|
|
"name": "Normalizar entrada",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [150, -120],
|
|
"parameters": {
|
|
"mode": "runOnceForEachItem",
|
|
"language": "javaScript",
|
|
"jsCode": "const body = $input.item.json.body || {};\n\n// Configuração fixa desta cópia do workflow. Ajustar por clínica ao\n// duplicar este workflow para uma nova instância.\nconst clinicConfig = {\n provider: \"zpro\",\n clinicId: \"clinica-exemplo\",\n};\n\nif (body.step !== \"process\") {\n return {\n json: {\n earlyReply: true,\n sessionId: body.protocol || \"\",\n mensagem: \"\",\n nomeContato: \"\",\n telefone: \"\",\n provider: clinicConfig.provider,\n clinicId: clinicConfig.clinicId,\n },\n };\n}\n\nreturn {\n json: {\n earlyReply: false,\n sessionId: body.protocol || \"\",\n mensagem: String(body.entrada || \"\").trim(),\n nomeContato: body.contactName || \"\",\n telefone: body.number || \"\",\n provider: clinicConfig.provider,\n clinicId: clinicConfig.clinicId,\n },\n};"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 2: Adicionar o node `If` que decide entre resposta antecipada e fluxo normal**
|
|
|
|
```json
|
|
{
|
|
"type": "addNode",
|
|
"node": {
|
|
"id": "if-early-reply",
|
|
"name": "É step=process?",
|
|
"type": "n8n-nodes-base.if",
|
|
"typeVersion": 2.3,
|
|
"position": [400, -120],
|
|
"parameters": {
|
|
"conditions": {
|
|
"options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict" },
|
|
"combinator": "and",
|
|
"conditions": [
|
|
{
|
|
"id": "cond-early-reply",
|
|
"leftValue": "={{ $json.earlyReply }}",
|
|
"rightValue": true,
|
|
"operator": { "type": "boolean", "operation": "true", "singleValue": true }
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 3: Rewire — Webhook → Normalizar entrada → If**
|
|
|
|
```json
|
|
[
|
|
{ "type": "removeConnection", "source": "Webhook Z-PRO", "target": "Respond to Webhook" },
|
|
{ "type": "addConnection", "source": "Webhook Z-PRO", "target": "Normalizar entrada" },
|
|
{ "type": "addConnection", "source": "Normalizar entrada", "target": "É step=process?" }
|
|
]
|
|
```
|
|
|
|
- [ ] **Step 4: Ligar a saída TRUE do If (índice 0) direto ao Respond to Webhook existente, com texto vazio**
|
|
|
|
```json
|
|
[
|
|
{ "type": "patchNodeField", "nodeName": "Respond to Webhook", "fieldPath": "parameters.responseBody", "patches": [{ "find": "teste ok", "replace": "={{ $json.mensagem || '' }}" }] },
|
|
{ "type": "addConnection", "source": "É step=process?", "sourceOutput": 0, "target": "Respond to Webhook" }
|
|
]
|
|
```
|
|
|
|
A saída FALSE (índice 1) do `If` fica sem conexão por enquanto — será ligada ao AI Agent na Task 4.
|
|
|
|
- [ ] **Step 5: Validar**
|
|
|
|
`n8n_validate_workflow` com `{"id": "<workflowId>"}`. Esperado: sem erros. Pode haver aviso de node com saída não conectada (`É step=process?` saída FALSE) — esperado nesta task, resolvido na Task 4.
|
|
|
|
- [ ] **Step 6: Testar os dois caminhos**
|
|
|
|
Ative o workflow, chame o webhook duas vezes:
|
|
|
|
```bash
|
|
curl -s -X POST "https://devn8n.gtigrupo.com.br/webhook/agendamento-zpro-clinica-exemplo" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"step":"outro","entrada":"x","number":"1","contactName":"y","protocol":"p1"}'
|
|
```
|
|
|
|
Esperado: corpo vazio (early reply, `step` diferente de `process`).
|
|
|
|
```bash
|
|
curl -s -X POST "https://devn8n.gtigrupo.com.br/webhook/agendamento-zpro-clinica-exemplo" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"step":"process","entrada":"Olá, quero marcar uma consulta","number":"5511999999999","contactName":"Fulano","protocol":"p2"}'
|
|
```
|
|
|
|
Esperado: corpo = `Olá, quero marcar uma consulta` (o `Respond to Webhook` está ecoando `mensagem` só para confirmar que os campos normalizados chegaram certos — será substituído pela resposta do Agent na Task 4).
|
|
|
|
Desative o workflow ao final (`deactivateWorkflow`), como na Task 2.
|
|
|
|
---
|
|
|
|
### Task 4: AI Agent com memória de sessão (sem tool ainda)
|
|
|
|
**Files:** Nenhum arquivo local — edita `<workflowId>`.
|
|
|
|
**Interfaces:**
|
|
- Consumes: `earlyReply` (falso), `sessionId`, `mensagem`, `nomeContato`, `telefone` da Task 3.
|
|
- Produces: texto de resposta do Agent, consumido pelo `Respond to Webhook`.
|
|
|
|
- [ ] **Step 1: Adicionar o node OpenAI Chat Model**
|
|
|
|
```json
|
|
{
|
|
"type": "addNode",
|
|
"node": {
|
|
"id": "openai-chat-model",
|
|
"name": "OpenAI Chat Model",
|
|
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
|
|
"typeVersion": 1,
|
|
"position": [650, 100],
|
|
"parameters": {
|
|
"model": { "value": "gpt-4o-mini" },
|
|
"options": {}
|
|
},
|
|
"credentials": {
|
|
"openAiApi": { "id": "<ID da Credential OpenAI criada no pré-requisito 3>", "name": "OpenAI account" }
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Substitua `<ID da Credential OpenAI criada no pré-requisito 3>` pelo ID real da credencial (visível na UI do n8n, em Settings → Credentials, ou via `n8n_manage_credentials` se disponível). Se preferir, este campo pode ser deixado para o usuário selecionar manualmente na UI do n8n após a criação do node — não bloqueia os steps seguintes.
|
|
|
|
- [ ] **Step 2: Adicionar o node Simple Memory**
|
|
|
|
```json
|
|
{
|
|
"type": "addNode",
|
|
"node": {
|
|
"id": "memoria-sessao",
|
|
"name": "Memória da Sessão",
|
|
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
|
|
"typeVersion": 1.4,
|
|
"position": [650, 250],
|
|
"parameters": {
|
|
"sessionIdType": "customKey",
|
|
"sessionKey": "={{ $('Normalizar entrada').item.json.sessionId }}",
|
|
"contextWindowLength": 20
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 3: Adicionar o node AI Agent**
|
|
|
|
```json
|
|
{
|
|
"type": "addNode",
|
|
"node": {
|
|
"id": "agente-agendamento",
|
|
"name": "AI Agent",
|
|
"type": "@n8n/n8n-nodes-langchain.agent",
|
|
"typeVersion": 3.1,
|
|
"position": [650, -120],
|
|
"parameters": {
|
|
"promptType": "define",
|
|
"text": "={{ $json.mensagem }}",
|
|
"options": {
|
|
"systemMessage": "Você é o assistente de agendamento da clínica, conversando por WhatsApp. Regras:\n1. O nome de contato do WhatsApp é \"{{ $('Normalizar entrada').item.json.nomeContato }}\" e o telefone é \"{{ $('Normalizar entrada').item.json.telefone }}\" — mas SEMPRE confirme o nome completo do paciente com o cliente antes de agendar, mesmo que já tenha o nome de contato.\n2. Pergunte a data e o horário desejados para a consulta, e opcionalmente o motivo.\n3. Nunca invente informação que o cliente não deu.\n4. Responda sempre em português, em tom cordial e objetivo, adequado para WhatsApp (mensagens curtas).\n5. Quando tiver o nome completo confirmado e a data/hora desejada, você pode agendar de verdade.\n6. NUNCA agende mais de uma vez na mesma conversa — se o cliente já confirmou um agendamento nesta conversa, não agende de novo; informe que o agendamento já foi feito.\n7. Se o agendamento falhar, explique o problema ao cliente em linguagem simples e pergunte se ele quer tentar de novo com outros dados, ou avise que vai encaminhar para um atendente."
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 4: Conectar Chat Model e Memory ao Agent, e a saída FALSE do If ao Agent**
|
|
|
|
```json
|
|
[
|
|
{ "type": "addConnection", "source": "OpenAI Chat Model", "sourceOutput": "ai_languageModel", "target": "AI Agent", "targetInput": "ai_languageModel" },
|
|
{ "type": "addConnection", "source": "Memória da Sessão", "sourceOutput": "ai_memory", "target": "AI Agent", "targetInput": "ai_memory" },
|
|
{ "type": "addConnection", "source": "É step=process?", "sourceOutput": 1, "target": "AI Agent" },
|
|
{ "type": "addConnection", "source": "AI Agent", "target": "Respond to Webhook" }
|
|
]
|
|
```
|
|
|
|
- [ ] **Step 5: Ajustar o Respond to Webhook para usar a saída do Agent**
|
|
|
|
```json
|
|
{
|
|
"type": "patchNodeField",
|
|
"nodeName": "Respond to Webhook",
|
|
"fieldPath": "parameters.responseBody",
|
|
"patches": [{ "find": "={{ $json.mensagem || '' }}", "replace": "={{ $json.output }}" }]
|
|
}
|
|
```
|
|
|
|
(`$json.output` é o campo de texto padrão que o node AI Agent produz.)
|
|
|
|
- [ ] **Step 6: Validar**
|
|
|
|
`n8n_validate_workflow` com `{"id": "<workflowId>"}`. Esperado: sem erros. Se aparecer erro sobre a credencial OpenAI ausente/inválida, ajuste o `credentials.openAiApi.id` (Step 1) ou peça para o usuário selecionar a credencial manualmente na UI antes de prosseguir.
|
|
|
|
- [ ] **Step 7: Testar a memória de sessão**
|
|
|
|
Ative o workflow. Envie duas mensagens com o **mesmo** `protocol`:
|
|
|
|
```bash
|
|
curl -s -X POST "https://devn8n.gtigrupo.com.br/webhook/agendamento-zpro-clinica-exemplo" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"step":"process","entrada":"Meu nome completo é João da Silva Teste","number":"5511999999999","contactName":"João","protocol":"p-memoria-1"}'
|
|
```
|
|
|
|
```bash
|
|
curl -s -X POST "https://devn8n.gtigrupo.com.br/webhook/agendamento-zpro-clinica-exemplo" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"step":"process","entrada":"Qual é o meu nome completo que eu te falei?","number":"5511999999999","contactName":"João","protocol":"p-memoria-1"}'
|
|
```
|
|
|
|
Esperado: a segunda resposta menciona "João da Silva Teste" — confirma que a memória por `sessionId=protocol` está funcionando entre execuções separadas do webhook.
|
|
|
|
Desative o workflow ao final.
|
|
|
|
---
|
|
|
|
### Task 5: Conectar a tool MCP `agendar` ao Agent
|
|
|
|
**Pré-requisito:** os 4 itens da seção "Pré-requisitos" no topo deste plano precisam estar prontos (node comunitário instalado, env var setada e n8n reiniciado, credenciais OpenAI e MCP criadas).
|
|
|
|
**Files:** Nenhum arquivo local — edita `<workflowId>`.
|
|
|
|
**Interfaces:**
|
|
- Consumes: credencial MCP stdio criada no pré-requisito 4.
|
|
- Produces: capacidade do Agent de chamar `agendar` de verdade.
|
|
|
|
- [ ] **Step 1: Adicionar o node MCP Client Tool**
|
|
|
|
```json
|
|
{
|
|
"type": "addNode",
|
|
"node": {
|
|
"id": "mcp-tool-agendar",
|
|
"name": "MCP - gti-scheduling-mcp",
|
|
"type": "n8n-nodes-mcp.mcpClientTool",
|
|
"typeVersion": 1,
|
|
"position": [900, 250],
|
|
"parameters": {
|
|
"connectionType": "cmd",
|
|
"include": "selected",
|
|
"includeTools": ["agendar"]
|
|
},
|
|
"credentials": {
|
|
"mcpClientCmdApi": { "id": "<ID da Credential MCP stdio criada no pré-requisito 4>", "name": "gti-scheduling-mcp (stdio)" }
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Os nomes exatos do tipo de credencial (`mcpClientCmdApi`) e da propriedade `connectionType` podem variar conforme a versão instalada do pacote `n8n-nodes-mcp` — se a validação do Step 3 apontar um nome de campo diferente, ajuste conforme o que a própria UI do n8n mostrar ao adicionar o node manualmente (Settings do node → aba Credentials).
|
|
|
|
- [ ] **Step 2: Conectar o node como tool do Agent**
|
|
|
|
```json
|
|
{
|
|
"type": "addConnection",
|
|
"source": "MCP - gti-scheduling-mcp",
|
|
"sourceOutput": "ai_tool",
|
|
"target": "AI Agent",
|
|
"targetInput": "ai_tool"
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 3: Validar**
|
|
|
|
`n8n_validate_workflow` com `{"id": "<workflowId>", "options": {"profile": "ai-friendly"}}`. Corrija qualquer erro de nome de campo/credencial apontado (ver nota no Step 1).
|
|
|
|
- [ ] **Step 4: Teste manual controlado, com dados fictícios, seguindo a mesma disciplina de segurança contra duplicidade do teste do `ZProAdapter`**
|
|
|
|
Ative o workflow. Envie, com um `protocol` novo e único:
|
|
|
|
```bash
|
|
curl -s -X POST "https://devn8n.gtigrupo.com.br/webhook/agendamento-zpro-clinica-exemplo" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"step":"process","entrada":"Oi, quero marcar uma consulta pra amanhã às 14h, meu nome completo é TESTE-N8N Paciente","number":"5511900000001","contactName":"Teste N8N","protocol":"p-e2e-1"}'
|
|
```
|
|
|
|
Continue a conversa (repetindo a chamada com o mesmo `protocol`, mudando só `entrada`) até o Agent confirmar o agendamento. **Antes de cada nova tentativa, se algo parecer ter falhado, confira visualmente no Z-PRO se o agendamento já foi criado** (mesma regra usada no teste manual do `ZProAdapter`) — não repita mensagens de confirmação "às cegas".
|
|
|
|
Confirme visualmente no Z-PRO que o agendamento fictício foi criado.
|
|
|
|
- [ ] **Step 5: Desativar o workflow ao final do teste**
|
|
|
|
`n8n_update_partial_workflow` com `{"type": "deactivateWorkflow"}` — só reativar definitivamente depois que o usuário revisar o resultado (Task 6).
|
|
|
|
---
|
|
|
|
### Task 6: Revisão final e ativação
|
|
|
|
**Files:** Nenhum arquivo local.
|
|
|
|
- [ ] **Step 1: Validação final completa**
|
|
|
|
`n8n_validate_workflow` com `{"id": "<workflowId>", "options": {"profile": "strict"}}`. Resolver qualquer erro/aviso restante.
|
|
|
|
- [ ] **Step 2: Apresentar o resumo ao usuário**
|
|
|
|
Antes de ativar definitivamente, mostrar ao usuário: URL do webhook de produção, nome do workflow, e pedir confirmação de que o Z-PRO já está configurado para apontar o fluxo de agendamento desta clínica para essa URL.
|
|
|
|
- [ ] **Step 3: Ativar**
|
|
|
|
Só ativar (`activateWorkflow`) depois da confirmação explícita do usuário no Step 2 — ativar aqui significa que mensagens reais de clientes passam a ser processadas.
|
|
|
|
---
|
|
|
|
## Observação sobre "commit"
|
|
|
|
Nem `D:\PROJETOS\KLINGO-CLINICAL-SYSLIFE-GCHAT-AGENDAMENTO` nem `gti-scheduling-mcp` são repositórios git — não há passo de `git commit` neste plano. O estado do workflow vive inteiramente no n8n; cada task é validada via `n8n_validate_workflow` e teste funcional (chamada real ao webhook), no lugar de testes automatizados de código.
|