Commit Graph

27 Commits

Author SHA1 Message Date
VPS 4 Builder 1e4f4dee2f feat(config): importar pacientes de planilha Google existente (somente-leitura)
- backend POST /api/clinica-sync/import-pacientes (le aba 'pacientes' de um ID/URL, nao altera sheets_id nem a planilha)
- endpoint set-id (opcional) para apontar planilha de backup
- frontend: campo de ID/URL + botao Importar no card Backup; rotulo Restaurar->Importar

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 01:24:44 +02:00
VPS 4 Builder c54532d5ea feat(agenda): importa cor do evento Google + UI do modal pequeno
- agendamentos.cor (TEXT); import grava cor do evento (colorId/agenda)
- frontend usa ag.cor (prioridade: status > cor própria > cor do dentista)
- StackModal: remove backdrop-blur (vidro); mobile vira bottom-sheet de altura auto, desktop painel pequeno com max-w; botão maximizar visível no mobile; padding responsivo

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 18:26:17 +02:00
VPS 4 Builder 1cfd184886 feat(agenda): importar agendamentos do Google para o sistema (admin/dono)
- POST /api/agenda/importar-google: janela -7d/+Ndias (default 60), idempotente por google_event_id, só dono/admin
- eventos importados viram agendamentos editáveis (status agendado, google_event_id preenchido)
- getGoogleEvents filtra os já importados (anti-duplicação)
- frontend: botão Download no cabeçalho (admin/dono) com confirmação e resultado
- testado: 113 criados / 113 pulados na 2a execução (idempotente); dados de teste limpos

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 18:03:46 +02:00
VPS 4 Builder eed0f615c8 fix(agenda): token Google malformado (state) + cores reais das agendas
- callback OAuth: decodifica state defensivamente (|/%7C/%257C) + salvaguarda re-split (evita owner_id colado com clinica_id nulo)
- reparo do token existente da recepção (script aplicado no banco)
- eventos do Google agora usam a cor real (colorId / cor da agenda); paleta padrão do Google
- frontend: eventos sem cor recebem cor NÃO usada na agenda, consistente por origem

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 17:37:28 +02:00
VPS 4 Builder 0ca0aa4284 feat(agenda): Google Calendar como backup + notificação (push one-way)
- escopo OAuth: calendar.readonly -> calendar.events (exige reconectar 1x)
- pushGoogleEvent best-effort (create/update/delete) com convidado=paciente, sendUpdates=all, reminders 1dia+1h
- google_event_id em agendamentos; marcador extendedProperties.private.scoreodonto + filtro na leitura (anti-duplicação)
- liga em criar/reagendar/cancelar/remarcar/restaurar; nunca bloqueia o agendamento
- aviso no AgendaSettingsModal (backup/notificação + reconectar)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 16:56:52 +02:00
VPS 4 Builder dc753a11b2 feat(agenda): feed de atividade da equipe (hoje) via audit_log
- backend GET /api/agenda/atividade (auditoria da clínica, default hoje, join paciente)
- frontend: botão History no cabeçalho + painel de feed

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 16:18:00 +02:00
VPS 4 Builder f084656712 feat(agenda): auditoria/autoria, faltas, a-reagendar, presença + RBAC por cargo
Agenda (multi-secretária):
- audit_log genérico + autoria (created/updated/canceled_by) + soft-delete + version (lock otimista)
- status novo vocabulário + índice único PARCIAL (libera slot ao cancelar/faltar)
- endpoints: falta, remarcar, restaurar, historico, pendencias (a reagendar), faltas, familia
- presença: heartbeat (DB última visita + Dragonfly ao vivo, janela 45s)
- frontend: StackModal, AgendaDetailModal, AgendaPresence; lista a-reagendar; pacienteId no fluxo de criação; chips de família + badge de faltas no modal

RBAC por cargo: funcoes.permissoes/nivel; gate de menu por cargo (array vazio herda role); hierarquia só-gerencia-abaixo no backend

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 16:10:58 +02:00
VPS 4 Builder d064aa9058 feat(contratos): sistema completo de contratos odontológicos
- Tabelas contratos e contrato_itens com migrações automáticas
- Endpoints CRUD com itens em transação
- ContratosView: listagem, filtro por status, cards, stats
- ContratoModal: wizard 3 abas (Dados/Itens/Cláusulas), catálogo de
  procedimentos, DnD para reordenar, financeiro completo, print A4
- Sidebar: novo item CONTRATOS
- App.tsx: nova rota /contratos com permissões dentista/funcionario
- PatientsView: botão CONTRATOS no menu financeiro

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 20:04:57 +02:00
VPS 4 Builder 15a8527f1c feat(pacientes): modais de receita, pedido de exame e edição em 4 páginas
- ReceitaModal: gerenciamento de modelos de receita por especialidade com
  drag-and-drop para reordenar medicamentos e preview de impressão
- PedidoExameModal: pedido de exames por catálogo (Raio-X / Tomografia /
  Outros) com DnD para ordenar, campos de região/observação por item e
  preview de impressão
