diff --git a/relatorios/RELATORIO-AGENDA-2026-05-20.html b/relatorios/RELATORIO-AGENDA-2026-05-20.html new file mode 100644 index 0000000..a910bb9 --- /dev/null +++ b/relatorios/RELATORIO-AGENDA-2026-05-20.html @@ -0,0 +1,1445 @@ + + +
+ +
+ O módulo de agenda do AgênciaPSI atravessou uma rodada estrutural de validação
+ via 13 cenários do documento vivo src/docs/agenda-compromisso-financeiro-cenarios.html.
+ A bateria expôs 14 bugs reais em apenas um dia — todos corrigidos —
+ e revelou um padrão recorrente: regressões silenciosas em fluxos
+ paralelos, particularmente em interações com billing_contracts e
+ financial_records.
+
+ A engenharia do módulo é funcionalmente robusta — os fluxos + críticos (status change, pacote saldo, pacote upfront, multa, antecipação, + edit imutável) operam corretamente após os fixes. Mas a base de código carrega + sintomas que devem ser endereçados antes da replicação para Rail e Clínica, + sob risco de duplicação de dívida. +
+ +AgendaEventDialog.vue (6.070), MelissaLayout.vue (4.331),
+ AgendaTerapeutaPage.vue (3.567). Refator sustentado é inviável neste estado.
+ P0
+ billing_contracts.updated_at —
+ coluna inexistente. UPDATEs falhavam silenciosamente em
+ Promise.allSettled. Patch tipo "trigger SQL"
+ eliminaria a categoria inteira.
+ P1
+ eventoSelecionado.value
+ é cópia, não referência reativa. Padrão repetido em outros componentes do
+ Melissa. Ergonomia ruim para mutações otimistas.
+ P1
+ /financeiro sem filtro. Falta UI dedicada de auditoria.
+ P2
+ | Arquivo | +LOC | +Tipo | +Observação | +
|---|---|---|---|
AgendaEventDialog.vue |
+ 6.070 | +Componente Vue monolítico | +≥7 responsabilidades distintas: cadastro, recorrência, billing, multa, pacote, lock, preview | +
MelissaLayout.vue |
+ 4.331 | +Layout container | +Container + ~30 handlers + 8 dialogs montados; deveria ser shell | +
AgendaTerapeutaPage.vue |
+ 3.567 | +Página Rail (legacy) | +Implementação paralela com lógica duplicada | +
useMelissaAgenda.js |
+ 2.863 | +Composable monolítico | +Bulk-load, normalize, handlers, status change, decisions, applies — tudo aqui | +
AgendaClinicaPage.vue |
+ 2.811 | +Página Clínica (legacy) | +3ª implementação paralela; receberá os mesmos bugs | +
MelissaEventoPanel.vue |
+ 1.010 | +Popover | +Aceitável, mas concentra lógica de derivação (paymentLabel, contractInfo, ações) | +
useAgendaEventLifecycle.js |
+ 685 | +Composable de lifecycle | +Carregamento, edit, delete; saudável em tamanho | +
AgendaStatusChangeConfirmDialog.vue |
+ 671 | +Dialog dedicado | +Recém-ampliado com bloco reverse (Fase 5); ainda dentro do aceitável | +
+ Total nos hotspots acima: ~22k LOC. Em escala de manutenção, + qualquer arquivo >1.000 LOC é candidato a refator; >2.500 LOC é débito + crítico — toda navegação demanda Ctrl+F. +
+ +src/
+├── features/agenda/
+│ ├── components/ (15 .vue — DialogV2, Toolbar, Calendar, etc)
+│ ├── composables/ (20 .js — lifecycle, events, services, etc)
+│ └── pages/ (5 .vue — Terapeuta, Clínica, Recorrencias, etc)
+├── layout/melissa/
+│ ├── composables/ (useMelissaAgenda 2.863 LOC)
+│ ├── MelissaLayout.vue (shell + handlers)
+│ ├── MelissaAgenda.vue (FullCalendar wrapper)
+│ ├── MelissaEventoPanel (popover)
+│ └── ...
+└── components/agenda/ (AgendaEventoFinanceiroPanel, etc)
+
+
+ src/features/agenda/composables/__tests__/ tem 7 specs Vitest
+ cobrindo composables principais (events, lifecycle, composer, picker, recurrence).
+ Não há testes E2E. Toda validação de fluxo financeiro
+ (status change, pacote, antecipar) depende de bateria manual contra o documento
+ vivo HTML.
+
Análise reconhece méritos antes de criticar. O que está bem feito:
+ +
+ O arquivo src/docs/agenda-compromisso-financeiro-cenarios.html
+ é uma boa prática rara: doc vivo que descreve cada cenário
+ com mockup interativo + critério de teste. Funciona como spec executável
+ informal. O addendum de C10 que adicionamos hoje preservou o histórico
+ de divergências.
+ Manter
+
financial_records.notes
+ Todas as transições de cancelamento, reversão e revogação registram entrada
+ cronológica em notes com formato [YYYY-MM-DD] motivo.
+ Permite reconstruir o histórico financeiro de qualquer sessão.
+ Estrutura simples mas efetiva — não criou tabela de auditoria paralela.
+ Manter
+
+ O dialog AgendaStatusChangeConfirmDialog agora cobre 4 contextos
+ distintos: realizada (avulsa/pacote), faltou/cancelado (com multa+saldo),
+ realizada com paid pré-existente (antecipação), e reversão para agendado
+ (com cancelar records + devolver saldo). É o ponto único de decisão
+ para mudanças com impacto financeiro.
+ Manter
+
@cobranca-atualizada
+ Sub-componentes (panel financeiro, dialog) emitem evento que sobe até
+ MelissaLayout e dispara M.refetch(). Padrão limpo
+ para propagar updates de pagamento sem acoplar pais e filhos via store global.
+ Manter — replicar em Rail/Clínica
+
+ Sessões em cancelado/faltou agora bloqueiam
+ "Editar sessão" + transições de status (exceto "Agendada" como caminho
+ explícito de recuperação) + label e badge cientes do estado. Evita
+ operações financeiras inadvertidas em sessões que não aconteceram.
+ Manter
+
+ financial_exceptions_charge_chk restringe valores possíveis
+ de charge_mode. financial_records.status_check
+ enumera estados válidos. Constraints de check ao invés de validação
+ apenas em código — defesa em profundidade.
+ Manter
+
+ Em vez de navegar para outro form quando falta uma dep (serviço, convênio, + paciente), abre quick-create por cima. Preserva contexto do usuário. + Padrão consistente. + Manter — padrão de design +
+ +
+ Cores semânticas consistentes — --ok (verde realizada),
+ --warn (amarelo falta), --danger (vermelho cancelar),
+ --info (azul agendada recém-adicionada). Padrão se mantém
+ entre popover, dialog e calendário.
+ Manter
+
+ AgendaEventDialog.vue com 6k LOC concentra: cadastro de evento,
+ recorrência, billing config, multas, pacote saldo/upfront, lock de cobrança
+ emitida, preview da série, edição de ocorrência única vs todos. Sete
+ responsabilidades distintas em um único componente — viola SRP.
+
+ Sintomas operacionais já observados: edição perigosa (qualquer alteração + precisa varrer todo o arquivo), regressões frequentes em flows não-relacionados, + teste unitário não consegue isolar um caso sem mockar 80% do contexto. +
++ Quebra natural: +
+AgendaEventDialogShell — orquestrador, gerencia steps e propsAgendaEventDialogStepBasic — paciente, data, hora, modalidadeAgendaEventDialogStepRecurrence — recorrência + preview de sérieAgendaEventDialogStepBilling — service/insurance/billing type/lockAgendaEventDialogStepConfirm — preview final + diff antes/depoisuseMelissaAgenda._applyStatusDecisions (cobrança dupla,
+ updated_at gotcha, link universal) não foram propagados
+ para AgendaTerapeutaPage nem AgendaClinicaPage.
+ + O caminho que vai dar errado: replicar manualmente os fixes para + cada um dos 3 contextos. Multiplica esforço por 3 e introduz drift. +
+
+ Caminho correto: extrair em useAgendaStatusChangeOrchestrator.js
+ consumido pelos três (Melissa via composable, Rail/Clínica via importação direta).
+ Tornar _applyStatusDecisions, _loadStatusChangeContext,
+ _needsConfirmDialog e _applyStatusUpdateOnly em
+ funções puras com deps por injeção.
+
Promise.allSettled escondendo falhas
+ Padrão recorrente: tasks.push(...); await Promise.allSettled(tasks).
+ Quando uma das tasks falha, vira {status:'rejected'} e o toast
+ warn genérico aparece — fácil de ignorar.
+
+ Caso real (corrigido hoje): UPDATE em billing_contracts com
+ campo updated_at inexistente. Falha silenciosa por semanas.
+ Foi descoberto manualmente quando o saldo não incrementava em teste E2E manual.
+
+ Política sugerida: +
+await sequencial
+ + try/catch + toast/console específico por falhaPromise.allSettled apenas para operações realmente
+ independentes (ex: pré-buscas de UI auxiliar)[agenda/status], [agenda/billing]) ao invés de
+ console.warn espalhadonormalizeForMelissa whitelist silenciosa
+ A função normalizeForMelissa(r) retorna um objeto com campos
+ explícitos. Campos no r original que não estão no return
+ somem silenciosamente. Bug do dia: owner_id
+ não estava no return → após o watch sync introduzido, virava null →
+ INSERT em financial_records violava NOT NULL.
+
+ Memória existente (project_pickdbfields_whitelist) documenta
+ bug análogo no pickDbFields. Padrão repetido.
+
+ Mitigação imediata: documentar e auditar manualmente todos os campos + necessários. Mitigação estrutural: TypeScript ou JSDoc tipado + no return — o linter sinalizaria campos faltantes antes do runtime. +
+ +
+ eventoSelecionado.value = ev copia a referência. Quando o
+ eventos computed recalcula com novo objeto, a ref guardada não
+ acompanha. Padrão repetido em outros lugares do Melissa (já há memória
+ documentando).
+
+ Mitigação aplicada hoje: watch em M.eventos com lookup por
+ id + recurrence_id/date (cobre transição virtual→materializada).
+
+ Mitigação estrutural: trocar o pattern por const selectedId =
+ ref(null) + const selectedEvent = computed(() =>
+ eventos.value.find(e => e.id === selectedId.value)). Reatividade
+ nativa, zero watches, zero race conditions.
+
refetch()
+ _reloadRange dispara queries paralelas (eventos, virtuais,
+ bloqueios, payment state, propagação cross-week). Operações UI sequenciais
+ rápidas (antecipar→revogar→antecipar) podem ler ctx antes do refetch anterior
+ propagar, levando a decrements/increments com base em valores stale.
+
+ Mitigação aplicada hoje no bloco reverseRestoreSaldo: refetch
+ explícito do billing_contracts.sessions_used direto do DB
+ imediatamente antes do UPDATE. Padrão "lê fresh, escreve
+ consciente".
+
+ Mitigação estrutural: mover lógica de increment/decrement de saldo para
+ RPC server-side com lock pessimista (SELECT ... FOR UPDATE).
+ Elimina race condition no nível de banco.
+
+ create_financial_record_for_session foi corrigido para ignorar
+ cancelled em idempotência (commit c23d0a5, já
+ documentado em memória). Mas o handler do antecipar fazia UPDATE manual
+ em record cancelled após chamar a RPC, reativando-o como paid.
+ Audit trail polluído.
+
+ Princípio: RPCs financeiras nunca devem reusar records cancelados. + Toda operação que cria cobrança gera record novo. Cancellation é terminal. +
+ +updated_at inconsistente entre tabelas
+ Algumas tabelas têm trigger set_updated_at automático
+ (ex: financial_exceptions), outras não
+ (billing_contracts). Código cliente assume incorretamente
+ que todas têm. Foi origem direta do bug do updated_at.
+
+ Tabela atual: +
+| Tabela | tem updated_at? | tem trigger? |
|---|---|---|
financial_records | ✅ | presume-se sim |
financial_exceptions | ✅ | ✅ trg_financial_exceptions_updated_at |
agenda_eventos | ✅ | presume-se sim |
recurrence_rules | ✅ | presume-se sim |
billing_contracts | ❌ | ❌ |
+ Recomendação: adicionar updated_at + trigger em
+ billing_contracts via migration. Tornar consistente em todas
+ as tabelas de domínio operacional.
+
+ UPDATEs em RLS-protected tables retornam silenciosamente 0 rows quando
+ a policy filtra. Sem RETURNING explícito o cliente não detecta.
+ No fluxo de status change atual, vários UPDATEs assumem que rodaram.
+
+ Mitigação: adicionar .select() ou .select('id').single()
+ em UPDATEs sensíveis; falhar explicitamente se 0 rows afetadas.
+
+ Mesma informação (e.g. sessions_used) lida de múltiplas fontes:
+ ctx.billingContract.sessions_used (snapshot do load),
+ ev.contract.sessionsUsed (via ruleContractMap), DB fresh,
+ cached em variáveis locais. Pontos de divergência são pontos de bug.
+
+ Princípio: single source of truth por operação. + Antes de UPDATE crítico, fresh-fetch + uso somente da leitura recente. + Em UIs reativas, derivar de um único store/computed. +
++ Em pacote saldo, três botões diferentes podem operar sobre a mesma sessão: +
++ Cada um cobre um caso de uso ligeiramente diferente, mas o overlap confunde. + Durante o teste do dia, usuário ficou perdido entre os três caminhos. +
++ Proposta: unified action menu. Um único botão "Marcar sessão" + abre menu contextual: +
+┌─ Marcar sessão como… ─────────────┐
+│ ✓ Realizada │
+│ ├─ Já recebi (PIX/dinheiro/...) │
+│ └─ Cobrar depois (saldo/avulsa) │
+│ ⚠ Faltou (+ multa/saldo) │
+│ ✕ Cancelar (+ regra) │
+├───────────────────────────────────┤
+│ 💰 Antecipar pagamento (futura) │
+└───────────────────────────────────┘
+
+
+ Sessão em cancelado tem 4 botões disabled (Realizada/Falta/
+ Reagendar/Cancelar) com tooltip "use Agendada para reativar". O
+ aprendizado depende do hover no tooltip — primeiro encontro pode ser frustrante.
+
+ Proposta: badge inline ao lado dos botões disabled, ou banner amarelo no topo + do popover: "Sessão encerrada. Clique Agendada para reabrir e + permitir novas ações." +
+ +
+ Ciclos antecipar/revogar/realizar geram records cancelled empilhados.
+ Em /financeiro o filtro padrão .neq('status','cancelled')
+ esconde do user normal, mas em queries de debug ou em telas
+ administrativas a poluição aparece.
+
+ Propostas: +
+financial_records_archive)+ Hoje foi refatorado o bloco "Cobrança no pacote saldo" para ter + sub-question explícita "A sessão já foi paga?". O mesmo padrão deve + ser auditado em outros lugares onde aparece "método de pagamento" com + opções mistas: +
+paymentMethodOptionsCobranca com "Já recebi — PIX". Padrão
+ novo deveria propagar para consistência.+ Fix aplicado hoje: label muda para "Aguardando uso do pacote" (saldo) ou + "Coberta pelo pacote (upfront)". Verificar consistência em: +
++ Toasts genéricos "Falha ao processar mudança de status" não ajudam usuário. + Quando RLS bloqueia ou constraint quebra, mensagem deveria ser específica: +
+
+ Padrão implementado hoje (alterna baseado em isAntecipacaoAtiva).
+ Pode ser confuso para usuário que esquece do que clicou — botão "muda
+ sozinho". Considerar:
+
+ No dialog reverse, radio "Manter cobrança ativa" deixa user reativar sessão + com record pending órfão. É uma escolha legítima mas raramente intencional. + Considerar adicionar warning quando seleciona "manter". +
+AgendaTerapeutaPage e
+ AgendaClinicaPage mantém as 3 implementações divergentes.
+ Primeira sprint após replicação vai gastar tempo descobrindo "por que
+ funciona em Melissa mas não em Clínica" (ou vice-versa).
+ + Sequência recomendada antes da replicação: +
++ Várias decisões de domínio são implícitas: +
++ Não há documentação formal das invariantes do domínio. Consequência: cada + bug exige reconstrução mental do que deveria ser válido. +
+
+ Recomendação: documento de invariantes do domínio em
+ Obsidian/Brain/wiki/agenda-invariantes.md + (futuramente)
+ constraints SQL ou triggers checando os mais críticos no banco.
+
tenant_id manual em todo INSERT
+ Cada INSERT em financial_records, agenda_eventos,
+ billing_contracts requer tenant_id explícito.
+ Esquecer = constraint violation, ou pior, escrever no tenant errado.
+
+ Mitigação parcial: RLS bloqueia leitura cross-tenant. Mas writes ainda + dependem do código cliente. Pattern de "service layer" com tenant injetado + centralmente reduziria a área de risco. +
+ ++ Edge functions (asaas-webhook, evolution-whatsapp, etc) operam direto no DB + e podem deixar state inconsistente com o que o frontend esperar. + Não foi escopo deste relatório, mas merece auditoria separada. +
+ ++ Cada fix do dia foi merged direto pra main e deploy implícito. Não há + feature flag para experimentar "novo dialog reverse" em produção sem + expor para todos. Em sistema com clientes pagantes, é fragil. +
+ +
+ Durante o teste, vários UPDATE billing_contracts SET sessions_used=X
+ foram aplicados manualmente para limpar estado. Em produção isso é
+ impraticável e arriscado. Falta:
+
+ billing_contracts.sessions_used é INTEIRO incrementado/
+ decrementado manualmente. Verdade "real" é o COUNT de records associados.
+ Risco: drift entre os dois ao longo do tempo.
+
+ Alternativa: tornar sessions_used uma VIEW computed via
+ COUNT(*) FROM financial_records WHERE billing_contract_id=X AND
+ status IN ('paid','pending'). Performance pode requerer materialização
+ ou índice; mas elimina classe inteira de bugs de sync.
+
+ Priorização: P0 = antes da próxima replicação (Rail/Clínica). + P1 = sprint atual ou próximo. P2 = quando + couber, valor compounding. P3 = ideal mas não bloqueante. +
+ +| # | +Recomendação | +Prio | +Esforço | +Impacto | +
|---|---|---|---|---|
| R1 | +
+ Extrair status change orchestrator para composable shared
+ useAgendaStatusChangeOrchestrator.js. Funções puras (loadContext,
+ needsDialog, applyDecisions, applyStatusUpdate). Melissa migra primeiro,
+ depois Rail/Clínica importam.
+ |
+ P0 | +4–6h | +Alto · elimina trio | +
| R2 | +
+ Migration: adicionar updated_at + trigger em
+ billing_contracts. Elimina o gotcha que custou
+ horas hoje. Padroniza com outras tabelas.
+ |
+ P0 | +30min | +Alto · elimina classe | +
| R3 | +
+ Auditar Promise.allSettled em fluxos financeiros.
+ Trocar por awaits sequenciais com try/catch dedicado. Adicionar
+ logger estruturado ([agenda/billing/saldo]).
+ |
+ P0 | +2–3h | +Alto · visibilidade | +
| R4 | +
+ Documentar invariantes do domínio em
+ Obsidian/Brain/wiki/agenda-invariantes.md. Estado válido
+ de status × records × contract. Referência consultável.
+ |
+ P0 | +1–2h | +Médio-alto · onboarding | +
| R5 | +
+ Refatorar AgendaEventDialog.vue em 5
+ sub-componentes (Shell, StepBasic, StepRecurrence, StepBilling,
+ StepConfirm). Manter API atual; migration interna.
+ |
+ P1 | +2–3 dias | +Alto · manutenção | +
| R6 | +
+ Trocar eventoSelecionado snapshot por
+ selectedId + computed. Elimina snapshot stale.
+ Replicar em outros refs do Melissa.
+ |
+ P1 | +1–2h | +Médio · estabilidade | +
| R7 | +
+ Auditoria visual da sessão — drawer com timeline
+ de records (pending/paid/cancelled), com cancelled colapsados por
+ default. Reduz poluição em /financeiro.
+ |
+ P1 | +1 dia | +Médio · UX | +
| R8 | +
+ RPCs server-side para increment/decrement de saldo
+ com SELECT FOR UPDATE. Elimina race condition em
+ fluxos rápidos.
+ |
+ P1 | +3–4h | +Médio-alto · correctness | +
| R9 | ++ Mensagens de erro específicas em handlers de + status/billing. Catalogar erros típicos (RLS, constraint, + state inválido). + | +P1 | +2h | +Médio · UX | +
| R10 | +
+ TypeScript ou JSDoc tipado em
+ normalizeForMelissa, pickDbFields e funções
+ de transformação de dados. Lint flagga campos faltantes.
+ |
+ P2 | +2–4h por área | +Alto longo prazo | +
| R11 | ++ Testes E2E (Playwright) dos 13 cenários. Substitui + bateria manual. CI roda em cada PR. + | +P2 | +1 semana | +Alto · confiança | +
| R12 | ++ Unified action menu "Marcar sessão" substituindo + os 3 botões sobrepostos (Usar/Antecipar/Realizada). + | +P2 | +1 dia | +Médio · clarity | +
| R13 | +
+ Feature flags via tenant_settings ou
+ biblioteca específica. Permite rollout gradual de mudanças no dialog.
+ |
+ P3 | +1 dia | +Baixo curto, alto longo | +
| R14 | +
+ sessions_used como VIEW computed
+ em vez de coluna incrementada. Elimina drift de sincronia.
+ Avaliar performance.
+ |
+ P3 | +1–2 dias | +Alto correctness, médio risco | +
| R15 | ++ Ferramenta de "data fix" versionada para correções + administrativas em produção. Audit log obrigatório. + | +P3 | +2–3 dias | +Alto operacional | +
updated_at +
+ trigger billing_contracts) · 30 min
+ Promise.allSettled em todo src/AgendaEventDialog em 5 sub-componentes (2–3 dias)sessions_used como VIEW+ O módulo de agenda é o coração operacional do AgênciaPSI — + é por onde o terapeuta vive o dia. Investimentos em estabilidade aqui têm + retorno desproporcional: cada bug evitado é uma sessão real do paciente + que não vira incidente. +
+ ++ A bateria de testes do dia provou que a metodologia funciona: + 13 cenários documentados + bateria manual + iteração rápida descobriu mais + bugs em 1 dia do que toda a auditoria anterior. Manter esse loop e + automatizá-lo (R11) é o investimento de maior alavancagem. +
+ ++ O risco maior não é o que já encontramos — esses estão + consertados. É o que ainda não foi exercitado em Rail e Clínica. A janela + para consolidar antes de replicar é agora. +
+ ++ A boa notícia: a base é sólida. Os bugs encontrados foram de execução, + não de design. As decisões arquiteturais maiores (SimplePractice-style + invariantes, status change centralizado, audit trail em notes, separação + avulsa/pacote) provaram-se corretas em uso real. O trabalho + é polir, não reescrever. +
+ +| # | +Bug | +Severidade | +Commit | +
|---|---|---|---|
| 1 | +Cobrança dupla em multa: _applyStatusDecisions inseria
+ multa mas deixava original pending |
+ Crítico | +d6423da |
+
| 2 | +'fixed' vs 'fixed_fee' off-by-key em
+ calcChargeAmount |
+ Médio (dormente) | +d6423da |
+
| 3 | +Label "Como cobrar?" com options "Já recebi" misturadas — usuário + marcou paid achando que era cobrar | +Alto UX | +079509e |
+
| 4 | +billing_contracts.updated_at inexistente causando
+ UPDATE silently falhar em Promise.allSettled |
+ Crítico | +16dfa02 |
+
| 5 | +Reverse transitions deixavam multa órfã (faltou→agendado) | +Alto | +5684297 |
+
| 6 | +consumeSaldo não amarrava billing_contract_id
+ ao evento |
+ Alto | +3f3f2ac |
+
| 7 | +Badge $ amber em sessão cancelada | +Médio | +753182c |
+
| 8 | +paymentLabel usava ev.price em vez de
+ paymentAmount para pending |
+ Médio | +753182c |
+
| 9 | +"Gerar fatura" disponível em sessão encerrada | +Alto | +753182c |
+
| 10 | +_reloadRange não destruturado em
+ _buildHandlers(deps) |
+ Médio | +753182c |
+
| 11 | +Faltou+multa-sem-consume não amarrava
+ billing_contract_id |
+ Médio | +5965b05 |
+
| 12 | +Re-antecipar reutilizava record cancelled (audit trail confuso) | +Alto | +b5e00a7 |
+
| 13 | +Popover snapshot stale após materialização virtual→real | +Alto | +b5e00a7 + f83315b |
+
| 14 | +normalizeForMelissa não expunha owner_id
+ → INSERT null violation |
+ Crítico | +7d2a405 |
+
project_c12_antecipar_iterar — iterar UX da antecipação (deferido pelo user)project_melissa_popover_snapshot — refator pra computed (mitigado mas não estrutural)project_billing_contracts_no_updated_at — gotcha documentado, fix em R2project_pendencia_doc_ajuda — doc completa para área de ajuda pós Fase 94da0bc2 HANDOFF + log: C12 deferred · testando C13
+f83315b agenda: popover watch acompanha transicao virtual->materializada
+7d2a405 agenda: normalizeForMelissa expoe owner_id/tenant_id/contract_id
+b5e00a7 agenda: popover sincroniza com eventos + antecipar nao reusa cancelled
+272c804 agenda: revogar antecipacao de pagamento
+00c4168 agenda: C12 prep — detectar paid pre-existente em pacote saldo realizada
+9ead3fd HANDOFF + log: C11 fechado · 4/4 sub-testes OK · proximo C12
+5965b05 agenda: link universal pacote + refresh saldo no reverse
+45984e8 agenda: label + badge cientes de pacote em sessoes state=none
+3f3f2ac agenda: consumeSaldo agora amarra billing_contract_id no evento
+5684297 agenda: reverse transition trava (Agendada apos artefatos)
+16dfa02 agenda pacote saldo: fix root cause + sequential awaits
+079509e agenda: dialog pacote saldo realizada — 2 sub-questions claras
+7dc7dce wiki: log session C10 fechado completo
+1e74a11 HANDOFF: C10 fechado · 5/5 sub-testes OK · proximo C11
+753182c agenda: C10 pos-test fixes + lock sessao encerrada + addendum doc
+3caf579 agenda popover: botao Agendada + fixes pos-C10/B
+d6423da agenda: pre-C10 fix _applyStatusDecisions cancela pendingRecord
+
+ | # | Cenário | Persona testada | Status |
|---|---|---|---|
| C1–C9 | Bloqueio, avulsas, recorrência, pacote, per_session | Melissa | OK (anteriormente) |
| C10 | Status change avulsa (5 sub-testes) | Melissa | OK |
| C11 | Status change pacote saldo (4 sub-testes) | Melissa | OK |
| C12 | Antecipar pagamento | Melissa | DB OK · UX a iterar |
| C13 | Edit cobrada (imutabilidade) | Melissa | Em teste agora |
| — | Rail (AgendaTerapeutaPage) | Rail | Pendente — após refator |
| — | Clínica (AgendaClinicaPage) | Clínica | Pendente — após refator |
src/docs/agenda-compromisso-financeiro-cenarios.html — doc vivo dos 13 cenários (com addendum C10)HANDOFF.md — estado de continuidade da sessãoObsidian/Brain/log.md — log cronológicoObsidian/Brain/wiki/agenda-compromisso-fluxo.md — fluxo conceitual~/.claude/projects/.../memory/MEMORY.md — índice de memórias persistentes