App de finanças pessoais para Android onde os dados vivem cifrados no aparelho, sem cadastro nem backend de usuários — construída, publicada e operada em produção por uma única pessoa: código, compliance legal e monitoramento.
01 · Contexto e problema
Tino é um copiloto financeiro para Android: os dados do usuário vivem cifrados no próprio aparelho, sem cadastro nem backend de usuários — a privacidade é uma propriedade da arquitetura, não uma promessa na política de privacidade.
Não é um repo de prática: eu levei do código à produção sozinho. Isso incluiu application id, LGPD/CDC, Termos de Uso e Política de Privacidade (site próprio), a ficha completa na Play Console (Data Safety, classificação de conteúdo, declaração de funções financeiras), um pipeline de identidade visual gerado por script, e monitoramento real em produção.
O problema técnico central: categorizar gastos com IA sem mandar cada transação para um LLM (custo, latência) nem expor dados sensíveis (CPF/CNPJ, cartão, PIX, e-mail, telefone) — numa app sem backend próprio para se apoiar.
Restrições
02 · Decisões técnicas
Armazenamento local cifrado
Problema
Os dados financeiros deviam viver só no aparelho, mas continuar consultáveis com relações estruturadas (categorias, orçamentos, transações) e cifrados em repouso, sem componente de servidor para o modelo de dados.
Opções
AsyncStorage/MMKV plano · Realm cifrado · SQLite sem cifrar + camada própria · Drizzle ORM sobre op-sqlite (SQLCipher)
Decisão ✓
Drizzle ORM sobre op-sqlite com SQLCipher: banco relacional cifrado em repouso, migrações tipadas, sem depender de um backend para o schema de dados.
Trade-off
O migrador que vem com o ORM tinha um bug real com DDL + defaults em SQLite, encontrado validando contra um banco real. Resolvido escrevendo um migrador próprio em vez de confiar no padrão.
Categorização com IA sem vazar PII nem pagar por cada transação
Problema
Queria categorização inteligente de gastos, mas mandar cada transação para um LLM é caro, lento e expõe dados sensíveis (CPF/CNPJ, cartão, PIX, e-mail, telefone) que um copiloto financeiro não pode filtrar.
Opções
IA por transação sem filtro · regras fixas sem IA · motor híbrido (regras → cache → fila de IA em lote) com anonimização prévia
Decisão ✓
Motor híbrido: regras determinísticas resolvem a maioria das transações sem tocar rede; o que não bate entra numa fila e é enviado em lote — Haiku para classificação, Opus para o chat —, sempre depois de uma função pura de anonimização de PII, testada isoladamente.
Trade-off
Mais peças do que 'manda tudo pra IA', mas a maioria das transações resolve de graça e no aparelho, e nenhum dado sensível sai cru.
Backend mínimo: proxy stateless em vez de backend de usuários
Problema
Precisava usar a API da Claude sem expor a key no cliente, para um app que se declara local-first e não quer construir um backend de usuários completo.
Opções
Backend completo com contas · SDK de IA embutido no cliente (key exposta) · Cloudflare Workers como proxy stateless
Decisão ✓
Cloudflare Workers (Hono) como proxy stateless: a key da IA vive só no Worker, com rate limiting e teto de gasto do lado do servidor; o Worker não persiste dados do usuário, só repassa a chamada já anonimizada.
Trade-off
Um salto de rede extra para a IA, em troca de zero superfície de backend de usuários para manter e gasto de IA limitado mesmo que o cliente seja comprometido.
Arquitetura
03 · Publicar sozinho, de ponta a ponta: quando o trabalho depois do código é metade do projeto
Levar o Tino de um repo à Play Store sozinho significou tratar tudo o que normalmente se divide entre papéis diferentes (jurídico, design, DevOps, PM) com o mesmo rigor do código.
Isso foi application id, LGPD/CDC, Termos de Uso e Política de Privacidade publicados em site próprio, e a ficha completa na Play Console: Data Safety, classificação de conteúdo e a declaração específica de funções financeiras.
Também um pipeline de identidade visual (ícone, splash e feature graphic gerados por script a partir de uma única definição) para não manter assets na mão, e monitoramento real em produção: Sentry configurado opt-in com um scrubber de PII —não é negociável num app que lida com dados financeiros—, Android Vitals e UptimeRobot vigiando o backend.
Resultado: um app financeiro em produção na Play Store, com prova fechada com testers reais em andamento, operado de ponta a ponta por uma única pessoa.
04 · De um repo à Play Store, sozinho
Application id, LGPD/CDC, Termos de Uso e Política de Privacidade em site próprio — não templates genéricos, adaptados ao que o app realmente faz com dados financeiros.
Ficha completa na Play Console: formulário de Data Safety, classificação de conteúdo e a declaração de funções financeiras que o Google exige para esse tipo de app.
Pipeline de identidade visual: ícone, splash e feature graphic gerados por script a partir de uma única definição, para não depender de retocar assets à mão a cada release.
Monitoramento de produção real: Sentry com scrubber de PII (opt-in), Android Vitals para estabilidade e desempenho, e UptimeRobot vigiando o backend — além de uma prova fechada com testers reais em andamento.
Demo interativa
Em breve: execute o código e veja-o rodando ao vivo, sem instalar nada.
Editor ao vivo (DartPad) — em breve
04 · Resultados · antes / depois
05 · Retrospectiva
Escreveria o migrador próprio desde o dia 1 em vez de confiar no do ORM: o bug com DDL + defaults em SQLite só apareceu validando contra um banco real, e custou tempo debugar algo que não era minha lógica.
Trataria o scrubber de PII como função pura e testada isolada desde o primeiro commit de IA, não depois: é a peça que menos margem de erro tolera, e por isso mereceu esse cuidado extra desde o início.
Escolheria de novo um proxy stateless num Worker em vez de um backend completo: num app que se vende como local-first, qualquer peça de servidor que não seja estritamente necessária é uma promessa quebrada.