## MEDICONNECT – Documentação Técnica e de Segurança

Aplicação SPA (React + Vite + TypeScript) consumindo Supabase (Auth, PostgREST, Edge Functions) via **Netlify Functions**. Este documento consolida: variáveis de ambiente, arquitetura de autenticação, modelo de segurança atual, riscos, controles implementados e próximos passos.

---

## 🚀 Guias de Início Rápido

**Primeira vez rodando o projeto?** Escolha seu guia:

- 📖 **[QUICK-START.md](./QUICK-START.md)** - Comandos rápidos (5 minutos)
- 📚 **[README-INSTALACAO.md](./README-INSTALACAO.md)** - Guia completo com troubleshooting
- 🚢 **[DEPLOY.md](./DEPLOY.md)** - Como fazer deploy no Netlify (produção)

**Arquitetura da aplicação:**

```
Frontend (Vite/React) → Netlify Functions → Supabase API
```

As Netlify Functions protegem as credenciais do Supabase e funcionam como proxy/backend.

---

## ⚠️ MUDANÇAS RECENTES NA API (21/10/2025)

### Base de Dados Limpa

**Todos os usuários, pacientes, laudos e agendamentos foram deletados.** Motivo: limpeza de dados inconsistentes e roles incorretos.

### Novas Permissões (RLS)

#### 👨‍⚕️ Médicos:

- ✅ Veem **todos os pacientes**
- ✅ Veem apenas **seus próprios laudos** (filtro: `created_by = médico`)
- ✅ Veem apenas **seus próprios agendamentos** (filtro: `doctor_id = médico`)
- ✅ Editam apenas **seus próprios laudos e agendamentos**

#### 👤 Pacientes:

- ✅ Veem apenas **seus próprios dados**
- ✅ Veem apenas **seus próprios laudos** (filtro: `patient_id = paciente`)
- ✅ Veem apenas **seus próprios agendamentos**

#### 👩‍💼 Secretárias:

- ✅ Veem **todos os pacientes**
- ✅ Veem **todos os agendamentos**
- ✅ Veem **todos os laudos**

#### 👑 Admins/Gestores:

- ✅ **Acesso completo a tudo**

### Novos Endpoints de Criação (Atualizado 21/10 - tarde)

⚠️ **IMPORTANTE**: A API mudou! `create-doctor` e `create-patient` (REST) **NÃO ENVIAM MAGIC LINK** e **NÃO CRIAM AUTH USER**.

**`create-user`** - Criação completa com autenticação (RECOMENDADO):

- Obrigatório: `email`, `full_name`, `role`
- Opcional: `phone`, `create_patient_record`, `cpf`, `phone_mobile`
- 🔐 **Envia magic link** automaticamente para ativar conta
- Cria: Auth user + Profile + Role + (opcionalmente) registro em `patients`
- **Use este para criar qualquer usuário que precisa fazer login**

**`create-doctor`** (Edge Function) - Criação de médico SEM autenticação:

- Obrigatório: `cpf`, `crm`, `crm_uf`, `full_name`, `email`
- Validações: CRM (4-7 dígitos), CPF (11 dígitos), UF válido
- ❌ **NÃO cria auth user** - apenas registro em `doctors`
- Use apenas se precisar criar registro de médico sem login

**`POST /rest/v1/patients`** - Criação de paciente SEM autenticação:

- Obrigatório: `full_name`, `cpf`, `email`, `phone_mobile`, `created_by`
- ❌ **NÃO cria auth user** - apenas registro em `patients`
- Use apenas se precisar criar registro de paciente sem login

**Quando usar cada endpoint:**

- **`create-user`** com `role="medico"`: Admin criando médico que precisa fazer login
- **`create-user`** com `role="paciente"` + `create_patient_record=true`: Admin criando paciente com login
- **`create-user`** com `role="admin"/"secretaria"`: Criar usuários administrativos
- **`create-doctor`**: Apenas para registros de médicos sem necessidade de login (raro)
- **`POST /rest/v1/patients`**: Apenas para registros de pacientes sem necessidade de login (raro)

---

