Sessão de 30/04. Investimentos saíram do modelo “1 linha = posição atual” pra modelo aporte (1 linha = 1 compra; posição é derivada agregando por nome). Spec completo emDocumentation Index
Fetch the complete documentation index at: https://docs.pixdopix.com.br/llms.txt
Use this file to discover all available pages before exploring further.
docs/superpowers/specs/2026-04-30-investimentos-aportes-design.md.
Resumo executivo
3 commits nomain, 1 migration Supabase em produção.
| Bloco | Commit | Status |
|---|---|---|
| Fix silencioso anterior (sheet fechava sem mostrar erro) | b90eafd | ✅ produção |
| Feat: modelo aporte completo (schema + form + display + helper) | b9f7078 | ✅ produção |
Fix: toggleTag com setForm funcional (descoberto no smoke test) | 56fae90 | ✅ produção |
1. Bug raiz: investimentos não cadastravam (1ª parte da sessão)
Sintoma: usuário relatou que cadastros não estavam indo pro banco. Investigação:- DB tinha 3 registros, todos
deletado=truedesde 2026-04-29 22:54 - API logs nas últimas 24h: zero
POST /rest/v1/investimentos - Mesmo bug-pattern que foi consertado em salarios no commit
81a007e
handleSubmit chamava .mutate(...) (fire-and-forget) e em seguida onOpenChange(false) síncrono. Se a mutation falhasse, o sheet fechava antes do toast renderizar — o erro era engolido e o usuário pensava que tinha cadastrado.
Fix (b90eafd):
- Hook:
createInvestimento/updateInvestimentovirammutateAsync - Sheet:
handleSubmitviraasync, comtry/await/catch— fecha só em sucesso
2. Modelo aporte (parte principal)
Decisão arquitetural
Cada linha deinvestimentos passa a representar uma compra individual, não a posição agregada. A posição (qty total + preço médio) é derivada agregando todas as linhas com o mesmo nome (case-insensitive) num mesmo workspace.
Por quê: preserva histórico de compras, calcula preço médio sem dor, mantém a tabela append-only. Padrão de home-broker.
Migração investimentos_aporte_qty_unit_tags_alocacoes
valor.
Taxonomia (lib/investment-taxonomy.{ts,json})
Adicionada flag temUnidades?: boolean na interface SubcategoriaInvestimento. Marcado em:
- Renda Fixa → Tesouro Direto
- Renda Variável → todas
- Internacional → todas
- Criptoativos → todas
valor.
Form (components/investimento-sheet.tsx)
Comportamento condicional baseado na subcategoria:
temUnidades: mostraQuantidade+Valor unitário (R$);Valor totalé read-only e auto-calcula (qty × unit)tagsdeclaradas (Ações): chips multi-select opcionalalocacoesdeclaradas (Cripto principais/altcoins/stablecoins): splitEm spot (R$)+Em staking (R$)com validação de soma vs valor total- Cabeçalho mudou pra “Novo Aporte” + hint sobre agregação por nome
Helper de agregação (lib/investment-aggregate.ts)
Novo módulo. agruparPorAtivo(investimentos: Investimento[]): AtivoAgregado[] retorna:
Display (app/investimentos/[categoria]/page.tsx)
Agora dentro de cada subcategoria os ativos são agregados por nome. Cada card mostra:
- Posição (qty + preço médio + custo total)
- Tags consolidadas (se houver)
- Botão “Ver aportes” → drilldown com aportes individuais (edit/delete por aporte)
3. Smoke test E2E
Testado via Playwright durante a sessão:| Cenário | Resultado |
|---|---|
| HGLG11 (FII): 2 aportes (10×130 + 8×145) | ✅ 18 un., custo R 136,67** (= 2460/18) |
| Bitcoin: 0,5 × R$ 350k com split 100k spot + 75k staking | ✅ alocações persistidas como JSONB; validação verde |
PETR4: 100 × R$ 35 com tags [blue chip, energia] | ✅ tags como text[]; chips visíveis no card |
| Drilldown “Ver aportes” | ✅ aportes individuais com qty × unit; edit/delete |
56fae90): toggleTag usava setForm({...form, tags: ...}) lendo do closure stale. Migrado pra setForm((prev) => ({...prev, tags: ...})) — consistente com cliques rápidos em sequência.
4. Fora de escopo (fase 2)
- Cotação atual via API externa (B3 / Alpha Vantage / CoinGecko)
- Rendimento da carteira = preço atual × qty − custo médio × qty
- Cruzamentos por tag em relatórios (ex: “patrimônio em blue chip vs growth”)
- Filtros por tag na própria página de classe
5. Bug-pattern análogo em outros sheets
O fix deb90eafd (await mutation antes de fechar sheet) também estava ausente em outros forms. Worth fazer uma sweep:
components/gasto-sheet.tsxcomponents/receita-sheet.tsxcomponents/meta-sheet.tsxcomponents/cartao-sheet.tsxcomponents/conta-fixa-sheet.tsxcomponents/parcela-sheet.tsxcomponents/gasolina-sheet.tsx
salarios em 81a007e, investimentos em b90eafd.)
Referências
- Spec de design:
docs/superpowers/specs/2026-04-30-investimentos-aportes-design.md - Doc de usuário:
docs/recursos/investimentos.mdx(atualizada nesta sessão) - Commit do fix análogo em salarios:
81a007e