Commit Graph

185 Commits

Author SHA1 Message Date
Leonardo f646efe522 Toast SLA: botão "Abrir conversa" abre drawer direto da thread
O alerta já vem com payload.thread_key vindo do edge conversation-sla-
check. Agora o toast renderiza 2 botões lado a lado quando thread_key
existe:
- "Abrir conversa" (outlined) → abre ConversationDrawer global direto
  na thread, sem navegar de página. Usa o store global que já existe.
- "Abrir CRM →" (solid) → fallback pra lista inteira via deeplink alias.

openConversationDrawer busca o row da view conversation_threads pelo
tenant+thread_key e delega pro conversationDrawerStore.openForThread.
Se a thread sumiu (arquivada/paciente deletado), cai no fallback de
navegar pra /conversas.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 11:33:38 -03:00
Leonardo 5f51bc068e Fix deeplink /crm/conversas não existe; alias dinâmico por role
Bug: toast do SLA tinha deeplink /crm/conversas que caía em NotFound.
As rotas reais são /therapist/conversas (terapeuta) e /admin/conversas
(clinic_admin), contextuais por role.

Fix: novo sistema de aliases em AppLayout.resolveDeeplink.
DEEPLINK_ALIASES traduz links semânticos (ex: /conversas, /crm/conversas)
pra rota real baseado em tenantStore.activeRole. Edge do SLA agora
emite /conversas (alias) em vez de path hardcoded; frontend resolve.

Padrão aplicável pras próximas features — basta registrar novo alias
aqui quando a rota depender de contexto.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 11:22:07 -03:00
Leonardo 4026415401 Notifications: não redispara toast pra system_alert antigas após F5
Bug: a cada mount (F5, navegação), todas as system_alert não-lidas
voltavam a disparar toast mesmo que o alerta já não fizesse mais
sentido (ex: saldo baixo já restabelecido, mas notif histórica ainda
não-lida reaparecia como toast sticky vermelho a cada reload).

Fix: seed do set alertedIds marca TODAS as system_alert do load inicial
como "já vistas nesta sessão". Alertas continuam no sino/drawer — o
usuário vê que tem pendências, mas sem bombardeio de toasts repetidos.
Toast só dispara pra alertas que chegarem depois do mount — seja via
Realtime (novidade) ou via catch-up encontrando id ainda não no set.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 10:21:12 -03:00
Leonardo 771b636cee SLA de conversas WhatsApp (Grupo 3.4): config + detecção + alerta
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>
2026-04-23 10:17:41 -03:00
Leonardo 4441661f62 Toast system_alert: agregar no catch-up pra não empilhar enxurrada
Bug: acumulando N system_alert não-lidas, o refreshAndMaybeAlert
(mount / visibilitychange / polling 60s) disparava N toasts de uma vez.
Comum após recarregar a página com alertas pendentes do último teste.

Fix: no catch-up, mostra só a notif mais recente, com sufixo "+N
outros alertas no sino" no detail se houver múltiplas. As demais são
marcadas no alertedIds pra não redisparar — continuam visíveis no
sininho/drawer com badge.

Eventos novos via Realtime seguem aparecendo individualmente (fluxo
normal — o usuário está online vendo chegar).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 10:03:24 -03:00
Leonardo 6db06abfc2 Toast system_alert ganha botão de ação com deeplink
Novo <Toast group="system-alerts"> no AppLayout com template custom
(vive no bloco global — persiste em qualquer layout/rota). Renderiza:
- Ícone de alerta + título em bold
- Detail em texto menor com opacity
- Botão com deeplink quando payload.deeplink existe, severity danger

Label do botão inferido do deeplink:
- /configuracoes/creditos-whatsapp → "Ir pra loja"
- /configuracoes/whatsapp-pessoal  → "Ver conexão"
- /configuracoes/whatsapp-oficial  → "Ver canal oficial"
- outros → "Abrir" (ou payload.actionLabel se vier explícito)

Clique navega via router.push se é path interno, senão
window.location.href. Toast continua sticky (24h) + closable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 10:00:18 -03:00
Leonardo 5c50db6704 Notifications: fallback de polling + catch-up ao focar a aba
Realtime em ambiente self-hosted às vezes perde eventos (WebSocket
desconecta silenciosamente, JWT expira, sleep do SO, etc). Sem fallback,
system_alert chega no DB mas toast nunca dispara — usuário só vê ao
relogar ou recarregar.

Três caminhos complementares agora:
1. Realtime (instantâneo, quando funciona)
2. visibilitychange — ao voltar pro foco da aba, recarrega notificações
   e dispara toast pras system_alert não-lidas ainda não exibidas
3. Polling a cada 60s como redundância

Set alertedIds (in-memory por sessão) evita toast duplicado quando dois
caminhos entregam a mesma notif. Seed inicial marca notifs já lidas/
arquivadas no mount pra não disparar retroativamente.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 09:54:48 -03:00
Leonardo e409ba64ef Saldo baixo WhatsApp: trigger dispara notificação ao cruzar threshold
Fecha o loop do Marco B — tenant não zera mais saldo sem aviso.

Nova função fn_whatsapp_low_balance_notify + trigger BEFORE UPDATE em
whatsapp_credits_balance:
- Dispara quando NEW.balance < NEW.low_balance_threshold e
  NEW.low_balance_alerted_at IS NULL
- Insere system_alert pros stakeholders do tenant (owner do canal
  WhatsApp ativo + clinic_admin + tenant_admin, deduplicado via UNION)
- Deeplink direto pra /configuracoes/creditos-whatsapp
- Seta NEW.low_balance_alerted_at = now() pra anti-spam

Reset do anti-spam já existia: add_whatsapp_credits seta
low_balance_alerted_at=NULL ao creditar (purchase/topup/refund).
Assim o ciclo completo funciona: cai abaixo → alerta → compra recrédita
→ cai de novo futuramente → alerta de novo.

Toast no frontend já é sticky vermelho pra type='system_alert'
(commit anterior). Config de threshold já existia na UI em
/configuracoes/creditos-whatsapp.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 09:25:03 -03:00
Leonardo 881fa16c27 Fluxo de reativação de canal WhatsApp + alerta toast sticky + notify owner
Cadeia de fixes descoberta ao testar o heartbeat 6.1 num tenant que migrou
de Evolution → Twilio e precisava voltar pro Evolution.

1. RLS notification_channels (migration 20260423000003)
   - Policy antiga tinha `deleted_at IS NULL` como primeira condição AND,
     bloqueando leitura de soft-deleted até pro próprio owner/saas_admin.
   - Isso fazia o chooser nunca detectar "canal antigo pra reativar".
   - Relaxada: owner/membro/saas_admin leem inclusive soft-deleted.
   - Filtro de deleted_at fica no código aplicativo (todos os queries já
     filtram explicitamente quando querem apenas ativos).

2. Edge function reactivate-notification-channel (nova)
   - Espelho da deactivate existente; service_role bypass RLS.
   - Aceita {channel_id} OU {tenant_id + provider}.
   - Autoriza saas_admin OU membro ativo do tenant.
   - Garante exclusividade: soft-deleta qualquer OUTRO canal ativo do
     mesmo tenant+channel.
   - Reseta metadata.first_unhealthy_at + connection_status=disconnected
     (heartbeat começa do zero).

3. SaasWhatsappPage (/saas/whatsapp)
   - loadChannel busca soft-deleted como fallback quando não tem ativo.
   - saveCredentials detecta soft-deleted e chama reactivate edge,
     depois atualiza credentials+display_name.
   - Banner âmbar "Canal configurado anteriormente" + botão vira
     "Reativar e salvar".

4. ConfiguracoesWhatsappPage tenant (/configuracoes/whatsapp-pessoal)
   - loadCredentials busca soft-deleted como fallback.
   - Card âmbar "WhatsApp Pessoal foi usado anteriormente" com botão
     "Reativar WhatsApp Pessoal" em vez de mostrar apenas "chame o suporte".

5. ChooserPage (/configuracoes/whatsapp)
   - Fix bug lateral: comparava activeProvider === 'evolution' (template)
     com 'evolution_api' (DB) — card nunca mostrava estado ativo. Agora
     normaliza via computed activeProviderKey.
   - softDeletedByProvider map carregado no mount; cards que têm row
     soft-deleted mostram "Reativar" em vez de "Ativar".
   - handleChoose chama reactivate edge antes de goSetup se detecta
     soft-deleted do provider escolhido.

6. whatsapp-heartbeat-check: notifica owner do channel + admins
   - notifyChannelStakeholders substitui notifyTenantAdmins.
   - Set dedupa o owner_id do channel + clinic_admin + tenant_admin.
   - Em tenant solo: 1 notificação; em clínica com canal de terapeuta
     específico: terapeuta (owner) + admin recebem; em clínica com canal
     do próprio admin: 1 (owner=admin).

