Commit Graph

149 Commits

Author SHA1 Message Date
VPS 4 Deploy Agent 9bda1dbb03 hotfix: remove undefined isMobile from DashboardPage
continuous-integration/webhook Deploy concluído (VPS4)
2026-05-31 21:38:16 +02:00
VPS 4 Deploy Agent fa9208189f chore(deploy): bump version
continuous-integration/webhook Ignorado: bump version
2026-05-31 21:31:14 +02:00
VPS 4 Deploy Agent 3700f5c493 fix(mobile): refactor headers and orientation choose UI to avoid layout break
continuous-integration/webhook Deploy concluído (VPS4)
2026-05-31 21:27:03 +02:00
VPS 4 Deploy Agent 4fb6181289 chore(deploy): bump version
continuous-integration/webhook Ignorado: bump version
2026-05-31 21:12:13 +02:00
VPS 4 Deploy Agent f8ddbc0743 feat(mobile): improve search UX and ImageDetails orientation UX
continuous-integration/webhook Deploy concluído (VPS4)
2026-05-31 21:08:27 +02:00
VPS 4 Deploy Agent cacacfe9e7 chore(deploy): bump version
continuous-integration/webhook Ignorado: bump version
2026-05-31 20:01:20 +02:00
VPS 4 Deploy Agent bcad7c4720 feat: layout mobile responsivo completo
continuous-integration/webhook Deploy concluído (VPS4)
2026-05-31 19:57:15 +02:00
VPS 4 Deploy Agent 0df3cb41d0 chore(deploy): bump version
continuous-integration/webhook Ignorado: bump version
2026-05-31 16:46:33 +02:00
VPS 4 Deploy Agent 9f02c41c31 feat(ui): responsividade mobile profissional (320px+) sem alterar desktop
continuous-integration/webhook Deploy concluído (VPS4)
Todo o tratamento mobile é aditivo e isolado atrás de @media (max-width:1023px/
480px/360px) — o visual desktop (≥1024px) permanece pixel-idêntico.

Navegação:
- Sidebar.jsx: vira drawer deslizante no mobile (top-bar fixo + hambúrguer +
  backdrop + botão fechar). Trava scroll do body, fecha ao navegar/tocar item.
  No desktop continua sidebar fixa idêntica.

Componente novo:
- DropdownMenu.jsx: menu flutuante chevron-down reutilizável (fecha em
  outside-click/ESC). Usado para colapsar ações secundárias no mobile.

Headers (GtosPage, PatientsPage):
- Busca full-width; botões "+ Novo/Atualizar" em linha no desktop (.hide-mobile)
  e colapsados em DropdownMenu no mobile (.show-mobile).

Tabelas → cards empilhados (PatientsPage, GtosPage, AdminClinicsPage):
- classe .responsive-table + data-label em cada td. No mobile thead some e
  cada linha vira card com rótulo:valor. Desktop mantém tabela normal.

CSS (index.css):
- Sistema de breakpoints completo, drawer, dropdown, cards de tabela,
  grid de thumbs reduzido, modais fullscreen, 100dvh, inputs 16px (anti-zoom
  iOS), alvos de toque ≥40px, paginação/stat-cards que quebram linha.

Fix: remove chave 'border' duplicada no style do stat card da GtosPage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 16:43:19 +02:00
VPS 4 Deploy Agent 5f8a4836b5 chore(deploy): bump version
continuous-integration/webhook Ignorado: bump version
2026-05-31 16:29:34 +02:00
VPS 4 Deploy Agent 35248fb27b fix(gtos): compatibilidade TransformModal com novo formato da API
continuous-integration/webhook Deploy concluído (VPS4)
A refatoração do GET /api/gtos para retornar { rows, total, pages }
quebrou o TransformModal que esperava um array direto.

Correções:
- routes/gtos.js: restaura suporte a ?patient=NOME (match exato) para
  o TransformModal continuar filtrando só as GTOs do paciente exibido,
  sem retornar resultados de outros pacientes via ILIKE.
- TransformModal.jsx: lê data.rows (novo formato) com fallback para
  array direto (compatibilidade durante transição).

As duas superfícies (TransformModal e GtosPage) agora usam a mesma
API, mesmos dados, sem lógica duplicada ou conflitante.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 16:25:37 +02:00
VPS 4 Deploy Agent b18e78cc6c chore(deploy): bump version
continuous-integration/webhook Ignorado: bump version
2026-05-31 16:09:48 +02:00
VPS 4 Deploy Agent f027842c76 feat(gtos): página de gerenciamento de GTOs com filtros e paginação
continuous-integration/webhook Deploy concluído (VPS4)
Backend:
- routes/gtos.js: GET /api/gtos reescrito com filtros (all/vinculada/enviada),
  busca ILIKE por patient_name e gto_number, paginação (page/limit),
  retorna { rows, total, pages } + thumb_url da primeira imagem vinculada.