## 1. Variáveis de Ambiente (`.env` / `.env.local`)

| Variável                 | Obrigatória      | Descrição                                                       |
| ------------------------ | ---------------- | --------------------------------------------------------------- |
| `VITE_SUPABASE_URL`      | Sim              | URL base do projeto Supabase (`https://<ref>.supabase.co`)      |
| `VITE_SUPABASE_ANON_KEY` | Sim              | Chave pública (anon) usada para Auth password grant e PostgREST |
| `VITE_APP_ENV`           | Não              | Identifica ambiente (ex: `dev`, `staging`, `prod`)              |
| `VITE_SERVICE_EMAIL`     | Não (desativado) | Email de usuário técnico (não usar em produção no momento)      |
| `VITE_SERVICE_PASSWORD`  | Não (desativado) | Senha do usuário técnico (não usar em produção no momento)      |

Boas práticas:

- Nunca exponha Service Role Key no frontend.
- Não comitar `.env` – usar `.env.example` como referência.

---

## 2. Arquitetura de Autenticação

### 🔐 Endpoints de Autenticação (Atualizado 21/10/2025)

#### **Login com Email e Senha**

- **Endpoint**: `POST /auth/v1/token?grant_type=password`
- **Netlify Function**: `/auth-login`
- **Body**: `{ "email": "usuario@exemplo.com", "password": "senha123" }`
- **Resposta**: `{ access_token, token_type: "bearer", expires_in: 3600, refresh_token, user: { id, email } }`
- **Uso**: Login tradicional com credenciais

#### **Magic Link (Login sem Senha)**

- **Endpoint**: `POST /auth/v1/otp`
- **Netlify Function**: `/auth-magic-link`
- **Body**: `{ "email": "usuario@exemplo.com" }`
- **Resposta**: `200 OK` (email enviado)
- **Uso**: Reenviar link de ativação ou login sem senha
- **Nota**: `create-user` já envia magic link automaticamente na criação

#### **Dados do Usuário Autenticado**

- **Endpoint**: `GET /auth/v1/user`
- **Netlify Function**: `/auth-user`
- **Headers**: `Authorization: Bearer <access_token>`
- **Resposta**: `{ id, email, created_at }`
- **Uso**: Verificar sessão atual

#### **Logout**

- **Endpoint**: `POST /auth/v1/logout`
- **Netlify Function**: `/auth-logout`
- **Headers**: `Authorization: Bearer <access_token>`
- **Resposta**: `204 No Content`
- **Uso**: Encerrar sessão e invalidar tokens

### 🔄 Fluxo de Autenticação

1. **Login**: Usuário envia email+senha → `authService.login` → `POST /auth-login`
2. **Tokens**: Resposta contém `access_token` (curto prazo) + `refresh_token` (longo prazo)
3. **Interceptor**: Anexa `Authorization: Bearer <access_token>` + `apikey` em todas as requisições
4. **Refresh**: Em 401, tenta renovar token automaticamente
5. **Enriquecimento**: `GET /user-info` busca roles, profile e permissions completos

### 🆕 Criação de Usuário

Edge Function `create-user` executa:

- Cria auth user
- Cria profile
- Atribui role
- **Envia magic link automaticamente**
- Opcionalmente cria registro em `patients` (se `create_patient_record=true`)

### 🔒 Motivos para Netlify Functions

- Protege `SUPABASE_ANON_KEY` no backend
- RLS controla acesso por `auth.uid()`
- Evita exposição de credenciais no frontend

---

## 3. Modelo de Autorização & Roles

Roles previstas: `admin`, `gestor`, `medico`, `secretaria`, `paciente`, `user`.

Camadas:

- Supabase Auth: autenticação e identidade (user.id).
- PostgREST + RLS: enforcement de linha/coluna (ex: paciente só vê seus próprios registros; médico vê pacientes atribuídos / futuras policies).
- Edge Functions: operações privilegiadas (criação de usuário composto; agregações que cruzam tabelas sensíveis).

Princípios:

- Menor privilégio: roles específicas são anexadas à tabela `user_roles` / claim custom (via função user-info).
- Expansão de permissões sempre via backend controlado (Edge ou admin interface separada).

