API RESTful para gerenciamento de pagamentos multi-gateway, desenvolvida com AdonisJS 6 e TypeScript.
- AdonisJS 6 - Framework Node.js
- TypeScript - Tipagem estática
- MySQL 8 - Banco de dados
- Lucid ORM - ORM para gestão do banco
- VineJS - Validação de dados
- Japa - Framework de testes (TDD)
- Docker / Docker Compose - Containerização
- Docker e Docker Compose
# Clonar o repositório
git clone https://github.com/fbciriaco/payment-gateway-api.git
cd payment-gateway-api
# Subir todos os serviços
docker compose up --build -d
# A API estará disponível em http://localhost:3333
# Gateway 1 mock em http://localhost:3001
# Gateway 2 mock em http://localhost:3002| Senha | Role | |
|---|---|---|
| admin@payment.com | admin123 | ADMIN |
# Instalar dependências localmente
npm install
# Criar o banco de teste
docker exec payment-mysql mysql -u root -proot -e "CREATE DATABASE IF NOT EXISTS payment_gateway_test;"
# Rodar os testes
node ace test functionalNível 3 — Implementação completa incluindo:
- Valor da compra calculado no backend a partir de múltiplos produtos e quantidades
- Gateways com autenticação (Bearer token para Gateway 1, headers fixos para Gateway 2)
- Controle de acesso por roles (ADMIN, MANAGER, FINANCE, USER)
- TDD com 56 testes funcionais
- Docker Compose com MySQL, aplicação e mock dos gateways
Implementado com Strategy Pattern para facilitar a adição de novos gateways:
PurchaseController → PaymentService → GatewayFactory → GatewayAdapterInterface
├── Gateway1Adapter
└── Gateway2Adapter
Para adicionar um novo gateway, basta:
- Criar uma classe que implemente
GatewayAdapterInterface - Registrá-la no
GatewayFactory
Lógica de failover: os gateways são tentados em ordem de prioridade. Se o primeiro falhar, o sistema tenta automaticamente o próximo. Se todos falharem, retorna erro ao cliente.
| Tabela | Descrição |
|---|---|
| users | Usuários do sistema com roles (ADMIN, MANAGER, FINANCE, USER) |
| gateways | Gateways de pagamento com status ativo/inativo e prioridade |
| clients | Clientes (compradores) criados automaticamente na compra |
| products | Produtos com valor em centavos |
| transactions | Transações de pagamento com referência ao gateway e status |
| transaction_products | Relação entre transações e produtos (pivot com quantidade) |
| Ação | ADMIN | MANAGER | FINANCE | USER |
|---|---|---|---|---|
| CRUD de usuários | ✅ | ✅ | ❌ | ❌ |
| CRUD de produtos | ✅ | ✅ | ✅ | ❌ |
| Listar clientes | ✅ | ✅ | ✅ | ✅ |
| Detalhe do cliente | ✅ | ✅ | ✅ | ✅ |
| Listar transações | ✅ | ✅ | ✅ | ✅ |
| Detalhe da transação | ✅ | ✅ | ✅ | ✅ |
| Realizar reembolso | ✅ | ❌ | ✅ | ❌ |
| Gerenciar gateways | ✅ | ❌ | ❌ | ❌ |
| Método | Rota | Descrição |
|---|---|---|
| POST | /api/login |
Autenticação do usuário |
| POST | /api/purchases |
Realizar uma compra |
| Método | Rota | Descrição | Roles |
|---|---|---|---|
| GET | /api/users |
Listar usuários | ADMIN, MANAGER |
| POST | /api/users |
Criar usuário | ADMIN, MANAGER |
| PUT | /api/users/:id |
Atualizar usuário | ADMIN, MANAGER |
| DELETE | /api/users/:id |
Remover usuário | ADMIN, MANAGER |
| GET | /api/products |
Listar produtos | Todos autenticados |
| POST | /api/products |
Criar produto | ADMIN, MANAGER, FINANCE |
| PUT | /api/products/:id |
Atualizar produto | ADMIN, MANAGER, FINANCE |
| DELETE | /api/products/:id |
Remover produto | ADMIN, MANAGER, FINANCE |
| GET | /api/clients |
Listar clientes | Todos autenticados |
| GET | /api/clients/:id |
Detalhe do cliente com compras | Todos autenticados |
| GET | /api/transactions |
Listar transações | Todos autenticados |
| GET | /api/transactions/:id |
Detalhe da transação | Todos autenticados |
| POST | /api/transactions/:id/refund |
Reembolsar transação | ADMIN, FINANCE |
| PATCH | /api/gateways/:id/toggle |
Ativar/desativar gateway | ADMIN |
| PATCH | /api/gateways/:id/priority |
Alterar prioridade do gateway | ADMIN |
curl -X POST http://localhost:3333/api/login \
-H "Content-Type: application/json" \
-d '{"email": "admin@payment.com", "password": "admin123"}'Resposta:
{
"type": "bearer",
"token": "oat_MjQ..."
}curl -X POST http://localhost:3333/api/products \
-H "Content-Type: application/json" \
-H "Authorization: Bearer SEU_TOKEN" \
-d '{"name": "Produto A", "amount": 1500}'Resposta:
{
"id": 1,
"name": "Produto A",
"amount": 1500,
"createdAt": "2025-03-15T00:00:00.000+00:00",
"updatedAt": "2025-03-15T00:00:00.000+00:00"
}curl -X POST http://localhost:3333/api/purchases \
-H "Content-Type: application/json" \
-d '{
"name": "João Silva",
"email": "joao@email.com",
"cardNumber": "5569000000006063",
"cvv": "010",
"products": [
{"id": 1, "quantity": 2},
{"id": 2, "quantity": 1}
]
}'Resposta:
{
"id": 1,
"clientId": 1,
"gatewayId": 1,
"externalId": "abc-123",
"status": "PAID",
"amount": 4500,
"cardLastNumbers": "6063",
"createdAt": "2025-03-15T00:00:00.000+00:00",
"updatedAt": "2025-03-15T00:00:00.000+00:00"
}curl -X POST http://localhost:3333/api/transactions/1/refund \
-H "Authorization: Bearer SEU_TOKEN"Resposta:
{
"id": 1,
"status": "REFUNDED",
"amount": 4500
}curl -X PATCH http://localhost:3333/api/gateways/1/toggle \
-H "Authorization: Bearer SEU_TOKEN"curl -X PATCH http://localhost:3333/api/gateways/1/priority \
-H "Content-Type: application/json" \
-H "Authorization: Bearer SEU_TOKEN" \
-d '{"priority": 2}'- Senhas são hasheadas com scrypt e nunca expostas nas respostas da API
- Número do cartão não é armazenado — apenas os últimos 4 dígitos
- Tokens de acesso aos gateways são gerenciados internamente pelos adapters
- Strategy Pattern para os gateways, permitindo extensibilidade modular
- TDD (Red → Green → Refactor) como metodologia de desenvolvimento
- Enum centralizado para roles, evitando strings soltas no código
- Validação com VineJS em todas as rotas que recebem dados
firstOrCreatepara clientes, evitando duplicação na compra- Seeder idempotente com
firstOrCreate, seguro para múltiplas execuções - Access Tokens para autenticação stateless da API