Comentários do exame
O popover Comentários deixa qualquer pessoa autorizada registrar uma anotação de texto livre sobre um exame — um recado para quem for atender o paciente depois, uma justificativa de contato com o solicitante, uma observação para o histórico clínico. Em alguns status do exame, o mesmo popover também oferece um atalho: gravar o comentário e trocar o status do exame numa única ação (Pendente, Reconvocar ou Retornar para laudar).

Para quem é
| Persona | Quem é | O que faz aqui |
|---|---|---|
| Médico / radiologista | Acompanha o exame no dia a dia | Registra observações clínicas, justifica um contato, marca o exame como pendente ou reconvoca o paciente |
| Administrador / gestor da unidade | Opera a unidade | Mesmas ações, mais a exclusão de comentários de qualquer autor |
Perfis sem exam:add-comment (ex.: read_only neste ambiente) | Consulta a worklist | Não vê o ícone de comentário na linha |
Como acessar
O comentário não é uma tela — é um popover ancorado a um ícone, com dois pontos de entrada:
| Onde | Ícone | Rota |
|---|---|---|
| Linha da worklist | Balão de comentário (pi-comment), sempre visível quando exam:add-comment | /exams |
| Grade de ícones do laudário | pi-comments | /exams/:examId/report |
:::info Quem vê o ícone
O ícone só aparece — não fica escondido nem no laudário nem na worklist — quando o exame não está
excluído e o usuário tem exam:add-comment (ou é platform admin):
canCommentExam(exam, user), exam-policy.ts:171-173. Sem a permissão, o comportamento observado
neste ambiente foi o ícone desaparecer completamente da linha (perfil read_only, que tem
exam:read mas não exam:add-comment) — não uma versão desabilitada com tooltip.
:::
Permissões que liberam cada ação
| Ação | Elemento | O que decide | Onde no código |
|---|---|---|---|
| Ver/abrir o popover | Ícone de balão / pi-comments | exam:add-comment em qualquer escopo do IAM, ou platform admin | exam-policy.ts:171-173, exam-user-context.factory.ts:42 |
| Listar comentários existentes | Corpo do popover, ao abrir (onShow()) | Nenhuma checagem própria no front — a query roda sempre que o popover abre; o backend aplica exam:list-comment com escopo RLS | exam-comments.component.ts:209-211 (front) · Comentar exame — API (back) |
| Salvar um novo comentário | Botão Salvar | Habilita só com texto não vazio (hasText()); a permissão de escrita é checada pelo backend | exam-comments.component.ts:221-232 |
| Apagar um comentário | Ícone de lixeira ao lado do comentário | Só aparece para o autor do próprio comentário (comment.userId === currentUserId()) — o front não verifica exam:delete-comment; o backend é quem de fato exige "autor ou platform admin" | exam-comments.component.ts:170-173; back: Comentar exame — API |
| Marcar Pendente / Reconvocar | Botões condicionais no rodapé | Só aparecem quando o status do exame está em {Novo, Laudando, Digitado, Digitado I.A.} (RN-C4) e há texto digitado | exam-comments.component.ts:38-44,148-151 |
| Retornar para laudar | Botão condicional no rodapé | Só aparece em exame Pendente com pelo menos um comentário já existente, ou em exame Reconvocado | exam-comments.component.ts:153-158 |
Passo a passo
1. Abrir o popover
Clique no ícone de balão de comentário na linha do exame (worklist) ou no ícone de comentários da grade do laudário.
![]()
2. Escrever o comentário
O popover mostra os comentários existentes (mais recentes primeiro, com nome/foto do autor e
"há quanto tempo") e um campo de texto no rodapé, limitado a 512 caracteres
(EXAM_COMMENT_MAX_LENGTH, exam-comment.ts:19, aplicado com [maxlength] no HTML e
Validators.maxLength no formulário). Sem nenhum comentário ainda, a lista mostra "Nenhum
comentário.".

Pressionar Enter (sem Shift) salva e fecha o popover; Shift+Enter quebra a linha sem
enviar (onEnter, exam-comments.component.ts:214-218).
3. Salvar
Com o campo preenchido, o botão Salvar habilita. Ao confirmar, o comentário é gravado com o autor sendo sempre o usuário autenticado — o cliente não escolhe o autor (mesma regra do backend, RN-01 de Comentar exame — API).

