Commit Graph
45 Commits
Author SHA1 Message Date
Mlcavalho1 8cf67d1e6b fix(cdi): throttle de 15min em erro BCB em vez de cachear vazio até 23:59
- Erro BCB (dado não publicado): bloqueia retry por 15 min, não até EOD
- Sucesso BCB: cache válido até 23:59 como antes
- Garante que o CDI do dia seja calculado quando BCB publicar (~9h)
2026-05-29 00:34:34 -03:00
Mlcavalho1 a188bcec3f fix(cdi): cachear resposta vazia do BCB até 23:59 quando dado ainda não publicado
BCB retorna objeto de erro (não array) quando a taxa do dia ainda não foi
publicada. Antes: decode falhava, cache ficava vazio, BCB era chamado a cada
request. Agora: decode error → put(nil) no cache → requests seguintes servidas
do cache em <1ms até fim do dia
2026-05-29 00:31:00 -03:00
Mlcavalho1 3c13c85081 debug(cdi): logs de diagnóstico em ApplyYield e fetchCDIRates 2026-05-29 00:28:09 -03:00
Mlcavalho1 4de1af5687 debug(accounts): logs temporários de timing em AccountService.List 2026-05-29 00:22:40 -03:00
Mlcavalho1 61981fffcf perf(cdi): cache em memória das taxas BCB com expiração às 23:59 do dia do fetch
- Cache map[date]rate compartilhado entre chamadas do mesmo processo
- Expira às 23:59:59 do dia corrente (não TTL fixo de 24h)
- Double-checked locking evita múltiplas chamadas concorrentes ao BCB
- Cobre múltiplas contas com start dates diferentes sem chamadas redundantes
2026-05-29 00:14:26 -03:00
Mlcavalho1 3d4141f3cc feat(ui): mobile bottom nav com 4 fixos + menu MAIS para rotas secundárias
- HOME, TX, IMPORT, PERS. fixos na barra inferior
- Botão '···' abre overlay com CONTAS, REC., CAT., CFG
- Overlay fecha ao navegar ou ao tocar fora
- Transição de fade no overlay
2026-05-29 00:07:30 -03:00
Mlcavalho1 e1f5eb2281 feat(ui): #50 meta mensal em Categorias + conquistas dinâmicas em /personagem
- CategoriesView: campo META MENSAL (R$) no formulário de criação/edição
- CategoriesView: badge verde com valor da meta na listagem
- categories store: monthly_budget nos tipos e chamadas de API
- CharacterView: sem alteração — conquistas dinâmicas já renderizam via title/icon/earned existentes
2026-05-28 23:26:51 -03:00
Mlcavalho1 8632251f8a feat(game): #49 motor de conquistas dinâmicas por categoria
- GameRepo: EnsureCategoryAchievement, RemoveCategoryAchievementIfNotEarned, ListCategoriesWithBudget, GetMonthlySpendByCategory
- GameService: OnCategoryBudgetSet, CheckCategoryBudgets
- ListAchievements filtra conquistas por categorias do perfil (sem vazamento entre usuários)
- NotifyAction chama CheckCategoryBudgets em transaction_created e import_confirmed
- CategoryHandler injeta GameService e chama OnCategoryBudgetSet após Create/Update
- 5 novos testes unitários cobrindo todos os cenários de AC
2026-05-28 23:26:46 -03:00
Mlcavalho1 f60ca423d0 feat(schema): #48 monthly_budget em categories + category_id em achievements
- Migration 018: ADD COLUMN monthly_budget NUMERIC(12,2) em categories
- Migration 018: ADD COLUMN category_id INTEGER REFERENCES categories(id) ON DELETE CASCADE em achievements
- Remove conquistas hardcoded veleiro_under_500 e health_3months do banco
- Reset game state do profile_id=1
- Atualiza CategoryRepository, CategoryInput e Category model para incluir monthly_budget
2026-05-28 23:26:39 -03:00
Mlcavalho1andClaude Sonnet 4.6 00356971c7 feat: #46 auto-categorização no import por histórico de descrições
- TransactionRepository.CategoryByDescription: busca a categoria mais
  recente para cada descrição normalizada no histórico do perfil
