Skip to content

gabriel-sa-dev/payment-event-processor

Repository files navigation

Payment Event Processor 💳 🚀

Processamento de pagamentos resiliente, idempotente e escalável.

Este projeto é um Processador de Eventos de Pagamento de alta performance, projetado para resolver um dos problemas mais críticos em sistemas financeiros modernos: a confiabilidade no recebimento de Webhooks.

Imagine que o Stripe (ou qualquer gateway) envia uma notificação de "Pagamento Confirmado", mas seu servidor cai no meio do processamento. Ou pior, ele envia a mesma notificação duas vezes e você libera o produto em dobro para o cliente. Este microserviço foi construído com foco obsessivo em Garantia de Entrega e Consistência de Dados.


🔝 Por que este projeto existe? (O Problema)

Webhooks são comunicações assíncronas entre servidores que podem falhar por diversos motivos: instabilidade na rede, picos de tráfego ou erros temporários no banco de dados. Um sistema financeiro não pode simplesmente "perder" um evento.

Este projeto implementa:

  1. Idempotência: Garante que mesmo que um evento seja recebido 10 vezes, ele será processado apenas uma vez.
  2. Resiliência: Se o processamento falhar por um erro temporário, o sistema tenta novamente de forma inteligente (Backoff Exponencial).
  3. Observabilidade: Monitoramento em tempo real de métricas, erros e saúde do sistema.

🛠 Tech Stack & Ferramentas

Escolhi cada tecnologia com o objetivo de equilibrar performance, tipagem forte e confiabilidade:

  • Linguagem: Go (Golang) - Escolhida pela sua concorrência nativa (Goroutines) e baixo consumo de memória.
  • Banco de Dados: PostgreSQL - Para garantir transações ACID e persistência robusta dos eventos.
  • Fila/Mensageria: Redis Streams - Utilizado para processamento em background, garantindo que o Gateway receba um 202 Accepted instantâneo enquanto o Worker processa a lógica pesada.
  • Infraestrutura: Docker & Docker Compose - Para abstração de ambiente e facilidade de deploy.
  • Padrões: Clean Architecture, Repository Pattern e Middleware para segurança (HMAC-SHA256).

🧠 Detalhes de Implementação (Foco em Qualidade)

Para este projeto, fiz questão de aplicar conceitos que demonstram meu compromisso com a excelência técnica:

  • Segurança com HMAC: Cada requisição é validada usando assinaturas criptográficas para garantir que os dados realmente vieram do provedor de pagamentos.
  • Tratamento de Erros Semântico: Diferencio erros "Transientes" (conectividade) de "Permanentes" (dados inválidos), evitando retries inúteis em dados corrompidos.
  • Dead Letter Queue (DLQ): Eventos que falham após todas as tentativas não são descartados; eles vão para uma fila de análise manual.
  • Padrão de Tabelas Cruas (Raw Events): Salvo o payload original antes de qualquer processamento, permitindo auditoria e "replay" de eventos se as regras de negócio mudarem.

👨‍💻 Sobre mim & Desejo de Aprender

Este projeto é um reflexo da minha jornada no desenvolvimento de software. Acredito que um bom programador não é aquele que apenas escreve código que funciona, mas aquele que:

  1. Antecipa erros (O que acontece se o banco ficar lento?).
  2. Escreve código para humanos (Nomes de variáveis intuitivos e estrutura limpa).
  3. É obcecado por testes (Este projeto possui testes unitários e de integração).

Estou em constante evolução, explorando padrões de alta disponibilidade e sistemas distribuídos. Este projeto foi uma oportunidade incrível para aprofundar meu conhecimento em Go e sistemas orientados a eventos.


🚀 Como visualizar a estrutura

Explore as pastas para entender a organização:

  • internal/domain: O coração do projeto, onde as regras de negócio vivem.
  • internal/middleware: Camada de segurança e validação.
  • internal/worker: Lógica asíncrona de consumo de fila.

Este é um projeto de portfólio. Para ver o código completo ou discutir oportunidades, sinta-se à vontade para entrar em contato!

🧪 Testando Webhooks

Linux/Mac (Bash)

# Variáveis
TIMESTAMP=$(date +%s)
SECRET="whsec_test_secret_key_for_development"
PAYLOAD='{"id":"evt_test_123","type":"payment_succeeded","created":1704672000,"data":{"object":{"id":"in_abc","subscription":"sub_xyz","customer_email":"test@example.com","amount":9900,"currency":"brl","plan_id":"plan_pro"}}}'

# Gerar assinatura
SIGNATURE=$(echo -n "${TIMESTAMP}.${PAYLOAD}" | openssl dgst -sha256 -hmac "${SECRET}" | cut -d' ' -f2)

# Enviar webhook
curl -X POST http://localhost:8080/webhooks/payments \
  -H "Content-Type: application/json" \
  -H "X-Webhook-Signature: sha256=${SIGNATURE}" \
  -H "X-Webhook-Timestamp: ${TIMESTAMP}" \
  -d "${PAYLOAD}"

Windows (PowerShell)

# Executar script de teste
.\scripts\test-webhook.ps1 -EventType "payment_succeeded"

