O CMS Headless, Multi-Idioma e Multi-Tenant Que Serve Agências Inteiras de uma Única Plataforma
SaaS Próprio
Developer tools, agências e múltiplos sites
Arquitetura, desenvolvimento, infraestrutura e operação
Produção Contínua desde 2025
O Rush CMS é meu SaaS: um CMS headless multi-tenant construído em Laravel 12 e Filament 4 para quem gerencia muitos sites ao mesmo tempoL agências e operações com dezenas de domínios sob o mesmo teto. Em vez de manter 50 instalações separadas de WordPress, uma única instância Laravel serve todos os clientes com isolamento de dados, cada um com seu conteúdo, seus usuários, suas permissões e sua API.
Diferente do resto do meu portfólio, este não é um projeto de cliente. É um produto que eu arquitetei, construí e mantenho sozinho, de ponta a ponta: do modelo de dados à infraestrutura, do painel administrativo à camada de API, do isolamento de tenant ao pipeline de 603 testes. É a peça onde minhas decisões de engenharia aparecem sem intermediário, porque cada uma foi minha.
E ele já está em produção. O próprio site que você está lendo, o rafhael.pro, roda em Rush CMS. Uma padaria com cardápio digital completo também. Casos de uso radicalmente diferentes servidos pela mesma base, que é exatamente o ponto de um CMS multi-tenant eficiente. O produto vive em rushcms.com.
O problema que o Rush resolve
Quem mantém muitos sites pequenos e médios conhece a dor: cada site vira uma instância separada de WordPress (ou similar), com sua própria atualização, seu próprio backup, sua própria superfície de ataque, sua própria conta de hospedagem. Dez sites viram dez sistemas para manter. Cinquenta viram um pesadelo operacional.
A alternativa óbvia, "um WordPress multisite", resolve parte do problema e cria outros: acoplamento entre sites, plugins que quebram todo mundo de uma vez, e um modelo de conteúdo preso a "posts e páginas" que não cabe em quem precisa de estruturas de dados próprias. Outro motivo: eu detesto ter que mexer com Wordpress, quando preciso muito, tenho que usar Sage para sofrer mentalmente menos.
Eu queria outra coisa: uma plataforma onde adicionar um novo site fosse adicionar um tenant, não subir um servidor. Onde o modelo de conteúdo fosse definido por quem usa, não imposto pela ferramenta. E onde a performance de entrega não dependesse de cache improvisado em cima de um sistema lento por natureza.
"Ah, mas e o Strapi? Existem diversas soluções no mercado", sim existe, e nenhuma me atendeu da forma que eu precisava - e queria. i18n first, multi-tenant isolado de fábrica, collections com databases, etc.
As decisões de arquitetura
Este é o coração desse case, porque o Rush CMS é, antes de tudo, um conjunto de decisões técnicas conscientes. Cada uma tem um porquê.
Multi-tenancy com isolamento real via global scopes
Os tenants são 100% isolados, e não existe um super-admin que enxerga os dados de todos os clientes, essa foi uma decisão deliberada de segurança e privacidade. O isolamento é feito por um global scope no Eloquent: toda query de um modelo tenant é automaticamente filtrada por site_id a partir do tenant resolvido pelo Filament. O resultado é zero vazamento de dados entre sites, com a regra de isolamento explícita no código e coberta por testes, não escondida atrás de mágica de framework.
Num produto multi-tenant um bug que vaza dados de um cliente para outro não é um bug comum, é um incidente de segurança. Por isso o isolamento é testado, não confiado.
Modelagem de conteúdo dinâmica em PostgreSQL com JSONB
Esta é a decisão mais importante do projeto. Em vez de criar uma tabela e uma migration para cada novo tipo de conteúdo, o Rush armazena o schema das Collections e os dados das Entries em JSONB no PostgreSQL, com índices GIN para busca. Na prática: um usuário pode criar uma nova Collection, com seus próprios campos, sem que uma única migration rode no banco.
Isso é o que permite o sistema de Collections no estilo Notion/Statamic: listas e bancos de dados que o usuário monta sozinho, podendo inclusive encadeá-los como dependências hierárquicas. Marcas de carro que se desdobram em modelos. Estados que se desdobram em cidades, em cascata reativa. Ou algo simples como uma lista de "tipos de tecnologia" aplicada a uma collection para virar um campo de seleção na hora de criar uma entry.
O modelo de dados deixa de ser definido por mim, no código, e passa a ser definido por quem usa, em runtime.
Geração de classes PHP em runtime para Custom Blocks
Este é um truque técnico, os Custom Blocks do editor de conteúdo são definidos pelo usuário no banco de dados, com {nome, ícone, campos}, e precisam virar classes PHP reais para o editor (Filament RichEditor/TipTap) reconhecê-los. A primeira abordagem foi class_alias(), mas ela tem uma limitação: dentro do método, static::class continua retornando a classe base, então o bloco não sabe quem ele é. A solução foi gerar subclasses reais em runtime via eval(), onde cada bloco conhece o próprio slug.
Usar eval() é o tipo de decisão que exige justificar o trade-off de segurança: o template do código é hardcoded, a única parte dinâmica é o slug (validado pelo banco e sanitizado via Str::studly()), e nenhum input de usuário chega ao eval(). É uma solução certa para um problema real, com o risco mapeado e contido.
Performance de entrega
Octane + RoadRunner com respostas abaixo de 20ms
Um CMS headless vive ou morre pela latência da API, é ela que alimenta os frontends. Rodo o Rush sobre Laravel Octane com RoadRunner, mantendo a aplicação viva em memória entre requisições em vez de subir e derrubar o framework a cada chamada. O resultado são respostas de API de ~20ms em endpoints simples e ~50ms nos complexos, rápidas o suficiente para servir sites SSR e estáticos via SSG com webhooks de rebuild, com cache de API no Redis por cima.
Operar Octane impõe disciplina: estado compartilhado entre requisições é uma armadilha, o código foi escrito com isso em mente, sem propriedades estáticas acumulando dados de request, injeção de dependência em vez de singletons com estado, e workers que reciclam a cada 10.000 jobs para conter vazamentos de memória.
i18n desde o dia 0
O Rush é 100% i18n-first: foi pensado em multi-idioma desde a base. É possível criar entries e outros conteúdos em múltiplos idiomas nativamente, e a própria plataforma está disponível em português e inglês. Internacionalização nesse CMS faz parte da estrutura. Ela veio assim por que o meu site tem a necessidade real de ter mais de um idioma, e na minha filosofia para esse projeto, se o Rush CMS não atender 100% o meu próprio site, ele não irá atender mais ninguém.
Nota: o repo desse site é público, você pode acessar em https://github.com/rush-cms-showcase/rafhael, essa org possui todos os sites de clientes que permitiram o repositório público.
O que o Rush faz
Por baixo dessas decisões, o Rush é um CMS completo, não um protótipo:
- Collections personalizáveis com 13+ tipos de campo e um sistema de listas/bancos reutilizáveis e encadeáveis como dependências
- Custom Blocks gerados em runtime, com editor de conteúdo estilo TipTap e blocos prontos como YouTube e galeria com lightbox
- Block builder de homepage para montar a página inicial na plataforma
- Form builder com captura automática de UTMs/referrer e disparo de e-mails para empresa e remetente
- Menu builder hierárquico com tags, categorias e webhooks
- Sistema de membros para sites com conteúdo exclusivo por área logada
- Gestão de usuários e papéis com 100+ permission nodes, no padrão
ação:recursodo Filament - Integração com Google Analytics via OAuth2
- Importador de WordPress que converte HTML em blocos, com preview e dry-run
- Integração MCP para controlar o CMS via LLM (ChatGPT, Claude) por linguagem natural, com tokens isolados por tenant
- Conversão automática de imagens para WebP em todos os campos de imagem, com 50-70% de economia de espaço
- Plataforma bilíngue (pt-br/en) completo
A engenharia por trás
O que torna o Rush sustentável a longo prazo não é a lista de features, é o rigor por baixo delas:
- 603 testes automatizados com Pest
- PHPStan/Larastan Level 5 para análise estática e detecção de erros antes do runtime
- Laravel Pint
- CI/CD via GitHub Actions rodando testes, análise estática, code style, auditoria de segurança e build do frontend a cada push
- Eliminação sistemática de N+1 usando eager loading e cache em Redis
- Documentação como código, no estilo ADR: Cada decisão de peso está registrada
A infraestrutura
O Rush roda em servidores Hetzner gerenciados via Coolify, com PostgreSQL 16, Redis 7, Nginx e Supervisor para os queue workers. É uma escolha de self-hosting que mantém um custo baixo e previsível, a operação inteira fica na casa de poucas dezenas de reais por mês, mantendo o controle total sobre a VPS.
Erros do Sentry, backup automatizado para S3 com lifecycle policy, e monitoramento fecham essa conta, o mesmo princípio que guia o código guia a infra: a solução mais simples e direta que entrega o resultado, sem complexidade desnecessária.
Resumindo, o que esse projeto demonstra?
O Rush CMS é uma prova de conceito ambulante, ele mostra três coisas que um case de cliente raramente consegue mostrar com a mesma clareza:
- Profundidade arquitetural. - As decisões difíceis, como isolamento de tenant por global scope, modelagem dinâmica em JSONB, geração de classes em runtime, performance via Octane, a migração medida para PostgreSQL, foram todas tomadas e defendidas por mim, e estão em produção sustentando dados reais de clientes reais.
- Manutenção de longo prazo. - Depois do MVP é que o bicho pega, manter um produto multi-tenant vivo, testado e rápido ao longo de meses, com CI/CD e documentação de decisões, é uma demonstração de manter um projeto em produção.
- Pragmatismo sob restrição. - Um único desenvolvedor com infraestrutura barata, stack enxuta, e ainda assim um CMS arquitetado para 50+ sites isolados, servindo abaixo de 20ms. Mostra que não precisa ter recursos infinitos, mas tomar a decisão certa em cada bifurcação.