Skip to main content

Sinalizar achado crítico e suspeita técnica — API

Permite a um usuário autorizado marcar ou desmarcar duas flags clínicas independentes de um exame: achado crítico (um resultado que exige atenção imediata) e suspeita técnica (uma dúvida sobre a qualidade técnica do exame). As duas flags têm o mesmo formato de rota, o mesmo modelo de resposta e o mesmo mecanismo de permissão — mas são estados separados: marcar uma não afeta a outra. Nenhuma das duas cria um comentário; ver Comentar exame para o recurso de texto livre.

Funcionamento​

Ler o estado atual (GET /exams/:id/critical-finding ou /technical-suspicion): devolve o valor booleano atual da flag, quando ela mudou pela última vez (since) e quem mudou (by). A leitura do achado crítico também registra um evento de auditoria (diagnosis.exam.critical-finding-read); a leitura da suspeita técnica não gera esse evento — divergência confirmada no código (ver mais abaixo).

Marcar/desmarcar (PUT/DELETE /exams/:id/critical-finding ou /technical-suspicion):

  1. Autentica o access token e autoriza a permissão específica da flag (exam:flag-critical-finding ou exam:flag-technical-suspicion) com escopo RLS sobre o id do exame — sem acesso ao exame ou à unidade, a resposta é 404.
  2. Busca o exame (com lock de escrita) e valida o corpo: reason é opcional, mas se enviado tem no máximo 500 caracteres.
  3. Se o valor pedido (true no PUT, false no DELETE) já é o valor atual da flag, a operação é idempotente: devolve o estado atual sem gravar nada de novo, sem gerar um novo evento de auditoria.
  4. Caso contrário, grava a mudança (quem marcou/desmarcou e quando), registra o evento de auditoria correspondente (diagnosis.exam.critical-finding-changed ou diagnosis.exam.technical-suspicion-changed, com o reason na metadata) e agenda a reprojeção do item de worklist do exame.

Descobrir capacidades (GET /exams/:id/capabilities): rota auxiliar usada para o front decidir se mostra as ações de sinalização, sem precisar tentar a chamada e tratar um 403. Devolve, entre outras capacidades do exame não relacionadas a este documento (canAssignTeam, canRevealPatientIdentity), os campos canFlagCriticalFinding e canFlagTechnicalSuspicion.

Endpoints​

MétodoRotaDescrição
GET/v1/exams/:id/capabilitiesIndica quais ações clínicas o ator pode executar no exame
GET/v1/exams/:id/critical-findingLê o estado atual da flag de achado crítico
PUT/v1/exams/:id/critical-findingMarca o exame como achado crítico
DELETE/v1/exams/:id/critical-findingDesmarca o achado crítico
GET/v1/exams/:id/technical-suspicionLê o estado atual da flag de suspeita técnica
PUT/v1/exams/:id/technical-suspicionMarca o exame como suspeita técnica
DELETE/v1/exams/:id/technical-suspicionDesmarca a suspeita técnica

Versão: v1

Swagger: tag Diagnosis — Exam clinical flags · Rota (Dev): http://localhost:3000/v1/exams/{id}/critical-finding

Lógica de decisão das sete rotas (achado crítico e suspeita técnica seguem o mesmo desenho):

Permissões​

RotaGuardsPermissão / escopo
GET /exams/:id/capabilitiesJwtAuthenticationGuard, AuthorizationGuardexam:read, RLS pelo id
GET /exams/:id/critical-findingidemexam:read, RLS pelo id
PUT/DELETE /exams/:id/critical-findingidemexam:flag-critical-finding, RLS pelo id, checado de novo na camada de serviço
GET /exams/:id/technical-suspicionidemexam:read, RLS pelo id
PUT/DELETE /exams/:id/technical-suspicionidemexam:flag-technical-suspicion, RLS pelo id, checado de novo na camada de serviço

Um usuário sem acesso à unidade do exame recebe 404, e um usuário com acesso ao exame mas sem a permissão de flag recebe 403 — os dois comportamentos são confirmados pelo teste de ponta a ponta diagnosis-exam-clinical-flags.e2e.spec.ts (um ator só com exam:read recebe 403 ao tentar PUT; um ator de outra unidade recebe 404).

Divergência confirmada no código. A rota de descoberta GET /exams/:id/capabilities calcula canFlagTechnicalSuspicion checando a permissão exam:mark-clinical (DiagnosisExamAccessPolicy.canFlagTechnicalSuspicion), mas a rota que de fato altera a flag (PUT/DELETE /exams/:id/technical-suspicion) exige exam:flag-technical-suspicion (DiagnosisExamAccessPolicy.canFlagTechnicalSuspicionInUnit, chamada dentro do serviço). São permissões diferentes. Na prática, isso pode fazer capabilities responder canFlagTechnicalSuspicion: false para quem tem exam:flag-technical-suspicion mas não exam:mark-clinical (ou o inverso). exam:mark-clinical é a permissão de uma funcionalidade distinta (GET/PUT /exams/:id/clinical-markings, fora do escopo deste documento). Trate a resposta de capabilities para canFlagTechnicalSuspicion como não confiável até esta divergência ser corrigida ou explicada pelo time de Diagnóstico. A confirmar — responsável: time de Diagnóstico; data: 24/09/2026.

Headers​

HeaderObrigatórioDescrição
AuthorizationSimBearer <access_token>
Content-TypeSim (em PUT)application/json

Path parameters​

NomeTipoObrigatórioDescrição
iduuidSimIdentificador do exame

Query parameters​

Nenhum.

Body​

PUT /exams/:id/critical-finding ou /technical-suspicion — SetDiagnosisCriticalFindingRequest / SetDiagnosisTechnicalSuspicionRequest:

json
{ "reason": "Achado compatível com pneumotórax hipertensivo, comunicado ao plantão." }
CampoTipoObrigatórioValidação
reasonstringNão@MaxLength(500) — não confunda com o texto de um comentário; fica só na metadata do evento de auditoria, não vira um registro em diagnosis_exam_comments

GET, DELETE e GET /capabilities não recebem corpo. Um DELETE com corpo é ignorado (a rota não declara @Body()).

Response​

200 — DiagnosisExamClinicalFlagEnvelopeResponse (mesmo formato para as duas flags):

json
{
"data": {
"value": true,
"since": "2026-09-24T12:00:00.000Z",
"by": "0196cf9a-9e32-7d69-a38d-7360192a811f"
}
}

Ao desmarcar (DELETE), a resposta volta a { "value": false, "since": null, "by": null }.

200 — GET /exams/:id/capabilities:

json
{
"data": {
"canAssignTeam": true,
"canFlagCriticalFinding": true,
"canFlagTechnicalSuspicion": false,
"canRevealPatientIdentity": false
}
}

Erros​

Classe de erroerrorCodeStatusQuando ocorre
(guard de autenticação)UNAUTHENTICATED401token ausente, inválido ou expirado
DiagnosisExamNotFoundErrorEXAM_NOT_FOUND404exame não existe ou está fora do escopo do ator (unidade diferente)
ForbiddenActionFORBIDDEN_ACTION403ator tem acesso ao exame mas não tem a permissão específica da flag (exam:flag-critical-finding ou exam:flag-technical-suspicion)
(validação de payload)BAD_REQUEST400reason maior que 500 caracteres

Regras de negócio​

