Skip to content

tracefinance/backend-crap-challenge

 
 

Repository files navigation

🚨 Payment API - Exemplo com Problemas Intencionais

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.

🚀 Como Executar

Pré-requisitos

  • Docker e Docker Compose
  • JDK 17+ (para desenvolvimento local)

Executando com Docker

# Subir a aplicação completa (API + MongoDB)
docker-compose up --build

# A API estará disponível em http://localhost:8080

Executando Localmente (Desenvolvimento)

# 1. Subir apenas o MongoDB
docker-compose up mongodb -d

# 2. Executar a aplicação
./gradlew run

🔧 Stack Técnica

  • 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

Contexto

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.


Tecnologias (preferenciais)

  • 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).

Regras de negócio

  • 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:00 e < 18:00:00 → diurno
    • >= 18:00:00 e < 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 categoria TX_COUNT_LIMIT para demonstrar extensibilidade.


Operações

Criar carteira

POST /wallets
{
  "ownerName": "string"
}

201 Created

{
  "id": "uuid",
  "ownerName": "string",
  "createdAt": "2024-08-25T22:31:44.4758Z"
}

Consultar políticas da carteira

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
  }
}

Realizar pagamento

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.


Listar pagamentos (com filtro por data)

GET /wallets/{walletId}/payments?startDate=2024-08-25T00:00:00.0000Z&endDate=2024-08-26T23:59:59.9999Z&cursor=abc123
  • startDate e endDate são opcionais. Se ausentes, retornar todos os pagamentos da carteira.
  • A listagem deve retornar no formato padrão utilizado em nossas APIs, com data e meta.
  • 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
  }
}

Gerenciar políticas de limite

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).

Criar política

POST /policies
{
  "name": "DEFAULT_VALUE_LIMIT",
  "category": "VALUE_LIMIT",
  "maxPerPayment": 1000,
  "daytimeDailyLimit": 4000,
  "nighttimeDailyLimit": 1000,
  "weekendDailyLimit": 1000
}

Listar políticas

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
  }
}

Associar política a uma carteira

PUT /wallets/{walletId}/policy
{
  "policyId": "uuid"
}

Pré-requisitos (eliminatórios)

  • Repositório privado no GitHub.

  • Testes automatizados abrangentes que cubram:

    🧪 Testes Unitários:

    • 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.

    🔗 Testes de Integração:

    • 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.


Seria legal (diferenciais)

  • Estrutura organizada em camadas (DDD, Clean Architecture).
  • OpenAPI/Swagger em /docs ou 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).

Bônus (extensibilidade)

  • Adicione uma categoria de política chamada TX_COUNT_LIMIT que 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.

Submissão

  1. Dê permissão de leitura para @tracefinancedev no repositório.
  2. Envie e-mail para backend@trace.finance com assunto Vaga Back-end e a URL do repo.
  3. No README, explique suas principais decisões de arquitetura e pontos de atenção.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Kotlin 95.8%
  • Dockerfile 2.1%
  • JavaScript 2.1%