- ImportService.Preview: pré-preenche category_id em linhas não-duplicatas
  cuja descrição já foi categorizada antes (case-insensitive)
- Duplicatas não recebem sugestão
- 2 novos testes: auto-categorize + duplicate-not-categorized

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-28 22:49:44 -03:00
Mlcavalho1andClaude Sonnet 4.6 26eabc460b fix: adicionar Authorization header nos fetch diretos do import store
preview e confirm usavam fetch sem o header Bearer, causando 401.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-28 22:41:25 -03:00
Mlcavalho1andClaude Sonnet 4.6 1d59cb2a0e feat: #45 meta de poupança configurável + conquistas genéricas
- Nova tabela user_settings com savings_goal_pct (default 40%)
- API GET /api/settings, PUT /api/settings
- DashboardService inclui savings_goal_pct no payload
- DashboardHandler dispara savings_checked com goal configurado
- GameService.NotifyAction: checa pct >= goal (sem hardcode de 40%)
- SettingsView: painel META DE POUPANÇA com input configurável
- HomeView: widget mostra meta dinâmica (META: X%) e usa savingsGoal
- stores/settings.ts: store com fetch e update

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-28 22:32:08 -03:00
Mlcavalho1andClaude Sonnet 4.6 2b8524dcde feat: #44 fatura de cartão com data futura fica pendente até confirmação
- Nova tabela pending_bill_imports (migration 016)
- ImportHandler.Confirm: quando is_credit_card=true e payment_date > hoje,
  salva como pending em vez de inserir transações
- Novos endpoints: GET /pending-bills, POST /pending-bills/:id/confirm,
  DELETE /pending-bills/:id
- Dashboard inclui pending_bill_imports no payload
- Frontend: resultado "fatura salva como pendente" no ImportView
- AccountsView exibe widget de faturas pendentes com ações de confirmar/descartar
- dashboard_test: mock de PendingBillRepo + TransactionRepository

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-28 22:26:42 -03:00
Mlcavalho1andClaude Sonnet 4.6 6292858970 feat: CDI % configurável por conta + fix mocks de teste
- Adiciona campo cdi_percentage (default 100%) na tabela accounts
- Cálculo CDI aplica proporção: balance × (compound-1) × (pct/100)
- Frontend exibe input de % quando yield_type=cdi e badge mostra valor
- Corrige mocks de teste desatualizados (DeleteByMonth, isTax)
- Corrige ConfirmIncome para rejeitar tipo expense (ErrRecurringNotIncome)

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-28 22:20:32 -03:00
Mlcavalho1andClaude Sonnet 4.6 433c4f42a5 fix: corrigir auth em game store e evitar logout no refresh
- Router usa isAuthenticated (localStorage) em vez de auth.check()
  que fazia round-trip ao servidor e deslogava se houvesse falha
- game.ts e CharacterView substituem fetch raw por api() que injeta
  Bearer token automaticamente, corrigindo erro 401/failed no personagem

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-27 21:31:01 -03:00
Mlcavalho1andClaude Sonnet 4.6 3db4c66d01 feat: substituir sprite SVG por animação de frames PNG do personagem
Cria pasta assets/sprites/character/ com 5 frames de idle e reescreve
CharacterSprite.vue para ciclar entre eles via setInterval.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-27 21:26:15 -03:00
Mlcavalho1andClaude Sonnet 4.6 acbce4edc0 feat: multi-usuário com autenticação JWT
- Tabela `profiles` + coluna `profile_id` em todas as entidades
  (categories, transactions, recurring_expenses, accounts, player_profile,
   xp_events, player_quests, player_achievements, player_cosmetics)
- Dados existentes migrados para profile_id = 1 (Manoel)
- CLI `./api create-user --name <n> --password <p>` cria perfil com
  seed de categorias e player_profile; faz upsert de senha se já existir
- Auth substituída: cookie+APP_PASSWORD → JWT Bearer 24h (HS256)
- Middleware RequireAuth injeta profile_id no context de todas as rotas
- Todos os repositórios filtram por profile_id do context
- Endpoints: POST /api/auth/login, GET /api/auth/me,
  POST /api/auth/change-password, POST /api/logout
