saas-docs: doc da aba Documentos do paciente (Fase 2)

Doc 03 cobrindo o fluxo completo da aba Documentos no prontuario:
- Layout 2-col (sidebar de tipos + main grid)
- Toolbar: Atualizar/Gerar/Upload
- Upload (drag-drop, metadados, visibilidade)
- 11 tipos de documento + classificacao automatica
- Gerar a partir de template (fluxo 3 steps com auto-fill de vars)
- Edicao in-place (re-editar doc gerado, preserva ID+audit) — feature
  nova de 22/05
- Preview com 5 acoes (Baixar/Editar/Compartilhar/Assinar/Excluir)
- Share dialog (link publico temporario)
- Assinatura eletronica
- Soft-delete + retencao 5 anos (LGPD/CFP)
- Mobile drawer pros tipos

12 FAQs cobrindo casos comuns: upload, geracao, auto-fill, edicao
de gerado, edicao de uploaded, share, sign, recuperar excluido,
formatos aceitos, visibilidade, fix do bug 22/05 dos botoes do preview.

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

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Leonardo
2026-05-22 14:04:05 -03:00
parent 89bf181742
commit ec56f9429b
2 changed files with 260 additions and 0 deletions
@@ -0,0 +1,173 @@
-- Importacao da doc da aba Documentos do paciente (Fase 2)
-- Gerado a partir de development/saas-docs/03-documentos-paciente-melissa.json
BEGIN;
DO $IMPORT$
DECLARE
v_doc_id uuid;
BEGIN
INSERT INTO public.saas_docs (
titulo, conteudo, categoria, exibir_no_faq, tipo_acesso,
pagina_path, ordem, ativo, medias
) VALUES (
'Documentos do paciente',
$HTML$<h2>Documentos do paciente</h2>
<p>A aba <strong>Documentos</strong> do prontuário (em <code>/melissa/paciente?id=...&amp;tab=documentos</code>) centraliza tudo que está vinculado àquele paciente: arquivos enviados por upload, documentos gerados a partir de templates (atestados, declarações, recibos, laudos), e tudo que precisa ser compartilhado ou assinado.</p>
<h3>1. Layout 2-col</h3>
<p>A página tem 2 colunas:</p>
<ul>
<li><strong>Sidebar esquerda (~240px):</strong> lista de tipos de documento com contadores. Click num tipo filtra a lista. "Todos" mostra tudo.</li>
<li><strong>Main direita:</strong> grid de cards dos documentos do tipo selecionado, com paginação a partir de 12 itens.</li>
</ul>
<p>No <strong>mobile</strong> (&lt;1024px), a sidebar vira um drawer acessado pelo botão "Tipos" no header.</p>
<h3>2. Toolbar (header)</h3>
<p>3 botões no topo:</p>
<ul>
<li><strong> Atualizar:</strong> refetch da lista (ícone spinner quando carregando)</li>
<li><strong>📄 Gerar:</strong> abre o dialog de geração a partir de template (vide seção 5)</li>
<li><strong> Upload</strong> (botão primário): abre o dialog de envio de arquivo (vide seção 3)</li>
</ul>
<h3>3. Upload de arquivo</h3>
<p>Click no botão <strong>Upload</strong> abre um dialog que aceita:</p>
<ul>
<li><strong>Drag-and-drop</strong> ou seleção manual</li>
<li>Formatos: PDF, imagens (JPG, PNG, WebP), Word, Excel, texto</li>
<li>Metadados opcionais: <strong>tipo</strong>, <strong>categoria</strong>, <strong>descrição</strong>, <strong>tags</strong>, <strong>visibilidade</strong> (privado / compartilhado supervisor / compartilhado portal paciente)</li>
</ul>
<p>Após o upload, o arquivo aparece na lista do tipo escolhido (ou "Outro" se você não selecionou).</p>
<h3>4. Tipos de documento (sidebar)</h3>
<p>Cada documento é classificado em um tipo. Tipos disponíveis:</p>
<ul>
<li><strong>Laudo</strong> laudo psicológico, parecer</li>
<li><strong>Atestado</strong> atestado psicológico</li>
<li><strong>Declaração</strong> comparecimento, início de tratamento, encaminhamento</li>
<li><strong>Recibo</strong> recibos de pagamento gerados</li>
<li><strong>Receita</strong> receituários (uso raro em psicologia)</li>
<li><strong>Exame</strong> laudos/resultados de exames trazidos pelo paciente</li>
<li><strong>Termo assinado</strong> TCLE, autorizações</li>
<li><strong>Relatório externo</strong> relatórios de acompanhamento gerados</li>
<li><strong>Identidade</strong> RG, CPF, CNH (cópias)</li>
<li><strong>Convênio</strong> carteirinhas, autorizações de convênio</li>
<li><strong>Outro</strong> fallback pra tudo que não se encaixa nos tipos acima</li>
</ul>
<p>O contador ao lado de cada tipo mostra quantos docs daquele tipo o paciente tem. Tipos vazios ficam com opacidade reduzida.</p>
<h3>5. Gerar a partir de template</h3>
<p>Click no botão <strong>Gerar</strong> abre o <em>DocumentGenerateDialog</em> em 3 passos:</p>
<ol>
<li><strong>Selecionar template:</strong> grid com todos os templates ativos (globais + do tenant). Click num card seleciona.</li>
<li><strong>Editar variáveis:</strong> os campos do template aparecem com FloatLabel. Variáveis que vêm do sistema (nome do paciente, CRP do terapeuta, CNPJ da clínica etc) vêm preenchidas automaticamente. Banner no topo conta "X de Y preenchidos". Campos vazios mostram um hint embaixo explicando onde cadastrar o dado (ex: <em>"Perfil → Registro Profissional"</em>).</li>
<li><strong>Preview:</strong> iframe sandboxed renderizando o HTML do template com as vars substituídas. Daqui você pode voltar pra editar, baixar o PDF (sem salvar no sistema), ou salvar como documento do paciente.</li>
</ol>
<div style="background: rgba(34,197,94,0.08); border: 1px solid rgba(34,197,94,0.25); border-radius: 10px; padding: 12px 14px; margin: 14px 0; font-size: 0.85rem; color: var(--text-color);">
<strong>💡 Auto-fill cobre:</strong> dados do paciente, terapeuta (incluindo registro profissional formatado tipo "CRP 12345/SP"), clínica/tenant (incluindo CNPJ formatado), data atual em formato curto e por extenso, e se a sessão for vinculada valor da sessão em número e por extenso.
</div>
<h3>6. Editar um documento gerado (re-edição in-place)</h3>
<p>Documentos gerados a partir de template podem ser <strong>re-editados</strong> mantendo o mesmo registro (ID, audit trail e link com o paciente preservados). Click em <strong>Editar</strong> no card do doc ou na sidebar do preview:</p>
<ol>
<li>O sistema busca o template original + os valores que você usou na primeira geração</li>
<li>Abre o dialog em modo edição (header amber "Editar documento") pulando direto pro passo 2 (variáveis pré-preenchidas)</li>
<li>Você ajusta o que precisar Preview <strong>Substituir documento</strong></li>
<li>O PDF é regenerado e substitui o anterior no Storage; o doc fica com o mesmo ID, audit trail intacto</li>
</ol>
<p><strong>Documento legado</strong> (sem registro de geração ou que era um upload): o dialog mostra um toast e cai no fluxo normal de "selecione um template". Ao salvar, ele linka o doc existente ao novo template/valores.</p>
<h3>7. Preview do documento</h3>
<p>Click num card abre o <em>DocumentPreviewDialog</em>:</p>
<ul>
<li><strong>Preview inline:</strong> iframe pra PDF, imagem renderizada direto, fallback "Preview não disponível" pra outros formatos</li>
<li><strong>Sidebar de detalhes</strong> (direita): tipo, categoria, visibilidade, descrição, tags</li>
<li><strong>5 botões de ação</strong> no rodapé da sidebar:
<ul>
<li><strong>Baixar</strong> download direto do arquivo</li>
<li><strong>Editar</strong> abre o generate dialog em modo edição (seção 6)</li>
<li><strong>Compartilhar</strong> gera link compartilhável (seção 8)</li>
<li><strong>Assinar</strong> fluxo de assinatura eletrônica (seção 9)</li>
<li><strong>Excluir</strong> (vermelho) soft-delete com confirmação</li>
</ul>
</li>
</ul>
<h3>8. Compartilhar</h3>
<p>Gera um link público temporário pro paciente acessar o documento sem precisar de login. Configurável:</p>
<ul>
<li>Tempo de expiração (1h, 24h, 7 dias, custom)</li>
<li>Senha opcional</li>
<li>Permitir download ou visualização</li>
</ul>
<p>O status compartilhado fica visível na sidebar de detalhes do preview.</p>
<h3>9. Assinar</h3>
<p>Fluxo de assinatura eletrônica (modal). O documento original recebe uma <strong>página adicional de assinatura</strong> com timestamp e identificação do signatário. A assinatura é registrada em <code>document_signatures</code> com hash do conteúdo original (proof of integrity).</p>
<h3>10. Excluir e recuperar</h3>
<p>Excluir é <strong>soft-delete</strong>: o documento ganha <code>deleted_at</code> mas o arquivo permanece no Storage e o registro fica preservado por <strong>5 anos</strong> (compliance LGPD/CFP). Pra recuperar, em <strong>Configurações Lixo de documentos</strong>.</p>
<h3> Notas pro desenvolvedor</h3>
<p>O componente <code>MelissaPatientDocuments.vue</code> reusa do <code>features/documents</code>:</p>
<ul>
<li><code>useDocuments</code> composable de fetch/CRUD/URLs assinadas</li>
<li><code>DocumentCard</code>, <code>DocumentUploadDialog</code>, <code>DocumentPreviewDialog</code>, <code>DocumentGenerateDialog</code>, <code>DocumentSignatureDialog</code>, <code>DocumentShareDialog</code></li>
</ul>
<p>O linkage <code>document_generated.documento_id</code> (FK pra <code>documents</code>) é o que viabiliza a re-edição in-place. Docs gerados antes da migration de linkage precisam do backfill SQL em <code>database-novo/tmp/backfill-document-generated-link.sql</code>.</p>$HTML$,
'Documentos',
true,
'usuario',
'/melissa/paciente',
3,
true,
'[{"tipo": "imagem", "url": ""}]'::jsonb
)
RETURNING id INTO v_doc_id;
INSERT INTO public.saas_faq_itens (doc_id, pergunta, resposta, ordem, ativo) VALUES
(v_doc_id, 'Como envio um documento que já existe (PDF/imagem do paciente)?',
$FAQ$Na aba <strong>Documentos</strong> do prontuário, click no botão <strong>Upload</strong> (azul, no canto superior direito). Você pode arrastar o arquivo pra área do dialog ou clicar pra selecionar. Antes de enviar, preencha o tipo, descrição e tags se quiser assim o doc vai pra categoria certa na sidebar.$FAQ$, 0, true),
(v_doc_id, 'Como gero um documento (atestado, declaração, recibo) a partir de template?',
$FAQ$Click no botão <strong>Gerar</strong> no header da aba Documentos do paciente. O dialog abre em 3 passos: (1) escolha o template, (2) confira as variáveis pré-preenchidas (e ajuste se necessário), (3) preview e <em>Salvar documento</em>. O PDF é gerado e salvo automaticamente no prontuário.$FAQ$, 1, true),
(v_doc_id, 'As variáveis (CRP, nome, CNPJ etc) preenchem sozinhas mesmo?',
$FAQ$Sim, sempre que possível. O sistema busca: dados do paciente (nome, CPF, RG, endereço, telefone, email), do terapeuta (nome, email, telefone, e o registro profissional formatado tipo <em>CRP 12345/SP</em>), da clínica (nome, endereço, telefone, CNPJ formatado), data atual em formato curto e por extenso. Se você abriu o gerador a partir de uma sessão, os dados da sessão (valor, data) também entram. Campos vazios mostram embaixo um hint dizendo onde cadastrar o dado faltante.$FAQ$, 2, true),
(v_doc_id, 'Posso editar um documento gerado sem refazer tudo do zero?',
$FAQ$Sim. Click em <strong>Editar</strong> no card do documento (ou na sidebar do preview). O dialog abre em <em>modo edição</em> com o template original selecionado e <strong>todos os valores que você usou anteriormente preenchidos</strong>. Você ajusta o que precisa, confere o preview e click em <em>Substituir documento</em>. O PDF é regenerado e substitui o anterior, mas o ID e o audit trail do doc continuam os mesmos.$FAQ$, 3, true),
(v_doc_id, 'Posso editar um documento que foi feito por upload (não por template)?',
$FAQ$Sim, mas o fluxo é diferente: como não template original, o sistema mostra um aviso e abre o dialog em modo "selecione um template". Ao salvar, ele <strong>substitui o arquivo enviado por um PDF gerado</strong> e linka ao novo template. Útil pra "converter" um upload manual em algo padronizado. Se você quer trocar o arquivo, exclua o doc e faça upload do novo.$FAQ$, 4, true),
(v_doc_id, 'Como compartilho um documento com o paciente sem ele precisar logar?',
$FAQ$No preview, click em <strong>Compartilhar</strong>. Um dialog gera um link público temporário com opção de tempo de expiração (1h, 24h, 7 dias, custom) e senha opcional. O paciente acessa pelo link, sem login. O status fica visível na sidebar de detalhes do doc.$FAQ$, 5, true),
(v_doc_id, 'Como assino eletronicamente um documento?',
$FAQ$No preview, click em <strong>Assinar</strong>. O fluxo adiciona uma página de assinatura ao PDF com timestamp e identificação. A assinatura é registrada com hash do conteúdo original qualquer alteração posterior invalida a integridade. Ideal pra laudos, declarações e atestados que precisam de validade legal.$FAQ$, 6, true),
(v_doc_id, 'Excluí um documento por engano, dá pra recuperar?',
$FAQ$Sim. Exclusão é <strong>soft-delete</strong> o documento ganha um marcador <code>deleted_at</code> mas continua no banco e o arquivo permanece no Storage. Pra recuperar, em <strong>Configurações Lixo de documentos</strong>. O período de retenção é de <strong>5 anos</strong> (compliance LGPD e regulamentação CFP), depois o arquivo é purgado permanentemente.$FAQ$, 7, true),
(v_doc_id, 'Por que alguns documentos aparecem na categoria "Outro"?',
$FAQ$Documentos enviados por upload sem tipo definido caem em "Outro" automaticamente. Documentos gerados a partir de templates cujo tipo não está mapeado pras categorias padrão (declarações, atestados, laudos, etc) também exemplos: contrato de prestação de serviços, autorização para gravação, termo de consentimento. Você pode mover o doc pra outra categoria editando o tipo na hora do upload ou via menu de ações no card.$FAQ$, 8, true),
(v_doc_id, 'Quais formatos de arquivo posso fazer upload?',
$FAQ$PDF, imagens (JPG, PNG, WebP, GIF), documentos Office (DOCX, XLSX, PPTX), texto simples (TXT, CSV) e formatos compactados (ZIP). Pra qualquer formato fora dessa lista, salve como PDF antes. O preview inline funciona pra PDF e imagens outros formatos mostram a opção "Baixar arquivo" no lugar.$FAQ$, 9, true),
(v_doc_id, 'Como o sistema garante que o documento não vaza pra outros profissionais?',
$FAQ$Cada documento tem um campo de <strong>visibilidade</strong>: <em>Privado</em> ( você ), <em>Compartilhado com supervisor</em> (você + seu supervisor) ou <em>Compartilhado com portal do paciente</em> (o paciente também pelo portal). O default é Privado. RLS (Row Level Security) no banco bloqueia leitura por terceiros, independente da visibilidade. URLs do Storage são assinadas e expiram em 1h.$FAQ$, 10, true),
(v_doc_id, 'Os botões da sidebar do preview (Baixar/Editar/Compartilhar/Assinar/Excluir) não funcionavam, foi corrigido?',
$FAQ$Sim. Bug conhecido até 2026-05-22: o <code>DocumentPreviewDialog</code> emitia os 5 eventos mas o componente pai não os escutava, então nada acontecia ao clicar. Agora todos os 5 botões funcionam normalmente e o de Editar abre o dialog de geração em modo edição.$FAQ$, 11, true);
RAISE NOTICE 'Doc criada: id=%, faq_itens=12', v_doc_id;
END;
$IMPORT$;
COMMIT;
File diff suppressed because one or more lines are too long