Pular para o conteúdo principal

Desenho Tecnico - RBAC Multi-Tenant por White Label

Status: implementado no código atual (white_label_permissao, Política B, backend_permission_user_can). ADR: adr/0002-rbac-multi-tenant.md. Alguns endpoints legado ainda não passam por backend_permission_require() — ver permissoes-matriz-endpoints.md.

Objetivo

Implementar controle de permissao em 2 niveis:

  1. Limite de delegacao do White Label (WL): define o que o WL pode distribuir.
  2. Permissoes do usuario do WL: definem o acesso final do usuario.

Regra central:

  • Um usuario do WL so pode usar uma permissao se:
    • a permissao estiver atribuida ao usuario, e
    • a permissao estiver autorizada no escopo daquele WL.

Problema atual

  • O catalogo de permissoes e global.
  • Admin de WL pode enxergar/atribuir permissoes que deveriam ser exclusivas de admin global.
  • Filtro por white_label_id existe em partes do sistema, mas nao como regra central de autorizacao.

Modelo de dados proposto

1) Catalogo global (ja existe)

  • permissoes(id, chave, descricao, ...)
  • permissao_usuario(user_id, permissao_id, ...) (ou equivalente atual)

2) Tabela nova: escopo de delegacao por WL

white_label_permission_scope

  • id (PK)
  • white_label_id (FK -> white_labels.id)
  • permissao_id (FK -> permissoes.id)
  • allowed (TINYINT(1) default 1)
  • source (ENUM('template','manual')) - opcional
  • created_by (INT) - usuario que alterou
  • created_at
  • updated_at
  • UNIQUE (white_label_id, permissao_id)

Finalidade:

  • controla quais permissoes um WL pode distribuir internamente.

3) Tabela opcional: template de permissao por tipo de WL

permission_templates

  • id (PK)
  • template_key (VARCHAR) ex: wl_mdr_default, wl_custo_efetivo_default
  • permissao_id
  • allowed
  • UNIQUE (template_key, permissao_id)

Finalidade:

  • bootstrap automatico no cadastro do WL por tipo_precificacao.

Classificacao de permissoes

Adicionar metadados no catalogo (permissoes) para facilitar governanca:

  • scope_level (ENUM('GLOBAL','TENANT'))
  • delegavel_para_wl (TINYINT(1))
  • modulo (VARCHAR) ex: comissoes, usuarios, terminais

Regra:

  • GLOBAL + delegavel_para_wl = 0: nunca aparece para admin de WL.
  • TENANT + delegavel_para_wl = 1: pode entrar no escopo do WL.

Fluxo funcional proposto

A) Cadastro/edicao de White Label

  1. Admin global seleciona tipo de WL (tipo_precificacao).
  2. Sistema aplica template base de permissoes.
  3. Admin global ajusta checkbox de modulos/permissoes.
  4. Sistema salva em white_label_permission_scope.

B) Edicao de permissao de usuario interno do WL

  1. Admin WL abre tela de permissoes de usuario.
  2. Backend lista apenas permissoes permitidas no white_label_permission_scope.
  3. Admin WL atribui/remocao.
  4. Backend valida novamente (server-side) antes de persistir.

C) Verificacao em runtime (can)

Para usuario de WL:

  1. verifica se usuario tem permissao em permissao_usuario;
  2. verifica se permissao esta allowed em white_label_permission_scope;
  3. so libera acesso se ambas as validacoes forem verdadeiras.

Para admin global:

  • pode usar regra global atual (sem restricao por WL), conforme perfil.

Regras de negocio obrigatorias

  • Admin WL nunca pode atribuir permissao fora do escopo do WL.
  • Frontend apenas ajuda UX; validacao real e sempre backend.
  • Alteracao de escopo do WL deve ser auditada (quem alterou, quando, antes/depois).
  • Ao remover permissao do escopo WL, existem 2 estrategias:
    • hard enforcement imediato (usuario perde acesso na hora, mesmo se ainda atribuido);
    • sync de limpeza (remove em lote de usuarios daquele WL).

Recomendacao inicial:

  • aplicar hard enforcement imediato no can(...) e sincronizacao assíncrona para limpeza.

API/servico de autorizacao (desenho)

Criar servico unico, ex: config/permissoes/authorization_service.php

Funcoes sugeridas:

  • getTenantScopePermissions($whiteLabelId): array
  • canAssignPermission($actorUserId, $targetUserId, $permissionKey): bool
  • can($userId, $permissionKey, $resourceWhiteLabelId = null): bool
  • listAssignablePermissionsForTenantAdmin($actorUserId): array

Vantagem:

  • para de repetir regra de escopo nos endpoints.

SQL base (exemplo)

CREATE TABLE white_label_permission_scope (
id INT AUTO_INCREMENT PRIMARY KEY,
white_label_id INT NOT NULL,
permissao_id INT NOT NULL,
allowed TINYINT(1) NOT NULL DEFAULT 1,
source ENUM('template','manual') DEFAULT 'manual',
created_by INT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uk_wl_perm (white_label_id, permissao_id),
KEY idx_wl (white_label_id),
KEY idx_perm (permissao_id),
CONSTRAINT fk_wl_scope_wl FOREIGN KEY (white_label_id) REFERENCES white_labels(id) ON DELETE CASCADE,
CONSTRAINT fk_wl_scope_perm FOREIGN KEY (permissao_id) REFERENCES permissoes(id) ON DELETE CASCADE
);

Plano de migracao (sem quebrar producao)

Fase 1 - Fundacao (baixo risco)

  • criar white_label_permission_scope;
  • popular escopo inicial por WL com base nas permissoes ja existentes;
  • criar endpoint de listagem de permissoes filtradas por WL.

Entrega:

  • tela de usuario WL ja deixa de mostrar permissoes globais.

Fase 2 - Enforcement real

  • atualizar can(...) para considerar escopo WL;
  • bloquear backend de atribuicao fora do escopo;
  • adicionar logs de tentativa de elevacao de privilegio.

Entrega:

  • seguranca real, mesmo contra chamada direta de API.

Fase 3 - Governanca e UX

  • templates por tipo_precificacao;
  • tela de cadastro/edicao de WL com checkboxes por modulo;
  • job de sincronizacao opcional para limpar permissoes legadas.

Entrega:

  • operacao escalavel para novos WLs com onboarding padronizado.

Impacto em telas existentes

  • dashboard/white_label/cadastrar.php:
    • incluir bloco de escopo de permissoes por modulo + preset por tipo de precificacao.
  • dashboard/permissoes/permissoes_usuarios.php:
    • listar apenas permissoes delegaveis do WL do usuario logado.
  • endpoints de permissao em config/permissoes/*:
    • validar escopo do WL em todas operacoes de grant/revoke/list.

Checklist de aceite

  • Admin WL nao enxerga permissao global.
  • Admin WL nao consegue atribuir permissao fora do escopo (UI + API).
  • Usuario WL perde acesso imediatamente quando permissao sai do escopo do WL.
  • Admin global continua com governanca total.
  • Logs de auditoria registram alteracoes de escopo e tentativas bloqueadas.

Resumo executivo

Sim, sua ideia e totalmente viavel e e o desenho correto para evoluir o sistema para multi-tenant maduro.
O ponto-chave e instituir formalmente o conceito de delegacao de permissao por White Label e aplicar essa validacao no backend como regra de autorizacao central.