- 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>
- VERDADE-HOJE.md e DEPLOY-PRODUCAO.md: produção v1.0.16 (commit 471c2c2);
tag promove por re-tag SEM rebuild (digest :v1.0.16 == :471c2c2, provado);
versão nasce da tag; constants.ts/update-version.js removidos. Passo 5 ✅.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- build.yml dividido em 2 jobs por ref:
• build (só push na main): builda 1x e publica por COMMIT (:<sha> + :latest), sem APP_VERSION.
• promote (só tag vX.Y.Z): re-tagueia :<sha> -> :vX.Y.Z via 'docker buildx imagetools create'
(SEM rebuild), valida integridade (imagem do commit existe; digest :versao == :commit;
front+back do mesmo commit) e deploya na VPS1. Falha se o commit não foi pushado.
- Versão semântica nasce da TAG e é injetada no deploy em runtime (compose.prod).
- Removidos frontend/constants.ts e update-version.js (fim do APP_VERSION manual).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Pasta única scoreodonto.com/doc/ com 9 docs que prestam:
VERDADE-HOJE (estado, principal), DEPLOY-PRODUCAO (runbook), BANCO-DEV-ESTRATEGIA,
REGISTRY, AUDITORIA-FUNCIONAL, BACKLOG-FINANCEIRO-V1, CRM_Ortodontia, RX_ARQUITETURA, RX_BACKLOG.
- Removidos os docs de infra sobrepostos/desatualizados (estado consolidado em VERDADE-HOJE;
histórico fica no git): arquitetura.md, deploy.md, CHECKLIST-DEPLOY-PRODUCAO.md,
PENDENCIAS.md, PENDENCIAS_E_DEPLOY.md.
- Pasta documentação/ eliminada.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- VERDADE-HOJE.md: reescrito p/ a verdade de 17/jun — banco DEV isolado (pgdev, não
compartilha mais), produção roda imagem v1.0.15, versão em runtime via /api/version.
Declarado documento principal (prevalece em divergência).
- deploy.md: §5 rollback ✅ (existe); §6 corrigida — remove o "não há CI/registry/deploy"
(era falso/contraditório); CI/CD por tag ATIVO, falta só o Passo 5.
- DEPLOY-PRODUCAO.md: status 🧪→✅ dos Passos 1/3/4 (promovidos em v1.0.15).
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>
- buildInfo.ts: hook useAppVersion() consome GET /api/version (fonte única = backend),
com fallback ao carimbo do bundle; deixa de depender do APP_VERSION manual.
- Versão exibida em Configurações ("Sobre o sistema") + telas públicas (Login/WaitingInvite);
removida do rodapé do Sidebar.
- compose.prod/deploy-prod.sh: injetam APP_VERSION (=tag) e APP_ENV=PROD em runtime,
desacoplando a versão semântica do build (commit/build seguem da imagem).
- constants.ts marcado legado + bump V1.0.15 (transitório até o Passo 5; evita colisão de tag).
- DEPLOY-PRODUCAO.md reescrito com status ✅/🧪/🎯 + nota de fase transitória.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- remove z-[1002] do wrapper sempre-presente do sino (furava modais z-50..z-120)
- z aplicado só ao dropdown aberto (z-50) + backdrop (z-40)
- doc: RX apontado ao banco dev isolado
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>
- VERDADE-HOJE.md: deploy/rollback/containers/versão refletem CI/CD por tag + registry
- DEPLOY-PRODUCAO.md: fluxo canônico = deploy por tag; manual vira fallback
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- build: fixa COMPOSE_PROJECT_NAME=scoreodontocom (imagem buildada batia com nome errado no tag/push → carimbo da Etapa 3 vazava)
- novo job deploy: só em tags v*, SSH VPS4->VPS1 roda deploy-prod.sh (push na main não deploya)
- deploy.md: Metade B + roadmap Etapa 6 = FEITO
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- docker-compose.prod.yml: produção roda imagens versionadas do registry (sem build)
- deploy-prod.sh <tag>: pull da tag + up -d --no-build + verificação /api/version + rollback
- deploy.md: Metade A (CI) marcada como FEITA
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
.gitea/workflows/build.yml — em push na main + tags v*, builda backend+frontend
com carimbo de versão e publica no registry (sem deploy). Login tolerante
(secret REGISTRY_TOKEN se existir; senão credencial do host). Retry p/ 499.
Runner self-hosted 'vps4-builder' (modo host) registrado na VPS4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- REGISTRY.md: login, convenção de nomes, build+push, pull/rollback, gotcha do 499
- arquitetura.md/deploy.md: registry agora ativo (git.clube67.com), não mais 'não existe'
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>
- reúne todos os .md de ScoreOdonto numa pasta única (fonte única, dentro do repo versionado pelo Gitea)
- arquitetura.md: reescrito p/ o estado REAL (3 VPS, banco compartilhado dev/prod, sem staging/listener/registry fantasmas)
- deploy.md: reescrito p/ o estado-ALVO (Gitea CI/CD: push->build->registry->deploy por tag)
- DEPLOY-PRODUCAO.md: runbook operacional executável (fluxo manual real de hoje)
- VERDADE-HOJE.md: auditoria (codigo/banco/containers/deploy/versao/rollback)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Remove o stack de "staging" que nunca foi isolado (apontava para o banco de
produção) e não tinha rota no Traefik:
- docker-compose-staging.yml, nginx/default-staging.conf
- deploy-prod-builder.sh, deploy-to-prod.sh (pipeline deprecado — ver DEPLOY-PRODUCAO.md)
- CHECKLIST-DEPLOY-PRODUCAO.md realinhado ao fluxo real: dev.scoreodonto.com (VPS4)
-> build -> VPS1; dev e prod compartilham o mesmo banco (sem ambiente isolado).
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>
- perfil profissional: chips de áreas de atuação (getMyAreas/setMyAreas)
- configurações da clínica: chips de áreas da unidade (getClinicaAreas/setClinicaAreas)
- fix: handleSavePerfil agora envia logradouro/numero (rua/número não salvavam)
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>
- novo painel showcase (marketplace de profissionais por proximidade, locação de
salas, agenda anti-overbooking, financeiro/GTO, RX, busca por proximidade)
- chips de perfis incl. biomédico(a); visual escuro moderno; splash mais rápido
- mantém login, recuperar/redefinir senha e cadastro via OnboardingChat
- App.tsx: handler onAuthSuccess extraído (reuso pós-login)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Profissionais e Salas: aba de busca bloqueia se a origem não tiver cep+cidade+estado
- clínica/consultório (donoclinica/donoconsultorio/admin/funcionário): checa endereço
da clínica ativa → CTA p/ Configurações
- dentista/biomédico/protético: checa o próprio perfil → CTA p/ completar perfil
- fail-safe: em erro de checagem não bloqueia
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- watchdog inline no index.html: erro de asset /assets/ (404 de bundle antiga em
cache), import dinâmico falho, ou #root vazio após 8s → reload automático
- index.tsx: listener vite:preloadError → reload
- anti-loop por timestamp (só recarrega se última tentativa >30s; re-arma sozinho)
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>
ViaCEP (auto-preenche endereço ao completar 8 dígitos):
- novo util services/viacep.ts (buscarCep), reutilizado
- ligado em Pacientes, Salas, Profissionais(perfil); Configurações migrada p/ o util
- filtro 'CEP (região)' do marketplace mantido como busca (sem auto-fill)
Menus por papel:
- biomédico: sem Ortodontia, RX e 'Ser Tutor Orto' (não são escopo)
- protético: passa a ver Dashboard/Agenda/Tratamentos/Lançar GTO (antes não via nada)
- RX/Radiografias: só papéis odonto (dentista + donos/funcionário)
- bottom nav mobile ajustado (biomédico/protético)
Fix 'Visualizar como':
- getActivePlugins é preview-aware (todos os plugins ativos enquanto houver PREVIEW_ROLE),
imune ao timing de hydrate/cache; enterPreview/exitPreview simplificados
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A árvore local já contém todo o trabalho do origin/main (23 commits): multi-tenancy
(tenantGuard em /api/agendamentos + escopo clinica_id), score, imports do Google.
Verificado: 0 rotas/métodos exclusivos do remoto perdidos; nenhum guard enfraquecido
(rotas globais usam superadminGuard, mais restritivo). Esta árvore = superset do remoto.
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>
- GET /api/agendamentos: tenantGuard + WHERE clinica_id (antes: SELECT * sem filtro/sem auth -> vazava todas as clinicas)
- getAgendamentos passa clinicaId da workspace ativa + guard de array
- salvarAgendamento injeta clinica_id (senao novos ficariam nulos e sumiriam apos o escopo)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- StackModal: overlay pointer-events-none + painel pointer-events-auto (agenda clicavel por baixo)
- ESC fecha; pointerdown fora do painel fecha; clicar em outro slot/evento fecha o atual e abre o novo
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- import entra como status 'importado' (provisorio): separa titulo NOME x PROCEDIMENTO, traz description do Google em observacoes, nao pontua
- 'importado' no CHECK de status
- falta bloqueada sem paciente vinculado / importado
- POST /agendamentos/:id/confirmar: vincula paciente, EXIGE cpf+telefone (enriquece cadastro), vira agendado
- pendencia 'a reagendar' so com paciente vinculado
- frontend: modal do importado mostra 'A CONFIRMAR' + Confirmar paciente (busca com desambiguacao homonimos: cpf/tel/nascimento + criar novo) + Remover; ScoreBadge
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- backend GET /api/pacientes/:id/score: faltas (status falta) + remarcacoes (audit_log 'remarcou', historico) + nivel (RISCO>=3 faltas, ATENCAO>=1 falta ou >=4 remarc)
- ScoreBadge (ATENCAO/RISCO + contadores), exibido no modal do evento e no modal de criar (ao escolher paciente)
- nao aparece quando o paciente esta limpo
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- novo componente ToothIcon (SVG, lucide-like)
- LandingPage: logo nav/mobile usa ToothIcon (sobre o gradiente premium)
- favicon.svg (dente branco em gradiente azul) + index.html
- Sidebar: menu DENTISTAS e 'ver como dentista' usam ToothIcon
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- import: detecta aba com 'paciente' no nome, escolhe a que casa mais colunas, mapeia por sinonimo (nome/sobrenome, telefone/tefefoneprincipal, convenio/credenciada/plano, datanasci...), gera id do CPF se faltar; importa so campos do sistema
- export: GET /api/pacientes/export -> CSV (sem ultimo tratamento, sem leads), BOM p/ Excel, download no front
- card Configuracoes: botao Baixar CSV (sempre) + importar de planilha (Google)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 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>