7. Toast frontend para system_alert
   - notificationStore.subscribeRealtime aceita callback onInsert.
   - useNotifications registra callback que dispara toast PrimeVue
     (severity error, life 24h, closable) para type='system_alert'.
   - Usuário precisa fechar manualmente — alerta crítico de infra
     não pode sumir sozinho.

Cron heartbeat ativado em runtime local via cron.schedule()
(não vai neste commit — é config de ambiente, não migration).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 09:21:29 -03:00
Leonardo e1f756ea82 Heartbeat WhatsApp Evolution (Grupo 6.1): detecção + incident + alerta admin
Detecta celular desconectado antes de falhar envios silenciosamente.

Banco (migration 20260423000002):
- Tabela whatsapp_connection_incidents (tenant_id, channel_id, kind,
  started_at, resolved_at, duration_seconds, notified_at, details).
  UNIQUE parcial garante no máximo 1 incident aberto por channel.
- RPCs whatsapp_heartbeat_open_incident (idempotente), _resolve_open_incidents
  e _mark_notified. Service_role only.
- RLS: membros do tenant leem, saas_admin tudo.
- ALTER notifications.type pra aceitar 'system_alert' (usado pelo alerta).

Edge function whatsapp-heartbeat-check:
- Varre notification_channels provider=evolution_api e ativos.
- GET {api_url}/instance/connectionState/{instance} (timeout 8s, rewrite
  localhost → host.docker.internal pra containers).
- Mapeia state pra connection_status (open/connecting/qr_pending/
  disconnected/error), persiste + last_health_check.
- Lógica de threshold: marca first_unhealthy_at em metadata na primeira
  falha; só abre incident após heartbeat_threshold_minutes (default 5).
- Notifica admins ativos (clinic_admin/tenant_admin) do tenant via
  insert em notifications. Anti-spam: só notifica 1x por incident.
- Aceita ?channel_id=X pra check on-demand de um tenant específico.

UI tenant (/configuracoes/whatsapp-pessoal):
- Novo card "Monitoramento de conexão" com toggle alerts_enabled +
  InputNumber threshold (1-60 min). Persiste em
  notification_channels.metadata.
- Histórico últimos 7 dias: kind (tag colorida), aberto/resolvido,
  início → fim, duração formatada (Ns/Xmin Ys/Nh Xmin).

UI SaaS (/saas/whatsapp):
- Badge "N incidents abertos" no header quando há algum.
- Botão "Verificar tudo agora" invoca a edge function e atualiza a lista.
- Tabela enriquecida: coluna Status ganha pill "Incident aberto",
  colunas novas Última check e Incidents 7d (em laranja se > 0).

Cron template no final da migration (comentado — descomentar
cron.schedule pra ativar 2min periódico).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 07:49:09 -03:00
Leonardo f76a2e3033 Admin SaaS: ajuste manual de créditos WhatsApp (+/-) com proteção de compras
Fecha polimento do Marco B (créditos/Asaas) entregue em 21/04.

Nova RPC admin_adjust_whatsapp_credits(tenant, amount_signed, admin_id, note):
- |amount| <= 1000 por operação (anti dedo-gordo). Valores maiores → repetir.
- Em remoção (amount < 0), aplica regra FIFO cortesia primeiro:
  removable = max(0, sum(topup_manual+adjustment+refund) - usage_total).
  Créditos de 'purchase' (Asaas/PIX) são intocáveis — estorno real vai pelo
  fluxo financeiro do Asaas.
- Protegida por is_saas_admin() — authenticated comum não consegue chamar.
- Registra como kind='adjustment' com amount signed (+ ou -).

Helper get_whatsapp_removable_balance(tenant) retorna {balance, removable,
protected_amount, topup_net, usage_total} pra UI mostrar breakdown.

Aba 4 (Pacotes WhatsApp):
- Desativação dispara ConfirmDialog com histórico (N compras, M tenants
  distintos) + aviso forte se é o único pacote ativo + nota que créditos já
  adquiridos continuam válidos.
- Fix visual: :key no ToggleSwitch força re-mount durante confirm pra não
  desligar visualmente antes do accept.

Aba 5 (Topup → Ajuste):
- Substituído Select de kind por SelectButton Adicionar/Remover.
- InputNumber max 1000 · label e botão dinâmicos.
- Modo Remover: card laranja com breakdown removível/protegido, botão
  vermelho, confirm obrigatório com saldo resultante.
- Error mapping friendly pt-BR pros códigos da RPC.

