APM SaaS.
O caixa da associação de pais e mestres, com regras que o próprio banco garante.

O problema
A APM de uma escola mexe com dinheiro das famílias, troca de diretoria a cada mandato e precisa prestar contas. A contribuição é associativa, não é mensalidade. Os dados são de alunos, então a LGPD vale. Se um lançamento puder ser editado depois, ninguém mais confia no saldo.
O que construí
Escrevi tudo sozinho: caixa, contribuições, projetos, importação de extrato com parser OFX, prestação de contas e a passagem de mandato de uma gestão para a outra. As notificações respeitam uma janela de silêncio das 21h às 8h. As regras mais importantes não ficam no código da aplicação. Elas estão no banco, e os testes quebram se alguém esquecer delas.
Decisões técnicas
01A regra mora no banco
33 tabelas com FORCE ROW LEVEL SECURITY, 38 policies, 11 funções SECURITY DEFINER, 3 constraint triggers e um EXCLUDE. Se a aplicação tiver um bug, o Postgres ainda recusa o dado que quebra a regra.
02Ledger que não se edita
Lançamento não é alterado nem apagado. A correção é um estorno, que fica no histórico. O dinheiro é guardado em centavos, como inteiro. Sem ponto flutuante, sem centavo sumindo no arredondamento.
03Testes que cobram toda tabela
rls.test.ts falha se existir tabela sem policy, e audit.test.ts falha se existir tabela sem auditoria. Tabela nova não entra desprotegida por esquecimento. Os testes rodam contra um Postgres de verdade, com Testcontainers.
Onde está no código: rls.test.ts · audit.test.ts
04Nenhuma chamada HTTP dentro de transação
O que precisa sair do sistema vai para um outbox e é processado por jobs no pg-boss, fora da transação. Os jobs são idempotentes, e um teste roda o job de novo para provar isso. Uma API externa lenta não segura lock no banco, e um retry não duplica nada.
Números
31
commits, autor único
~165
testes
37
tabelas
15
migrações
Stack
- TanStack Start
- React 19
- Better Auth
- PostgreSQL
- Drizzle
- Zod 4
- Tailwind 4
- pg-boss
- Vitest
- Testcontainers
- Playwright
Telas


CRM Next