Tablify: construindo um SaaS de gestão para restaurantes nas horas vagas
Nos últimos meses venho desenvolvendo o Tablify, um sistema de gestão para restaurantes, bares, pizzarias e lanchonetes, como projeto pessoal em paralelo ao meu trabalho full-time. A proposta é simples de descrever e bem mais difícil de executar bem: cardápio digital via QR Code, gestão de mesas em tempo real, painel de cozinha, controle de estoque, relatórios financeiros e um módulo de delivery próprio, uma alternativa direta ao iFood, sem comissão por pedido.
Esse post não é um discurso de "como validei meu SaaS e fechei clientes rapidamente". É sobre o que realmente aconteceu até agora: decisões técnicas, erros que cometi, e o tanto de trabalho que fica invisível quando alguém só vê a tela final.
A stack
Backend em Java 21 com Spring Boot, Thymeleaf para o server-side rendering, PostgreSQL com Flyway cuidando de todas as migrations, multi-tenancy via restaurante_id em praticamente todas as tabelas. A landing page é um site estático separado, em Astro com Tailwind. Tudo rodando em uma VPS única atrás de Nginx, com deploy automatizado via crontab lendo um JAR novo a cada 5 minutos.
Nada exótico. A escolha consciente foi não usar microsserviços, não usar Kubernetes, não sobre-engenheirar uma arquitetura para uma escala que ainda não existe. Um monólito bem estruturado, com isolamento de tenant no nível da aplicação, resolve o problema que eu tenho hoje.
O multi-tenant é mais sutil do que parece
A decisão de arquitetura mais importante do projeto foi isolar os dados por restaurante_id em vez de ter um banco por cliente. Funciona bem para a escala atual, mas essa escolha tem uma consequência que só fica óbvia quando você olha com atenção: toda query mal escrita custa caro para todo mundo, não só para o tenant dela.
Isso ficou claro numa auditoria de performance que fiz no código: nenhuma tabela tinha índice além dos que vêm de constraints UNIQUE. Toda consulta filtrando por restaurante_id, ou seja, praticamente todas, fazia um seq scan na tabela inteira, que cresce com o volume de todos os tenants somados, não só o daquele restaurante. Some isso a um problema clássico de N+1 nas associações EAGER de pedidos e itens (uma tela de cozinha fazendo polling a cada 3 segundos podia disparar mais de cem queries por chamada), e o resultado é um sistema que funciona liso com poucos dados e degrada de um jeito que pega todo mundo de surpresa conforme qualquer tenant cresce.
A lição prática: numa arquitetura multi-tenant compartilhada, "funciona bem no meu ambiente de teste com 3 restaurantes cadastrados" não diz nada sobre como o sistema se comporta em produção. Índice em coluna de tenant não é otimização prematura, é pré-requisito.
Segurança como processo, não como feature
Uma das decisões que tomei cedo foi tratar segurança como algo que exige revisão deliberada e recorrente, não como algo que se resolve "quando sobrar tempo". Isso incluiu passar o código por uma auditoria dedicada, indo além do funcional (o sistema faz o que deveria fazer?) para o adversarial (o que acontece se alguém tentar quebrar isso de propósito?).
Uma mudança concreta que saiu desse processo: nenhum segredo de produção (senha de banco, chave de API, credencial de e-mail transacional) fica hoje versionado no código. Tudo é carregado em tempo de execução via variável de ambiente, isolado do repositório. Parece básico, e é, mas é o tipo de prática que só vira hábito de verdade depois que você para para revisar com essa lente específica, em vez de só focar em fazer a feature funcionar.
O isolamento entre tenants também recebeu atenção redobrada: como o Tablify é multi-tenant com dados de vários restaurantes convivendo nas mesmas tabelas, cada consulta e cada escrita precisa validar explicitamente que o usuário só acessa e altera dados do próprio restaurante, e essa validação de posse foi revisada sistematicamente em todos os fluxos de escrita, não só nos de leitura.
Esse tipo de trabalho não aparece em nenhuma tela para o usuário final. Não é uma feature que se vende. Mas é a parte do projeto que, se malfeita, custa a confiança de todo mundo de uma vez, e por isso tratei como prioridade tão séria quanto qualquer funcionalidade nova.
Zero clientes pagantes, e o que isso me ensinou sobre priorização
Depois de meses de desenvolvimento, o Tablify tem hoje zero clientes pagantes ativos. Isso dói escrever, mas é a realidade e é mais útil do que fingir uma tração que não existe.
O primeiro erro de aquisição foi de mídia paga: rodei campanhas no Meta Ads com CTR alto e conversão zero, porque o objetivo da campanha estava configurado como "visualizações de landing page" em vez de conversão/mensagens, com segmentação geográfica ampla demais, jogando tráfego frio direto para uma tela de cadastro, o funil de maior fricção possível para quem nunca ouviu falar do produto.
O segundo aprendizado foi sobre onde investir esforço. Fiquei tentado, mais de uma vez, a construir feature nova (módulo financeiro mais robusto, programa de indicação, rede de revendedores) como resposta a objeções que eu imaginava que prospects teriam, sem nenhum prospect real tendo levantado essas objeções. Programa de indicação, em particular, é uma proposta que logicamente pressupõe ter clientes existentes para indicar. Sem cliente pagante, é esforço apontado para o lugar errado.
O que teve resultado real e mensurável foi SEO orgânico: páginas de blog segmentadas por cidade da região metropolitana de Fortaleza (Eusébio, Caucaia, Maracanaú, entre outras) alcançaram primeira posição no Google em menos de uma semana para termos de busca locais. Tráfego pago tentando comprar atenção cara; conteúdo específico e bem direcionado geograficamente trazendo gente que já estava procurando.
O que ficou como princípio
Algumas coisas que esse processo deixou claras, do jeito difícil:
- Índice em coluna de tenant não é luxo. Numa arquitetura compartilhada, é a diferença entre escalar e degradar para todo mundo junto.
- Segurança que "funciona nos testes manuais" não é segurança. Falhas de isolamento e de configuração costumam ser invisíveis até alguém procurar por elas de propósito, e o certo é procurar antes que alguém de fora precise fazer isso primeiro.
- Não construa para objeção hipotética. Feature nova antes do primeiro cliente pagante é aposta sem informação; conversa real com prospect é informação.
- Processo importa mais que ferramenta. Boa parte dos retrabalhos que tive não vieram de escolha errada de tecnologia, vieram de pular etapa, seja validar tenant antes de salvar, seja configurar corretamente o objetivo de uma campanha antes de gastar orçamento nela.
O Tablify segue em desenvolvimento. A prioridade agora não é feature nova, é consolidar a base de segurança e performance já revisada e conseguir o primeiro cliente pagante de fato, validando o que já existe antes de expandir o escopo.
Se você tem um restaurante na região de Fortaleza e quer testar, o Tablify está em tablify.com.br, com 14 dias grátis e sem cartão de crédito.