- EditarPacienteModal: reformulado em 4 páginas (Dados / Família /
  Endereço / Histórico) com navegação anterior/próximo e modal 2xl
- Backend: tabelas modelos_receita, items_receita, pedidos_exame,
  items_pedido_exame criadas na migração; colunas de endereço adicionadas
  em pacientes; endpoints CRUD para receitas e pedidos de exame
- Integração: botões Receita e Raio-X no menu clínico agora abrem os
  novos modais reais em vez do placeholder

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 16:53:28 +02:00
VPS 4 Builder ee3f6c3bb2 feat(patients): fix date bug, convenio dropdown, redesign grupo familiar
- Fix dataNascimento date format error: convert dd/MM/yyyy → yyyy-MM-dd when
  loading EditarPacienteModal so <input type="date"> validates correctly
- Change convênio field from free text to dropdown populated from planos table
- Redesign grupo familiar: search a patient as family member instead of named
  group, with parentesco field (datalist with common options, accepts custom)
- GET /api/pacientes: proper camelCase aliases, LEFT JOINs for grupoFamiliarNome
  and indicadoPorNome, sort parameter support (az/za/convenio/recentes)
- Add startup migrations: ADD COLUMN IF NOT EXISTS for grupofamiliarid,
  grupofamiliarrelacao, indicadorporid on pacientes table
- savePaciente: preserve caller-supplied id instead of overwriting with Math.random
- Add grupoFamiliarRelacao to Paciente type

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 15:54:54 +02:00
VPS 4 Builder 6b67fbc26e fix(sync): truncate fields in import-legacy to match column VARCHAR limits
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 07:05:31 +02:00
VPS 4 Builder 6cf18c049f fix(sync): propagate real tab name in pushTableToSheet and pullTableFromSheet
Ensures values.update and values.get use the actual tab title returned by
ensureSheetTab (case-insensitive match) so writes don't fail when existing
Apps Script tabs have different casing than our expected names.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 06:46:30 +02:00
VPS 4 Builder 319c0dcedd fix(oauth): check googleCreds not process.env in URL guard
process.env is only set if env var exists; credentials saved via UI
live in googleCreds. Guard was blocking users who saved via DB.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 06:36:22 +02:00
VPS 4 Builder 263c98d74f feat(settings): Google OAuth credentials UI in Configurações
Backend:
- Load GOOGLE_CLIENT_ID/SECRET from DB at startup (env vars take priority)
- GET /api/settings/google-credentials → masked status (secret never returned)
- POST /api/settings/google-credentials → save to DB, hot-reload in memory
- /api/auth/google/url returns 503 with clear message when unconfigured

Frontend (ConfiguracoesView):
- OAuth credential inputs (Client ID + Client Secret with show/hide toggle)
- Shows configured status badge (ENV vs DB) and masked clientIdHint
- Instructions with redirect URI shown inline

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 05:56:00 +02:00
VPS 4 Builder fc891ab878 fix(oauth): set GOOGLE_REDIRECT_URI in docker-compose; guard missing credentials
- Add APP_URL and GOOGLE_REDIRECT_URI=https://scoreodonto.com/api/oauth2callback
  to docker-compose backend environment
- /api/auth/google/url returns 503 with clear message when CLIENT_ID/SECRET unset
- GoogleConnectButton shows alert instead of silently breaking on API error

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 05:52:33 +02:00
VPS 4 Builder 63962d51c1 feat(sync): Google Sheets bidirectional backup (PG ↔ Sheets)
Backend:
- Add SYNC_TABLES config (pacientes, agendamentos, financeiro, leads, guias)
- Add getSheetsClient(), ensureSheetTab(), pushTableToSheet(), pullTableFromSheet()
- Add schedulePush() debounced 5s auto-push after every write to main tables
- Add GET /api/sync/status, POST /api/sync/push, POST /api/sync/pull
- Update OAuth scope to include spreadsheets

Frontend:
- Redesign SyncView: per-table status grid, two-button operation (Backup/Restore),
  terminal log with color-coded lines, auto-backup info notice

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 05:44:52 +02:00
VPS 4 Builder 2f3c0420e3 feat(routing): switch from hash routing to HTML5 History API
Remove all window.location.hash assignments and hashchange events.
Navigate with history.pushState; listen on popstate. Fix base href to
'/' so assets resolve correctly on deep paths. Update magic link URL.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 04:44:53 +02:00
VPS 4 Builder 435176c0c3 fix(backend): add camelCase response mapping for all GET endpoints
PG stores columns lowercase but frontend expects camelCase. Each GET endpoint
now maps the response to include camelCase aliases alongside the lowercase fields.

- agendamentos: dentistaId, pacienteNome, pacienteCelular
- dentistas: corAgenda
- procedimentos: especialidadeId, especialidadeNome, valorParticular, codigoInterno;
  fix valoresPlanos filter (v.procedimentoid) and map planoId, planoNome, codigoPlano
