Módulo Anexos (Attachment) — visão geral
O módulo de anexos gerencia os arquivos vinculados a um exame — pedido médico, exame anterior,
laudo externo, resultado, documento do paciente, termo de consentimento e outros — e a via de
upload para quem não tem login no Portal 2.0. Ele vive em dois pacotes do backend (NestJS), dentro
do domínio diagnosis:
diagnosis/clinical-media— upload, listagem, consulta, reclassificação e exclusão de anexos de um exame por um usuário autenticado do portal. O mesmo pacote também hospeda áudio, comentários e imagens-chave do exame, documentados em outras páginas; esta seção cobre só a faceta de anexo de arquivo.diagnosis/external-attachment-invitation— emissão de um convite de upload de curta duração para que um terceiro sem conta no portal (ex.: paciente, outra clínica) anexe documentos a um exame específico, sem autenticação de usuário.
Escopo deste levantamento. Cobre só o backend do Portal 2.0 atual (branch
integration/with-fixlaudodemm-pacs-portal-main-api). As telas de frontend correspondentes não foram localizadas nem verificadas — verA confirmarem cada página de rota.
Prefixo de rotas e versionamento
Assim como o módulo Authentication, a API usa versionamento
nativo do NestJS por URI (VersioningType.URI, versão padrão 1) na mesma aplicação "main"
(app/main), então toda rota deste módulo é servida sob /v1/... (ex.:
/v1/exams/:examId/attachments). Em desenvolvimento local, o serviço sobe na porta 3000
(MAIN_API_PORT, default 3000) e expõe o Swagger em http://localhost:3000/docs.
Arquitetura
Anexo interno vs. anexo via convite externo
As duas vias escrevem na mesma tabela de anexos (diagnosis_exam_attachments), mas com
origin diferente: INTERNAL_OPERATOR para upload feito por um usuário autenticado do portal, e
EXTERNAL_INVITATION para upload feito por um terceiro através de um convite. A resposta pública
de leitura (DiagnosisExamAttachmentResponse) não expõe esse campo origin — só aparece
internamente e na trilha de auditoria.
O convite externo nunca usa JwtAuthenticationGuard: a consulta e o consumo do convite são
protegidos só por um ExternalAttachmentInvitationCapabilityGuard, que confere apenas o formato
Bearer <token> do header Authorization — a validade real do token (existência, expiração,
consumo) é responsabilidade do service de cada rota, não do guard.
Classificações de anexo
O mesmo enum AttachmentClassification vale para as duas vias (upload interno e convite externo):
OTHERS, PRIOR_EXAM, MEDICAL_REQUEST, EXTERNAL_REPORT, EXAM_RESULTS, PATIENT_DOCUMENT,
CONSENT_FORM, OTHER_ATTACHMENTS. A ordem de exibição na listagem segue uma ordem fixa por
classificação (não a data de upload) — ver a página de Anexos do exame.
Proteção de exame assinado
Um anexo de um exame com status SIGNED ou RESIGNED só pode ser excluído se sua classificação
for EXAM_RESULTS; qualquer outra classificação é recusada com ATTACHMENT_SIGNED_SHIELD (400).
Essa proteção existe só na exclusão — reclassificar ou adicionar um novo anexo a um exame já
assinado não é bloqueado pelo código lido neste levantamento.
Fora do escopo deste levantamento
Um sistema legado equivalente (mm-pacs-portal-api / mm-pacs-public-api, fora deste
levantamento) descrevia recursos adicionais — gestão de anexos duplicados por
anexo_original_id, duplicação de anexos entre exames, conciliação de anexos via integração
Clinux, e geração de PDF de imagens-chave/laudo. Nenhum desses recursos foi encontrado nos
pacotes clinical-media e external-attachment-invitation lidos nesta branch — a coluna
originalAttachmentId ainda existe na entidade, mas nenhum service ou rota deste levantamento a
consome. Antes de assumir que essas capacidades existem no Portal 2.0 atual, confirme com o time de
Diagnosis se elas foram migradas para outro pacote ainda não documentado ou se ficaram para trás
como dívida do legado.
Páginas deste módulo
| Página | Cobre |
|---|---|
| Anexos do exame | POST/GET/PATCH/DELETE /exams/:examId/attachments... — upload, listagem, busca, reclassificação e exclusão por um usuário autenticado |
| Convite de anexo externo | POST /exams/:examId/external-attachment-invitations, GET/POST /external-attachment-invitations/current... — upload por terceiro sem login, via token de curta duração |
:::tip OpenAPI
A documentação interativa (schemas + "Try it out") está disponível em /docs no ambiente onde a
API está rodando (local: http://localhost:3000/docs).
:::