Pitch: Criei um assistente de finanças "Local-First" com Rust e Tauri - Conheçam o Visconde
Olá pessoal, tudo bem? Primeira vez escrevendo por aqui! Acompanho o TabNews há algum tempo, mas nunca fui um leitor assíduo. E tenho que dizer, é lindo ver quantos especialistas brasileiros nós temos. Podemos ter perdido a copa, mas no jogo da engenharia de software, sem dúvida estamos no jogo!
Estou aqui pra falar de um projeto pessoal. A inspiração para esse aplicativo veio de uma lembrança de uns 15 anos atrás: eu observava meu avô, já idoso, usando o computador para pagar contas no Internet Banking da Caixa. Ele faz falta <3. Meu avô, um contador meticuloso, todos os meses pegava a fatura do cartão de crédito, conferia item por item e somava tudo na mão para garantir que o valor total do banco estava correto.
Sinto que que essa atenção aos detalhes e o desejo de ter controle absoluto sob o próprio dinheiro parecem ter se perdido.
Então você criou mais um app de finanças? Mais um SaaS pra coleção?
Não é mais um SaaS. Não tem API. Não tem banco de dados. Optei por algo fácil e barato de ser mantido, já que só consigo trabalhar nele em meu tempo livre. Um app desktop rápido, leve e com uma experiência única, usando matemática e regras contábeis reais para ser um verdadeiro assistente pessoal de finanças.
A Filosofia:
- Privacy by Design: Zero telemetria. Zero analytics. Com a evolução do Visconde, pretendo coletar dados de uso anônimos (se assim o usuário desejar) no futuro.
- Local-First: O banco de dados (SQLite) vive apenas no dispositivo do usuário.
- Ele não é apenas um "rastreador de gastos do mês", ele é um simulador de vida financeira.
- Ele entende a matemática financeira brasileira rodando quase 100% offline.
A Stack Tech
Para manter o aplicativo rápido e não depender de nuvem, tomei algumas decisões de arquitetura que acho que podem ser úteis para quem está criando projetos por aqui:
1. O App: Tauri v2 + Rust + React (TypeScript)
Fugi do Electron. Embora eu já tivesse experiência com ele, decidi ir por outro caminho e aproveitar para aprender coisas novas. Usando Rust e Tauri, o Visconde consome uma fração da RAM, cerca de 45Mb. A lógica de cálculo pesado e o acesso ao SQLite ficam encapsulados no backend em Rust, enquanto a interface usa React e Tailwind CSS no frontend.
2. O Banco de Dados: SQLite local
Tive dúvidas sobre o SQLite, mas ele se mostrou ser a melhor escolha. O tempo de resposta para ler, simular ou gravar uma operação complexa de amortização é virtualmente zero, limitado apenas pelo armazenamento do dispositivo.
Utilizei a lib rusqlite_migration para que as alterações no banco de dados sejam feitas na inicialização da aplicação, garantindo que usuários que possuem uma versão antiga consigam usar novas funções sem perder os dados antigos.
3. Criptografia "Nível Enterprise": Key Wrapping e Palavras de Recuperação
Como o app gerencia o patrimônio e os dados sensíveis dos usuários, deixar o SQLite em texto puro estava fora de cogitação. Implementei um sistema de multi-perfis isolados, onde cada banco de dados é criptografado via SQLCipher (PRAGMA key).
Mas o detalhe arquitetural que mais me orgulho aqui foi ter fugido da criptografia simples e implementado um sistema de Key Wrapping nativo em Rust.
Em vez de usar a senha do usuário para encriptar os dados diretamente, o sistema gera uma Master Key (MK) única para o banco. A senha do usuário serve exclusivamente para derivar uma chave que descriptografa essa MK.
Isso traz duas vantagens técnicas interessantes:
-
Troca de Senha Instantânea (O(1)): Se o usuário quiser mudar a senha, eu não preciso descriptografar e re-criptografar o arquivo SQLite inteiro. Eu apenas pego a Master Key, descriptografo com a senha velha e "empacoto" (wrap) novamente com a senha nova.
-
Sistema de Fallback: Como podem ver na lógica do backend, caso a senha padrão falhe, o sistema testa automaticamente se a chave recebida bate com o hash das Palavras de Recuperação (mk_hash_recovery). Isso garante que o usuário nunca perca o acesso ao próprio patrimônio, mantendo a segurança zero-knowledge.
O código ficou mais ou menos assim:
// Tentativa com a senha principal (Key Wrapping)
let mut mk_result = crate::security::decrypt_master_key(mk_enc, &pass, salt);
// Fallback nativo: Se falhou com a senha, tenta abrir com as palavras de recuperação
if mk_result.is_err() {
if let (Some(mk_rec), Some(salt_rec)) = (&profile.mk_hash_recovery, &profile.salt_recovery) {
mk_result = crate::security::decrypt_master_key(mk_rec, &pass, salt_rec);
}
}
Vem conhecer o Visconde! Adoraria seu feedback
Acabei de lançar a versão Alpha! Ele já é funcional e os simuladores estão rodando de maneira bem aceitável. Eu adoraria um feedback sincero dessa comunidade high tech: testem a usabilidade, as fórmulas matemáticas e fiquem à vontade para inspecionar como os dados são salvos localmente.
Vocês podem ver as telas, os módulos disponíveis e baixar o instalador (por enquanto somente para Windows) no site oficial. Só um detalhe, ainda não assinei o executável do instalador (vai aparecer um aviso do Windows Defender aí na sua máquina), pois isso também tem um custo, mas assim que eu fizer isso crio um novo post discutindo a engenharia de assinatura e técnica de baixo custo que está disponível com as ferramentas atuais.
Se alguém tiver dúvidas sobre como configurar o Tauri v2 na prática, ou quiser discutir a abordagem Local-First para dados sensíveis, deixem nos comentários! Vou tentar responder a todos.
Fonte: https://visconde.app