Skip to content

Latest commit

 

History

30 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

ecommerce-microservices

CI Java Spring Boot Architecture Built with Claude Code

Plataforma de e-commerce baseada em microsserviços, orientada a eventos (Event-Driven Architecture), construída como referência de boas práticas do ecossistema Spring para portfólio técnico.

Backend distribuído de e-commerce com 9 microsserviços autônomos, coordenados por uma Saga por Coreografia sobre AWS SNS/SQS (simulados localmente via LocalStack) — sem orquestrador central. Segue DDD, Clean/Hexagonal Architecture e os Twelve-Factor App. Todo o fluxo — incluindo os dois caminhos de compensação da Saga, idempotência, rate limiting e observabilidade — foi validado com um teste de integração real de ponta a ponta, subindo a stack inteira via Docker Compose e exercitando cada serviço de verdade (nada mockado).

O código do projeto (Maven multi-módulo, serviços, docs) vive todo dentro de ecommerce-platform/. Só .github/workflows/ fica na raiz do repositório git (aqui), porque é onde o GitHub Actions exige que esteja.

Stack

Java 21 · Spring Boot 3 · Spring Cloud (Config, Gateway) · Spring Cloud AWS (SNS/SQS) · Spring Data JPA · Spring Security + JWT · PostgreSQL · Flyway · Docker / Docker Compose · LocalStack · Resilience4j (Retry, Circuit Breaker, Rate Limiter) · Micrometer · OpenTelemetry · Prometheus · Grafana · Jaeger · Mailpit · JUnit 5 · Mockito · Testcontainers · JaCoCo.

Arquitetura

Visão geral da arquitetura da plataforma de e-commerce com 9 microsserviços, mensageria SNS/SQS e infraestrutura local

A imagem acima apresenta uma visão geral dos 9 microsserviços, da camada de eventos AWS SNS/SQS e da infraestrutura local com Docker Compose. Ela está disponível no repositório em arquitetura.png.

Visão da Saga por Coreografia ponta a ponta — do request no Gateway até a confirmação/cancelamento do pedido e o e-mail de notificação. Setas sólidas verdes = caminho feliz; setas tracejadas vermelhas = compensação. Diagramas C4 completos (contexto e contêineres, com todos os 9 serviços e bancos) em ecommerce-platform/docs/diagrams/.

flowchart TB
    client(["👤 Cliente / Admin"])
    gw["🚪 gateway-service<br/>JWT · Rate Limiting"]
    order["📦 order-service<br/><i>PENDING → CONFIRMED / CANCELLED</i>"]
    inventory["📊 inventory-service<br/><i>reserva / libera estoque</i>"]
    payment["💳 payment-service<br/><i>aprova / recusa pagamento</i>"]
    notification["📧 notification-service"]
    bus{{"AWS SNS + SQS (LocalStack)<br/>Saga por Coreografia"}}
    mailpit(["📬 Mailpit"])
    confirmed(["✅ CONFIRMED"])
    cancelled(["❌ CANCELLED<br/><i>estoque liberado se reservado</i>"])

    client -->|"HTTPS + JWT"| gw
    gw -->|"cria pedido"| order

    order ==>|"① OrderCreated"| bus
    bus ==>|"① OrderCreated"| inventory

    inventory ==>|"② StockReserved"| bus
    inventory -.->|"② StockUnavailable"| bus

    bus ==>|"② StockReserved"| payment
    bus -.->|"② StockUnavailable"| order

    payment ==>|"③ PaymentApproved"| bus
    payment -.->|"③ PaymentDeclined"| bus

    bus ==>|"③ PaymentApproved"| order
    bus -.->|"③ PaymentDeclined"| order
    bus -.->|"OrderCancelled (compensação)"| inventory

    order ==> confirmed
    order -.-> cancelled

    bus -.->|"assina todos os eventos"| notification
    notification --> mailpit

    style bus fill:#e8a33d,color:#000
    style confirmed fill:#2e7d32,color:#fff
    style cancelled fill:#c62828,color:#fff
    style gw fill:#1168bd,color:#fff