Frontend:
- GtosPage.jsx (/gtos): cards de stats clicáveis (Todas/Vinculadas/Enviadas)
  com contadores em tempo real; tabela com colunas: thumb, número, paciente,
  qtd imagens (badge colorido), descrição, data, status, ações; paginação
  numérica; busca com debounce 350ms.
- StatusBadge: Pendente / Vinculada / Enviada com cores distintas.
- GtoDetailModal: info completa, grid de imagens vinculadas com thumb +
  botão desvincular, toggle enviada/pendente com feedback visual.
- CreateGtoModal: formulário com número, paciente, descrição.
- Sidebar: item GTOs (fa-file-medical) entre Pacientes e Novo Paciente.
- App.jsx: rota /gtos (ProtectedRoute).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 16:06:42 +02:00
VPS 4 Deploy Agent 98dcb729a5 chore(deploy): bump version
continuous-integration/webhook Ignorado: bump version
2026-05-31 16:00:51 +02:00
VPS 4 Deploy Agent b6a1d3d68e fix(clinics): 3 bugs de unicidade e wipe corrigidos
continuous-integration/webhook Deploy concluído (VPS4)
1. admin-clinics.js — bloqueia cadastro de clinic_name + pc_name duplicados:
   Antes só validava email único. Agora verifica se já existe dispositivo com
   a mesma combinação clinic_name + pc_name (case-insensitive). Sem isso, dois
   PCs com mesmo nome na mesma clínica sobrescreveriam arquivos um do outro
   no Wasabi (caminho idêntico).

2. admin-clinics.js — wipe usava client_name ao invés de clinic_name no banco:
   'DELETE FROM images WHERE client_name = clinic_name' deletava o conjunto
   errado de imagens (client_name é o nome do PC, não da clínica). Corrigido
   para 'WHERE clinic_name = $1'. Wasabi continua usando sanitize(clinic_name)/
   como prefixo (correto).

3. server.js — verificação de duplicata no connect incluía clinicName:
   O check usava só clientName (pc_name), causando falso positivo: dois PCs
   de clínicas diferentes com o mesmo nome (ex: ambos "PC-SALA-1") — o segundo
   era desconectado. Agora verifica clinicName + clientName juntos.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 15:57:37 +02:00
VPS 4 Deploy Agent 32ac1f119f chore(deploy): bump version
continuous-integration/webhook Ignorado: bump version
2026-05-31 15:40:24 +02:00
VPS 4 Deploy Agent 62e3ded5a7 feat(auth): token-first — device-info endpoint + pc_name autoritativo
continuous-integration/webhook Deploy concluído (VPS4)
- GET /api/auth/device-info?token=xxx: valida machine_token e retorna
  clinic_name e pc_name sem exigir email/senha. Usado pelo client para
  preview antes de salvar e para validação no save.

- client-identify: quando autenticado via machine_token, usa
  socket.user.pcName como nome autoritativo (ignora o que o client enviou).

- server-identified: clientInfo agora inclui 'pcName' para o client
  manter o nome em sincronia com o cadastro do servidor.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 15:36:56 +02:00
VPS 4 Deploy Agent c43e752694 chore(deploy): bump version
continuous-integration/webhook Ignorado: bump version
2026-05-31 09:10:41 +02:00
VPS 4 Deploy Agent 526f3f2eae fix(auth): machine_token não exige email+senha no socket + case-insensitive
continuous-integration/webhook Deploy concluído (VPS4)
Bugs corrigidos:

1. Condição bloqueante: 'if (email && password && token.includes("-"))' fazia
   o machine_token ser ignorado se o client conectasse só com o token (sem
   email/senha). A conexão caía para o check de JWT, falhava e era rejeitada.
   Agora o machine_token é verificado sempre que o token contém hífens —
   email+senha são opcionais (validados se presentes, ignorados se ausentes).

2. Comparação de email case-sensitive: 'device.email === email' falhava
   se houver diferença de maiúsculas/minúsculas entre o cadastro e o config
   do client. Corrigido para .toLowerCase() em ambos os lados.

3. Log de autenticação: emite mensagem clara no console quando machine_token
   é aceito, incluindo nome da clínica e do PC, facilitando diagnóstico.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 09:06:29 +02:00