---

## 4. Armazenamento de Tokens

Status revisado: Access Token agora em memória (via `tokenStore`), Refresh Token em `sessionStorage` (escopo aba). LocalStorage legado é migrado e limpo.

Motivações da mudança:

- Reduz superfície de ataque para XSS persistente (access token não persiste após reload se atacante injeta script tardio).
- Session scoping limita reutilização indevida do refresh token após fechamento total do navegador.

Persistência atual:
| Tipo | Local | Expiração Natural |
| -------------- | ----------------- | ------------------------------------ |
| Access Token | Memória JS | exp claim (curto prazo) |
| Refresh Token | sessionStorage | exp claim / revogação backend |
| User Snapshot | Memória JS | Limpo em logout / reload opcional |

Riscos remanescentes:

- XSS ainda pode ler refresh token dentro da mesma aba.
- Ataques supply-chain podem capturar tokens em runtime.

Mitigações planejadas:

1. CSP + bloqueio de inline script não autorizado.
2. Auditoria de dependências e lockfile imutável.
3. (Opcional) Migrar refresh para cookie httpOnly + rotacionamento curto (exige backend/proxy).

Fallback / Migração:

- Em primeira utilização o `tokenStore` migra chaves legacy (`authToken`, `refreshToken`, `authUser`) e remove do `localStorage`.

Operações:

- `tokenStore.setTokens(access, refresh?)` atualiza memória e session.
- `tokenStore.clear()` remove tudo (usado em logout e erro crítico de refresh).

Fluxo de Refresh:

1. Requisição falha com 401.
2. Wrapper (`http.ts`) obtém refresh do `tokenStore`.
3. Se sucesso, novo par é salvo (access renovado em memória, refresh substituído em session).
4. Se falha, limpeza e redirecionamento esperados pelo layer de UI.

Próximos passos (prioridade decrescente):

1. Testes e2e validando não persistência pós reload sem refresh.
2. Detecção de reuse (se Supabase expor sinalização) e invalidação proativa.
3. Adicionar heurística antiflood de refresh (backoff exponencial).

---

## 5. Regras de Segurança no Banco (RLS)

Dependemos de Row Level Security para proteger dados. A aplicação pressupõe policies:

- Tabelas de domínio (patients, doctors) filtradas por `auth.uid()` (ex: patient.id = auth.uid()).
- Tabela de roles apenas legível para o próprio usuário e roles administrativas.
- Operações de escrita restritas ao proprietário ou a roles privilegiadas.

Checklist a validar (fora do front):
[] Policies para SELECT/INSERT/UPDATE/DELETE em cada tabela sensível.
[] Policies específicas para evitar enumerar usuários (ex: `profiles`).
[] Remoção de permissões públicas redundantes.

---

## 6. Edge Functions

Usadas para:

- `user-info`: agrega roles + profile + permissões derivadas.
- `create-user`: fluxo atômico de criação (signup + role + domínio) quando disponível.

Critérios para mover lógica para Edge:

- Necessidade de Service Role Key (não pode ir ao front).
- Lógica multi-tabela que exige atomicidade e validação adicional.
- Redução de round-trips (performance e consistência).

---

## 7. Decisão: Proxy Backend (A Avaliar)

Status: NÃO implementado.

Quando justificar criar proxy:
| Cenário | Benefício do Proxy |
|---------|--------------------|
| Necessidade de Service Role | Segredo fora do client |
| Orquestração complexa >1 função | Transações / consistência |
| Rate limiting custom | Proteção anti-abuso |
| Auditoria centralizada | Logs correlacionados |

Custos de um proxy:

- Latência adicional.
- Manutenção (deploy, uptime, patches de segurança).
- Duplicação parcial de capacidades já cobertas por RLS.

Decisão atual: permanecer sem proxy até surgir necessidade concreta (service role / complexidade). Reavaliar trimestralmente.

---

## 8. Hardening do Cliente

Implementado:

- Interceptor único normaliza erros e tenta 1 refresh controlado.
- Remoção de tokens técnicos persistidos.
- Remoção de senha do domínio (ex: `MedicoCreate`).

