Skip to content

Repository files navigation

PayFlow — Digital Payments Platform

A production-grade, PhonePe-style UPI payments system built with Java 21, Spring Boot 3, PostgreSQL, and Apache Kafka. Demonstrates microservices architecture, event-driven design, JWT security, and concurrency control patterns.


Architecture

Client
  |
  v
[API Gateway :8080]  -- JWT validation at edge
  |
  |-- /api/auth/**      --> [User Service    :8081] <--> [PostgreSQL userdb]
  |-- /api/users/**     --> [User Service    :8081]
  |-- /api/wallets/**   --> [Wallet Service  :8082] <--> [PostgreSQL walletdb]
  |-- /api/payments/**  --> [Payment Service :8083] <--> [PostgreSQL paymentdb]
                                    |
                                    | Kafka: payment-events topic
                                    v
                         [Notification Service :8084] <--> [PostgreSQL notificationdb]

Services

Service Port Responsibility
API Gateway 8080 JWT auth filter, routing
User Service 8081 Registration, login, UPI ID management
Wallet Service 8082 Balance management, transfers, transaction history
Payment Service 8083 Payment orchestration, Kafka event publishing
Notification Service 8084 Kafka consumer, push/SMS notifications

Key Design Decisions

1. Optimistic Locking (Wallet Service)

@Version on the Wallet entity prevents double-spend in concurrent payment requests. If two requests debit the same wallet simultaneously, one gets OptimisticLockException and is rejected — no dirty reads, no lost updates.

2. Event-Driven Notifications (Kafka)

Payment Service publishes domain events (PAYMENT_INITIATED, PAYMENT_SUCCESS, PAYMENT_FAILED) to the payment-events topic. Notification Service consumes these asynchronously — decoupled, resilient, and easy to extend (analytics, fraud detection can tap the same topic).

3. Idempotency (Wallet Service)

Every transfer carries a paymentId (UUID). Before debiting, wallet-service checks if referenceId already exists in wallet_transactions. Duplicate Kafka retries or network replays are safely rejected with 409 CONFLICT.

4. Database-per-Service

Each service owns its schema in a dedicated PostgreSQL instance. No shared tables, no cross-service JOINs — true data isolation.

5. JWT at the Gateway

The API Gateway validates tokens once at the edge. Downstream services trust the Authorization header forwarded by the gateway (internal network trust model).


Quick Start

Prerequisites

  • Docker & Docker Compose
  • Java 21+ (for local dev)
  • Maven 3.9+

Run with Docker Compose

git clone https://github.com/23Anish/PayFlow-DigitalPaymentsPlatform.git
cd PayFlow-DigitalPaymentsPlatform
docker-compose up --build

Services start in order: PostgreSQL instances → Zookeeper → Kafka → App services

Kafka UI

Visit http://localhost:8090 to inspect topics, consumer groups, and messages.


API Reference

Register User

POST /api/auth/register
Content-Type: application/json

{
  "phone": "9876543210",
  "email": "anishthumula@gmail.com",
  "password": "password123",
  "fullName": "Anish Thumula",
  "upiHandle": "23Anish"
}

Login

POST /api/auth/login
Content-Type: application/json

{ "phone": "9876543210", "password": "password123" }

Returns accessToken — use as Authorization: Bearer <token> for all other requests.

Create Wallet

POST /api/wallets
Authorization: Bearer <token>

Add Money

POST /api/wallets/add-money
Authorization: Bearer <token>
Content-Type: application/json

{ "amount": 1000.00, "source": "BANK_ACCOUNT" }

Send Money (UPI Transfer)

POST /api/payments
Authorization: Bearer <token>
Content-Type: application/json

{
  "receiverUpiId": "friend@payflow",
  "amount": 500.00,
  "note": "For dinner",
  "type": "UPI_TRANSFER"
}

Payment History

GET /api/payments/history?page=0&size=20
Authorization: Bearer <token>

Testing the Kafka Flow

  1. Register two users (Alice + Bob)
  2. Create wallets for both, add money to Alice
  3. POST /api/payments to send from Alice to Bob
  4. Open Kafka UI (http://localhost:8090) → topic payment-events
  5. See PAYMENT_INITIATED, then PAYMENT_SUCCESS events
  6. Notification-service logs show both Alice and Bob notified

Tech Stack

  • Java 21 — Records, pattern matching, text blocks
  • Spring Boot 3.2 — Web, JPA, Security, Validation
  • Spring Cloud Gateway — Reactive edge proxy
  • PostgreSQL 15 — Per-service databases
  • Apache Kafka — Async event streaming (Confluent Platform 7.5)
  • JWT (JJWT 0.12) — Stateless authentication
  • Lombok — Boilerplate reduction
  • Docker + Docker Compose — Containerized local dev

Project Structure

payflow/
├── api-gateway/           # Spring Cloud Gateway + JWT filter
├── user-service/          # Auth, registration, UPI ID
├── wallet-service/        # Balance, transfers, optimistic locking
├── payment-service/       # Orchestration + Kafka producer
├── notification-service/  # Kafka consumer + notification storage
├── docker-compose.yml     # Full local stack
└── pom.xml                # Parent POM (multi-module)

About

UPI payments platform using Spring Boot microservices, PostgreSQL (optimistic locking for concurrency control), and Kafka for async event-driven notifications. Implemented idempotency guarantees, JWT auth at the API gateway edge, and database-per-service isolation.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages