Provedor de Prótese SEM conta (doc/MODO1-LINK-SEGURO-PROTESE): - Token por OS: tabela protese_os_link (aleatório 24B base64url, expira 60 dias, revogável, conta acessos). POST /protese/os/:id/link (gera/recupera) + POST .../link/revogar. - Leitura pública GET /api/p/:token (sem auth): payload curado com a mesma blindagem soLab — SEM paciente_id (CPF) e SEM valor cobrado ao paciente; mostra trabalho, etapas, componentes, fotos, custódia, ocorrências, histórico e custo do lab. - Página pública ProtesePublicView (mobile-first 320px+), interceptada no index.tsx antes do app autenticado; CTA "Criar conta grátis". Botão Gerar link / WhatsApp / Copiar na aba Monitoramento (modo clínica). - Validado em DEV: leitura, blindagem (CPF/valor ocultos), token inválido→404, revogação→404. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
5.8 KiB
Modo 1 — Provedor de Prótese SEM conta (link seguro /p/TOKEN)
Desenho (24/jun/2026). Evolução registrada como "fora de escopo" em
PROVEDOR-PROTESE-DECISAO.md. Princípio (decisão arquitetural): a clínica opera 100% da OS; o protético não precisa ter conta. O link é a porta de entrada do ecossistema — acompanha hoje, vira conta amanhã.
Objetivo
A clínica cria/gere a OS normalmente. O protético recebe um link seguro (WhatsApp/e-mail) e, sem login, acompanha e atua na OS dele. Com CTA para criar conta grátis (conversão).
Clínica cria OS ──► gera link /p/TOKEN ──► WhatsApp/e-mail ──► Protético abre (sem conta)
├─ vê a OS (sem CPF/valores do paciente)
├─ confirma recebimento/devolução
├─ avança etapa / anexa foto
└─ responde ocorrência
"Crie sua conta grátis" ──► cadastro (card Protético)
1. Escopo do token: por OS (não por protético)
Escopo mínimo = menor superfície de risco. Um token dá acesso a uma OS. Vantagens: revogável individualmente, expira por trabalho, não expõe a carteira inteira do protético. (Evolução: um token "carteira" por protético-na-clínica que lista várias OS — fica para depois.)
2. Modelo de dados (revogável e auditável)
CREATE TABLE IF NOT EXISTS protese_os_link (
token TEXT PRIMARY KEY, -- aleatório longo (≥ 32 bytes base62), NÃO sequencial
os_id TEXT NOT NULL,
protetico_id TEXT, -- a quem se destina (rastreio)
created_by TEXT, -- quem na clínica gerou
created_at TIMESTAMPTZ DEFAULT NOW(),
expires_at TIMESTAMPTZ, -- opcional (ex.: +30 dias); null = sem expirar
revoked_at TIMESTAMPTZ, -- revogação manual
last_access_at TIMESTAMPTZ,
acessos INTEGER DEFAULT 0
);
CREATE INDEX IF NOT EXISTS idx_protese_os_link_os ON protese_os_link (os_id);
Preferir tabela a JWT puro: permite revogar e auditar acessos. O token nunca contém dados.
3. Rotas públicas (sem authGuard; o token é a credencial)
Todas resolvem os_id pelo token (valida não-revogado, não-expirado) e aplicam a mesma blindagem
do provedor: sem paciente_id/CPF, sem valores do paciente (reusa a lógica soLab).
| Rota | Ação |
|---|---|
GET /api/p/:token |
OS: nº, clínica, dentista, paciente (nome, conforme permissão), prazo, status, observações, fotos, componentes, ocorrências, custódia. Sem CPF/valores do paciente. |
POST /api/p/:token/custodia |
confirmar recebimento / devolução (clínica↔lab) |
POST /api/p/:token/status |
avançar a produção (recebido→…→finalizado) |
POST /api/p/:token/foto |
anexar foto do trabalho (+ ocorrência) |
POST /api/p/:token/ocorrencias/:id/resposta |
responder ocorrência (contraditório) |
Cada ação registra no histórico da OS um actor "Protético (link)" com o protetico_id do token —
mantendo a auditoria. Mesmas validações de status/foto já existentes.
4. Geração e envio (lado clínica)
Na OS (modal, aba Etapas ou Monitoramento): botão "Enviar ao protético" →
POST /api/protese/os/:id/link gera/recupera o token e devolve a URL
https://scoreodonto.com/p/TOKEN. Atalhos: WhatsApp (https://wa.me/?text=…) e e-mail
(mailto:). Botão "Revogar link" para invalidar.
5. Frontend público /p/:token
Rota fora do app autenticado (sem Sidebar/login). Página enxuta que reusa as seções do
OSDetailModal em modo "público/lab" (etapas, fotos, componentes, custódia, ocorrências — sem
financeiro/clientes). Topo com a marca + rodapé fixo:
"Gostou de acompanhar por aqui? Crie sua conta grátis e gerencie todos os seus laboratórios." → leva ao cadastro já com o card Protético (adicionado) e e-mail pré-preenchido.
6. Segurança (checklist)
- Token aleatório ≥ 32 bytes, base62, não sequencial; comparação em tempo constante.
- Escopo de 1 OS; expiração opcional; revogável; rate-limit por token/IP.
- Sem CPF e sem valores do paciente (mesma blindagem
soLabda Fase 1). - Ações registram actor no histórico (auditoria);
last_access_at/acessospara detectar abuso. - OS
entregue/cancelado→ link vira somente leitura.
7. Conversão (o "porquê de negócio")
O link é aquisição: o protético experimenta o produto sem fricção e, ao criar conta, herda o
histórico (as OS daquela clínica já estão ligadas ao protetico_id dele). Liga direto ao
marketplace/score (Fase 5) — quanto mais clínicas o usam, mais OS e melhor o score do protético.
8. Faseamento sugerido
- ✅ 1a (núcleo) — IMPLEMENTADA 24/jun: tabela
protese_os_link(token aleatório 24 bytes base64url, expira em 60 dias, revogável);POST /api/protese/os/:id/link(gera/recupera) +POST …/link/revogar;GET /api/p/:token(leitura pública curada — sem CPF, sem valor do paciente; conta acessos). Página pública/p/:token(ProtesePublicView, mobile-first 320px+, interceptada noindex.tsxantes do app autenticado); botão "Gerar link / WhatsApp / Copiar" na aba Monitoramento (modo clínica). CTA "Criar conta grátis". Validado em DEV (leitura, blindagem, token inválido→404, revogação→404). - 1b (ação): custódia + status + foto pelo link (escrita), com auditoria.
- 1c (conversão): herança de histórico ao criar conta + revogação/expiração na UI.
Nenhuma refatoração: reusa OS/eventos/custódia/ocorrências/blindagem já existentes. Só adiciona a camada de token público.