- guias: full camelCase map (dataSolicitacao, beneficiarioNome, tipoTratamento, etc.)
- gto-builder: map items (builderId, procedimentoId, codigoTUSS, valorTotal, etc.)
  and builder fields (pacienteId, dentistaId, credenciadaId)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 04:26:03 +02:00
VPS 4 Builder 38bbf36735 fix(backend): lowercase all column names in buildInsert/buildUpdate and explicit queries
All PostgreSQL columns are stored lowercase (PG folds unquoted identifiers).
The previous code quoted camelCase keys ("corAgenda", "builderId", etc.) which
caused column-not-found errors.

- buildInsert: k.toLowerCase() for all column names, no more double-quotes
- buildUpdate: k.toLowerCase() for SET clause and WHERE column
- dentistas/register: "corAgenda" → coragenda
- procedimentos PUT: "procedimentoId" → procedimentoid in DELETE
- gto_builders INSERT: "pacienteId"/"dentistaId"/"credenciadaId" → lowercase
- gto_items queries: "builderId" → builderid, "valorTotal" → valortotal
- guias: "dataSolicitacao"/"beneficiarioNome"/etc → lowercase with normalizedSort

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 04:18:29 +02:00
VPS 4 Builder e61ef6c0ca fix(backend): move procedimentos/reorder before /:id to prevent route shadowing
Express matches routes in registration order. PUT /procedimentos/:id was
registered before /procedimentos/reorder, causing 'reorder' to be captured
as an id param and the reorder endpoint to be unreachable.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 23:20:39 +02:00
VPS 4 Builder a0ab095923 refactor(backend): migrate all queries to native PostgreSQL, remove MySQL shim
- Remove translateQuery function, pool.query override, and pool.getConnection mock entirely
- Replace all ? placeholders with $N positional parameters throughout
- Replace INSERT INTO t SET ? with buildInsert() helper across pacientes, dentistas, especialidades, planos, procedimentos, financeiro, leads, gto_items
- Replace UPDATE t SET ? WHERE id = ? with buildUpdate() helper across the same tables
- Replace all pool.getConnection()/beginTransaction/commit/rollback blocks with withTransaction()
- Convert ON DUPLICATE KEY UPDATE to ON CONFLICT DO UPDATE SET in dentistas/register (usuarios, vinculos, dentistas tables)
- Fix dentistas/register to use withTransaction instead of SET FOREIGN_KEY_CHECKS
- Fix all [rows] array destructuring to { rows } object destructuring (PG native result shape)
- Fix guias dynamic WHERE builder to use incrementing $N parameter indices
- Fix double-quoted string literal bug in procedimentos categoria query ("Particular" → 'Particular')
- Quote camelCase column names in gto_items/gto_builders queries ("builderId", "valorTotal", etc.)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 23:13:35 +02:00
VPS 4 Builder 1330147eaf fix: corrige inconsistências críticas de backend e navegação
- Backend: substitui string literals com aspas duplas por aspas simples
  nas queries PostgreSQL (settings, GTO builder, google_tokens delete)
- Backend: corrige alias SQL 'dentistanome' para 'dentistaNome' (quoted)
  e ajusta frontend para usar 'pacientenome' (lowercase do PG)
- Backend: move app.listen() para após todas as rotas registradas
- Backend: ativa generateIntelligentNotifications no startup + intervalo 5min
- Backend: magic link usa process.env.APP_URL em vez de localhost:3000 hardcoded
- Frontend: adiciona 'relatorios' às permissões do role 'funcionario'
- Frontend: adiciona onClick ao botão Relatórios do Dashboard
- Frontend: adiciona Content-Type e JWT token em salvarAgendamento/atualizarAgendamento
- Frontend: MeusTratamentos passa JWT token nas chamadas a /api/guias
- Frontend: ClinicasView passa JWT token no endpoint de atualização de cor
- Frontend: corrige subtítulo 'MYSQL + GOOGLE' para 'POSTGRESQL + GOOGLE'

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 21:43:23 +02:00
VPS 4 Builder 0f71db2205 fix(backend): correct lowercase column names in dashboard stats query (datavencimento, dentistaid); fix notificacoes routes to use PG syntax; exclude base/ from .gitignore 2026-05-13 15:54:01 +02:00
VPS 4 Builder e260eed28b fix(backend): Convert legacy queries and add translate wrapper 2026-05-13 09:53:00 +02:00
Antigravity AI Agent 606da6de97 feat: migrate ScoreOdonto CRM to Docker, PostgreSQL, and DragonflyDB 2026-05-13 07:13:41 +02:00
Antigravity AI Agent 4917d03bdf chore: clean up codebase content, keeping only the environment and infrastructure configurations 2026-05-13 05:21:31 +02:00
Antigravity AI Agent 19dbbae8b8 chore: initial setup with PostgreSQL, DragonflyDB, and Nginx routing configs 2026-05-13 05:12:32 +02:00