- Frontend: auth store usa localStorage (fc_token/fc_profile),
  api.ts envia Authorization header, LoginView usa campo name
- SettingsView reescrita com troca de senha e logout
- docker-compose.yml: remove APP_USERNAME/APP_PASSWORD, adiciona JWT_SECRET

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-27 20:04:44 -03:00
Mlcavalho1andClaude Sonnet 4.6 50637bd590 fix: remover referência a ErrCannotEditImported no Update
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-27 16:42:44 -03:00
Mlcavalho1andClaude Sonnet 4.6 88461a4aea feat: excluir transações de extrato + delete em lote por mês
Remove restrição que bloqueava delete de transações importadas.
Adiciona DELETE /transactions?month=YYYY-MM para exclusão em lote
e botão "EXCLUIR MÊS" na view de transações.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-27 16:41:26 -03:00
Mlcavalho1andClaude Sonnet 4.6 0507d7bff3 feat: permitir excluir transações de extrato (import)
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-27 16:37:05 -03:00
Mlcavalho1andClaude Sonnet 4.6 2b0aa352d5 feat: salvar data original da transação e data de vencimento no cartão
Ao importar fatura de cartão com PaymentDate configurado, a data efetiva
da transação passa a ser o vencimento e a data de compra é preservada em
original_date. Migration 013 adiciona a coluna original_date em transactions.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-27 16:25:52 -03:00
Mlcavalho1andClaude Sonnet 4.6 9ba3a3678b feat: total dos valores a importar no rodapé da prévia
Soma apenas as linhas novas (não duplicatas), exibida alinhada à direita.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-27 16:05:28 -03:00
Mlcavalho1andClaude Sonnet 4.6 482bae698a feat: categorizar transações no preview de importação
Select de categoria em cada linha da prévia; category_id salvo no
BulkInsert. Duplicatas ficam desabilitadas.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-27 16:04:19 -03:00
Mlcavalho1andClaude Sonnet 4.6 54d5a03604 fix: checkbox 'fatura de cartão' auto-configura colunas corretas
Ao marcar 'Fatura de cartão', amount_column=3, description=1,
skip_negative=true — elimina erro de coluna errada no CSV do banco.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-27 15:58:04 -03:00
Mlcavalho1andClaude Sonnet 4.6 e438002c0a feat: importação de fatura de cartão — strip R$, skip negativos, all_expenses
Parser limpa prefixo R$ e símbolos de moeda antes de parsear o valor.
Flags SkipNegative e AllExpenses para CSV de fatura de cartão.
UI: checkboxes "Fatura de cartão" e "Ignorar valores negativos".

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-27 15:56:14 -03:00
Mlcavalho1andClaude Sonnet 4.6 7dae05cabf feat: categoria is_tax exclui impostos do denominador do savings_pct
savings_pct = (receita - despesas) / (receita - impostos).
Toggle IMPOSTO no CRUD de categorias; badge dourado na lista.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-27 15:53:53 -03:00
Mlcavalho1andClaude Sonnet 4.6 2cf6d94a03 fix: auth stateless com HMAC — sessões sobrevivem restarts do container
Tokens assinados com APP_PASSWORD via HMAC-SHA256 eliminam o in-memory
sessions map. Também corrige env vars (_USERNAME→APP_USERNAME).

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-27 15:48:01 -03:00
Mlcavalho1andClaude Sonnet 4.6 7282109206 feat: confirmar despesas recorrentes cria transação manual
Botão CONFIRMAR para despesas pendentes, igual ao fluxo de receitas.
Backend remove guard income-only no ConfirmIncome.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-27 15:45:17 -03:00
Mlcavalho1andClaude Sonnet 4.6 5c55da8a4a feat: CurrencyInput em todos os campos de valor monetário
Input digit-by-digit em centavos com formatação BRL automática.
Substitui amountRaw/initialRaw + parseAmount nas 3 views.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-27 15:42:37 -03:00
Mlcavalho1andClaude Sonnet 4.6 62aea56d72 fix: restaurar link CFG→/categorias no nav e corrigir redirect
REC. → /recorrencias, CFG → /categorias (categorias voltam a ser acessíveis).

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-27 15:27:17 -03:00
Mlcavalho1andClaude Sonnet 4.6 25156c36e1 fix: registrar migrations 009-011 e gravar schema_migrations após apply
As migrations de receitas recorrentes, CDI yield e cartão de crédito
foram criadas mas não embedadas no runner — causando 500 em produção.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-27 15:22:22 -03:00
Mlcavalho1andClaude Sonnet 4.6 e3b3433703 feat(#37): módulo de cartão de crédito com faturas mensais
- Migration 011: closing_day/due_day em accounts + tabela credit_bills
- CreditBillService: cria/atualiza fatura corrente on-demand no GET /accounts
- Widget FATURA ATUAL no dashboard com total e botão PAGAR
- AccountsView: campos closing_day/due_day para contas credit + painel fatura
- Dashboard: current_bills lista faturas não pagas de todos os cartões

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-27 15:12:53 -03:00
Mlcavalho1andClaude Sonnet 4.6 ee6cd9f37e feat(#35): rendimento CDI automático em contas de investimento
- Migration 010: colunas yield_type e last_yield_date em accounts + source='yield' nas transações
- CDIYieldService: busca taxas BCB (serie 12) e cria transação source=yield com rendimento acumulado
- Weekends/feriados sem taxa usam última taxa disponível (AC4)
- GET /api/accounts dispara cálculo CDI on-demand antes de retornar saldos
- AccountsView: seletor yield_type (none/cdi/variable) + badge CDI/VAR na listagem
- Transações source=yield aparecem no histórico com descrição 'Rendimento CDI — {período}'

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-27 15:06:05 -03:00
Mlcavalho1andClaude Sonnet 4.6 79f4a62a1b feat(#36): receitas recorrentes com confirmação de salário até dia 5
- Migration 009: coluna `type` em recurring_expenses + tabela recurring_late
- API Go: tipo income/expense em CRUD; endpoints POST /confirm e /late
- Dashboard: campo pending_income_recurrings na resposta
- Frontend: RecurringView com seções RECEITAS e DESPESAS separadas
- HomeView: widget de confirmação (dia 1-5) e badge SALÁRIO PENDENTE (pós dia 5)
- Testes unitários: 4 novos casos (income covered, late, confirm, reject expense)

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-27 15:00:28 -03:00
Mlcavalho1andClaude Sonnet 4.6 d20892977d feat(#34): PWA instalável com cache do shell para Android
- vite-plugin-pwa com Workbox (generateSW, autoUpdate)
- manifest.webmanifest: standalone, theme #0a0418, ícones 192/512
- Service worker pré-cacheia 29 entradas (shell completo offline)
- Google Fonts cacheadas via CacheFirst (1 ano)
- Ícone pixel art Arcade Neon (SVG + PNGs gerados)
- Meta tags PWA e apple-touch-icon no index.html

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-27 11:57:56 -03:00
Mlcavalho1andClaude Sonnet 4.6 a8a4a76dd5 feat: autenticação com cookie de sessão + tela de login Arcade Neon
- Go: middleware RequireAuth protege todas as rotas /api/*
- Go: POST /api/login valida APP_USERNAME/APP_PASSWORD e emite cookie HttpOnly 30 dias
- Go: GET /api/auth/me e POST /api/logout
- Vue: LoginView com design Arcade Neon
- Vue: router guard redireciona para /login se não autenticado
- Vue: api.ts redireciona para /login em qualquer 401
- docker-compose: APP_USERNAME e APP_PASSWORD como env vars

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-26 23:23:57 -03:00
Mlcavalho1andClaude Sonnet 4.6 c327d5c970 feat(#29): Arcade Neon design system — visual overhaul completo
Implementa o sistema visual Arcade Neon do neon-handoff/ em todo o app:

- tokens.css: tokens --fc-*, utilities (fc-pixel/mono/body/glow), form inputs/buttons globais
- AppHud.vue: HUD persistente com LV/XP/META + nav chips por rota
- BottomNav.vue: nav mobile com 5 rotas
- NeonPanel.vue, CharacterSprite.vue, XPBar.vue, HUDStat.vue: componentes base
- MonthSwitcher.vue, LevelUpModal.vue
- HomeView, CharacterView, TransactionsView, ImportView, CategoriesView,
  AccountsView, SettingsView: reescritos com Arcade Neon
- sprites PNG (lv01–lv15) + sprite-data.json: cosméticos com temas de cor
- game.ts: equippedTheme getter para merge de cores do cosmético equipado
- 008_cosmetics.sql: seeds alinhados com sprite-data.json

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-26 22:53:41 -03:00
Mlcavalho1andClaude Sonnet 4.6 2277f4375d fix: migration runner idempotente e seeds com UNIQUE constraint
Runner agora checa schema_migrations antes de rodar cada SQL — sem
reexecução de seeds a cada startup. Quests: UNIQUE(title, quest_type).
Cosmetics: UNIQUE(name), tipos corrigidos para hair/shirt/pants/shoes.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-26 22:01:48 -03:00
Mlcavalho1andClaude Sonnet 4.6 c1964ea036 feat(#22): gamificação RPG — XP, quests, conquistas, cosméticos e personagem SVG pixel art
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-26 21:46:41 -03:00
Mlcavalho1andClaude Sonnet 4.6 9a964423fd feat(#21): contas bancárias e patrimônio consolidado
CRUD de contas (corrente/poupança/investimento/cartão) com saldo calculado
automaticamente. account_id nullable em transactions. Widget patrimônio no
dashboard. Tela /contas. Seletor de conta nas transações manuais.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-26 21:34:56 -03:00
Mlcavalho1andClaude Sonnet 4.6 fbcb1d76aa feat(#20): dashboard financeiro mensal — 4 widgets + endpoint de agregação
Adiciona GET /api/dashboard?month=YYYY-MM com resumo mensal (% poupado,
gastos por categoria, evolução 6 meses, últimas 10 transações, recorrências
pendentes). HomeView.vue reescrita com 4 widgets e gráficos CSS nativos.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-26 20:32:05 -03:00
Mlcavalho1andClaude Sonnet 4.6 12e8500827 feat(#19): registro manual de transações e recorrências fixas
Adiciona CRUD manual de transações (income/expense) com filtro mensal, CRUD de
recorrências fixas com verificação mensal de cobertura (±10% por categoria),
endpoint de ignore/unignore e telas Vue para Transações e Configurações.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-26 20:26:48 -03:00
Mlcavalho1andClaude Sonnet 4.6 83dff2de78 feat(#18): import de extratos OFX e CSV — parser, dedup, preview e confirmação
Parser OFX tolerante ao formato SGML de bancos brasileiros (sem closing tags, BOM,
timezone suffix). Parser CSV com separador de campo/decimal configurável. Dedup por
FITID (OFX) ou date+amount+desc normalizado. Fluxo: POST /preview → revisão na UI
→ POST /confirm salva e loga. Migration 002 adiciona external_id com unique index.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-26 20:17:46 -03:00
Mlcavalho1andClaude Sonnet 4.6 d6782d51a5 feat(#17): CRUD de categorias — API Go + tela Vue + testes unitários
API REST /api/categories (GET/POST/PUT/DELETE) com regras de negócio:
categorias padrão não podem ser excluídas; categorias com transações vinculadas
também bloqueadas. Tela Vue com formulário inline de criação/edição, indicador
visual de categorias padrão e botão de exclusão condicional.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-26 20:11:54 -03:00
Mlcavalho1andClaude Sonnet 4.6 a3d8f363a5 feat: setup monorepo infra — Go API + Vue 3 + PostgreSQL + Dockerfile Dokploy
Monorepo com apps/api (Go 1.23 + chi + pgx) e apps/web (Vue 3 + Vite + TypeScript).
Dockerfile multi-stage consolida tudo em imagem única (~25MB) para deploy no Dokploy.
Migrations rodando na inicialização; Vue embedado no binário Go via //go:embed.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-26 20:06:37 -03:00