:::caution Falha ao salvar — print abaixo é do ambiente desatualizado; erro mudou depois do fix
O print abaixo (HTTP 400 / "The GraphQL operation is invalid.") veio de um build antigo do
ambiente de teste — confirmado depois como bug de bundle desatualizado, já resolvido (ver a nota
completa em Comentários — visão geral). Repetindo o teste já com o ambiente
corrigido (perfil administrator), o erro de schema não ocorre mais, mas salvar ainda falha por um
motivo diferente: a mutation responde 200 com um erro GraphQL UPSTREAM_UNAVAILABLE ("A required
service is temporarily unavailable."). Ou seja, salvar um comentário continua não funcionando neste
ambiente, mas por uma causa nova e distinta da retratada no print. Isso impediu capturar a tela com
um comentário efetivamente salvo e listado.
:::

Estados da tela
| Estado | Quando aparece | |
|---|---|---|
| Vazio | Exame sem nenhum comentário ativo | ![]() |
| Preenchido, pronto para salvar | Texto digitado, botões habilitados | ![]() |
| Erro ao salvar | Falha na chamada ao servidor (ver caixa acima) | ![]() |
| Ícone ausente | Usuário sem exam:add-comment (ex.: read_only) |
Regras de negócio
| ID | Regra | O que a tela faz / impede |
|---|---|---|
| RN-C1 | Ícone só aparece para quem pode comentar e em exame não excluído | canCommentExam; sem a permissão, o ícone some da linha (não fica desabilitado) |
| RN-C2 | Comentário limitado a 512 caracteres, texto em branco não conta como preenchido | Validators.maxLength(512) + hasText() (trim) habilitam/desabilitam os botões |
| RN-C3 | Exame assinado bloqueia a troca de status combinada com o comentário | Antes de aplicar Pendente/Reconvocar/Retornar, o componente busca o detalhe do exame no servidor; se já está concluído, cancela a cadeia e mostra o aviso EXAM.COMMENTS.ASSINADO_BLOQUEADO — o comentário isolado (botão Salvar) não passa por essa checagem |
| RN-C4 | Pendente/Reconvocar só aparecem em exame nos status Novo/Laudando/Digitado/Digitado I.A.; Retornar para laudar só em Pendente (com comentário) ou Reconvocado | canFlagPendingOrRecall / canReturnToReport, exam-comments.component.ts:148-158 |
| RN-C5 (divergência assumida) | O legado tinha um catálogo de motivos configurável por empresa (exigir_motivo); o BFF atual não expõe esse catálogo, então Pendente/Reconvocar sempre seguem o caminho direto (comentário + status, sem seleção de motivo) | Documentado como SPEC_DEVIATION no próprio componente (exam-comments.component.ts:74-78) |
| RN-C6 (divergência assumida) | O legado escolhia o status de retorno (Novo ou Laudando) conforme já existir um laudo em rascunho; o BFF não expõe essa consulta, então Retornar para laudar sempre volta para o status Novo | exam-comments.component.ts:80-82,243-245 |
| RN-C7 | Salvar ou apagar um comentário atualiza o contador da linha (badge no ícone) sem esperar o próximo carregamento da worklist | commentAdded (output) → onCommentAdded, incremento otimista em exam-worklist.component.ts:1030-1035 |
| RN-A10 | Só o autor apaga o próprio comentário no front; o backend também aceita platform admin | exam-comments.component.ts:170-173; back: RN-04 de Comentar exame — API |
Rotas e contratos relacionados
O front fala GraphQL com o BFF, não a rota REST descrita como contrato público do backend — o
comentário do próprio serviço é explícito: "a regra do projeto é falar GraphQL com o BFF"
(exam-actions.service.ts:190-199). O BFF traduz essas mutations/queries para as rotas REST
documentadas em Comentar exame — API.
| Operação GraphQL | Equivale à rota REST (back) | Quando é chamada |
|---|---|---|
query ExamComments($examId) | GET /v1/exams/:examId/comments | Toda vez que o popover abre (onShow) |
mutation AddExamComment($examId, $description) | POST /v1/exams/:examId/comments | Botão Salvar, e também no primeiro passo de Pendente/Reconvocar/Retornar |
mutation DeleteExamComment($commentId) | DELETE /v1/exam-comments/:id | Ícone de lixeira no próprio comentário |
Compliance
| Órgão / norma | Exigência | Como a tela atende |
|---|---|---|
| LGPD | minimização; nunca reexibir conteúdo sensível fora de contexto | O campo aceita só texto livre; nenhuma mensagem de erro do front repete o conteúdo digitado |
| HIPAA | trilha de quem escreveu/apagou o quê e quando | Delegada ao backend (diagnosis.exam.comment-added/comment-removed), consultável via Audit |
Relacionado
- ⚙️ API: Comentar exame
- 🩺 Achado crítico
- 📋 Exames — Ações da linha
- 📂 Módulo: Comentários — visão geral