Files
agenciapsilmno/AUDITORIA.md
2026-03-12 08:58:36 -03:00

12 KiB

Auditoria Técnica — AgenciaPsi MVP

Data: 2026-03-11 Stack: Vue 3 · PrimeVue · Supabase · PostgreSQL · FullCalendar Modelo: claude-sonnet-4-6


1. Visão Geral Arquitetural

Pontos fortes:

  • Estrutura feature-based bem definida (features/agenda, features/patients)
  • Separação correta: repository → composable → page
  • Multi-tenancy é first-class: tenant_id em todos os queries críticos
  • Sistema de guards robusto: RBAC + entitlements + tenantFeatures + session race-condition handling
  • useRecurrence é bem arquitetado: virtual occurrences no frontend + exceções no banco (sem N linhas futuras)

2. Bugs Críticos

[RESOLVIDO] useRecurrence.js — variável occurrenceCount não declarada

Bug original: branches custom_weekdays, monthly e yearly usavam occurrenceCount sem declará-la → ReferenceError em runtime. Nenhum dos três contava ocorrências anteriores ao range, então max_occurrences nunca funcionava corretamente.

Correção (Sessão 2): Cada branch ganhou let occurrenceCount = 0 + fase de pré-contagem de ruleStart até effStart.

Resolvido em: Sessão 2 — 2026-03-11


[RESOLVIDO] Exceção de remarcação fora do range não aparece

Bug original: loadExceptions só buscava original_date no range. Se original_date estivesse fora mas new_date caísse dentro, a sessão remarcada não aparecia.

Correção (Sessão 3):

  • loadExceptions: duas queries paralelas — q1 (original_date no range) + q2 (reschedule com new_date no range). Mescladas e deduplicadas por id.
  • expandRules post-pass: itera exceções não consumidas (handledExIds), injeta inbound reschedules com buildOccurrence(rule, newDate, ex.original_date, ex).

Resolvido em: Sessão 3 — 2026-03-11


3. Segurança

[RESOLVIDO] SQL dumps no repositório

Arquivos: schema.sql, backup.sql, data_dump.sql, full_dump.sql

Verificado via git log --all --full-history — arquivos nunca foram commitados. Movidos para pasta externa ao repositório. Nenhuma purga de histórico necessária.

Resolvido em: Sessão 3 — 2026-03-11


[RESOLVIDO] useAgendaEvents — sem tenant_id em nenhuma operação

Correção (Sessão 2): tenant_id injetado em create(), loadMyRange(), update(), remove(), removeSeriesFrom(), removeAllSeries(). Helpers assertTenantId() e getUid() adicionados.

Resolvido em: Sessão 2 — 2026-03-11


[RESOLVIDO] loadRules em useRecurrence sem filtro tenant_id

Correção (Sessão 2): loadRules e loadAndExpand aceitam tenantId opcional e aplicam .eq('tenant_id', tenantId). Call site em AgendaTerapeutaPage._reloadRange passa tenantStore.activeTenantId.

Resolvido em: Sessão 2 — 2026-03-11


[RESOLVIDO] console.log expõe dados de pacientes no browser

Correção (Sessão 2): Todos os console.* substituídos pelo supportLogger. Logs só aparecem quando modo suporte está ativo (token válido no banco).

Resolvido em: Sessão 2 — 2026-03-11 Arquivos criados: src/support/supportLogger.js, src/support/supportDebugStore.js


🟡 [ABERTO] window.__guardsBound / window.__supabaseAuthListenerBound

Usar window.* para controle de listeners é frágil em hot-reload. Solução: Gerenciar via módulo singleton ou app.config.globalProperties.


[RESOLVIDO] globalRole do profiles sem cache no guard

Adicionados globalRoleCacheUid + globalRoleCache no guards.js. Cache invalida em: uid change, SIGNED_OUT, SIGNED_IN com user diferente. Query ao banco ocorre apenas na primeira navegação por sessão.

Resolvido em: Sessão 4 — 2026-03-11


4. Duplicações e Inconsistências

[RESOLVIDO] Dois composables para a mesma entidade

src/composables/useAgendaEvents.js era código morto (sem imports). Deletado. O autoritativo src/features/agenda/composables/useAgendaEvents.js permanece.

