Research: Validação e escopo por CRP
Decision: CRP como filtro redutor
- Chosen:
x-professional-registration-id contém UUID interno; ausente significa “Todos”.
- Rationale: evita CRP textual ambíguo e mantém
ownerUserId como fronteira obrigatória.
- Alternatives: tenant/schema separado (complexidade incompatível); CRP textual (normalização e enumeração).
Decision: paciente como raiz do escopo
- Chosen:
patients.professional_registration_id nullable no rollout; dependentes derivam pelo paciente.
- Rationale: reduz migration transversal e mantém um paciente em exatamente um CRP.
- Alternatives: coluna em todas as tabelas (redundância); associação N:N (fora do escopo atual).
Decision: validação futura resiliente
- Chosen: fila BullMQ
crp-validation, job idempotente e datas/estado no PostgreSQL.
- Rationale: reutiliza Redis/worker existentes; expiração funciona mesmo com fila atrasada.
- Alternatives: cron exclusivo (latência/perda); fila como fonte de verdade (não auditável o suficiente).
Decision: adapter externo
- Chosen: contrato interno tolerante a 0/1/N resultados, timeout e payload desconhecido; chamada real somente em produção.
- Rationale: OpenAPI externo não tipa respostas de sucesso e já retornou 500.
- Alternatives: acoplar payload externo ao domínio (frágil); chamada local real (testes instáveis).
Decision: N bloqueios calculados
- Chosen:
evaluateOperation(action, owner, registration?) retorna allowed e blockers[].
- Rationale: cadastro, CRP e tier são dimensões independentes e podem bloquear simultaneamente.
- Alternatives:
user.status único (perde causas); primeiro erro apenas (UX incompleta).
Decision: tiers iniciais
- Chosen: reconhecer
free e standard; aplicar somente a regra aprovada free=5 nesta feature.
- Rationale: cria extensão sem inventar catálogo comercial.
- Alternatives: hardcode boolean premium; definir benefícios sem decisão de produto.