VPS 4 Deploy Agent 42fc1fc90e chore(deploy): bump version
continuous-integration/webhook Ignorado: bump version
2026-05-31 07:56:19 +02:00
VPS 4 Deploy Agent 1d19c8e845 fix(sync): corrige event name force-sync → sync-request no trigger-sync
continuous-integration/webhook Deploy concluído (VPS4)
O servidor emitia 'force-sync' mas o client-monitor.js só ouve
'sync-request'. O botão Sincronizar do painel nunca chegava ao cliente.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 07:53:07 +02:00
VPS 4 Deploy Agent 0b1e62538a chore(deploy): bump version
continuous-integration/webhook Ignorado: bump version
2026-05-31 07:52:04 +02:00
VPS 4 Deploy Agent 7b883761ef fix(storage): elimina inconsistências de clinicName/patientName no Wasabi
continuous-integration/webhook Deploy concluído (VPS4)
Causa das gambiarras identificadas e corrigidas:

1. clinicName inconsistente: `(clientInfo ? clientInfo.clinicName : fallback)`
   retornava undefined quando clientInfo.clinicName não estava definido,
   gerando pasta 'desconhecido' no Wasabi para clientes sem machine_token.
   Corrigido para `clientInfo?.clinicName || 'Clínica não identificada'`
   nos 3 handlers: send-image, request-presigned-urls, image-upload-direct.

2. patientName inconsistente: banco gravava 'Paciente não identificado'
   mas Wasabi usava 'Desconhecido' quando o nome estava vazio, quebrando
   a recuperação por key. Ambos agora usam 'Desconhecido' como fallback.

O getImageBufferWithFallback com tentativa em 'Desconhecido' permanece
como safety net para imagens antigas já gravadas no Wasabi, mas não
será mais necessário para novos uploads.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 07:48:46 +02:00
VPS 4 Deploy Agent 33ee2cf801 chore(deploy): bump version
continuous-integration/webhook Ignorado: bump version
2026-05-31 07:41:57 +02:00
VPS 4 Deploy Agent 83ea87911b fix(ui): ThumbImg com fallback automático para thumbnails ausentes (404)
continuous-integration/webhook Deploy concluído (VPS4)
Cria ThumbImg.jsx: wrapper de <img> que intercepta onError e exibe
placeholder 🦷 + label "Aguardando reenvio" em vez de imagem quebrada.

Aplicado em:
- DashboardPage: cards de pacientes e galeria de imagens do paciente
- PatientsPage: miniatura na coluna Nome da tabela

Enquanto o Plan B (reupload-files) não tiver sido concluído pelo cliente
Windows, o card exibe o placeholder informativo em vez de ícone de erro.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 07:38:22 +02:00
VPS 4 Deploy Agent 40ec9b94eb chore(deploy): bump version
continuous-integration/webhook Ignorado: bump version
2026-05-31 07:13:22 +02:00
VPS 4 Deploy Agent aa147a3551 fix(cron): adiciona cron verifyStorage + corrige dispatch manual
continuous-integration/webhook Deploy concluído (VPS4)
- Novo cron 'verifyStorage' (30min): percorre as 200 imagens mais
  recentes, tenta buscar no storage com fallback legado; para cada
  arquivo ausente aciona scheduleReupload() (Plan B) imediatamente.
  Primeira execução 15s após o boot para cobrir os IDs 404 sem esperar
  o usuário abrir o card.

- cronState agora tem dois jobs; /api/cron/status retorna ambos.
- POST /api/cron/run/:key usa mapa de funções; suporta 'thumbBackfill'
  e 'verifyStorage' (botão "Executar agora" na tela de Configurações).

- lastResult do verifyStorage inclui: checked, missing, requested.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 07:10:28 +02:00
VPS 4 Deploy Agent b044aa0f3a chore(deploy): bump version
continuous-integration/webhook Ignorado: bump version
2026-05-31 06:55:10 +02:00
VPS 4 Deploy Agent e716e0e131 fix: cron enabled=1 + plan-b reenvio automático de imagens ausentes
continuous-integration/webhook Deploy concluído (VPS4)
Bug fix:
- server.js e routes/images.js: 'enabled = true' → 'enabled = 1'
  (PostgreSQL rejeita smallint = boolean — causava 'operator does not exist')

Plan B — imagens ausentes no Wasabi:
- server.js: pendingReupload (Map clientName → Set<original_filename>)
  quando getImageBufferWithFallback retorna null no endpoint /thumbnail,
  scheduleReupload() registra o original_filename e emite 'reupload-files'
  imediatamente se o cliente estiver online, ou na próxima conexão.
- server.js: client-identify agora drena a fila pendente do cliente ao
  reconectar, antes de emitir clients-list-updated.
