diff --git a/doc/MODO1-LINK-SEGURO-PROTESE.md b/doc/MODO1-LINK-SEGURO-PROTESE.md new file mode 100644 index 0000000..8e553f0 --- /dev/null +++ b/doc/MODO1-LINK-SEGURO-PROTESE.md @@ -0,0 +1,89 @@ +# 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) +```sql +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 `soLab` da Fase 1). +- Ações registram actor no histórico (auditoria); `last_access_at`/`acessos` para 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):** tabela + `GET /api/p/:token` (leitura) + página pública read-only + botão "enviar". +- **1b (ação):** custódia + status + foto pelo link (escrita), com auditoria. +- **1c (conversão):** CTA de cadastro com herança de histórico + 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. diff --git a/frontend/views/OnboardingChat.tsx b/frontend/views/OnboardingChat.tsx index 5235505..0d3b03f 100644 --- a/frontend/views/OnboardingChat.tsx +++ b/frontend/views/OnboardingChat.tsx @@ -1,6 +1,6 @@ import React, { useState, useEffect, useRef } from 'react'; import { - Building2, Briefcase, Stethoscope, Sparkles, DoorOpen, + Building2, Briefcase, Stethoscope, Sparkles, DoorOpen, FlaskConical, ArrowRight, ArrowLeft, ChevronLeft, Loader2, Send, Check, CheckCircle2, User as UserIcon } from 'lucide-react'; @@ -17,6 +17,7 @@ const SLIDES: { icon: any; accent: string; title: string; desc: string; cta: str { icon: Briefcase, accent: '#0d9488', title: 'Consultórios', desc: 'Para quem voa solo: agenda inteligente e cobrança sem complicação.', cta: 'Cadastrar meu consultório', pre: { perfil: 'consultorio' } }, { icon: Stethoscope, accent: '#7c3aed', title: 'Dentistas', desc: 'Sua agenda única — sem overbooking, mesmo atendendo em vários lugares.', cta: 'Sou dentista', pre: { perfil: 'profissional', profissao: 'dentista' } }, { icon: Sparkles, accent: '#db2777', title: 'Biomédicos', desc: 'Harmonização orofacial e estética com prontuário e fotos por procedimento.', cta: 'Sou biomédico(a)', pre: { perfil: 'profissional', profissao: 'biomedico' } }, + { icon: FlaskConical, accent: '#2d6a4f', title: 'Protéticos', desc: 'Laboratório completo: bancada, ordens, etapas, componentes, financeiro e score.', cta: 'Sou protético(a)', pre: { perfil: 'profissional', profissao: 'protetico' } }, { icon: DoorOpen, accent: '#0d9488', title: 'Salas', desc: 'Alugue ou anuncie salas por hora, dia ou mês. Valor fixo ou negociado.', cta: 'Tenho salas para alugar', pre: { perfil: 'sala' } }, ];