# RX — Backlog de robustez, segurança e limpeza > Tarefas derivadas da revisão de 2026-06-12 (multi-tenant + client.exe + storage). > Prioridade: **P1** (faria primeiro) · **P2** · **P3**. Marcar `[x]` ao concluir. > Regra do projeto: nada vai pra prod sem autorização; dev.rx e prod.rx **compartilham > DB+Wasabi** (ver T3.1 — separar é o que mais reduz risco). --- ## 3. Robustez do RX / resync - [ ] **T3.1 (P1) — Separar DEV de PROD (DB + Wasabi).** Hoje compartilham o mesmo Postgres (`dental_images`) e o mesmo bucket → testes mexem em dado real. Opções: banco `dental_images_dev` e/ou prefixo/bucket Wasabi por ambiente (`RX_ENV`). - [x] **T3.2 (P1) — Healthcheck de reconciliação Wasabi↔banco** por `clinica_id`/`tenant_id`. FEITO (dev): `GET /api/admin/rx-health` (RX) — contagens por (tenant,clínica) + cron + `?clinica_id=&checkLimit=N` (HEAD-check de ausentes). Proxy `GET /api/rx/health` (scoreodonto, superadmin). Validado: Consultt 2723 imgs/513 pac, 0 ausentes em 15. Commit 016305e. - [ ] **T3.3 (P2) — Índice único parcial** `images(original_filename) WHERE enabled=1` como trava de duplicata no banco. ⚠️ Criar CONCURRENTLY e fora do boot (se houver duplicata, a criação no boot derrubaria o servidor). - [ ] **T3.4 (P2) — Remover `send-image` legado** após confirmar que todo `.exe` em campo é ≥ Direct Upload (1.3.x). Elimina um caminho de upload + base64 pela VPS. - [ ] **T3.5 (P2) — Throttle/progresso no resync.** `trigger-sync` reescaneia todos os PNGs; em clínica grande é pesado → lote + reporte de progresso. - [ ] **T3.6 (P3) — `check-image-exists`**: garantir que checa linha no banco **E** objeto no Wasabi (senão objeto sumido nunca é reenviado). ## 4. Client.exe - [ ] **T4.1 (P1) — Code signing do instalador NSIS** (evita SmartScreen nas clínicas). - [ ] **T4.2 (P1) — `machine_token` em repouso**: proteger no config local (DPAPI/cripto). - [ ] **T4.3 (P2) — Retry/backoff + fila persistente** nos PUT do Wasabi e na `uploadQueue` (sobreviver a restart / internet ruim). - [ ] **T4.4 (P2) — Telemetria pro `/clients`**: client envia `last_sync`, profundidade da fila e últimos erros → página mostra saúde real. - [ ] **T4.5 (P2) — `lookupPatientInfo` tolerante a versão** do banco do sensor RF. - [ ] **T4.6 (P3) — Pipeline de auto-update**: automatizar envio de `Setup x.y.z.exe` + `latest.yml` pro `updates/` do prod ao rebuildar. ## 5. Segurança / hardening - [ ] **T5.1 (P1) — `api_token` global criptografado em repouso** (hoje texto puro em `settings.rx_config_global`) + rotação + idealmente token de escopo reduzido (não-god). - [x] **T5.2 (P1) — Auditar escopo GLOBAL do `tenantGuard`** — FEITO (dev). 🔴 Achado crítico: a família `/api/sync/*` (sync GLOBAL legado) usava `tenantGuard` → **burlável sem clinicaId**; `DELETE /api/sync/truncate-all` fazia `TRUNCATE pacientes,agendamentos,financeiro,leads,guias` de **todas as clínicas** → qualquer usuário logado (até funcionário) apagava o banco inteiro. **Corrigido**: os 13 endpoints `/api/sync/*` → `superadminGuard`. Provado: não-superadmin agora recebe **403** (antes truncava). 2º achado: **`/api/settings/google-credentials`** GET+POST (credenciais OAuth GLOBAIS da plataforma) também era `tenantGuard` → qualquer logado sobrescrevia → **→ `superadminGuard`** (403 p/ não-super; front só chama p/ superadmin). **Auditoria completa**: todos os demais `tenantGuard` (clinica-sync, dashboard, agendamentos, avaliacoes, financeiro, guias, leads/:id/converter, DELETE :id, rx/devices) exigem `req.clinicaId` + `WHERE clinica_id` → seguros. - [ ] **T5.3 (P1) — Auth do `remote-crud-patient`** (socket escreve no banco local do client): validar papel/escopo forte no servidor. - [ ] **T5.4 (P2) — Defesa em profundidade no RX server**: validar tenant nos endpoints admin (não confiar só no proxy do scoreodonto). - [ ] **T5.5 (P2) — Revisar os 9 dias de WIP** (`auth.js`, `database.js`, `storage.js`, páginas) antes do prod. - [!] **T5.6 (P3→P0) — Auditar histórico do git por segredos** — FEITO. 🔴🔴🔴 ACHADOS CRÍTICOS: - `dental-server/bkp/docs/ENV-CONFIG.txt` tem o **`JWT_SECRET` REAL** (confirmado == o do servidor) commitado → **qualquer um com acesso ao repo forja JWT de admin do RX**. - `INSTRUCOES-SERVIDOR-VPS.txt` tem o **`DB_PASSWORD`/`REDIS_PASSWORD` reais** em texto puro. AÇÃO OBRIGATÓRIA (decisão do usuário, não automatizei): 1. **Rotacionar JWT_SECRET** (invalida tokens, força re-login) — fecha a forja. 2. **Rotacionar senha do Postgres/Redis** (10.99.0.3). 3. Remover os segredos dos arquivos versionados + **scrub do histórico** (git filter-repo/BFG). `.secrets` já está no .gitignore (feito antes); isso NÃO resolve os já commitados → rotação é mandatória. ## 6. Limpeza / tech-debt - [ ] **T6.1 (P1) — Consolidar os 4 caminhos de upload** (`image-upload-direct`, `send-image`, `/api/images/upload`, `/upload-file`) → manter 1–2, remover o resto. - [ ] **T6.2 (P2) — Simplificar `storage.js` pós-resync** (remover fallback legado quando todos os objetos estiverem na key nova). - [ ] **T6.3 (P2) — Remover diretórios mortos** (`bkp/`, `public_legacy/`, `old-root-files/`). - [ ] **T6.4 (P3) — Upgrade Node 20 → 22** (AWS SDK exigirá ≥22 em 2027). - [ ] **T6.5 (P3) — Log levels** (info/debug/error) no servidor RX. - [ ] **T6.6 (P3) — Passada final de comentários/padronização** no fluxo RX. --- ### Log - **2026-06-12** — T3.2 concluída (healthcheck de reconciliação, read-only). - **2026-06-12** — T5.2 concluída. 🔴 Fechado RCE-like: `/api/sync/truncate-all` (e família) + `/api/settings/google-credentials` deixavam qualquer logado truncar o banco / trocar OAuth global → agora `superadminGuard` (403 p/ não-super). Mudanças no **scoreodonto (dev), não commitadas**. - **2026-06-12** — T3.6 auditada: `check-image-exists` já está correto (checa banco+Wasabi, apaga órfão). Sem fix. - **2026-06-12** — T5.6 🔴🔴🔴: JWT_SECRET REAL + senha de DB/Redis commitados (ENV-CONFIG.txt, EXEMPLO-ENV.txt, INSTRUCOES-SERVIDOR-VPS.txt, test-db2.js). **Passo 3 FEITO** (redigidos do working tree, commits 4616f20+2b679a5). **PENDENTE/MANDATÓRIO (usuário): rotacionar JWT_SECRET + senha Postgres/Redis + scrub do histórico** — até lá, a exposição persiste no histórico do Gitea.