Stack e escolhas
As tecnologias que sustentam a Conta e o motivo de cada uma ter sido escolhida.
O quadro geral
| Camada | Escolha | Por quê |
|---|---|---|
| Framework | Next.js 16 (App Router, Turbopack) | Server Components reduzem o JS enviado; o mesmo projeto serve UI e as poucas rotas de servidor |
| UI | React 19 + Tailwind 4 | Tailwind 4 configura o design system em CSS, sem arquivo de config JS |
| Linguagem | TypeScript estrito | Sem any, com noUncheckedIndexedAccess — acesso indexado devolve T | undefined |
| Chain | viem | API tipada e explícita; sem a superfície de legado do ethers |
| Auth e carteira | Privy | Passkey + carteira embutida sem que a chave passe por nós |
| Banco | Supabase (Postgres) | Postgres gerenciado com boa DX; usado como cache, não como autoridade |
| Validação | Zod | Um schema por fronteira: toda rota de API e todas as variáveis de ambiente |
| Observabilidade | Sentry | Captura de erro no cliente, servidor e edge |
| Deploy | Vercel | Integração nativa com Next, incluindo cron |
Por que Base
Uma L2 EVM com custo de transação baixo o suficiente para que patrocinar o gás de cada operação de usuário seja economicamente viável. Numa L1, o modelo de "o usuário não precisa ter ETH" seria caro demais para sustentar.
Sendo EVM, a carteira do usuário é uma EOA padrão: legível e utilizável por qualquer ferramenta do ecossistema, não um formato proprietário nosso.
Por que BRLA
Uma stablecoin ERC-20 com paridade 1:1 com o real e 18 casas decimais.
A paridade importa por um motivo prático: o usuário raciocina em reais, e o saldo dele é em reais. Não há exposição cambial escondida entre o depósito e o saque, e não há conversão de moeda para explicar na interface.
As 18 casas decimais tornam a conversão de centavos exata em aritmética inteira — nenhum arredondamento em nenhum caminho de dinheiro. Veja Dados e ledger.
Por que passkey em vez de seed phrase
Seed phrase é a maior barreira de adoção da autocustódia, e a maior fonte de perda irreversível. Passkey entrega a mesma propriedade — a chave está com o usuário, não conosco — usando um mecanismo que o sistema operacional já gerencia, sincroniza e protege com biometria.
O usuário não aprende nada novo. Ele desbloqueia com o rosto ou a digital, como já faz no resto do telefone.
Convenções de código
TypeScript estrito
Sem any. noUncheckedIndexedAccess ligado — todo acesso indexado precisa ser tratado como possivelmente indefinido.
Server Components por padrão
Client Component só quando há hook ou estado. Menos JavaScript no dispositivo.
Zod em toda fronteira
Rotas de API e variáveis de ambiente são validadas por schema. Entrada não validada não entra.
Idioma dividido
Interface em português. Código, commits e identificadores em inglês.
Ambientes
O app roda contra Base Sepolia em desenvolvimento e Base mainnet em produção. A troca é uma variável de ambiente.
Uma consequência prática: as rails de dólares dependem de contratos que só existem em mainnet, então elas não são testáveis em Sepolia. As rails de PIX funcionam nos dois.
Testes
Vitest cobre a lógica com risco de dinheiro: máquinas de estado das rails,
aritmética de conversão, análise de BR Code, verificação de webhook, guards de
concorrência. Praticamente todo módulo em lib/ tem um .test.ts ao lado.
O que é testado é escolhido pelo mesmo critério do resto do sistema: o que, se estiver errado, move dinheiro para o lugar errado.