feat(protese): Modo 1 fatia 1a — leitura da OS por link seguro /p/TOKEN (sem conta)
build-and-promote / build (push) Has been skipped
build-and-promote / promote (push) Successful in 58s

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>
This commit is contained in:
VPS 4 Builder
2026-06-24 06:53:02 +02:00
parent 5f4460e37d
commit 672c3b01e5
6 changed files with 322 additions and 5 deletions
+12
View File
@@ -1124,6 +1124,18 @@ export const HybridBackend = {
const res = await apiFetch(`${API_URL}/protese/lab/indicadores`);
return await res.json().catch(() => ({}));
},
// Modo 1: link seguro de acompanhamento da OS
gerarProteseLink: async (osId: string) => {
const res = await apiFetch(`${API_URL}/protese/os/${osId}/link`, { method: 'POST' });
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error || 'Erro ao gerar link');
return await res.json();
},
// Leitura PÚBLICA via token (sem login — não usa apiFetch/Authorization)
getProtesePublic: async (token: string) => {
const res = await fetch(`${API_URL}/p/${encodeURIComponent(token)}`);
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error || 'Link inválido ou expirado.');
return await res.json();
},
// Agenda de uma sala (reservas + bloqueios de manutenção) — usado pelo operador da unidade.
getSalaReservas: async (salaId: string): Promise<any[]> => {