Mais controle, menos desperdício.
API REST para controle financeiro pessoal, permitindo gerenciar categorias, registrar receitas e despesas com recorrência automática, e visualizar relatórios financeiros detalhados.
CashWise é uma plataforma de gestão financeira pessoal que oferece:
- Cadastro de categorias personalizadas
- Registro de lançamentos (receitas e despesas)
- Sistema de recorrência automática
- Relatórios visuais com análises financeiras
- Filtros avançados por período, tipo e categoria
- ✅ CRUD de Categorias - Gerenciamento completo com validação de vínculo
- ✅ CRUD de Lançamentos - Receitas e despesas com recorrência
- ✅ Geração Automática - Lançamentos recorrentes criados automaticamente
- ✅ Filtros Avançados - Busca por período, tipo e categoria com paginação
- ✅ Relatórios Financeiros - Saldo, evolução mensal e distribuição por categoria
- ✅ Validações Robustas - Regras de negócio aplicadas via Bean Validation
- Java 17+
- Spring Boot 3.x
- Spring Data JPA
- Spring Web
- Bean Validation
- MySQL 8+
- Maven
- Hibernate (geração automática de schema)
- JDK 17 ou superior
- MySQL 8+
- Maven 3.8+
git clone https://github.com/DJFCoder/cashwise-API.git
cd cashwiseExecute o script SQL:
mysql -u root -p < src/main/resources/db/V1__cashwise_db.sqlOu crie manualmente:
CREATE DATABASE IF NOT EXISTS cashwise_db;Edite src/main/resources/application.properties:
spring.datasource.url=jdbc:mysql://localhost:3306/cashwise_db
spring.datasource.username=seu_usuario
spring.datasource.password=sua_senha
spring.jpa.hibernate.ddl-auto=update./mvnw spring-boot:runA API estará disponível em: http://localhost:8080
| Método | URI | Descrição | Corpo da Requisição | Resposta de Sucesso | Erros Possíveis |
|---|---|---|---|---|---|
| POST | / |
Cadastrar nova categoria | { "name": "Alimentação" } |
201 Created – CategoryResponse |
400 – nome inválido/duplicado |
| GET | /listar |
Listar todas categorias | — | 200 OK – List |
— |
| GET | /{id} |
Buscar categoria por ID | — | 200 OK – CategoryResponse |
404 – categoria não encontrada |
| PUT | /{id} |
Atualizar nome da categoria | { "name": "Viagem" } |
200 OK – CategoryResponse |
400 – nome inválido/duplicado404 – categoria não encontrada |
| DELETE | /{id} |
Excluir categoria* | — | 204 No Content |
404 – categoria não encontrada409 – categoria possui lançamentos vinculados |
{
"id": 3,
"name": "Alimentação"
}| Método | URI | Descrição | Corpo da Requisição | Resposta de Sucesso | Erros Possíveis |
|---|---|---|---|---|---|
| POST | / |
Cadastrar novo lançamento | TransactionRequest (JSON) | 201 Created – TransactionResponse |
400 – dados inválidos404 – categoria não encontrada |
| GET | /listar |
Listar com filtros e paginação | — (query params) | 200 OK – Page |
400 – parâmetros inválidos |
| GET | /{id} |
Buscar lançamento por ID | — | 200 OK – TransactionResponse |
404 – lançamento não encontrado |
| DELETE | /{id} |
Excluir lançamento* | — | 204 No Content |
404 – lançamento não encontrado |
Tipos válidos: RECEITA, DESPESA
Recorrências válidas: UNICA, DIARIA, SEMANAL, MENSAL, TRIMESTRAL, ANUAL
💡 Recorrências diferentes de UNICA geram automaticamente lançamentos futuros.
{
"type": "Receita",
"categoryId": 1,
"amount": 2500.00,
"description": "Salário mensal",
"recurrency": "MONTHLY"
}{
"id": 10,
"type": "Receita",
"category": { "id": 1, "name": "Salário" },
"amount": 2500.00,
"date": "2025-06-01",
"description": "Salário mensal",
"recurrency": "MONTHLY"
}| Parâmetro | Tipo | Obrigatório | Descrição | Exemplo |
|---|---|---|---|---|
startDate |
LocalDate | Não | Data inicial do período | 2025-01-01 |
endDate |
LocalDate | Não | Data final do período | 2025-06-30 |
type |
String | Não | Filtrar por tipo (Receita ou Despesa) |
Despesa |
categoryId |
Long | Não | Filtrar por categoria | 2 |
page |
int | Não | Número da página (0-based) | 0 |
size |
int | Não | Tamanho da página (padrão 20) | 10 |
sortBy |
String | Não | Campo de ordenação (padrão: createdAt) | amount |
sortDirection |
String | Não | asc ou desc (padrão: desc) |
asc |
GET /api/lancamento/listar?startDate=2025-01-01&endDate=2025-06-30&type=Despesa&page=0&size=10&sortBy=amount&sortDirection=desc| Método | URI | Descrição | Corpo da Requisição | Resposta de Sucesso | Erros Possíveis |
|---|---|---|---|---|---|
| POST | /{id}/desativar |
Desativa geração de filhos | — | 200 OK – RecurrencyOperationResponse |
404 – lançamento não encontrado400 – lançamento é filho |
| POST | /{id}/ativar |
Reativa geração de filhos | — | 200 OK – RecurrencyOperationResponse |
404 – não encontrado400 – filho ou UNIQUE |
| POST | /{id}/data-final |
Define/remove data limite | EndDateRequest | 200 OK – RecurrencyOperationResponse |
400 – data inválida ou filho404 – não encontrado |
| GET | /{id}/children |
Lista lançamentos filhos gerados | — | 200 OK – List |
404 – original não encontrado |
| GET | /{id}/count |
Conta quantidade de filhos gerados | — | 200 OK – ChildCountResponse |
404 – original não encontrado |
{ "endDate": "2025-12-31" }Envie null para remover a data de término (recorrência infinita).
{
"transactionId": 5,
"operation": "DEACTIVATED",
"message": "Recorrência desativada com sucesso. Novos lançamentos não serão mais gerados automaticamente."
}{
"parentTransactionId": 5,
"childCount": 3,
"message": "Lançamentos filhos encontrados"
}| Método | URI | Descrição | Parâmetros | Resposta de Sucesso | Erros Possíveis |
|---|---|---|---|---|---|
| GET | /balancete |
Saldo (receitas - despesas) | startDate, endDate (obrigatórios) |
200 OK – BalanceResponse |
400 – período inválido |
| GET | /distribuicao |
Gastos por categoria | startDate, endDate (obrigatórios) |
200 OK – DistributionResponse |
400 – período inválido |
| GET | /evolucao-mensal |
Evolução mensal | year (obrigatório) |
200 OK – MonthlyEvolutionResponse |
400 – ano inválido |
{
"startDate": "2025-01-01",
"endDate": "2025-06-30",
"revenues": 15000.00,
"expenses": 8000.00,
"balance": 7000.00,
"status": "SUPERAVIT"
}{
"startDate": "2025-01-01",
"endDate": "2025-06-30",
"distribution": {
"Alimentação": 2500.00,
"Transporte": 1200.00,
"Lazer": 800.00
},
"totalCategories": 3
}{
"year": 2025,
"monthlyData": [
{
"month": 1,
"year": 2025,
"revenues": 5000.00,
"expenses": 3000.00
},
{
"month": 2,
"year": 2025,
"revenues": 5500.00,
"expenses": 3200.00
}
],
"totalMonths": 2
}br.com.devjf.cashwise/
├── controller/ ← REST endpoints
├── domain/ ← entidades, enums, DTOs, mappers
├── service/ ← regras de negócio
├── repository/ ← acesso a dados
└── job/ ← RecurrencyJob (01:00 diário)
- ✔️ Todo lançamento deve estar vinculado a uma categoria existente
- ✔️ Valores devem ser maiores que zero
- ✔️ Recorrência é obrigatória e controlada pelo sistema
- ✔️ Lançamentos recorrentes geram automaticamente entradas futuras
- ✔️ Categorias só podem ser excluídas se não houver lançamentos vinculados
- ✔️ Lançamentos não podem ser editados (apenas excluídos)
- ✔️ Todos os valores são em Real (BRL)
- ✔️ Validações ocorrem via
@Validnos DTOs - ✔️ Job gera no máximo 2 filhos/dia por lançamento original
- ✔️ Relatórios somente-leitura, sem exportação no MVP
| Campo | Tipo | Restrições | Descrição |
|---|---|---|---|
| id | BIGINT | PK, AUTO_INCREMENT | Identificador único |
| name | VARCHAR(120) | NOT NULL, UNIQUE | Nome da categoria |
| created_at | DATETIME | NOT NULL | Data/hora de criação |
| updated_at | DATETIME | NOT NULL | Data/hora da última alteração |
| Campo | Tipo | Restrições | Descrição |
|---|---|---|---|
| id | BIGINT | PK, AUTO_INCREMENT | Identificador único |
| category_id | BIGINT | FK → category(id), NOT NULL | Categoria vinculada |
| type | ENUM | NOT NULL | RECEITA ou DESPESA |
| amount | DECIMAL(15,2) | NOT NULL, > 0 | Valor monetário (até 9999999999999.99) |
| description | VARCHAR(255) | NOT NULL | Descrição livre |
| recurrency | ENUM | NOT NULL | UNIQUE, DAILY, WEEKLY, MONTHLY, QUARTERLY, ANUAL |
| recurrency_active | BOOLEAN | DEFAULT TRUE | Indica se a recorrência está ativa (apenas para originais) |
| recurrency_end_date | DATE | NULL | Data limite da recorrência (NULL = infinita) |
| parent_transaction_id | BIGINT | FK → transaction(id), NULL | Referência para o lançamento original (filhos) |
| created_at | DATETIME | NOT NULL | Data/hora de criação |
| updated_at | DATETIME | NOT NULL | Data/hora da última alteração |
Índices recomendados:
CREATE INDEX idx_transaction_created_at ON transaction(created_at);
CREATE INDEX idx_transaction_category_id ON transaction(category_id);
CREATE INDEX idx_transaction_type ON transaction(type);
CREATE INDEX idx_transaction_parent_id ON transaction(parent_transaction_id);Execute os testes:
./mvnw testDesenvolvido com ☕ por DevJF
Para reportar bugs ou sugerir melhorias, abra uma issue.