O problema
Resumo mensal parece a tela mais boba do app. Ela quebra em dois lugares: somar dinheiro com double, que perde centavo, e trazer todas as transações do banco para somar no Java.
Backend
Controle de gastos com resumo mensal. O Postgres soma, não o Java, e todo valor é BigDecimal para não perder centavo.
2consultas JPQL agregam no banco
Resumo mensal parece a tela mais boba do app. Ela quebra em dois lugares: somar dinheiro com double, que perde centavo, e trazer todas as transações do banco para somar no Java.
Categoria 1—N Transação, com o tipo da transação derivado da categoria. O resumo é uma consulta JPQL com sum e group by — a agregação acontece no banco. Valores em BigDecimal com escala fixa. PostgreSQL via Docker Compose; H2 isolado nos testes.
Copiei do controller. É isto que a API responde.
/api/resumo?ano=2026&mes=7200 OKResposta
{
"ano": 2026,
"mes": 7,
"totalReceitas": 8400.00,
"totalDespesas": 5231.47,
"saldo": 3168.53,
"porCategoria": [
{ "categoria": "Salário", "tipo": "RECEITA", "total": 8400.00 },
{ "categoria": "Aluguel", "tipo": "DESPESA", "total": 2600.00 },
{ "categoria": "Mercado", "tipo": "DESPESA", "total": 1487.32 }
]
}Os totais já vêm somados do banco. A aplicação não percorre transação nenhuma.
TransacaoRepository, a consulta que faz o trabalhoJPQLConsulta
select c.nome as categoria, t.tipo as tipo, sum(t.valor) as total
from Transacao t join t.categoria c
where t.data between :inicio and :fim
group by c.nome, t.tipo
order by sum(t.valor) descO group by roda no Postgres. Mil ou cem mil transações custam quase o mesmo.
O banco devolve o total já somado. Quem tem dez mil lançamentos abre a tela na mesma velocidade de quem tem dez.
double erra centavo, e erro de centavo em app de dinheiro aparece no extrato do usuário.
Não existe jeito de cadastrar despesa marcada como receita, porque o tipo vem da categoria. O modelo impede, então não depende de eu lembrar de validar.