Planejado:

- Content Security Policy estrita (nonce ou hashes para scripts inline).
- Sanitização consistente para HTML dinâmico (não inserir dangerouslySetInnerHTML sem validação).
- Substituir localStorage por memória + fallback volátil.
- Feature Policy / Permissions Policy (desabilitar sensores não usados).
- SRI (Subresource Integrity) para libs CDN (se adotadas no futuro).

---

## 9. Logging & Observabilidade

Diretrizes:

- Nunca logar tokens ou refresh tokens.
- Em produção, anonimizar IDs sensíveis onde possível (hash irreversível).
- Separar logs de segurança (auth failures, tentativas repetidas) de logs de aplicação.

Próximo passo: Implementar adaptador de log (console wrapper) com níveis + redaction de padrões (regex para JWT / emails).

---

## 10. Tratamento de Erros

Wrapper `http` fornece shape padronizado `ApiResponse<T>`.
Princípios:

- Não propagar stack trace de servidor ao usuário final.
- Exibir mensagem genérica em 5xx; detalhada em 4xx previsível (ex: validação).
- Em 401 após falha de refresh -> limpar sessão e redirecionar login.

---

## 11. Ameaças Principais & Contramedidas

| Ameaça                 | Vetor                       | Contramedida Atual                     | Próximo Passo                             |
| ---------------------- | --------------------------- | -------------------------------------- | ----------------------------------------- |
| XSS persistente        | Input não sanitizado        | Sem campos com HTML arbitrário         | CSP + sanitização + remover localStorage  |
| Token theft            | XSS / extensão maliciosa    | Sem service role key                   | Migrar tokens p/ memória                  |
| Enumeração de usuários | Erros detalhados em login   | Mensagem genérica                      | Rate limit + monitorar padrões            |
| Escalada de privilégio | Manipular roles client-side | Roles derivadas no backend (user-info) | Policies de atualização de roles estritas |
| Replay refresh token   | Interceptação               | TLS + troca de token no refresh        | Reduzir lifetime e detectar reuse         |

---

## 12. Roadmap de Segurança (Prioridade)

1. (P1) Migrar tokens para memória + session fallback.
2. (P1) Validar/Documentar RLS efetiva para cada tabela.
3. (P2) Implementar logging redaction adapter.
4. (P2) CSP + lint anti `dangerouslySetInnerHTML`.
5. (P3) Mecanismo de invalidação global de sessão (revogar refresh em logout server-side se necessário).
6. (P3) Testes automatizados de rota protegida (e2e smoke).

---

## 13. Serviços Atuais (Resumo)

| Domínio         | Arquivo                  | Observações                                                |
| --------------- | ------------------------ | ---------------------------------------------------------- |
| Autenticação    | `authService.ts`         | login, logout, refresh, user-info, getCurrentAuthUser      |
| Médicos         | `medicoService.ts`       | CRUD + remoção de password do payload                      |
| Pacientes       | `pacienteService.ts`     | Listagem/CRUD com normalização                             |
| Roles           | `userRoleService.ts`     | list/assign/delete                                         |
| Criação Usuário | `userCreationService.ts` | Edge first fallback manual                                 |
| Relatórios      | (planejado)              | Pendende confirmar implementação real (`reportService.ts`) |
| Consultas       | (planejado)              | Padronizar nome tabela (`consultas` vs `consultations`)    |
| SMS             | `smsService.ts`          | Placeholder                                                |

Arquivos legados/deprecados destinados a remoção após verificação de ausência de imports: `consultaService.ts`, `relatorioService.ts`, `listarPacientes.*`, `pacientes.js`, `api.js`.

---

## 14. Convenções de Código

- DB `snake_case` -> front `camelCase`.
- Limpeza de campos `undefined` antes de mutações (evita null overwrites).
- Requisições POST/PUT/PATCH com `Prefer: return=representation` quando necessário.
- ApiResponse<T>: `{ success: boolean, data?: T, error?: string, message?: string }`.

---

## 15. Scripts Básicos

Instalação:

```
pnpm install
```

Dev:

```
pnpm dev
```

Build:

```
pnpm build
```

---

## 16. Estrutura Simplificada

```
src/
  services/
  pages/
  components/
  entities/
```

---

## 17. Próximos Passos Técnicos (Geral)

- Implementar serviços faltantes (reports/consultas) alinhados ao padrão http wrapper.
- Testes unitários dos mapeadores (medico/paciente) e do fluxo de refresh.
- Avaliar substituição de localStorage (Roadmap P1).
- Revisar necessidade de proxy a cada trimestre (documentar decisão em CHANGELOG/ADR).

---

## 18. Desenvolvimento: Tipagem, Validação e Testes

### 18.1 Geração de Tipos a partir do OpenAPI

Arquivo da especificação parcial: `docs/api/openapi.partial.json`

Gerar (ou regenerar) os tipos TypeScript:

```
pnpm gen:api-types
```

Resultado: `src/types/api.d.ts` (não editar manualmente). Atualize o spec antes de regenerar.

Fluxo para adicionar/alterar endpoints:

1. Editar `openapi.partial.json` (paths / schemas).
2. Rodar `pnpm gen:api-types`.
3. Ajustar services para usar novos tipos (`components["schemas"]["<Nome>"]`).
4. Adicionar/atualizar validação Zod (se aplicável).
5. Criar ou atualizar testes.

### 18.2 Schemas de Validação (Zod)

Arquivo central: `src/validation/schemas.ts`

Inclui:

- `loginSchema`
- `patientInputSchema` + mapper `mapPatientFormToApi`
- `doctorCreateSchema` / `doctorUpdateSchema`
- `reportInputSchema` + mapper `mapReportFormToApi`

Boas práticas:

- Validar antes de chamar service.
- Usar mapper para manter isolamento entre modelo de formulário e payload API (snake_case).
- Adicionar novos schemas aqui ou dividir em módulos se crescer (ex: `validation/patient.ts`).

### 18.3 Testes (Vitest)

Config: `vitest.config.ts`

Scripts:

```
pnpm test        # execução única
pnpm test:watch  # modo watch
```

Suites atuais:

- `patient.mapping.test.ts`: mapeamento form -> API
- `doctor.schema.test.ts`: normalização de UF, campos obrigatórios
- `report.schema.test.ts`: payload mínimo e erros

Adicionar novo teste:

1. Criar arquivo em `src/tests/*.test.ts`.
2. Importar schema/service a validar.
3. Cobrir pelo menos 1 caso feliz e 1 caso de erro.

### 18.4 Padrões de Services

Cada service deve:

- Usar tipos gerados (`components["schemas"]`) para payload/response quando possível.
- Encapsular mapeamentos snake_case -> camelCase em funções privadas (ex: `mapReport`).
- Limpar chaves com valor `undefined` antes de enviar (já adotado em pacientes/relatórios).
- Emitir `{ success, data?, error? }` uniformemente.

### 18.5 Endpoints de Arquivos (Foto / Anexos Paciente)

Formalizados na spec com uploads `multipart/form-data`:

- `/auth/v1/pacientes/{id}/foto` (POST/DELETE)
- `/auth/v1/pacientes/{id}/anexos` (GET/POST)
- `/auth/v1/pacientes/{id}/anexos/{anexoId}` (DELETE)

Quando backend estabilizar response detalhado (ex: tipos MIME), atualizar schema `PacienteAnexo` e regenerar tipos.

### 18.6 Validação de CPF

Endpoint `/pacientes/validar-cpf` retorna schema `ValidacaoCPF`:

```
{
  "valido": boolean,
  "existe": boolean,
  "paciente_id": string | null
}
```

Integração: usar antes de criar paciente para alertar duplicidade.

### 18.7 Checklist ao Criar Novo Recurso

1. Definir schema no OpenAPI (entrada + saída).
2. Gerar tipos (`pnpm gen:api-types`).
3. Criar service com wrappers padronizados.
4. Adicionar Zod schema (form/input).
5. Criar testes (mínimo: validação + mapeamento).
6. Atualizar README (se conceito novo).
7. Verificar se precisa RLS/policy nova no backend.

