Esta é uma implementação propositalmente problemática de uma API de pagamentos usando Kotlin + Ktor + MongoDB para ser usada como exemplo em entrevistas técnicas.
- Docker e Docker Compose
- JDK 17+ (para desenvolvimento local)
# Subir a aplicação completa (API + MongoDB)
docker-compose up --build
# A API estará disponível em http://localhost:8080# 1. Subir apenas o MongoDB
docker-compose up mongodb -d
# 2. Executar a aplicação
./gradlew run- ✅ Kotlin + Ktor - Framework web
- ✅ MongoDB - Banco de dados
- ✅ Koin - Injeção de dependência
- ✅ KMongo - Driver MongoDB para Kotlin
- ✅ Docker Compose - Orquestração de containers
Você deve construir uma API de pagamentos para carteiras virtuais (wallets) que respeite políticas de limite por período (diurno, noturno, final de semana) e garanta consistência dos registros mesmo em situações de múltiplos acessos simultâneos ou requisições repetidas.
- Linguagem: Kotlin ou Java (preferencial).
- Banco de dados: o candidato poderá definir qual o banco de dados se encaixa nos requisitos.
- Outras stacks são aceitáveis, desde que atendam aos requisitos funcionais e não funcionais, mas será considerado diferencial seguir as preferências acima.
Recomendações para o banco de dados:
- Defina índices para consultas de listagem e verificação de regras (
constraints).- Utilize chaves/estratégias que impeçam gravações duplicadas conforme as regras deste desafio (por exemplo, índice único sobre um identificador derivado por carteira + atributos de pagamento, se optar por essa abordagem).
- Cada carteira possui
ownerName(não vazio ou nulo). - Valor máximo por pagamento: R$ 1.000,00.
- Limites padrão:
- Diurno (06:00–18:00): até R$ 4.000,00 por dia.
- Noturno (18:00–06:00): até R$ 1.000,00 por noite.
- Final de semana (sábado/domingo, 00:00–24:00): até R$ 1.000,00 por dia.
- O limite é diário por período. Uma carteira pode chegar a R$ 5.000,00 no mesmo dia útil (4k no período diurno + 1k no noturno).
- As bordas devem ser respeitadas:
>= 06:00:00e< 18:00:00→ diurno>= 18:00:00e< 06:00:00(do dia seguinte) → noturno
- Cada carteira pode estar vinculada a uma política de limites.
- O sistema deve suportar mais de um tipo de política, por categoria. Exemplos de categorias:
VALUE_LIMIT(limites por valor total/por período) — categoria da política padrão (default).TX_COUNT_LIMIT(limites por quantidade de transações por dia) — exemplo em Bônus.
- A política ativa de cada carteira deve ser resolvida em tempo de execução.
- A inclusão de uma nova política não deve exigir alterações no fluxo principal de pagamento.
Observação: para este desafio, considere uma política ativa por carteira. A política padrão deve ser de categoria
VALUE_LIMIT(apenas limites de valor). A tarefa bônus propõe uma política alternativa de categoriaTX_COUNT_LIMITpara demonstrar extensibilidade.
POST /wallets
{
"ownerName": "string"
}
201 Created
{
"id": "uuid",
"ownerName": "string",
"createdAt": "2024-08-25T22:31:44.4758Z"
}GET /wallets/{walletId}/policies
200 OK
{
"data": [
{
"id": "uuid",
"name": "DEFAULT_VALUE_LIMIT",
"category": "VALUE_LIMIT",
"maxPerPayment": 1000,
"daytimeDailyLimit": 4000,
"nighttimeDailyLimit": 1000,
"weekendDailyLimit": 1000,
"createdAt": "2024-08-20T10:00:00.0000Z",
"updatedAt": "2024-08-26T12:34:56.7890Z"
}
],
"meta": {
"total": 1
}
}POST /wallets/{walletId}/payments
Body:
{
"amount": 999.99,
"occurredAt": "2024-08-26T09:42:17.2500Z"
}
Regras:
- O valor deve ser maior que zero e no máximo R$ 1.000,00.
- O sistema deve estar preparado para não processar o mesmo pagamento mais de uma vez, mesmo que a requisição seja repetida (por exemplo, devido a falhas de rede ou envios duplicados pelo cliente).
- Quando duas ou mais requisições acontecerem quase ao mesmo tempo para a mesma carteira, o consumo de limite não pode ultrapassar o valor permitido.
- Caso julgue necessário, você pode incluir campos adicionais no corpo ou cabeçalhos da requisição para permitir a identificação única de tentativas de pagamento.
201 Created
{
"paymentId": "uuid",
"status": "APPROVED",
"amount": 999.99,
"occurredAt": "2024-08-26T09:42:17.2500Z"
}422 quando não há limite suficiente.
409 quando uma tentativa repetida contém dados diferentes de um pagamento já registrado.
400 para erros de validação.
GET /wallets/{walletId}/payments?startDate=2024-08-25T00:00:00.0000Z&endDate=2024-08-26T23:59:59.9999Z&cursor=abc123
startDateeendDatesão opcionais. Se ausentes, retornar todos os pagamentos da carteira.- A listagem deve retornar no formato padrão utilizado em nossas APIs, com
dataemeta. - A paginação deve ser feita por cursor (
nextCursor,previousCursor).
200 OK
{
"data": [
{
"id": "uuid",
"walletId": "uuid",
"amount": 250.00,
"occurredAt": "2024-08-25T14:22:08.1234Z",
"status": "APPROVED",
"createdAt": "2024-08-25T14:22:08.2234Z",
"updatedAt": "2024-08-25T14:22:08.2234Z"
},
{
"id": "uuid",
"walletId": "uuid",
"amount": 500.00,
"occurredAt": "2024-08-25T17:59:59.9999Z",
"status": "APPROVED",
"createdAt": "2024-08-25T18:00:00.0500Z",
"updatedAt": "2024-08-25T18:00:00.0500Z"
}
],
"meta": {
"nextCursor": "def456",
"previousCursor": null,
"total": 2,
"totalMatches": null
}
}Categoria da política (campo obrigatório):
VALUE_LIMIT: política baseada em valores (limites por período e valor máximo por pagamento).TX_COUNT_LIMIT: política baseada em quantidade de transações por dia (ver Bônus).
POST /policies
{
"name": "DEFAULT_VALUE_LIMIT",
"category": "VALUE_LIMIT",
"maxPerPayment": 1000,
"daytimeDailyLimit": 4000,
"nighttimeDailyLimit": 1000,
"weekendDailyLimit": 1000
}
GET /policies
200 OK
{
"data": [
{
"id": "uuid",
"name": "DEFAULT_VALUE_LIMIT",
"category": "VALUE_LIMIT",
"maxPerPayment": 1000,
"daytimeDailyLimit": 4000,
"nighttimeDailyLimit": 1000,
"weekendDailyLimit": 1000,
"createdAt": "2024-08-18T08:30:00.0000Z",
"updatedAt": "2024-08-25T22:31:44.4758Z"
},
{
"id": "uuid",
"name": "Weekday-Plus",
"category": "VALUE_LIMIT",
"maxPerPayment": 1000,
"daytimeDailyLimit": 4000,
"nighttimeDailyLimit": 2000,
"weekendDailyLimit": 1000,
"createdAt": "2024-08-19T09:00:00.0000Z",
"updatedAt": "2024-08-26T11:15:30.3333Z"
}
],
"meta": {
"nextCursor": null,
"previousCursor": null,
"total": 2,
"totalMatches": null
}
}PUT /wallets/{walletId}/policy
{
"policyId": "uuid"
}
-
Repositório privado no GitHub.
-
Testes automatizados abrangentes que cubram:
- Validação de regras de negócio (limites por período, valores máximos).
- Cálculo correto de períodos (diurno/noturno/final de semana).
- Bordas de horário (05:59:59, 06:00:00, 17:59:59, 18:00:00).
- Lógica de políticas diferentes (VALUE_LIMIT, TX_COUNT_LIMIT).
- Tratamento de exceções e validações.
- Persistência: criação e consulta de carteiras, pagamentos e políticas.
- Filtros e paginação: listagem de pagamentos com filtros de data e cursor.
- Reset diário: verificação de limite zerado em novos períodos.
- Políticas dinâmicas: diferentes categorias de política aplicadas na mesma base de código com estruturas de resposta específicas.
- APIs end-to-end: todos os endpoints retornando estruturas corretas conforme a política ativa.
-
Instruções claras para rodar a aplicação e dependências.
-
Uso de banco de dados com script ou migração para criar coleções/índices.
-
README técnico com decisões de design e trade-offs.
- Estrutura organizada em camadas (DDD, Clean Architecture).
- OpenAPI/Swagger em
/docsou Postman (Collection e Environment). - Logs estruturados com identificadores de requisição.
- Métricas simples (quantidade de pagamentos aprovados/recusados).
- Auditoria dos eventos de pagamento (quem, quando, o quê).
- Docker Compose com aplicação + MongoDB.
- Workflow de CI (build + test).
- Commits padronizados (Conventional).
- Adicione uma categoria de política chamada
TX_COUNT_LIMITque restrinja o número máximo de transações que uma carteira pode realizar em um mesmo dia (independente do valor). - Por exemplo, a política pode limitar a 5 pagamentos por dia.
- Ao tentar realizar uma transação além do limite diário permitido, a API deve rejeitar a operação.
- A solução deve permitir a inclusão de novas políticas semelhantes no futuro de forma simples, sem alterar o fluxo de código existente.
- Dê permissão de leitura para
@tracefinancedevno repositório. - Envie e-mail para
backend@trace.financecom assunto Vaga Back-end e a URL do repo. - No README, explique suas principais decisões de arquitetura e pontos de atenção.