ConfirmDialog com v-html habilitado pra suportar <br><br> entre frases
e <strong>/cores. Inputs livres (row.name, tenantName) passam por
escapeHtml() antes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 07:39:41 -03:00
Leonardo 2644e60bb6 CRM WhatsApp Grupo 3 completo + Marco A/B (Asaas) + admin SaaS + refactors polimórficos
Sessão 11+: fechamento do CRM de WhatsApp com dois providers (Evolution/Twilio),
sistema de créditos com Asaas/PIX, polimorfismo de telefones/emails, e integração
admin SaaS no /saas/addons existente.

═══════════════════════════════════════════════════════════════════════════
GRUPO 3 — WORKFLOW / CRM (completo)
═══════════════════════════════════════════════════════════════════════════

3.1 Tags · migration conversation_tags + seed de 5 system tags · composable
useConversationTags.js · popover + pills no drawer e nos cards do Kanban.

3.2 Atribuição de conversa a terapeuta · migration 20260421000012 com PK
(tenant_id, thread_key), UPSERT, RLS que valida assignee como membro ativo
do mesmo tenant · view conversation_threads expandida com assigned_to +
assigned_at · composable useConversationAssignment.js · drawer com Select
filtrável + botão "Assumir" · inbox com filtro aside (Todas/Minhas/Não
atribuídas) e chip do responsável em cada card (destaca "Eu" em azul).

3.3 Notas internas · migration conversation_notes · composable + seção
colapsável no drawer · apenas o criador pode editar/apagar (RLS).

3.5 Converter desconhecido em paciente · botão + dialog quick-cadastro ·
"Vincular existente" com Select filter de até 500 pacientes · cria
telefone WhatsApp (vinculado) via upsertWhatsappForExisting.

3.6 Histórico de conversa no prontuário · nova aba "Conversas" em
PatientProntuario.vue · PatientConversationsTab.vue com stats (total /
recebidas / enviadas / primeira / última), SelectButton de filtro, timeline
com bolhas por direção, mídia inline (imagem/áudio/vídeo/doc via signed
URL), indicadores ✓ ✓✓ de delivery, botão "Abrir no CRM".

═══════════════════════════════════════════════════════════════════════════
MARCO A — UNIFICAÇÃO WHATSAPP (dois providers mutuamente exclusivos)
═══════════════════════════════════════════════════════════════════════════

- Página chooser ConfiguracoesWhatsappChooserPage.vue com 2 cards (Pessoal/
  Oficial), deactivate via edge function deactivate-notification-channel
- send-whatsapp-message refatorada com roteamento por provider; Twilio deduz
  1 crédito antes do envio e refunda em falha
- Paridade Twilio (novo): módulo compartilhado supabase/functions/_shared/
  whatsapp-hooks.ts com lógica provider-agnóstica (opt-in, opt-out, auto-
  reply, schedule helpers em TZ São Paulo, makeTwilioCreditedSendFn que
  envolve envio em dedução atômica + rollback). Consumido por Evolution E
  Twilio inbound. Evolution refatorado (~290 linhas duplicadas removidas).
- Bucket privado whatsapp-media · decrypt via Evolution getBase64From
  MediaMessage · upload com path tenant/yyyy/mm · signed URLs on-demand

═══════════════════════════════════════════════════════════════════════════
MARCO B — SISTEMA DE CRÉDITOS WHATSAPP + ASAAS
═══════════════════════════════════════════════════════════════════════════

Banco:
- Migration 20260421000007_whatsapp_credits (4 tabelas: balance,
  transactions, packages, purchases) + RPCs add_whatsapp_credits e
  deduct_whatsapp_credits (atômicas com SELECT FOR UPDATE)
- Migration 20260421000013_tenant_cpf_cnpj (coluna em tenants com CHECK
  de 11 ou 14 dígitos)

Edge functions:
- create-whatsapp-credit-charge · Asaas v3 (sandbox + prod) · PIX com
  QR code · getOrCreateAsaasCustomer patcha customer existente com CPF
  quando está faltando
- asaas-webhook · recebe PAYMENT_RECEIVED/CONFIRMED e credita balance

Frontend (tenant):
- Página /configuracoes/creditos-whatsapp com saldo + loja + histórico
- Dialog de confirmação com CPF/CNPJ (validação via isValidCPF/CNPJ de
  utils/validators, formatação on-blur, pré-fill de tenants.cpf_cnpj,
  persiste no primeiro uso) · fallback sandbox 24971563792 REMOVIDO
- Composable useWhatsappCredits extrai erros amigáveis via
  error.context.json()

Frontend (SaaS admin):
- Em /saas/addons (reuso do pattern existente, não criou página paralela):
  - Aba 4 "Pacotes WhatsApp" — CRUD whatsapp_credit_packages com DataTable,
    toggle is_active inline, dialog de edição com validação
  - Aba 5 "Topup WhatsApp" — tenant Select com saldo ao vivo · RPC
    add_whatsapp_credits com p_admin_id = auth.uid() (auditoria) · histórico
    das últimas 20 transações topup/adjustment/refund

═══════════════════════════════════════════════════════════════════════════
GRUPO 2 — AUTOMAÇÃO
═══════════════════════════════════════════════════════════════════════════

2.3 Auto-reply · conversation_autoreply_settings + conversation_autoreply_
log · 3 modos de schedule (agenda das regras semanais, business_hours
custom, custom_window) · cooldown por thread · respeita opt-out · agora
funciona em Evolution E Twilio (hooks compartilhados)

2.4 Lembretes de sessão · conversation_session_reminders_settings +
_logs · edge send-session-reminders (cron) · janelas 24h e 2h antes ·
Twilio deduz crédito com rollback em falha

═══════════════════════════════════════════════════════════════════════════
GRUPO 5 — COMPLIANCE (LGPD Art. 18 §2)
═══════════════════════════════════════════════════════════════════════════

5.2 Opt-out · conversation_optouts + conversation_optout_keywords (10 system
seed + custom por tenant) · detecção por regex word-boundary e normalização
(lowercase + strip acentos + pontuação) · ack automático (deduz crédito em
Twilio) · opt-in via "voltar", "retornar", "reativar", "restart" ·
página /configuracoes/conversas-optouts com CRUD de keywords

═══════════════════════════════════════════════════════════════════════════
REFACTOR POLIMÓRFICO — TELEFONES + EMAILS
═══════════════════════════════════════════════════════════════════════════

- contact_types + contact_phones (entity_type + entity_id) — migration
  20260421000008 · contact_email_types + contact_emails — 20260421000011
- Componentes ContactPhonesEditor.vue e ContactEmailsEditor.vue (add/edit/
  remove com confirm, primary selector, WhatsApp linked badge)
- Composables useContactPhones.js + useContactEmails.js com
  unsetOtherPrimaries() e validação
- Trocado em PatientsCadastroPage.vue e MedicosPage.vue (removidos campos
  legados telefone/telefone_alternativo e email_principal/email_alternativo)
- Migration retroativa v2 (20260421000010) detecta conversation_messages
  e cria/atualiza phone como WhatsApp vinculado

═══════════════════════════════════════════════════════════════════════════
POLIMENTO VISUAL + INFRA
═══════════════════════════════════════════════════════════════════════════

- Skeletons simplificados no dashboard do terapeuta
- Animações fade-up com stagger via [--delay:Xms] (fix specificity sobre
  .dash-card box-shadow transition)
- ConfirmDialog com group="conversation-drawer" (evita montagem duplicada)
- Image preview PrimeVue com botão de download injetado via MutationObserver
  (fetch + blob para funcionar cross-origin)
- Áudio/vídeo com preload="metadata" e controles de velocidade do browser
- friendlySendError() mapeia códigos do edge pra mensagens pt-BR via
  error.context.json()
- Teleport #cfg-page-actions para ações globais de Configurações
- Brotli/Gzip + auto-import Vue/PrimeVue + bundle analyzer
- AppLayout consolidado (removidas duplicatas por área) + RouterPassthrough
- Removido console.trace debug que estava em watch de router e queries
  Supabase (degradava perf pra todos)
- Realtime em conversation_messages via publication supabase_realtime
- Notifier global flutuante com beep + toggle mute (4 camadas: badge +
  sino + popup + browser notification)

═══════════════════════════════════════════════════════════════════════════
MIGRATIONS NOVAS (13)
═══════════════════════════════════════════════════════════════════════════

20260420000001_patient_intake_invite_info_rpc
20260420000002_audit_logs_lgpd
20260420000003_audit_logs_unified_view
20260420000004_lgpd_export_patient_rpc
20260420000005_conversation_messages
20260420000005_search_global_rpc
20260420000006_conv_messages_notifications
20260420000007_notif_channels_saas_admin_insert
20260420000008_conv_messages_realtime
20260420000009_conv_messages_delivery_status
20260421000001_whatsapp_media_bucket
20260421000002_conversation_notes
20260421000003_conversation_tags
20260421000004_conversation_autoreply
20260421000005_conversation_optouts
20260421000006_session_reminders
20260421000007_whatsapp_credits
20260421000008_contact_phones
20260421000009_retroactive_whatsapp_link
20260421000010_retroactive_whatsapp_link_v2
20260421000011_contact_emails
20260421000012_conversation_assignments
20260421000013_tenant_cpf_cnpj

═══════════════════════════════════════════════════════════════════════════
EDGE FUNCTIONS NOVAS / MODIFICADAS
═══════════════════════════════════════════════════════════════════════════

Novas:
- _shared/whatsapp-hooks.ts (módulo compartilhado)
- asaas-webhook
- create-whatsapp-credit-charge
- deactivate-notification-channel
- evolution-webhook-provision
- evolution-whatsapp-inbound
- get-intake-invite-info
- notification-webhook
- send-session-reminders
- send-whatsapp-message
- submit-patient-intake
- twilio-whatsapp-inbound

═══════════════════════════════════════════════════════════════════════════
FRONTEND — RESUMO
═══════════════════════════════════════════════════════════════════════════

Composables novos: useAddonExtrato, useAuditoria, useAutoReplySettings,
useClinicKPIs, useContactEmails, useContactPhones, useConversationAssignment,
useConversationNotes, useConversationOptouts, useConversationTags,
useConversations, useLgpdExport, useSessionReminders, useWhatsappCredits

Stores: conversationDrawerStore

Componentes novos: ConversationDrawer, GlobalInboundNotifier, GlobalSearch,
ContactEmailsEditor, ContactPhonesEditor

Páginas novas: CRMConversasPage, PatientConversationsTab, AddonsExtratoPage,
AuditoriaPage, NotificationsHistoryPage, ConfiguracoesWhatsappChooserPage,
ConfiguracoesConversasAutoreplyPage, ConfiguracoesConversasOptoutsPage,
ConfiguracoesConversasTagsPage, ConfiguracoesCreditosWhatsappPage,
ConfiguracoesLembretesSessaoPage

Utils novos: addonExtratoExport, auditoriaExport, excelExport,
lgpdExportFormats

Páginas existentes alteradas: ClinicDashboard, PatientsCadastroPage,
PatientCadastroDialog, PatientsListPage, MedicosPage, PatientProntuario,
ConfiguracoesWhatsappPage, SaasWhatsappPage, ConfiguracoesRecursosExtrasPage,
ConfiguracoesPage, AgendaTerapeutaPage, AgendaClinicaPage, NotificationItem,
NotificationDrawer, AppLayout, AppTopbar, useMenuBadges,
patientsRepository, SaasAddonsPage (aba 4 + 5 WhatsApp)

Routes: routes.clinic, routes.configs, routes.therapist atualizados
Menus: clinic.menu, therapist.menu, saas.menu atualizados

═══════════════════════════════════════════════════════════════════════════
NOTAS

- Após subir, rodar supabase functions serve --no-verify-jwt
  --env-file supabase/functions/.env pra carregar o módulo _shared
- WHATSAPP_SETUP.md reescrito (~400 linhas) com setup completo dos 3
  providers + troubleshooting + LGPD
- HANDOFF.md atualizado com estado atual e próximos passos

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 07:05:24 -03:00
Leonardo 037ba3721f HANDOFF.md atualizado para Sessoes 1-10 + proxima sessao A#31-rev
Documento "ler primeiro ao voltar" reflete estado atual: 15 areas auditadas,
zero critico/alto aberto, A#31 reformulada como "Preparacao pra deploy"
(MVP nao tem cloud Supabase nem secrets reais).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 22:02:48 -03:00
Leonardo d6eb992f71 Sessoes 6cont-10: hardening em 6 areas + scan completo do SaaS
Continuacao de 7c20b51. Esta etapa fechou TODA revisao senior do SaaS
(15 areas auditadas) + refator parcial de pacientes.

Ver commit.md para descricao completa por sessao.

# Estado final do projeto
- A# auditoria abertos: 1 (A#31 Deploy real)
- V# verificacoes abertos: 14 (todos medios/baixos adiados com plano)
- Criticos: 0
- Altos: 0
- Vitest: 208/208 (era 192, +16 nos novos composables)
- SQL integration: 33/33
- E2E (Playwright): 5/5
- Areas auditadas: 15

# Highlights
- Documentos 100% fechado (V#50/51/52: portal-paciente policy + content_sha256 + 4 cron jobs retention)
- Tenants V#1 P0: tenant_invites com RLS off + 0 policies (mesmo padrao A#30)
- Calendario 100% fechado: feriados WITH CHECK
- Addons V#1 P0 (dinheiro): addon_transactions WITH CHECK saas_admin
- Central SaaS V#1: faq write so saas_admin (era tenant_admin)
- Servicos/Prontuarios 100% fechado: services/medicos/insurance_plans + cascades
- Pacientes V#9: 2 composables novos (useCep, usePatientSupportContacts) + repo estendido + script extraido (template intocado, fica para quando houver E2E)

# 8 migrations novas neste commit
- 20260419000011_documents_portal_patient_policy.sql
- 20260419000012_documents_content_hash.sql
- 20260419000013_cron_retention_jobs.sql
- 20260419000014_financial_security_hardening.sql
- 20260419000015_communication_security_hardening.sql
- 20260419000016_tenants_calendario_hardening.sql
- 20260419000017_addons_central_saas_hardening.sql
- 20260419000018_servicos_prontuarios_hardening.sql

Total acumulado: 18 migrations (Sessoes 1-10).

# A#31 reformulado pra proxima sessao
"Deploy real" muda escopo: como nao ha cloud Supabase nem secrets reais
ainda (MVP), proxima sessao vira "Preparacao completa pra deploy" (DEPLOY.md,
validar migrations num container limpo, audit edge functions, listar env vars,
script db.cjs deploy-check).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 22:00:06 -03:00
Leonardo 7c20b518d4 Sessoes 1-6 acumuladas: hardening B2, defesa em camadas, +192 testes
Repositorio estava ha ~5 sessoes sem commit. Consolida tudo desde d088a89.

Ver commit.md na raiz para descricao completa por sessao.

# Numeros
- A# auditoria abertos: 0/30
- V# verificacoes abertos: 5/52 (todos adiados com plano)
- T# testes escritos: 10/10
- Vitest: 192/192
- SQL integration: 33/33
- E2E (Playwright, novo): 5/5
- Migrations: 17 (10 novas Sessao 6)
- Areas auditadas: 7 (+documentos com 10 V#)

# Highlights Sessao 6 (hoje)
- V#34/V#41 Opcao B2: tenant_features com plano + override (RPC SECURITY DEFINER, tela /saas/tenant-features)
- A#20 rev2 self-hosted: defesa em 5 camadas (honeypot + rate limit + math captcha condicional + paranoid mode + dashboard /saas/security)
- Documentos hardening (V#43-V#49): tenant scoping em storage policies (vazamento entre clinicas eliminado), RPC validate_share_token, signatures policy granular
- SaaS Twilio Config (/saas/twilio-config): UI editavel para SID/webhook/cotacao; AUTH_TOKEN permanece em env var
- T#9 + T#10: useAgendaEvents.spec.js + Playwright E2E (descobriu bug no front que foi corrigido)

# Sessoes anteriores (1-5) consolidadas
- Sessao 1: auth/router/session, normalizeRole extraido
- Sessao 2: agenda - composables/services consolidados
- Sessao 3: pacientes - tenant_id em todas queries
- Sessao 4: security review pagina publica - 14/15 vulnerabilidades corrigidas
- Sessao 5: SaaS - P0 (A#30: 7 tabelas com RLS off corrigidas)

# .gitignore ajustado
- supabase/* + !supabase/functions/ (mantem 10 edge functions, ignora .temp/migrations gerados pelo CLI)
- database-novo/backups/ (regeneravel via db.cjs backup)
- test-results/ + playwright-report/
- .claude/settings.local.json (config local com senha de dev removida do tracking)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 15:42:46 -03:00
Leonardo d088a89fb7 Documentos Pacientes, Template Documentos Pacientes Saas, Documentos prontuários, Documentos Externos, Visualização Externa, Permissão de Visualização, Render Otimização 2026-03-30 14:08:19 -03:00
Leonardo 0658e2e9bf Adicionada compressão Brotli/Gzip, auto-import de Vue e PrimeVue, e análise visual do bundle para otimização de produção e Remove AppLayout duplicado de cada área (therapist, admin, configuracoes, account, supervisor, billing, features) e consolida sob um único pai no router/index.js. Adiciona RouterPassthrough para grupos de rota sem layout intermediário. Remove debug ativo (console.trace em router.push e queries Supabase em todo watch de rota) que degradava performance para todos os usuários. 2026-03-25 12:14:43 -03:00
Leonardo bfe148ef12 safe point before auto-import cleanup 2026-03-25 09:11:05 -03:00
Leonardo 3f1786c9bf + Menu Hover no Layout Rail, Twilio, Sms, Email, Templates, LNovo Layout Configurações 2026-03-25 08:39:45 -03:00
Leonardo 53a4980396 Correcao Sidebar Classico e Rail, Correcao Layout, Ajuste de Breakpoint para Tailwind, Ajuste AppTopbar, Ajuste Menu PopOver, Recriado Paleta de Cores, Inserido algumas animações leves, Reajuste Cor items NOVOS da tabela, Drawer Ajuda Corrigido no Logout, Whatsapp, sms, email, recursos extras 2026-03-24 21:26:58 -03:00
Leonardo a89d1f5560 Copyright, Financeiro, Lançamentos, aprimoramentos de ui 2026-03-21 08:05:40 -03:00
Leonardo 29ed349cf2 Agenda google, avisos globais, feriados + avisos globais, templates de email, configuracoes empresa, preview empresa. 2026-03-18 15:47:37 -03:00
Leonardo d6d2fe29d1 carousel, agenda arquivados, agenda cor, agenda arquivados, grupos pacientes, pacientes arquivados - desativados, sessoes verificadas, ajuste notificações, Prontuario, Agenda Animation, Menu Profile, bagdes Profile, Offline 2026-03-18 09:26:09 -03:00
Leonardo 66f67cd40f Layout 100%, Notificações, SetupWizard 2026-03-17 21:08:14 -03:00
Leonardo 84d65e49c0 Sistema de Suporte , Documentação 2026-03-16 09:41:18 -03:00
Leonardo f66f6f3fde Ajuste Layout, Dashboard Terapeuta, Timeline, Suporte técnico, Documentação e FAQ 2026-03-15 19:46:06 -03:00
Leonardo ee09b30987 Setup Wizard 2026-03-14 19:09:44 -03:00
Leonardo 587079e414 Ajuste Convenios e Particular 2026-03-13 21:09:34 -03:00
Leonardo 06fb369beb Preficicação, Convenio, Ajustes Agenda, Configurações Excessões 2026-03-13 16:03:08 -03:00
Leonardo f4b185ae17 Agenda, Agendador, Configurações 2026-03-12 08:58:36 -03:00
Leonardo f733db8436 ZERADO 2026-03-06 06:37:13 -03:00
Leonardo d58dc21297 Ajuste rotas, Menus, Layout, Permissãoes UserRoleGuard 2026-02-24 12:04:59 -03:00
Leonardo b1c0cb47c0 Ajuste usuarios - Inicio agenda 2026-02-23 18:57:40 -03:00
Leonardo 89b4ecaba1 Ajuste em Massa - Paciente, Terapeuta, Clinica e Admin - Inicio agenda 2026-02-22 17:56:01 -03:00
Leonardo 6eff67bf22 route 2026-02-19 13:09:44 -03:00
Leonardo 62e79e243a assets 2026-02-19 13:03:15 -03:00
Leonardo 3a671b1e9e assets 2026-02-19 12:59:03 -03:00
Leonardo b3bb817e3f commit 2026-02-19 12:53:21 -03:00
Leonardo 676042268b first commit 2026-02-18 22:36:45 -03:00
Cagatay Civici ec6b6ef53a set version as 5 5.0.0 2026-02-02 21:49:03 +03:00
tugcekucukoglu 76a3b60333 cchore: update PrimeVue version 2026-01-30 17:51:18 +03:00
tugcekucukoglu 410c08d693 chore: layout config updates 2025-12-25 10:03:32 +03:00
tugcekucukoglu a4b2c96b0d submodule added 2025-12-25 09:09:55 +03:00
tugcekucukoglu a47200fdf7 remove assets 2025-12-25 09:07:45 +03:00
tugcekucukoglu 7c32ae1f6f chore: remove sass warnings 2025-12-09 14:05:01 +03:00
Atakan db99863fac update transitions & dependencies 2025-12-08 14:36:22 +03:00
Atakan c2ef85fcab update for tw v4 2025-12-04 12:26:25 +03:00
Atakan deea8861f8 update 2025-11-18 05:16:32 +03:00
Atakan 319f976d2b add blocks 2025-11-08 17:37:47 +03:00
Atakan 13a50a3af3 update tw 2025-11-08 17:35:43 +03:00