# Ou manualmente
$timestamp = [int][double]::Parse((Get-Date -UFormat %s))
$secret = "whsec_test_secret_key_for_development"
$payload = '{"id":"evt_test_123","type":"payment_succeeded","created":1704672000,"data":{"object":{"id":"in_abc","subscription":"sub_xyz","customer_email":"test@example.com","amount":9900,"currency":"brl"}}}'

$signedPayload = "$timestamp.$payload"
$hmac = New-Object System.Security.Cryptography.HMACSHA256
$hmac.Key = [System.Text.Encoding]::UTF8.GetBytes($secret)
$hash = $hmac.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($signedPayload))
$signature = [BitConverter]::ToString($hash).Replace("-","").ToLower()

Invoke-RestMethod -Uri "http://localhost:8080/webhooks/payments" `
  -Method Post `
  -Headers @{
    "Content-Type" = "application/json"
    "X-Webhook-Signature" = "sha256=$signature"
    "X-Webhook-Timestamp" = "$timestamp"
  } `
  -Body $payload

📁 Estrutura do Projeto

payment-event-processor/
├── cmd/
│   ├── api/
│   │   └── main.go           # HTTP API server
│   └── worker/
│       └── main.go           # Queue consumer worker
├── internal/
│   ├── config/               # Configuração via env vars
│   ├── database/             # Conexão PostgreSQL
│   ├── domain/               # Entidades de domínio
│   ├── handler/              # HTTP handlers
│   ├── middleware/           # Auth, rate limit, logging
│   ├── queue/                # Redis Streams
│   ├── repository/           # Acesso a dados
│   └── worker/               # Processamento de eventos
├── migrations/               # SQL migrations
├── examples/                 # Payloads de exemplo
├── scripts/                  # Scripts de teste
├── docker-compose.yml
├── Dockerfile
├── Makefile
└── go.mod

⚙️ Configuração

Variáveis de Ambiente

Variável Descrição Default
PORT Porta do servidor HTTP 8080
ENV Ambiente (development/production) development
DATABASE_URL URL de conexão PostgreSQL -
DATABASE_MAX_CONNS Conexões máximas do pool 10
REDIS_URL URL de conexão Redis -
WEBHOOK_SECRET Secret HMAC para verificação -
WEBHOOK_TOLERANCE_SECONDS Tolerância de timestamp 300
RATE_LIMIT_REQUESTS Requests por janela 100
RATE_LIMIT_WINDOW_SECONDS Janela de rate limit 60
WORKER_CONCURRENCY Número de workers 5
WORKER_MAX_RETRIES Retries antes do DLQ 3
WORKER_RETRY_BASE_DELAY_MS Delay base para retry 1000

🛠 Comandos Make

make up              # Iniciar todos os serviços
make down            # Parar e remover containers
make build           # Build dos binários
make test            # Rodar testes
make test-coverage   # Testes com coverage
make logs            # Ver logs de todos serviços
make logs-api        # Ver logs da API
make logs-worker     # Ver logs do Worker
make migrate         # Rodar migrations
make seed            # Popular dados iniciais
make health          # Verificar health
make metrics         # Ver métricas
make help            # Ver todos comandos

🔄 Tipos de Evento Suportados

Tipo Ação
payment_succeeded Marca invoice como paid, subscription como active, incrementa receita
payment_failed Marca invoice como failed, subscription como past_due
charge_refunded Marca invoice como refunded, incrementa reembolsos

🏗 Arquitetura

                    ┌──────────────┐
                    │   Stripe     │
                    └──────┬───────┘
                           │
                           ▼
┌──────────────────────────────────────────────┐
│                  API Server                   │
│  ┌────────────┐  ┌────────────┐  ┌─────────┐ │
│  │ Signature  │  │ Rate Limit │  │ Logging │ │
│  └─────┬──────┘  └─────┬──────┘  └────┬────┘ │
│        └───────────────┼───────────────┘     │
│                        ▼                      │
│              ┌─────────────────┐              │
│              │ Webhook Handler │              │
│              └────────┬────────┘              │
└───────────────────────┼───────────────────────┘
                        │
           ┌────────────┴────────────┐
           ▼                         ▼
    ┌─────────────┐          ┌─────────────┐
    │  PostgreSQL │          │    Redis    │
    │  (raw_events)│         │  (Streams)  │
    └─────────────┘          └──────┬──────┘
                                    │
                                    ▼
                    ┌───────────────────────────┐
                    │         Workers           │
                    │  ┌─────────────────────┐  │
                    │  │ payment_succeeded   │  │
                    │  │ payment_failed      │  │
                    │  │ charge_refunded     │  │
                    │  └─────────┬───────────┘  │
                    └────────────┼──────────────┘
                                 │
                    ┌────────────┴────────────┐
                    ▼                         ▼
             ┌─────────────┐          ┌─────────────┐
             │  PostgreSQL │          │     DLQ     │
             │  (updates)  │          │  (failures) │
             └─────────────┘          └─────────────┘

📝 Licença

MIT

About

Resilient Payment Event Processor in Go. Focus on Idempotency, Resiliency (Redis Streams/PostgreSQL) and Clean Architecture. [Demo Version]

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors