LUCAS KARSTEN DEV SÊNIOR · IBIRAMA, SC, BR

Construí sozinho um SaaS B2B
com IA. Do banco ao billing.

Sou dev há sete anos, quase tudo em sistema empresarial: ERP, CRM, integração bancária. No último ano fiz o mibi inteiro sozinho. Abaixo tem um bug que me custou umas boas noites. Lê o código e decide se vale a conversa.

O search_path não sobrevive ao pooler

Cada cliente do mibi fica num schema Postgres separado. Trocar de schema por requisição parece trivial: chama set_config('search_path', ...) e segue. Só que o Neon roda PgBouncer em modo transação, e aí a conexão só fica presa a um backend fixo dentro de uma transação. Meu search_path valia pro primeiro statement e sumia no segundo, que caía em outro backend. Deu 42P01 relation "candidate" does not exist, intermitente, só em produção, só sob carga.

// is_local=true (SET LOCAL): preservado pelo pooler em modo transação.
await client.query("BEGIN");
await client.query("SELECT set_config('search_path', $1, true)", [safe + ", public"]);
// app.current_tenant tem que bater com o search_path, senão a policy
// RESTRICTIVE tenant_schema_guard bloqueia tudo, calada.
await client.query("SELECT set_config('app.current_tenant', $1, true)", [safe]);

O nome do schema passa por allow-list antes de chegar no banco. E se o reset do search_path falhar, eu destruo o client em vez de devolver pro pool. Um client sujo voltando pro pool atende a próxima requisição, de outra empresa, apontando pro schema errado.

A nota completa, com o código e as outras duas armadilhas →

Como eu trabalho

Hoje qualquer pessoa coloca um app no ar com Claude Code, e o meu também saiu assim. A diferença aparece nas decisões que quem só tem a ideia não sabe que precisa tomar. O que acontece quando o modelo responde errado. Quem apaga o dado quando o candidato pede. Como voltar o banco se a migration subir quebrada. Quanto custou a chamada de ontem. A lista abaixo é o que eu levo pra qualquer projeto, e costuma valer mais que o produto que eu construí com ela.

Stack

Linguagem
TypeScript · Node · React 19 · Next.js 16
Infra
Vercel · GitHub Actions · Vercel Blob
Banco
Postgres no Neon · node-pg-migrate · RLS
IA
Anthropic Claude (SDK) · custo por chamada rastreado
Pagamento
Stripe
E-mail
Resend · domínio verificado, SPF e DKIM
Observabilidade
Sentry · PostHog
Testes
Jest · Playwright (e2e e visual) · SWC
Segurança
bcrypt · jose (JWT) · otpauth (2FA) · DOMPurify · validação de upload por file-type · geo-blocking
Validação
Zod em toda entrada de API
Documentos
unpdf, mammoth e csv-parse para ler CV em PDF, DOCX e planilha
Antes
GeneXus · Oracle · SQL Server · C#/.NET · JavaScript

O que tem dentro do mibi

Produto
mibi.app.br ↗
Papel
Fundador e único desenvolvedor
Arquitetura
Multi-tenant, um schema Postgres isolado por cliente
IA
8 agentes Anthropic Claude, custo medido por chamada
Conformidade
LGPD: anonimização, consentimento versionado, Art. 20
Billing
Stripe, 4 planos + enterprise
Estado
No ar. Sem cliente pagante ainda.

Arquitetura do mibi

Cada empresa cliente vive em um schema Postgres isolado. As requisições passam por uma API REST que ajusta o search_path e o contexto de RLS, e chegam a oito agentes Claude especializados, que devolvem um score auditável de zero a cem. TENANTS schema · cliente A schema · cliente B schema · cliente C schema · cliente D BORDA API REST search_path + RLS AGENTES CLAUDE triagem de CV entrevista assíncrona scoring 0-100 + 5 agentes especializados
Um schema por cliente, um agente por tarefa. A trilha de decisão fica registrada porque o Art. 20 da LGPD exige.

O que eu pego como freela

Antes disso

Cinco dos sete anos foram GeneXus, ERP e sistema financeiro. Não é stack que impressiona startup, mas foi ali que eu aprendi a mexer em código que fecha o mês de uma empresa, onde migração errada não tem ctrl+z. Legado não me assusta, passei metade da carreira dentro de um.

  1. 2025–CynclyDev sênior · ERP de varejo · GeneXus, Oracle, C#/.NET
  2. 2025DatainfoDev sênior · sistemas para educação
  3. 2021–25eSalesGerenciador financeiro · integração bancária e cobrança
  4. 2020–21SiscobraMigração de sistemas legados
  5. 2018–19EvolutizeManutenção e evolução de ERP

Como eu fecho um projeto

Disponibilidade
Sou CLT em tempo integral. O freela sai à noite e no fim de semana, de 10 a 15 h por semana.
Formato
Escopo fechado, combinado antes de começar. Não pego alocação por hora nem plantão.
Tamanho típico
De 40 a 120 horas. Nessa carga dá 1 a 2 meses de calendário. Combino prazo por data, não por esforço.

Tem algo parado no backlog?

Me conta em duas linhas o que é. Se não for pra mim, eu digo na resposta e paro por aí.

contato@lucaskarsten.com.br