Files
agenciapsilmno/development/saas-docs/05-assinatura-eletronica-melissa.json
Leonardo 3a42b0696d saas-docs: doc da Assinatura eletronica de documentos (Fase 3 #7)
Doc 05 cobrindo o fluxo end-to-end de assinatura eletronica:
- Visao geral (terapeuta cria solicitacao -> link publico -> paciente
  abre sem login -> aceite LGPD -> assinatura registrada server-side)
- Lado terapeuta: DocumentSignatureDialog (signatarios, toggle link
  publico, validade 24h/3d/7d/30d, URL copyavel)
- Lado paciente publico: SharedDocumentPage com /shared/document/:token
  (preview + painel LGPD + checkbox aceite + assinar/recusar + SHA-256
  computado client-side)
- Audit trail: hash + timestamp server + IP/UA via inet_client_addr()
  e current_setting (anti-spoof)
- Portal logado: PortalDocumentos lista pendencias com KPIs + filtro
- Expiracao de link, multiplos signatarios, validade legal LGPD/CFP/
  MP2200-2 (limite ICP-Brasil)
- Notas dev: RPCs, service, composable, components, pendencia notificacao
  automatica via Modulo 6

12 FAQs cobrindo: como pedir assinatura, paciente sem login, audit
registrado, terapeuta assinar tambem, validade do link, recusar, portal
do paciente, envio manual hoje, validade legal, integridade do conteudo,
cancelar solicitacao, multiplos signatarios.

categoria='Documentos', pagina_path='/melissa/paciente', ordem=5.
SQL import em database-novo/tmp/import-doc-assinatura-eletronica.sql.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 19:26:32 -03:00

88 lines
16 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"titulo": "Assinatura eletrônica de documentos",
"conteudo": "<h2>Assinatura eletrônica de documentos</h2>\n\n<p>O sistema permite enviar documentos clínicos (TCLE, contratos, autorizações, laudos) pro paciente assinar <strong>sem que ele precise ter login</strong>. O fluxo registra a assinatura com hash do conteúdo, IP, user-agent e timestamp — gerando um audit trail compliance LGPD/CFP.</p>\n\n<h3>1. Visão geral do fluxo</h3>\n<ol>\n <li><strong>Terapeuta</strong> abre o documento no prontuário e clica em <em>Assinar</em></li>\n <li>Adiciona os signatários (nome + email) e ativa <em>\"Gerar link público para assinatura\"</em></li>\n <li>Sistema cria signature requests + um <strong>link público temporário</strong> com token</li>\n <li>Terapeuta copia a URL e envia pro paciente (WhatsApp, email, SMS — manual por enquanto)</li>\n <li><strong>Paciente</strong> abre o link em qualquer navegador, lê o documento, marca o checkbox de aceite LGPD e clica <em>Assinar</em></li>\n <li>Sistema computa SHA-256 do PDF baixado, registra assinatura via RPC server-side (IP/UA capturados pelo banco)</li>\n <li>Terapeuta vê o status atualizado no documento (pendente → assinado)</li>\n</ol>\n\n<h3>2. Lado terapeuta — criar solicitação</h3>\n<p>No preview de um documento (na aba <em>Documentos</em> do prontuário), clique no botão <strong>Assinar</strong> na sidebar de ações. O <em>DocumentSignatureDialog</em> abre com:</p>\n<ul>\n <li><strong>Lista de signatários:</strong> adicione um ou mais — pra cada um, nome + email são obrigatórios. O paciente principal vem pré-preenchido se disponível.</li>\n <li><strong>Toggle \"Gerar link público para assinatura\"</strong> (default ON): cria um share_link junto com as signature requests. Sem isso, só fica a request registrada — o paciente precisa logar no portal pra assinar.</li>\n <li><strong>Select de validade do link:</strong> 24h / 3 dias / 7 dias / 30 dias. Default 7 dias (168h).</li>\n <li><strong>Submit:</strong> cria as requests + link e mostra a URL pronta pra copiar.</li>\n</ul>\n\n<h3>3. Lado paciente — link público (sem login)</h3>\n<p>Ao abrir o link <code>/shared/document/:token</code>, o paciente vê:</p>\n<ul>\n <li><strong>Preview do PDF</strong> inline (iframe)</li>\n <li><strong>Painel azul</strong> embaixo do preview com:\n <ul>\n <li>Aviso LGPD/CFP explicando o que vai ser registrado</li>\n <li>Checkbox <em>\"Li o documento e concordo com seu conteúdo\"</em> (bloqueia botões até marcado)</li>\n <li>Select de signatário (se houver mais de um cadastrado)</li>\n <li>Botões <strong>Assinar</strong> (emerald) e <strong>Recusar</strong> (rose)</li>\n </ul>\n </li>\n</ul>\n\n<p>Ao clicar Assinar:</p>\n<ol>\n <li>Sistema baixa o PDF e computa <strong>SHA-256</strong> client-side (proof of integrity — se o doc foi alterado depois, hash não bate)</li>\n <li>Chama a RPC <code>sign_document_by_token</code> passando o hash</li>\n <li>RPC captura <strong>IP via inet_client_addr()</strong> e <strong>user-agent via current_setting('request.headers')</strong> — server-side, à prova de spoof client-side</li>\n <li>Registra em <code>document_signatures</code>: timestamp, hash, IP, UA, status='assinado'</li>\n <li>Mostra tela de confirmação \"Documento assinado com sucesso\"</li>\n</ol>\n\n<h3>4. Audit trail registrado</h3>\n<p>Cada assinatura grava:</p>\n<ul>\n <li><strong>signatario_id</strong> (se o signatário tem cadastro como paciente vinculado)</li>\n <li><strong>signatario_nome</strong> e <strong>signatario_email</strong> (do que foi cadastrado pelo terapeuta)</li>\n <li><strong>assinado_em</strong> — timestamp da RPC (server time, não client clock)</li>\n <li><strong>assinatura_hash</strong> — SHA-256 do PDF no momento da assinatura</li>\n <li><strong>ip_address</strong> — capturado server-side (anti-spoof)</li>\n <li><strong>user_agent</strong> — header HTTP via current_setting</li>\n <li><strong>status</strong> — pendente / enviado / assinado / recusado / expirado</li>\n</ul>\n\n<div style=\"background: rgba(16,185,129,0.08); border: 1px solid rgba(16,185,129,0.3); border-radius: 10px; padding: 12px 14px; margin: 14px 0; font-size: 0.85rem;\">\n <strong>🛡️ Por que server-side?</strong> Capturar IP/UA no banco via <code>inet_client_addr()</code> é anti-spoof: o cliente não consegue forjar valores arbitrários. Garante que o audit trail reflete a sessão HTTP real, não um POST manipulado.\n</div>\n\n<h3>5. Recusar a assinatura</h3>\n<p>O paciente pode <strong>recusar</strong> em vez de assinar — útil se ele não concorda com o conteúdo. Click em <strong>Recusar</strong> abre um <em>confirm</em>; ao confirmar, o sistema registra a recusa (com timestamp + IP/UA da mesma forma) e marca a request como <code>status='recusado'</code>. O terapeuta vê isso na lista de signature requests e pode entrar em contato pra ajustar o documento.</p>\n\n<h3>6. Portal do paciente — lista de pendências</h3>\n<p>Pacientes logados no portal (<code>/portal/documentos</code>) veem uma lista de TODOS os documentos solicitados pra eles, com KPIs no topo:</p>\n<ul>\n <li><strong>Total</strong> · <strong>Pendentes</strong> · <strong>Assinados</strong> · <strong>Recusados</strong></li>\n</ul>\n<p>Filtro por status (todos / pendentes / assinados) + lista. Click em <strong>Assinar agora</strong> num item pendente leva pro <code>/shared/document/:token</code> (mesma página pública, mas com auth já garantida via portal).</p>\n\n<h3>7. Expiração e múltiplos usos</h3>\n<ul>\n <li><strong>Validade do link:</strong> configurada na criação (24h/3d/7d/30d). Após expirar, retorna 410 Gone. Terapeuta pode gerar novo link pelo botão <em>Compartilhar</em> no preview do doc.</li>\n <li><strong>Limite de usos:</strong> calculado como <code>max(signatários × 3, 5)</code> — gerar 1 signatário dá 5 usos disponíveis (margem de erro / reload / multi-device).</li>\n <li><strong>Cada assinatura é única:</strong> mesmo signatário não consegue assinar 2x — a RPC bloqueia se já houver registro com status=assinado.</li>\n</ul>\n\n<h3>8. Múltiplos signatários</h3>\n<p>Documentos como termo de autorização de menor podem precisar de 2+ assinaturas (responsável legal + paciente menor, ou os dois pais). O dialog aceita N signatários; cada um recebe sua própria entry em <code>document_signatures</code>. O link público é o mesmo — quando o paciente abre, escolhe qual signatário ele é no select e assina apenas a sua entry.</p>\n\n<h3>9. Validade legal</h3>\n<p>A assinatura eletrônica registrada pelo sistema atende:</p>\n<ul>\n <li><strong>LGPD (Lei 13.709/2018):</strong> consentimento explícito registrado com timestamp, IP e UA — base legal Art. 7º I</li>\n <li><strong>Código de Ética CFP:</strong> documento clínico com identificação inequívoca do signatário (nome+email+IP+hash)</li>\n <li><strong>MP 2200-2/2001 (ICP-Brasil):</strong> assinatura <em>simples</em> com integridade via hash — não é certificado A1/A3, mas é válida pra documentos sem exigência ICP</li>\n</ul>\n<p>⚠️ Pra documentos que exigem ICP-Brasil (notarial, procuração com poderes especiais), use uma plataforma externa de assinatura qualificada — esse fluxo não substitui.</p>\n\n<h3>⚠️ Notas pro desenvolvedor</h3>\n<ul>\n <li><strong>RPCs:</strong> <code>sign_document_by_signature_id</code> (paciente logado no portal), <code>sign_document_by_token</code> (link público), <code>get_signable_document_by_token</code> (resolve token → doc + signature_request), <code>list_my_signatures</code> (lista do paciente, cruza por signatario_id, signatario_email e patient.user_id)</li>\n <li><strong>Service:</strong> <code>DocumentSignatures.service.js</code> com wrappers <code>signByPortal</code>, <code>signByToken</code>, <code>getSignableDocumentByToken</code>, <code>listMySignatures</code>, <code>hashDocument</code>, <code>refuseSignature</code>, <code>createSignatureRequests</code>, <code>createShareLink</code>, <code>buildShareUrl</code></li>\n <li><strong>Composable:</strong> <code>useDocumentSignatures</code> (Tipo A blueprint)</li>\n <li><strong>UI lado terapeuta:</strong> <code>DocumentSignatureDialog.vue</code> (component)</li>\n <li><strong>UI lado paciente:</strong> <code>PortalDocumentos.vue</code> (portal logado) + <code>SharedDocumentPage.vue</code> (link público)</li>\n <li><strong>Notificação automática</strong> (paciente recebe email/WA quando signature criada) — pendente, depende de Módulo 6 (notifications factory channel)</li>\n</ul>",
"categoria": "Documentos",
"exibir_no_faq": true,
"tipo_acesso": "usuario",
"pagina_path": "/melissa/paciente",
"ordem": 5,
"ativo": true,
"medias": [
{ "tipo": "imagem", "url": "" }
],
"_faq_itens": [
{
"pergunta": "Como peço pra um paciente assinar um documento (TCLE, contrato, autorização)?",
"resposta": "Na aba <strong>Documentos</strong> do prontuário, clique no doc → no preview, clique em <strong>Assinar</strong> (sidebar de ações). O dialog abre. Adicione o paciente como signatário (nome + email), mantenha <em>\"Gerar link público para assinatura\"</em> marcado, escolha validade (7 dias é o default) e clique em <strong>Solicitar</strong>. O sistema cria a request e mostra uma URL pra copiar. Envie pro paciente via WhatsApp, email, SMS — como preferir.",
"ordem": 0,
"ativo": true
},
{
"pergunta": "Como o paciente assina sem ter login no sistema?",
"resposta": "Ele abre o link público (<code>/shared/document/:token</code>) em qualquer navegador. Vê o PDF inline, lê o aviso LGPD/CFP, marca o checkbox <em>\"Li o documento e concordo\"</em>, e clica <strong>Assinar</strong>. O sistema computa hash SHA-256 do PDF, chama a RPC server-side que captura IP/User-Agent e registra a assinatura. Nada de cadastro, nada de senha.",
"ordem": 1,
"ativo": true
},
{
"pergunta": "Que informação fica registrada quando ele assina?",
"resposta": "Tudo que precisa pra audit compliance: <strong>nome e email</strong> do signatário (do cadastro), <strong>timestamp server-side</strong> (não do relógio do cliente), <strong>hash SHA-256 do PDF</strong> no momento da assinatura (qualquer alteração posterior invalida a integridade), <strong>IP</strong> e <strong>User-Agent</strong> capturados pelo banco via <code>inet_client_addr()</code> e <code>current_setting('request.headers')</code> — anti-spoof. Tudo fica em <code>public.document_signatures</code>.",
"ordem": 2,
"ativo": true
},
{
"pergunta": "O terapeuta também precisa assinar o documento?",
"resposta": "Depende do tipo. Pra atestados, laudos e declarações, geralmente sim — você gera o PDF a partir do template (que já contém seu nome + registro profissional + assinatura digitalizada se você incluiu no rodapé). Pra contratos e termos com paciente como contraparte, você adiciona você mesmo como segundo signatário no dialog antes de enviar. Cada um abre o link e assina sua entry separadamente.",
"ordem": 3,
"ativo": true
},
{
"pergunta": "O link tem validade? E se expirar?",
"resposta": "Tem. Você escolhe 24h, 3 dias, 7 dias ou 30 dias na hora de criar (default 7d). Depois disso o link retorna erro 410 Gone. Se o paciente não assinou a tempo, gere um novo link: no preview do doc, clique em <strong>Compartilhar</strong> ou abra o dialog de assinatura novamente — vai criar outro token. Limite de usos do link: ~5 (margem pra reload/multi-device), depois também expira.",
"ordem": 4,
"ativo": true
},
{
"pergunta": "E se o paciente recusar a assinatura?",
"resposta": "Tem botão <strong>Recusar</strong> ao lado do <em>Assinar</em>. Clique pede confirmação; ao confirmar, a request fica com <code>status='recusado'</code> com timestamp e IP/UA registrados igual à assinatura. Você vê o status na lista de pendências do doc e na aba do prontuário. Geralmente: ajuste o conteúdo do documento e envie nova solicitação.",
"ordem": 5,
"ativo": true
},
{
"pergunta": "O paciente pode assinar depois pelo Portal sem precisar do link?",
"resposta": "Sim, se ele tem conta de portal. Em <strong>/portal/documentos</strong> aparece a lista de tudo que está pendente pra ele assinar, com KPIs (total, pendentes, assinados, recusados) e botão <strong>Assinar agora</strong> que leva pra mesma página de assinatura. Útil pra pacientes que perderam o link no WhatsApp — eles loga e acha tudo num lugar só.",
"ordem": 6,
"ativo": true
},
{
"pergunta": "Como compartilho o link com o paciente — tem envio automático?",
"resposta": "Hoje o envio é <strong>manual</strong>: o dialog gera a URL, você copia e cola onde quiser (WhatsApp, email, SMS, AirDrop, QR code, link em conversa direta). Envio automático (notificação por WA/email quando signature é criada) está no roadmap, depende do Módulo 6 (notifications factory channel) que ainda não foi implementado.",
"ordem": 7,
"ativo": true
},
{
"pergunta": "A assinatura tem validade legal mesmo sem certificado ICP-Brasil?",
"resposta": "Pra documentos clínicos comuns (TCLE, contrato de prestação, autorizações, declarações entre terapeuta-paciente), <strong>sim</strong>. A assinatura simples com timestamp + hash + IP + UA atende LGPD (Art. 7º I — consentimento explícito) e o Código de Ética do CFP. Pra documentos que exigem certificado ICP-Brasil (notarial, procuração com poderes especiais), use uma plataforma externa de assinatura qualificada — esse fluxo não substitui.",
"ordem": 8,
"ativo": true
},
{
"pergunta": "O paciente consegue editar o documento antes de assinar?",
"resposta": "Não. O paciente <strong>só visualiza</strong> — o PDF é renderizado em iframe e a integridade é garantida pelo hash SHA-256 computado no momento da assinatura. Se o conteúdo precisar mudar, é você que ajusta o documento (editar via template ou regenerar) e envia nova solicitação. A assinatura antiga (se houve) fica registrada com o hash do conteúdo antigo — o doc atual tem hash diferente, mostrando que mudou.",
"ordem": 9,
"ativo": true
},
{
"pergunta": "Como cancelo uma solicitação de assinatura?",
"resposta": "Hoje não há um botão \"cancelar\" direto na UI. O caminho é: ignore (deixa expirar pelo prazo do link) ou peça pro admin marcar como <code>status='expirado'</code> no banco. Em versões futuras teremos botão de cancelar na lista de pendências do doc.",
"ordem": 10,
"ativo": true
},
{
"pergunta": "Posso pedir mais de uma pessoa pra assinar o mesmo documento?",
"resposta": "Sim. Pra termos com múltiplos signatários (autorização de atendimento de menor com 2 pais, contrato com responsável legal + paciente), adicione cada um como signatário separado no dialog. Cada um vira uma entry em <code>document_signatures</code>. O link público é o mesmo — quando o signatário abre, escolhe quem ele é no select acima dos botões e assina apenas a entry dele. Útil também pra você incluir si mesmo (terapeuta) + paciente num contrato bilateral.",
"ordem": 11,
"ativo": true
}
]
}