manual/f6_3_drop_public_tenant_tables.supabase_admin.sql — ponto de nao-retorno,
revisar antes de aplicar:
- pre-flight assert (tenants=schemas, 78 tabelas, 6 anon NAO no template)
- 2 FKs public->tenant viram coluna solta (document_share_links.documento_id,
whatsapp_credits_transactions.conversation_message_id)
- dropa 9 views public (6 recriadas por schema + 2 dead + v_twilio item#1)
- DROP CASCADE das 78 tabelas (derivado de _tenant_template; dados ja nos schemas)
- limpa financial_records_inject_tenant (obsoleto)
ITENS EM ABERTO verificados (16 reads FE remanescentes, TODOS na superficie
SaaS-admin ja flagada na F3): SaasFeriadosPage (feriados defaults),
SaasNotificationTemplatesPage (templates default), SaasWhatsappPage +
v_twilio_whatsapp_overview/getAllChannels (whatsapp admin cross-tenant).
Resolver (apontar pra _tenant_template ou fan-out por schema) ANTES do DROP.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- attach_agnostic_triggers reescrito SELF-CONTAINED (dirigido por colunas: set_
updated_at em toda tabela com updated_at + prevent_* em patient_groups). Nao
le mais de public -> sobrevive ao DROP da F6.3.
- trigger AFTER INSERT em tenant_schemas (trg_attach_business_triggers) dispara
os 3 attach (agnostic + schema_aware + notif) pro schema novo. clone_tenant_
template nao precisou ser tocado (ele insere em tenant_schemas). GRANT EXECUTE
dos attach pra postgres/service_role.
- provision_account_tenant: clone ANTES do seed (seed_determined_commitments e
no-op se schema nao existe; precisa do schema criado primeiro)
Smoke: tenant novo nasce com 84 triggers automaticamente (vs 81 nos existentes,
que sao mais que suficientes). Provision order corrigida.
App agora testavel: dados nos schemas (F6.1) + funcoes/triggers/RPCs roteiam
(F6.2). Falta so F6.3 DROP (com OK + app testado).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
DB (supabase_admin, manual/f6_2e_cron_rpcs.supabase_admin.sql):
- E2 (varrem TODOS os tenants via loop FROM tenant_schemas): cleanup/unstick_
notification_queue, sync_overdue_financial_records (EXECUTE format por schema),
populate_notification_queue (set_config search_path por tenant; profiles global)
- E1 (per-tenant via service_role): novo helper _tenant_schema_unchecked (sem
is_tenant_member — service_role nao e membro; REVOKE de anon/authenticated).
sla_open_breach, sla_mark_notified(+p_tenant_id), whatsapp_heartbeat_open_
incident/mark_notified/resolve(+p_tenant_id). convert_abandoned_intake_to_lead
resolve tenant internamente (intake public/F1b -> writes no schema).
first_response_stats/_runs: _tenant_route (user-facing, frontend ja passa
p_tenant_id); _first_response_runs computa thread_key (coluna nao existe).
- REVOKE das RPCs de servico de anon/authenticated; GRANT service_role
Edge: whatsapp-heartbeat-check (tdb.rpc->admin.rpc + p_tenant_id nos heartbeat
RPCs), conversation-sla-check (sla_mark_notified + p_tenant_id).
Gotchas: (1) service_role nao e tenant_member -> helper unchecked + REVOKE;
(2) conversation_messages nao tem coluna thread_key (computar); (3) DROP+CREATE
de nova assinatura precisa dropar ambas p/ idempotencia.
Smoke: E2 sync_overdue 13 across tenants; E1 sla_open_breach roteia; first_
response_stats user OK.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Aplicado como supabase_admin (trigger functions sao owned por supabase_admin).
14 funcoes reescritas pra operar no schema do TG_TABLE_SCHEMA (set_config
search_path dinamico + tenant_id_for_schema p/ tabelas globais audit_logs):
log_audit_change, trg_fn_patient_status_history/timeline/risco,
auto_create_financial_record_from_session, fn_sla_resolve_on_outbound,
fn_clinical_note_version, fn_document_signature_timeline,
fn_documents_timeline_insert, sync_legacy_email/phone_fields,
fn_agenda_regras_semanais_no_overlap, patients_validate_member_consistency.
sync_busy_mirror_agenda_eventos: cross-tenant via tenant_schema_for +
EXECUTE format (espelha "Ocupado" nos schemas das clinicas).
financial_records_inject_tenant: obsoleto, nao anexado nos schemas.
Detach dos 14 schema-aware das tabelas tenant em public (quebrariam la);
attach_schema_aware_triggers recria 22 triggers/schema (defs reais, tenant_id
removido de WHEN/UPDATE OF). agenda_cfg_sync e trg_fn_financial_records_auto_
overdue (agnosticos) ficam em public E nos schemas.
Smoke: sessao->realizado cria financial_record (R$250) no schema + marca billed;
audit roteia tenant_id correto; patient status muda -> timeline no schema.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
attach_agnostic_triggers(schema) recria nos schemas os triggers de public cuja
funcao e provadamente schema-agnostica (so mexe em NEW/OLD): familia updated_at
(8: set_updated_at, fn_clinical_notes_updated_at, set_insurance_plans/medicos/
services_updated_at, set_updated_at_recurrence, update_payment_settings/
professional_pricing_updated_at) + prevent_promoting_to_system +
prevent_system_group_changes. Backfill dos 9 (54 triggers/schema). Smoke:
set_updated_at dispara no schema. Schema-aware vem no Lote B; wiring no clone
no fim da F6.2
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- F6.0 (migration): clone_tenant_template pros 9 tenants existentes (schemas
vazios; dispara trigger F5 -> expostos no PostgREST)
- F6.1 (manual supabase_admin): copia dados public -> schemas com
session_replication_role=replica (desabilita FK check, so supabase_admin).
Tabelas com tenant_id por filtro; 3 filhas sem tenant_id (commitment_services,
insurance_plan_services, recurrence_rule_services) por JOIN no pai; exclui
colunas GENERATED (net_amount, margin_brl); reset de 4 sequences; ON CONFLICT
DO NOTHING (idempotente). Dados continuam em public (DROP so na F6.3)
- Verificado: contagens public vs schemas batem (35 patients, 37 eventos,
355 mensagens, 54 financeiro...); seeds default replicados por schema
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- manual/f5_pgrst_refresh_schemas.supabase_admin.sql: refresh_pgrst_schemas()
(owned supabase_admin, postgres nao e superuser neste stack) seta
pgrst.db_schemas in-database na role authenticator a partir de tenant_schemas
+ NOTIFY pgrst reload config/schema. Expoe/retira schema SEM restart; GUC
persiste entre stop/start
- migration 20260613000002: trigger em tenant_schemas dispara o refresh a cada
clone/drop (clone/drop nao precisam ser tocados)
- config.toml: baseline public,graphql_public + comentario explicando que a
config in-db supersede em runtime
- E2E testado via HTTP: clone -> pgrst.db_schemas inclui tenant_x -> REST
Accept-Profile retorna 200 (vs 406 schema inexistente); drop -> volta 406.
Sem restart de container
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fluxos anon identificam tenant por token/slug e nao resolvem o schema fisico.
Decisao (opcao C): manter em public com RLS por token. Volta a global:
patient_intake_requests, patient_invites, patient_invite_attempts,
document_share_links, agendador_configuracoes, agendador_solicitacoes.
- migration 20260613000001_f1b: remove as 6 do _tenant_template (template v2,
78 tabelas). Smoke: clone gera 78, zero tabelas anon no schema, drop limpo
- frontend: 38 cadeias em 14 arquivos revertidas tenantDb().from() ->
supabase.from() com tenant_id/owner_id restaurado (via comparacao com main)
- edge: convert-abandoned-intakes restaurada do main (SELECT global)
- save-intake-progress: ja usava public, sem mudanca
- doc F0 atualizado: 78 tenant + 59 global
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- _shared/tenant.ts: helper (adminClient, tenantDbForId, schemaForTenant,
listTenantSchemas, resolveTenantByChannel, tenantSchemaName)
- _shared/whatsapp-hooks.ts: hooks de tabela tenant recebem tdb; RPCs de
credito (deduct/add_whatsapp_credits) e tenant_members seguem em supa+p_tenant_id
- inbound (twilio/evolution): tenant_id da URL -> tdb pra conversation_messages
e notification_channels
- crons de fila (process-notification/email/sms/whatsapp-queue): varrem
listTenantSchemas e drenam a fila de cada schema (Q3: filas sao per-tenant);
modo single-tenant se body.tenant_id vier
- crons reminders/checks (send-session-reminders, conversation-sla-check,
whatsapp-heartbeat-check, convert-abandoned-intakes, sync-email-templates):
loop por tenant
- routing por tenant_id (send-whatsapp-message, send-session-reminder-manual,
twilio-provision, de/reactivate-channel, twilio-webhook): tenantDbForId;
channel-actions sem tenant_id varrem schemas por channel_id
- asaas-*: tenant_id do body -> tdb; asaas-webhook fica global (whatsapp_credit_purchases)
- notification-webhook (Meta): resolve tenant via channel_routing por phone_number_id,
fan-out por message_id quando nao resolve
- caller send-session-reminder-manual passa tenant_id (evento vive no schema)
Pendente: save-intake-progress e fluxos anon por token (decisao de roteamento)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sessao completa de ~14 commits. 2 grandes blocos:
BLOCO 1 — Melissa UI overhaul: tray bottom-right (substitui topbar
band), mobile collapse parcial em <md, busca global unificada
(MelissaBusca ganha "Ir para [data]", popover da agenda deletado),
dock com 4 builtins, hero resumo com cancelado/remarcado, settings+
ajuda click-outside, cronometro evento-aware (botao ⏱ na timeline +
sessionPlan + confirm fechar), documents edit in-place via
document_generated.documento_id, wire-up dos 5 botoes do preview.
BLOCO 2 — 5 docs saas novas (03-07 em development/saas-docs/) +
SQL imports + 60 FAQs total. Cobertura: aba Documentos paciente,
pagina Templates, Assinatura eletronica, Emissao de recibo
profissional, Relatorios + 3 formatos de export.
Memorias adicionadas:
- feedback_tailwind_utility_load_order (hidden perde pra CSS base
do componente por ordem de carga Vite)
- project_documents_reedit_in_place (linkage documento_id + editingDocId)
PROXIMA SESSAO (23/05): Fase 6 restante (C12 antecipar UX iter —
unico item de codigo da lista de ontem), Fase 7 restante (regressao
Agenda C7-C13, validacao manual). Antes/depois: panorama MVP no
ROADMAP canonico — ainda restam #12 papel timbrado, #15 NFS-e,
§1.5 Sentry, Asaas Fase B, M4 cutover, validacao centralizada
de forms.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Doc 07 cobrindo a pagina de Relatorios + 3 formatos de exportacao:
- Layout 2-col (sidebar stats+filtros, main grafico+tabela)
- 4 periodos (semana/mes/3m/6m), agrupamento auto (dia vs week ISO
vs month ISO)
- 5 KPIs clicaveis como filtros (total/realizadas/faltas/canc/remarc)
- Grafico Chart.js com cores por status
- DataTable paginada + status com tag colorida
- Export PDF (HTML->PDF A4, KPIs + tabela)
- Export Excel XLSX (exceljs dinamico, frozen header, alternating
rows, branded, formatos data+currency)
- Export CSV (vanilla, BOM UTF-8, separador ; pt-BR)
- Filtros aplicados na tela respeitados na exportacao
- Nome do arquivo com timestamp pra evitar overwrite
- Notas dev: reportExport.service.js, pdf.service, exceljs lazy load
12 FAQs: como ver, periodos disponiveis, exportar PDF/Excel/CSV,
quando usar qual formato, filtros respeitados, formulas, agrupamento
do grafico, filtrar por paciente, ver outro terapeuta, nome do
arquivo, exportacao agendada (pendente).
categoria='Relatórios', pagina_path='/melissa/relatorios', ordem=7.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Doc 06 cobrindo o quick path de emissao de recibo:
- Quando o botao aparece (AgendaEventoFinanceiroPanel com record
status=paid)
- O que vem auto-preenchido (paciente, sessao, valor, forma pgto,
terapeuta+registro formatado, clinica+CNPJ, data)
- Registro profissional generico — CRP/CRM/CRFa/CREFITO/CRESS/CRN/
Outro (variavel terapeuta_registro auto-formata)
- Valor por extenso (helper valorExtenso.js, ate 999 milhoes)
- Onde fica salvo (download + aba Documentos categoria 'Recibo')
- Quick path emitirReciboParaSessao() vs flow manual de Gerar
- Notas dev: service, helper, mapping, migration do template,
localizacao do botao
12 FAQs cobrindo casos comuns: emitir recibo de sessao paga, por
que botao nao aparece, valor por extenso correto, suporte multi-
conselho, onde salva, recibo avulso, CRP vazio, CNPJ formatado,
corrigir valor, enviar pra assinar, data sessao vs emissao,
reemitir.
categoria='Financeiro', pagina_path='/melissa/agenda', ordem=6.
SQL import em database-novo/tmp/import-doc-recibo-profissional.sql.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Doc 04 cobrindo a pagina de gestao de templates:
- Globais (sistema, read-only) vs Tenant (seus, editaveis)
- Lista em grid com cards + badge "padrao" pros globais
- Preview de template global (iframe sandbox A4) + botao Duplicar
- Criar novo template (nome/tipo/desc/cabecalho/corpo/rodape)
- Editor rich-text com menu de variaveis (insere {{nome_var}})
- Lista de variaveis disponiveis (paciente/terapeuta/clinica/sessao/geral)
- Mobile drawer pros templates
- Duplicar (cria copia em "Seus templates" com sufixo "(copia)")
- Desativar (soft-delete, docs antigos continuam acessiveis)
- Mapeamento tipo template -> categoria do doc gerado
12 FAQs: pra que serve, por que nao edita padroes, como usar variavel,
quais variaveis, recuperar desativado, duplicar pra personalizar,
global vs tenant, imagens (logo/assinatura), cabecalho/rodape em todas
as paginas, variaveis obrigatorias, limites, compartilhamento entre
terapeutas do mesmo tenant.
categoria='Documentos', pagina_path='/melissa/documentos-templates',
ordem=4. SQL import em database-novo/tmp/import-doc-documentos-
templates.sql.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
DocumentPreviewDialog emitia @download/@edit/@share/@sign/@delete que
o MelissaPatientDocuments nao ouvia — os 5 botoes da sidebar do preview
caiam no vazio. Adicionado wire-up roteando pros mesmos handlers do
card (onDownload, onEdit, onShare, onSign, onDelete). Share/sign/delete
fecham o preview antes de abrir o proprio dialog pra UX limpa; download
mantem preview aberto (acao instantanea).
DocumentGenerateDialog ganha prop editing-doc-id. Quando setado:
- Busca template_id + dados_preenchidos via loadGeneratedFromDocId
- Pre-seleciona template, popula vars (sobrescreve auto-loaded vars
com dados_preenchidos pra preservar customizacao anterior)
- Pula direto pra step 'edit'
- Save vira UPDATE in-place (preserva documents.id e audit trail)
- Header muda pra "Editar documento" + icone pi-pencil amber
- Botao final vira "Substituir documento"
- Doc sem registro generated (legado): toast info + flow normal de
select template; ao salvar, cria o registro generated linkado.
MelissaPatientDocuments:
- onEdit substituido (era shortcut pra onPreview): abre generate dialog
com editing-doc-id setado.
- Novo ref editingDoc dedicado (separado do selectedDoc que serve
preview/share/sign/delete) pra evitar vazar "edit state" pro botao
"Gerar" do header quando user so abre preview e fecha.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
document_generated.documento_id (FK pra documents) estava sempre NULL
no INSERT — sem isso nao da pra rastrear qual generated belongs to
qual documents row, impossibilitando re-edicao.
DocumentGenerate.service saveGeneratedDocument:
- Modo create (default): INSERT em documents PRIMEIRO pra capturar
doc.id, depois INSERT em document_generated com documento_id setado.
- Modo edit (editingDocId param novo): UPDATE in-place — substitui
PDF no Storage (novo path), atualiza bucket_path/tamanho/nome em
documents (preserva id+audit), atualiza dados_preenchidos+pdf_path
em document_generated. Se nao houver registro generated (doc legado),
INSERT vinculando ao documents.id. Cleanup best-effort do PDF antigo.
- Nova fn loadGeneratedFromDocId(documentoId): busca template_id +
dados_preenchidos pra pre-popular o dialog de edicao.
useDocumentGenerate.generateAndSave: ganha 2o param editingDocId que
passa pro service.
Backfill SQL pra docs antigos: match dg.pdf_path = d.bucket_path +
tenant/patient guard. 3 docs linkados no DB local, 5 ficaram orfaos
(paths que nao existem mais em documents — cleanup antigo).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Script usado pra importar a doc 02-cronometro-melissa.json
diretamente no banco via psql (mesmo padrao da doc Busca global).
DO block com dollar quoting ($HTML$ e $FAQ$) pra evitar escape hell
no HTML conteudo + nos FAQs.
Importacao executada em 2026-05-22. Doc id=e87d4d33-7f5c-454e-a2ff-
0f92505b7c3c + 12 FAQ itens vinculados.
Path: database-novo/tmp/import-doc-cronometro.sql — pasta tmp pra
artefatos de operacao (nao parte do schema canonico).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Doc JSON com 10 secoes cobrindo: 3 jeitos de abrir (hero, timeline,
card proximo paciente), pre-selecao + autostart via evento, exibicao
de programado/atraso (sessionPlan), anatomia do dialog, minimizar
(chip no dock), parar (salva DB) vs fechar (descarta com confirm),
toque no fim, persistencia localStorage, regra "um cronometro por
vez", atividade livre sem paciente, mobile (chip sem nome).
12 FAQs incluindo o caso de uso central (Larissa chegou agora),
comportamento do X com sessao rodando, cronometro multi-aba,
significado do badge 'atrasada Xmin', etc.
categoria='Sessão', pagina_path='/melissa', ordem=2 (busca era 1).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tray no canto inferior direito (substitui o topbar band do topo):
busca + plan-DEV + bell + ajuda + cog. Sibling de .melissa-dock
(fora de .win11-summary) pra ficar sempre interativo mesmo com
secao aberta (que aplica blur+pointer-none). z-index 66 (acima
do dock=65). Em <md (768px) collapse parcial — bell/help/cog/
plan-DEV somem e viram popup vertical no botao ⋮; dot vermelho
no ⋮ quando ha notificacoes nao lidas. Search sempre visivel.
Dock: 4 builtins na ordem Agenda · Pacientes · WhatsApp · Financeiro
(antes so Agenda+WhatsApp). MRU (max 3) ganha @media (max-width:
767px) display:none — utility 'hidden' do Tailwind perdia pro
.dock-pin{display:grid} por ordem de carga. Divisor entre builtins
e pins user some em mobile se so houver MRU (que ja esta oculto).
Wire-ups das commits anteriores:
- ref melissaBuscaRef + provide('openMelissaBusca') pra acoes
contextuais futuras (botao tray chama direto via ref)
- @goto-date no <MelissaBusca> -> onBuscaGotoDate via _callOnAgenda
- @iniciar-cronometro no <MelissaTimelineHoje> -> handler que abre
o cronometro com sessionPlan + autostart; opcao (b) "ja ativo"
mostra toast warn sem trocar paciente
- Card "Proximo paciente" troca CTA pra "Iniciar cronometro" quando
emCurso E tem patient_id; @open chama o mesmo handler do timeline
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
MelissaCronometro.abrir() agora aceita opts { pacienteId, autostart,
sessionPlan }. Retorna { opened, alreadyRunning, samePaciente, ... }
pra caller decidir o feedback. Estado sessionPlan { startH, endH }
exibe "Programado: HH:MM – HH:MM" sob o select + badge laranja
"atrasada Xmin" quando hNow > startH. Cronometro NAO auto-ajusta —
analista decide quando comecar/parar. Tick a 30s atualiza atraso.
sessionPlan persiste no localStorage junto com o snapshot.
X agora dispara confirmarFechar(): pede ConfirmDialog quando ha
sessao em andamento OU tempo decorrido nao salvo; fecha direto se
clean. Tooltip mudou pra "Encerrar sem salvar".
Chip minimizado: nome do paciente fica display:none em <md (mobile)
pra nao estourar largura do dock — icone + timer cobrem o essencial.
MelissaTimelineHoje: botao ⏱ overlay no canto sup. direito das pills
(horizontal + vertical) quando ev esta em curso E tem patient_id.
Pulso emerald sutil pra chamar atencao; @click.stop pra nao abrir
o evento. Novo emit iniciar-cronometro(ev).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
MelissaBusca ganha parser de data ('hoje', 'amanha', 'ontem',
DD/MM/YYYY) e card destacado azul "Ir para [data]" como primeiro
item do flatList. Quando query parseia como data, pula a RPC
search_global (nao busca paciente com nome '20/06'). Enter sem
selecao explicita pega o primeiro item — UX spotlight padrao.
Novo emit goto-date(date) capturado em MelissaLayout via helper
_callOnAgenda que abre a agenda se fechada e chama gotoDate exposto
pela MelissaAgenda (alias pro onBuscaGotoDate existente).
MelissaAgenda perde o popover proprio (MelissaAgendaSearchPopover
deletado), o ref searchPopover, o hotkey Ctrl+K local e
onBuscaSelectEvento. Ctrl+K agora vive so na MelissaBusca — evita
dois listeners no mesmo atalho. MelissaBusca expoe openDialog via
defineExpose pra a lupa do tray chamar.
MelissaPacientes: comment update mencionando o tray.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Acrescenta sufixo "(x foi cancelado, x foi remarcado)" depois do chip
de atendimentos quando ha sessoes nesses status em eventosHojeReais.
Sufixo nao-clicavel, peso menor pra nao competir com o link do total.
Pluralizacao gramatical (1 foi / 2+ foram).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Popover Personalizar (cog) e drawer de Ajuda agora fecham quando o
user clica em qualquer lugar fora do panel. Listener mousedown em
capture, watch em open pra anexar/desanexar; ignora o proprio botao
trigger (data-ajuda-toggle pro ajuda; cogBtnEl ref pro settings) pra
nao fazer close+reopen. Tambem flipa o panel do settings de top-12
pra bottom-12 (cog agora vive no bottom da .melissa-tray).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 commits em paciente.documentos e documents/generate. Bug raiz dos
"campos vem vazios": isFinite(null) global retorna true, null.toFixed
crashava em loadAllVariables. Trocado por Number.isFinite (strict).
Proxima sessao retoma de Fase 2 (2.7-2.9 gerar PDF dentro da aba
Documentos do paciente).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
loadVariables falhava com TypeError quando nao havia sessao
vinculada (agendaEventoId=null) E o user nao passava extras.valor.
Stack: 'Cannot read properties of null (reading toFixed)'.
Causa: usei isFinite() global em vez de Number.isFinite():
isFinite(null) => true (coerce: Number(null) === 0)
Number.isFinite(null) => false
Como isFinite(null) retorna true, o codigo entrava no branch
`valorNum.toFixed(2)` e crashava. Com isso, loadAllVariables
inteiro estourava e variables.value zerava — explicando os
inputs todos vazios mesmo com paciente/perfil/clinica preenchidos.
Fix: trocar isFinite por Number.isFinite (versao strict, nao
coerce null/undefined/string).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
User reportou que mesmo com profile/paciente/clinica preenchidos
os campos do dialog continuam vazios. Pra diagnosticar:
- Promise.all -> Promise.allSettled: nao mascara falha individual
- console.error por source que falhou (patient/session/therapist/clinic)
- console.log com payload completo em dev mode (ownerId, tenantId,
patientId, agendaEventoId, valores carregados, errors)
Depois de identificar a causa esses logs ficam ou viram telemetria
estruturada.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dois problemas reportados no dialog "Gerar documento":
1. Inputs usavam <label> + <InputText> simples, fora do padrao
FloatLabel adotado no resto do app.
2. Quando o auto-preenchimento vinha vazio o user nao tinha onde
ir cadastrar o dado.
Mudancas:
- TEMPLATE_VARIABLES ganha campo `source` em cada entrada com a
descricao de onde o dado eh cadastrado (ex: "Perfil -> Registro
Profissional"). Map canonico no DocumentTemplates.service.js.
- DocumentGenerateDialog refatorado:
* FloatLabel variant="on" em todos os inputs
* Banner no topo com contagem "X de Y preenchidos" (verde se 100%,
amber se faltam dados)
* Hint (`pi pi-link` + texto source) embaixo de cada campo vazio
apontando onde cadastrar
* Erro de carregamento renderizado dentro do step edit
* Input ganha `invalid` quando vazio (borda destaque)
- useDocumentGenerate.loadVariables:
* console.error em caso de excecao (era engolido em silencio)
* mensagem amigavel quando loadAllVariables retorna tudo vazio
(caso comum quando paciente/perfil/clinica estao incompletos)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drawer teleportado pro body perdia as vars --m-* (definidas em
.win11-root no MelissaLayout), caia nos fallbacks hardcoded (#1a1d2e)
e ficava mais escuro que o resto do tema.
Fix:
- Wrapper .mpd-drawer-portal recebe class win11-root pra trazer as
vars --m-* pro escopo teleportado.
- Vars locais --mpd-bg/--mpd-border/--mpd-text com cascata:
--m-* (win11-root) -> --p-* (PrimeVue global) -> hardcoded.
Respeita dark/light automaticamente.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>