Files
KLINGO-CLINICAL-SYSLIFE-GCHAT/docs/superpowers/specs/2026-08-11-confirmacao-agenda-clinicall-design.md
T
2026-08-11 16:02:37 -03:00

11 KiB

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/<data> (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.