Política de SLA por prioridade e modalidade — API
Define o prazo de laudo (em minutos) por prioridade de exame e, opcionalmente, por modalidade, com uma agenda semanal de janelas ativas. É a política base sobre a qual o cap de protocolo clínico pode atuar depois.
Funcionamento
- Autentica (
JwtAuthenticationGuard) e autoriza (AuthorizationGuard) a permissãosla:read(leitura) ousla:write/sla:delete(escrita) no escopo dotenantId/unitIddo path. - Confirma que o tenant está ativo (
GET/PUTde tenant) ou que a unidade está ativa e pertence a um tenant ativo (GET/PUT/DELETEde unidade) — resolvido pelo diretório de organização. Não encontrado/inativo →404. - Leitura (
GET): monta a política efetiva — para cada uma das 6 prioridades × (nenhuma modalidade + 14 modalidades), resolve a primeira regra que casar na cascata unidade → tenant → padrão do sistema (ver Escopos e herança na visão geral) e devolve também os overrides próprios do escopo consultado. - Escrita (
PUT): valida o corpo (ver Body), confere a versão esperada (e, para unidade, a versão esperada do tenant herdado), substitui toda a lista de overrides do escopo de uma vez (não é um merge) e audita a mudança. Devolve a política efetiva recalculada. - Restaurar uma regra (
DELETE .../rules/:priority): só existe para unidade. Remove o override exato (prioridade + modalidade, se informada) e a unidade volta a herdar do tenant/sistema para aquela combinação. Se esse override exato não existir,404.
Endpoints
| Método | Rota | Descrição |
|---|---|---|
| GET | /v1/tenants/:tenantId/sla-policy | Lê a política efetiva do tenant (overrides do tenant + padrão do sistema) |
| PUT | /v1/tenants/:tenantId/sla-policy | Substitui todos os overrides de SLA do tenant |
| GET | /v1/units/:unitId/sla-policy | Lê a política efetiva da unidade (overrides da unidade + do tenant herdado + padrão do sistema) |
| PUT | /v1/units/:unitId/sla-policy | Substitui todos os overrides de SLA da unidade |
| DELETE | /v1/units/:unitId/sla-policy/rules/:priority | Restaura uma regra exata da unidade para o valor herdado |
Versão: v1
Swagger: Diagnosis — SLA policy · Rota (Dev): http://localhost:3000/v1/tenants/:tenantId/sla-policy
Lógica de decisão (autenticação, autorização, existência do escopo, validação e versão → desfechos):
Permissões
| Rota | Guards | Permissão exigida | Escopo |
|---|---|---|---|
GET /tenants/:tenantId/sla-policy | JwtAuthenticationGuard, AuthorizationGuard | sla:read | tenant (path tenantId) |
PUT /tenants/:tenantId/sla-policy | idem | sla:write | tenant (path tenantId) |
GET /units/:unitId/sla-policy | idem | sla:read | unit (path unitId) |
PUT /units/:unitId/sla-policy | idem | sla:write | unit (path unitId) |
DELETE /units/:unitId/sla-policy/rules/:priority | idem | sla:delete | unit (path unitId) |
Sem token → 401. Sem a permissão no escopo do path → 403. Não há rota de restauração de regra
para tenant — o DELETE de regra exata só existe no escopo de unidade.
Headers
| Header | Obrigatório | Descrição |
|---|---|---|
Authorization | Sim | Bearer <token> |
Path parameters
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
tenantId | uuid | Sim (rotas de tenant) | ParseUUIDPipe — formato inválido → 400 |
unitId | uuid | Sim (rotas de unidade) | ParseUUIDPipe — formato inválido → 400 |
priority | enum ExamPriority | Sim (DELETE .../rules/:priority) | ParseEnumPipe — valor fora do enum → 400 |
Query parameters
DELETE /units/:unitId/sla-policy/rules/:priority:
| Nome | Tipo | Obrigatório | Default | Descrição |
|---|---|---|---|---|
expectedVersion | integer ≥ 0 | Sim | — | Versão da política da unidade que o cliente leu por último |
modality | enum ExamModality | Não | null (regra "só prioridade") | Modalidade do override exato a restaurar |
GET não recebe query parameters.
Body
ReplaceDiagnosisSlaPolicyRequest (tenant) / ReplaceDiagnosisUnitSlaPolicyRequest (unidade, estende o de tenant):
json{"expectedVersion": 3,"expectedTenantVersion": 5,"overrides": [{"priority": "EMERGENCY","modality": "CT","slaMinutes": 60,"days": [{ "weekday": 0, "mode": "ALL_DAY", "startTime": null, "endTime": null },{ "weekday": 1, "mode": "WINDOW", "startTime": "08:00", "endTime": "18:00" },{ "weekday": 2, "mode": "WINDOW", "startTime": "08:00", "endTime": "18:00" },{ "weekday": 3, "mode": "WINDOW", "startTime": "08:00", "endTime": "18:00" },{ "weekday": 4, "mode": "WINDOW", "startTime": "08:00", "endTime": "18:00" },{ "weekday": 5, "mode": "INACTIVE", "startTime": null, "endTime": null },{ "weekday": 6, "mode": "INACTIVE", "startTime": null, "endTime": null }]}]}
expectedTenantVersion só existe no corpo das rotas de unidade.
| Campo | Tipo | Obrigatório | Validação |
|---|---|---|---|
expectedVersion | integer | Sim | @IsInt @Min(0); deve ser igual à versão atual do escopo, senão 409 |
expectedTenantVersion | integer | Sim (só unidade) | @IsInt @Min(0); deve ser igual à versão atual do tenant herdado, senão 409 |
overrides | array de regras | Sim | pode ser vazio (remove todos os overrides do escopo) |
overrides[].priority | enum ExamPriority | Sim | ROUTINE, OUTPATIENT, URGENT, EMERGENCY, ON_CALL, INPATIENT |
overrides[].modality | enum ExamModality | null | Não | null = regra vale para todas as modalidades dessa prioridade; senão uma das 14 modalidades do catálogo |
overrides[].slaMinutes | integer | Sim | 1 a 59999 minutos |
overrides[].days | array de 7 dias | Sim | exatamente os 7 weekday (0=domingo…6=sábado) únicos, e ao menos um dia com mode !== INACTIVE |
overrides[].days[].weekday | integer | Sim | 0 a 6 |
overrides[].days[].mode | enum DiagnosisSlaRuleDayMode | Sim | ALL_DAY, WINDOW, INACTIVE |
overrides[].days[].startTime / endTime | string HH:mm | null | Condicional | obrigatórios e startTime < endTime quando mode = WINDOW; devem ser null nos demais modos |
Não pode haver duas entradas em overrides com a mesma combinação priority + modality
(inclusive duas com modality: null para a mesma prioridade) — 409 SLA_RULE_DUPLICATE.
Response
200 — DiagnosisSlaPolicyEnvelopeRestResponse:
json{"data": {"scope": { "type": "UNIT", "id": "b7a1...-uuid" },"configured": true,"version": 4,"tenantVersion": 5,"priorities": ["ROUTINE", "OUTPATIENT", "URGENT", "EMERGENCY", "ON_CALL", "INPATIENT"],"modalities": ["MR", "CT", "CR", "DX", "US", "MG", "OT", "XA", "CP", "NM", "ES", "EEG", "ECG", "BMD"],"overrides": [{ "priority": "EMERGENCY", "modality": "CT", "slaMinutes": 60, "days": ["..."] }],"effectiveRules": [{"priority": "EMERGENCY","modality": "CT","slaMinutes": 60,"days": ["..."],"source": "UNIT","sourceRuleModality": "CT","hasOwnOverride": true}]}}
effectiveRules traz uma entrada por prioridade × (nenhuma modalidade + cada uma das 14
modalidades) — sempre a grade completa, já resolvida. tenantVersion é null quando a resposta é
de uma rota de tenant (não existe uma versão "acima" dele).
| Campo | Tipo | Descrição |
|---|---|---|
scope.type / scope.id | enum / uuid | Escopo consultado (TENANT ou UNIT) e seu id |
configured | boolean | true se o escopo tem pelo menos um override próprio |
version | integer | Versão do escopo consultado |
tenantVersion | integer | null | Versão do tenant herdado (só em rotas de unidade) |
overrides | array | Só os overrides próprios do escopo consultado (sem herança) |
effectiveRules[].source | enum DiagnosisSlaRuleSource | SYSTEM, TENANT ou UNIT — de onde veio o valor efetivo |
effectiveRules[].hasOwnOverride | boolean | true se o escopo consultado tem override exato para essa combinação |
effectiveRules[].sourceRuleModality | enum | null | Modalidade da regra que efetivamente casou (pode ser null mesmo pedindo uma modalidade específica, se só existir a regra "geral" daquela prioridade) |
Erros
| Classe de erro | errorCode | Status | Quando ocorre |
|---|---|---|---|
| (validação de payload) | BAD_REQUEST | 400 | corpo, path (uuid) ou query inválidos |
ScopedResourceNotFoundError | — | 404 | tenant/unidade inexistente, inativo ou fora do escopo autorizado |
DiagnosisSlaRuleOverrideNotFoundError | SLA_RULE_OVERRIDE_NOT_FOUND | 404 | DELETE .../rules/:priority sem override exato para restaurar |
DiagnosisSlaPolicyVersionConflictError | SLA_POLICY_VERSION_CONFLICT | 409 | expectedVersion do próprio escopo divergente da versão atual |
DiagnosisSlaTenantVersionConflictError | SLA_TENANT_VERSION_CONFLICT | 409 | (rotas de unidade) expectedTenantVersion divergente da versão atual do tenant |
DiagnosisSlaRuleDuplicateError | SLA_RULE_DUPLICATE | 409 | dois overrides do corpo com a mesma prioridade + modalidade |
DiagnosisSlaRuleWeekInvalidError | SLA_RULE_WEEK_INVALID | 422 | semana incompleta/duplicada, todos os dias inativos, janela sem início/fim válidos, ou prioridade/modalidade fora do catálogo |
DiagnosisSlaRuleDurationInvalidError | SLA_RULE_DURATION_INVALID | 422 | slaMinutes fora de 1..59999 |
Regras de negócio
| ID | Regra | Comportamento esperado |
|---|---|---|
| RN-01 | Resolução em cascata | unidade (específica) → unidade (geral) → tenant (específica) → tenant (geral) → padrão do sistema |
| RN-02 | Regra padrão do sistema é fixa por prioridade, 7 dias ALL_DAY | ver tabela de padrões abaixo; não depende de variável de ambiente |
| RN-03 | PUT substitui a lista inteira de overrides do escopo | não é merge — overrides ausentes no corpo deixam de existir |
| RN-04 | Toda regra cobre exatamente os 7 dias da semana | dias faltando ou repetidos → 422 SLA_RULE_WEEK_INVALID |
| RN-05 | Uma regra não pode ter todos os dias INACTIVE | precisa de ao menos um dia alcançável → senão 422 |
| RN-06 | Janela (WINDOW) exige HH:mm válido com início < fim | fora disso → 422; ALL_DAY/INACTIVE não podem ter horário |
| RN-07 | Duração entre 1 e 59.999 minutos, sempre inteiro | fora disso → 422 SLA_RULE_DURATION_INVALID |
| RN-08 | modality: null cobre a prioridade inteira quando não há regra mais específica | uma prioridade pode ter uma regra geral e regras específicas por modalidade convivendo, sem duplicar |
| RN-09 | Restaurar (DELETE) só existe para unidade | tenant não tem override "acima" para herdar de volta |
| RN-10 | Toda escrita audita antes/depois com ator, IP e versão resultante | eventos diagnosis.sla-policy.tenant-replaced, unit-replaced e unit-rule-restored |
Prazos-padrão do sistema por prioridade (constantes no código, DiagnosisSystemSlaRuleCatalog, sem override de ambiente):
| Prioridade | Prazo padrão |
|---|---|
ROUTINE | 2880 min (48h) |
OUTPATIENT | 1440 min (24h) |
URGENT | 120 min (2h) |
EMERGENCY | 60 min (1h) |
ON_CALL | 120 min (2h) |
INPATIENT | 240 min (4h) |
Esses valores coincidem com os prazos-padrão descritos na especificação de legado (BR-SLA-013).
Compliance
A confirmar — responsável: time de Compliance/Diagnosis; data: 24/09/2026. O card de legado
F-001 registra parecer de compliance (LGPD parcial por auditoria de alteração; HIPAA não aplicável;
ANVISA sim, por exigir trilha imutável e validação de prazos inválidos) sobre a feature de
produto, não sobre este contrato HTTP reescrito. Não foi possível confirmar no código atual se a
trilha de auditoria (diagnosis.sla-policy.*) é tratada como append-only nem se há um processo de
change control formal sobre esta rota — o que existe e está confirmado é o registro de
antes/depois/ator/IP por escrita (ver Regras de negócio, RN-10).
Variáveis de ambiente
Nenhuma variável de ambiente específica desta política. Os limites (7 dias, 1–59999 minutos, 6 prioridades, 14 modalidades) e os prazos-padrão por prioridade são constantes no código.
Tempo médio de resposta
A confirmar — responsável: time de Diagnosis; data: 24/09/2026. Não há medição publicada; não foi
executado neste levantamento.
Requisitos não funcionais
| Requisito | Definição |
|---|---|
| Idempotência | PUT é idempotente para o mesmo expectedVersion + mesmo corpo (mas a versão muda a cada aplicação bem-sucedida, então repetir a chamada com o mesmo expectedVersion após o primeiro sucesso resulta em 409) |
| Paginação | Não se aplica — effectiveRules sempre traz a grade completa (6 prioridades × 15 combinações de modalidade) |
| Rate limit | Não confirmado neste levantamento — não há decorator de throttling neste controller |
| Cache | Não |
| Auditoria | Sim — ver tabela de eventos na visão geral do módulo |
Relacionado
- 📂 Módulo: SLA
- 🔗 Próximo passo: Cap de SLA por protocolo clínico (AVC/Trauma)