Loading
  • Saga por Coreografia: order-service cria o pedido (PENDING) e publica OrderCreated. inventory-service reserva estoque e publica StockReserved/StockUnavailable. payment-service decide aprovar/recusar e publica PaymentApproved/PaymentDeclined. order-service reage a esses dois últimos e fecha o pedido (CONFIRMED/CANCELLED, com inventory-service liberando o estoque na compensação). notification-service observa tudo e envia e-mail/SMS.
  • Outbox Pattern em todo serviço publicador (a mudança de estado e o registro do evento a publicar são commitados na mesma transação; um worker assíncrono publica de fato no SNS).
  • Idempotent Consumer em todo serviço consumidor (tabela processed_events — reentrega do SQS nunca duplica efeito).
  • Retry + Circuit Breaker + DLQ: publicação no SNS protegida por Resilience4j (retry com backoff + circuit breaker); toda fila SQS tem DLQ própria com maxReceiveCount configurado.
  • Módulo platform/ compartilha infraestrutura (eventos, mensageria, segurança, observabilidade, exceções, testes) sem nenhuma regra de negócio.

Passo a passo da Saga

Nenhum serviço chama outro diretamente — toda a coordenação acontece publicando e consumindo eventos via SNS/SQS. O correlationId é gerado na criação do pedido e propagado em todo evento subsequente da mesma transação distribuída (rastreável ponta a ponta nos logs de cada serviço).

  1. Cliente cria o pedido via gateway-service (JWT obrigatório, role CUSTOMER/ADMIN) → order-service persiste o pedido com status PENDING e grava o evento OrderCreated na tabela outbox, na mesma transação — nada é publicado no SNS ainda nesse instante.
  2. Um worker assíncrono do order-service lê a outbox e publica OrderCreated de fato no tópico SNS.
  3. inventory-service consome OrderCreated (fila própria, checagem de idempotência via processed_events antes de agir) e tenta reservar estoque:
    • Há estoque → publica StockReserved (carrega totalAmount, copiado do pedido, porque payment-service nunca consome OrderCreated diretamente).
    • Não há estoque → publica StockUnavailable e o fluxo já pula para a compensação (passo 6) — payment-service nunca chega a ser acionado nesse caminho.
  4. payment-service consome StockReserved e decide por um limite de valor configurável (platform.payment.approval-threshold, default 500.00): pedido ≤ limite → aprovado; acima → recusado.
    • Aprovado → publica PaymentApproved.
    • Recusado → publica PaymentDeclined.
  5. order-service reage ao resultado — é o único serviço que muda o status do pedido:
    • PaymentApproved → status vira CONFIRMED, publica OrderConfirmed.
    • PaymentDeclined → status vira CANCELLED, publica OrderCancelled.
  6. Compensação (originada por PaymentDeclined ou por StockUnavailable): inventory-service consome OrderCancelled e libera o estoque que havia reservado — no caminho de StockUnavailable não há nada reservado para liberar.
  7. notification-service está inscrito nos 7 tópicos da Saga; reage aos eventos terminais (OrderConfirmed/OrderCancelled) enviando e-mail (Mailpit local / Amazon SES em produção). Eventos intermediários (StockReserved, PaymentApproved etc.) são só observados/logados, sem e-mail próprio.

As três ramificações possíveis, todas provadas ao vivo com evidência real (e-mail recebido, estado do banco):

Caminho Evento decisivo Status final Estoque Pagamento E-mail
Sucesso PaymentApproved CONFIRMED Reservado (permanece) Processado, aprovado "Pedido confirmado"
Pagamento recusado PaymentDeclined CANCELLED Reservado → liberado (compensação) Processado, recusado "Pedido cancelado"
Estoque indisponível StockUnavailable CANCELLED Nunca chega a ser reservado Nunca chega a ser processado "Pedido cancelado"

Diagramas C4, sequência detalhada da Saga (incluindo os diagramas de sequência de sucesso/compensação), catálogo de eventos e ADRs: ver ecommerce-platform/docs/ (índice abaixo) — em especial docs/saga/fluxo-saga.md.

Validação end-to-end

