Construindo uma Plataforma SaaS Multitenant com Java, Quarkus e AWS

Em mais de duas décadas desenvolvendo soluções em Java, tive a oportunidade de atuar na arquitetura de diversos sistemas SaaS. Alguns deles nasceram pequenos e escalaram rápido. Outros começaram grandes e precisaram de uma base sólida desde o primeiro deploy. Em todos, um desafio se repetiu: como construir uma arquitetura SaaS multitenant segura, escalável e sustentável no médio/longo prazo?

Neste artigo, compartilho como tenho estruturado esse tipo de plataforma usando Java com Quarkus, AWS e boas práticas que aprendi liderando times técnicos em produtos reais.


1. O que é SaaS Multitenant?

Vamos começar do começo. SaaS (Software as a Service) é um software que você oferece para várias empresas (clientes), geralmente pela internet. Multitenant significa que múltiplas empresas usam a mesma aplicação, mas cada uma vê e acessa apenas seus próprios dados.

Pense como um prédio com vários apartamentos: todos compartilham o mesmo prédio, mas cada morador tem sua chave e seu espaço.

O desafio está em garantir que:

  • Um cliente não veja dados de outro
  • Possamos isolar acessos, configurações e recursos
  • Escalemos sem precisar duplicar o sistema inteiro para cada novo cliente

2. Arquitetura Base com Java, Quarkus e AWS

Tecnologias que costumo usar:

  • Java + Quarkus: para ganhar performance e inicialização rápida
  • PostgreSQL (RDS): banco de dados relacional da AWS
  • Amazon Cognito: faz o login/autenticação dos usuários
  • S3 + CloudFront: para guardar arquivos e entregar conteúdo rápido
  • SQS e SNS: para comunicação entre partes do sistema sem travar tudo (eventos assíncronos)
  • SSM Parameter Store: para guardar senhas e configs com segurança
  • Terraform + GitHub Actions: para criar infraestrutura e fazer deploy automático

Estrutura do projeto:

  • core: onde ficam as regras de negócio (ex: cadastro de usuário, geração de relatórios)
  • infra: onde ficam os acessos ao banco, Cognito, S3, etc.
  • usecases: os casos de uso do sistema (ex: CriarTenantUseCase)
  • api: onde expomos os endpoints REST (ex: /v1/login)

3. Como isolar os dados de cada cliente

Imagine que você tem 3 clientes: Empresa A, Empresa B e Empresa C.

Você pode escolher entre:

  1. Um banco diferente para cada empresa
  2. Um único banco com um schema para cada empresa
  3. Um único banco com uma coluna “tenant_id” em todas as tabelas

Eu costumo usar a opção 3. Ela é mais simples de escalar, fácil de manter e permite centralizar os dados com controle via código. Em cada tabela do banco, adicionamos uma coluna tenant_id.

Como funciona na prática:

  • Exemplo de tabela:
CREATE TABLE usuarios (
  id SERIAL PRIMARY KEY,
  nome TEXT NOT NULL,
  email TEXT NOT NULL,
  tenant_id TEXT NOT NULL
);
  • Toda consulta ou inserção no banco inclui o tenant_id.
SELECT * FROM usuarios WHERE tenant_id = 'empresa_a';
  • No código, usamos filtros automáticos para evitar esquecer esse controle:
TypedQuery<Usuario> q = em.createQuery("SELECT u FROM Usuario u WHERE u.tenantId = :tenantId", Usuario.class);
q.setParameter("tenantId", tenantAtual);
  • Em frameworks como Hibernate, podemos usar interceptadores ou EntityListeners para adicionar o tenant_id automaticamente em cada operação.

Diagrama:

+-------------------------+
|    TABELA USUARIOS      |
+-------------------------+
| id         | 123        |
| nome       | João       |
| email      | joao@x.com |
| tenant_id  | empresa_a  |
+-------------------------+

Vantagens dessa abordagem:

  • Escala muito bem
  • Mais simples de gerenciar
  • Código único para todos os tenants

Desvantagens:

  • Requer atenção redobrada no controle de acesso
  • Não há isolamento físico, apenas lógico

Mas com boas práticas e validações, funciona muito bem.


4. Como fazer login com AWS Cognito

O Cognito é como se fosse um “login do Google” para o seu sistema. Você não precisa criar toda a lógica de autenticação, reset de senha, confirmação de e-mail, etc.

Como funciona:

  1. Criamos um “User Pool” no Cognito (tipo uma base de usuários)
  2. Cada usuário novo é criado lá, com o e-mail, senha, e o company_id
  3. Quando o usuário faz login, o Cognito devolve um token JWT com essas infos

No backend Java, usamos esse token para saber quem está acessando e a qual empresa pertence.

Configuração no Quarkus:

mp.jwt.verify.publickey.location=https://cognito-idp.sa-east-1.amazonaws.com/<pool_id>/.well-known/jwks.json
quarkus.oidc.enabled=true

Diagrama de fluxo:


5. Deploy automatizado por cliente com Terraform e GitHub Actions

Quando um novo cliente entra na plataforma, criamos automaticamente:

  • Bucket no S3 para guardar arquivos desse cliente
  • Entrada no SSM com as configs dele
  • Subdomínio no Route 53 (ex: empresa-a.sistema.com)
  • Parametrização no backend com tenant_id

Como fazer isso:

  • Usamos Terraform com variáveis por tenant
  • Criamos workflows no GitHub Actions que, ao detectar uma mudança ou nova empresa, executam a criação de tudo automaticamente

Diagrama:

[GitHub Actions]
       |
       | --> [Terraform Apply com tenant_id]
       |        |
       |        |--> cria Bucket S3
       |        |--> cria entradas no SSM
       |        |--> cria subdomínio

6. Como medir o uso e fazer billing (cobrança)

Você pode cobrar por:

  • Número de usuários ativos
  • Quantidade de relatórios gerados
  • Espaço usado em disco
  • Número de requisições

Como registrar o uso:

  • Criamos uma tabela usage_log
CREATE TABLE usage_log (
  tenant_id TEXT,
  action TEXT,
  timestamp TIMESTAMP DEFAULT now()
);
  • Cada vez que algo importante acontece, gravamos um log ali

Como cobrar:

  • Uma Lambda executa todo dia 1 e conta os logs do mês anterior
  • Disparamos uma cobrança com Stripe ou outro meio de pagamento

Diagrama:


7. Lições práticas que aprendi

  • Sempre tenha logs separados por empresa (ajuda no suporte)
  • Evite criar código fixo para um cliente: use configs e feature flags
  • Guarde tudo com rastro: tenant_id, user_id, horário, IP
  • Controle bem os acessos de “admin do sistema”
  • Comece simples, mas pensando em crescimento

Conclusão

Criar um sistema SaaS multitenant parece complexo, mas fica mais fácil com os conceitos certos e ferramentas adequadas. Com Java, Quarkus e AWS conseguimos montar uma base sólida, segura e escalável.

Se você está começando um SaaS ou tem um sistema que precisa evoluir, espero que esse guia te ajude. Se quiser trocar uma ideia sobre arquitetura ou tirar dúvidas, é só me chamar por aqui!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.