diff --git a/docs/superpowers/specs/2026-08-11-confirmacao-agenda-clinicall-design.md b/docs/superpowers/specs/2026-08-11-confirmacao-agenda-clinicall-design.md new file mode 100644 index 0000000..20ba30a --- /dev/null +++ b/docs/superpowers/specs/2026-08-11-confirmacao-agenda-clinicall-design.md @@ -0,0 +1,200 @@ +# Design — Confirmação de Agenda via WhatsApp (ClinicAll) + +**Data:** 2026-08-11 +**Status:** Aprovado pelo usuário, aguardando plano de implementação. + +## Objetivo + +Mesmo padrão já implementado para o Klingo +(`docs/superpowers/specs/2026-08-11-confirmacao-agenda-klingo-design.md`), +agora para o **ClinicAll**: permitir que o paciente confirme presença +numa consulta agendada via WhatsApp. Diferente do Klingo, o ClinicAll +não tem uma API de "Telefonia" separada — os endpoints de confirmação +fazem parte da mesma `TCalendarController` já usada no MVP de +agendamento (`docs/superpowers/specs/2026-08-11-mcp-server-nativo-n8n-clinicall-design.md`), +verificados diretamente no manual oficial (`docs/API Clinicall.pdf`, +versão 1.1.16). + +## Relação com o trabalho anterior + +- Reaproveita o **MCP Server standalone de Mensageria (Z-PRO)** + (`docs/n8n-agendamento-runbook.md`, seção 17) para o disparo do + lembrete — mesma decisão do Klingo, assumindo que o cliente ClinicAll + de exemplo também usaria Z-PRO/GChat como canal de WhatsApp. +- É um MCP **novo e separado** do MCP de agendamento do ClinicAll + (seção 14.3 do runbook) — mesmo `TCalendarController`/`TDomainController`, + mas endpoints diferentes (confirmação de presença, não criação de + agendamento), mesmo espírito de separação de responsabilidades já + usado no Klingo (MCP de Telefonia separado do MCP de Agendamento). +- Mesma pendência de autenticação já documentada no MVP de agendamento + do ClinicAll: o manual não documenta nenhum header de autenticação + por requisição para `TCalendarController`/`TDomainController`. + **Decisão idêntica à já tomada**: `authentication: none` em todos os + nodes HTTP, nada inventado. + +## Escopo: 5 tools do MCP Server "ClinicAll - Confirmação de Agenda" + +| Tool | Endpoint | Uso | +| --- | --- | --- | +| `listar_agendamentos_do_dia` | `GET /TCalendarController/agendamento` (param: `data`) | Base do lembrete proativo — todas as marcações de uma data (livres e agendadas) | +| `buscar_agendamento_por_cpf` | `GET/POST /TCalendarController/agendamentoSemPaciente` (params: `cpf`, `dataNascimento`) | O agente usa isso pra achar a consulta pendente do paciente — **precisa de CPF e data de nascimento**, diferente do Klingo (que só pedia CPF) | +| `confirmar_presenca` | `POST /TCalendarController/AgendamentoFlags` | Ação central — atualiza `estadoAgenda`/`situacaoAgenda` da marcação | +| `consultar_estados_agenda` | `GET /TDomainController/estadoAgenda` | Tabela de domínio — valores exatos aceitos em `estadoAgenda` (ex.: `"CONFIRMADO PELA TELEFONISTA"`, `"NAO CONFIRMADO"`, `"FALTOU"`) | +| `consultar_situacoes_agenda` | `GET /TDomainController/situacaoAgenda` | Tabela de domínio — valores exatos aceitos em `situacaoAgenda` (ex.: `"Agendado"`, `"Presente"`, `"Atrasado"`) | + +**Diferença estrutural real em relação ao Klingo**: o Klingo aceita um +código curto de 1 letra (`C`/`S`/`N`) pra confirmar. O ClinicAll exige +uma **string exata e longa** em dois campos separados +(`estadoAgenda`/`situacaoAgenda`), cujos valores válidos só existem +documentados nas tabelas de domínio — por isso `consultar_estados_agenda` +e `consultar_situacoes_agenda` entram como tools de apoio (não +opcionais): sem elas, o agente teria que adivinhar a string exata, o +que violaria a disciplina de não inventar valores. Não há tool +equivalente a NPS ou consulta de bloqueios — o manual do ClinicAll não +documenta nada parecido para este módulo; ficam fora, sem inventar. + +## Arquitetura + +Três peças, mesmo padrão do Klingo: + +``` +1) MCP Server "ClinicAll - Confirmação de Agenda" (servidor + 5 sub-workflows) + [MCP Server Trigger] ──Tools──┬── listar_agendamentos_do_dia ──▶ GET /TCalendarController/agendamento + ├── buscar_agendamento_por_cpf ──▶ GET/POST /TCalendarController/agendamentoSemPaciente + ├── confirmar_presenca ──▶ POST /TCalendarController/AgendamentoFlags + ├── consultar_estados_agenda ──▶ GET /TDomainController/estadoAgenda + └── consultar_situacoes_agenda ──▶ GET /TDomainController/situacaoAgenda + +2) Workflow proativo "Lembrete de Confirmação - ClinicAll (exemplo)" + [Cron 8h diário] → [ClinicAll: listar_agendamentos_do_dia (amanhã)] + → [Loop por agendamento] → [Mensageria ZPRO: enviar_texto] + +3) Workflow de exemplo "Confirmação de Agenda - GChat - ClinicAll+Z-PRO (exemplo)" + [Webhook Z-PRO/GChat] → [AI Agent] → resposta ao paciente + tools: MCP ClinicAll - Confirmação de Agenda (buscar_agendamento_por_cpf, confirmar_presenca, + consultar_estados_agenda, consultar_situacoes_agenda) + memória: Postgres Chat Memory (mesmo padrão dos outros exemplos) +``` + +Sem cliente ClinicAll real disponível: mesma disciplina do Klingo — +estrutura completa, validada (`n8n_validate_workflow`, 0 erros +esperados), sem teste de ponta a ponta. + +## Componentes + +### MCP Server "ClinicAll - Confirmação de Agenda" + +Mesmo esqueleto de sub-workflow dos outros MCP Servers deste projeto: +`Execute Workflow Trigger` → `Config ClinicAll` (`Set` com `baseUrl` +placeholder) → montagem de query/body → `HTTP Request` +(`authentication: none`, `neverError: true` + `fullResponse: true`) → +classificação de resultado (mesma taxonomia genérica dos outros +providers: `AUTHENTICATION_ERROR` 401/403, `NOT_FOUND` 404, +`VALIDATION_ERROR` 400/422, `CLINICALL_API_ERROR` demais — o manual não +documenta código de erro específico pra estes endpoints). + +- **`listar_agendamentos_do_dia`**: parâmetro `data` (obrigatório, + conforme documentado — "Mandatório data da agenda"). URL: + `{{baseUrl}}/datasnap/rest/TCalendarController/agendamento/` + (mesmo endpoint base já usado no MVP de agendamento com `PUT` para + conciliar; aqui usado com `GET` para listar). +- **`buscar_agendamento_por_cpf`**: parâmetros `cpf` e `dataNascimento` + (ambos obrigatórios, conforme documentado). Endpoint: + `{{baseUrl}}/datasnap/rest/TCalendarController/agendamentoSemPaciente`. + **Ambiguidade real do manual**: o endpoint documenta métodos `GET, + POST` sem esclarecer se os parâmetros vão como query string (GET) ou + corpo (POST) — o exemplo do manual não mostra a requisição, só a + resposta. Decisão desta etapa: implementar como `GET` com os dois + parâmetros como query string (`?cpf=...&dataNascimento=...`), por + ser o padrão mais comum nos demais endpoints GET documentados deste + mesmo manual (todos os outros GETs do ClinicAll usam query string, + nunca body) — mas isso é uma suposição não verificada contra a API + real, registrada explicitamente como tal. +- **`confirmar_presenca`**: parâmetros `idAgenda` (obrigatório), + `situacaoAgenda` (obrigatório, string exata — ex.: `"Agendado"`), + `estadoAgenda` (obrigatório, string exata — ex.: `"CONFIRMADO PELA + TELEFONISTA"`), `confirmadoPor` (opcional — nome de quem confirmou, + útil quando não é o próprio paciente respondendo), `usuarioConfirmou`, + `dataConfirmacao`, `horarioFlag`, `usuarioFlag` (estes quatro + opcionais, preenchidos com dados fixos identificando a automação — + ex.: `usuarioConfirmou: "bot-whatsapp"` — já que não há usuário + humano operando). Endpoint: + `{{baseUrl}}/datasnap/rest/TCalendarController/AgendamentoFlags`. +- **`consultar_estados_agenda`**: sem parâmetro obrigatório (aceita + `nome` opcional de busca, conforme documentado). Endpoint: + `{{baseUrl}}/datasnap/rest/TDomainController/estadoAgenda`. +- **`consultar_situacoes_agenda`**: mesmo padrão, endpoint + `{{baseUrl}}/datasnap/rest/TDomainController/situacaoAgenda`. + +### Workflow proativo "Lembrete de Confirmação - ClinicAll (exemplo)" + +``` +[Cron Trigger, 8h diário] → [ClinicAll: listar_agendamentos_do_dia] + (data = amanhã, calculada via expressão) + → [Loop] → [Mensageria ZPRO: enviar_texto] + (number = telefoneCelular do paciente dentro do objeto Paciente + aninhado, body = mensagem com nomePaciente + dataAgenda/horaAgenda) +``` + +Mesmo padrão do Klingo: chamada direta via `Execute Workflow` (sem IA, +fluxo determinístico). Nota: no ClinicAll, o telefone do paciente vem +aninhado dentro do objeto `Paciente` de cada item da lista +(`item.Paciente.telefoneCelular`), diferente do Klingo onde `celular` +era um campo direto do item — refletir isso na extração de dados. +Itens com `situacaoAgenda: "Livre"` (sem paciente vinculado) devem ser +filtrados antes do envio — só mandar lembrete pra marcações com +`idPaciente` preenchido. Texto fixo nesta rodada (sem Google Docs — é +exemplo/esqueleto, sem gestor real). Fica **inativo** de propósito — +sem clínica real, ativar geraria só chamadas com erro. + +### Workflow de exemplo "Confirmação de Agenda - GChat - ClinicAll+Z-PRO (exemplo)" + +Réplica estrutural do padrão já usado no Klingo e no Z-PRO (webhook → +AI Agent → memória Postgres), sem cliente real associado. + +- **Webhook**: mesmo contrato Z-PRO/GChat já documentado (seção 6 do + runbook). +- **AI Agent**: `systemMessage` fixo instruindo o agente a: entender se + a mensagem é uma resposta de confirmação/recusa; se for, pedir **CPF + e data de nascimento** do paciente (diferente do Klingo, que só + precisava do CPF) e usar `buscar_agendamento_por_cpf` para achar a + marcação pendente; consultar `consultar_estados_agenda` e + `consultar_situacoes_agenda` para obter as strings exatas válidas + antes de decidir o que enviar (nunca inventar um valor de estado); + chamar `confirmar_presenca` com `estadoAgenda: "CONFIRMADO PELA + TELEFONISTA"` (paciente confirmou) ou `estadoAgenda: "NAO + CONFIRMADO"`/`"FALTOU"` conforme o caso, mantendo `situacaoAgenda: + "Agendado"` (a marcação continua agendada, só o estado de confirmação + muda); responder confirmando o registro ao paciente. +- **Tools**: MCP ClinicAll - Confirmação de Agenda — `buscar_agendamento_por_cpf`, + `confirmar_presenca`, `consultar_estados_agenda`, + `consultar_situacoes_agenda` conectadas (todas as 4 exceto + `listar_agendamentos_do_dia`, que só serve ao workflow proativo). +- **Memória**: `Postgres Chat Memory`, mesmo padrão da seção 16/18 do + runbook, credencial placeholder (sem cliente real). + +Fica **inativo** de propósito, mesma razão do workflow proativo. + +## Fora de escopo (adiado) + +- NPS / avaliação pós-consulta — não documentado no manual do + ClinicAll para este módulo. +- Consulta de bloqueios de agenda — não documentado no manual do + ClinicAll para este módulo (existe `flagEstadoAgenda: "B" — + BLOQUEADO` como estado de uma marcação individual, mas não um + endpoint de consulta de bloqueios como no Klingo). +- Resolver a ambiguidade de GET vs. body em `agendamentoSemPaciente` + contra a API real — fica pendente até haver clínica real pra testar. +- Configuração via Google Docs no workflow de exemplo — sem gestor + real associado. +- Teste de ponta a ponta contra a API real do ClinicAll — sem clínica + real disponível, mesma limitação já registrada no MVP de agendamento. + +## Testes + +Sem clínica ClinicAll real disponível: validação estrutural apenas +(`n8n_validate_workflow`, 0 erros esperados em todos os workflows). +Teste real de ponta a ponta fica pendente para quando houver uma +clínica ClinicAll real — nesse momento, resolver primeiro a +autenticação (mesma pendência do MVP de agendamento) e a ambiguidade +de `agendamentoSemPaciente` antes de qualquer teste de confirmação.