Skip to main content

Módulo SLA — visão geral

O módulo de SLA (Service Level Agreement) define o prazo de laudo que cada exame precisa cumprir. Ele guarda a política de prazo por prioridade e modalidade e o cap de protocolo clínico (AVC e Trauma), que aperta esse prazo e pode disparar um achado crítico. Ele vive em package/diagnosis/sla-policy (core/http/persistence), dentro do domínio Diagnosis do backend (mm-pacs-portal-main-api).

Este módulo não calcula sozinho o prazo de um exame específico: ele só guarda e expõe a política. O cálculo do prazo (sla_expiration_date de um exame) é acionado pelo domínio de Exames (criação, edição e reprocessamento de exame) e pelo domínio de Laudo/achado crítico, que chamam os serviços internos deste módulo — ver Motor de cálculo (uso interno) abaixo. A confirmar — responsável: time de Diagnosis/Exames; data: 24/09/2026. A documentação do lado de Exames que aciona esse cálculo ainda não existe neste repositório de docs.

Reescrita do legado​

Este módulo é a reescrita das features de legado F-001 (configurar SLA por prioridade e modalidade), F-002 (calcular o prazo de SLA do exame) e F-003 (cap de SLA por protocolo clínico AVC/Trauma), antes implementadas em mm-pacs-portal-api/routes/empresa.js sobre as tabelas tb_sla e tb_empresa_sla_protocolo. Ao comparar com a especificação de legado (funil Bitrix, cards F-001/F-002/F-003), confirme estas mudanças de contrato no código atual:

  • Hierarquia tenant → unidade. O legado guardava um único SLA "por empresa" (tb_sla vinculada a empresa_id). O código atual tem dois escopos: tenant (DiagnosisSlaScopeType.TENANT) e unidade (DiagnosisSlaScopeType.UNIT), com a unidade herdando do tenant e o tenant herdando de um catálogo de padrões do sistema. Não existe mais um único nível "empresa".
  • Substituição integral virou versionamento otimista. O legado sempre fazia destroy + bulkCreate (BR-SLA-017) e descartava os ids das linhas (BR-SLA-018). O código atual versiona cada política (version, incrementada a cada PUT) e exige expectedVersion (e, para unidade, também expectedTenantVersion) no corpo/query de toda escrita — conflito vira 409, não uma sobrescrita silenciosa.
  • Protocolo: os nomes mudaram de avc/trauma (legado) para o enum DiagnosisSlaProtocol (STROKE, TRAUMA), mas o par continua fixo — sempre os dois, nunca mais nem menos (DiagnosisSlaProtocolPolicyInvalidError, 422).
  • Limite de minutos do protocolo mudou. A especificação de legado (BR-SLA-057) limitava o prazo de protocolo habilitado a no máximo 59 minutos. O código atual (DiagnosisSlaProtocolRule.assertDuration) usa o mesmo limite das regras normais de SLA — 1 a 59.999 minutos — sem o teto de 59. A confirmar — responsável: time de Diagnosis; data: 24/09/2026.: não foi possível confirmar se essa mudança foi intencional (o cap de protocolo existe para ser mais curto que o SLA base, mas o código não impõe isso estruturalmente; quem cadastra o valor precisa saber disso).
  • "Nunca afrouxa" (BR-SLA-037) continua valendo, mas hoje é aplicado pelo serviço interno ApplyDiagnosisSlaProtocolService (ver abaixo), não por uma rota HTTP deste módulo.
  • Os prazos-padrão por prioridade (BR-SLA-013) são os mesmos no código atual — ver tabela na página Política de SLA por prioridade e modalidade.

A pesquisa no card de contexto do Bitrix não trouxe o campo de correlação "status vs código real" preenchido (ufCrm110_1782750927 vazio nos três cards F-001/F-002/F-003) — trate as regras de legado (BR-SLA-*) só como pista de intenção de produto, não como contrato atual; o contrato atual é o descrito nas páginas deste módulo, confirmado no código.

Arquitetura​

Escopos e herança​

Toda política deste módulo é resolvida em cascata, do mais específico para o mais genérico:

  1. Unidade, prioridade + modalidade (override exato da unidade).
  2. Unidade, só prioridade (modality: null na unidade).
  3. Tenant, prioridade + modalidade (override exato do tenant).
  4. Tenant, só prioridade (modality: null no tenant).
  5. Padrão do sistema para a prioridade (constante no código, ver tabela na página de política de prioridade/modalidade).

O mesmo padrão vale para o cap de protocolo, mas sem o eixo de modalidade: unidade (se tiver override) → tenant (se version > 0) → padrão do sistema (as duas regras desabilitadas). O campo source de cada resposta (SYSTEM | TENANT | UNIT) diz de onde veio o valor efetivo.

Versionamento otimista​

Nenhuma escrita substitui a política sem confirmar a versão que o cliente leu por último:

  • Escrita em tenant: exige expectedVersion igual à versão atual do tenant. Diferente → 409 SLA_POLICY_VERSION_CONFLICT.
  • Escrita em unidade: exige expectedVersion da própria unidade e expectedTenantVersion igual à versão atual do tenant (mesmo que a unidade não tenha override próprio, a versão do tenant herdado precisa bater). Tenant divergente → 409 SLA_TENANT_VERSION_CONFLICT; unidade divergente → 409 SLA_POLICY_VERSION_CONFLICT.
  • Toda escrita bem-sucedida incrementa a versão em 1.

Permissões​

Todas as rotas exigem um Bearer token válido (JwtAuthenticationGuard) e a permissão do domínio SLA no escopo do path (AuthorizationGuard + @Authorize):

PermissãoUso
sla:readLer a política efetiva ou o protocolo (tenant ou unidade)
sla:writeSubstituir a política ou o protocolo (tenant ou unidade)
sla:deleteRestaurar (remover) um override — de uma regra ou do protocolo — de volta ao valor herdado

O escopo da permissão é o tenantId ou unitId do próprio path da rota — sem token válido → 401; sem a permissão nesse escopo → 403.

Transação e isolamento por tenant (RLS)​

Toda rota deste controller passa pelo DiagnosisAuthorizationTransactionInterceptor, que abre a escrita/leitura dentro de uma transação com Row-Level Security aplicada para o domínio diagnosis antes de executar o handler. Se o contexto de RLS não puder ser montado, a chamada falha com 403 RLS_TRANSACTION_UNAVAILABLE antes mesmo de chegar à lógica de SLA.

Auditoria​

Toda escrita (replace ou restore, em qualquer escopo) grava um evento de auditoria com ator, IP, snapshot antes/depois e a versão resultante — nunca dados clínicos do paciente:

EventoQuando
diagnosis.sla-policy.tenant-replacedPUT /tenants/:tenantId/sla-policy
diagnosis.sla-policy.unit-replacedPUT /units/:unitId/sla-policy
diagnosis.sla-policy.unit-rule-restoredDELETE /units/:unitId/sla-policy/rules/:priority
diagnosis.sla-policy.tenant-protocol-replacedPUT /tenants/:tenantId/sla-protocol-policy
diagnosis.sla-policy.unit-protocol-replacedPUT /units/:unitId/sla-protocol-policy
diagnosis.sla-policy.unit-protocol-restoredDELETE /units/:unitId/sla-protocol-policy

Motor de cálculo (uso interno)​

ResolveDiagnosisSlaDeadlineService, CalculateDiagnosisSlaDeadlineService e ApplyDiagnosisSlaProtocolService não têm rota HTTP própria neste módulo — são serviços injetados diretamente pelos serviços de Exame, Prontuário clínico e Laudo (confirmado em change-diagnosis-exam-attributes.service.ts, create-diagnosis-exam.service.ts, duplicate-diagnosis-exam.service.ts, change-diagnosis-exam-unit.service.ts, process-diagnosis-exam-ingestion.service.ts, delete-diagnosis-exam.service.ts, maintain-diagnosis-exam-clinical-markings.service.ts e maintain-diagnosis-report.service.ts). Resumo do comportamento confirmado no código:

  • O cálculo do prazo base soma slaMinutes da regra efetiva só dentro das janelas ativas (ALL_DAY conta o dia inteiro; WINDOW só entre startTime e endTime; INACTIVE não conta), avançando semana a semana no fuso configurado em SLA_TIMEZONE (default America/Sao_Paulo) a partir de um instante de referência (referenceAt).
  • O cap de protocolo pega o menor prazo entre os protocolos habilitados e com marcação presente no exame, e só reduz o prazo atual — nunca o aumenta (minimumDeadline sempre escolhe o menor dos dois quando ambos existem).
  • Se uma regra de protocolo com startsCriticalFinding habilitado se aplica e o exame ainda não está marcado como achado crítico, o exame passa a ser marcado — e a operação exige um actorUserId não vazio, senão lança erro interno (UnexpectedError).

Este comportamento é o contrato observável do motor de cálculo, mas não é uma rota — não tem página de referência HTTP própria. A confirmar — responsável: time de Diagnosis/Exames; data: 24/09/2026.: como e quando exatamente o domínio de Exames aciona esse cálculo (criação, edição, reprocessamento) ainda não está documentado neste repositório.

Páginas deste módulo​

PáginaCobre
Política de SLA por prioridade e modalidadeGET/PUT /tenants/:tenantId/sla-policy, GET/PUT /units/:unitId/sla-policy, DELETE /units/:unitId/sla-policy/rules/:priority
Cap de SLA por protocolo clínico (AVC/Trauma)GET/PUT /tenants/:tenantId/sla-protocol-policy, GET/PUT /units/:unitId/sla-protocol-policy, DELETE /units/:unitId/sla-protocol-policy

:::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, tag Diagnosis — SLA policy). :::