Estudo de caso · P01
Minhas Contas
Sistema financeiro pessoal. Construído porque eu precisava.
Comecei com uma planilha que eu usava há anos para controlar meu dinheiro. Ela cresceu, ficou complexa, cheia de fórmulas frágeis — e um dia corrompeu. Então eu decidi construir o produto que eu realmente precisava.
Status
Em desenvolvimento
Stack
O Problema
Planilhas para controle financeiro pessoal têm um problema fundamental: elas são estáticas. Cada mês era uma aba nova. O saldo de fevereiro não sabia o que havia acontecido em janeiro. Parcelamentos precisavam ser atualizados manualmente. Cartões de crédito eram um pesadelo.
Tentei apps de mercado. Nenhum controlava o que eu precisava:
- →Múltiplos bancos com saldos independentes
- →Parcelamentos que se propagam automaticamente pelos meses seguintes
- →Benefícios VA/VR separados do dinheiro pessoal
- →Investimentos sem misturar com conta corrente
- →Sincronização entre dispositivos sem precisar abrir o computador
Decisão
Construir exatamente o que eu precisava. Sem tentar criar um produto genérico para todo mundo. Otimizado para o meu fluxo financeiro específico — e suficientemente estruturado para que qualquer pessoa com as mesmas necessidades possa usar.
Arquitetura e Decisões
A decisão mais crítica foi como modelar o banco de dados para que o saldo se propague entre meses automaticamente, sem recalcular tudo toda vez que um lançamento é adicionado.
Propagação de saldo
Cada mês armazena o saldo inicial (herdado do mês anterior) e os lançamentos do período. Ao atualizar um lançamento em março, apenas os meses posteriores são recalculados — não o histórico inteiro.
Firebase como backend
Escolha consciente: autenticação, banco de dados e hospedagem num único SDK. Para um projeto pessoal sem servidor dedicado, Firebase reduz fricção sem sacrificar consistência.
Firestore vs. SQL
Dados financeiros são hierárquicos por natureza (conta → mês → lançamento). Documentos aninhados no Firestore representam essa hierarquia melhor do que tabelas relacionais para esse caso específico.
Arquitetura reativa
onSnapshot em vez de chamadas pontuais. O estado da UI reflete sempre o estado do banco de dados — sem polling, sem cache manual.
Desafios Técnicos
Race Conditions no Firestore
Quando o usuário adiciona vários lançamentos rapidamente, múltiplos callbacks onSnapshot disparam quase ao mesmo tempo. Cada um lê o estado atual, calcula o novo saldo e tenta escrever de volta — resultando em estado inconsistente.
Solução: Mutex usando useRef para serializar operações de escrita. A fila garante que apenas uma operação acontece por vez, sem bloquear a UI.
const writeLock = useRef(false);
const writeQueue = useRef<(() => Promise<void>)[]>([]);
const enqueue = (op: () => Promise<void>) => {
writeQueue.current.push(op);
processQueue();
};
const processQueue = async () => {
if (writeLock.current) return;
writeLock.current = true;
while (writeQueue.current.length > 0) {
const op = writeQueue.current.shift()!;
await op();
}
writeLock.current = false;
};Modelagem de parcelamentos
Parcelamentos precisam aparecer nos meses corretos sem que o usuário configure cada parcela manualmente. A solução foi armazenar a parcela original com metadados (total de parcelas, data de início) e gerar as ocorrências em runtime — nunca duplicando dados no banco.
Isso significa que alterar o valor de um parcelamento atualiza todas as parcelas automaticamente, sem precisar editar cada mês individualmente.
O que foi construído
Múltiplos bancos
Saldos independentes por conta, propagados automaticamente entre meses.
Parcelamentos
Cartões com limite real. Parcelas que aparecem nos meses corretos sem configuração manual.
Faturas automáticas
A fatura fecha, os lançamentos se consolidam. Nenhuma soma manual.
Benefícios VA/VR
Saldo separado do dinheiro pessoal, com controle de uso diário.
Investimentos
Não misturado com conta corrente. Visão clara de patrimônio vs. liquidez.
Sync em tempo real
onSnapshot do Firestore. Abrir em dois dispositivos mostra o mesmo estado.
PWA
Instalável no celular. Funciona offline para leituras. Ícone na tela inicial.
O que aprendi
Modelagem no Firestore é diferente de SQL
Pensar em documentos ao invés de tabelas muda como você estrutura dados. A hierarquia natural dos dados financeiros se encaixa melhor em documentos aninhados do que em joins.
Race conditions são invisíveis até serem devastadoras
Aprendi a identificar operações potencialmente concorrentes antes de escrever. Qualquer operação que lê e escreve estado assincronamente é suspeita.
PWA é subestimado
A diferença entre abrir um link e ter um ícone na tela inicial muda o comportamento de uso completamente. Instalação é retenção.
Produto ao vivo