Skip to content

Repository files navigation

wallet-live

Carteira digital de investimentos com backend, regras financeiras e HTML renderizado no servidor escritos em Rust, servidos por um único binário.

Simulação educacional. Não movimenta dinheiro real, não integra meio de pagamento e não oferece recomendação de investimento. Projeto final do bootcamp Santander 2026 — Rust AI Developer (DIO).

📖 Documentação técnica completa


Problema que resolve

Uma carteira de investimentos precisa registrar aportes, executar compras e vendas a preço de mercado, calcular custo médio e resultado por posição, e manter um histórico auditável — sem jamais perder precisão monetária.

O material didático que originou o projeto modelava dinheiro como ponto flutuante e o histórico como um log de compras que só sabia somar. Nenhum dos dois sobrevive a um produto que também vende: ponto flutuante acumula erro (ADR-0004) e um log append-only não representa saída (ADR-0005).

Escopo

Faz: aporte de caixa, compra e venda de ativos ao preço de mercado, custo médio ponderado, resultado por posição, extrato imutável, painel de mercado informativo, API administrativa de catálogo.

Não faz: saque, transferência entre usuários, ordem limitada ou agendada, estorno, múltiplas moedas de denominação, recuperação de senha. Lista completa em known-limitations.md.

Funcionalidades

  • Carteira — saldo em caixa, depósito, compra e venda ao preço de mercado, custo médio ponderado por posição, resultado por ativo e resumo do patrimônio.
  • Extrato — livro-razão imutável, paginado na interface e exportável em CSV.
  • Cotações reais — preços da API pública da Coinbase, com sincronização agendada, criação automática do catálogo mínimo numa instalação vazia e atualização num único UPDATE.
  • Painel de mercado — as 100 maiores criptomoedas em BRL, com gráfico temporal em 24 h ou 7 d, servido de um snapshot em memória: trocar de moeda não custa chamada externa.
  • Operações sem recarregar a página — htmx troca só o fragmento da carteira; sem JavaScript, o fluxo clássico de redirect continua inteiro.
  • Interface bilíngue — pt-BR e inglês, a partir de um catálogo tipado.
  • Autenticação e sessão — argon2, JWT de acesso curto + refresh token rotacionado e revogável, lockout progressivo e CSRF em todos os formulários.
  • API administrativa — catálogo sob /api/v1, com OpenAPI gerada do código.
  • Pronto para orquestração — migrações no boot, sondas separadas, desligamento gracioso, logs estruturados e exportação OTLP opcional.

Não implementado: MFA, recuperação de senha, exclusão de conta, notificações, backup automatizado. Ver known-limitations.md.

Arquitetura em uma tela

Diagrama animado da arquitetura: uma requisição entra pelo navegador, atravessa os middlewares request_tracing, security_headers e refresh_session, chega às rotas, passa por services/portfolio e repository e alcança as seis tabelas do PostgreSQL; em paralelo, os jobs quotes e market consomem Coinbase e CoinGecko

Um POST /buy atravessando a pilha, as seis consultas concorrentes que montam a WalletView e os dois jobs de segundo plano. Âmbar lastreia preço e chega ao banco; violeta é informativo e morre em memória — a separação é a do ADR-0009.

routes/     HTTP puro: formulário/JSON, CSRF, redirect, fragmento vs página
   ↓
services/   Orquestração: consultas concorrentes, paginação, projeção de gráfico
   ↓
repository  TODO o SQL; validação na borda da escrita
   ↓
PostgreSQL  CHECKs como última linha de defesa

Um binário único: templates (Askama), migrações (SQLx) e assets estáticos são embutidos nele. Sem frontend separado, sem build de JavaScript, sem microsserviço.

Detalhes: system-overview.md · component-architecture.md · data-flow.md

Decisões que definem o projeto

Tema Decisão ADR
Dinheiro DecimalNUMERIC, escala canônica de 8 casas. Ponto flutuante nunca entra no núcleo financeiro 0004
Modelo de dados holdings materializa a posição; transactions é o livro-razão imutável 0005
Verificação estática SQL, templates e traduções checados em tempo de compilação 0003 · 0006
Injeção de dependência Extratores do Axum: a proteção de uma rota é visível na assinatura do handler 0002
Sessão JWT curto + refresh opaco com rotação atômica e revogação real 0007
Interface SSR + htmx como progressive enhancement; CSP fechada sem unsafe-inline 0003
CSS Compilado em build-time por executável único — sem Node, sem npm 0010
Mercado Snapshot em memória, fora do banco: dado de terceiro não lastreia operação 0009
Observabilidade OTLP opt-in, sem custo quando desligada 0012

Tecnologias

axum · tokio · sqlx (PostgreSQL, verificado em compilação) · askama · rust_decimal · password-auth (argon2) · jwt-simple · subtle · reqwest · tracing + OpenTelemetry · thiserror · serde · utoipa (OpenAPI) · htmx (vendorado) · Tailwind CSS (build-time).

Justificativa de cada uma: technology-decisions.md.

Requisitos

Requisito Versão
Rust 1.95+ (edition 2024)
Docker + Compose Recente
PostgreSQL 18 (via Docker ou próprio)

Node e npm não são necessários — nem para o CSS.

Instalação e execução

docker compose up -d db
cp .env.example .env

Edite .env e substitua ADMIN_SECRET_KEY e JWT_SECRET — os valores de exemplo são públicos.

cargo run

