“Dashboards confiáveis só existem quando snapshots, APIs e exports falam a mesma língua.” — #30DiasJava Field Notes
🎯 Objetivo do Day 10
Cheguei à metade da primeira quinzena do #30DiasJava e era hora de transformar os eventos financeiros do desafio em métricas que um board executivo possa confiar. O foco do dia foi entregar um Reporting Service que roda isolado do OLTP, gera snapshots diários e expõe dados em formatos que escalam do dashboard ao Excel.
🛠️ O que saiu do forno
- Snapshots Spring Batch: jobs particionados escrevem em
reporting_*usandoINSERT ... ON CONFLICTpara manter histórico sem recálculos. - Insight APIs + Redis: consultas agregadas servidas por projections JPA e cache com TTL curto — respostas em milissegundos.
- Exports self-service: geração PDF/CSV com Thymeleaf + OpenPDF, publicação em S3/MinIO e e-mail automático para as áreas interessadas.
- RBAC/OAuth2: escopos dedicados (
reporting:finance,reporting:leadership) controlam o que cada papel enxerga. - Observabilidade ponta a ponta: métricas como
reporting.batch.durationereporting.export.count, traces distribuídos e dashboards Grafana opinativos.
🧪 Decisões de arquitetura
- Batch isolado: jobs executam em um worker dedicado para não competir com o tráfego online.
- Projeções dedicadas: queries pré-otimizadas evitam n+1 e trazem apenas o necessário para os gráficos.
- Fila de exports: pedidos são persistidos, processados idempotentemente e versionados para auditoria.
- Governança de dados: cada snapshot recebe
datasetVersion, authoring metadata e é rastreável até o evento bruto.
📈 Por que importa
- Disponibiliza métricas repetíveis sem planilhas paralelas.
- Libera o time de engenharia das requisições ad hoc diárias.
- Mantém o banco transacional saudável: leitura pesada e exports rodam longe do OLTP.
- Garante alertas pró-ativos: qualquer batch acima de 10 minutos ou falha de export dispara incident response.
🔗 Recursos
- Deep dive: Reporting Service — Under the Hood
- Código: adelmonsouza/30DiasJava-Day10-ReportingService
- Projeto pessoal: Este é um projeto do desafio #30DiasJava, mantido independentemente para fins educacionais.
Next episode → Day 11/30 — Logging Service in Spring Boot