A modern, event-driven e-commerce platform built with microservices architecture, implementing CQRS, Event Sourcing, and the Saga pattern.
┌─────────────────────────────────────────────────────────────────────────────┐
│ Client Applications │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ BFF (Backend for Frontend) │
│ GraphQL API Gateway - Port 8080 │
└─────────────────────────────────────────────────────────────────────────────┘
│ gRPC
┌────────────────────────┼────────────────────────┐
▼ ▼ ▼
┌──────────────────────┐ ┌──────────────────────┐ ┌──────────────────────┐
│ Product Services │ │ Inventory Service │ │ Order Service │
│ (CQRS Pattern) │ │ Port 8085 │ │ Port 8084 │
│ │ │ gRPC: 9091 │ │ gRPC: 9094 │
│ Command: 8083/9093 │ └──────────────────────┘ └──────────────────────┘
│ Query: 8086/9090 │ │ │
└──────────────────────┘ │ │
│ │ │
│ CDC │ CDC │ CDC
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ Debezium Connect (Change Data Capture) │
│ Port 8087 │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ Redpanda (Kafka-compatible Message Broker) │
│ Port 9092 (external), 29092 (internal) │
└─────────────────────────────────────────────────────────────────────────────┘
│
┌────────────────────────┼────────────────────────┐
▼ ▼ ▼
┌──────────────────────┐ ┌──────────────────────┐ ┌──────────────────────┐
│ Product Query Svc │ │ Inventory Service │ │ Payment Service │
│ (Event Consumer) │ │ (Event Consumer) │ │ Port 8089 │
└──────────────────────┘ └──────────────────────┘ └──────────────────────┘
| Component | Technology |
|---|---|
| Language | Java 21, Spring Boot 3.x |
| API Gateway | GraphQL (Spring for GraphQL) |
| Service Communication | gRPC |
| Message Broker | Redpanda (Kafka-compatible) |
| CDC | Debezium |
| Databases | PostgreSQL 16 (write), Elasticsearch 8.11 (read) |
| Caching | Redis 7 |
| Tracing | Zipkin |
| Containerization | Docker Compose |
- Port: 8080
- Purpose: GraphQL API gateway that aggregates data from multiple microservices
- Communication: gRPC clients to downstream services
GraphQL Operations:
# Queries
product(id: ID!): ProductDetails
# Mutations
createProduct(input: CreateProductInput!): ProductDetails
createOrder(productId: ID!, quantity: Int!): Order- HTTP Port: 8083
- gRPC Port: 9093
- Database: PostgreSQL (
product_db) - Purpose: Handles write operations for products (CQRS - Command side)
- Features:
- Creates products
- Publishes events via Outbox pattern
- Flyway database migrations
- HTTP Port: 8086
- gRPC Port: 9090
- Database: Elasticsearch
- Purpose: Handles read operations for products (CQRS - Query side)
- Features:
- Consumes product events from Kafka
- Full-text search capabilities
- Optimized for read performance
- HTTP Port: 8085
- gRPC Port: 9091
- Database: PostgreSQL (
inventory_db) - Cache: Redis
- Purpose: Manages product inventory/stock levels
- Features:
- Stock reservation (Saga participant)
- Redis caching for fast lookups
- Outbox pattern for reliable messaging
- HTTP Port: 8084
- gRPC Port: 9094
- Database: PostgreSQL (
order_db) - Purpose: Manages order lifecycle
- Features:
- Order creation and status management
- Saga orchestrator for order fulfillment
- Outbox pattern for reliable messaging
- HTTP Port: 8089
- Database: PostgreSQL (
payment_db) - Purpose: Handles payment processing
- Features:
- Payment processing (Saga participant)
- Outbox pattern for reliable messaging
- Port: 5432
- Databases:
product_db,inventory_db,order_db,payment_db - Configuration: WAL level set to
logicalfor Debezium CDC
- Port: 6379
- Purpose: Caching layer for inventory service
- Port: 9200
- Purpose: Read-optimized storage for product search
- External Port: 9092
- Internal Port: 29092
- Console: 8088
- Purpose: Kafka-compatible message broker for event streaming
- Port: 8087
- Purpose: Change Data Capture from PostgreSQL outbox tables
- Connectors:
product-events-connectororder-events-connectorinventory-outbox-connectorpayment-outbox-connector
- Port: 9411
- Purpose: Distributed tracing across all microservices
The Product domain is split into separate services:
- Command Service: Writes to PostgreSQL
- Query Service: Reads from Elasticsearch
- Events synchronize data between the two
State changes are captured as events and published through Kafka/Redpanda.
All services use outbox tables for reliable event publishing:
- Events are written to an outbox table within the same transaction
- Debezium captures changes and publishes to Kafka
- Guarantees at-least-once delivery
Order fulfillment uses choreography-based saga:
- Order Service creates order
- Inventory Service reserves stock
- Payment Service processes payment
- Services publish success/failure events
- Docker and Docker Compose
- Java 21 (for local development)
- Maven (for local development)
# Start all services
docker compose up -d --build
# View logs
docker compose logs -f
# Stop all services
docker compose down
# Reset everything (including data)
docker compose down -v| Service | URL |
|---|---|
| GraphQL Playground | http://localhost:8080/graphiql |
| Redpanda Console | http://localhost:8088 |
| Zipkin UI | http://localhost:9411 |
| Debezium Connect | http://localhost:8087 |
| Elasticsearch | http://localhost:9200 |
After starting the stack, register the CDC connectors:
# Product events connector
./infra/debezium/register-connector.sh
# Order events connector
./infra/debezium/register-order-connector.sh
# Inventory outbox connector
./infra/debezium/register-inventory-outbox-connector.sh
# Payment outbox connector
./infra/debezium/register-payment-outbox-connector.shmutation {
createProduct(input: {
name: "Laptop"
description: "High-performance laptop"
price: 999.99
currency: "USD"
category: "Electronics"
}) {
id
name
price
}
}query {
product(id: "product-001") {
id
name
description
price
stockLevel
}
}mutation {
createOrder(productId: "product-001", quantity: 2) {
id
status
productId
}
}serendib-mall/
├── docker-compose.yml # Docker orchestration
├── proto/ # Shared gRPC protocol definitions
│ ├── product/
│ ├── inventory/
│ ├── order/
│ └── payment/
├── infra/
│ ├── postgres/
│ │ └── init.sql # Database initialization
│ └── debezium/
│ └── *.sh # Connector registration scripts
├── serendibmall-bff/ # GraphQL BFF service
├── product-command-service/ # Product write service (CQRS)
├── product-query-service/ # Product read service (CQRS)
├── inventory-service/ # Inventory management
├── order-service/ # Order management
└── payment-service/ # Payment processing
If databases don't exist, services will fail. Ensure PostgreSQL volume is fresh:
docker compose down -v
docker compose up -d --buildDebezium may fail if Redpanda isn't fully ready. The compose file includes restart: on-failure:5 to handle this automatically.
docker compose ps
docker compose logs <service-name>Access Redpanda Console at http://localhost:8088 to view topics and messages.
This project is for educational and demonstration purposes.