Empresas e unidades: separar os dados de cada cliente
Um app feito no MadBuilder pode atender vários clientes ao mesmo tempo sem que um veja os dados do outro. Esta página explica os dois jeitos de separar, por empresa e por unidade, como escolher entre eles no painel Tenancy & Banco e o que muda nas telas do app depois de publicar.
Empresa, unidade e usuário
Três palavras aparecem em toda esta página. Vale fixar o sentido de cada uma antes de ligar qualquer opção:
| Termo | O que é | Exemplo |
|---|---|---|
| Empresa tenant | O cliente que contrata o seu sistema. É o limite mais forte: os dados de uma empresa nunca aparecem para outra. | Rede Bem Viver, Clínica Vida Plena. |
| Unidade filial | Uma filial dentro de uma empresa. Toda unidade pertence a uma empresa só. | Bem Viver — Centro e Bem Viver — Norte, as duas da Rede Bem Viver. |
| Usuário | Uma pessoa com login. Ela é vinculada a uma ou mais unidades e trabalha em uma de cada vez, a unidade ativa. | Letícia, que atende nas duas unidades da Rede Bem Viver. |
Separar por empresa e separar por unidade são opções independentes. Um app pode usar só uma delas, as duas juntas ou nenhuma. Empresas e unidades são cadastradas dentro do app publicado, em Administração › Empresas e Administração › Unidades; o passo a passo dessas telas está em Login, usuários e unidades, seção 06.
Qual configuração escolher
Responda pela situação dos seus clientes. A primeira coluna é o que você tem; as outras dizem o que ligar.
| Situação | Tenancy (cliente) | Multi-unidade |
|---|---|---|
| Sistema interno de uma organização só, sem filiais. | Cliente único | Desligado |
| Uma organização com filiais que não devem ver os registros umas das outras. | Cliente único | Ligado |
| Sistema vendido para muitos clientes (SaaS), cada cliente com uma equipe só. | Cliente único (cada cliente é uma unidade) ou Pool | Ligado (com Cliente único) |
| Sistema vendido para redes com filiais: a rede não pode ver outra rede, e as filiais separam os próprios registros. | Pool | Ligado |
| Cliente que exige os dados num banco separado (contrato, volume, exigência legal). | Dedicado (Bridge) | Conforme as filiais |
O painel Tenancy & Banco
Toda a configuração fica num painel do projeto, no MadBuilder. Há três caminhos para abri-lo:
- No menu lateral do Studio, grupo Geração & ferramentas, item Tenancy & Banco.
- Em Propriedades do projeto, seção Tenancy & Banco, botão Abrir configuração.
- Na tela de Modelos de dados, pelo selo Tenancy: … no alto. Ele mostra o modo atual e as colunas que o painel acrescenta (tenant_id, unit_id).

O painel grava sozinho a cada alteração: no alto aparece Salvando… e depois Salvo, sem botão de salvar. São quatro blocos:
| Bloco | O que define | Nesta página |
|---|---|---|
| 1 · Banco | Onde as tabelas ficam: SQLite, MySQL, MariaDB ou PostgreSQL, os dados de acesso ao servidor, conexão segura (SSL/TLS) e um nome de banco por modelo de dados. | Não é assunto desta página. |
| 2 · Tenancy (cliente) | Como as empresas são separadas: Cliente único, Pool ou Dedicado (Bridge). | Seção 04 |
| 2b · Unidade (filial) | Separação por unidade, o modo de leitura (só a ativa ou todas), o banco por empresa e o licenciamento. | Seções 05 e 06 |
| 3 · IA · acesso | Só um atalho para o painel MCP Server, onde se define o que o agente de IA pode ler e alterar. | — |
Separar por empresa (bloco 2 · Tenancy)
O bloco Tenancy (cliente) tem três cartões. Eles mudam onde os dados de cada empresa ficam guardados:
| Cartão | Como guarda | Quando usar |
|---|---|---|
| Cliente único padrão | Um banco, sem separação por empresa. | App interno, ou SaaS em que cada cliente é uma unidade (seção 05). |
| Pool | Um banco para todas as empresas. Cada registro guarda a empresa dona, e o app só mostra os da empresa de quem está logado. | Muitos clientes, custo baixo, um banco só para administrar. |
| Dedicado (Bridge) | Um banco separado para cada empresa. Usuários, permissões e auditoria continuam num banco compartilhado. | Cliente que exige isolamento físico, ou muito volume por cliente. |
Pool: um banco, registros marcados com a empresa
O Pool pede dois passos no bloco 2. Só escolher o cartão não separa nada:
- Clique no cartão Pool.
- Ligue Isolar por linha (tenant_id): "Liga o filtro automático por tenant nos models data-plane".
- Em Conexões isoladas por tenant, marque os modelos de dados cujas tabelas devem ser separadas por empresa. Os selos iam e log aparecem travados.

O que acontece nos modelos marcados:
- Toda tabela ganha a coluna tenant_id, inclusive as que já existiam. As tabelas criadas depois já nascem com ela.
- Nas telas do app, cada listagem, campo de seleção, filtro e dashboard mostra só os registros da empresa de quem está logado. Vale também para quem é administrador.
- Todo registro novo é gravado com a empresa de quem está logado. A coluna não aparece nos formulários e nas listagens geradas, e o formulário não consegue escolher outra empresa: um valor de tenant_id enviado por ele é ignorado. Para cadastrar em outra empresa, a pessoa troca de empresa no topo do app (pergunta frequente).
- Coluna marcada como única passa a ser única dentro da empresa: duas empresas podem usar o mesmo código.
Dedicado (Bridge): um banco por empresa
No Dedicado, cada empresa tem um banco próprio. O app escolhe o banco no login, pela empresa da pessoa, e passa a ler e gravar só nele. Usuários, permissões e auditoria continuam num banco compartilhado.
- Clique no cartão Dedicado (Bridge). No bloco 2b, Banco próprio por empresa aparece ligado e travado: o cartão já liga essa opção.
- Em Conexões de tenant (allowlist), adicione uma linha por banco de empresa. O Nome lógico segue o
formato tenant_<nome>, só com letras minúsculas, números e
_(ex.:tenant_bemviver). Na coluna Banco, informe o nome do banco dessa empresa. - Crie os bancos. Em Comandos, o painel lista um comando por linha para rodar no app instalado. Pelo próprio app, a lista Administração › Empresas ganha a ação Provisionar banco para as empresas que ainda não têm banco.

php artisan mad:tenant:provision … por empresa, com o nome do banco informado na linha.No app, o cadastro da empresa ganha o campo Conexão, preenchido sozinho ao provisionar ("Deixe em branco para empresas em banco único"), e a linha Modo de tenancy acima da lista de empresas passa a dizer Bridge (banco por empresa).
Separar por unidade (bloco 2b · Unidade)
A unidade é uma camada dentro da empresa. Com ela ligada, cada registro guarda a unidade dona, e cada pessoa trabalha numa unidade por vez. O bloco Unidade (filial) tem quatro opções:

