Skip to main content

Módulo Tenant / Organização — visão geral

O módulo de organização é o dono da hierarquia multi-tenant do Portal 2.0: tenants (organizações/clientes) e as unidades que cada tenant tem, mais quatro capacidades que vivem em cima dessa hierarquia — branding (identidade visual e domínio customizado), configuração tipada com override por nível, módulos (feature flags por tenant/unidade) e PACS (o storage de imagens médicas usado por cada unidade). Ele vive no pacote organization do backend (NestJS), organizado nos submódulos tenant, unit, branding, configuration, module e pacs.

Não existe camada "empresa" (company) neste código. Um rascunho anterior desta doc descrevia uma hierarquia Tenant → Company → Unit; o código atual tem só dois níveis: Tenant → Unit. Se você tiver visto uma versão antiga com "companies", ela não reflete o backend atual.

Prefixo de rotas e versionamento​

Como o restante da API principal, este módulo usa o versionamento nativo do NestJS por URI (VersioningType.URI, versão padrão 1), então toda rota fica sob /v1/.... Não há segmento de tenant no prefixo — os ids são sempre parâmetros explícitos de path (:tenantId, :unitId), o que permite que o mesmo access token atue sobre qualquer tenant/unidade que o ator tenha permissão de acessar.

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.

Hierarquia de domínio​

Arquitetura dos submódulos​

Autorização: dois padrões coexistindo​

Este módulo usa dois mecanismos de autorização diferentes, e vale reconhecê-los para não confundir um pelo outro ao ler o código ou o Swagger:

  1. Guard declarativo genérico (@Authorize({ permissions, scope }) + AuthorizationGuard, compartilhado com o resto do backend) — resolve o escopo (tenant, unit, unit-list, platform-admin, etc.) a partir do path/query da requisição e decide no nível HTTP.
  2. Checagem fina dentro do serviço (OrganizationTenantAdminAuthorizationService para tenant/unit/branding; OrganizationModuleAuthorizationService para configuration/module; OrganizationPacsAuthorizationService para pacs) — quase sempre redundante com o guard, mas é a fonte de verdade real, porque alguns serviços são chamados também fora do HTTP (ex.: API pública interna entre módulos do backend).

Divergências confirmadas entre o que o guard HTTP parece permitir e o que o serviço realmente aceita — documentadas em detalhe nas páginas de cada rota, mas vale destacar aqui porque afeta várias páginas:

  • Em pacs, três rotas (liberar/remover PACS do tenant, registrar unidade num PACS) declaram um guard que aceitaria um gestor de tenant com permission:manage, mas o serviço por trás exige administrador de plataforma de fato.
  • reativar/mover unidade exigem administrador de plataforma de forma estrita (assertCanManageTenants), sem o atalho de permission:manage por tenant que outras rotas de escrita aceitam.
  • Em branding e em partes de tenant/unit, o serviço aceita também quem tem a permissão equivalente no tenant dono do recurso, mesmo sem uma concessão granular no recurso específico (ex.: gerenciar o tenant inteiro dá acesso à branding de qualquer unidade dele).

Configuração e módulos: dois mecanismos irmãos de override​

configuration e module resolvem o mesmo problema de formas propositalmente distintas:

Configuração (configuration)Módulos (module)
O que guardaUm valor tipado (STRING/NUMBER/BOOLEAN/JSON) por chaveUm estado ligado/desligado por chave (14 chaves fixas de feature)
CascataDEFAULT (catálogo) → TENANT → UNIT, primeiro nível com valor explícito venceTENANT → UNIT, override de unidade sempre vence quando existe
HistóricoNão — só o valor atual por nívelSim — cada mudança gera uma linha de controle preservada (soft-delete, nunca apagada)
Escrita restrita porAllowlist de chaves liberadas para escrita (a maior parte do catálogo ainda não migrou)Nada análogo — qualquer uma das 14 chaves pode ser ligada/desligada, mas nem toda chave tem efeito real no resto do sistema (ver "consumer matrix" na página de módulos)
AuditoriaTelemetria de acesso (sucesso/falha), sem gravar o valorEvento de outbox com antes/depois a cada troca

PACS: três camadas​

pacs é o submódulo mais complexo. Três conceitos, hierárquicos:

  1. Platform PACS — catálogo global (não pertence a nenhum tenant) dos storages de imagem médica; espelha um storage que existe de fato num serviço externo (PACS Storage Management).
  2. PACS do tenant ("release") — a liberação de um Platform PACS para um tenant específico, com uma classificação de negócio: papel (MAIN/BACKUP/CUSTOM), se é o default do papel, e (para backup) retenção.
  3. PACS da unidade — o vínculo de uma unidade a um PACS do tenant, que por padrão herda o default do papel e pode ser sobrescrito manualmente para apontar a um PACS de papel CUSTOM.

Ver visão detalhada em PACS do tenant para as regras de classificação e herança, e PACS por unidade para o vínculo em si.

Convenção de erros​

Toda exceção de negócio estende BaseError (ValidationError → sempre 400; BusinessError → statusCode explícito no construtor; AlreadyExistsError → sempre 409; ForbiddenAction → sempre 403) e já carrega seu statusCode e errorCode fixos. O filtro global de exceções só repassa esses valores — não há uma tabela central de mapeamento status↔erro. Cada página de rota abaixo lista as classes de erro reais confirmadas no código, com o status e a condição exata.

Páginas deste módulo​

PáginaCobre
Tenants (perfil e ciclo de vida)GET/PATCH /tenants/:id/profile, GET /tenants, GET /tenants/:id, POST .../inactivate, POST .../reactivate
Unidades (perfil, ciclo de vida e logo)POST/PATCH/GET /units[/:id], DELETE/POST .../inactivate, POST .../reactivate, GET/PUT/DELETE .../logo
Mover unidade entre tenantsPOST .../units/:id/move e .../move/revert
Branding do tenantGET/PUT/DELETE /tenants/:id/branding/*, domínio customizado
Branding da unidadeGET/PUT/DELETE /units/:id/branding/*
Resolução de domínio customizado (interno)POST /internal/v1/organization/custom-domains/resolve
Configuração (tenant e unidade)GET/PUT/DELETE .../configurations/*
Módulos (feature flags por tenant/unidade)GET/PUT/DELETE .../modules/*, histórico de controle
PACS — Catálogo global (plataforma)POST/GET/PUT/DELETE /pacs[/:id]
PACS — Liberação e classificação do tenantPOST/PUT/GET/DELETE /tenants/:id/pacs/*, apply-to-inherited
PACS — Vínculo da unidadeGET/POST /tenants/:id/units/:id/pacs/*, move, override, retry

:::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). :::