Abra http://localhost:3000. As migrações são aplicadas no boot.

Stack completo em Docker:

docker compose --profile app up --build

Guia completo: installation.md · Problemas conhecidos: troubleshooting.md

Configuração

Três variáveis são obrigatórias — o serviço não sobe sem elas:

Variável Finalidade
DATABASE_URL Conexão com o Postgres
ADMIN_SECRET_KEY Credencial da API administrativa
JWT_SECRET Chave de assinatura das sessões

Outras dez têm padrão sensato. Referência completa, com efeito e risco de cada uma: configuration.md.

⚠️ Em produção, use exatamente COOKIE_SECURE=true. A comparação é literal: TRUE, 1 e yes resultam em false, silenciosamente (DT-04).

Testes

118 testes em duas camadas — 83 de unidade, 35 de contrato.

docker compose up -d db && cargo test

Só o que não toca banco:

cargo test --test payload_market --test payload_quotes

Os payloads das integrações externas são reais, capturados de produção e versionados: a maior taxa da captura da Coinbase tem 41 dígitos significativos, contra os 28 da mantissa do Decimal — um fixture inventado nunca revelaria isso.

test-strategy.md · test-catalogue.md · test-matrix.md — incluindo os riscos sem cobertura.

Estrutura do repositório

src/
  main.rs            # 8 linhas: tokio::main -> App::start()
  lib.rs             # os módulos como BIBLIOTECA — permite tests/ existir
  app.rs             # boot, AppState, router, camadas, sondas, tracing
  config.rs          # lê e valida o ambiente uma vez (fail-fast)
  models.rs · error.rs · i18n.rs
  quotes.rs          # cotações Coinbase -> preços (lastreia dinheiro)
  market.rs          # snapshot CoinGecko em memória (informativo)
  repository.rs      # todo o acesso ao banco + 26 testes
  auth/              # user, session, admin, csrf, throttle
  services/          # portfolio: orquestração da carteira
  routes/            # api (JSON), frontend (SSR), flash
tests/               # suíte de contrato; payloads reais versionados
templates/ · migrations/ · static/ · styles/ · docs/

Segurança

Controles: CSP sem unsafe-inline, CSRF, lockout progressivo, argon2, refresh token rotativo com revogação real, comparação de segredo em tempo constante, queries parametrizadas, erros 5xx censurados, container sem privilégio, zero dependências npm.

Isso não torna o sistema seguro — torna-o um sistema com controles conhecidos e limites documentados. Riscos residuais, ameaças e ações prioritárias em threat-model.md.

Para relatar uma vulnerabilidade: SECURITY.md.

Observabilidade

Logs estruturados (JSON opcional) com request_id por requisição, traces e o histograma http.server.request.duration exportáveis via OTLP — opt-in: sem OTEL_EXPORTER_OTLP_ENDPOINT, nenhuma tentativa de conexão.

Sondas separadas: /healthz (liveness, não toca o banco) e /readyz (readiness).

observability.md

Limitações conhecidas

Registradas para que a ausência não seja confundida com omissão:

  • Instância única — lockout e snapshot de mercado vivem em memória do processo.
  • Sem backup implementadodocker compose down -v é perda total (DT-05).
  • Nenhum teste executa JavaScript — o htmx é verificado pelo HTML emitido.
  • Reversão de migração nunca testada — os 11 .down.sql existem, nenhum é executado.
  • Cobertura de testes não medida — não há ferramenta configurada.
  • Sem criptografia em repouso.

Completas: known-limitations.md · Débitos com prioridade: technical-debt.md

Roadmap

As cinco fases planejadas estão concluídasroadmap.md é hoje um histórico. O trabalho pendente está registrado como débito técnico, não como roadmap.

Contribuindo

Relatos de defeitos, sugestões, revisão técnica e discussões por meio de issues são bem-vindos.

Enquanto a proveniência e o modelo de licenciamento do projeto não estiverem resolvidos, pull requests contendo código de terceiros não serão incorporados ao repositório.

Consulte CONTRIBUTING.md e licensing.md.

Licença

Este repositório ainda não possui licença open source definida.

O projeto contém extensa contribuição autoral própria, mas foi iniciado a partir de estrutura e componentes do projeto didático rust-fullstack-carteira-investimentos, publicado pela DIO sem uma licença open source expressa identificada.

Por essa razão, ainda não está demonstrado o direito de sublicenciar o repositório inteiro sob MIT, Apache-2.0 ou outra licença.

Enquanto a proveniência e a autorização do código-base não forem resolvidas, aplicam-se os direitos autorais padrão. A publicação pública permite a visualização do código e o uso das funcionalidades previstas pelo GitHub, mas não concede autorização geral para copiar, modificar, redistribuir ou utilizar comercialmente o projeto.

Também permanece pendente a auditoria das licenças das dependências Rust. Consulte licensing.md para a análise completa.

Notas de ambiente (Windows)

  • TLS do cargo: .cargo/config.toml já desativa apenas a checagem de revogação, que falha com CRYPT_E_NO_REVOCATION_CHECK em algumas redes.
  • jwt-simple sem cmake: configurado com pure-rust.
  • Postgres 18: o volume é montado em /var/lib/postgresql (convenção da imagem 18+).
  • Proxy corporativo com inspeção TLS: ver troubleshooting.md §3.

About

Auditable investment-wallet simulation in Rust with exact decimal accounting, immutable ledger, SSR, and PostgreSQL.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages