Módulo Exame — visão geral
O módulo de Exame é o núcleo do domínio de diagnóstico do Portal 2.0: cria e mantém o registro do
exame (ingestão assíncrona, edição de dados do paciente/pedido, exclusão e restauração), controla o
ciclo de vida clínico (status, prioridade, modalidade, SLA, unidade), atribui a equipe responsável
(radiologista, digitador, residente, médico solicitante), relaciona exames entre si (prévios,
complementares, conjugados, duplicados) e compartilha exames entre unidades. Ele vive em quatro
pacotes do backend (NestJS), todos dentro de diagnosis/: exam (o agregado central), workflow-policy
(as regras de negócio configuráveis que o exame consulta), status-reason (o catálogo de motivos de
mudança de status) e medical-catalog (especialidades, subespecialidades e modalidades usadas para
classificar o exame).
Fonte de verdade. Este levantamento foi feito inteiramente a partir do código atual (branch
integration/with-fixlaudo) e dos testes em__test__. Não existe rascunho anterior deste módulo. Cartões de negócio do Bitrix (funil 562, features F-001 a F-014 e F-S01/F-S04) descrevem o sistema legado (mm-pacs-portal-api, rotasroutes/exame.js,routes/marcacaoClinica.js,routes/motivo.js,routes/especialidade.js, tabelastb_exame*) e foram usados só como pista de intenção de produto — o campo que mapearia "status vs. código real" (ufCrm110_1782750927) está vazio em todos os 13 cartões consultados, então nenhuma regra de negócio foi copiada do Bitrix sem confirmação direta no código NestJS atual. Divergências notáveis em relação ao legado (confirmadas no código, não presumidas): não existe mais uma máquina de estados fechada para o status do exame — qualquer status do catálogo pode suceder qualquer outro, desde que a permissão e o motivo (quando exigido pela política da unidade) sejam satisfeitos; e o achado crítico/suspeita técnica não é mais um comentário com prefixo fixo (ver Achado crítico e suspeita técnica, no módulo Comment).
Prefixo de rotas e versionamento
Como no restante da API, o versionamento é nativo do NestJS por URI (VersioningType.URI, versão
padrão 1): toda rota deste módulo é servida sob /v1/... (ex.: /v1/exams/:id,
/v1/exam-ingestions, /v1/units/:unitId/status-reasons, /v1/medical-catalog/specialties). 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
Módulos irmãos — fora do escopo desta documentação
Este levantamento cobre apenas exam, workflow-policy, status-reason e medical-catalog. Dois
pacotes vizinhos do domínio de diagnóstico têm documentação própria e não são repetidos aqui:
- Busca, contagem, exportação e favoritos da worklist (
diagnosis/worklist) — ver módulo Busca. A busca lê o mesmo read model que este módulo projeta a cada mudança de exame, mas a lógica de filtro/paginação/favoritos pertence àquele módulo. - SLA (
diagnosis/sla-policy) — ver módulo SLA. O prazo de laudo por prioridade/modalidade, o cap por protocolo clínico (AVC/Trauma) e o motor de cálculo do prazo são documentados lá; este módulo apenas consomeResolveDiagnosisSlaDeadlineServicesempre que cria, muda prioridade/modalidade/unidade, duplica ou restaura um exame. - Comentário e achado crítico/suspeita técnica (
diagnosis/clinical-mediapara comentário; flags dentro do própriodiagnosis/exam) — ver módulo Comentários e achado crítico. As rotasGET /exams/:id/capabilitieseGET/PUT/DELETE /exams/:id/critical-finding/technical-suspicionjá estão documentadas lá em detalhe e não são repetidas neste levantamento.
O ciclo de vida do exame
O status do exame (ExamStatus) tem doze valores: NEW, TO_PREPARE, PENDING, REPORTING,
TYPING, DRAFTED, DRAFTED_AI, PRE_REPORTED, SIGNED, RESIGNED, REEVALUATE, RECALL. Cada
um espelha um ReportStatus do domínio de laudo (documentado à parte, no domínio de Laudo/Exam
Report) — por exemplo SIGNED ⇄ SIGNED, REEVALUATE ⇄ SECOND_OPINION, DRAFTED ⇄ TYPED. Ver
o mapa completo em Transição de status.
Não existe mais uma máquina de estados fechada. Diferente do que um desenho de fluxo sugeriria, o código atual (
ChangeDiagnosisExamAttributesService.changeStatus) permite qualquer transição entre dois status do catálogo, exceto quando o exame já estáSIGNEDouRESIGNED(protegido contra mudança manual —EXAME_JA_ASSINADO), contanto que a política de motivo da unidade seja respeitada. O único outro travamento é o gate de preparação: sair deTO_PREPAREouPENDINGexige que os campos obrigatórios da política de preparo da unidade estejam preenchidos.
Onde este módulo se conecta com workflow-policy, status-reason e medical-catalog
workflow-policyresolve, por unidade, a política efetiva (unidade → tenant → default) que controla: quais prioridades a unidade aceita e qual é a prioridade default; quais modalidades entram automaticamente em preparação; se duplicar um exame assinado o joga de volta em preparação e se renova o SLA; se a mudança manual de status exige motivo; se a data de preparo é atualizada ao sair deTO_PREPARE; e (por unidade) qual médico é automaticamente associado a todo exame novo. Tem ainda uma política de preparo por unidade (preparation-policy) com os campos exigidos para sair deTO_PREPARE/PENDING, e preferências de tela/impressão por unidade (exam-preferences) usadas pelo frontend. Ver Política de fluxo de trabalho, Política de preparo e Preferências de exame da unidade.status-reasoné o catálogo de motivos de mudança de status, dono por unidade e compartilhável com outras unidades do mesmo tenant.ChangeDiagnosisExamAttributesServiceconsulta esse catálogo sempre que a política da unidade exige motivo para a transição. Ver Motivos de status por unidade.medical-catalogfornece o vocabulário clínico (especialidade → subespecialidade → apelido DICOM) usado para classificar automaticamente o exame pela descrição do estudo DICOM, na ingestão e sempre que a modalidade ou a descrição do estudo mudam. Ver Opções do catálogo médico, Especialidades, Subespecialidades e Catálogo por unidade e modalidade.
Convenção de erros
Toda exceção de negócio estende BaseError/DomainError/BusinessError/ValidationError e já
carrega seu statusCode e errorCode fixos no construtor. O filtro global (AllExceptionsFilter)
apenas repassa esses valores. As páginas abaixo listam os erros confirmados por rota.
Rate limiting
Nenhum controller deste módulo declara um guard de rate limit próprio. O RateLimitGuard global
(RateLimitModule.forRoot, via APP_GUARD) se aplica a todas as rotas daqui: 100 requisições por
60000 ms por padrão, configurável por RATE_LIMIT_LIMIT/RATE_LIMIT_TTL_MS/RATE_LIMIT_ENABLED.
Páginas deste módulo
Exame — ciclo de vida e atributos
| Página | Cobre |
|---|---|
| Ciclo de vida do exame | GET/PATCH /exams/:id, PUT/DELETE /exams/:id/release, PUT/DELETE /exams/:id/exclusion |
| Ingestão de exame | POST /exam-ingestions, GET /exam-ingestions/:trackingId e o consumidor de fila |
| Transição de status | PATCH /exams/:id/status |
| Motivos de status por unidade | GET/POST/PATCH/DELETE /units/:unitId/status-reasons(/:reasonId), associações entre unidades |
| Prioridade, modalidade e SLA | PATCH /exams/:id/priority, /modality, /sla |
| Mudança de unidade | PATCH /exams/:id/unit, GET /exams/:id/unit-history |
Equipe e relacionamentos entre exames
| Página | Cobre |
|---|---|
| Atribuição de equipe | GET/PUT/DELETE /exams/:id/assignments(/:responsibility), GET /team-change-reasons |
| Relacionamentos do exame | prévios, complementares e conjugados (/exams/:id/prior-exams, /complements, /conjugates), GET /exams/:id/prior-exam-candidates |
| Duplicação de exame | POST/GET/DELETE /exams/:id/duplicates(/relation) |
| Compartilhamento entre unidades | GET/POST/DELETE /exams/:id/shares(/:unitId) |
Metadados, registros e utilitários do exame
| Página | Cobre |
|---|---|
| Caso interessante | GET/PUT/DELETE /exams/:id/interesting-case |
| Registros técnicos e impressão | GET /exams/:id/logs/integration, /logs/messaging, POST /exams/:id/printouts |
| Replicação de código de paciente | POST /exams/patient-code-replications |
Catálogo médico
| Página | Cobre |
|---|---|
| Opções do catálogo médico | GET /medical-catalog/clinical-markings, /form-types |
| Especialidades | GET/POST/PATCH/DELETE /medical-catalog/specialties(/:id), vínculo com unidade |
| Subespecialidades | GET/POST/PATCH/DELETE /medical-catalog/subspecialties(/:id), apelidos DICOM |
| Catálogo por unidade e modalidade | GET /medical-catalog/units/:unitId/modalities/:modality/subspecialties |
Políticas de workflow
| Página | Cobre |
|---|---|
| Política de fluxo de trabalho | GET/PUT/DELETE /tenants/:tenantId/diagnosis-workflow-policy, /units/:unitId/diagnosis-workflow-policy |
| Política de preparo | GET/PUT/DELETE /units/:unitId/preparation-policy |
| Preferências de exame da unidade | GET/PATCH /units/:unitId/exam-preferences |
:::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).
:::