A production-ready payment processing system built with Spring Boot 3.2, Spring for GraphQL, PostgreSQL, and JWT security. Designed for reliability, scalability, and observability.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Client (Web / Mobile) β
βββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββ
β HTTP / WebSocket
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Spring Security (JWT Filter) β
β JwtAuthenticationFilter β SecurityContextHolder β
βββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β GraphQL Layer (/graphql, /graphql-ws) β
β β
β @QueryMapping @MutationMapping @SubscriptionMapping β
β @SchemaMapping @Argument @ContextValue β
β β
β ββββββββββββββββββ ββββββββββββββββββββ ββββββββββββββββββββββββ β
β β PaymentGQL β βSubscriptionCtrl β β GraphQLExceptionRslvrβ β
β β Controller β β (Reactor Sinks) β β (Error Classificationβ β
β βββββββββ¬βββββββββ ββββββββββββββββββββ ββββββββββββββββββββββββ β
ββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Service Layer β
β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββ ββββββββββββββββ β
β βPaymentServiceβ βAccountServiceβ βRiskService β βAuditService β β
β β β β β β β β (@Async) β β
β β @CircuitBreakβ β @Cacheable β β β β β β
β β @Retry β β @CacheEvict β β β β β β
β ββββββββ¬ββββββββ ββββββββββββββββ ββββββββββββββ ββββββββββββββββ β
βββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Data Layer (JPA / Hibernate) β
β β
β Accounts ββββββββ Payments ββββββββ Transactions β
β β β
β βββββ Refunds β
β βββββ AuditLogs β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β PostgreSQL (HikariCP pool, Flyway migrations, Optimistic Lock) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- Java 21+
- Maven 3.8+
- Docker & Docker Compose
# Start PostgreSQL
docker run -d \
--name payments-db \
-e POSTGRES_DB=payments \
-e POSTGRES_USER=payments \
-e POSTGRES_PASSWORD=secret \
-p 5432:5432 \
postgres:16-alpine
# Run the application
./mvnw spring-boot:run \
-Dspring-boot.run.jvmArguments="-DGRAPHIQL_ENABLED=true"Open: http://localhost:8080/graphiql
# Get account
query {
account(id: "a0000000-0000-0000-0000-000000000001") {
id email fullName status currency balance
payments(page: 0, size: 5) {
content { id referenceId amount status }
totalElements hasNext
}
}
}
# List payments with filters
query {
payments(
filter: { status: COMPLETED, currency: USD, minAmount: "100" }
sort: { field: "createdAt", direction: DESC }
page: 0, size: 20
) {
content {
referenceId amount status processingFee netAmount
sender { email }
recipient { email }
}
totalElements totalPages
}
}
# Analytics
query {
paymentStats(currency: USD, period: "month") {
totalVolume totalCount successRate averageAmount
}
}# Create account
mutation {
createAccount(input: {
email: "merchant@example.com"
fullName: "My Merchant"
currency: USD
externalId: "MERCHANT-001"
}) { id email status }
}
# Initiate payment
mutation {
initiatePayment(input: {
senderId: "..."
recipientId: "..."
amount: "250.00"
currency: USD
method: CREDIT_CARD
description: "Order #12345"
idempotencyKey: "unique-client-key-001"
}) {
success
message
payment { id referenceId status processingFee netAmount }
errors { field message }
}
}
# Confirm payment
mutation {
confirmPayment(paymentId: "...") {
success payment { status completedAt }
}
}
# Refund
mutation {
refundPayment(input: {
paymentId: "..."
amount: "100.00"
reason: "Customer requested"
idempotencyKey: "refund-unique-key-001"
}) {
success
refund { id amount status processedAt }
}
}subscription {
paymentStatusUpdated(paymentId: "...") {
id status updatedAt
}
}| Concern | Solution |
|---|---|
| Idempotency | Every mutation carries an idempotencyKey; duplicate requests return the original result |
| Concurrency | Pessimistic locks (SELECT FOR UPDATE) on account rows during balance changes |
| Optimistic Locking | @Version on Account and Payment entities to detect stale updates |
| Validation | Domain-layer PaymentValidator + Bean Validation annotations on DTOs |
| Fraud Detection | RiskService scoring (amount, velocity, account age, KYC) β extend for ML integration |
| Resilience | Resilience4j Circuit Breaker + Retry wrapping the payment processor |
| Audit | Async AuditService writing immutable AuditLog records with IP / user-agent |
| Error Handling | GraphQLExceptionResolver maps domain exceptions to typed GraphQL errors |
| Observability | Micrometer + Prometheus metrics on field fetch latency + error rates |
| Security | JWT-based stateless auth; @PreAuthorize on all resolvers |
| Schema Mapping | @QueryMapping, @MutationMapping, @SchemaMapping, @SubscriptionMapping |
# All tests
./mvnw test
# Unit tests only
./mvnw test -Dtest="*Test"
# Integration tests only
./mvnw test -Dtest="*IntegrationTest"| Layer | Test File | Annotations |
|---|---|---|
| Domain Model | DomainModelTest |
@Nested, @DisplayName |
| Validation | PaymentValidatorTest |
@ParameterizedTest, @CsvSource |
| Service (unit) | PaymentServiceTest |
@ExtendWith(MockitoExtension) |
| Service (unit) | AccountServiceTest |
@Mock, @InjectMocks |
| Repository | RepositoryIntegrationTest |
@DataJpaTest |
| GraphQL layer | PaymentGraphQLControllerTest |
@GraphQlTest, GraphQlTester |
| Full lifecycle | PaymentSystemIntegrationTest |
@SpringBootTest, @Transactional |
# Health
curl http://localhost:8080/actuator/health
# Prometheus metrics
curl http://localhost:8080/actuator/prometheus
# Custom metrics
graphql_field_fetch_seconds_* # per-field GraphQL latency
graphql_errors_total # total GraphQL errorssrc/main/java/com/payments/
βββ PaymentSystemApplication.java
βββ config/
β βββ AppConfig.java # Thread pool, instrumentation
β βββ GraphQLConfig.java # Scalar registrations
β βββ SecurityConfig.java # JWT security chain
βββ exception/
β βββ PaymentExceptions.java # Domain exception hierarchy
β βββ Exceptions.java # Factory methods
β βββ GraphQLExceptionResolver.java
βββ graphql/
β βββ resolver/
β β βββ PaymentGraphQLController.java # @QueryMapping / @MutationMapping
β β βββ SubscriptionController.java # @SubscriptionMapping
β βββ scalar/
β β βββ CustomScalars.java # Currency scalar
β βββ directive/
β βββ GraphQLMetricsInstrumentation.java
βββ model/
β βββ entity/ # JPA entities
β βββ dto/ # Input/output records
βββ repository/ # Spring Data JPA repositories
βββ security/
β βββ JwtService.java
β βββ JwtAuthenticationFilter.java
β βββ AccountUserDetailsService.java
βββ service/
β βββ AccountService.java
β βββ PaymentService.java
β βββ AuditService.java
β βββ RiskService.java
β βββ impl/
β βββ AccountServiceImpl.java
β βββ PaymentServiceImpl.java
βββ validation/
βββ PaymentValidator.java