API RESTful que permite transferências de dinheiro entre usuários comuns e lojistas.
- Usuários podem ser criados como
common(podem enviar e receber) ouseller(apenas recebem). - Cada usuário possui uma carteira (
wallet) criada automaticamente. - É possível depositar valores manualmente na carteira e registrar transferências entre usuários, sempre preservando o histórico de lançamentos.
- Transferências passam por autorização externa e só são concluídas após confirmação; lojistas não podem ser pagadores, mas podem receber de qualquer usuário.
- Notificações ao recebedor são enfileiradas para processamento assíncrono.
- Criar usuários (um pagador
commone um recebedor). - Depositar fundos no pagador para liberar saldo.
- Criar a transferência: o sistema valida regras de negócio, consulta o autorizador externo e registra lançamentos de débito/crédito nas carteiras.
- Ao concluir, publica um evento que agenda a notificação do recebedor em background.
- Escopo coberto: criação de usuário, consulta por id, depósito, criação de transferência e notificação do recebedor.
- Não há autenticação ou autorização de chamadas HTTP; foco está no domínio de pagamentos.
- As operações são síncronas até a conclusão da transferência; a notificação do recebedor é disparada de forma assíncrona.
- Dados de senha são persistidos como texto simples (mantido assim para o exercício); em produção seria obrigatório aplicar hashing, ou delegar a autenticação para um microserviço próprio para esse fim.
- Framework Hyperf + Swoole: escolhido por alinhar com a stack usada pela empresa e entregar alta performance em I/O.
- DDD em camadas: domínio isolado em
app/Core/Domain, aplicação orquestrando casos de uso e infraestrutura cuidando de HTTP, persistência e integrações. - Saldo derivado de ledger: o saldo da carteira é calculado a partir de lançamentos (
ledgerEntries) para preservar histórico e rastreabilidade. - Eventos de domínio: transferência criada como
pendingpublica evento que aciona o processamento e, ao concluir, outro evento agenda a notificação. - UUIDs para entidades, evitando dependência do banco para identidade.
- Integrações HTTP com serviços de autorização e notificação usando Guzzle, com tratamento de erros específico para cada parceiro.
- Fila assíncrona (Redis): Hyperf Async Queue entrega o job de notificação com retentativas configuráveis.
- PHP 8.1+, Hyperf 3.1, Swoole, Guzzle.
- Banco relacional (PostgreSQL via
.env.example) e Redis para filas (async-queue). - Testes com PHPUnit (
composer test), análise estática com PHPStan (composer analyse) e formatação com PHP-CS-Fixer (composer cs-fix).
- Clone o repositório do GitHub e entre na pasta:
git clone <URL-do-repo> && cd simple-payment. - Suba todo o stack com Docker:
make up. - Aguarde a mensagem
==> Stack ready, que indica que o banco, Redis e API estão prontos. - Visualize os logs do servidor para confirmar a subida:
make logs. - Não é necessário iniciar os workers da
async-queue; o Hyperf já inicia os workers junto com o servidor. - Para acompanhar as requisições (autorizador e notify), use:
make integration-logs. Exemplo de saída:
[2026-01-16 04:48:09] integration.INFO: [2026-01-16T04:48:09+00:00] "GET /api/v2/authorize?payer=ae366894-f45c-4aff-a989-bde18da12bbd HTTP/1.1" 403 [] []
[2026-01-16 04:48:12] integration.INFO: [2026-01-16T04:48:12+00:00] "GET /api/v2/authorize?payer=ae366894-f45c-4aff-a989-bde18da12bbd HTTP/1.1" 403 [] []
[2026-01-16 04:48:14] integration.INFO: [2026-01-16T04:48:14+00:00] "GET /api/v2/authorize?payer=ae366894-f45c-4aff-a989-bde18da12bbd HTTP/1.1" 200 [] []
[2026-01-16 04:48:14] integration.INFO: [2026-01-16T04:48:14+00:00] "POST /api/v1/notify HTTP/1.1" 504 [] []
[2026-01-16 04:48:20] integration.INFO: [2026-01-16T04:48:20+00:00] "POST /api/v1/notify HTTP/1.1" 504 [] []
[2026-01-16 04:48:27] integration.INFO: [2026-01-16T04:48:27+00:00] "POST /api/v1/notify HTTP/1.1" 504 [] []
[2026-01-16 04:48:33] integration.INFO: [2026-01-16T04:48:33+00:00] "POST /api/v1/notify HTTP/1.1" 204 [] []
- Domínio (
app/Core/Domain): entidades (User,Wallet,Transfer,LedgerEntry), enums e regras de negócio. Ex.:Wallet::transferTovalida saldo, reserva valores (committedBalance) e gera lançamentos de débito/crédito vinculados à transferência. - Aplicação (
app/Core/Application): command e handlers que orquestram casos de uso (User/CreateHandler,User/TransferHandler,Wallet/ProcessTransferHandler,Transfer/NotifyPayeeHandler). - Infraestrutura (
app/Infra): adaptadores HTTP (controllers + validação), repositórios (ORM Hyperf), integrações externas (autorizador e notificador), fila assíncrona e publicação de eventos. - Fluxo de transferência detalhado:
User/TransferHandlercarrega carteiras, valida saldo e o tipo do pagador cria uma transferênciapendinge publica o evento de domínioTransfer/PendingCreated.ProcessTransferHandler, consulta o autorizador externo e grava lançamentos de débito/crédito.- Ao concluir, a transferência é marcada como
completede o eventoCompleteddispara um job que notifica o recebedor em background.
- Rotas principais:
POST /user,GET /user/{id},POST /user/{id}/deposit,POST /transfer.
- Criar usuário comum:
curl --location 'http://localhost:9501/user' \
--header 'Content-Type: application/json' \
--data-raw '{
"full_name": "Cecelia Will V",
"kind": "common",
"document_type": "cpf",
"document": "11122233344",
"email": "Alexane37@gmail.com",
"password": "cOwOYX2rF6zKnov"
}'- Depositar na carteira do usuário:
curl --location 'http://localhost:9501/user/b64b6362-98ea-44e1-8b9d-aaab39c2f691/deposit' \
--header 'Content-Type: application/json' \
--data '{
"amount": 1000
}'- Consultar usuário por id:
curl --location 'http://localhost:9501/user/b64b6362-98ea-44e1-8b9d-aaab39c2f691'- Criar transferência entre usuários:
curl --location 'http://localhost:9501/transfer' \
--header 'Content-Type: application/json' \
--data '{
"amount": 10,
"payer": "b64b6362-98ea-44e1-8b9d-aaab39c2f691",
"payee": "a9155293-954b-46d8-a890-acd1ed8d5857"
}'- User: especializações
CommoneSeller; armazena documento (CPF/CNPJ), e-mail e referencia aWallet. ApenasCommonpode transferir. - Wallet: mantém
ledgerEntries, calcula saldo atual e consideracommittedBalancepara reservar valores de transferências pendentes (soma de transferspendingpara evitar double spend). - LedgerEntry: lançamentos do tipo
creditoudebit, com operaçãomanualoutransfer, opcionalmente vinculados a uma transferência. - Transfer: estado (
pending,completed,failed,reverted), carteiras de pagador/recebedor e motivo de falha quando existir. - Eventos de domínio:
Transfer\PendingCreatedeTransfer\Completedorquestram processamento e notificação.
- Factory:
UserFactorycria instâncias coerentes de usuários e carteiras. - Command/Handler: classes de comando representam ações e handlers encapsulam os casos de uso.
- Repository Pattern: interfaces no domínio com implementações ORM na infraestrutura.
- Mediator / Publisher-Subscriber: eventos de domínio desacoplam casos de uso (processamento de transferência e notificação).
- Testes unitários e de integração usando repositórios em memória para isolamento. Cobertura aproximada: ~74% (ponto conhecido a evoluir).
- TDD não foi seguido; os testes vieram após as primeiras iterações de código.
- Comandos:
make testspara suíte completa,make test-filter filter=Patternpara filtros,make analysepara análise estática emake fixpara formatação. - Cobertura HTML opcional com
make coverage(gera emruntime/coverage/index.html).
- Crescimento do
ledgerEntriesdentro deWalletpode degradar cálculo de saldo; precisa de estratégia de agregação/lazy loading para escala maior. - Ausência de DTOs torna contratos de entrada/saída menos explícitos e acopla controllers às entidades.
- Cobertura de testes ainda média (~74%) e sem ciclo TDD.
- Senhas persistidas sem hashing e ausência de autenticação/autorização HTTP.
- Dependência de serviços externos (autorizador e notificador) sem circuit breaker; falhas podem bloquear processamento.
- Introduzir DTOs e mapeamento dedicado nas bordas (HTTP/infra) para reduzir acoplamento e validar contratos.
- Revisar estratégia de saldo (ex.: agregações periódicas, lazyload de lançamentos, cache).
- Aumentar cobertura de testes, cobrindo fluxos de erro das integrações externas e casos de concorrência.
- Implementar hashing de senha, autenticação e políticas de autorização para endpoints sensíveis.
- Adicionar resiliência às integrações (timeouts configuráveis, retries com backoff e circuit breaker) e observabilidade de eventos/fila.