### 18.8 Futuro: Automação CI

Pipeline desejado:

- Lint → Build → Test → (Gerar tipos e verificar diff do `api.d.ts`) → Deploy.
- Falhar se `docs/api/openapi.partial.json` mudou sem `api.d.ts` regenerado.

---

## 19. Referência Rápida

| Ação                   | Comando                            |
| ---------------------- | ---------------------------------- |
| Instalar deps          | `pnpm install`                     |
| Dev server             | `pnpm dev`                         |
| Build                  | `pnpm build`                       |
| Gerar tipos API        | `pnpm gen:api-types`               |
| Rodar testes           | `pnpm test`                        |
| Testes em watch        | `pnpm test:watch`                  |
| Atualizar spec + tipos | editar spec → `pnpm gen:api-types` |

---

## 19.1 Acessibilidade (A11y)

Recursos implementados para melhorar usabilidade, leitura e inclusão:

### Preferências do Usuário

Gerenciadas via hook `useAccessibilityPrefs` (localStorage, chave única `accessibility-prefs`). As opções persistem entre sessões e são aplicadas ao elemento `<html>` como classes utilitárias.

| Preferência        | Chave interna   | Classe aplicada     | Efeito Principal                                 |
| ------------------ | --------------- | ------------------- | ------------------------------------------------ |
| Tamanho da Fonte   | `fontSize`      | (inline style root) | Escala tipográfica global                        |
| Modo Escuro        | `darkMode`      | `dark`              | Ativa tema dark Tailwind                         |
| Alto Contraste     | `highContrast`  | `high-contrast`     | Contraste forte (cores simplificadas)            |
| Fonte Disléxica    | `dyslexicFont`  | `dyslexic-font`     | Aplica fonte OpenDyslexic (fallback legível)     |
| Espaçamento Linhas | `lineSpacing`   | `line-spacing`      | Aumenta `line-height` em blocos de texto         |
| Reduzir Movimento  | `reducedMotion` | `reduced-motion`    | Remove / suaviza animações não essenciais        |
| Filtro Luz Azul    | `lowBlueLight`  | `low-blue-light`    | Tonalidade quente para conforto visual noturno   |
| Modo Foco          | `focusMode`     | `focus-mode`        | Atenua elementos fora de foco (leitura seletiva) |
| Leitura de Texto   | `textToSpeech`  | (sem classe)        | TTS por hover (limite 180 chars)                 |

Atalho de teclado: `Alt + A` abre/fecha o menu de acessibilidade. `Esc` fecha quando aberto.

### Componente `AccessibilityMenu`

- Dialog semântico com `role="dialog"`, `aria-modal="true"`, foco inicial e trap de tab.
- Botões toggle com `aria-pressed` e feedback textual auxiliar.
- Reset central limpa preferências e cancela síntese de fala ativa.

### Formulários

- Todos os campos críticos com `id` + `label` associada.
- Atributos `autoComplete` coerentes (ex: `email`, `name`, `postal-code`, `bday`, `new-password`).
- Padrões (`pattern`) e `inputMode` para CPF, CEP, telefone, DDD, números.
- `aria-invalid` + mensagens condicionais (ex: confirmação de senha divergente).
- Normalização para envio (CPF/telefone/cep) realizada no service antes do request (sem formatação).

### Tabela de Pacientes

- Usa `scope="col"` nos cabeçalhos, suporte dark mode, indicador VIP com `aria-label`.

### Temas & CSS

Classes utilitárias adicionadas em `index.css` permitindo expansão futura sem alterar componentes. O design evita uso de inline style exceto na escala de fonte global, facilitando auditoria e CSP.

### Boas Práticas Futuras

1. Adicionar detecção automática de `prefers-reduced-motion` para estado inicial.
2. Implementar fallback de TTS selecionável por foco + tecla (reduzir leitura acidental).
3. Testes automatizados de acessibilidade (axe-core) e verificação de contraste.
4. Suporte a aumentar espaçamento de letras (letter-spacing) opcional.

