# 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.