SaaS multi-tenant começa bonito no Figma e quebra no primeiro where esquecido. O front esconde o menu do outro estabelecimento. A API “já filtra pelo tenant logado”. Até alguém mandar um id na URL e ver a agenda do vizinho.
Isolamento de verdade não mora no componente. Mora na regra de leitura e escrita, validada em cada acesso ao dado.
O que o ForBarber já deixa público
Plataforma de gestão para barbearias: agendamento, cartão fidelidade, financeiro, equipe. Dezenas de estabelecimentos, cada um com clientes, barbeiros e números próprios. Nada pode vazar de um tenant para o outro — e o app precisa responder no pico da sexta, agenda cheia.
Três decisões de produto, do que o site já conta:
- isolamento de tenant por regra, validado em cada leitura e escrita no Firebase — o cliente A não lê documento do cliente B, mesmo que o front tente;
- acesso por papel (dono, gerente, barbeiro, recepção), cada barbearia com a própria hierarquia;
- mudança de plano que trava operação sensível sem derrubar sessão nem perder agenda em curso.
Isso é plataforma, não “um app com um if no React”.
O analítico também tem tenant
O ForBarber não para no agendamento. O transacional sai do Firebase para um PostgreSQL analítico via Airflow. Tabelas de faturamento, horário de pico, retorno da cartela, ticket por barbeiro. O dono vê isso no Power BI — só o que é dele.
Se o operacional isola e o painel mistura, o produto mente no fim do mês. Isolamento no banco vale para o extract também. Não invento métrica de receita nem quantidade de tenants aqui: o que importa é a regra, não o slide de escala.
O erro barato
Filtro no front é UX. tenantId só no client é esperança. A regra precisa falhar fechada: sem tenant no contexto, sem dado. Bug de tela não pode virar vazamento.
O mesmo princípio aparece noutro case, com outra stack: RLS no Postgres no Advocacia Web. Ferramenta diferente, tese igual.
Se o seu SaaS ainda confia no front para não misturar cliente, escreve.