Fundador · solo (API + Web + Mobile) · do zero à produção em 5 meses. Em produção com assinantes pagantes e uso diário crescente - o foco agora é retenção. A Batameta diz pro motorista de app exatamente quanto ele precisa faturar hoje pra pagar as contas dele em dia, e avalia cada oferta de corrida no segundo em que ela chega pra ele saber se aceita. O produto tem 4 apps: site institucional em Next.js, admin em Next.js para a operação, mobile React Native (onde mora o Copilot nativo Android) e API NestJS sobre PostgreSQL multi-schema. Está em produção com motoristas reais usando todo dia.
O que ele resolve
Imagine um motorista com uma conta de R$ 800 que vence no dia 8. Ele tenta se planejar dividindo o valor pelos dias restantes do mês - mas a conta tá errada, a jornada não bate e a fatura escorrega. Multiplica isso por custos recorrentes (aluguel, seguro, combustível) e algum choque não-recorrente eventual (um pneu, uma revisão), e a maioria dos motoristas não consegue dizer se fechou o custo na semana. A Batameta transforma o modelo financeiro inteiro - contas com data de vencimento real, custos recorrentes, jornada de trabalho, faturamento acumulado - em um único número: 'sua meta hoje é R$ X.'
Como um motorista usa no dia a dia
O onboarding pergunta duas coisas: em quais dias da semana você trabalha e como são as contas + custos recorrentes. Daí em diante: abre o app no começo do dia, vê a meta diária num único número; liga o Copilot; dirige. No momento em que o Uber ou 99 mostra uma oferta, o Copilot classifica em verde/amarelo/vermelho sobre a tela, com R$/km, R$/hora, R$/min, tempo total e embarque → destino. Loga a sessão no final da rodada; a engine recalcula a meta de amanhã a partir do que você ganhou hoje e do que sobrou do mês.
A engine de metas
Meta mensal = recorrente + não-recorrente + lucro desejado + contas postergadas de meses anteriores, ponderadas pelo vencimento real de cada uma. Meta diária = (mensal − já ganho) ÷ dias úteis restantes, respeitando o padrão de jornada que o motorista escolheu. Quando bate a mensal, entra uma extra-diária baseada na própria média de ganho. Tudo isso chega como uma única notificação no começo do dia pra que o motorista abra o app já sabendo o que fazer.
Desafio: ler apps que não controlamos
O Copilot precisa ler cada oferta do Uber/99 no momento em que ela aparece, em tempo real, no celular do motorista. A gente não controla esses apps. Não dá pra entrar com código, não tem API pública, e a gente não quer screenshot saindo do device por questão de privacidade e custo. Qualquer coisa que faça o motorista tocar pra avaliar é lenta demais - a oferta expira.
Solução: bridge nativo no Android
Construí um módulo nativo em Kotlin que o React Native chama via bridge. Um AccessibilityService observa Uber/99 em foreground, atravessa a view tree e cai pra OCR via ML Kit quando a árvore está bloqueada. Parsers por app (UberParser, NinetyNineParser) extraem preço, distância, tempo, embarque, destino e nota. A avaliação roda 100% no device contra o perfil de custos do motorista em cache - a API só serve config de parser (cache de 1h). Zero chamadas por corrida significa privacidade preservada e Copilot funcionando até em conexão ruim.
Desafio: confiar no parser em aparelhos que eu nunca vou ter
Eu testo no meu celular. Os usuários têm milhares de outros - versões de Android diferentes, fabricantes diferentes, alterações específicas de cada OEM na view tree. A tela do Uber num Xiaomi com Android 12 não é o mesmo DOM de um Samsung com Android 14. Como saber se o parser tá pegando certo lá fora?
Solução: pipeline de telemetria anonimizada
Toda vez que uma oferta entra no Copilot, com consentimento explícito do usuário, o device manda um payload mínimo: o dado bruto extraído da tela, a saída parseada, versão do app, versão do módulo do Copilot, versão do Android, fabricante, endereço de embarque/destino bruto e parseado. Totalmente anonimizado - a gente não tem como mapear um payload de volta pra um usuário. Comparar bruto vs parseado em escala mostra exatamente em quais aparelhos o parser está falhando e onde ele precisa endurecer. O Copilot fica melhor quanto mais é usado.
Desafio: todo app de corrida muda a UI sem avisar
Uber atualiza um layout. 99 manda um redesign. iFood e InDrive não se parecem em nada. Hard-codar parser contra a view tree de hoje significa Copilot quebrado em uma semana e release de app emergencial toda vez que um vendor mexe.
Solução: core Open/Closed + parser hot-swap
O core do Copilot é fechado - não sabe nada de app específico. Cada integração entra como parser implementando um único contrato (extract → validate → emit). Config de parser vem da API e atualiza de hora em hora, então quebra de UI corrige sem release de app. Adicionar Uber, 99, iFood, InDrive ou o próximo app de corrida é parser plugando, nunca rewrite do core.
Plataforma de backend
NestJS event-driven + Prisma sobre PostgreSQL com 7 schemas isolados (customers, marketing, goals, finances, admin, payments, public) - bounded contexts com fronteira clara de ownership. RabbitMQ desacopla trabalho async, MongoDB guarda logs de evento de alta escrita, OpenAI cuida de enriquecimento de endereço ambíguo em fila separada. Pagamento é agnóstico por design: Stripe pra cartão, AbacatePay pra PIX nativo BR (cobrança + recorrência + webhooks). Os dois rails são idempotentes, reconciliação igual independente do provedor. Ativação orquestra push Expo, WhatsApp (WAHA), React Email + Resend, mais engine de referral/reward e módulo de gamification (badges, níveis, streaks).
Trade-offs que doeram
Só Android: AccessibilityService não tem equivalente no iOS pra ler tela de outros apps. Usuários iOS pegam a engine de metas e o lado financeiro, mas não o Copilot - é um gap real de produto. Rampa de permissão: AccessibilityService tem implicação séria de privacidade, então o onboarding tem que tomar tempo pra explicar o que ele lê e o que não lê; alguns motoristas desistem aí. Confiança na telemetria: o motorista precisa optar pelo pipeline de qualidade do parser; cobertura nos nichos de aparelho menores é mais lenta até a adoção crescer. PostgreSQL multi-schema é overkill na escala atual, mas adicionar domínio vira operação de schema em vez de rearquitetura - prefiro pagar essa complexidade agora do que depois.
- Por que Copilot nativo Android em vez de notificações in-app?AccessibilityService em Kotlin + OCR via ML KitUm avaliador de oferta precisa ler a tela do Uber/99 no momento que ela aparece sem modificar os apps deles e sem screenshot saindo do device. AccessibilityService é o único caminho. Avaliação 100% local mantém privado e zera custo de API por corrida.
- Por que config de parser server-side, avaliação client-side?Parser hot-swappable, avaliação localUber/99 mudam UI sem avisar. Puxar config de parser da API significa que corrigimos sem release de app. Mas avaliação fica local pra dado do usuário não sair do device e não pagar custo de rate-limit por corrida.
- Por que pagamento dual-rail (Stripe + AbacatePay)?Stripe + AbacatePayStripe é o rail internacional fácil de cartão, mas PIX domina BR e PIX recorrente pelo AbacatePay é dramaticamente mais barato que cartão pra persona motorista. Os dois rails rodam webhook-driven com idempotência, então reconciliação é idêntica.
- Por que PostgreSQL multi-schema (7 schemas) em vez de schema único?Schema por bounded-contextCustomers, marketing, goals, finances, admin, payments e public moram em schemas próprios. Bounded contexts ganham fronteira clara de ownership; backup, migration e até roles de acesso por domínio ficam simples. Adicionar domínio é operação de schema, não rearquitetura.
- Por que telemetria opt-in com bruto + parseado?Payload anônimo, bruto junto do parseadoNão dá pra validar qualidade do parser contra um ecossistema Android inteiro a partir de um único celular. Mandar o dado bruto da tela junto do parseado - anonimizado e com consentimento - mostra em escala onde o parsing diverge, em que versão do Android, fabricante e build do app, pra que o Copilot melhore quanto mais é usado em vez de degradar a cada layout novo do vendor.
- Por que integração de pagamento agnóstica em vez de travar num único provedor?Adapter agnóstico de provedorStripe e AbacatePay ficam atrás do mesmo contrato interno. Tratamento de webhook e reconciliação não sabem qual provedor gerou um evento. Se preço ou disponibilidade muda em qualquer um, trocar é config, não refactor - e um terceiro rail (um banco futuro, um PIX futuro) está a um adapter de distância.
No ar em produção com assinantes pagantes e uso diário crescente - o foco agora é retenção, transformar a Batameta em parte da rotina diária do motorista. Entregue: 4 apps em produção, o Copilot nativo na mão dos motoristas pela Play Store, pagamento dual-rail agnóstico (Stripe + AbacatePay), ~76 specs em Jest guardando o código e uma arquitetura Open/Closed pronta pro próximo app de corrida plugar.