Resolvido em: Sessão 3 — 2026-03-11


[RESOLVIDO] Dois mappers para agenda

src/features/agenda/domain/agenda.mappers.js estava vazio e sem imports. Deletado. src/features/agenda/domain/agenda.types.js também sem imports. Deletado. Diretório domain/ removido. O autoritativo src/features/agenda/services/agendaMappers.js permanece.

Resolvido em: Sessão 4 — 2026-03-11


[RESOLVIDO] N+1 Query — migração paciente_idpatient_id

Resolvido em: Sessão 3 — 2026-03-11

Migration executada: migrations/unify_patient_id.sql

  • UPDATE copiou paciente_idpatient_id onde null (resultado: 0 órfãos — todos já tinham patient_id)
  • ALTER TABLE agenda_eventos DROP COLUMN paciente_id executado com sucesso

Código atualizado:

  • useAgendaEvents.js: paciente_id removido do BASE_SELECT; create()/update() stripam paciente_id do payload
  • agendaRepository.js: workaround N+1 de orphan ids removido
  • agendaMappers.js: paciente_id agora é alias de patient_id (UI only)
  • AgendaTerapeutaPage.vue + AgendaClinicaPage.vue: pickDbFields usa patient_id
  • AgendamentosRecebidosPage.vue: dbFields removeu paciente_id
  • PatientsListPage.vue + AgendaEventDialog.vue: .or().eq('patient_id', id)

5. Limpeza Necessária

[RESOLVIDO] Template Sakai removido — bundle de produção

Resolvido em: Sessão 3 — 2026-03-11

Removidos: src/views/uikit/ (15 arquivos), src/views/utilities/Blocks.vue, src/components/BlockViewer.vue, src/components/FloatingConfigurator.vue, src/views/pages/Documentation.vue, src/assets/demo/, src/navigation/menus/sakai.demo.menu.js, src/router/routes.demo.js, src/assets/styles.scss (@use demo removido)

Referências limpas: package.json renomeado para agenciapsi, demoRoutes e sakaiDemoMenu removidos dos index files, FloatingConfigurator removido de Login, NotFound, Access, Error, ResetPasswordPage.


🟡 [PARCIAL] Arquivos obsoletos no projeto

Deletados (Sessão 4):

  • src/layout/ConfiguracoesPage-old.vue
  • src/features/agenda/domain/ (diretório inteiro — 2 arquivos não usados)

Ainda presentes:

  • src/layout/ConfiguracoesPage - Copia.vue — verificar se está no git (staged como D)
  • src/views/pages/public/Landingpage-v1 - bkp.vue
  • comandos.txt (na raiz)

[RESOLVIDO] Logs excessivos em produção

console.time/timeLog/timeEnd/warn/error em guards.js substituídos por logGuard(), logError(), logPerf().

Resolvido em: Sessão 2 — 2026-03-11


6. Status das Features do MVP

Feature Status Observação
Agenda de sessões Implementado FullCalendar + composables
Cadastro de pacientes Implementado CRUD completo
Recorrência de sessões Corrigido Bugs de occurrenceCount e cross-range resolvidos
Sessões presenciais/online Implementado campo modalidade
Controle de faltas Implementado exception_type = 'patient_missed'
Remarcação Corrigido Bug cross-range resolvido (Sessão 3)
Bloqueio de agenda Implementado BloqueioDialog.vue
Agendamento online Implementado AgendadorPublicoPage.vue
Prontuário Integrado Seção "Sessões" adicionada ao PatientProntuario.vue
Notificações/lembretes Não implementado Sem trigger/edge function
Financeiro/faturamento ⚠️ Parcial Páginas de plano mas sem sessão→pagamento
Relatórios Implementado RelatoriosPage.vue — terapeuta — sessões, faltas, taxa, gráfico

7. Backlog Técnico

  • Cache de globalRole no guard (reduzir queries por navegação)
  • Implementar notificações: WhatsApp/Email via Supabase Edge Functions
  • Integração prontuário ↔ sessões
  • Integração sessão ↔ pagamento (financeiro)
  • Relatórios básicos: sessões realizadas, faltas, receita
  • Migrar domínio de recorrência para TypeScript
  • Consolidar dois mappers de agenda (agendaMappers.js vs domain/agenda.mappers.js)
  • Remover arquivos obsoletos (ConfiguracoesPage-old, Landingpage-v1 bkp, etc.)

