5b99292b2d
- documentação/MAPA-FUNCIONAL-COMPLETO.md: inventário de rotas/telas/botões/fluxos, matriz de módulos, mapa de conexões (mermaid) e notas — baseado em evidências do código. - documentação/AUDITORIA-ESTRATEGICA-MODELAGEM.md: análise Pessoa→Vínculo→Workspace, entidades mal classificadas e riscos arquiteturais. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
158 lines
15 KiB
Markdown
158 lines
15 KiB
Markdown
# AUDITORIA ESTRATÉGICA DE MODELAGEM — ScoreOdonto
|
||
|
||
> **Análise crítica da modelagem e da visão de negócio.** Não altera código, banco, documentação ou migrations.
|
||
> Baseada exclusivamente em evidências reais: `backend/server.js`, schema real (tabelas), fluxos existentes e
|
||
> `MAPA-FUNCIONAL-COMPLETO.md`. Estado verificado: produção `v1.0.18` · DEV `dev`. Data: 19/jun/2026.
|
||
|
||
---
|
||
|
||
## Evidências-âncora (o que o código realmente diz)
|
||
|
||
| Camada | Evidência no código | Tabela/linha |
|
||
|---|---|---|
|
||
| **Identidade (Pessoa)** | `usuarios` é o ponto único de login; perfil multi-área (`usuario_areas`), capacidades por pessoa (`usuario_plugins`), `is_tutor` | `usuarios`, `me/areas`, `me/plugins` |
|
||
| **Vínculo (join)** | `vinculos(usuario_id, clinica_id, role, setor_id, funcao_id)` + `CHECK role IN (paciente, dentista, biomedico, protetico, funcionario, donoclinica, donoconsultorio, donosala, admin)` | `server.js:4851` |
|
||
| **Workspace** | `clinicas` ganhou `tipo ∈ {pessoal, consultorio, clinica}` + `owner_id`; comentário literal **"Clinicas → workspaces (Fase 1)"** | `server.js:4822-4824` |
|
||
| **Workspace pessoal automático** | No registro, cria `clinicas(tipo='pessoal', owner_id=usuario)` — **toda pessoa nasce com um workspace** | `server.js:537,550` |
|
||
| **Agregação** | `me/workspaces` → `listarWorkspaces(userId)` reúne clínicas (via vínculo) + salas | `server.js:5680` |
|
||
| **Marketplace = pessoa** | `propostas_profissional.profissional_id` → `JOIN usuarios u` | `server.js:6307` |
|
||
| **Legado clínica-cêntrico** | `pacientes` tem `clinica_id` e **não tem `usuario_id`**; `dentistas` é tabela à parte com `usuario_id` opcional; tudo passa por `tenantGuard`+`clinica_id` | `pacientes`, `dentistas:1542` |
|
||
|
||
**Leitura imediata:** a *espinha de identidade e acesso* **já é** Pessoa → Vínculo → Workspace (e isso está em migração ativa, declarada como "Fase 1"). Os *dados clínicos/operacionais* **ainda são** Clínica → Pessoa. O sistema é **híbrido, com a direção já apontada pelo próprio código**.
|
||
|
||
---
|
||
|
||
## ANÁLISE 1 — Pessoa × Workspace
|
||
|
||
1. **Centrado em clínica ou pessoa?** Híbrido. **Autenticação/autorização/workspaces:** centrado em **pessoa**. **Operação clínica e financeira:** centrado em **clínica** (`tenantGuard` + `clinica_id`).
|
||
2. **A pessoa é entidade principal?** **Sim, há evidência forte:** `usuarios` é a âncora; áreas, plugins e tutor são da pessoa; o profissional do marketplace é a pessoa; e cada pessoa recebe um **workspace pessoal** ao se cadastrar.
|
||
3. **A clínica é apenas um workspace?** **Sim, há evidência explícita:** `clinicas.tipo` pode ser `pessoal | consultorio | clinica`, com `owner_id`. A clínica é hoje **um tipo de workspace** dentro da própria tabela `clinicas` (que virou, de fato, a tabela de workspaces).
|
||
4. **Módulos que favorecem Pessoa→Vínculo→Workspace:** login/identidade, `vinculos`+RBAC (`funcoes`/`setores`), `me/workspaces`, `usuario_plugins`, `usuario_areas`, Salas (workspace `tipo='sala'`), Marketplace de Profissionais, Tutoria.
|
||
5. **Módulos que favorecem Clínica→Pessoa:** Pacientes, Dentistas (tabela-recurso), Agenda, Financeiro/Comissão/Repasse, Orçamentos/Contratos, Glosas — **toda a operação** ainda é escopada por `clinica_id`.
|
||
6. **Mais sustentável em 5 anos:** **Pessoa → Vínculo → Workspace.** Justificativa técnica: a tabela `vinculos` é N:N (uma pessoa, vários workspaces, papéis distintos por workspace) — é o único modelo que comporta dentista em várias clínicas, locação de salas, tutoria e marketplace **sem duplicar a pessoa**. O modelo clínica-cêntrico exige duplicar o humano por clínica (é o que `dentistas` já faz, e é exatamente o gargalo).
|
||
|
||
---
|
||
|
||
## ANÁLISE 2 — Consultório
|
||
|
||
**Hoje é simultaneamente (A) Papel e (C) Workspace:** existe a *role* `donoconsultorio` em `vinculos` **e** o `tipo='consultorio'` em `clinicas` (`server.js:590` decide o `tipoWs` a partir da role do dono).
|
||
|
||
**Classificação ideal:** **(C) Workspace** — um `tipo` de workspace, sendo `donoconsultorio` apenas o *papel do dono* dentro dele. O sistema já está ~80% nesse modelo.
|
||
|
||
**Impactos:** baixo do ponto de vista de dados (já existe `tipo='consultorio'`). O resíduo é **semântico**: a role codifica o tipo do workspace (acoplamento role↔tipo). Enquanto persistir, decisões de UI/permissão ramificam em dois lugares ("é consultório?" pode ser perguntado pela role *ou* pelo tipo), gerando divergência.
|
||
|
||
---
|
||
|
||
## ANÁLISE 3 — Protéticos
|
||
|
||
**Hoje o protético é:** **Usuário/Profissional.** É `usuarios` com role `protetico` em `vinculos`, recebe workspace pessoal, e produz trabalho via `protese_os`/`protese_produtos`.
|
||
|
||
**Existe conflito conceitual? Sim.** O protético-pessoa está modelado como **profissional do ecossistema**, mas o **laboratório** (onde o trabalho/custo realmente reside, `protese_laboratorios` + custo lab que abate comissão) é um **cadastro interno separado**. Ou seja, a faceta "fornecedor" está **descolada** da pessoa: a pessoa é profissional, o fornecedor é um cadastro à parte.
|
||
|
||
**Modelo que faz mais sentido: (B) Protético = profissional do ecossistema** — e o **laboratório** é que ocupa o papel de *fornecedor*. Justificativa: o protético, como humano, se encaixa perfeitamente em Pessoa→Vínculo→Workspace (igual a dentista/biomédico); empurrá-lo para "fornecedor" o trataria como entidade não-humana e quebraria o login/marketplace/áreas que já funcionam para ele. A natureza "fornecimento" pertence ao **laboratório**, não ao indivíduo (ver Análise 4). (C) só seria verdade se um protético autônomo *fosse* o próprio laboratório — caso que o modelo atual não distingue.
|
||
|
||
---
|
||
|
||
## ANÁLISE 4 — Laboratórios
|
||
|
||
**Hoje aparecem como:** **(A) Cadastro interno** — `protese_laboratorios` escopado por clínica, alimentando OS e custo lab. Não há identidade própria nem login; não cruzam clínicas.
|
||
|
||
| Classificação | Vantagens | Desvantagens |
|
||
|---|---|---|
|
||
| **A) Cadastro auxiliar** (estado atual) | Simples; isolado por clínica; zero atrito | Cada clínica recadastra o mesmo laboratório; sem visão consolidada; sem relação direta com a pessoa protético |
|
||
| **B) Participante do ecossistema** (entidade própria) | Laboratório único reaproveitável; liga custo lab à entidade real; base para reputação/histórico | Exige resolver identidade/duplicidade e governança de dados entre clínicas |
|
||
| **C) Workspace independente** | Coerente com a linha Pessoa/Workspace; laboratório operaria como ator (recebe OS de várias clínicas) | Maior complexidade de tenancy; só se justifica se o laboratório for *operar dentro* da plataforma |
|
||
|
||
**Análise (sem assumir locação):** hoje é **A**, e isso é consistente com o legado clínica-cêntrico. A tensão é que o laboratório é a **única entidade "fornecedor" real** do sistema e está modelada como simples lookup — o que limita qualquer evolução para histórico/qualidade/integração entre clínicas. **B** é o ponto de equilíbrio entre o estado atual e a direção arquitetural; **C** só se sustenta se o laboratório virar *operador* na plataforma.
|
||
|
||
---
|
||
|
||
## ANÁLISE 5 — Pacientes
|
||
|
||
**Hoje o paciente pertence à CLÍNICA.** Evidências: `pacientes.clinica_id`, **ausência de `usuario_id`**, e até **dois variantes de INSERT** (um com `clinica_id`, outro sem — resíduo legado). Não há identidade de paciente no ecossistema; o mesmo CPF em duas clínicas vira **dois registros**.
|
||
|
||
- **Compartilhamento entre clínicas:** inexistente (duplicação por clínica).
|
||
- **Histórico:** preso à clínica; não há prontuário único da pessoa.
|
||
- **Multiempresa:** o isolamento é forte (bom para tenancy), mas impede portabilidade.
|
||
- **Privacidade/LGPD:** o modelo atual é, na verdade, **mais seguro por isolamento** (cada clínica é controladora dos seus dados). Um paciente "do ecossistema" exigiria base legal/consentimento para compartilhar histórico entre controladores distintos — não trivial.
|
||
|
||
**Abordagem mais coerente com a arquitetura ATUAL:** **o paciente pertence à clínica.** É o que o código faz e o que o LGPD-por-isolamento favorece. **Porém** isso é a **maior contradição** com a direção Pessoa→Workspace: o paciente é a única "pessoa" do sistema que **não** é tratada como pessoa. É coerente com o presente e **incoerente com o futuro declarado**.
|
||
|
||
---
|
||
|
||
## ANÁLISE 6 — Marketplace
|
||
|
||
| Módulo | Encaixa em | Evidência |
|
||
|---|---|---|
|
||
| Salas | **Modelo B** | workspace `tipo='sala'`, reservas cross-clínica |
|
||
| Profissionais | **Modelo B** | `profissional_id` → `usuarios`; cruza clínicas |
|
||
| Tutoria | **Modelo B** | candidatura/pagamento ligados à pessoa (`is_tutor`, MercadoPago) |
|
||
| Próteses | **Modelo A** (hoje) | `protese_os` por `clinica_id` |
|
||
| Laboratórios | **Modelo A** (hoje) | cadastro interno por clínica |
|
||
|
||
**Conclusão:** o marketplace **só faz sentido no Modelo B (Pessoa→Vínculo→Workspace→Marketplace)**. Salas, Profissionais e Tutoria já estão lá porque dependem da **pessoa cruzando fronteiras de clínica** — algo que o Modelo A (Clínica→Tudo) torna impossível sem duplicação. Próteses/Laboratórios são os **retardatários** ainda presos ao Modelo A; são a fronteira onde os dois modelos colidem.
|
||
|
||
---
|
||
|
||
## ANÁLISE 7 — Escalabilidade (horizonte 5 anos)
|
||
|
||
| Cenário | Suporta hoje? | Gargalo |
|
||
|---|---|---|
|
||
| Dentista em múltiplas clínicas | **Parcial** | `vinculos` suporta a identidade, mas `dentistas` **duplica a pessoa por clínica** (agenda/horários presos a `dentistas.id`); não há visão unificada do profissional |
|
||
| Biomédico em vários locais | Parcial | mesma duplicação via tabela-recurso |
|
||
| Profissionais temporários (Delivery) | **Não** | marketplace só tem proposta-mensagem; sem contrato/pagamento/vínculo temporário |
|
||
| Locação de salas | **Sim (estrutura)** | falta captura de pagamento (fluxo financeiro aberto) |
|
||
| Tutoria | **Sim** | escala de oferta de tutores |
|
||
| Marketplace | Parcial | só Tutoria fatura |
|
||
| Protéticos independentes | Parcial | pessoa ok, mas laboratório-fornecedor é cadastro preso à clínica |
|
||
| Redes de clínicas | **Não** | **não existe entidade "rede/grupo" acima da clínica**; workspaces são planos, sem hierarquia |
|
||
|
||
**O modelo escala?** A **camada de identidade sim**; a **camada operacional não**. Gargalos críticos: (1) **duplicação da pessoa** em `dentistas`/recursos; (2) **paciente não-portável**; (3) **ausência de hierarquia** (rede→clínica); (4) **tenancy de `clinica_id` único** impede consolidação cross-clínica (uma pessoa ver tudo o que é seu em todas as clínicas).
|
||
|
||
---
|
||
|
||
## ANÁLISE 8 — Contradições (por gravidade)
|
||
|
||
| Gravidade | Contradição | Evidência |
|
||
|---|---|---|
|
||
| **ALTA** | `dentistas` é entidade paralela a `usuarios` (mesmo humano duplicado por clínica, com `usuario_id` *opcional*) → identidade fragmentada | `dentistas:1542`, `:328` |
|
||
| **ALTA** | `pacientes` é entidade clínica-presa sem identidade de pessoa, com **dois INSERTs** (com/sem `clinica_id`) → ambiguidade legada + bloqueio de portabilidade | INSERTs de `pacientes` |
|
||
| **MÉDIA** | O "workspace" está **dividido em duas tabelas**: `clinicas` (pessoal/consultorio/clinica) **e** `salas` — conceito único, dois lugares | `clinicas:4823`, `salas` |
|
||
| **MÉDIA** | Acoplamento **role ↔ tipo de workspace** (`donoconsultorio`⇄`tipo='consultorio'`) | `server.js:590` |
|
||
| **MÉDIA** | Estado de capacidades em **dois lugares**: `usuario_plugins` (servidor) vs `localStorage` (cliente) → divergência entre dispositivos | `pluginRegistry.ts`, `me/plugins` |
|
||
| **BAIXA** | Protético-pessoa (profissional) × laboratório (fornecedor) descolados | `protese_laboratorios` |
|
||
| **BAIXA** | `superadmin` fora de `vinculos` (é `usuarios.role`) → plano de auth separado (aceitável, mas assimétrico) | `me/workspaces:5682` |
|
||
|
||
---
|
||
|
||
## RESULTADO FINAL
|
||
|
||
**1. Resumo executivo.** O ScoreOdonto é um ERP odontológico multiempresa em **transição arquitetural declarada no próprio código** ("Fase 1: Clinicas → workspaces"). A **identidade, o acesso e os workspaces já operam no modelo Pessoa→Vínculo→Workspace**; a **operação clínica/financeira permanece clínica-cêntrica**. As três frentes de marketplace já vivem no modelo novo; pacientes, dentistas-recurso e laboratórios são o legado que ainda não migrou. As contradições graves são todas de **identidade duplicada** (a mesma pessoa existindo como `usuarios` + `dentistas`, e o paciente sem identidade de pessoa).
|
||
|
||
**2. Modelo que melhor representa o sistema HOJE:** **híbrido** — `Pessoa → Vínculo → Workspace` na espinha; `Clínica → Pacientes/Dentistas/Financeiro` na operação.
|
||
|
||
**3. Modelo que melhor representa o sistema NO FUTURO:** `Pessoa → Vínculo → Workspace → Serviços → Marketplace → Financeiro` — e o código já está pavimentado para ele.
|
||
|
||
**4. Entidades CORRETAMENTE classificadas:** `usuarios` (Pessoa), `vinculos` (Vínculo+RBAC), Clínica/Consultório/Sala como **workspaces**, Dentista/Biomédico/Protético/Tutor como **papéis da pessoa**, Profissional do marketplace e capacidades (`areas`/`plugins`) como atributos da pessoa.
|
||
|
||
**5. Entidades MAL classificadas:**
|
||
- **`dentistas`** — modelada como entidade própria; é, na verdade, uma **projeção da pessoa por workspace** (duplica o humano).
|
||
- **`pacientes`** — entidade presa à clínica; é a única "pessoa" do sistema **não tratada como pessoa**.
|
||
- **Laboratórios** — cadastro auxiliar; é o **único fornecedor real** e está subdimensionado.
|
||
- **Consultório** — vive como role **e** tipo (redundância).
|
||
|
||
**6. Riscos arquiteturais:** identidade fragmentada (dentistas); paciente não-portável e com resíduo de schema; conceito de workspace partido em duas tabelas; ausência de hierarquia "rede→clínica"; tenancy de `clinica_id` único barrando visão consolidada da pessoa; estado de plugins divergente cliente/servidor.
|
||
|
||
**7. Oportunidades arquiteturais:** a "Fase 1" **já entregou o mais difícil** (identidade + vínculo + workspace + workspace pessoal automático). O ecossistema (marketplace, salas, tutoria) **só existe** porque essa base existe. Unificar as entidades-recurso (dentista) e a entidade-paciente sob a pessoa **destravaria de uma vez** multi-clínica, portabilidade de histórico, redes e o marketplace — sem reescrever o que já está certo.
|
||
|
||
**8. Recomendação estratégica única:** **assumir e consolidar a PESSOA como âncora única do sistema, reconhecendo que a clínica já é — no código — apenas um tipo de workspace.** A decisão estratégica de fundo não é "se" migrar para Pessoa→Vínculo→Workspace (o sistema já escolheu isso na Fase 1), e sim **parar de manter o legado clínica-cêntrico em paralelo** nas duas entidades que ainda o sustentam (paciente e dentista-recurso) — pois é a coexistência dos dois modelos, não a escolha de um, que gera todas as contradições de gravidade ALTA.
|
||
|
||
---
|
||
|
||
> *Nota de método: tudo acima decorre de leitura de `backend/server.js`, do schema real (tabelas `usuarios`,
|
||
> `vinculos`, `clinicas`, `pacientes`, `dentistas`, `salas`, `protese_*`, `propostas_profissional`) e do
|
||
> `MAPA-FUNCIONAL-COMPLETO.md`. Onde o código tinha ambiguidade (ex.: dois INSERTs de `pacientes`, role↔tipo),
|
||
> descreveu-se o fato observado, sem inferir intenção. Conforme solicitado, não há propostas de implementação,
|
||
> migrations, código ou tarefas.*
|
||
</content>
|