Templates de documentos sao "setup", nao operacao diaria — deveriam
viver em Configuracoes, nao no menu de Documentos do paciente.
Mudancas:
1. Melissa — melissaConfigGrupos.js ganha grupo "Documentos" com
1 item "Modelos de documentos" -> slug `documentos-templates`
(pagina nativa MelissaDocumentosTemplates ja existe + ja esta
wired no MelissaLayout linha 2896).
2. Rail/Classic — routes.configs.js ganha rota
/configuracoes/documentos/templates (name=ConfiguracoesDocumentos
Templates) apontando pro mesmo DocumentTemplatesPage.vue.
3. Rotas antigas removidas — routes.therapist.js e routes.clinic.js
nao tem mais /documents/templates nem nomes de rota
therapist-documents-templates / admin-documents-templates.
URLs antigas dao 404 (decisao do user — limpa).
4. ConfiguracoesPage (sidebar Rail/Classic) ganha grupo
"Documentos" antes do "Empresa & Plataforma" com item "Modelos
de documentos".
5. Menus de pacientes (therapist.menu + clinic.menu) NAO tem mais
"Templates" — caminho de acesso e Configuracoes.
6. pagesIndex.js (busca global) atualizado: novo path, novos
keywords (recibo, atestado, laudo, tcle, lgpd, consent), roles
['therapist','admin'].
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ROADMAP #1.2 #7 — Assinatura eletronica no portal.
Migration 20260521000007 cria RPC list_my_signatures (SECURITY DEFINER)
que cruza auth.uid() por 3 caminhos (signatario_id, signatario_email,
patient.user_id) e devolve solicitacoes pendentes + share_token pra
link de assinatura. service.listMySignatures wrappa a RPC.
Composable useDocumentSignatures ganha loadMine().
PortalDocumentos.vue (nova) — lista signatures do paciente logado com
KPIs (total/pendentes/assinados/recusados), filtro, e botao "Assinar
agora" que navega pra /shared/document/:token. Item no portal.menu
"Documentos > Para assinar".
SharedDocumentPage.vue estendida: agora chama getSignableDocumentBy
Token primeiro (RPC nova). Quando o documento tem signatures pendentes,
mostra painel azul abaixo do preview com:
- Aviso LGPD/CFP explicando o que sera registrado (IP/UA/timestamp/hash)
- Checkbox aceite obrigatorio
- Selecao de signatario quando multi-signatario
- Botoes Assinar/Recusar com loading state
- Computacao SHA-256 server-fetched antes do click
Fluxo: terapeuta gera doc -> cria signature + share_link -> link e
listado em /portal/documentos -> paciente clica -> /shared/document/
:token mostra doc + painel -> aceite -> assinatura registrada via RPC
sign_document_by_token (IP/UA capturados server-side).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Modulo 5 da Fase 1 + quick wins fechados. features/tenantship/ com
2 services + 2 composables (members + invites). MembersPage.vue
nova em views/pages/admin/ + rota /admin/members em routes.clinic.
Migration 20260520000005 cria RPC accept_tenant_invite (SECURITY
DEFINER + lock FOR UPDATE) — tenantInvitesRepository.acceptInvite
agora chama RPC real (nao mais stub). SaasTenantFeaturesPage
refatorada pra usar novo tenantFeatureAdminService. SetupWizardPage
2648 linhas deferido pra sessao dedicada.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>
Sai do estado "preview/sandbox" e liga o Melissa como layout real
ativavel pelo user em Configuracoes -> Profile.
Mudancas:
- routes.misc.js: /preview/melissa/:secao? -> /melissa/:secao?,
nome PreviewMelissa -> Melissa. Sem alias por compat (autorizado).
- router/index.js: novo beforeEach apos o supportGuard e antes do
applyGuards. Quando to.name e' therapist.dashboard ou admin.dashboard
E localStorage.layout_variant === 'melissa' E viewport >= 1280px,
redireciona pra { name: 'Melissa' }. Le do localStorage (gravado pelo
bootstrapUserSettings + setVariant) pra evitar esperar store do DB e
evitar flash do shell antes do redirect. Bypassa mobile pq Melissa
nao foi feito pra <xl e o effectiveVariant ja forca 'classic' la.
- MelissaLayout.vue: 2 chamadas router.push apontavam pra
'PreviewMelissa', agora 'Melissa'. Header doc atualizado.
- useMelissaPacientes.js: comment doc citando /preview/melissa
generalizado pra "sem session retorna vazio".
- ProfilePage.vue: card Melissa perde badge "Em construcao" e ganha
badge "Beta". Texto explicativo perde "navegacao completa ainda
nao esta integrada" e ganha "Ao salvar, sua proxima entrada na
home cai direto no Melissa". Link /preview/melissa -> /melissa.
Remove regra CSS .lv-card--wip orfa.
Tradeoff aceito: rotas especificas (/therapist/agenda etc.) seguem
no shell classico/rail. So a HOME do role e' interceptada pra /melissa.
Coerente com o desenho atual do MelissaLayout, que ja abre Agenda /
Pacientes / etc. como overlays internos via deep-link /melissa/<secao>.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Roteamento por URL (substitui o ref local secaoAberta):
- routes.misc.js: rota vira /preview/melissa/:secao? — param opcional
- MelissaLayout.vue: secaoAberta agora e computed do route.params.secao,
validado contra SECOES (chave invalida -> null). abrirSecao/fecharSecao
fazem router.push em vez de mutar ref. Habilita back/forward, refresh
e deep-link tipo /preview/melissa/agenda.
Pagina Pacientes (WIP, ainda nao wireada no slot do Layout):
- src/layout/melissa/MelissaPacientes.vue (novo, ~? linhas) — fullscreen
3-col espelhando MelissaAgenda: aside esquerda com filtros (status /
grupos / tags), lista central com cards + busca, quick view direita
com KPIs do paciente selecionado + acoes.
- Carrega pacientes (todos os status), grupos/tags do tenant, vinculos
patient_groups + patient_tags + session counts em paralelo.
- Integra PatientProntuario (overlay), PatientCadastroDialog,
PatientCreatePopover + ComponentCadastroRapido, e
conversationDrawerStore (acao WhatsApp da quick view).
useMelissaPacientes ganha opcao { onlyActive }:
- default true (compat com cards do resumo / cronometro / eventos hoje
— so faz sentido com ativos)
- false retorna Ativo + Inativo + Arquivado, pra uso na pagina nova
- select agora inclui data_nascimento (necessario pros KPIs da quick view)
Cronometro: zera ao parar — terminou a sessao, fica pronto pra proxima
sem precisar reabrir o popover.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bot que coleta nome, motivo de busca e preferências ANTES do paciente
entrar no fluxo humano. Terapeuta abre a conversa e já encontra
resumo em conversation_notes.
Banco (migration 20260423000007):
- conversation_bots: config 1 por tenant. enabled, greeting/closing
messages, steps (JSONB array de {prompt, variable, type}), trigger_mode
(new_contact | all_unassigned | keyword), trigger_keywords[],
idle_timeout_minutes, respect_optout.
Defaults vêm com 4 perguntas úteis: nome, motivo, modalidade,
horário preferido.
- conversation_bot_sessions: estado por thread. current_step,
collected_data JSONB, status (active | completed | abandoned_idle |
abandoned_manual | opted_out). UNIQUE parcial garante 1 ativa por
(tenant, thread).
- RLS: leitura tenant/saas_admin, escrita admins (config) + service_role
(sessions, só edge altera).
Shared (_shared/whatsapp-hooks.ts):
- maybeProcessBot: carrega config, busca sessão ativa, avança step
com resposta, envia próxima pergunta via SendFn. Ao esgotar steps,
envia closing + cria conversation_notes com resumo das variáveis
coletadas. Se humano assume (conversation_assignments preenchido),
sessão marca 'abandoned_manual' e bot sai.
- Trigger modes:
- 'new_contact' (default): só inicia pra thread sem histórico bot
E sem paciente vinculado (lead real).
- 'all_unassigned': qualquer thread sem assignee.
- 'keyword': matched contra lista; normalizeForMatch já existe.
Integração nos inbound (ambos providers):
- evolution-whatsapp-inbound: chama maybeProcessBot após opt-in/opt-out,
ANTES do auto-reply. Se bot processou, skip auto-reply (senão duas
respostas sobrepostas).
- twilio-whatsapp-inbound: idem, usando makeTwilioCreditedSendFn pra
cobrar crédito de cada mensagem enviada pelo bot.
UI (/configuracoes/conversas-bots):
- Toggle enabled + Select trigger_mode + (se keyword) chips de keywords.
- Textareas greeting/closing.
- Editor de steps: reordenar (up/down), remover, add, editor com prompt
e variable (regex /^[a-z_][a-z0-9_]*$/).
- Botão "Padrão" restaura mensagens/steps default.
- InputNumber idle_timeout + toggle respect_optout.
- Card inferior: últimas 30 sessões (7 dias) com status, contato,
nome coletado (primeiro campo), progresso (step X/N), início.
- Entrada na landing de configurações + rota /configuracoes/conversas-bots.
Caveat conhecido: a resolução de conversation_notes.created_by usa
o primeiro admin ativo do tenant (pickAnyAdmin). Pra uma v2 seria
ideal ter um user "bot" sintético dedicado.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Completa o Grupo 3 do CRM com alerta de conversa sem resposta além
do tempo configurado — reutiliza o pipeline system_alert (toast
vermelho sticky + sininho + drawer).
Banco (migration 20260423000005):
- conversation_sla_rules: 1 linha por tenant com threshold global
(1-1440 min), respect_business_hours, business_hours_start/end,
business_days (ISO 1=seg..7=dom), alert_scope (assigned_only|all),
notify_admin_on_breach. Default: enabled=false.
- conversation_sla_breaches: incidents com UNIQUE parcial
(tenant_id, thread_key) WHERE resolved_at IS NULL — idempotência.
- Trigger AFTER INSERT em conversation_messages resolve o breach
automaticamente quando chega nova outbound na thread.
- RPCs service_role: sla_open_breach (idempotente), sla_mark_notified.
- RLS: membros do tenant leem; clinic_admin/tenant_admin/saas_admin
escrevem na config; service_role escreve em breaches.
Edge function conversation-sla-check (cron 5min):
- Varre tenants com enabled=true.
- Query conversation_threads onde last_message_direction='inbound'
(+ assigned_to NOT NULL se scope='assigned_only').
- Se respect_business_hours: calcula businessMinutesElapsed em TS
iterando dia por dia a interseção da janela [start,end] com
[last_inbound_at, now], só em dias marcados em business_days. TZ
fixa em America/Sao_Paulo via Intl.DateTimeFormat.
- Se elapsed >= threshold: sla_open_breach (idempotente) + notifica
assigned_to sempre + admins se notify_admin_on_breach (deduplicado
via Set).
- Anti-spam: só notifica 1x por incident (checa notified_at).
- Notification leva deeplink pra /crm/conversas e payload.thread_key
pro frontend destacar a conversa (fora de escopo deste commit).
UI em /configuracoes/conversas-sla:
- Toggle enabled + InputNumber threshold com preview "≈ Xh Ymin".
- Toggle respect_business_hours → revela start/end + seletor de dias
úteis (pills toggleáveis Seg..Dom, ISO order).
- Select scope.
- Toggle notify_admin_on_breach.
- Card abaixo com breaches dos últimos 7 dias (status aberto/resolvido,
thread_key, limite configurado no momento do breach, duração).
- Adicionada na ConfiguracoesPage landing + rota /configuracoes/conversas-sla.
Cron template comentado no fim da migration (mesmo padrão do heartbeat).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>