8. Prioridades de Ação

Fazer AGORA — todos concluídos

  1. [x] Remover dumps SQL → nunca commitados, movidos para fora do repo
  2. [x] Corrigir bug occurrenceCount → pré-contagem em todos os branches
  3. [x] Adicionar tenant_id ao useAgendaEvents e loadRules → injetado em todas as operações
  4. [x] Remover console.log com dados de pacientessupportLogger

Fazer em seguida — todos concluídos

  1. [x] Corrigir bug remarcação cross-range → 2 queries + post-pass em expandRules
  2. [x] Consolidar dois useAgendaEvents → legado deletado
  3. [x] Unificar paciente_id + patient_id → migration executada + código limpo
  4. [x] Remover Sakai de demo → removido + menu SaaS limpo

Backlog

  1. [x] Cache de globalRole no guard — globalRoleCacheUid/globalRoleCache em guards.js
  2. [ ] Notificações (WhatsApp/Email via Edge Functions) ← próximo
  3. [x] Integração prontuário ↔ sessões — seção "Sessões" em PatientProntuario.vue
  4. [x] Relatórios básicos — RelatoriosPage.vue em /therapist/relatorios
  5. [x] Consolidar mappers de agenda — domain/ deletado, agendaMappers.js é único

9. Sistema de Suporte Técnico SaaS

Sistema seguro para admins SaaS acessarem a agenda de terapeutas em modo debug.

Arquivo Responsabilidade
migrations/support_sessions.sql Tabela, índices, RLS, RPCs (token gerado via gen_random_uuid() duplo — sem pgcrypto)
src/support/supportLogger.js Logger centralizado — silencioso fora do modo suporte
src/support/supportDebugStore.js Store Pinia — valida token via RPC validate_support_session
src/support/supportSessionService.js CRUD de sessões de suporte (criar/listar/revogar)
src/support/components/SupportDebugBanner.vue Banner fixo na agenda com painel de logs filtráveis
src/views/pages/saas/SaasSupportPage.vue Painel SaaS para gerenciar sessões de suporte

RPCs no banco:

  • create_support_session(p_tenant_id, p_ttl_minutes){ token, expires_at, session_id }
  • validate_support_session(p_token){ valid, tenant_id }
  • revoke_support_session(p_token)boolean

10. Histórico de Sessões

Sessão 1 — 2026-03-11

  • Auditoria técnica completa gerada
  • Nenhum item resolvido

Sessão 2 — 2026-03-11

  • Sistema de suporte técnico SaaS implementado (migration + 5 arquivos criados)
  • Bug occurrenceCount corrigido (itens 2 e 4)
  • tenant_id adicionado ao useAgendaEvents e loadRules (item 3)
  • console.* substituídos por supportLogger

Sessão 4 — 2026-03-11

  • Cache globalRole adicionado ao guard (item 9) — sem query ao banco por navegação
  • Integração prontuário ↔ sessões (item 11) — painel "Sessões" em PatientProntuario.vue
  • RelatoriosPage.vue criada em /therapist/relatorios (item 12) — cards, gráfico Chart.js, tabela DataTable
  • Consolidação mappers (item 13) — domain/agenda.mappers.js vazio deletado + agenda.types.js + dir domain/
  • ConfiguracoesPage-old.vue deletado (limpeza)

Sessão 3 — 2026-03-11

  • Bug remarcação cross-range resolvido (item 5)
  • logPerf is not defined em guards.js corrigido
  • pgcrypto → substituído por gen_random_uuid() duplo no support_sessions
  • Sakai demo removido completamente (item 8) + styles.scss corrigido
  • useAgendaEvents legado deletado (item 6)
  • paciente_id unificado em patient_id — migration executada (item 7)
  • SQL dumps confirmados como nunca commitados (item 1 encerrado)

Para retomar: devolva este arquivo ao início da conversa e indique qual item quer atacar.