Rancho
Marketplace para pequenos mercados com inventário em event sourcing, Kafka para ingestão de catálogo em massa, pagamentos em PIX e Stripe. Três apps sincronizados em produção.
2025ProduçãoFundador & Arquiteto Full-StackMarketplaceE-commerceLogísticaFintechSaaS
- NestJS
- Prisma
- PostgreSQL
- Elasticsearch
- Kafka
- React Native
- Expo
- Next.js 15
- Stripe
- AbacatePay
- Docker
- Kubernetes
██+ vendedores, ██+ clientes
███+ pedidos/dia
<200ms API, <1s catálogo
50+ modelos, 3 apps
⚠️
Informações operacionais e comerciais protegidas por NDA. Métricas de usuários, volume de transações e MRR foram omitidos.
Impact
- Inventário com event sourcing: eventos RESERVE/RELEASE/STOCK_IN/ADJUSTMENT/RETURN com StockSnapshot para leitura rápida e ledger de eventos para auditoria. Transações atômicas garantem que nunca se vende além do estoque, mesmo com pedidos concorrentes.
- Ingestão de catálogo via Kafka: upload CSV/XLSX dispara um tópico, consumer valida e indexa no Elasticsearch, DLQ captura falhas. Admin vê progresso em tempo real com IDs de correlação por batch. Suporta 1000+ SKUs por upload.
- Hierarquia multi-nível: três tipos de usuário (CUSTOMER, SELLER, EMPLOYEE) com RBAC em quatro níveis. Vendedores com múltiplos mercados, funcionários com escopo departamental. Estrutura de árvore para franquias.
- Três aplicações compartilhando o mesmo schema Prisma: app React Native/Expo para iOS, Android e Web, API NestJS com 30+ módulos e docs OpenAPI automáticos, e dashboard admin Next.js 15 com analytics em tempo real.
KPIs
Modelos de BD
50+
Módulos API
30+
Aplicações
3 (Mobile, Backend, Admin)
Tipos de evento de estoque
6
SLA de pedido
<200ms
Importação bulk
1000+ SKU/batch
Processadores
Stripe + AbacatePay
Vendedores ativos
████████
Traction & Growth
Active Users
██+ vendedores, ██+ clientes
Paying Customers
████████
Monthly Price
████████ (tiered)
MRR
████████
Acquisition Channel
Vendas diretas, word-of-mouth, Meta Ads
Product-led growth: tier grátis para o primeiro mercado, upgrade ao adicionar mais locais. Taxa de sucesso de pagamento acima de 99%. LTV estimado R$ 4000 a R$ 6000 em 12 meses. NPS: 58.
Architecture
rancho-system-integration
Key Decisions
- Event sourcing para inventário em vez de campo de quantidade simples: Dois modelos ao invés de um, mas garante auditoria, habilita queries temporais e previne atualizações perdidas sob concorrência. Snapshots mantêm leituras O(1).
- Kafka para importação de catálogo em vez de processamento síncrono: Consistência eventual para produtos, mas suporta uploads de 1000+ SKUs sem bloquear. DLQ e retry dão confiança. A barra de progresso no admin mostra o que está acontecendo em tempo real.
- Elasticsearch junto do PostgreSQL: Indexação dupla tem custo, mas busca full-text com fuzziness e autocomplete seria impossível com LIKE. Consistência eventual em milissegundos é aceitável para catálogo.
- Expo para cross-platform em vez de apps separados: Algumas limitações nativas, mas um único codebase é iteração muito mais rápida. O ecosistema React Native cobre o que precisamos.
- Schema Prisma compartilhado entre as três apps: Mais simples que transações distribuídas, mas escalar serviços de forma independente fica difícil. Aceitável para a escala atual; sharding por market_id como saída se necessário.
Hard Problems
- Cem clientes comprando as últimas 5 unidades simultaneamente. Transações Prisma com RESERVE atômico garantem que o StockSnapshot.available_quantity seja decrementado antes de inserir o pedido. Race conditions impossíveis com o índice correto em product_listing_id + created_at.
- 5000 SKUs de um único mercado com enriquecimento de dados de fontes externas. O consumer Kafka valida, faz lookup, correlaciona e indexa no Elasticsearch. BatchJob + BatchJobItem com IDs de correlação permitem ao admin ver exatamente qual item falhou e por quê.
- 500 vendedores sem microserviços: isolamento via market_id em OrderItem, ProductListing e StockEvent. Middleware filtra por contexto do vendedor atual. Constraints de banco e triggers evitam leituras cross-market acidentais.
- Usuário paga em BRL via PIX AbacatePay; vendedor recebe em USD via Stripe. PaymentOrchestrator cria entrada de crédito após sucesso, vendedor saca para Stripe. Taxa de câmbio cacheada por hora. Cron diário reconcilia ledger com as APIs dos provedores.
- App mobile mostrava contagem diferente do dashboard admin por causa de reserves pendentes. Invalidação do cache StockSnapshot a cada novo StockEvent via webhook. Dashboard recebe mensagem via WebSocket. Mobile faz poll a cada 30s ou no app focus.
Ops & Runbook
- Se batch job fica em PROCESSING por mais de 5 minutos, alerta escala. Investigação: tail dos logs do Kafka consumer, verificar IDs de correlação em BatchJobItem. Timeout acima de 10 minutos: falha manual e retry.
- Cron noturno soma entradas StockEvent, compara com StockSnapshot atual. Mismatch acima de 5%: alerta para time ops. Resolução: force refresh e evento ADJUSTMENT.
- Cron às 02:00 UTC compara tabela Payment com invoices Stripe e transações AbacatePay. Caso comum: webhook recebido em duplicata, idempotency key resolvendo corretamente.
- Reindex do Elasticsearch em mudança de schema: deletar índice antigo, rodar reindex em massa do snapshot PostgreSQL, alternar alias. Buscas usam índice antigo durante a operação.
- Lag do Kafka consumer acima de 1000 mensagens: verificar latência de queries PostgreSQL, velocidade de indexação no Elasticsearch, timeout de lookup externo. Escalar instâncias de consumer se CPU acima de 80%.
Security & Privacy
- Queries filtradas por middleware seller_id. JWT do vendedor A não acessa dados do vendedor B. Constraints de banco e testes de integração verificam esse isolamento.
- Compliance PCI via Stripe e AbacatePay. Números de cartão nunca vistos pelo sistema. Assinaturas de webhook verificadas com HMAC-SHA256.
- @UseGuards(JwtAuthGuard, RoleGuard) em todos os endpoints. 403 retornado e acesso logado em auditoria para tentativas não autorizadas.
- IDs de correlação de batch jobs gerados server-side, não sequencialmente previsíveis. Mensagens de erro sanitizadas para não vazar detalhes de implementação.
- Snapshots diários para S3 com KMS. Point-in-time recovery dos últimos 30 dias. Testado mensalmente em ambiente staging.
- Rate limiting: 1000 req/min por IP para endpoints públicos, 5000/min por usuário autenticado para endpoints privados.
What I'd Improve Next
- Separar PaymentsModule em serviço independente via gRPC ou eventos. Requer banco por serviço, o que significa refatorar o schema Prisma compartilhado.
- WebSocket subscriptions para inventário em vez de polling a cada 30s. Menos drenagem de bateria no mobile.
- Previsão de demanda por ML com dados históricos de pedidos. Auto-sugestão de reposição de estoque para vendedores.
- Camada GraphQL para substituir os endpoints REST. Consultas mais eficientes no mobile, federação entre as três apps fica mais simples.