A Spring Boot microservice that handles payment processing in an event-driven platform. Participates in the distributed saga coordinated by the Saga Orchestrator — receives payment commands, processes them, and replies with success or failure events.
The Payment Service does not expose a write API. It is driven entirely by Kafka commands issued by the orchestrator.
On receiving a ProcessPaymentCommand, it validates the payment amount, persists the result, and publishes the outcome back to Kafka so the saga can proceed.
Saga Orchestrator
│
▼
Kafka: order.payment.process
│
▼
PaymentService.processPayment()
│
├── amount valid ──► Persist Payment (PROCESSED)
│ │
│ ▼
│ Kafka: order.payment.processed
│ │
│ Saga Orchestrator
│ │
│ ▼
│ OrderConfirmedCommand
│
└── amount invalid ► Persist Payment (FAILED)
│
▼
Kafka: order.payment.failed
│
Saga Orchestrator
│
▼
ReleaseInventoryCommand → OrderCanceledCommand
- Java 17, Spring Boot 4.0.3
- PostgreSQL — payment persistence (Hibernate,
ddl-auto: update) - Apache Kafka — event consumption and publishing
- Lombok — boilerplate reduction
- Spotless — code formatting (Google Java Format)
- Docker (for Kafka and PostgreSQL)
- Java 17+
- Maven
Start Kafka and PostgreSQL via the shared Docker Compose configuration:
cd ~/Workspace/event-driven-simulator/infrastructure/docker-compose
docker compose up -dThis starts:
- PostgreSQL on
localhost:5432— databasepayment_db, credentialspostgres/postgres - Kafka on
localhost:9094(external) — KRaft mode, no Zookeeper - Kafka UI at
http://localhost:8090
mvn spring-boot:runThe service starts on port 8083.
GET /api/v1/payments/{orderId}
Response 200 OK:
{
"paymentId": "a1b2c3d4-...",
"orderId": "773d07c8-...",
"productId": "prod-1",
"quantity": 2,
"amount": 20.00,
"status": "PROCESSED",
"failureReason": null
}Returns 404 Not Found if no payment exists for the given order.
| Status | Description |
|---|---|
PROCESSED |
Payment succeeded; saga will confirm the order |
FAILED |
Payment rejected (invalid amount); saga will compensate and cancel |
| Topic | Direction | Description |
|---|---|---|
order.payment.process |
Inbound | Command from orchestrator to process payment |
order.payment.processed |
Outbound | Published when payment succeeds |
order.payment.failed |
Outbound | Published when payment is rejected |
mvn clean install # Build and run all tests
mvn test # Run tests only
mvn spotless:apply # Format code (run before committing)
mvn spotless:check # Verify formattingcom.platform.paymentservice
├── config/ # KafkaProducerConfig, KafkaConsumerConfig (@EnableKafka)
├── controller/ # PaymentController — GET /api/v1/payments/{orderId}
├── event/
│ ├── inbound/ # ProcessPaymentCommand
│ └── outbound/ # PaymentProcessedEvent, PaymentProcessingFailedEvent
├── exception/ # PaymentNotFoundException, GlobalExceptionHandler
├── messaging/
│ ├── consumer/ # PaymentCommandConsumer — Kafka listener
│ └── producer/ # KafkaProducerService — async event publishing
├── model/ # Payment entity, PaymentStatus enum
├── repository/ # PaymentRepository (Spring Data JPA)
└── service/ # PaymentService — core business logic
| Service | Port | Role |
|---|---|---|
| event-driven-saga-orchestrator | 8085 | Issues payment commands; handles outcomes |
| event-driven-order-service | 8081 | Receives final confirm/cancel from orchestrator |
| event-driven-inventory-service | 8082 | Compensated on payment failure |