Skip to main content

Assinar e corrigir o laudo — API

Torna o laudo oficial ao assiná-lo (padrão, complementar por médico adicional, ou pré-assinatura por residente), e permite corrigir o texto de um laudo já assinado sem reabrir o fluxo de assinatura.

Funcionamento​

Uma única rota, POST /reports/:id/signatures, cobre os três tipos de assinatura via o campo kind do corpo:

Sem kind (assinatura padrão, com propagação a conjugados).

  1. Busca o laudo mais recente do exame apontado (o "âncora") e a lista de exames "conjugados" (irmãos da mesma solicitação, quando houver). Sem conjugados, assina só o laudo âncora.
  2. Com conjugados, tenta assinar o laudo mais recente de cada exame conjugado (âncora incluída), na mesma sequência de validações abaixo; a falha em um conjugado é só logada — não interrompe os demais nem falha a chamada. Ao final, remove a marcação de "exame duplicado" do exame âncora, best-effort.
  3. Para cada laudo assinado individualmente:
    • Laudo não encontrado → recusa.
    • Laudo sem conteúdo nenhum (html vazio e não é OIT/mamografia/ecocardiograma) → recusa — não é possível assinar um laudo vazio.
    • Laudo já SIGNED → recusa.
    • Laudo PRE_SIGNED pelo próprio ator que está tentando assinar agora → recusa — quem pré-assinou como residente não pode fazer a assinatura final do próprio pré-laudo.
    • Exame excluído (soft delete) → recusa distinta de "exame não encontrado".
    • Confirma elegibilidade física do ator na unidade do exame e que os formulários de preparo do exame/laudo estão completos.
    • Se já existe um radiologista atribuído ao exame e esse radiologista já atuou no laudo → recusa (mesma família de erro do caso "pré-assinante tentando assinar").
    • Se o laudo é OIT, recalcula as iniciais do leitor a partir do nome do ator (ignorando títulos como "dr"/"dra") e grava nas extensões do formulário.
    • Verifica se há assinatura digital disponível para o ator (token SafeID presente e a integração habilitada) — se sim, marca o laudo como digitalmente assinado.
    • Persiste a assinatura. Atualiza o status do exame para SIGNED (primeira assinatura) ou RESIGNED (reassinatura); se o exame estava em preparo pendente e vai mudar de status, refaz a checagem completa de preparo. Remove marca de duplicata se houver. Reatribui a responsabilidade de radiologista ao assinante.
    • Registra o laudo assinado para entrega em integração externa.
    • Grava evento de auditoria de assinatura.
    • Após o commit da transação, dispara best-effort a geração do PDF final (síncrona à assinatura, mas seu resultado não bloqueia nem reverte a assinatura em si).

kind: "COMPLEMENT" (assinatura complementar por médico adicional).

  • Só é aceita sobre um laudo já SIGNED. É recusada se o próprio assinante original tentar complementar o próprio laudo, ou se já existe um médico adicional registrado (bloqueio de complemento duplo).
  • Confirma elegibilidade física do ator na unidade.
  • Registra o ator com o papel "médico adicional" no laudo — não muda signerUserId nem o status do laudo, só adiciona o papel.

kind: "RESIDENT" (pré-assinatura por residente).

  • Recusada se o laudo já está SIGNED.
  • Confirma elegibilidade física do residente na unidade.
  • Move o laudo para o status PRE_SIGNED com o residente registrado — não é a assinatura final; um médico precisa concluir depois com a assinatura padrão (e não pode ser o mesmo residente, conforme a regra de assinatura padrão acima).

POST /reports/:id/revisions (correção ortográfica pós-assinatura).

  1. Laudo precisa existir e estar SIGNED — senão recusa.
  2. O ator que corrige não pode ser o próprio assinante original — a correção exige um segundo par de olhos.
  3. Confirma que o ator tem a permissão de assinatura na unidade do laudo e elegibilidade física.
  4. Aplica a correção de texto (html) — o status e o signerUserId do laudo não mudam, só o conteúdo.
  5. Se addAsReviewer: true, registra o ator com o papel de "revisor ortográfico" (se ainda não tiver) e reivindica a responsabilidade de revisor no exame.
  6. Grava evento de auditoria e, após o commit, dispara o mesmo processamento pós-assinatura (PDF) do fluxo de assinatura normal.

