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.
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.
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
- Saga por Coreografia:
order-servicecria o pedido (PENDING) e publicaOrderCreated.inventory-servicereserva estoque e publicaStockReserved/StockUnavailable.payment-servicedecide aprovar/recusar e publicaPaymentApproved/PaymentDeclined.order-servicereage a esses dois últimos e fecha o pedido (CONFIRMED/CANCELLED, cominventory-serviceliberando o estoque na compensação).notification-serviceobserva 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
maxReceiveCountconfigurado. - Módulo
platform/compartilha infraestrutura (eventos, mensageria, segurança, observabilidade, exceções, testes) sem nenhuma regra de negócio.
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).
- Cliente cria o pedido via
gateway-service(JWT obrigatório, roleCUSTOMER/ADMIN) →order-servicepersiste o pedido com statusPENDINGe grava o eventoOrderCreatedna tabelaoutbox, na mesma transação — nada é publicado no SNS ainda nesse instante. - Um worker assíncrono do
order-servicelê aoutboxe publicaOrderCreatedde fato no tópico SNS. inventory-serviceconsomeOrderCreated(fila própria, checagem de idempotência viaprocessed_eventsantes de agir) e tenta reservar estoque:- Há estoque → publica
StockReserved(carregatotalAmount, copiado do pedido, porquepayment-servicenunca consomeOrderCreateddiretamente). - Não há estoque → publica
StockUnavailablee o fluxo já pula para a compensação (passo 6) —payment-servicenunca chega a ser acionado nesse caminho.
- Há estoque → publica
payment-serviceconsomeStockReservede decide por um limite de valor configurável (platform.payment.approval-threshold, default500.00): pedido ≤ limite → aprovado; acima → recusado.- Aprovado → publica
PaymentApproved. - Recusado → publica
PaymentDeclined.
- Aprovado → publica
order-servicereage ao resultado — é o único serviço que muda o status do pedido:PaymentApproved→ status viraCONFIRMED, publicaOrderConfirmed.PaymentDeclined→ status viraCANCELLED, publicaOrderCancelled.
- Compensação (originada por
PaymentDeclinedou porStockUnavailable):inventory-serviceconsomeOrderCancellede libera o estoque que havia reservado — no caminho deStockUnavailablenão há nada reservado para liberar. notification-serviceestá 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,PaymentApprovedetc.) 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 | |
|---|---|---|---|---|---|
| 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.
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 (
eventIdrepetido) 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 (
createdAtnulo após update emcustomer-service/product-service, por reconstrução de entidade JPA transiente) — com teste de regressão adicionado em ambos os serviços.
cd ecommerce-platform
./mvnw clean package -DskipTests
docker compose build
docker compose up -dSobe 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.
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 paraapply.
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 applyDepois 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.
cd ecommerce-platform
./mvnw clean verifyTestes 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.
| 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 | — |
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 |
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 |
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
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 nodocker-compose.yml),novo-evento-dominio(novo evento emplatform-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.
ecommerce-platform/CLAUDE.md— visão geral para desenvolvimento assistido por IA (stack, regras, estrutura).ecommerce-platform/docs/architecture/visao-geral.md— arquitetura detalhada.ecommerce-platform/docs/diagrams/— diagramas C4 (contexto e contêineres).ecommerce-platform/docs/saga/fluxo-saga.md— fluxo completo da Saga (sucesso e compensação).ecommerce-platform/docs/events/catalogo-eventos.md— catálogo de eventos, tópicos e filas.ecommerce-platform/docs/api/— especificações OpenAPI de cada serviço.ecommerce-platform/docs/deployment/local.md— guia de execução local.ecommerce-platform/docs/deployment/aws.md— notas de migração para AWS real.ecommerce-platform/infrastructure/terraform/README.md— guia completo de instalação em produção (Terraform).ecommerce-platform/docs/decisions/— Architecture Decision Records.