IDRegraComportamento esperado
RN-01Achado crítico e suspeita técnica são independentesmarcar/desmarcar uma não altera a outra (confirmado lendo o serviço: não há chamada cruzada entre changeCriticalFinding e changeTechnicalSuspicion)
RN-02PUT/DELETE são idempotentes por valorrepetir a mesma operação (já marcado → marcar de novo) devolve 200 com o estado atual, sem gerar novo evento de auditoria nem novo registro de "desde quando"
RN-03since/by refletem a última mudança realdesmarcar zera os dois (since: null, by: null); marcar grava o usuário autenticado e o instante do servidor
RN-04reason não é comentárioo motivo informado no PUT só é gravado na metadata do evento de auditoria; não cria linha em diagnosis_exam_comments nem aparece na listagem de comentários do exame
RN-05Leitura do achado crítico é auditada; leitura da suspeita técnica não éconfirmado no controller (criticalFinding() passa por ReadDiagnosisExamAuditService.readCriticalFinding, que grava diagnosis.exam.critical-finding-read; technicalSuspicion() chama o serviço de flags diretamente, sem auditoria de leitura)
RN-06Alterar a flag reprojeta o worklist do exameis_critical_finding/is_technical_suspicion do item de worklist (GET /worklist) são recalculados de forma assíncrona, não nesta resposta

Compliance​

Órgão / normaExigênciaComo a rota atende
LGPDbase legal de tratamento por profissional de saúde; minimizaçãoreason é de preenchimento opcional e limitado a 500 caracteres; a flag em si não expõe dado de paciente
HIPAAtrilha de quem marcou/desmarcou, quando e por quêeventos diagnosis.exam.critical-finding-changed / technical-suspicion-changed carregam before/after, reason e o ator, consultáveis via Audit
ANVISA (indireto)rastreabilidade de uma marcação clínica no prontuáriosince/by preservam quem fez a última mudança; o histórico completo de mudanças fica no log de auditoria (append-only), não apenas o estado atual

Variáveis de ambiente​

Nenhuma variável de ambiente específica destas rotas foi identificada neste levantamento.

Tempo médio de resposta​

A confirmar — responsável: time de Diagnóstico; data: 24/09/2026. Não há medição publicada; não foi executado neste levantamento.

Requisitos não funcionais​

RequisitoDefinição
IdempotênciaSim, por valor — PUT/DELETE repetidos com o mesmo valor-alvo não geram novo evento nem erro
Rate limitNão identificado @Throttle específico nestas rotas neste levantamento
CacheNão
AuditoriaSim, exceto na leitura da suspeita técnica (ver RN-05)

Divergências e lacunas confirmadas​

  • Desenho totalmente diferente do legado. No sistema antigo (Bitrix, card F-003), achado crítico e suspeita técnica eram registrados como um comentário com texto prefixado ("Achado Critico: " / "Motivo da remoção do Achado Crítico: ") que também alterava a flag do exame numa única chamada (POST /exame/achadocritico, POST /exame/suspeitaTecnica). O código atual não tem prefixo de texto, não cria comentário e usa rotas PUT/DELETE dedicadas com um campo reason separado. Trate a especificação legada (BR-CMT-040 a BR-CMT-046) como substituída pelo comportamento atual.
  • Regra de exclusão mútua não existe mais. A regra legada de que marcar achado crítico desliga automaticamente a suspeita técnica (BR-CMT-092) não tem equivalente no código atual — as duas flags são independentes (RN-01). Se o produto ainda espera essa exclusão mútua, é uma lacuna a levar ao time de Diagnóstico, não um comportamento a documentar como existente.
  • Flags de duplicado/original não fazem mais parte desta rota. O legado propagava is_original/is_duplicado junto com o achado crítico (BR-CMT-042); no código atual esses campos existem em diagnosis/exam como parte de uma capacidade separada (marcação de exame duplicado/original), sem relação com critical-finding — fora do escopo deste documento.
  • Divergência de permissão em capabilities — ver o quadro na seção Permissões acima (canFlagTechnicalSuspicion checado com exam:mark-clinical, mas a rota de escrita exige exam:flag-technical-suspicion).

Relacionado​

  • 💬 Comentar exame — recurso de texto livre, independente destas flags
  • 📋 Audit — consultar logs — como ler os eventos diagnosis.exam.critical-finding-* e technical-suspicion-*
  • 📂 Módulo: Comment
  • 🖥️ Tela: A confirmar — responsável: time de frontend; data: 24/09/2026. (fora do escopo deste levantamento, que cobriu apenas o backend)