- Público, sem auth. Checa Postgres (crítico → HTTP 503 se down) e Dragonfly/Redis
(opcional → "degraded" mas 200; "disabled" se cache off). Inclui version/commit/
environment (de BUILD_INFO) e uptime_s. Sem vazar mensagens de erro.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- backend: tabelas protese_os/_evento/_foto/_produtos + endpoints /api/protese/*
(laboratorios, os, bancada, status, foto/raw assinado, produtos); catálogo do protético;
custo de lab → DESPESA na entrega (idempotente, estorno no delete) + garantia com foto.
- Acesso: helper proteticoAcessivelPelaClinica (interno por vínculo OU diretório) valida o POST
e o catálogo; catálogos passam por tenantGuard; correção do label da notificação (tipo resolvido).
- Frontend: ProteseView (Bancada do protético / Minhas OS da clínica) + rota /proteses
+ item de menu PRÓTESES no Sidebar (dentista/protético/funcionário).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- DATABASE_URL parametrizado (${SCOREO_DB_*}); default mantém produção (VPS1) intacta
- server.js: não força SSL p/ host @pgdev (container dev local); SSL segue p/ VPS3
- .gitignore: ignora .env (override local de dev)
- doc: status de implementação do banco DEV isolado
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- backend: endpoint GET /api/version + linha [VERSION] no boot (le APP_VERSION/GIT_COMMIT/BUILD_TIME/APP_ENV)
- frontend: buildInfo.ts le import.meta.env.VITE_* ; versão no rodapé do Sidebar
- Dockerfiles (front+back): ARG/ENV do carimbo de versão
- docker-compose.yml: build args (APP_VERSION/GIT_COMMIT/BUILD_TIME/APP_ENV) com defaults
- bump V1.0.12 -> V1.0.13
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Financeiro V1 (Épicos 1–4):
- FKs de origem no lançamento (paciente/profissional/procedimento/agendamento/contrato/realizado), soft delete e cron "Atrasado"
- prontuário de procedimentos realizados (fotos antes/depois) + regra sem-comissão (garantia/reabertura do mesmo profissional)
- normalizeFinanceiro: corrige CHECK capitalizado vs enforceUppercase (lançamentos não salvavam pela UI)
- baixa de pagamento (pago_em), despesas (fornecedor/centro de custo/recorrente), competência por data de conclusão
- relatório financeiro (período, paciente, profissional, forma, convênio, glosa)
- orçamento Assinado -> contas a receber; contrato vigente -> cobrança recorrente; renovação automática de contrato
Financeiro V2 (Comissão/Repasse):
- regras de % (padrão/procedimento/override por profissional) + custo de laboratório
- base selecionável (recebido/produção), fechamento persistido, pagar (gera despesa) + comprovante + estorno
Glosas de convênio: por item de GTO, recurso/protocolo/prazo, recuperar/estornar, impacto no relatório
GTO -> Financeiro: finalizar gera RECEITA (convênio a receber); LancarGTO passa a persistir; convênios reais (planos)
Contratos: modelo "Atendimento a Convênios / Repasse (Dentista Credenciado)" + variáveis de convênio
Salas (redesenho): perfil "Dono de Sala"; locação sempre ativa; menus MINHAS/ALUGAR SALAS;
sala como workspace isolado (seletor agrupado Clínicas x Salas, tenantGuard por dono); financeiro de
locação (reserva confirmada -> recebível); Painel da Sala (KPIs, agenda visual, recebíveis, relatório por sala)
Docs: BACKLOG-FINANCEIRO-V1, AUDITORIA-FUNCIONAL-SCOREODONTO, CHECKLIST-DEPLOY-PRODUCAO
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- salas.area + filtro por área no marketplace + badge no card + seletor no cadastro
- preço por modalidade: hora/turno/diária/semanal/mensal podem ser FIXO (valor) ou
SOB CONSULTA (flags *_consulta) — precos() mostra 'Sob consulta'
- backfill de área das salas pelo papel do dono
- POST/PUT salas aceitam area + flags; marketplace retorna/filtra por área
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- catálogo (Especialidades/Procedimentos): seletor de área no form + badge colorido na lista
- marketplace de profissionais: filtro por área (via usuario_areas)
- backend: GET/PUT /api/me/areas e /api/clinicas/:id/areas (multi-área de perfil/clínica)
- HybridBackend: getAreas/getMyAreas/setMyAreas
- (Fase 2c pendente: UI multi-área no perfil/configurações da clínica)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- tabela referência 'areas' (slug, nome, cor, ícone) seedada com 3 áreas
- coluna 'area' em especialidades e procedimentos + backfill idempotente
- junções multi-área: clinica_areas e usuario_areas (backfill por papel/catálogo)
- POST especialidades/procedimentos default de área pelo papel (roleToArea) + marca clinica_areas
- seedBiomedicina grava area='biomedicina'; GET /api/areas
- Fase 2 (próxima): seletor/badge de área no catálogo, filtro por área no marketplace, UI multi-área de perfil/clínica
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- reverte bloqueio anterior: biomédico GERENCIA especialidades/procedimentos do seu
consultório (workspace pessoal já criado no cadastro)
- acesso liberado p/ o papel biomédico (menu + permissão)
- coluna 'ativo' em especialidades/procedimentos + toggle ativar/desativar na UI
- auto-seed do catálogo de biomedicina estética (botox, preenchimento, bioestimulador,
peeling, microagulhamento, etc.) no cadastro do biomédico + endpoint idempotente
/api/me/seed-biomedicina (restrito ao papel biomédico) p/ contas existentes
- valor por procedimento já suportado (valorparticular)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- login: paleta verde/teal (headline mantida)
- home (LandingPage): cards de Marketplace de Profissionais, Locação de Salas,
Busca por Proximidade e RX/Radiografias
- perfil profissional: campos Rua/Logradouro e Número (+ ViaCEP preenche a rua);
backend usuarios.logradouro/numero + GET/PUT perfil
- biomédico: remove tratamento 'dentista' (Dashboard 'Profissional'; tratamentos sem 'odontológico')
- backend: blockBiomedico nas rotas de procedimentos/especialidades (POST/PUT/DELETE)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- coluna geo em clinicas + índice GiST; geocoda ao salvar endereço da clínica
- helper resolveOrigem: CEP digitado → clínica ativa → geo do próprio usuário
- marketplaces (salas/profissionais) ordenam por distância sempre que há origem;
raio passa a ser filtro opcional (não mais obrigatório p/ calcular distância)
- frontend envia clinicaId ativo automaticamente (CEP digitado sobrepõe)
- clínica buscando profissional: mais próximos + especialidade; dentista→sala por distância
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- geocoder de CEP com cache (cep_geo) + rotação: AwesomeAPI → Nominatim(CEP, c/ User-Agent) → ViaCEP+Nominatim(endereço)
- colunas geo geography(Point,4326) + índice GiST em salas e usuarios
- geocoda ao salvar (POST/PUT salas, PUT perfil) via setGeoByCep
- marketplaces aceitam ?cep=&raio= → ST_DWithin + dist_km, ordenado por distância
- frontend: filtro Meu CEP + Raio + badge ~X KM nos cards
- fix: clinicas.nome inexistente → nome_fantasia (salas/minhas + marketplace)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- App.tsx: wrappers de padding (p-4/md:p-8) e max-w-7xl/mx-auto agora só se aplicam quando não é tela standalone; login/landing/public renderizam full-bleed
- OnboardingChat.tsx: classe ob-noscroll esconde a barra de rolagem do slide intro (mantém scroll), substituindo a custom-scrollbar indefinida no fluxo de login
Inclui também demais alterações pendentes do working tree (snapshot do estado atual de dev).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 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>
- 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>
- 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>
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>
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>
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>
- 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>
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>
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>
- 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>
- 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>