Como estou construindo um ERP com Node.js e MongoDB
A jornada real de construir o StockPro: decisões de modelagem, por que escolhi MongoDB e o que aprendi resolvendo problemas de estoque em produção.
Construir um ERP do zero não é escrever CRUDs. É modelar regras de negócio que mudam toda semana, lidar com consistência de estoque em tempo real e aceitar que a primeira versão do seu modelo de dados vai estar errada.
Por que comecei com MongoDB
A maioria dos tutoriais de ERP empurra PostgreSQL. Fui na contramão porque:
- Documentos aninhados refletem bem entidades como produto + variações + movimentações.
- A equipe com quem trabalho já tinha operação em Mongo.
- Eu precisava iterar rápido no schema — e
$seté mais barato que migração.
Obviamente existe preço. Transações em Mongo funcionam, mas você precisa de replica set e atenção com idempotência.
O modelo de estoque (simplificado)
interface Product {
_id: ObjectId;
sku: string;
name: string;
variants: Variant[];
}
interface StockMovement {
_id: ObjectId;
productId: ObjectId;
variantSku: string;
type: "IN" | "OUT" | "ADJUST";
quantity: number;
reason: string;
occurredAt: Date;
}
A regra de ouro que eu quebrei e aprendi do jeito difícil: saldo nunca é armazenado como campo mutável. Saldo é projeção das movimentações. Se você confia em um stock: number atualizado por código, em 3 meses ele vai divergir. Sempre.
Como calculo o saldo
Um pipeline de agregação rodando em cache com invalidação por evento:
db.movements.aggregate([
{ $match: { variantSku: "CAM-AZ-M" } },
{ $group: {
_id: "$variantSku",
total: { $sum: {
$cond: [{ $eq: ["$type", "OUT"] }, { $multiply: ["$quantity", -1] }, "$quantity"]
}}
}}
])
O que eu faria diferente
- Ter começado com event sourcing leve desde o dia 1.
- Separado read models (listagens) de write models (movimentações).
- Não ter subestimado o quanto o usuário final quebra regras — sempre.
ERP é 20% de código e 80% de conversa com quem usa o sistema.
Nos próximos posts vou abrir as partes de precificação e a integração com Fluig.
Gostou do post?
Compartilha com alguém que tá resolvendo o mesmo problema.