Além da suíte automatizada, a stack inteira foi validada em tempo real: cold start completo via Docker Compose, os 9 serviços + 7 bancos exercitados de verdade, e as três ramificações da Saga provadas ponta a ponta com evidência concreta (não só asserção de teste):

  • Caminho feliz, compensação por pagamento recusado e compensação por estoque indisponível — cada uma confirmada por e-mail real recebido no Mailpit e pelo estado final correto de estoque/pagamento no banco.
  • Idempotência: reenvio real da mesma mensagem SQS (eventId repetido) não duplica o efeito.
  • Rate limiting do gateway: disparo de 40 requisições confirmou o corte exato no limite configurado.
  • Observabilidade: todos os alvos do Prometheus up, datasources do Grafana provisionados, traces reais capturados no Jaeger.
  • Esse processo encontrou e corrigiu um bug real (createdAt nulo após update em customer-service/product-service, por reconstrução de entidade JPA transiente) — com teste de regressão adicionado em ambos os serviços.

Como rodar

cd ecommerce-platform
./mvnw clean package -DskipTests
docker compose build
docker compose up -d

Sobe sozinho: LocalStack (com os 7 tópicos SNS e 4 filas SQS/DLQ já criados), 7 PostgreSQL, config-server, gateway-service, os 7 microsserviços de negócio, Prometheus, Grafana, Jaeger e Mailpit. Um usuário ADMIN já vem semeado (admin@ecommerce-platform.local / Admin@12345).

Guia completo (fluxo de fumaça via curl, portas de cada serviço, como acessar Grafana/Jaeger/Mailpit): ecommerce-platform/docs/deployment/local.md.

Produção (AWS)

Terraform completo em ecommerce-platform/infrastructure/terraform/ provisiona a mesma arquitetura acima rodando numa conta AWS real — nenhum código de serviço muda, só a origem de configuração/credenciais (ver ADR 0003 e as notas de migração):

  • Compute: ECS Fargate — um serviço por container (9 microsserviços + Prometheus/Grafana/Jaeger), service discovery via AWS Cloud Map.
  • Dados: 1 RDS PostgreSQL por serviço + Secrets Manager (JWT, credenciais de banco, senha do Grafana — nunca em texto puro).
  • Mensageria: os mesmos 7 tópicos SNS + 4 filas SQS/DLQ do catálogo de eventos, com uma IAM role por serviço restrita a publicar/consumir exatamente o que aquele serviço publica/consome no catálogo (least privilege).
  • Rede: VPC com subnets públicas/privadas, ALB público só na frente do gateway-service, ALB interno (nunca exposto à internet por padrão) para Prometheus/Grafana/Jaeger.
  • Validado com terraform validate/terraform plan (grafo de dependências resolve por completo, todas as ~9 ações de criação planejadas corretamente); falta só uma conta AWS real para apply.

Instalação:

cd ecommerce-platform/infrastructure/terraform/environments/prod
cp terraform.tfvars.example terraform.tfvars   # ajuste ao menos admin_cidr_blocks
terraform init -backend-config=backend.hcl      # bucket S3 + tabela DynamoDB de lock (bootstrap manual, ver guia)
terraform plan
terraform apply

Depois do primeiro apply (cria o ECR vazio), publique as imagens Docker e reaplique. Passo a passo completo — bootstrap do state remoto, build/push das imagens, e as lacunas do lado da aplicação que ainda faltam antes de apontar para uma conta real (isolar o profile local no config-repo, trocar o e-mail para Amazon SES) — em ecommerce-platform/infrastructure/terraform/README.md.

Testes

cd ecommerce-platform
./mvnw clean verify

Testes unitários (JUnit 5 + Mockito) e de integração reais (Testcontainers: PostgreSQL e LocalStack de verdade — nunca mocks para infraestrutura) em todos os módulos. Gate de cobertura JaCoCo ≥ 80% por módulo, obrigatório para o build passar. CI: .github/workflows/ci.yml.

Microsserviços

Serviço Responsabilidade Escuta Publica
gateway-service Roteamento, JWT, rate limiting — —
config-server Configuração centralizada — —
auth-service Login, cadastro, JWT, refresh token — —
customer-service CRUD de clientes — —
product-service CRUD de produtos — —
order-service Cria pedidos, núcleo da Saga PaymentApproved, PaymentDeclined, StockUnavailable OrderCreated, OrderConfirmed, OrderCancelled
inventory-service Reserva/libera estoque OrderCreated, OrderCancelled StockReserved, StockUnavailable
payment-service Processa pagamento (simulado, por limite) StockReserved PaymentApproved, PaymentDeclined
notification-service E-mail (Mailpit) / SMS (log) todos os 7 eventos —

