Files
Rafael MelgaçoandClaude Opus 5 c7202d87c6 feat(agenda): o lembrete de compromisso ganha onde se liga
O `99c33257` fez nascer o disparador do lembrete — o cron que a cada cinco
minutos procura compromisso a vencer e manda o aviso. Faltava a outra metade do
par: `calendar_event_types.reminder_enabled` e `reminder_minutes_before` não
existiam no `criarSchema`, no `alterarSchema` nem na projeção do GET de
`app/api/v1/agenda/tipos/route.ts`, e não apareciam em
`app/app/settings/tenant/agenda/`. Ninguém conseguia LIGAR o lembrete — nem pela
tela, nem pela API —, então a varredura devolvia zero linhas em toda instalação.

É o invariante 6 do Sistema Vivo ("toda configuração tem superfície") e o
anti-pattern que esta casa nomeia: capacidade que existe e não tem como ser
usada. O cabeçalho do próprio cron media e declarava o buraco na main 58dcb811.

O que entra:

- os dois campos no `criarSchema`, no `alterarSchema` e na projeção do GET, mais
  `lembreteLigado`/`lembreteAntecedenciaMin` no coletor `listaTiposDeAtendimento`
  (que a rota projeta). Eles NÃO vão ao modelo — a ferramenta MCP projeta o
  próprio recorte, pelo mesmo motivo dos quatro números da grade;
- faixa de 15 min a 7 dias para a antecedência, deliberadamente mais estreita que
  o CHECK do banco (`between 0 and 43200`): 0 min nunca dispara, porque
  `estaNaHora` recusa compromisso já começado, e 30 dias não é lembrete. A recusa
  sai em 422 com texto em português, traduzido na borda;
- os dois controles no bloco do tipo, em Configurações › Tipos de agendamento. O
  campo de minutos fica DESABILITADO com o aviso desligado — controle ativo ao
  lado de caixa desmarcada faz quem digita concluir que agendou alguma coisa — e
  campo desabilitado não entra no `FormData`, então desligar preserva a
  antecedência guardada em vez de sobrescrevê-la;
- a lista mostra "avisa o cliente N min antes" sem abrir nada: mensagem que sai
  sozinha para o telefone de um cliente não pode viver escondida atrás de um
  clique em "Editar".

PADRÃO OFF, e isso é o ponto. Não há `.default(true)` no Zod: quem não manda o
campo não liga nada, e o default da coluna (migration 0194) segue decidindo.
Nenhuma instalação existente muda de comportamento por atualizar.

Provas: `app/api/v1/agenda/tipos/route.test.ts` (14 casos — o valor CHEGA ao
banco, a faixa recusa sem escrever, a organização A não altera o tipo da B) e um
caso novo em `tests/e2e/agenda-tipos-de-agendamento.spec.ts`, executado em
ambiente fresco estilo VPS (Supabase local do `baseline.sql`, `next build` de
produção): 5/5 verdes, com a linha do banco conferida depois.

O trabalho original do lembrete é de @rafaeskytrabalho, no PR #423; este commit
fecha o laço que aquele deixou declarado em voz alta.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 09:30:44 -03:00
..