- original_filename adicionado ao SELECT do endpoint /thumbnail.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 06:52:39 +02:00
VPS 4 Deploy Agent 75ce7c1f36 chore(deploy): bump version
continuous-integration/webhook Ignorado: bump version
2026-05-31 06:47:32 +02:00
VPS 4 Deploy Agent 67accb56aa feat: cron automático de thumbnails + lista de pacientes em tabela + CRUD
continuous-integration/webhook Deploy concluído (VPS4)
Backend:
- server.js: cron thumb-backfill a cada 10min com rastreio de estado
  (lastRun, nextRun, running, lastResult). GET /api/cron/status e
  POST /api/cron/run/:key para consulta e disparo manual via painel.
- routes/images.js: PUT /api/images/patients/:name — edita patient_name,
  doctor e remark em todas as imagens do paciente de uma vez.

Frontend:
- PatientsPage.jsx (/patients): tabela com colunas Nome (+ miniatura),
  Dentista, Imagens, Última atualização, Observações, Ações. Suporta
  busca, paginação infinita, editar e excluir por linha.
- SettingsPage.jsx (/settings): seção de Cron Jobs com status, resultado
  e botão "Executar agora"; seção de informações do servidor.
- EditPatientModal.jsx: edita nome, dentista e observações do paciente.
- Sidebar.jsx: add "Pacientes" (todos usuários) e "Configurações" (admin).
- App.jsx: rotas /patients (protegida) e /settings (admin).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 06:44:45 +02:00
VPS 4 Deploy Agent 003e568318 chore(deploy): bump version
continuous-integration/webhook Ignorado: bump version
2026-05-31 06:37:07 +02:00
VPS 4 Deploy Agent 8f8fba2f82 fix(thumbnail): corrige 500 em RX sem thumb — fallback Wasabi legado
continuous-integration/webhook Deploy concluído (VPS4)
Causa raiz: request-presigned-urls usava firstName/lastName para montar
o patientName do caminho no Wasabi, mas o client envia apenas name.
Resultado: toda imagem era salva em '.../Desconhecido/arquivo.png' no
Wasabi, mas o banco guardava o nome real do paciente — na recuperação,
a key ficava diferente e resultava em NoSuchKey → 500.

Correções:
1. server.js: getImageBufferWithFallback() — tenta o path correto (nome
   real) e, se falhar, tenta o path legado 'Desconhecido'. Usado tanto
   para ler thumb existente quanto para gerar do original.
2. server.js: patientName corrigido em send-image e request-presigned-urls
   para usar data.patientData.name (o campo que o client realmente envia),
   garantindo consistência entre Wasabi e banco em novos uploads.
3. routes/images.js: runThumbBackfill agora usa storage.getImageBuffer
   com fallback 'Desconhecido' em vez de leitura apenas do disco local
   — o boot backfill passa a funcionar para imagens no Wasabi.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 06:34:07 +02:00
VPS 4 Deploy Agent aba438b4d5 chore(deploy): bump version
continuous-integration/webhook Ignorado: bump version
2026-05-31 05:21:33 +02:00
VPS 4 Deploy Agent 9786b96fd7 fix(frontend): exibe clínica antes do nome do PC na lista de dispositivos
continuous-integration/webhook Deploy concluído (VPS4)
Item 1 — Clínica antes do PC:
- public_legacy/clients.html: nome exibido como "Clínica — PC" na lista
  de clientes identificados no painel de monitoramento.
- public_legacy/app.js: displayName dos clientes ativos agora inclui
  clinicName como prefixo ("Clínica — PC"); propagado automaticamente
  para o dropdown de filtro e demais usos que iteram clientsList.
  Card de sincronização de dispositivos atualizado da mesma forma.
  Clínicas sem identificação ("Clínica não identificada") exibem só o
  nome do PC (sem prefixo vazio).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 05:12:55 +02:00
VPS 4 Deploy Agent 0483a842f1 chore(deploy): bump version
continuous-integration/webhook Ignorado: bump version
2026-05-31 02:36:36 +02:00
VPS 4 Deploy Agent 7cdd82eeb4 fix(sync): re-upload correto quando arquivo foi deletado do storage
continuous-integration/webhook Deploy concluído (VPS4)
- storage.js: adiciona fileExists() com HeadObject (sem baixar o arquivo)
- check-image-exists: verifica existência física no storage, não só no banco;
  se registro existe mas arquivo não, apaga o registro órfão e retorna exists=false
