813 lines
62 KiB
Markdown
813 lines
62 KiB
Markdown
# Arcádia Tenants — Mapa Completo da Gestão Multi-Tenant
|
|
|
|
> Mapa da arquitetura multi-tenant da Arcádia Suite: hierarquia
|
|
> Master/Parceiro/Cliente, sistema de planos, ativação de módulos,
|
|
> empresas (Matriz/Filiais), comissões de parceiros, controle de acesso,
|
|
> e middleware de isolamento.
|
|
> Atualizado em: Março 2026
|
|
|
|
---
|
|
|
|
## 1. Visão Geral
|
|
|
|
A Arcádia Suite opera em modelo **multi-tenant hierárquico** com três níveis. Cada tenant possui um plano que define quais módulos da plataforma estão habilitados, e pode conter múltiplas empresas (CNPJ) para operações fiscais.
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ HIERARQUIA DE TENANTS │
|
|
│ │
|
|
│ ┌──────────────┐ │
|
|
│ │ MASTER │ ← Operador da plataforma │
|
|
│ │ │ ← Vê tudo, controla tudo │
|
|
│ │ tenantType: │ ← Pode criar parceiros │
|
|
│ │ "master" │ ← Pode excluir tenants │
|
|
│ └──────┬───────┘ │
|
|
│ │ │
|
|
│ ┌────────────┼────────────┐ │
|
|
│ ▼ ▼ ▼ │
|
|
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|
│ │ PARCEIRO A │ │ PARCEIRO B │ │ PARCEIRO C │ │
|
|
│ │ │ │ │ │ │ │
|
|
│ │ tenantType: │ │ Consultorias │ │ Integradores │ │
|
|
│ │ "partner" │ │ Revendas │ │ Franquias │ │
|
|
│ │ │ │ │ │ │ │
|
|
│ │ partnerCode: │ │ comissão: % │ │ plano: │ │
|
|
│ │ "PARC-001" │ │ sobre clientes│ │partner_pro │ │
|
|
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
|
|
│ │ │ │ │
|
|
│ ┌────┴────┐ ┌───┴───┐ ┌───┴───┐ │
|
|
│ ▼ ▼ ▼ ▼ ▼ ▼ │
|
|
│ ┌────────┐┌────────┐┌────────┐┌────────┐┌────────┐┌────────┐ │
|
|
│ │Cliente1││Cliente2││Cliente3││Cliente4││Cliente5││Cliente6│ │
|
|
│ │ ││ ││ ││ ││ ││ │ │
|
|
│ │tenant ││tenant ││tenant ││tenant ││tenant ││tenant │ │
|
|
│ │Type: ││Type: ││Type: ││Type: ││Type: ││Type: │ │
|
|
│ │"client"││"client"││"client"││"client"││"client"││"client"│ │
|
|
│ │ ││ ││ ││ ││ ││ │ │
|
|
│ │parent: ││parent: ││parent: ││parent: ││parent: ││parent: │ │
|
|
│ │Parc.A ││Parc.A ││Parc.B ││Parc.B ││Parc.C ││Parc.C │ │
|
|
│ │ ││ ││ ││ ││ ││ │ │
|
|
│ │Plano: ││Plano: ││Plano: ││Plano: ││Plano: ││Plano: │ │
|
|
│ │starter ││pro ││free ││enterpr.││starter ││pro │ │
|
|
│ └────────┘└────────┘└────────┘└────────┘└────────┘└────────┘ │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### Visibilidade por tipo:
|
|
|
|
| Tipo | Vê | Cria | Exclui |
|
|
|------|-----|------|--------|
|
|
| **Master** | Todos os tenants | Parceiros e Clientes | Qualquer (exceto master) |
|
|
| **Partner** | Seu tenant + seus clientes | Apenas clientes vinculados | Nenhum |
|
|
| **Client** | Apenas seu próprio tenant | Nenhum | Nenhum |
|
|
|
|
---
|
|
|
|
## 2. Banco de Dados — Tabelas de Tenant
|
|
|
|
### 2.1 — tenants (Tabela Principal)
|
|
|
|
```
|
|
┌──────────────────────────────────────────────────────────────────┐
|
|
│ tenants │
|
|
│ Tabela: "tenants" — shared/schema.ts:849 │
|
|
│ │
|
|
│ ┌─────────── Identificação ──────────────────┐ │
|
|
│ │ id serial PK │ │
|
|
│ │ name text NOT NULL │ │
|
|
│ │ slug text UNIQUE │ │
|
|
│ │ email text │ │
|
|
│ │ phone text │ │
|
|
│ │ logoUrl text │ │
|
|
│ └─────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌─────────── Hierarquia ─────────────────────┐ │
|
|
│ │ tenantType "master" | "partner" | │ │
|
|
│ │ "client" │ │
|
|
│ │ parentTenantId integer (self-ref FK) │ │
|
|
│ │ partnerCode text (código único parceiro) │ │
|
|
│ │ commissionRate numeric(5,2) (% comissão) │ │
|
|
│ └─────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌─────────── Plano e Limites ────────────────┐ │
|
|
│ │ plan "free" | "starter" | "pro" │ │
|
|
│ │ | "enterprise" | │ │
|
|
│ │ "partner_starter" | │ │
|
|
│ │ "partner_pro" │ │
|
|
│ │ status "active" | "trial" | │ │
|
|
│ │ "suspended" | "cancelled" │ │
|
|
│ │ maxUsers integer (default 5) │ │
|
|
│ │ maxStorageMb integer (default 1000) │ │
|
|
│ │ features JSONB → TenantFeatures │ ← Módulos │
|
|
│ └─────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌─────────── Billing ────────────────────────┐ │
|
|
│ │ billingEmail text │ │
|
|
│ │ trialEndsAt timestamp │ │
|
|
│ └─────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌─────────── Dados Empresariais ─────────────┐ │
|
|
│ │ cnpj text │ │
|
|
│ │ tradeName text │ │
|
|
│ │ address text │ │
|
|
│ │ city, state text │ │
|
|
│ │ segment text │ │
|
|
│ │ notes, source text │ │
|
|
│ │ commercialContact / commercialPhone │ │
|
|
│ └─────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌─────────── Metadata ───────────────────────┐ │
|
|
│ │ settings text (JSON config) │ │
|
|
│ │ createdAt timestamp │ │
|
|
│ │ updatedAt timestamp │ │
|
|
│ └─────────────────────────────────────────────┘ │
|
|
└──────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 2.2 — TenantFeatures (JSONB — Sistema de Módulos)
|
|
|
|
O campo `features` na tabela `tenants` é um JSONB que controla **quais módulos da Arcádia estão habilitados** para cada tenant. O tipo é definido em `shared/schema.ts:821` e espelhado no frontend em `client/src/hooks/use-tenant-features.ts:3`.
|
|
|
|
```
|
|
┌──────────────────────────────────────────────────────────────────┐
|
|
│ TenantFeatures (JSONB) │
|
|
│ │
|
|
│ ┌─────────── Módulos Booleanos ──────────────┐ │
|
|
│ │ │ │
|
|
│ │ ide → IDE integrada │ │
|
|
│ │ whatsapp → WhatsApp multi-sessão │ │
|
|
│ │ crm → CRM completo │ │
|
|
│ │ erp → SOE/ERP │ │
|
|
│ │ bi → Business Intelligence │ │
|
|
│ │ manus → IA Manus (GPT-4o) │ │
|
|
│ │ centralApis → APIs centrais │ │
|
|
│ │ centralApisManage → Gerenciar APIs │ │
|
|
│ │ comunidades → Chat interno │ │
|
|
│ │ biblioteca → Biblioteca de conhecimento │ │
|
|
│ │ bibliotecaPublish → Publicar na biblioteca │ │
|
|
│ │ suporteN3 → Suporte nível 3 │ │
|
|
│ │ retail → Módulo Varejo │ │
|
|
│ │ plus → ERP Plus (Laravel) │ │
|
|
│ │ fisco → Motor Fiscal │ │
|
|
│ │ cockpit → Cockpit executivo │ │
|
|
│ │ compass → Process Compass │ │
|
|
│ │ production → Módulo Produção │ │
|
|
│ │ support → Módulo Suporte │ │
|
|
│ │ xosCrm → XOS CRM (Kanban) │ │
|
|
│ │ │ │
|
|
│ └─────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌─────────── Configurações Numéricas ────────┐ │
|
|
│ │ │ │
|
|
│ │ whatsappSessions → Nº sessões WA (0-N) │ │
|
|
│ │ maxChannels → Nº canais permitidos │ │
|
|
│ │ │ │
|
|
│ └─────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌─────────── Configurações de Texto ─────────┐ │
|
|
│ │ │ │
|
|
│ │ ideMode → "none" | "no-code" | │ │
|
|
│ │ "low-code" | "pro-code" │ │
|
|
│ │ manusTools[] → Lista de tools habilitadas │ │
|
|
│ │ │ │
|
|
│ └─────────────────────────────────────────────┘ │
|
|
└──────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 2.3 — tenant_empresas (Matriz/Filiais)
|
|
|
|
Cada tenant pode ter **múltiplas empresas** (CNPJs) cadastradas — essencial para operações fiscais (NF-e/NFC-e) por filial.
|
|
|
|
```
|
|
┌──────────────────────────────────────────────────────────────────┐
|
|
│ tenant_empresas │
|
|
│ Tabela: "tenant_empresas" — shared/schema.ts:889 │
|
|
│ │
|
|
│ ┌─────────── Identificação ──────────────────┐ │
|
|
│ │ id serial PK │ │
|
|
│ │ tenantId FK → tenants.id (CASCADE) │ │
|
|
│ │ razaoSocial text NOT NULL │ │
|
|
│ │ nomeFantasia text │ │
|
|
│ │ cnpj text NOT NULL │ │
|
|
│ │ ie text (inscrição estadual) │ │
|
|
│ │ im text (inscrição municipal) │ │
|
|
│ │ email, phone text │ │
|
|
│ │ tipo "matriz" | "filial" │ │
|
|
│ │ status "active" | "inactive" │ │
|
|
│ └─────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌─────────── Endereço ───────────────────────┐ │
|
|
│ │ cep, logradouro, numero, complemento, │ │
|
|
│ │ bairro, cidade, uf, codigoIbge │ │
|
|
│ └─────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌─────────── Fiscal ─────────────────────────┐ │
|
|
│ │ regimeTributario "simples" | "presumido" │ │
|
|
│ │ | "real" │ │
|
|
│ │ certificadoDigitalId FK certificado │ │
|
|
│ │ ambienteFiscal "producao" | "homologacao" │ │
|
|
│ │ serieNfe integer (default 1) │ │
|
|
│ │ serieNfce integer (default 1) │ │
|
|
│ │ plusEmpresaId integer (link ERP Plus) │ │
|
|
│ └─────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌─────────── Metadata ───────────────────────┐ │
|
|
│ │ createdAt, updatedAt timestamp │ │
|
|
│ └─────────────────────────────────────────────┘ │
|
|
└──────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
**Uso típico:**
|
|
|
|
```
|
|
Tenant "Empresa ABC" (id: 5)
|
|
├── Empresa Matriz: "ABC Comércio LTDA" (CNPJ: 12.345.678/0001-00)
|
|
│ regime: simples, ambiente: producao, série NF-e: 1
|
|
├── Filial SP: "ABC Comércio SP" (CNPJ: 12.345.678/0002-81)
|
|
│ regime: simples, ambiente: producao, série NF-e: 2
|
|
└── Filial RJ: "ABC Comércio RJ" (CNPJ: 12.345.678/0003-62)
|
|
regime: simples, ambiente: homologacao, série NF-e: 1
|
|
```
|
|
|
|
### 2.4 — tenant_users (Membership)
|
|
|
|
```
|
|
┌──────────────────────────────────────────────────────────────────┐
|
|
│ tenant_users │
|
|
│ Tabela: "tenant_users" — shared/schema.ts:923 │
|
|
│ │
|
|
│ id serial PK │
|
|
│ tenantId FK → tenants.id (CASCADE) │
|
|
│ userId FK → users.id (CASCADE) │
|
|
│ role "owner" | "admin" | "member" │
|
|
│ isOwner "true" | "false" │
|
|
│ createdAt timestamp │
|
|
│ │
|
|
│ → Link N:N entre users e tenants │
|
|
│ → Um usuário pode pertencer a múltiplos tenants │
|
|
│ → Cada tenant tem um owner + admins + members │
|
|
└──────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 2.5 — tenant_plans (Planos Disponíveis)
|
|
|
|
```
|
|
┌──────────────────────────────────────────────────────────────────┐
|
|
│ tenant_plans │
|
|
│ Tabela: "tenant_plans" — shared/schema.ts:933 │
|
|
│ │
|
|
│ id serial PK │
|
|
│ code text UNIQUE ("free", "starter", "pro", │
|
|
│ "enterprise", "partner_starter", "partner_pro") │
|
|
│ name text NOT NULL │
|
|
│ description text │
|
|
│ tenantType "master" | "partner" | "client" │
|
|
│ maxUsers integer (default 5) │
|
|
│ maxStorageMb integer (default 1000) │
|
|
│ features JSONB → TenantFeatures │
|
|
│ monthlyPrice integer (centavos) │
|
|
│ yearlyPrice integer (centavos) │
|
|
│ trialDays integer (default 14) │
|
|
│ isActive "true" | "false" │
|
|
│ sortOrder integer │
|
|
│ createdAt timestamp │
|
|
└──────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 2.6 — partner_clients (Relacionamento Parceiro↔Cliente)
|
|
|
|
```
|
|
┌──────────────────────────────────────────────────────────────────┐
|
|
│ partner_clients │
|
|
│ Tabela: "partner_clients" — shared/schema.ts:951 │
|
|
│ │
|
|
│ id serial PK │
|
|
│ partnerId FK → tenants.id (CASCADE) │
|
|
│ clientId FK → tenants.id (CASCADE) │
|
|
│ commissionRate numeric(5,2) — Override do rate do parceiro │
|
|
│ status "active" | "suspended" | "ended" │
|
|
│ notes text │
|
|
│ startedAt timestamp │
|
|
│ endedAt timestamp │
|
|
└──────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 2.7 — partner_commissions (Comissões dos Parceiros)
|
|
|
|
```
|
|
┌──────────────────────────────────────────────────────────────────┐
|
|
│ partner_commissions │
|
|
│ Tabela: "partner_commissions" — shared/schema.ts:963 │
|
|
│ │
|
|
│ id serial PK │
|
|
│ partnerId FK → tenants.id (CASCADE) │
|
|
│ clientId FK → tenants.id (CASCADE) │
|
|
│ referenceMonth text ("2026-01", "2026-02", ...) │
|
|
│ clientPlanCode text (código do plano do cliente) │
|
|
│ clientPlanValue integer (valor do plano em centavos) │
|
|
│ commissionRate numeric(5,2) NOT NULL │
|
|
│ commissionValue integer NOT NULL (valor em centavos) │
|
|
│ status "pending" | "approved" | "paid" | "cancelled" │
|
|
│ approvedAt timestamp │
|
|
│ paidAt timestamp │
|
|
│ paymentReference text │
|
|
│ createdAt timestamp │
|
|
│ │
|
|
│ Fluxo: pending → approved → paid │
|
|
│ │
|
|
│ Exemplo: │
|
|
│ Parceiro A tem Cliente X no plano "pro" (R$ 299/mês) │
|
|
│ commissionRate: 20% │
|
|
│ commissionValue: 5980 centavos (R$ 59,80) │
|
|
└──────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Planos Pré-definidos (Seed)
|
|
|
|
A rota `POST /api/admin/plans/seed` cria os 6 planos padrão:
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ PLANOS PARA CLIENTES │
|
|
├────────────┬──────────┬──────────┬──────────────────────────────────┤
|
|
│ Plano │ Preço/mês│ Usuários │ Módulos │
|
|
├────────────┼──────────┼──────────┼──────────────────────────────────┤
|
|
│ Gratuito │ R$ 0 │ 2 │ erp, crm │
|
|
│ (free) │ │ │ │
|
|
├────────────┼──────────┼──────────┼──────────────────────────────────┤
|
|
│ Starter │ R$ 99 │ 5 │ erp, crm, bi, fisco, │
|
|
│ │ │ │ whatsapp, compass │
|
|
├────────────┼──────────┼──────────┼──────────────────────────────────┤
|
|
│ Pro │ R$ 299 │ 15 │ erp, crm, bi, fisco, retail, │
|
|
│ │ │ │ plus, whatsapp, manus, cockpit, │
|
|
│ │ │ │ compass, support, biblioteca │
|
|
├────────────┼──────────┼──────────┼──────────────────────────────────┤
|
|
│ Enterprise │ R$ 999 │ 100 │ TODOS os módulos │
|
|
│ │ │ 50GB │ (erp, crm, bi, fisco, retail, │
|
|
│ │ │ │ plus, whatsapp, manus, ide, │
|
|
│ │ │ │ cockpit, compass, production, │
|
|
│ │ │ │ support, xosCrm, centralApis, │
|
|
│ │ │ │ comunidades, biblioteca) │
|
|
└────────────┴──────────┴──────────┴──────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ PLANOS PARA PARCEIROS │
|
|
├──────────────────┬──────────┬──────────┬────────────────────────────┤
|
|
│ Plano │ Preço/mês│ Usuários │ Módulos │
|
|
├──────────────────┼──────────┼──────────┼────────────────────────────┤
|
|
│ Parceiro Starter │ R$ 199 │ 10 │ erp, crm, bi, fisco, │
|
|
│ │ │ │ retail, whatsapp, compass, │
|
|
│ │ │ │ support │
|
|
├──────────────────┼──────────┼──────────┼────────────────────────────┤
|
|
│ Parceiro Pro │ R$ 499 │ 50 │ TODOS os módulos │
|
|
│ │ │ 25GB │ (igual Enterprise) │
|
|
└──────────────────┴──────────┴──────────┴────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Sistema de Papéis (Roles)
|
|
|
|
A Arcádia opera com **dois níveis de papéis** que se complementam:
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ SISTEMA DUPLO DE ROLES │
|
|
│ │
|
|
│ ┌─────────── Papel do Sistema (users.role) ──────────────────┐ │
|
|
│ │ │ │
|
|
│ │ "master" → Superadmin, acesso total, bypass de tenant │ │
|
|
│ │ "admin" → Administrador, acessa /api/admin/* │ │
|
|
│ │ "user" → Usuário padrão, sem acesso admin │ │
|
|
│ │ │ │
|
|
│ │ Verificado no middleware global de admin: │ │
|
|
│ │ if (role !== "admin" && role !== "master") → 403 │ │
|
|
│ └─────────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌─────────── Papel no Tenant (tenant_users.role) ────────────┐ │
|
|
│ │ │ │
|
|
│ │ "owner" → Dono do tenant, criador, full control │ │
|
|
│ │ "admin" → Administrador do tenant │ │
|
|
│ │ "member" → Membro comum, acesso operacional │ │
|
|
│ │ │ │
|
|
│ │ Usado para scoping de dados e permissões intra-tenant │ │
|
|
│ └─────────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ Combinação no login (getEnrichedUser): │
|
|
│ user.role + user.tenantId + user.tenantType + user.tenantRole │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 5. Controle de Acesso — Helpers
|
|
|
|
O backend implementa dois helpers essenciais em `server/admin/routes.ts`:
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ getAllowedTenantIds(user) │
|
|
│ │
|
|
│ Retorna os IDs de tenants que o usuário pode acessar: │
|
|
│ │
|
|
│ • master → null (acesso total, sem filtro) │
|
|
│ • partner → [seu tenantId, ...clientIds vinculados] │
|
|
│ • client → [apenas seu tenantId] │
|
|
│ │
|
|
│ Usado em: GET /tenants, GET /partner-clients, GET /commissions, │
|
|
│ GET /empresas, GET /tenants/hierarchy │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ canAccessTenant(user, tenantId) │
|
|
│ │
|
|
│ Verifica se o usuário pode operar sobre um tenant específico: │
|
|
│ │
|
|
│ • master → true (sempre) │
|
|
│ • partner → true se tenantId ∈ getAllowedTenantIds() │
|
|
│ • client → true apenas se tenantId === user.tenantId │
|
|
│ │
|
|
│ Usado em: PATCH /tenants/:id, DELETE /empresas/:id, │
|
|
│ POST /empresas, etc. │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Middleware de Módulos (requireModule)
|
|
|
|
O middleware `requireModule` em `server/retail/routes.ts:25` bloqueia endpoints quando um módulo não está ativo para o tenant:
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ requireModule(moduleKey: keyof TenantFeatures) │
|
|
│ │
|
|
│ Fluxo: │
|
|
│ 1. Identifica tenantId do usuário logado │
|
|
│ 2. Busca tenant no banco │
|
|
│ 3. Verifica features[moduleKey] === true │
|
|
│ 4. Se false → 403 com mensagem: │
|
|
│ { │
|
|
│ error: "Módulo 'X' não está ativo para este tenant", │
|
|
│ moduleKey: "plus", │
|
|
│ action: "Ative o módulo em Admin → Módulos" │
|
|
│ } │
|
|
│ │
|
|
│ Exemplo de uso: │
|
|
│ router.post("/plus/sync/customers", │
|
|
│ requireModule("plus"), ← Bloqueia se Plus não está ativo │
|
|
│ async (req, res) => { ... } │
|
|
│ ); │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Hook Frontend (useTenantFeatures)
|
|
|
|
O hook `useTenantFeatures()` em `client/src/hooks/use-tenant-features.ts` fornece acesso às features do tenant no frontend:
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ useTenantFeatures() │
|
|
│ │
|
|
│ Fonte: GET /api/soe/tenant/modules │
|
|
│ Cache: 60 segundos (staleTime: 60000) │
|
|
│ │
|
|
│ Retorna: │
|
|
│ { │
|
|
│ features: TenantFeatures, ← Objeto completo de features │
|
|
│ isLoading: boolean, │
|
|
│ plan: string, ← Código do plano atual │
|
|
│ isEnabled: (key) => bool, ← Verificação rápida │
|
|
│ } │
|
|
│ │
|
|
│ Defaults (quando não logado / sem tenant): │
|
|
│ ide: true, crm: true, erp: true, manus: true, compass: true │
|
|
│ Todos os demais: false │
|
|
│ │
|
|
│ Uso no componente: │
|
|
│ const { isEnabled } = useTenantFeatures(); │
|
|
│ if (isEnabled("bi")) { /* mostra menu BI */ } │
|
|
│ if (isEnabled("retail")) { /* mostra módulo varejo */ } │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 8. Interface de Administração
|
|
|
|
### 8.1 — Admin.tsx (Página Principal)
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ Admin.tsx — client/src/pages/Admin.tsx (2.635 linhas) │
|
|
│ Rota: /admin │
|
|
│ │
|
|
│ 6 Abas: │
|
|
│ ┌─────────────┬──────────┬────────────┬───────────┬──────────────┐ │
|
|
│ │ Conexões │ Tarefas │ Knowledge │ Bibliotecas│ Módulos │ │
|
|
│ │ │ │ │ │ │ │
|
|
│ │ WhatsApp │ Dev │ Knowledge │ Conteúdo │ Ativação │ │
|
|
│ │ ERPNext │ Center │ Graph │ Docs │ por tenant │ │
|
|
│ │ APIs │ Pipeline │ Q&A │ Templates │ Toggle on/ │ │
|
|
│ │ │ │ │ │ off módulos │ │
|
|
│ └─────────────┴──────────┴────────────┴───────────┴──────────────┘ │
|
|
│ ┌─────────────┐ │
|
|
│ │Casa de │ │
|
|
│ │Máquinas │ │
|
|
│ │ │ │
|
|
│ │ Status dos │ │
|
|
│ │ motores │ │
|
|
│ │ (:8002-8006)│ │
|
|
│ └─────────────┘ │
|
|
│ │
|
|
│ Aba "Módulos" renderiza: <MultiTenantSection /> │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 8.2 — MultiTenantSection (Gestão Completa)
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ MultiTenantSection.tsx (1.486 linhas) │
|
|
│ client/src/components/MultiTenantSection.tsx │
|
|
│ │
|
|
│ 4 Abas internas: │
|
|
│ │
|
|
│ ┌─ Tenants ──────────────────────────────────────────────────┐ │
|
|
│ │ │ │
|
|
│ │ Lista de tenants com: │ │
|
|
│ │ • Nome, tipo (Master/Parceiro/Cliente) │ │
|
|
│ │ • Plano atual e status │ │
|
|
│ │ • Nº de filhos (childCount) │ │
|
|
│ │ • Tenant pai (parentTenant) │ │
|
|
│ │ • Ações: Editar, Ativar/Desativar módulos │ │
|
|
│ │ │ │
|
|
│ │ Formulário de criação: │ │
|
|
│ │ • Nome, email, phone │ │
|
|
│ │ • Tipo (master/partner/client) │ │
|
|
│ │ • Plano (seleciona do tenant_plans) │ │
|
|
│ │ • Tenant pai (para hierarquia) │ │
|
|
│ │ • Features auto-preenchidas pelo plano selecionado │ │
|
|
│ │ • Toggle individual de cada módulo │ │
|
|
│ │ │ │
|
|
│ └─────────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌─ Planos ───────────────────────────────────────────────────┐ │
|
|
│ │ │ │
|
|
│ │ CRUD de planos com: │ │
|
|
│ │ • Código, nome, descrição │ │
|
|
│ │ • Tipo de tenant (client/partner) │ │
|
|
│ │ • Preço mensal e anual (centavos) │ │
|
|
│ │ • Max usuários e storage │ │
|
|
│ │ • Features (toggle de cada módulo) │ │
|
|
│ │ • Botão "Seed" para criar planos padrão │ │
|
|
│ │ • Botão "Propagar" para aplicar features do plano │ │
|
|
│ │ a todos os tenants que usam esse plano │ │
|
|
│ │ │ │
|
|
│ └─────────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌─ Comissões ────────────────────────────────────────────────┐ │
|
|
│ │ │ │
|
|
│ │ Lista de comissões de parceiros: │ │
|
|
│ │ • Parceiro, Cliente, Mês referência │ │
|
|
│ │ • Valor do plano, taxa de comissão, valor da comissão │ │
|
|
│ │ • Status (pending → approved → paid) │ │
|
|
│ │ • Ações: Aprovar, Marcar como paga │ │
|
|
│ │ │ │
|
|
│ └─────────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌─ Empresas ─────────────────────────────────────────────────┐ │
|
|
│ │ │ │
|
|
│ │ EmpresasSubSection: │ │
|
|
│ │ • Lista de empresas (Matriz/Filiais) por tenant │ │
|
|
│ │ • CNPJ, Razão Social, Nome Fantasia │ │
|
|
│ │ • IE, IM, Regime Tributário │ │
|
|
│ │ • Endereço completo (CEP, logradouro, cidade, UF) │ │
|
|
│ │ • Config Fiscal (ambiente, série NF-e, série NFC-e) │ │
|
|
│ │ • Link com ERP Plus (plusEmpresaId) │ │
|
|
│ │ • Ações: Criar, Editar, Excluir │ │
|
|
│ │ │ │
|
|
│ └─────────────────────────────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 9. API REST Completa (/api/admin/*)
|
|
|
|
### Tenants
|
|
|
|
| Método | Endpoint | Função | Acesso |
|
|
|--------|----------|--------|--------|
|
|
| GET | `/tenants` | Lista tenants (filtrado por acesso) | master/partner/client |
|
|
| POST | `/tenants` | Cria tenant (resolve features do plano) | master/admin |
|
|
| PATCH | `/tenants/:id` | Atualiza tenant (canAccessTenant) | master/partner |
|
|
| DELETE | `/tenants/:id` | Exclui tenant (proteção master) | somente master |
|
|
| GET | `/tenants/hierarchy` | Árvore hierárquica de tenants | master/partner |
|
|
| GET | `/tenants/stats` | Estatísticas (total, por tipo, por status) | master/admin |
|
|
|
|
### Planos
|
|
|
|
| Método | Endpoint | Função |
|
|
|--------|----------|--------|
|
|
| GET | `/plans` | Lista todos os planos |
|
|
| POST | `/plans` | Cria novo plano |
|
|
| PATCH | `/plans/:id` | Atualiza plano |
|
|
| DELETE | `/plans/:id` | Exclui plano |
|
|
| POST | `/plans/:id/propagate` | Propaga features do plano para todos os tenants que o usam |
|
|
| POST | `/plans/seed` | Cria 6 planos padrão |
|
|
|
|
### Parceiro-Cliente
|
|
|
|
| Método | Endpoint | Função |
|
|
|--------|----------|--------|
|
|
| GET | `/partner-clients` | Lista relacionamentos parceiro↔cliente |
|
|
| POST | `/partner-clients` | Cria vínculo parceiro↔cliente |
|
|
|
|
### Comissões de Parceiros
|
|
|
|
| Método | Endpoint | Função |
|
|
|--------|----------|--------|
|
|
| GET | `/commissions` | Lista comissões (filtro por partnerId, status) |
|
|
| PATCH | `/commissions/:id/approve` | Aprova comissão |
|
|
| PATCH | `/commissions/:id/pay` | Marca como paga |
|
|
|
|
### Empresas (Matriz/Filiais)
|
|
|
|
| Método | Endpoint | Função |
|
|
|--------|----------|--------|
|
|
| GET | `/empresas` | Lista empresas (filtro por tenantId + acesso) |
|
|
| GET | `/empresas/:id` | Detalhe da empresa |
|
|
| POST | `/empresas` | Cria empresa (verifica canAccessTenant) |
|
|
| PATCH | `/empresas/:id` | Atualiza empresa |
|
|
| DELETE | `/empresas/:id` | Exclui empresa |
|
|
|
|
### Outros Admin
|
|
|
|
| Método | Endpoint | Função |
|
|
|--------|----------|--------|
|
|
| GET | `/profiles` | Lista perfis de usuários |
|
|
| POST | `/profiles` | Cria perfil |
|
|
| PATCH | `/profiles/:id` | Atualiza perfil |
|
|
| DELETE | `/profiles/:id` | Exclui perfil |
|
|
| GET | `/users` | Lista usuários (com tenant info) |
|
|
| PATCH | `/users/:id` | Atualiza usuário |
|
|
| PATCH | `/users/:id/status` | Altera status do usuário |
|
|
| PATCH | `/partners/:id/status` | Altera status de parceiro |
|
|
| PATCH | `/clients/:id/status` | Altera status de cliente |
|
|
| GET | `/stats` | Estatísticas gerais (tenants, users, leads) |
|
|
| GET | `/libraries` | Lista bibliotecas de conteúdo |
|
|
|
|
**Total: 33 endpoints de administração**
|
|
|
|
---
|
|
|
|
## 10. Fluxo Completo — Onboarding de Tenant
|
|
|
|
```
|
|
┌──────────┐ ┌────────────┐ ┌──────────────┐ ┌──────────────┐
|
|
│ 1. CRIAR │───▶│ 2. PLANO │───▶│ 3. FEATURES │───▶│ 4. EMPRESAS │
|
|
│ TENANT │ │ │ │ │ │ │
|
|
│ │ │ Seleciona │ │ Auto-resolve │ │ Cadastra │
|
|
│ POST │ │ plano │ │ do plano ou │ │ Matriz │
|
|
│ /admin/ │ │ (free, │ │ toggle │ │ + Filiais │
|
|
│ tenants │ │ starter, │ │ individual │ │ │
|
|
│ │ │ pro, etc) │ │ de módulos │ │ CNPJ, IE, │
|
|
│ name, │ │ │ │ │ │ endereço, │
|
|
│ email, │ │ maxUsers │ │ ide: true │ │ regime │
|
|
│ type │ │ maxStorage │ │ crm: true │ │ tributário, │
|
|
│ │ │ preço │ │ bi: false │ │ certificado │
|
|
│ │ │ │ │ ... │ │ digital │
|
|
└──────────┘ └────────────┘ └──────────────┘ └──────────────┘
|
|
│
|
|
▼
|
|
┌──────────────┐ ┌──────────────┐ ┌──────────────────────────┐
|
|
│ 5. VINCULAR │ │ 6. COMISSÕES │ │ 7. USUÁRIOS │
|
|
│ PARCEIRO │ │ │ │ │
|
|
│ (se partner) │ │ Automáticas │ │ Convida users │
|
|
│ │ │ mensais │ │ tenant_users │
|
|
│ POST /admin/ │ │ baseadas no │ │ roles: owner/admin/ │
|
|
│ partner- │ │ plano do │ │ member │
|
|
│ clients │ │ cliente │ │ │
|
|
│ │ │ │ │ Scoping automático │
|
|
│ partnerId │ │ pending → │ │ de todos os dados │
|
|
│ clientId │ │ approved → │ │ por tenantId │
|
|
│ commission% │ │ paid │ │ │
|
|
└──────────────┘ └──────────────┘ └──────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 11. Propagação de Plano
|
|
|
|
Quando um plano é atualizado, a feature de **propagação** atualiza todos os tenants que usam esse plano:
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ POST /api/admin/plans/:id/propagate │
|
|
│ │
|
|
│ 1. Busca o plano por ID │
|
|
│ 2. Pega features, maxUsers, maxStorageMb do plano │
|
|
│ 3. Atualiza TODOS os tenants onde plan === plan.code: │
|
|
│ UPDATE tenants SET │
|
|
│ features = plan.features, │
|
|
│ maxUsers = plan.maxUsers, │
|
|
│ maxStorageMb = plan.maxStorageMb │
|
|
│ WHERE plan = 'pro' │
|
|
│ 4. Retorna: { propagated: 15, planCode: "pro" } │
|
|
│ │
|
|
│ Exemplo: │
|
|
│ Plano "pro" ganha módulo "production" → │
|
|
│ Propagar → 15 tenants "pro" recebem production: true │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 12. Isolamento de Dados
|
|
|
|
Toda query de dados respeita o escopo do tenant:
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ ISOLAMENTO POR tenantId │
|
|
│ │
|
|
│ Padrão em todas as queries: │
|
|
│ │
|
|
│ const tenantId = (req.user as any).tenantId; │
|
|
│ const data = await db.select() │
|
|
│ .from(tabela) │
|
|
│ .where(eq(tabela.tenantId, tenantId)); │
|
|
│ │
|
|
│ Tabelas com tenantId: │
|
|
│ • tenants (hierarquia) • crm_channels │
|
|
│ • tenant_empresas • crm_threads │
|
|
│ • crm_leads • crm_events │
|
|
│ • crm_clients • crm_campaigns │
|
|
│ • crm_opportunities • crm_products │
|
|
│ • crm_partners • crm_contracts │
|
|
│ • crm_pipeline_stages • crm_commission_rules │
|
|
│ • crm_proposals • crm_quick_messages │
|
|
│ • retail_activity_feed • valuation_* │
|
|
│ │
|
|
│ Resultado: Dados do Tenant A NUNCA são vistos pelo Tenant B │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 13. Arquivos-Chave
|
|
|
|
| Arquivo | Função | Linhas |
|
|
|---------|--------|--------|
|
|
| `shared/schema.ts` (L821-977) | TenantFeatures type + 6 tabelas tenant | ~160 |
|
|
| `server/admin/routes.ts` | API admin (33 endpoints) | 876 |
|
|
| `client/src/pages/Admin.tsx` | Página admin (6 abas) | 2.635 |
|
|
| `client/src/components/MultiTenantSection.tsx` | Gestão multi-tenant (4 sub-abas) | 1.486 |
|
|
| `client/src/hooks/use-tenant-features.ts` | Hook de features no frontend | 59 |
|
|
| `server/retail/routes.ts` (L25) | Middleware requireModule | ~25 |
|
|
| `server/storage.ts` (getEnrichedUser) | Enriquece user com tenant info | — |
|
|
|
|
---
|
|
|
|
## 14. Resumo Visual
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ ARCÁDIA MULTI-TENANT STACK │
|
|
│ │
|
|
│ ┌───── Autenticação ──────────────────────────────────────────┐ │
|
|
│ │ Login → getEnrichedUser → user + tenantId + tenantType │ │
|
|
│ │ + tenantRole + features │ │
|
|
│ └─────────────────────────────────────────┬───────────────────┘ │
|
|
│ │ │
|
|
│ ┌─────────────────────────────────────────▼───────────────────┐ │
|
|
│ │ Middleware │ │
|
|
│ │ ┌──────────┐ ┌─────────────┐ ┌────────────────────┐ │ │
|
|
│ │ │requireAuth│ │requireModule │ │getAllowedTenantIds │ │ │
|
|
│ │ │role check │ │feature check │ │canAccessTenant │ │ │
|
|
│ │ └──────────┘ └─────────────┘ └────────────────────┘ │ │
|
|
│ └─────────────────────────────────────────┬───────────────────┘ │
|
|
│ │ │
|
|
│ ┌─────────────────────────────────────────▼───────────────────┐ │
|
|
│ │ API /api/admin/* │ │
|
|
│ │ 33 endpoints: Tenants, Plans, Empresas, Comissões │ │
|
|
│ └─────────────────────────────────────────┬───────────────────┘ │
|
|
│ │ │
|
|
│ ┌─────────────────────────────────────────▼───────────────────┐ │
|
|
│ │ PostgreSQL │ │
|
|
│ │ 6 tabelas: tenants, tenant_users, tenant_plans, │ │
|
|
│ │ tenant_empresas, partner_clients, partner_commissions │ │
|
|
│ └─────────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌───── Frontend ──────────────────────────────────────────────┐ │
|
|
│ │ Admin.tsx (6 abas) → MultiTenantSection (4 sub-abas) │ │
|
|
│ │ useTenantFeatures() hook → GET /api/soe/tenant/modules │ │
|
|
│ └─────────────────────────────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
```
|