---

### 19.2 Testes de Acessibilidade & Fallback de Render (Status Temporário)

Resumo do Problema:
Durante a criação de testes de interface para o `AccessibilityMenu`, o ambiente de testes (Vitest + jsdom e também `happy-dom`) deixou de materializar a árvore DOM de componentes React – inclusive para um componente mínimo (`<div>Hello</div>`). Não houve erros de compilação nem warnings relevantes, apenas `container.innerHTML === ''` após `render(...)`.

Hipóteses já investigadas (sem sucesso):

- Troca de `@vitejs/plugin-react-swc` por `@vitejs/plugin-react` (padrão Babel) + pin de versão do Vite (5.4.10).
- Alternância de ambiente (`jsdom` -> `happy-dom`).
- Remoção/isolamento de ícones (`lucide-react`) e libs auxiliares (mock de `@axe-core/react`).
- Render manual via `createRoot` e flush de microtasks.
- Ajustes de transform / esbuild jsx automatic.

Decisão Temporária (para garantir “teste que funciona”):

1. Marcar suites unitárias dependentes de render React como `describe.skip` enquanto a causa raiz é isolada.
2. Introduzir um teste E2E real em browser (Puppeteer) que valida a funcionalidade essencial do menu.

Arquivos Impactados:

- Skipped (com TODO):
  - `src/__tests__/accessibilityMenu.semantic.test.tsx`
  - `src/__tests__/miniRender.test.tsx`
  - `src/__tests__/manualRootRender.test.tsx`
- Novo teste E2E:
  - `src/__tests__/accessibilityMenu.e2e.test.ts`

Script E2E:

```
pnpm test:e2e-menu
```

O teste:

1. Sobe (ou reutiliza) o dev server Vite (porta 5173).
2. Abre a SPA no Chromium headless.
3. Clica no botão do menu de acessibilidade.
4. Verifica presença do diálogo (role="dialog") e depois fecha.

Critério de Aceite Provisório:
Enquanto o bug de render unitário persistir, a cobertura de comportamento crítico do menu é garantida pelo teste E2E (abre, foca, fecha). As preferências de acessibilidade continuam cobertas por testes unitários puros (sem render React) onde aplicável.

Próximos Passos para Retomar Testes Unitários:

1. Criar reprodutor mínimo externo (novo repo) com dependências congeladas para confirmar se é interação específica local.
2. Rodar `pnpm ls --depth 0` e comparar versões de `react`, `react-dom`, `@types/react`, `vitest`, `@vitejs/plugin-react`.
3. Forçar transpile isolado de um teste (`vitest --run --no-threads --dom`) para descartar interferência de thread pool.
4. Se persistir, habilitar logs detalhados de Vite (`DEBUG=vite:*`) e inspecionar saída transformada de um teste simples.
5. Reintroduzir gradativamente (mini -> menu) removendo mocks temporários.

Quando Corrigir:

- Remover skips (`describe.skip`).
- Reativar (opcional) auditoria `axe-core` com `@axe-core/react`.
- Documentar causa raiz aqui (ex: conflito de plugin, polyfill global, etc.).

Risco Residual:
Falhas específicas de acessibilidade sem cobertura E2E mais profunda (ex: foco cíclico em condições de teclado complexas) podem passar. Mitigação: expandir cenários E2E após estabilizar ambiente unitário.

Estado Atual: Fallback E2E ativo e validado. (Atualizar este bloco quando o pipeline unitário React estiver normalizado.)

---

---

## 18. ADRs (Decisões Arquiteturais) Resumidas

| ID      | Decisão                                       | Status | Justificativa                              |
| ------- | --------------------------------------------- | ------ | ------------------------------------------ |
| ADR-001 | Sem proxy backend inicial                     | Ativo  | RLS + Edge Functions suficientes agora     |
| ADR-002 | Tokens em memória + refresh em sessionStorage | Ativo  | Redução de risco XSS mantendo simplicidade |
| ADR-003 | Criação de usuário via Edge fallback manual   | Ativo  | Resiliência caso função indisponível       |

