FinControl — Controle Financeiro Pessoal
Sistema completo de gestão financeira pessoal.
Spring Boot 3 · Angular 20 · PostgreSQL 15 · Liquibase · Node 22
fincontrol/
│
├── backend/ ← Spring Boot 3 / Java 21
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ ├── java/com/fincontrol/
│ │ │ ├── FinControlApplication.java
│ │ │ ├── config/
│ │ │ │ └── SecurityConfig.java
│ │ │ ├── controller/
│ │ │ │ ├── AuthController.java
│ │ │ │ ├── DashboardController.java
│ │ │ │ ├── GoalController.java
│ │ │ │ ├── ReportController.java
│ │ │ │ └── TransactionController.java
│ │ │ ├── dto/
│ │ │ │ ├── AlertDto.java
│ │ │ │ ├── AnnualSummaryResponse.java
│ │ │ │ ├── AuthResponse.java
│ │ │ │ ├── DashboardResponse.java
│ │ │ │ ├── GoalRequest.java
│ │ │ │ ├── GoalResponse.java
│ │ │ │ ├── MonthSummary.java
│ │ │ │ ├── TransactionRequest.java
│ │ │ │ ├── TransactionResponse.java
│ │ │ │ └── UserDto.java
│ │ │ ├── entity/
│ │ │ │ ├── Goal.java
│ │ │ │ ├── Transaction.java
│ │ │ │ └── User.java
│ │ │ ├── exception/
│ │ │ │ ├── GlobalExceptionHandler.java
│ │ │ │ └── ResourceNotFoundException.java
│ │ │ ├── repository/
│ │ │ │ ├── GoalRepository.java
│ │ │ │ ├── TransactionRepository.java
│ │ │ │ └── UserRepository.java
│ │ │ ├── security/
│ │ │ │ ├── CustomOAuth2UserService.java
│ │ │ │ ├── JwtAuthenticationFilter.java
│ │ │ │ ├── JwtTokenProvider.java
│ │ │ │ └── OAuth2SuccessHandler.java
│ │ │ └── service/
│ │ │ ├── DashboardService.java
│ │ │ ├── EmailAlertService.java
│ │ │ ├── GoalService.java
│ │ │ ├── ReportService.java
│ │ │ └── TransactionService.java
│ │ └── resources/
│ │ ├── application.yml
│ │ └── db/changelog/
│ │ ├── db.changelog-master.yml
│ │ └── changes/
│ │ ├── v1.0.0__create_users_table.yml
│ │ ├── v1.1.0__create_transactions_table.yml
│ │ ├── v1.2.0__create_goals_table.yml
│ │ └── v1.3.0__create_indexes.yml
│ └── test/java/com/fincontrol/
│ ├── controller/
│ │ └── TransactionControllerTest.java
│ └── service/
│ ├── GoalServiceTest.java
│ └── TransactionServiceTest.java
│
└── frontend/ ← Angular 20 / Node 22
├── angular.json
├── package.json
├── tsconfig.json
├── tsconfig.app.json
├── tsconfig.spec.json
└── src/
├── index.html
├── main.ts
├── styles.css
├── environments/
│ ├── environment.ts ← base (aponta para localhost)
│ ├── environment.dev.ts ← development
│ └── environment.prod.ts ← production
└── app/
├── app.component.ts
├── app.config.ts ← providers: router, http, animations
├── app.routes.ts ← lazy-loaded routes
├── core/
│ ├── guards/
│ │ └── auth.guard.ts
│ ├── interceptors/
│ │ └── auth.interceptor.ts ← injeta JWT + trata 401
│ └── services/
│ ├── auth.service.ts
│ ├── dashboard.service.ts
│ ├── format.service.ts ← moeda, %, mês
│ ├── goal.service.ts
│ ├── report.service.ts
│ ├── transaction.service.ts
│ ├── auth.service.spec.ts
│ ├── format.service.spec.ts
│ └── transaction.service.spec.ts
├── features/
│ ├── auth/
│ │ ├── login/login.component.ts
│ │ └── callback/callback.component.ts
│ ├── dashboard/dashboard.component.ts
│ ├── lancamentos/lancamentos.component.ts
│ ├── cartoes/cartoes.component.ts ← resumo por cartão + tabela anual
│ ├── poupanca/poupanca.component.ts ← metas + simulador
│ ├── metas/metas.component.ts
│ └── historico/historico.component.ts
└── shared/
├── components/layout/layout.component.ts
└── models/
├── user.model.ts
├── transaction.model.ts ← CATEGORY_LABELS, tipos
├── goal.model.ts ← GOAL_TYPE_LABELS, GOAL_TYPE_ICONS
├── dashboard.model.ts
└── index.ts ← barrel export
Ferramenta
Versão
Java
21
Maven
3.9+
Node.js
22+
Angular CLI
20+
PostgreSQL
15+
# Verificar versões
java --version
node --version
ng version
CREATE DATABASE fincontrol ;
CREATE USER fincontrol WITH PASSWORD ' sua_senha' ;
GRANT ALL PRIVILEGES ON DATABASE fincontrol TO fincontrol;
O Liquibase cria o schema automaticamente — não execute SQL manualmente.
# ── Banco ─────────────────────────────────────────────────
export DB_USERNAME=fincontrol
export DB_PASSWORD=sua_senha
# ── Google OAuth2 ──────────────────────────────────────────
# Obtenha em: https://console.cloud.google.com
# Redirect URI: http://localhost:8080/login/oauth2/code/google
export GOOGLE_CLIENT_ID=seu_client_id.apps.googleusercontent.com
export GOOGLE_CLIENT_SECRET=seu_client_secret
# ── JWT ────────────────────────────────────────────────────
export JWT_SECRET=minima-32-caracteres-aqui-seguro-prod
# ── Email (Gmail App Password) ─────────────────────────────
export MAIL_USERNAME=seu@gmail.com
export MAIL_PASSWORD=xxxx-xxxx-xxxx-xxxx
# ── URLs ───────────────────────────────────────────────────
export FRONTEND_URL=http://localhost:4200
cd backend
mvn spring-boot:run
# API em http://localhost:8080
# Liquibase executa e cria as tabelas automaticamente
cd frontend
npm install
npm start
# App em http://localhost:4200
Backend (JUnit 5 + Mockito)
cd backend
mvn test
# Relatório em: target/surefire-reports/
Frontend (Jasmine + Karma)
cd frontend
npm test
# ou headless para CI:
npm test -- --watch=false --browsers=ChromeHeadless
🗃️ Liquibase — Adicionando Migrações
# Crie o arquivo com a convenção de nome:
touch backend/src/main/resources/db/changelog/changes/v1.4.0__add_tags_table.yml
Registre no master:
# db.changelog-master.yml
- include :
file : db/changelog/changes/v1.4.0__add_tags_table.yml
Verificar histórico de migrações aplicadas:
SELECT id, author, description, dateexecuted
FROM databasechangelog
ORDER BY dateexecuted;
Rollback (se necessário):
mvn liquibase:rollback -Dliquibase.rollbackCount=1
Método
Endpoint
Descrição
GET
/api/auth/me
Usuário autenticado
PATCH
/api/auth/alerts?enabled=true
Toggle alertas por e-mail
Método
Endpoint
Descrição
GET
/api/dashboard?year=2026&month=2
Resumo do mês
GET
/api/dashboard/annual
Todos os anos
GET
/api/dashboard/years
Anos com lançamentos
Método
Endpoint
Descrição
GET
/api/transactions?year=2026
Por ano
GET
/api/transactions?year=2026&month=2
Por mês
GET
/api/transactions/recent
Últimos 10
POST
/api/transactions
Criar
PUT
/api/transactions/{id}
Atualizar
DELETE
/api/transactions/{id}
Excluir
Método
Endpoint
Descrição
GET
/api/goals
Listar
GET
/api/goals/{id}
Detalhe
POST
/api/goals
Criar
PUT
/api/goals/{id}
Atualizar
DELETE
/api/goals/{id}
Excluir
Método
Endpoint
Descrição
GET
/api/reports/pdf?year=2026
PDF anual
GET
/api/reports/pdf?year=2026&month=2
PDF mensal
# docker-compose.yml
version : ' 3.9'
services :
db :
image : postgres:15-alpine
environment :
POSTGRES_DB : fincontrol
POSTGRES_USER : fincontrol
POSTGRES_PASSWORD : fincontrol123
ports :
- " 5432:5432"
volumes :
- pgdata:/var/lib/postgresql/data
healthcheck :
test : ["CMD-SHELL", "pg_isready -U fincontrol"]
interval : 5s
timeout : 5s
retries : 5
volumes :
pgdata :
Angular 20 (Standalone Components · OnPush · Signals)
│ HTTP + Bearer JWT
▼
Spring Boot 3 API
│
├── SecurityConfig ← CORS, CSRF desabilitado, Stateless
├── JwtAuthFilter ← Valida token em cada request
├── OAuth2SuccessHandler ← Gera JWT após login Google
│
├── Controllers ← Recebem requests HTTP, mapeiam para DTOs
├── Services ← Lógica de negócio, sem acoplamento com HTTP
├── Repositories ← JPQL queries tipadas, sem SQL manual
└── Entities ← JPA + Lombok
│
▼
PostgreSQL 15
└── Liquibase ← Único dono do schema, migrações versionadas
1. Usuário clica "Entrar com Google"
2. Angular redireciona → /oauth2/authorization/google
3. Spring redireciona → Google OAuth2
4. Google autentica → callback para /login/oauth2/code/google
5. CustomOAuth2UserService cria/atualiza User no banco
6. OAuth2SuccessHandler gera JWT e redireciona:
→ http://localhost:4200/auth/callback?token=eyJ...
7. CallbackComponent lê o token, salva no localStorage
8. authInterceptor injeta "Authorization: Bearer {token}" em todas as requests