| Opção | O que faz |
|---|---|
| Multi-unidade | Liga a separação por unidade: coluna unit_id nas tabelas, escolha da unidade no login e troca de unidade no topo do app. |
| Ver todas as unidades do usuário | Listagens, campos de seleção e filtros mostram os registros de todas as unidades da pessoa, sem trocar de unidade. Detalhes na seção 06. |
| Banco próprio por empresa | Cada empresa, com as filiais dela, usa um banco separado. É o mesmo efeito do cartão Dedicado, que já liga esta opção. |
| Licenciamento | Transforma cada unidade ou empresa num cliente com plano, módulos, validade e limite de usuários. Ver Licenciamento. |
O que muda com Multi-unidade ligado
- Nas tabelas. Todas as tabelas dos modelos de dados do projeto ganham a coluna unit_id, inclusive as que já existiam. Ela não aparece nos formulários e nas listagens geradas: o app preenche sozinho.
- No login. Quem tem vínculo com mais de uma unidade escolhe em qual entrar, na janela Escolha a unidade. Quem tem uma só entra direto.
- No topo do app. Um seletor mostra a unidade ativa e troca para outra sem sair. Com mais de uma empresa, o seletor é de empresa e o nome da unidade fica ao lado, clicável. No menu do perfil há também Trocar Unidade. As telas estão em Login, usuários e unidades, seção 04.
- Nas telas. Listagem, campo de seleção (combo, busca, rádio, lista de marcação), combo dependente, filtro de coluna, filtro avançado e dashboard mostram só os registros da unidade ativa. Com Ver todas as unidades do usuário, mostram os de todas as unidades da pessoa.
- No cadastro. O registro novo vai para a unidade ativa. A edição mantém a unidade que o registro já tinha, mesmo que a pessoa esteja em outra unidade.
- Nos códigos únicos. Uma coluna única passa a ser única dentro da unidade: duas filiais podem ter o
pedido
PED-0001.
UPDATE no banco do app). O mesmo vale para tenant_id ao ligar o Pool.
Ver só a unidade ativa ou todas as do usuário
Por padrão, a pessoa vê só os registros da unidade ativa. Para consultar outra filial, ela troca de unidade no topo. Em muitos negócios isso atrapalha: a gerente regional quer ver os atendimentos das duas filiais na mesma lista. É para isso que existe Ver todas as unidades do usuário, no bloco 2b.
Regras do modo "todas as unidades"
| Situação | Só a unidade ativa | Todas as unidades do usuário |
|---|---|---|
| Listagem, campo de seleção, combo dependente, filtros, dashboards | Registros da unidade ativa. | Registros de todas as unidades da pessoa. |
| Cadastrar um registro novo | Vai para a unidade ativa, a que está no seletor do topo. | |
| Editar um registro de outra unidade | Não acontece: o registro não aparece. | O registro continua na unidade dele. |
| Escolher um registro de outra filial num campo de seleção (ex.: o cliente atendido no Norte) | Não aparece na lista. | Aparece e é aceito ao salvar. |
| Código único (ex.: número do atendimento) | Pode repetir em outra unidade. | É recusado se já existe em qualquer unidade da pessoa. Em unidade de que ela não participa, pode repetir. |
Algumas partes do app continuam na unidade ativa nos dois modos: os filtros salvos da listagem, os painéis de conciliação, o PDV, o acesso do agente de IA e as telas em que o próprio desenvolvedor pediu o filtro da unidade ativa (por exemplo, o calendário com filtro de unidade ligado).
O que o app garante
As regras abaixo valem sem nenhuma configuração extra, em qualquer tela gerada:
- Ninguém grava na unidade dos outros. Se um formulário tentar gravar um registro numa unidade de que a pessoa não participa, o app recusa com a mensagem "Você não tem acesso à unidade escolhida", no campo da unidade ou num aviso no canto da tela.
- O formulário não escolhe a empresa. No Pool, o registro é sempre gravado na empresa de quem está logado.
- Validações enxergam o mesmo que a tela. "Este código já está sendo utilizado" só considera os registros que a pessoa enxerga, e um campo de seleção só aceita um registro que ela poderia escolher. Nenhuma mensagem revela que um código existe em outro cliente.
- Administrador também é separado. Quem tem perfil de administrador vê os dados da empresa e da unidade em que entrou, como todo mundo. Para ver outra empresa ou unidade, troca no topo.
- Usuários e permissões são do app inteiro. Cadastro de pessoa, perfis e auditoria nunca são separados por empresa: é o que permite a mesma pessoa ter vínculo em vários clientes.
Aplicar as mudanças no app
O painel grava a configuração no projeto; o app só muda depois de publicado.
- Republique o projeto. É a publicação que cria as colunas novas no banco, ajusta os índices únicos e atualiza as regras das telas.
- No MadCloud, se a Hospedagem mostrar "O app está com variáveis da plataforma desatualizadas", clique em Sincronizar agora.
- Em servidor próprio ou pelo download do projeto, as variáveis vêm no
.envgerado, num bloco "Multi-tenancy & Banco". Quando há banco externo, comandos ou avisos, o pacote traz também umSETUP-INSTALL.mdcom o passo a passo. Ver Instalação em servidor próprio.
Em código próprio
Telas geradas já respeitam empresa e unidade. Esta seção é para quem escreve código PHP próprio no projeto (códigos, serviços, relatórios com SQL).
- Os models das tabelas com unit_id ou tenant_id já filtram sozinhos, no modo configurado. Não acrescente um filtro pela unidade ativa num model desses: no modo "todas as unidades", ele esconderia registros que a pessoa deveria ver.
- Em consulta direta ao banco (sem model), use a lista de unidades que a leitura enxerga.
// Unidade ativa (onde os cadastros novos entram)
$unidade = \Mad\Database\UnitContext::id();
// Unidades que a leitura enxerga: a ativa, ou todas as da pessoa
$unidades = \Mad\Database\UnitContext::readIds(); // null = sem filtro
$total = DB::table('atendimento')
->when($unidades !== null, fn ($q) => $q->whereIn('unit_id', $unidades))
->count();
// Empresa de quem está logado
$empresa = \Mad\Database\TenantContext::id();No PDF exportado, os campos {UNIT_NAME} e {TENANT_NAME} trazem o nome da unidade e da
empresa: ver Cabeçalho e rodapé do PDF.
Perguntas frequentes
Coloquei um campo de empresa no formulário, escolhi outra empresa e o registro foi gravado na minha.
É proposital. No Pool, o registro é sempre gravado na empresa de quem está logado, mesmo para o administrador: se o formulário pudesse escolher, qualquer pessoa gravaria dados no cliente de outra. E, mesmo que gravasse, o registro sumiria da sua lista, porque a leitura também é da sua empresa. Para cadastrar em outra empresa, troque de empresa no seletor do topo (a pessoa precisa ter vínculo com uma unidade dela) e cadastre de lá.
Liguei o Pool e cada empresa continua vendo tudo.
Confira os três pontos: o cartão Pool selecionado, Isolar por linha (tenant_id) ligado e pelo menos um modelo marcado em Conexões isoladas por tenant. A coluna Avisos do painel aponta quando falta o último. Depois, republique o projeto (seção 08).
Liguei Multi-unidade e os registros antigos sumiram.
Eles continuam no banco, mas estão com a unidade vazia e nenhuma unidade é dona deles. Preencha a coluna unit_id desses registros com o código da unidade dona. Veja o aviso da seção 05.
Sou administrador e não vejo os dados das outras filiais.
A separação vale para todos. Troque de unidade no topo. Se a sua equipe precisa consultar várias filiais ao mesmo tempo, ligue Ver todas as unidades do usuário e vincule essas pessoas às unidades que devem ver (seção 06).
No modo "todas as unidades", o app diz que um código já está em uso, mas ele é de outra filial.
Nesse modo, a verificação de código único considera todas as unidades que a pessoa enxerga, porque ela vê os registros de todas na mesma lista. Use outro código, ou cadastre pela filial que não tem esse código com o modo "só a unidade ativa".
Posso mudar de Pool para Dedicado depois?
A configuração muda no painel, mas os dados já gravados não mudam de banco sozinhos: os registros do Pool ficam no banco principal. Trocar de modo com o app em uso exige migrar os dados de cada empresa para o banco dela. Escolha o modo antes de colocar clientes no app sempre que possível.
O agente de IA respeita empresa e unidade?
Nas telas, sim: o que ele consulta pelas telas do app segue as mesmas regras. O acesso direto aos dados pelo servidor MCP tem configuração própria, no painel MCP Server (bloco 3 · IA · acesso leva até lá).
Onde cadastro as empresas e as unidades?
No app publicado, em Administração › Empresas e Administração › Unidades. Os vínculos de cada pessoa ficam na aba Unidades do cadastro do usuário. Passo a passo em Login, usuários e unidades.