Pular para o conteúdo
Neto Alves
Voltar

OSCapstack CRM

Sistema operacional comercial para originação de crédito imobiliário, em produção.

OperacionalProprietário

Desenvolvimento full-stack, de ponta a ponta · 26 dias de construção

RLS policies
146
telas
42

01 Problema

A operação inteira rodava em planilha. Lead chegava por três canais — Instagram, LinkedIn e WhatsApp — e era copiado à mão; ninguém sabia de cabeça quem já tinha sido atendido, e agenda, proposta e documento viviam cada um num lugar diferente. O produto tinha que virar o sistema operacional da corretora, não uma planilha com verniz.

02 Arquitetura

Monorepo TypeScript com Fastify 5 na API e Supabase/PostgreSQL como banco. Três frontends isolados: painel administrativo em React, painel do consultor externo (acesso restrito, dados só do que é dele) e uma landing em Astro para captação. São 56 tabelas com 146 RLS policies, 219 endpoints e 42 telas. Em produção em os.capstack.capital.

03 Decisões difíceis

146 RLS policies em 56 tabelas

A autorização mora no banco, não na aplicação: cada tabela tem suas próprias políticas de row-level security, então um bug na API não vaza dado de outro consultor. O custo é performance — toda policy roda uma função de contexto por linha — resolvido reescrevendo os helpers como subquery escalar, para o planner do PostgreSQL avaliar uma vez por consulta em vez de uma vez por linha (otimização de InitPlan).

Deploy blue-green em VPS

A cada deploy, a nova versão sobe numa porta separada da que está servindo. Um health-check de 15 tentativas decide se ela está saudável antes de qualquer usuário ser roteado para lá. Se falha, o container novo é removido e o antigo continua servindo — o pior caso de um deploy ruim é o deploy não acontecer, nunca um ar fora do ar.

Dead man’s switch do WhatsApp

Um container pode responder 200 no health-check HTTP e ainda assim estar com a instância do WhatsApp desconectada — é uma falha que nenhum probe HTTP convencional enxerga. Um cron de 2 em 2 minutos consulta o estado real da conexão; se caiu, ele para de pingar o healthchecks.io de propósito, para que o serviço externo dispare o alarme pela ausência de sinal.

Roleta ponderada segura sob concorrência

A distribuição de leads usa peso por consultor (clientes_ativos / peso), mas dois leads chegando ao mesmo tempo não podem cair no mesmo consultor por uma leitura desatualizada. A escolha do cliente e do consultor usa SELECT … FOR UPDATE dentro de uma única transação, serializando a leitura-e-escrita sem lock de tabela inteira.

04 Stack

  • TypeScript
  • Fastify 5
  • Supabase
  • PostgreSQL
  • React
  • Astro
  • Playwright
  • pgTAP
  • Docker

05 O que mudou

Os três canais passaram a cair num lugar só, e o lead é distribuído na hora — por roleta ponderada ou direcionado a um consultor. A agenda sincroniza com o Google Calendar, documento de cliente é lido por IA em vez de conferido à mão, a mensageria responde sozinha o que é repetitivo, e o relatório de performance chega com o que a IA achou fora do padrão. Admin e vendedor têm cada um o seu app. E o dono monta o próprio funil e as próprias automações: mudar uma regra do processo deixou de depender de mim.