API RESTful para gerenciamento de finanças pessoais. Permite que usuários criem contas, autentiquem-se com JWT e registrem suas transações financeiras (receitas, despesas e investimentos).
- Visão Geral
- Tecnologias e Bibliotecas
- Arquitetura do Projeto
- Estrutura de Pastas
- Pré-requisitos
- Como Clonar o Repositório
- Configuração do Ambiente
- Como Rodar o Projeto
- Banco de Dados e Migrações
- Rotas da API
- Autenticação
- Testes
- Qualidade de Código
- CI/CD
- Variáveis de Ambiente
A Finance App API é um backend Node.js que oferece:
- Cadastro, login e gerenciamento de usuários
- Autenticação via JWT com access token (15 min) e refresh token (30 dias)
- CRUD completo de transações financeiras por usuário
- Cálculo de saldo por período com breakdown de receitas, despesas e investimentos
- Documentação interativa com Swagger UI
| Tecnologia | Versão | Uso |
|---|---|---|
| Node.js | 20+ | Runtime JavaScript no servidor |
| Express | 5.x | Framework HTTP para criação das rotas e middlewares |
| Tecnologia | Versão | Uso |
|---|---|---|
| PostgreSQL | latest | Banco de dados relacional principal |
| Prisma ORM | 6.x | ORM para comunicação com o banco, migrações e tipagem |
| Biblioteca | Versão | Uso |
|---|---|---|
| jsonwebtoken | 9.x | Geração e verificação de tokens JWT |
| bcrypt | 6.x | Hash seguro de senhas (custo 10) |
| bcryptjs | 3.x | Alternativa JS pura do bcrypt |
| Biblioteca | Versão | Uso |
|---|---|---|
| Zod | 3.x | Validação e tipagem de schemas nos controllers |
| validator | 13.x | Validação de formatos (moeda, email, etc.) |
| Biblioteca | Versão | Uso |
|---|---|---|
| uuid | 13.x | Geração de IDs únicos (UUID v4) |
| dayjs | 1.x | Manipulação e formatação de datas |
| dotenv | 17.x | Carregamento de variáveis de ambiente do .env |
| dotenv-cli | 11.x | Injeção de .env em scripts npm |
| swagger-ui-express | 5.x | Documentação interativa da API |
| Tecnologia | Uso |
|---|---|
| Docker | Containerização do PostgreSQL (desenvolvimento e testes) |
| Docker Compose | Orquestração dos containers |
| Ferramenta | Versão | Uso |
|---|---|---|
| Jest | 29.x | Framework de testes unitários e de integração |
| Supertest | 7.x | Testes de requisições HTTP (E2E) |
| @faker-js/faker | 9.x | Geração de dados falsos para testes |
| ESLint | 9.x | Linter para padronização e qualidade do código |
| Prettier | 3.x | Formatação automática do código |
| Husky | 9.x | Git hooks (pre-commit e commit-msg) |
| lint-staged | 16.x | Executa linter/prettier apenas nos arquivos alterados antes do commit |
| git-commit-msg-linter | 5.x | Valida a mensagem de commit no padrão Conventional Commits |
O projeto segue uma arquitetura em camadas inspirada nos princípios de Clean Architecture e SOLID. Cada camada tem uma responsabilidade bem definida e se comunica apenas com a camada imediatamente abaixo.
HTTP Request
│
▼
┌──────────────┐
│ Routes │ Define os endpoints e chama os controllers via Factory
└──────┬───────┘
│
▼
┌──────────────┐
│ Middleware │ Autenticação JWT (extrai userId do token)
└──────┬───────┘
│
▼
┌──────────────┐
│ Controller │ Valida input (Zod), chama Use Case, formata resposta HTTP
└──────┬───────┘
│
▼
┌──────────────┐
│ Use Case │ Contém toda a regra de negócio da aplicação
└──────┬───────┘
│
▼
┌──────────────┐
│ Repository │ Acessa o banco de dados via Prisma ORM
└──────┬───────┘
│
▼
┌──────────────┐
│ PostgreSQL │ Banco de dados relacional
└──────────────┘
| Padrão | Descrição |
|---|---|
| Factory Pattern | Cada controller é criado por uma função make*Controller() que instancia e injeta todas as dependências |
| Dependency Injection (DI) | Use Cases e Repositories são injetados via construtor, nunca instanciados internamente |
| Repository Pattern | Toda comunicação com o banco é abstraída em classes de Repository |
| Adapter Pattern | Serviços externos (bcrypt, uuid, jwt) são encapsulados em Adapters para fácil substituição |
| ESM Modules | O projeto usa "type": "module" — todos os imports/exports são sintaxe ES Module (import/export) |
- Testabilidade: Como as dependências são injetadas, é possível substituir por mocks nos testes sem modificar o código de produção.
- Manutenibilidade: Cada arquivo tem uma responsabilidade única (Single Responsibility Principle).
- Desacoplamento: Trocar o banco de dados ou a lib de hash de senha não exige alterar Use Cases ou Controllers.
finance-app-api/
├── .github/
│ └── workflows/
│ └── main.yml # Pipeline CI/CD (GitHub Actions)
├── .husky/ # Git hooks configurados pelo Husky
├── docs/
│ └── swagger.json # Documentação OpenAPI (Swagger)
├── prisma/
│ ├── prisma.js # Instância singleton do PrismaClient
│ ├── schema.prisma # Definição dos modelos do banco de dados
│ └── migrations/ # Histórico de migrações do banco
├── src/
│ ├── app.js # Configuração do Express (middlewares e rotas)
│ ├── adapters/ # Adaptadores para serviços externos
│ │ ├── id-generator.js # Gera UUIDs (uuid v4)
│ │ ├── password-hasher.js # Hash de senha (bcrypt)
│ │ ├── password-comparator.js # Compara senha com hash
│ │ ├── tokens-generator.js # Gera access + refresh token (JWT)
│ │ └── token-verifier.js # Verifica e decodifica JWT
│ ├── controllers/ # Recebem a requisição, validam e respondem
│ │ ├── helpers/
│ │ │ └── http.js # Helpers de resposta (ok, created, badRequest, etc.)
│ │ ├── user/ # Controllers de usuário
│ │ └── transaction/ # Controllers de transação
│ ├── errors/ # Classes de erros customizados
│ │ ├── users.js # EmailAlreadyInUseError, UserNotFoundError, etc.
│ │ └── transactions.js # TransactionNotFoundError, etc.
│ ├── factories/
│ │ └── controllers/
│ │ ├── user.js # Factories que montam e injetam dependências dos controllers de usuário
│ │ └── transaction.js # Factories dos controllers de transação
│ ├── middlewares/
│ │ └── auth.js # Middleware JWT: extrai e valida o Bearer Token
│ ├── repositories/
│ │ └── postgres/ # Implementações do Repository para PostgreSQL
│ │ ├── user/ # Operações CRUD de usuários via Prisma
│ │ └── transaction/ # Operações CRUD de transações via Prisma
│ ├── routes/
│ │ ├── users.js # Rotas de usuário (/api/users)
│ │ ├── transactions.js # Rotas de transação (/api/transactions)
│ │ ├── users.e2e.test.js # Testes E2E das rotas de usuário
│ │ └── transactions.e2e.test.js # Testes E2E das rotas de transação
│ ├── schemas/ # Schemas de validação com Zod
│ │ ├── user.js # createUserSchema, updateUserSchema, loginSchema
│ │ └── transaction.js # createTransactionSchema, updateTransactionSchema
│ ├── tests/
│ │ └── fixtures/ # Dados fixos reutilizáveis nos testes
│ └── use-cases/ # Regras de negócio da aplicação
│ ├── user/ # create, delete, get-by-id, get-balance, login, refresh-token, update
│ └── transaction/ # create, delete, get-by-user-id, update
├── index.js # Entry point — inicia o servidor Express
├── docker-compose.yml # Containers do PostgreSQL (dev e test)
├── jest.config.js # Configuração do Jest
├── jest.global-setup.js # Sobe o container de teste e aplica migrações antes dos testes
├── jest.setup-after-env.js # Limpa o banco de testes antes de cada teste
├── eslint.config.js # Configuração do ESLint
├── .prettierrc.json # Configuração do Prettier
├── .env.example # Exemplo do arquivo .env (desenvolvimento)
└── .env.test.example # Exemplo do arquivo .env.test (testes)
Antes de começar, certifique-se de ter instalado na sua máquina:
- Node.js — versão 20 ou superior
node -v # deve exibir v20.x.x ou superior - npm — vem junto com o Node.js
npm -v
- Docker e Docker Compose — para rodar o PostgreSQL
docker -v docker compose version
- Git — para clonar o repositório
git --version
# Clone o repositório
git clone https://github.com/silvamaarcus/finance-app-api.git
# Acesse a pasta do projeto
cd finance-app-apinpm installO comando
postinstallroda automaticamentehusky(configura os git hooks) eprisma generate(gera o Prisma Client).
Copie os arquivos de exemplo e preencha com seus valores:
# Para desenvolvimento
cp .env.example .env
# Para testes
cp .env.test.example .env.testEdite o arquivo .env com as informações do seu banco:
PORT=8080
POSTGRES_USER=postgres
POSTGRES_PASSWORD=password
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_DATABASE=finance-app
DATABASE_URL=postgresql://postgres:password@localhost:5432/finance-app
JWT_ACCESS_TOKEN_SECRET=sua_chave_secreta_de_access_token_aqui
JWT_REFRESH_TOKEN_SECRET=sua_chave_secreta_de_refresh_token_aquiEdite o arquivo .env.test com as informações do banco de testes (porta 5433):
DATABASE_URL=postgresql://postgres:password@localhost:5433/finance-app
JWT_ACCESS_TOKEN_SECRET=sua_chave_secreta_de_access_token_aqui
JWT_REFRESH_TOKEN_SECRET=sua_chave_secreta_de_refresh_token_aquiPor que duas portas? O
docker-compose.ymlsobe dois containers: um na porta5432(desenvolvimento) e outro na porta5433(testes). Assim os testes nunca afetam o banco de desenvolvimento.
# Sobe o container do PostgreSQL para desenvolvimento em segundo plano
docker compose up -d postgres# Aplica todas as migrações e cria as tabelas no banco de dados
npx prisma migrate deploy# Modo desenvolvimento (reinicia automaticamente ao salvar arquivos)
npm run start:dev
# Modo produção
npm startO servidor estará disponível em: http://localhost:8080
A documentação Swagger estará em: http://localhost:8080/docs
O projeto usa Prisma ORM com PostgreSQL. Os modelos são:
| Campo | Tipo | Descrição |
|---|---|---|
id |
String (UUID) | Identificador único |
first_name |
String | Primeiro nome (max 50 chars) |
last_name |
String | Último nome (max 50 chars) |
email |
String (único) | E-mail do usuário (max 100 chars) |
password |
String | Senha hasheada com bcrypt (max 100 chars) |
| Campo | Tipo | Descrição |
|---|---|---|
id |
String (UUID) | Identificador único |
user_id |
String | Referência ao usuário dono da transação |
name |
String | Nome/descrição da transação (max 50 chars) |
date |
DateTime | Data da transação |
amount |
Decimal | Valor (10 dígitos, 2 casas decimais) |
type |
Enum | EARNING | EXPENSE | INVESTMENT |
Cascade Delete: ao deletar um usuário, todas as suas transações são deletadas automaticamente.
# Criar uma nova migração após alterar o schema.prisma
npx prisma migrate dev --name nome_da_migracao
# Aplicar migrações em produção
npx prisma migrate deploy
# Abrir o Prisma Studio (interface visual do banco)
npx prisma studio
# Regenerar o Prisma Client (necessário após alterar o schema)
npx prisma generateA URL base é: http://localhost:8080
A documentação completa e interativa está disponível em: http://localhost:8080/docs
| Método | Rota | Autenticação | Descrição |
|---|---|---|---|
POST |
/api/users |
Não | Cria um novo usuário |
GET |
/api/users/me |
Sim | Retorna os dados do usuário autenticado |
PATCH |
/api/users/me |
Sim | Atualiza os dados do usuário autenticado |
DELETE |
/api/users/me |
Sim | Deleta o usuário autenticado |
GET |
/api/users/me/balance |
Sim | Retorna o saldo financeiro por período |
POST |
/api/users/login |
Não | Autentica o usuário e retorna os tokens JWT |
POST |
/api/users/refresh-token |
Não | Gera um novo par de tokens usando o refresh token |
// Body da requisição
{
"first_name": "João",
"last_name": "Silva",
"email": "joao@email.com",
"password": "senha123"
}
// Resposta 201 Created
{
"id": "uuid-gerado",
"first_name": "João",
"last_name": "Silva",
"email": "joao@email.com",
"tokens": {
"accessToken": "eyJhbGci...",
"refreshToken": "eyJhbGci..."
}
}// Resposta 200 OK
{
"earnings": { "amount": 5000, "percentage": 62 },
"expenses": { "amount": 2000, "percentage": 25 },
"investments": { "amount": 1000, "percentage": 13 },
"balance": 2000
}Todas as rotas de transação exigem autenticação (Bearer Token).
| Método | Rota | Descrição |
|---|---|---|
GET |
/api/transactions/me |
Lista as transações do usuário autenticado |
POST |
/api/transactions/me |
Cria uma nova transação |
PATCH |
/api/transactions/me/:transactionId |
Atualiza uma transação existente |
DELETE |
/api/transactions/me/:transactionId |
Deleta uma transação |
// Body da requisição
{
"name": "Salário",
"date": "2024-01-05T00:00:00.000Z",
"amount": 5000,
"type": "EARNING"
}
// Resposta 201 Created
{
"id": "uuid-gerado",
"user_id": "uuid-do-usuario",
"name": "Salário",
"date": "2024-01-05T00:00:00.000Z",
"amount": "5000.00",
"type": "EARNING"
}A API usa JWT (JSON Web Token) com dois tokens:
| Token | Duração | Uso |
|---|---|---|
accessToken |
15 minutos | Enviado no header de cada requisição protegida |
refreshToken |
30 dias | Usado para gerar um novo par de tokens quando o accessToken expirar |
Inclua o token no header Authorization de todas as requisições protegidas:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
1. POST /api/users/login → recebe { accessToken, refreshToken }
2. Usa o accessToken nas requisições (válido por 15 min)
3. Quando expirar: POST /api/users/refresh-token → recebe novos tokens
O projeto possui três tipos de testes:
| Tipo | Localização | Descrição |
|---|---|---|
| Unitários | src/use-cases/**/*.test.js |
Testam a lógica de negócio isolada (com mocks) |
| Integração | src/repositories/**/*.test.js |
Testam a comunicação real com o banco de dados |
| E2E | src/routes/**/*.e2e.test.js |
Testam o fluxo completo da requisição HTTP ao banco |
Antes de rodar os testes, o Jest automaticamente:
- Sobe o container
postgres-testvia Docker Compose (porta 5433) - Aplica as migrações no banco de teste com
prisma db push - Limpa todas as tabelas do banco antes de cada teste para garantir isolamento
# Roda todos os testes uma vez
npm test
# Roda em modo watch (re-executa ao salvar arquivos)
npm run test:watch
# Roda os testes e gera relatório de cobertura
npm run test:coverageO relatório de cobertura é gerado na pasta
coverage/. Abracoverage/lcov-report/index.htmlno navegador para ver o resultado visual.
✓ CreateUserUseCase — should create user successfully
✓ CreateUserUseCase — should throw EmailAlreadyInUseError if email is already in use
✓ POST /api/users — should return 201 when user is created
✓ POST /api/users/login — should return 200 and tokens on valid credentials
...
O projeto usa várias ferramentas para manter a qualidade e consistência do código.
Verifica erros e padrões de código:
# Verifica os arquivos sem corrigir
npm run eslint:checkFormata o código automaticamente:
# Verifica se o código está formatado
npm run prettier:check
# Formata todos os arquivos de src/
npm run prettier:fixOs git hooks configurados pelo Husky garantem que:
- Antes de cada commit (
pre-commit): ESLint e Prettier são executados automaticamente nos arquivos alterados vialint-staged. - Na mensagem de commit (
commit-msg): O git-commit-msg-linter valida que a mensagem segue o padrão Conventional Commits.
Todas as mensagens de commit devem seguir o padrão:
tipo: descrição curta
Exemplos:
feat: add login endpoint
fix: correct password comparison logic
refactor: extract token generator to adapter
test: add unit tests for create-user use case
docs: update README
chore: update dependencies
O projeto possui um pipeline de GitHub Actions em .github/workflows/main.yml que é executado a cada push na branch main.
push na branch main
│
▼
┌───────────────────┐
│ Job: check │
│ ───────────── │
│ 1. Checkout │
│ 2. Setup Node 20 │
│ 3. npm ci │
│ 4. ESLint check │
│ 5. Prettier check│
│ 6. npm test │
└────────┬──────────┘
│ (se tudo passar)
▼
┌───────────────────┐
│ Job: migrate │
│ ───────────── │
│ 1. Checkout │
│ 2. Setup Node 20 │
│ 3. npm ci │
│ 4. prisma migrate│
│ deploy │
└───────────────────┘
Para o pipeline de produção funcionar, configure os seguintes secrets no repositório (Settings > Secrets and variables > Actions):
| Secret | Descrição |
|---|---|
DATABASE_URL |
URL de conexão do banco de dados de produção |
JWT_ACCESS_TOKEN_SECRET |
Chave secreta para assinar access tokens |
JWT_REFRESH_TOKEN_SECRET |
Chave secreta para assinar refresh tokens |
| Variável | Exemplo | Descrição |
|---|---|---|
PORT |
8080 |
Porta em que o servidor Express vai rodar |
POSTGRES_USER |
postgres |
Usuário do PostgreSQL |
POSTGRES_PASSWORD |
password |
Senha do PostgreSQL |
POSTGRES_HOST |
localhost |
Host do banco de dados |
POSTGRES_PORT |
5432 |
Porta do banco de dados |
POSTGRES_DATABASE |
finance-app |
Nome do banco de dados |
DATABASE_URL |
postgresql://postgres:password@localhost:5432/finance-app |
URL completa de conexão (usada pelo Prisma) |
JWT_ACCESS_TOKEN_SECRET |
sua_chave_secreta |
Chave para assinar access tokens (use uma string longa e aleatória) |
JWT_REFRESH_TOKEN_SECRET |
outra_chave_secreta |
Chave para assinar refresh tokens (diferente da de access) |
| Variável | Exemplo | Descrição |
|---|---|---|
DATABASE_URL |
postgresql://postgres:password@localhost:5433/finance-app |
URL do banco de testes (porta 5433) |
JWT_ACCESS_TOKEN_SECRET |
test_secret |
Chave para testes |
JWT_REFRESH_TOKEN_SECRET |
test_secret_refresh |
Chave para testes |
Segurança: nunca commite os arquivos
.envou.env.testcom valores reais. Eles estão no.gitignore.
A API retorna erros padronizados com mensagens descritivas:
| Erro | HTTP | Quando ocorre |
|---|---|---|
EmailAlreadyInUseError |
400 | Email já cadastrado ao criar usuário |
UserNotFoundError |
404 | Usuário não encontrado |
InvalidPasswordError |
401 | Senha incorreta no login |
ForbiddenError |
403 | Usuário sem permissão para a operação |
UnauthorizedError |
401 | Token ausente, inválido ou expirado |
TransactionNotFoundError |
404 | Transação não encontrada |
ISC — Marcus