# Sessões 6 (continuação) → 10 — hardening em 6 áreas + scan completo do SaaS Continuação do commit `7c20b51` (Sessões 1-6 iniciais). Esta etapa fechou **toda revisão sênior do SaaS** + refator parcial de pacientes. **Estado final do projeto:** - A# auditoria abertos: **1** (A#31 Deploy real) - V# verificações abertos: 14 (todos médios/baixos adiados com plano completo no DB) - 🔴 Críticos: **0** ✅ - 🟠 Altos: **0** ✅ - Vitest: **208/208** (era 192) - SQL integration: **33/33** - E2E (Playwright): **5/5** - Áreas auditadas: **15** (todas as principais do SaaS) --- ## Sessão 6 (continuação) — Documentos pendentes + Pacientes V#3 ### Documentos: 100% fechado (V#50, V#51, V#52) - **V#50** — Policy `documents: portal patient read` adicional. Paciente lê documento via portal quando `compartilhado_portal=true` AND patient pertence a auth.uid AND não expirou. - **V#51** — `documents.content_sha256` (nullable, índice parcial). `Documents.service.uploadDocument` calcula SHA-256 hex client-side via `crypto.subtle.digest`. Helper novo `verifyDocumentIntegrity(docId)` baixa arquivo e re-hash. - **V#52** — Migration `...13` cron retention via pg_cron: 4 jobs (document_access_logs 1 ano, math_challenges 1h, public_submission_attempts 90 dias, submission_rate_limits 30 dias). ### Pacientes V#3 (parcial — fundação) - `src/features/patients/services/patientsRepository.js` — list/get/create/update/softDelete + groups + tags + getSessionCounts. - `src/features/patients/composables/usePatients.js` — wrapper reativo (rows/loading/error). - PatientsListPage.hydrateAssociationsSupabase migrada — substitui 4 queries diretas por chamadas ao repo (paralelismo preservado). - V#9 (PatientsCadastroPage 1991 linhas) → adiado pra Sessão 10. --- ## Sessão 7 — Tenants + Calendário ### Tenants (8 V#) - 🔴 **V#1 P0** — `tenant_invites` com RLS off + 0 policies (mesmo padrão A#30 Sessão 5). Tabela tinha 0 rows. Migration: ENABLE RLS + 4 policies (SELECT tenant_admin/saas; INSERT WITH CHECK invited_by=auth.uid; UPDATE só revogação; DELETE tenant_admin/saas). Aceitar invite continua via RPC `tenant_accept_invite` SECURITY DEFINER. - 🟠 **V#2** profiles INSERT WITH CHECK (id = auth.uid) - 🟠 **V#3** support_sessions INSERT WITH CHECK (admin_id = auth.uid + saas_admin guard) - 🟡 **V#4 (signup público)** verificado: RPC `ensure_personal_tenant` SECURITY DEFINER já existia (Signup.vue:232) → **ok** - 🟡 **V#5 (accept_invite)** verificado: RPCs `tenant_accept_invite` + `tenant_invite_member_by_email` já existiam → **ok** - 🟡 **V#6** user_settings INSERT WITH CHECK - 🟢 V#7/V#8 baixos — adiados ### Calendário (2 V#) — 100% fechado - 🔴 **V#1** feriados_insert + feriados_saas_insert ganharam WITH CHECK. Spam de feriado global bloqueado. - 🟢 **V#2** feriados_delete agora permite tenant_admin (não só owner). --- ## Sessão 8 — Addons + Central SaaS ### Addons (4 V#) - 🔴 **V#1 P0 (dinheiro)** — `addon_transactions_admin_insert` ganhou WITH CHECK (EXISTS saas_admins). Edge functions com service_role bypassam RLS, pipeline preservado. **Authenticated comum não cria mais transação fake.** - 🟠 **V#2** — 3 CHECK constraints em `addon_credits`: balance >= 0, total_consumed >= 0, total_purchased >= 0. Saldo negativo silencioso eliminado. - 🟡 V#3 (UI extrato) — adiado. - 🟡 V#4 — verificado: `addon_products` não tem `tenant_id` (catálogo global por design) → **ok**. ### Central SaaS (3 V#) - 🟠 **V#1** — `faq_admin_write` substituído por `faq_saas_admin_write` em `saas_faq` E `saas_faq_itens` — só saas_admin escreve. Tenant_admin lê via `faq_auth_read` (permanece). - 🟢 V#2/V#3 médios/baixos — adiados. --- ## Sessão 9 — Serviços/Prontuários (100% fechado) 5/5 V# corrigidos: - 🔴 **V#1** services + insurance_plans → 4 policies separadas (SELECT tenant_member; INSERT/UPDATE/DELETE owner+saas). - 🔴 **V#2** medicos → 4 policies separadas (catálogo de médicos referenciadores compartilhado entre profissionais do tenant). - 🟠 **V#3** commitment_services — cascade reescrito via JOIN com services (USING permite tenant_member; WITH CHECK só owner). - 🟠 **V#4** insurance_plan_services — cascade reescrito via JOIN com insurance_plans. - 🟡 **V#5** commitment_time_logs/determined_commitments/determined_commitment_fields ganharam WITH CHECK em INSERT. --- ## Sessão 10 — Pacientes V#9 (script extraído) PatientsCadastroPage.vue: 1991 → 1951 linhas (qualitativo > quantitativo). ### 2 composables novos - **`useCep.js`** — busca ViaCEP reutilizável. 6 testes (sem rede, mock fetch). - **`usePatientSupportContacts.js`** — CRUD de contatos de suporte encapsulado (load/save/add/remove/iniciaisFor). 10 testes com builder thenable. ### patientsRepository estendido - `getPatientRelations(patientId)` — retorna {groupIds, tagIds} - `replacePatientGroup(patientId, groupId, {tenantId})` - `replacePatientTags(patientId, tagIds, {tenantId, ownerId})` ### PatientsCadastroPage refatorado - 8 funções de query → delegação 1-linha ao patientsRepository - onCepBlur → usa composable useCep - Contatos de suporte → composable - Template **não** foi tocado (zero risco de regressão visual) - Quebra de template em sub-componentes Vue → adiado pra quando houver E2E cobrindo a página --- ## 📦 Migrations consolidadas neste commit (8) ``` 20260419000011_documents_portal_patient_policy.sql (V#50) 20260419000012_documents_content_hash.sql (V#51) 20260419000013_cron_retention_jobs.sql (V#52 + math_challenges + submissions + rate_limits) 20260419000014_financial_security_hardening.sql (5 V# financeiro — fechados na Sessão 6) 20260419000015_communication_security_hardening.sql (5 V# comunicação — fechados na Sessão 6) 20260419000016_tenants_calendario_hardening.sql (Tenants V#1-V#3,V#6 + Calendário V#1-V#2) 20260419000017_addons_central_saas_hardening.sql (Addons V#1-V#2 + Central SaaS V#1) 20260419000018_servicos_prontuarios_hardening.sql (Serviços V#1-V#5) ``` **Total acumulado de migrations no histórico: 18** (Sessões 1-10). Várias dessas exigiram conexão direta como `supabase_admin` (ver memory `project_supabase_admin_gotcha.md` e `commit.md` anterior) por causa de tabelas owned por esse role. --- ## 🆕 Novos arquivos (código) ``` src/features/patients/composables/useCep.js src/features/patients/composables/usePatientSupportContacts.js src/features/patients/composables/usePatients.js src/features/patients/composables/__tests__/useCep.spec.js (+6 testes) src/features/patients/composables/__tests__/usePatientSupportContacts.spec.js (+10 testes) src/features/patients/services/patientsRepository.js ``` --- ## 🛠️ Modificações - `src/features/patients/PatientsListPage.vue` — hydrateAssociationsSupabase usa repo - `src/features/patients/cadastro/PatientsCadastroPage.vue` — script extraído (queries → repo, CEP → composable, contatos → composable). Template intocado. - `src/services/Documents.service.js` — uploadDocument calcula content_sha256 + helper verifyDocumentIntegrity --- ## 📊 Áreas auditadas (estado final) | Área | V# total | Estado | |---|---|---| | auth | 10 | 100% fechado/ok | | router | 9 | 100% | | stores | 1 | 100% | | agenda | 11 | 100% | | pacientes | 10 | **100% fechado** ✅ | | seguranca | 1 | 100% | | saas | 10 | 100% | | documentos | 10 | **100% fechado** ✅ | | financeiro | 11 | 5 fechados, 6 médios/baixos adiados | | comunicacao | 10 | 5 fechados, 5 médios/baixos adiados | | tenants | 8 | 6 fechados, 2 baixos adiados | | calendario | 2 | **100% fechado** ✅ | | addons | 4 | 3 resolvidos, 1 médio adiado | | central_saas | 3 | 1 alto fechado, 2 médios adiados | | servicos | 5 | **100% fechado** ✅ | **Zero crítico/alto restante no sistema inteiro.** --- ## ⚠️ Pendências documentadas no DB (não esquecidas) ### A# (1 aberto) - **A#31 Deploy real** — alto. Reformulação pendente: como ainda não há cloud Supabase nem secrets reais, próxima sessão é "Preparação completa pra deploy" (DEPLOY.md, validar migrations num container limpo, audit de edge functions, listar env vars, script `db.cjs deploy-check`). ### V# adiados (14) Todos médios/baixos com plano completo em `dev_verificacoes_items.acao_sugerida`: - financeiro (6): parcelamento CHECK, payouts flow, recurrence DELETE policy, composables, máscara PIX, dashboard inadimplência - comunicacao (5): notifications/schedules silos, email_templates_global filtros, retention notification_logs, dashboard health, audit dismissals/preferences - tenants (2): owner_users policies, company_profiles + dev_user_credentials - central_saas (2): rate limit voto, valores tipo_acesso - addons (1): UI de extrato ### Outros - PatientsCadastroPage template breakdown — quando houver E2E - Pacientes V#9 segue 100% no banco (script foi extraído; template é refator visual separado)