- send-image: mesma lógica — registro órfão é removido e re-upload prossegue
- Remove migrate-to-wasabi.js do repositório

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 02:33:33 +02:00
VPS 4 Deploy Agent 91881ab7a3 chore(deploy): bump version
continuous-integration/webhook Ignorado: bump version
2026-05-31 01:58:36 +02:00
VPS 4 Deploy Agent 21f33c88a4 feat(storage): reorganiza Wasabi com estrutura clinic_name/pc_name/patient_name
continuous-integration/webhook Deploy concluído (VPS4)
- Adiciona coluna clinic_name em images (ALTER TABLE IF NOT EXISTS)
- Todas as funções de storage recebem clinicName como parâmetro: saveImage,
  getImageBuffer, getImageUrl, deleteImage, getDownloadPresignedUrl, getUploadPresignedUrl
- Chave Wasabi passa de pc_name/patient/arquivo → clinic_name/pc_name/patient/arquivo
- server.js: usa socket.user.clinicName (preenchido via machine_token auth do DB) como
  fonte primária do nome da clínica nos 3 handlers de upload e na rota thumbnail
- Todos os INSERTs em images passam a gravar clinic_name
- Corrige bug oculto: wipe de clínica agora apaga o prefixo correto no Wasabi
- Scripts utilitários atualizados: backfill-wasabi-thumbs, recreate-all-thumbs, migrate-to-wasabi
- client-monitor.js: envia clinicName no client-identify (fallback para clientes legados)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 01:56:18 +02:00
VPS 4 Deploy Agent 651afb49bc chore(deploy): bump version
continuous-integration/webhook Ignorado: bump version
2026-05-31 01:34:01 +02:00
VPS 4 Deploy Agent 22be2adefd fix(clinics): adiciona campo senha no formulário de cadastro de clínica
continuous-integration/webhook Deploy concluído (VPS4)
- Form não enviava password → servidor retornava 400 em todo cadastro
- Adicionado input password no modal de cadastro
- pc_name tornado opcional no servidor (já era opcional no UI)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 01:30:52 +02:00
VPS 4 Deploy Agent 7fec895778 chore(deploy): bump version
continuous-integration/webhook Ignorado: bump version
2026-05-31 01:13:37 +02:00
VPS 4 Deploy Agent f158325002 fix(client): renomeia RF Dental → Score Client e corrige URL do executável
continuous-integration/webhook Deploy concluído (VPS4)
- Troca nome do sistema de "RF Dental" para "Score Client" em toda UI (título, sidebar, login, página de download)
- Corrige link de download: era hardcoded /updates/RFDental-Setup.exe (inexistente), agora lê o nome real do arquivo a partir do latest.yml e constrói URL versionada dinamicamente

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 01:08:07 +02:00
VPS 4 Deploy Agent 16f16d7d8e chore(deploy): bump version
continuous-integration/webhook Ignorado: bump version
2026-05-30 23:46:12 +02:00
VPS 4 Deploy Agent 8796558fa3 feat(clinics): wipe cirúrgico por dispositivo — apaga banco + pasta Wasabi só da clínica; remove Zerar Sistema da sidebar
continuous-integration/webhook Deploy concluído (VPS4)
- DELETE /admin/clinics/:id/wipe: apaga images/gto_images do banco (WHERE client_name),
  lista e deleta em batch todos os objetos Wasabi com prefixo 'clinic_name/',
  e remove o registro do dispositivo
- UI: botão 'Limpar dados' (🧹) separado do 🗑️ (remove só o cadastro),
  modal com aviso, confirmação e log da operação
- Sidebar: remove link 'Zerar Sistema'
2026-05-30 23:42:46 +02:00
VPS 4 Deploy Agent e0ddb7e0ec chore(deploy): bump version
continuous-integration/webhook Ignorado: bump version
2026-05-30 23:29:56 +02:00
VPS 4 Deploy Agent c7f24fc8d2 fix(a11y): add id/name and htmlFor to all form fields — fix browser warnings about unlabeled inputs
continuous-integration/webhook Deploy concluído (VPS4)
2026-05-30 23:27:00 +02:00
VPS 4 Deploy Agent 61a4c3ab76 chore(deploy): bump version
continuous-integration/webhook Ignorado: bump version
2026-05-30 23:11:45 +02:00
VPS 4 Deploy Agent 7861ad5870 fix(transform): overflow:hidden no painel + imagem 65% (65%×√2≈92% — cabe em qualquer ângulo)
continuous-integration/webhook Deploy concluído (VPS4)
2026-05-30 23:08:17 +02:00
VPS 4 Deploy Agent 2bdd78ec59 chore(deploy): bump version
continuous-integration/webhook Ignorado: bump version
2026-05-30 21:29:25 +02:00