Endpoints​

MétodoRotaDescrição
POST/v1/reports/:id/signaturesAssina o laudo (padrão / complementar / residente, via kind)
POST/v1/reports/:id/revisionsCorrige o texto de um laudo já assinado

Versão: v1

Swagger: POST /reports/{id}/signatures · Rota (Dev): http://localhost:3000/v1/reports/{id}/signatures

Lógica de decisão da assinatura padrão (sem kind), aplicada ao laudo âncora e a cada conjugado:

Permissões​

RotaGuardsPermissão / escopo
POST /reports/:id/signaturesJwtAuthenticationGuard, AuthorizationGuard, SensitiveRouteGuard, DiagnosisClinicalLicenseGuardREPORT_SIGN, escopo resource:report
POST /reports/:id/revisionsJwtAuthenticationGuard, AuthorizationGuardREPORT_WRITE, escopo resource:report — mais a checagem interna de REPORT_SIGN na unidade

SensitiveRouteGuard exige que o token traga assurance: "MFA" e que o step-up de MFA não seja mais antigo que o limite configurado para a classe de ação OTHER_PRIVILEGED (ApplicationPrivilegedAccessPolicy). Sem MFA → 403 INSUFFICIENT_ASSURANCE; MFA velho demais → 403 MFA_STEP_UP_REQUIRED; sem usuário autenticado → 401.

DiagnosisClinicalLicenseGuard exige licença profissional ativa (hasActiveProfessionalLicense) — senão 403 CLINICAL_LICENSE_REQUIRED. Assinar um laudo exige MFA recente e licença profissional ativa — os dois guards, além da permissão REPORT_SIGN.

Path parameters​

NomeTipoObrigatórioDescrição
idUUIDSimId do laudo (na assinatura padrão, funciona como âncora para propagação a conjugados)

Body​

POST /reports/:id/signatures — SignDiagnosisReportRequest:

json
{ "kind": "COMPLEMENT" }
CampoTipoObrigatórioValidação
kind"STANDARD" | "COMPLEMENT" | "RESIDENT"Não@IsIn; ausente = assinatura padrão

POST /reports/:id/revisions — ReviseDiagnosisReportSpellingRequest:

json
{ "html": "<p>texto corrigido</p>", "addAsReviewer": true }
CampoTipoObrigatórioValidação
htmlstringSim@IsString @IsNotEmpty
addAsReviewerbooleanNão@IsBoolean — registra o ator como revisor ortográfico do laudo/exame

Response​

200 — DiagnosisReportResponse (mesmo formato de Criar, editar, consultar e excluir laudo), refletindo statusId: "SIGNED"/"RESIGNED"/"PRE_SIGNED", signerUserId, signedAt e isDigitallySigned conforme o tipo de assinatura.

Erros​

Classe de erroerrorCodeStatusQuando ocorre
DiagnosisReportNotFoundErrorREPORT_NOT_FOUND404laudo inexistente
DiagnosisReportEmptyErrorREPORT_EMPTY400assinar laudo sem conteúdo nenhum
DiagnosisReportAlreadySignedErrorREPORT_SIGNED400laudo já SIGNED
DiagnosisPreSignedUserErrorPRE_SIGNED_USER400quem pré-assinou tenta fazer a assinatura final do próprio pré-laudo, ou radiologista já atribuído já atuou no laudo
DiagnosisExamExcludedErrorEXAME_EXCLUIDO400exame do laudo foi excluído
DiagnosisReportNotSignedErrorREPORT_NOT_SIGNED400guarda defensiva pós-persistência (não deveria ocorrer em uso normal); também lançado por complementSign/reviseSpelling quando o laudo não está SIGNED
DiagnosisReportTransitionNotAllowedErrorREPORT_COULD_NOT_SIGN400complemento pelo próprio assinante ou com médico adicional já registrado; correção pelo próprio assinante
ForbiddenAction (INSUFFICIENT_ASSURANCE/MFA_STEP_UP_REQUIRED)—403SensitiveRouteGuard: sem MFA ou MFA expirado
ForbiddenAction (CLINICAL_LICENSE_REQUIRED)—403DiagnosisClinicalLicenseGuard: sem licença profissional ativa
(validação de preparo do exame)PREPARATION_FIELDS_MISSING400formulários de preparo do exame incompletos (documentado no Swagger da rota; serviço não detalhado neste levantamento)

Regras de negócio​

IDRegraComportamento esperado
RN-01TOTP/MFA e licença profissional são pré-condição de qualquer assinaturaos dois guards rodam antes de qualquer lógica de negócio
RN-02Não se assina laudo vazioREPORT_EMPTY, exceto quando é OIT/mamografia/ecocardiograma estruturado
RN-03Quem pré-assina como residente não conclui a própria assinaturaPRE_SIGNED_USER
RN-04Assinatura padrão propaga a conjugados, tolerando falhas parciaisfalha num conjugado é logada, não interrompe os demais nem falha a chamada
RN-05Assinatura digital (SafeID) é decidida pelo token do ator, não por uma config globalisEnabled() && actor.hasSafeId && actor.hasSafeIdAccessToken
RN-06Assinatura complementar não pode ser feita pelo próprio assinante nem duplicadaREPORT_COULD_NOT_SIGN nos dois casos
RN-07Correção ortográfica exige um segundo médicoo próprio assinante não pode corrigir o próprio laudo
RN-08Correção não muda status nem assinante do laudosó o html muda; o laudo continua SIGNED
RN-09Geração do PDF pós-assinatura é assíncrona e best-effortfalha na geração/assinatura digital do PDF não desfaz a assinatura do laudo — vira um item de reprocessamento (ver Geração e impressão de PDF)

Compliance​

Órgão / normaExigênciaComo a rota atende
CFM / ICP-Brasilassinatura eletrônica com verificação forte de identidadeMFA recente obrigatório (SensitiveRouteGuard) + licença profissional ativa (DiagnosisClinicalLicenseGuard) antes de qualquer assinatura; assinatura digital ICP-Brasil via SafeID quando o ator está habilitado
LGPD / HIPAAtrilha de quem assinou/complementou/corrigiu, quando e com que resultadoeventos de auditoria diagnosis.report.signed, .complement-signed, .spelling-revised, .pre-signed-by-resident
ANVISA (indireto)laudo assinado não é alterado silenciosamenteconteúdo de laudo assinado só muda por rota própria e auditada (esta página), nunca pelo PATCH genérico

Variáveis de ambiente​

VariávelUsoObrigatória
(SafeID / DiagnosisDigitalSignatureClient)Habilita/desabilita a assinatura digital ICP-Brasil e a comunicação com o provedor externoA confirmar — responsável: time de Diagnosis; data: 24/09/2026. (implementação do cliente não lida neste levantamento)

Tempo médio de resposta​

A confirmar — responsável: time de Diagnosis; data: 24/09/2026. Não há medição publicada; a assinatura envolve, no mínimo, uma chamada síncrona ao guard de MFA e, quando SafeID está habilitado, uma chamada de rede ao provedor externo — tempos não medidos neste levantamento.

Requisitos não funcionais​

RequisitoDefinição
IdempotênciaNão — assinar duas vezes o mesmo laudo falha na segunda (REPORT_SIGNED); corrigir duas vezes aplica duas mudanças
AuditoriaSim — um evento por assinatura/complemento/correção
Efeito colateral assíncronoSim — geração de PDF best-effort após o commit, ver Geração e impressão de PDF

Relacionado​