Módulo platform/

Bibliotecas Maven compartilhadas, sem regra de negócio — cada serviço acima depende só do que precisa.

Módulo Responsabilidade
platform-bom BOM: centraliza toda versão de dependência
platform-common ApiResponse/PageResponse/ErrorResponse, superclasses JPA, utilitários
platform-events Contratos dos 7 eventos de domínio da Saga
platform-exception Exceções de negócio + handler global de erro
platform-security JWT: geração, validação, filtro, roles
platform-messaging Publish/consume SNS/SQS, Outbox, Idempotent Consumer, Retry + Circuit Breaker
platform-observability Correlation ID, tracing, métricas, log estruturado
platform-testing Fixtures de evento, JWT de teste, bases de Testcontainers

infrastructure/

Configuração de tudo que sobe via docker-compose.yml mas não é código Java.

Diretório O que configura
localstack Cria os 7 tópicos SNS e 4 filas SQS/DLQ da Saga automaticamente
config-repo Configuração compartilhada servida pelo config-server (JWT secret, endpoint do LocalStack, etc.)
prometheus Scrape config — um alvo por microsserviço
grafana Provisionamento automático de datasources (Prometheus + Jaeger)
terraform Infraestrutura de produção real na AWS (VPC, ECS Fargate, RDS, SNS/SQS, ALB, Secrets Manager) — validada com terraform validate/plan

Estrutura do repositório

ecommerce-microservices/          # raiz do repositório git
├── .github/workflows/ci.yml      # CI (só pode ficar na raiz do repo, exigência do GitHub Actions)
└── ecommerce-platform/           # o projeto em si
    ├── platform/                 # bibliotecas Maven compartilhadas (sem regra de negócio)
    ├── services/                 # os 9 microsserviços, cada um com seu README
    ├── infrastructure/           # LocalStack init, config-repo, Prometheus, Grafana, Terraform de produção
    ├── docs/                     # arquitetura, diagramas, eventos, saga, API, deployment, ADRs
    ├── docker-compose.yml
    ├── pom.xml                   # Maven Multi-Module raiz
    └── CLAUDE.md                 # contexto para desenvolvimento assistido por IA

Desenvolvimento assistido por IA (Claude Code)

Este projeto foi construído com Claude Code seguindo uma prática de Context Engineering: em vez de gerar código a partir de prompts soltos, o repositório carrega um contexto estruturado que qualquer sessão de IA (ou dev humano) lê antes de tocar no código, em ecommerce-platform/.claude/:

  • CLAUDE.md — a "memória" do projeto: stack, estrutura alvo do monorepo, tabela de responsabilidades de cada serviço e onde encontrar cada regra.
  • .claude/rules/ (10 arquivos) — regras não negociáveis carregadas em toda sessão: arquitetura hexagonal, comunicação só por eventos (nunca REST síncrono entre serviços), um banco por serviço, idioma (código em inglês, docs em português), segurança, resiliência, observabilidade, testes. É o que manteve os 9 microsserviços — implementados em marcos/sessões separados — consistentes entre si.
  • .claude/skills/ (3 skills) — automações reutilizáveis: novo-microsservico (scaffold completo, já registrado no Maven e no docker-compose.yml), novo-evento-dominio (novo evento em platform-events + catálogo + produtor/consumidor ligados), novo-adr (registra decisão arquitetural no formato padrão).
  • docs/decisions/ — Architecture Decision Records geradas durante a implementação (ex.: Saga por coreografia vs. orquestração; Mailpit para e-mail local).

O planejamento em marcos, a implementação dos 9 microsserviços e do módulo platform/, a infraestrutura, os testes (unitários + Testcontainers), o CI e a bateria de testes de integração real foram todos feitos nessa parceria entre engenharia de contexto e execução por IA — o repositório documenta o processo tanto quanto o resultado.

Documentação

About

Projeto Backend de E-commerce com Microsserviços utilizando Spring Boot, Spring Cloud, AWS SNS/SQS e Saga por Coreografia

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages