DB
- drop agenda_excecoes (substituida por financial_exceptions + lock-edit
baseado em financial_records)
- financial_records.payment_link (Asaas + link compartilhavel)
- financial_exceptions.consume_on_miss (rotular nao-show consome ou nao)
- billing_contracts.charging_style (upfront/saldo/per_session)
Payment refactor
- paymentSettlement -> paymentMethod (string) + markPaidNow (bool).
Handler aplica payment_method sempre; status='paid'+paid_at apenas
quando markPaidNow=true && method != 'link'. Asaas (link) sempre
liquida via webhook, nunca nasce paid.
- create_financial_record_for_session com pos-RPC patch pra payment_method
e (opcional) status='paid' quando user marca "ja recebi".
Indicadores visuais (3 canais distintos por estado)
- Paid: barra esquerda emerald-500 4px na agenda (MelissaAgenda),
pi-check-circle no popover/Resumo.
- Pending: badge \$ amber canto direito (mantido); linha amber no popover/
Resumo "A receber R\$ X (cobranca pendente)".
- Neutro: sem badge nem barra (compromisso pessoal, bloqueio, ou
ocorrencia virtual de pacote upfront/saldo).
- Bulk-load de paymentState em _reloadRange etapa 4 (1 query unica em
financial_records mapeada por agenda_evento_id).
- AgendaEventDialog Resumo lateral ganha linha entre pi-clock e
pi-map-marker via novo sessionPaymentRecord (sem guard de
occurrenceMode, contrario ao occFinancialRecord que continua so pra
Rail/Clinica). 5 estados: paid+paid_at, overdue+venceu, pending+vence,
sem cobranca c/ valor, sem cobranca s/ valor.
UX de convenio
- InsurancePlanServiceQuickCreateDialog novo: cadastra procedimento
POR CIMA do AgendaEventDialog sem sair da agenda. Auto-seleciona
novo procedimento so quando nada estava selecionado antes.
- Caixa cinza "Cadastrar procedimento" sempre visivel quando convenio
selecionado, com copy variavel (0 procedimentos: chamada urgente;
1+: "se quiser adicionar mais").
- "+ Novo convenio" toolbar em ConfiguracoesConveniosPage (botao
estava faltando, empty state mandava clicar em botao inexistente).
- Hint contextual abaixo do card Sessao/Honorarios: convenio = "N da
guia eh opcional", gratuito = "sem cobranca", particular = sem hint.
Label "N da Guia" tambem ganhou "(opcional)" no service-picker dialog.
Bug fixes
- pickDbFields whitelist faltando 'modalidade' (useMelissaAgenda.js:74)
— sessoes avulsas eram salvas como presencial independente da
escolha visual. Adicionado.
- goToConveniosConfig removida — fazia router.push("/therapist/
configuracoes/convenios") mas /configuracoes/* eh rota raiz, nao
filha. Substituida pelo quick-create inline (#1).
- bloqueioCobrindo + dialogBlockOverlap passados via deps em
_buildHandlers (refs do useMelissaAgenda nao sao acessiveis no
escopo de _buildHandlers).
Fase 5 (status change + edit cobrada)
- AgendaStatusChangeConfirmDialog: confirm dialog quando user muda
status pra realizada/faltou/cancelado, com opcoes de markPaid ou
gerar cobranca conforme o caso.
- useAgendaBloqueios novo composable: extrai logica de bloqueios
cinza (background events) do MelissaAgenda.
Doc viva
- src/docs/agenda-compromisso-financeiro-cenarios.html: 13 cenarios
de teste manual. C1-C4 ja validados. Cada teste validado vira parte
da doc final pra area de ajuda (pos-Fase 9).
Wiki/handoff
- agenda-compromisso-fluxo e agenda-billing-pesquisa-mercado (decisoes
arquiteturais sobre billing).
- HANDOFF.md atualizado.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
11 KiB
title: Plano de auditoria fase-a-fase — fluxo de compromisso da agenda date: 2026-05-13 status: em-andamento related: agenda-billing-pesquisa-mercado, recorrencia-agenda
Contexto
Auditoria do ciclo completo de compromisso da agenda, fase-a-fase, validando cada etapa contra a agenda-billing-pesquisa-mercado (Cliniko / SimplePractice / TherapyNotes). Cada fase tem 3 entregas: auditar o que existe, decidir o gap, codar.
Decisões já tomadas (5 das 8 perguntas)
| # | Decisão |
|---|---|
| 1 | Disparo de cobrança: híbrido configurável (manual / status-driven / note-signed) |
| 4 | No-show: semi-automático via dialog de confirmação ao mudar status |
| 5 | Edit de cobrada: bloqueia (já implementado) |
| 7 | Refund: credit note nova (alinhado NFS-e) |
| 8 | Pagamento: entidade separada de financial_records |
Pendentes: #2 (lead/Inquiry), #3 (pacote upfront), #6 (janela de cancelamento — provavelmente já resolvido por min_hours_notice em financial_exceptions).
Plano de 8 fases
Ordem por dependência ("o que destrava o quê") e por estado atual.
✅ Fase 1 — Compromisso SEM paciente (bloqueio/feriado/exceção) — CONCLUÍDA 2026-05-13
Auditoria fez:
- ✅
agenda_excecoesé tabela órfã (0 referências em src/) — apesar de schema, policies, trigger e enums existentes - ✅
agenda_bloqueiosé a entidade canônica usada pelos 3 layouts - ✅
BloqueioDialog(4 modos: horário/período/dia/feriados) é compartilhado por Melissa Agenda (viaMelissaLayout.vue:2186), Rail e Clínica - ✅
MelissaBloqueios.vuetem form inline próprio pra admin/edit (caso de uso legítimo distinto do dialog de 4 modos) - ✅ Bloqueios não eram renderizados no FullCalendar — apenas impediam criação. UX inconsistente vs pausas/feriados que aparecem como background events
- ⚠️ Tipos customizáveis de bloqueio: descartado no MVP (sem cliente real)
- ⚠️ Robustez de
marcarSessoesParaRemarcar: adiado pra Fase 5 (status change)
Aplicado:
- Migration
20260513000001_drop_agenda_excecoes.sql— dropa tabela + 2 enums + trigger; policies caem com CASCADE agendaMappers.js: nova funçãobuildBloqueioBackgroundEvents(bloqueios, rangeStart, rangeEnd)— renderiza bloqueios como background events cinza (#6b728033), suporta dia-inteiro, com hora, e recorrente semanal- Novo composable
useAgendaBloqueios.js— load por owner único OU array (multi-owner pra Clínica),buildEventsForRangereutilizável - Wire em
useMelissaAgenda+MelissaAgenda.vue— bloqueios concatenados aofcEvents - Wire em
AgendaTerapeutaPage— bloqueios concatenados aocalendarEvents - Wire em
AgendaClinicaPage— bloqueios consolidados de todos os ownerIds - Refs stale removidas de
database-novo/docs/schema_map.mdedatabase-novo/db.config.json
Verificação:
- ESLint nos arquivos modificados: 0 errors novos (11 pré-existentes em código não-tocado)
- Vitest
agendaMappers.spec.js: 40/40 tests passed - ⚠️ Falta rodar a migration no banco local (pendente de execução manual; arquivo SQL pronto)
- ⚠️ Falta validar visualmente nos 3 layouts (Melissa/Rail/Clínica) — verificar que bloqueios aparecem em cinza após criar pelo BloqueioDialog
🟢 Fase 2 — Compromisso COM paciente
Estado: dialog refatorado em 11/05 (cards 40px, picker DataTable, 50/50 layout, 3 estados Sessão/Honorários, conceito Pacote, resumo flutuante). Working tree.
Auditar:
- Fluxo de cadastro mínimo de paciente in-line (já existe via
PatientCadastroDialogquick mode?) - Decidir #2 (Inquiry/lead separado ou só quick-create)
- Modalidade presencial/online consistente
Gap potencial:
- Quick-create exige só nome ou mais campos? (Cliniko: só nome; TherapyNotes: só last name)
- Decisão #2 (Inquiry/lead) — adiar pra v2 provável
Codar: ajustes pequenos, principalmente UX. Provavelmente quase nada novo.
🟢 Fase 3 — Recorrência
Estado: modelo "1 real + N-1 virtual" + occurrenceMode no 2º dialog estabilizado em 12/05. Ver recorrencia-agenda.
Auditar:
occurrenceModejá replicado em Melissa; falta Rail (AgendaTerapeutaPageL1630 + L3080) e Clínica (AgendaClinicaPageL1119 + L2398)- Decisão #3 (pacote upfront via account credit) — adiar provável
Codar: replicar occurrenceMode em Rail/Clínica. Talvez add de pacote upfront (Cliniko model) numa fase futura.
🟠 Fase 4 — Cobrança: modo de disparo configurável (DECISÃO #1)
Estado: Fase 1 atual ("Gerar cobrança ao salvar") existe como checkbox em criação avulsa+particular. Não tem setting de modo.
Auditar:
- Onde vive a config? Card novo em
/configuracoes/excecoes-financeirasou página irmã/configuracoes/cobranca-defaults? - Granularidade: por tenant (clínica), por owner (terapeuta), ou ambos com herança?
Gap:
- Tabela/coluna nova pra
charge_trigger_modeenum (manual/status_driven/note_signed) - UI de config
- Job overnight pra modo
status_driven(Supabase edge function + cron) - Trigger no signature de nota pra
note_signed(depende de modulo de notas; nao temos) - Checkbox atual da agenda passa a fazer sentido só em modo manual (ou vira override universal?)
Codar:
- Migration: setting de modo (tenant_billing_settings ou colunas em agenda_configuracoes)
- UI de config
- Job pra modo status_driven (avaliar se entra na v1 ou v2)
- Refator do checkbox atual pra respeitar o modo
🟠 Fase 5 — Status change → cobrança com confirm dialog (DECISÃO #4)
Estado: lógica automática roda em useAgendaFinanceiro.handleStatusChange. Consulta regra em financial_exceptions, cria/ajusta/cancela financial_record SEM perguntar.
Auditar:
- Quais status disparam: hoje só
faltouecancelado(mappingSTATUS_TO_EXCEPTION) professional_cancellationna tabela mas não no mapping- Onde
handleStatusChangeé chamado (quais entradas de status change disparam)
Gap:
- Confirm dialog ao mudar status pra
faltou/cancelado: "Aplicar cobrança de R$X conforme regra? [Sim / Não / Editar valor]" - Adicionar
professional_cancellationao mapping (status atual da agenda inclui? checar) - Decidir: dialog aparece sempre ou só quando
charge_mode !== 'none'
Codar:
- Dialog componente novo (
AgendaStatusChargeConfirmDialog.vue) - Interceptar
handleStatusChangeantes da aplicação automática - Adicionar
professional_cancellationno mapping - Toast diferenciado pra "aplicado/recusado/editado"
🟢 Fase 6 — Edit de cobrada (DECISÃO #5 — JÁ IMPLEMENTADO)
Estado: propagateToSerie filtra por financial_records em status imutável. UI lock em AgendaEventDialog via occFinancialRecord. Working tree.
Auditar: validar contra cenários reais (testar série com 4 sessões, 2 cobradas, 2 abertas; editar template; verificar que cobranças não mudam).
Codar: zero (talvez add de aviso UX se faltar clareza).
🔴 Fase 7 — Pagamento como entidade separada (DECISÃO #8)
Estado: hoje financial_records.paid_at marca pagamento (acoplado). Não tem entidade payments independente.
Auditar:
- Como financial_records.paid_at é usado hoje (queries de receita, dashboards, conciliação)
- Webhook PSP existente? (provável que PIX e cartão sejam manuais hoje)
Gap:
- Migration: tabela
payments(id, amount, method, paid_at, source, allocated_to_record_id NULL-able) - Alocação manual de pagamento "solto" a um financial_record
- Pagamento parcial (1 payment cobre N records ou 1 record recebe N payments?)
- Repo + composable + UI
Codar: fase pesada — provavelmente sub-dividir.
🔴 Fase 8 — Reembolso / credit note (DECISÃO #7)
Estado: hoje só tem financial_records.status='cancelled'. Não preserva original como doc fiscal.
Auditar: processo fiscal atual (já emite NFS-e? quando? como cancela?)
Gap:
- Migration: tabela
credit_notes(id, original_record_id, amount, reason, issued_at) - Constraint: credit note tem valor ≤ |original|
- UI no Financeiro pra "Reembolsar"
- Integração com NFS-e (pode ser separada)
Codar: fase pesada — provavelmente sub-dividir.
🟣 Fase 9 — Plano Inicial (entrevista + N sessões regulares)
Estado: apenas conceito; nada codado.
Pedido do user (2026-05-14): clínica cobra 1 entrevista inicial (valor X) + 4 sessões regulares (valor Y cada). É o "plano de entrada" pra novos pacientes. User faz isso manualmente hoje na clínica dele.
Conceito:
- Config nas settings da agenda do tenant:
- Toggle "Habilitar plano inicial"
- Valor entrevista (R$)
- Qtd de sessões regulares (default 4)
- Valor por sessão regular (R$)
- (Opcional) Texto/descrição que aparece no fluxo
- Quando user cria 1ª sessão de paciente novo (sem histórico):
- Sistema oferece: "Aplicar plano inicial? Entrevista R$ X + 4× R$ Y = total R$ Z"
- Ao aceitar, materializa 5 sessões com
pricediferenciado: 1ª = X, demais = Y - Pode ser tratado como 1 série recorrente "especial" com 1ª ocorrência destacada
- OU como 2 entidades distintas (1 avulsa entrevista + 1 série de 4)
Decisões pendentes:
- Estrutura: série única com 1ª diferenciada OU avulsa + série separada?
- Onde fica a config:
agenda_configuracoes(jsonb adicional?) ou tabela novaintake_plans? - "Paciente novo" = sem sessões anteriores? Ou marcador manual no cadastro?
- Plano único do tenant ou múltiplos planos (avaliação clínica, avaliação neuropsi, etc)?
Cabe na Fase 4 (cobrança)? Não — Fase 4 é só modo de disparo; aqui é estrutura de pacote pré-configurado. Fica como Fase 9 separada.
Ordem sugerida de execução
| Ordem | Fase | Razão |
|---|---|---|
| 1ª | Fase 1 | Curta, validação, define se tem cleanup de tabelas necessário |
| 2ª | Fase 5 | Destrava UX urgente (confirm dialog evita cobrar errado) |
| 3ª | Fase 4 | Híbrido configurável — destrava racional do checkbox atual |
| 4ª | Fase 2 | Quase 100% pronta, validar e finalizar |
| 5ª | Fase 3 | Replicar occurrenceMode em Rail/Clínica |
| 6ª | Fase 6 | Já feito; só testar |
| 7ª | Fase 7 | Refator estrutural pesado — entra depois das fases UX |
| 8ª | Fase 8 | Depende fiscal NFS-e — pode ir pra v2 |
| 9ª | Fase 9 | Plano Inicial (entrevista + 4 sessões) — pedido do user, conceito pronto, codar pós-7 |
Como cada fase termina
- Página da fase na wiki é atualizada com o resultado
- Commit dedicado com prefixo
agenda(fase-N): ... - Update no index da wiki
- Entrada no
log.md