Skip to content

ADR-201: Identity — Organization & Collaborator

Status: Accepted

Contexto

middag-account é multi-tenant desde o início. Clientes são organizações (empresas/instituições), não usuários WordPress individuais. Cada organização precisa de: dados fiscais (CNPJ/EIN), hierarquia (holding→subsidiária), IDs duais de Stripe e HubSpot (BR + GLOBAL), verificação pelo admin, e controle granular de acesso para membros da equipe do cliente. O WooCommerce não oferece nada disso nativamente — trata todos como "customers" individuais.

Decisão

Organization como Raiz Multi-Tenant

Organization é o tenant de nível superior. Todo outro domínio referencia uma org — queries SEMPRE filtram por organization_id. Dados cross-organization NUNCA vazam sem permissão explícita.

Dados da Organization

CampoTipoNotas
NomestringNome comercial
Razão socialstringNome legal (para documentos fiscais)
Tax IDstringCNPJ, EIN, VAT — label e formato configuráveis
EndereçoobjectRua, cidade, estado, CEP, país
stripe_customer_id_brstringCustomer ID na conta Stripe BR
stripe_customer_id_globalstringCustomer ID na conta Stripe GLOBAL
hubspot_company_id_brstringCompany ID no HubSpot BR
hubspot_company_id_globalstringCompany ID no HubSpot GLOBAL
Status de verificaçãoenumpending → verified / rejected
parent_organization_idnullableFK para org pai (hierarquia)
Company contextenummiddag_br / middag_global (roteamento default)

Hierarquia de Organization

Até 3 níveis: holding → subsidiária → filial. Cada nível deve ser entidade faturável (CNPJ/EIN próprio). Configurável por admin. Não recursiva — profundidade máxima fixa.

Verificação (4 estados)

O ciclo de verificação segue 4 estados: pendingunder_reviewverified / rejected. O estado under_review é intermediário entre o envio de documentação pelo cliente e a decisão do admin. Organizações em estado rejected podem reenviar documentação, retornando a under_review.

Verificação automática por Tax ID (ex: CNPJ via API da Receita Federal) é suportada: se validação passa, transiciona diretamente para verified.

Hook middag_organization_verified dispara na verificação (sync HubSpot, email de boas-vindas). Funcionalidades comerciais (compras, aceite de quotes, emissão de NF) requerem status verified.

Detalhes completos do workflow, transições e restrições em REF-201-01 §12.

Collaborator RBAC

Collaborators são membros dentro de uma organização, com acesso controlado por papel (role) e escopos (scopes).

5 Roles (hierarquia estrita)

RoleNívelDescrição
owner1Criador/dono. Acesso implícito a todos os escopos. Imutável — não pode ser excluído nem rebaixado.
admin2Gerencia equipe: convida, remove, altera roles/scopes
member3Acesso conforme escopos atribuídos
guest4Acesso limitado — tipicamente apenas documents
pending5Convite enviado, aguardando aceitação

11 Scopes

ScopeControla Acesso A
organizationDetalhes da org, atualizar perfil
financesFaturas, notas fiscais
ordersHistórico de pedidos
licensesLicenças, ativação, downloads
ticketsService requests (criar, visualizar)
quotesPropostas (visualizar, aceitar)
contractsContratos, termos de SLA
documentsDocumentos compartilhados
downloadsDownloads de produtos
entitlementsEntitlements, environments, services
adminOperações administrativas (admin only)

Extensível via filtro middag_collaborator_scopes.

Convite por Token

Fluxo: Admin envia convite → email com token → collaborator clica → define senha → login. Token tem TTL configurável. Role pending até aceitação.

Imutabilidade do Owner

  • Owner não pode ser excluído
  • Owner não pode ter role alterado
  • Owner tem acesso implícito a todos os scopes (scopes ignorados)
  • Transferência de ownership: operação administrativa especial

Limite de Collaborators com Scope tickets

Default: 5 collaborators com scope tickets por organization. Configurável via POLICY. Reflete termos de uso: "5 colaboradores por conta de suporte."

Responsabilidades do OrganizationService em REF-201-01.

Middleware Enforcement

Requisições à API REST são validadas em camadas: JWT → Organization → Role → Scope. Cada rota declara os scopes necessários; rotas sem declaração são bloqueadas (fail-closed). O header X-Middag-Company (middag_br / middag_global) funciona como filtro de dados, não como scope.

Detalhes completos em REF-201-01 §11.

Consequências

Positivas:

  • Multi-tenancy real desde o início — não retrofit
  • Clientes são organizações, não usuários WP — modelo B2B correto
  • Dual Stripe/HubSpot IDs permitem operação dual-entity sem gambiarras
  • RBAC granular (5 roles × 9 scopes) cobre cenários de equipe real

Negativas:

  • Complexidade de manter isolamento multi-tenant em todas as queries
  • Hierarquia de org até 3 níveis adiciona complexidade de consulta
  • Owner imutável requer fluxo especial de transferência

Referências

  • REF-201-01 — RBAC Roles & Scopes (matriz completa)
  • ADR-101 — Product Vision (organization-first como diferencial)
  • ADR-202 — Entitlement (pertence a Organization)
  • ../reference/personas.md — Personas §2-4 (Admin, Cliente, Colaborador)