Registrar novas decisões futuras em uma pasta `docs/adr`.

---

## 19. Checklist de Release (Segurança)

[] Remover credenciais de desenvolvimento do README / código.
[] Validar CSP ativa no ambiente (report-only -> enforce).
[] Executar análise de dependências (npm audit / pnpm audit) e corrigir críticas.
[] Verificar que nenhum token aparece em logs.
[] Confirmar policies RLS completas.

---

## 20. Notas Finais

Este documento substitui versões anteriores e consolida segurança + operação. Atualize sempre que fluxos críticos mudarem (auth, roles, storage de tokens, Edge Functions novas).

---

Última atualização: (manter manualmente) 2025-10-03.

---

## 21. Logging Centralizado & Redaction

Implementado `logger.ts` substituindo gradualmente `console.*`.

Características:

- Níveis: debug, info, warn, error.
- Redação automática de:
  - Padrões de JWT (três segmentos base64url).
  - Campos com `token`, `password`, `secret`, `email`.
  - Emails em strings.
- Nível dinâmico: produção => `info+`, demais => `debug`.

Uso:

```
import { logger } from 'src/services/logger';
logger.info('login success', { userId });
```

Práticas recomendadas:

- Não logar payloads completos com PII.
- Remover valores sensíveis antes de enviar para meta.
- Usar `error` somente para falhas não recuperáveis ou que exigem telemetria.

Backlog de logging:

- Adicionar transporte opcional (Sentry / Logtail).
- Exportar métricas (Prometheus / OTEL) para 401s e latência.

Status adicional:

- Mascaramento de CPF implementado (`***CPF***XX`).
- Contador global de 401 consecutivos com limite (3) antes de limpeza forçada de sessão.

---

## 22. Política CSP (Rascunho)

Objetivo: mitigar XSS e exfiltração de contexto.

Cabeçalho sugerido (Report-Only inicial):

```
Content-Security-Policy-Report-Only: \
  default-src 'self'; \
  script-src 'self' 'strict-dynamic' 'nonce-<nonce-value>' 'unsafe-inline'; \
  style-src 'self' 'unsafe-inline'; \
  img-src 'self' data: blob:; \
  font-src 'self'; \
  connect-src 'self' https://*.supabase.co; \
  frame-ancestors 'none'; \
  base-uri 'self'; \
  form-action 'self'; \
  object-src 'none'; \
  upgrade-insecure-requests; \
  report-uri https://example.com/csp-report
```

Adoção:

1. Aplicar em modo report-only (Netlify / edge) e coletar violações.
2. Eliminar dependências inline e remover `'unsafe-inline'`.
3. Adicionar hashes/nonce definitivos.
4. Migrar para modo enforce.

Complementos:

- Lint contra `dangerouslySetInnerHTML` sem sanitização.
- Biblioteca de sanitização (ex: DOMPurify) caso HTML dinâmico seja necessário.

---

## 23. Contador de 401 Consecutivos

Mecânica:

- Cada resposta final 401 (sem refresh bem-sucedido) incrementa contador global.
- Sucesso de requisição ou refresh resetam o contador.
- Ao atingir 3, sessão é limpa (`tokenStore.clear()`) e próximo acesso exigirá novo login.

Racional: evitar loops silenciosos de requisições falhando e reduzir superfície de brute force de refresh.

Parâmetros:

- Limite atual: 3 (configurável em `src/services/authConfig.ts`).

---

## 24. Verificação de Drift do OpenAPI

Script: `pnpm check:api-drift`

Fluxo CI recomendado:

1. Rodar `pnpm check:api-drift`.
2. Se falhar, forçar desenvolvedor a executar `pnpm gen:api-types` e commitar.

Implementação: gera tipos em memória via `openapi-typescript` e compara com `src/types/api.d.ts` normalizando quebras de linha.

---

## 25. Mascaramento de CPF no Logger

Padrão suportado: 11 dígitos com ou sem formatação (`000.000.000-00`).
Saída: `***CPF***00` (mantendo apenas os dois últimos dígitos para correlação mínima).

Objetivo: evitar exposição de identificador completo em logs persistentes.
