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
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).
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.
- 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.
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
| Tema | Decisão | ADR |
|---|---|---|
| Dinheiro | Decimal ↔ NUMERIC, 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 |
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.
| 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.
docker compose up -d dbcp .env.example .envEdite .env e substitua ADMIN_SECRET_KEY e JWT_SECRET — os valores de exemplo
são públicos.
cargo runAbra http://localhost:3000. As migrações são aplicadas no boot.
Stack completo em Docker:
docker compose --profile app up --buildGuia completo: installation.md · Problemas conhecidos: troubleshooting.md
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 exatamenteCOOKIE_SECURE=true. A comparação é literal:TRUE,1eyesresultam emfalse, silenciosamente (DT-04).
118 testes em duas camadas — 83 de unidade, 35 de contrato.
docker compose up -d db && cargo testSó o que não toca banco:
cargo test --test payload_market --test payload_quotesOs 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.
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/
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.
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).
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 implementado —
docker 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.sqlexistem, 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
As cinco fases planejadas estão concluídas — roadmap.md é hoje um histórico. O trabalho pendente está registrado como débito técnico, não como roadmap.
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.
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.
- TLS do cargo:
.cargo/config.tomljá desativa apenas a checagem de revogação, que falha comCRYPT_E_NO_REVOCATION_CHECKem algumas redes. jwt-simplesemcmake: configurado compure-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.
