Skip to content

luchersou/payment-microservice

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

20 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🧩 Payment Microservices System

A backend project that demonstrates a microservices architecture using NestJS, RabbitMQ, Docker, PostgreSQL, and Prisma ORM. This project was built to showcase real-world backend architecture concepts such as event-driven systems, Saga pattern (Choreography), asynchronous processing, and distributed transaction management.

NestJS RabbitMQ PostgreSQL Prisma Docker TypeScript


πŸ“ Architecture

This project implements a microservices architecture with an API Gateway that orchestrates communication between services using both synchronous HTTP (for queries) and asynchronous events (for commands).

graph LR
    Client[Client] -->|HTTP| GW[API Gateway]

    GW -->|Events| RMQ[RabbitMQ]
    GW -.->|HTTP| Order[Order Service]
    GW -.->|HTTP| Payment[Payment Service]

    RMQ <-->|Events| Order
    RMQ <-->|Events| Payment

    Order --> OrderDB[(PostgreSQL<br/>Order DB)]
    Payment --> PaymentDB[(PostgreSQL<br/>Payment DB)]

    style GW fill:#4A90E2,color:#fff
    style RMQ fill:#FF6B35,color:#fff
    style Order fill:#50C878,color:#fff
    style Payment fill:#50C878,color:#fff
    style OrderDB fill:#9B59B6,color:#fff
    style PaymentDB fill:#9B59B6,color:#fff
Loading

Architecture Highlights

  • API Gateway: Single entry point for all client requests (port 3000)
  • Event-Driven Commands: POST/PATCH operations emit events via RabbitMQ
  • Synchronous Queries: GET operations make direct HTTP calls to microservices
  • Saga Pattern (Choreography): Distributed transactions coordinated through events, with compensating actions for failures and cancellations
  • Service Autonomy: Each microservice has its own database and business logic
  • Decoupled Communication: Services communicate through events, not direct calls

πŸ—οΈ Project Structure

payment-microservices/
β”œβ”€β”€ apps/
β”‚   β”œβ”€β”€ api-gateway/                 # API Gateway (Port 3000)
β”‚   β”‚   └── src/
β”‚   β”‚       β”œβ”€β”€ common/
β”‚   β”‚       β”‚   └── http-client.helper.ts
β”‚   β”‚       └── modules/
β”‚   β”‚           β”œβ”€β”€ orders/
β”‚   β”‚           β”‚   β”œβ”€β”€ dto/
β”‚   β”‚           β”‚   β”œβ”€β”€ orders.controller.ts
β”‚   β”‚           β”‚   β”œβ”€β”€ orders.service.ts
β”‚   β”‚           β”‚   └── orders.module.ts
β”‚   β”‚           └── payments/
β”‚   β”‚               β”œβ”€β”€ payments.controller.ts
β”‚   β”‚               β”œβ”€β”€ payments.service.ts
β”‚   β”‚               └── payments.module.ts
β”‚   β”‚
β”‚   β”œβ”€β”€ order-service/               # Order Microservice (Port 3001)
β”‚   β”‚   β”œβ”€β”€ prisma/
β”‚   β”‚   β”‚   β”œβ”€β”€ generated/
β”‚   β”‚   β”‚   β”œβ”€β”€ migrations/
β”‚   β”‚   β”‚   β”œβ”€β”€ prisma.module.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ prisma.service.ts
β”‚   β”‚   β”‚   └── schema.prisma
β”‚   β”‚   └── src/
β”‚   β”‚       └── modules/
β”‚   β”‚           └── order/
β”‚   β”‚               β”œβ”€β”€ dto/
β”‚   β”‚               β”œβ”€β”€ order.consumer.ts
β”‚   β”‚               β”œβ”€β”€ order.controller.ts
β”‚   β”‚               └── order.service.ts
β”‚   β”‚
β”‚   └── payment-service/             # Payment Microservice (Port 3002)
β”‚       β”œβ”€β”€ prisma/
β”‚       β”‚   β”œβ”€β”€ generated/
β”‚       β”‚   β”œβ”€β”€ migrations/
β”‚       β”‚   β”œβ”€β”€ prisma.module.ts
β”‚       β”‚   β”œβ”€β”€ prisma.service.ts
β”‚       β”‚   └── schema.prisma
β”‚       └── src/
β”‚           └── modules/
β”‚               └── payment/
β”‚                   β”œβ”€β”€ dto/
β”‚                   β”œβ”€β”€ payment.consumer.ts
β”‚                   β”œβ”€β”€ payment.controller.ts
β”‚                   └── payment.service.ts
β”‚
β”œβ”€β”€ libs/
β”‚   β”œβ”€β”€ contracts/                   # Shared contracts
β”‚   β”‚   β”œβ”€β”€ events/                  # Event definitions
β”‚   β”‚   β”‚   β”œβ”€β”€ order-created.event.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ order-cancelled.event.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ payment-approved.event.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ payment-declined.event.ts
β”‚   β”‚   β”‚   └── payment-failed.event.ts
β”‚   β”‚   └── types/
β”‚   β”‚       └── event-types.enum.ts
β”‚   β”‚       └── cancel-reason.enum.ts
β”‚   β”‚
β”‚   └── messaging/                   # Shared RabbitMQ module
β”‚       └── rabbitmq/
β”‚           β”œβ”€β”€ config/
β”‚           β”œβ”€β”€ constants/
β”‚           β”œβ”€β”€ rabbitmq.module.ts
β”‚           └── rabbitmq.service.ts
β”‚
β”œβ”€β”€ docker-compose.yml
└── README.md

πŸš€ Features

βœ… API Gateway

  • Single entry point for all client requests
  • Routes queries (GET) directly to microservices via HTTP
  • Emits events for commands (POST/PATCH) via RabbitMQ
  • Centralized error handling and logging
  • Request timeout and retry logic

βœ… Order Service

  • Manages order lifecycle (PENDING_PAYMENT β†’ PAID β†’ CANCELLED β†’ FAILED)
  • Consumes order.create.requested and order.cancel.requested events to persist order state
  • Consumes payment.approved, payment.declined, payment.failed events to update order status
  • Emits order.created and order.cancelled events to trigger downstream reactions
  • RESTful API for order queries (GET endpoints)
  • Isolated PostgreSQL database

βœ… Payment Service

  • Manages payment lifecycle (PROCESSING β†’ APPROVED / DECLINED / FAILED / REFUNDED / CANCELLED)
  • Consumes order.created event to initiate payment processing
  • Consumes order.cancelled event to cancel or refund payments in progress
  • Emits payment.approved, payment.declined, payment.failed events based on processing result
  • Simulates payment gateway integration with approval/decline logic
  • Provides payment statistics and queries
  • Isolated PostgreSQL database

βœ… Event-Driven Architecture

  • RabbitMQ for asynchronous messaging
  • Dead Letter Queue (DLQ) for failed messages
  • Event replay and idempotency handling
  • Durable queues and persistent messages

βœ… Saga Pattern (Choreography)

  • Happy path: order.create.requested β†’ order.created β†’ payment.approved β†’ order marked as PAID
  • Failure path: payment.declined / payment.failed β†’ order marked as CANCELLED / FAILED
  • Compensating transaction: order.cancel.requested β†’ order.cancelled β†’ payment marked as CANCELLED or REFUNDED
  • No central coordinator β€” each service reacts to events and emits its own

πŸ› οΈ Technologies

Technology Purpose
NestJS Backend framework for building scalable Node.js applications
TypeScript Type-safe language for robust code
RabbitMQ Message broker for event-driven architecture
PostgreSQL Relational database for order and payment data
Prisma ORM Type-safe database access and migrations
Docker Containerization for consistent environments
Docker Compose Multi-container orchestration

πŸ“¦ Installation

Prerequisites

  • Node.js (v18+)
  • Docker and Docker Compose
  • npm or yarn

Steps

  1. Clone the repository
   git clone https://github.com/luchersou/payment-microservice.git
   cd payment-microservices
  1. Install dependencies
   npm install
  1. Start services with Docker Compose
   docker-compose up --build

πŸ”Œ API Endpoints

All requests go through the API Gateway on http://localhost:3000/api

πŸ“‹ Orders

Method Endpoint Description
POST /orders Create a new order (emits event)
GET /orders Get all orders (paginated)
GET /orders/:id Get order by ID
PATCH /orders/:id Update order status (emits event)

πŸ’³ Payments

Method Endpoint Description
GET /payments Get all payments (paginated)
GET /payments/:id Get payment by ID
GET /payments/order/:orderId Get payment by order ID
GET /payments/stats Get payment statistics by status

πŸ“‘ Event Flow

Create Order Flow

1. Client β†’ POST /api/orders
2. API Gateway β†’ Emit order.create.requested β†’ RabbitMQ

3. Order Service β†’ Consume order.create.requested
   - Generate orderId
   - Persist order (status: PENDING_PAYMENT)
   - Emit order.created β†’ RabbitMQ

4. Payment Service β†’ Consume order.created
   - Create payment (status: PROCESSING)
   - Simulate payment gateway

5. Payment Service β†’ Emit:
   - payment.approved
   - OR payment.declined
   - OR payment.failed

6. Order Service β†’ Consume payment event
   - Update order status:
     - APPROVED β†’ PAID
     - DECLINED β†’ CANCELLED
     - FAILED β†’ FAILED

Cancel Order Flow

1. Client β†’ PATCH /api/orders/:id/cancel
2. API Gateway β†’ Emit order.cancel.requested β†’ RabbitMQ

3. Order Service β†’ Consume order.cancel.requested
   - Update order status β†’ CANCELLED
   - Emit order.cancelled β†’ RabbitMQ

4. Payment Service β†’ Consume order.cancelled
   - If PROCESSING β†’ Mark as CANCELLED
   - If APPROVED β†’ Mark as REFUNDED

πŸ§ͺ Example Requests

πŸ“‹ Orders

Create Order

POST http://localhost:3000/api/orders
Content-Type: application/json

{
  "userId": "d55fa6d6-63c2-4633-aeaf-ecf0c80fb48f",
  "total": 999
}

cURL:

curl -X POST http://localhost:3000/api/orders \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "d55fa6d6-63c2-4633-aeaf-ecf0c80fb48f",
    "total": 999
  }'

Response:

{
    "orderId": "11c4a663-47fd-4590-9c2d-ee72cc58bbbd",
    "message": "Order creation request accepted",
    "status": "PENDING_PAYMENT"
}

Get All Orders (Paginated)

GET http://localhost:3000/api/orders?page=1&limit=10

cURL:

curl http://localhost:3000/api/orders?page=1&limit=10

Response:

{
  "data": [
    {
      "id": "476f5730-aa83-4ff0-ab9f-d6e19836e195",
      "userId": "d55fa6d6-63c2-4633-aeaf-ecf0c80fb48f",
      "total": 999,
      "status": "PAID",
      "createdAt": "2026-02-15T01:42:19.000Z",
      "updatedAt": "2026-02-15T01:42:21.000Z"
    },
    {
      "id": "b7740f92-e574-4936-aa23-56f98ba61418",
      "userId": "d55fa6d6-63c2-4633-aeaf-ecf0c80fb48f",
      "total": 999,
      "status": "CANCELLED",
      "createdAt": "2026-02-15T01:42:39.000Z",
      "updatedAt": "2026-02-15T01:42:40.000Z"
    }
  ],
  "meta": {
    "page": 1,
    "limit": 10,
    "total": 2,
    "totalPages": 1
  }
}

Get Order by ID

GET http://localhost:3000/api/orders/476f5730-aa83-4ff0-ab9f-d6e19836e195

cURL:

curl http://localhost:3000/api/orders/476f5730-aa83-4ff0-ab9f-d6e19836e195

Response:

{
  "id": "476f5730-aa83-4ff0-ab9f-d6e19836e195",
  "userId": "d55fa6d6-63c2-4633-aeaf-ecf0c80fb48f",
  "total": 999,
  "status": "PAID",
  "createdAt": "2026-02-15T01:42:19.000Z",
  "updatedAt": "2026-02-15T01:42:21.000Z"
}

Cancel Order (Manual)

PATCH http://localhost:3000/api/orders/476f5730-aa83-4ff0-ab9f-d6e19836e195/cancel

cURL:

curl -X PATCH http://localhost:3000/api/orders/476f5730-aa83-4ff0-ab9f-d6e19836e195 \
  -H "Content-Type: application/json" \
  -d '{"status": "CANCELLED"}'

Response:

{
    "orderId": "476f5730-aa83-4ff0-ab9f-d6e19836e195",
    "message": "Order cancellation request accepted"
}

πŸ’³ Payments

Get All Payments (Paginated)

GET http://localhost:3000/api/payments?page=1&limit=10

cURL:

curl http://localhost:3000/api/payments?page=1&limit=10

Response:

{
  "data": [
    {
      "id": "8a5da4d7-3512-4c74-bd62-64b6c0e93e7a",
      "orderId": "476f5730-aa83-4ff0-ab9f-d6e19836e195",
      "amount": 999,
      "status": "APPROVED",
      "createdAt": "2026-02-15T01:42:19.500Z",
      "updatedAt": "2026-02-15T01:42:20.500Z"
    },
    {
      "id": "1220b65f-df5f-456d-8238-e03520bff097",
      "orderId": "b7740f92-e574-4936-aa23-56f98ba61418",
      "amount": 999,
      "status": "DECLINED",
      "createdAt": "2026-02-15T01:42:39.200Z",
      "updatedAt": "2026-02-15T01:42:40.200Z"
    }
  ],
  "meta": {
    "page": 1,
    "limit": 10,
    "total": 2,
    "totalPages": 1
  }
}

Get Payment by ID

GET http://localhost:3000/api/payments/8a5da4d7-3512-4c74-bd62-64b6c0e93e7a

cURL:

curl http://localhost:3000/api/payments/8a5da4d7-3512-4c74-bd62-64b6c0e93e7a

Response:

{
  "id": "8a5da4d7-3512-4c74-bd62-64b6c0e93e7a",
  "orderId": "476f5730-aa83-4ff0-ab9f-d6e19836e195",
  "amount": 999,
  "status": "APPROVED",
  "createdAt": "2026-02-15T01:42:19.500Z",
  "updatedAt": "2026-02-15T01:42:20.500Z"
}

Get Payment by Order ID

GET http://localhost:3000/api/payments/order/476f5730-aa83-4ff0-ab9f-d6e19836e195

cURL:

curl http://localhost:3000/api/payments/order/476f5730-aa83-4ff0-ab9f-d6e19836e195

Response:

{
  "id": "8a5da4d7-3512-4c74-bd62-64b6c0e93e7a",
  "orderId": "476f5730-aa83-4ff0-ab9f-d6e19836e195",
  "amount": 999,
  "status": "APPROVED",
  "createdAt": "2026-02-15T01:42:19.500Z",
  "updatedAt": "2026-02-15T01:42:20.500Z"
}

Get Payment Statistics

GET http://localhost:3000/api/payments/stats

cURL:

curl http://localhost:3000/api/payments/stats

Response:

{
  "byStatus": [
    {
      "status": "APPROVED",
      "count": 2,
      "totalAmount": 1998
    },
    {
      "status": "DECLINED",
      "count": 1,
      "totalAmount": 999
    }
  ]
}

πŸ›οΈ Design Patterns Used

  • Microservices Architecture: Independent services with isolated databases
  • API Gateway Pattern: Single entry point for client requests
  • Event-Driven Architecture: Asynchronous communication via RabbitMQ
  • Saga Pattern (Choreography): Distributed transactions with compensating actions across services

πŸ“„ License

This project is licensed under the MIT License.


πŸ‘€ Author

Lucas Herzinger Souza

About

Event-driven microservices system for asynchronous order processing. Built with NestJS, RabbitMQ, PostgreSQL, Docker and Prisma ORM. Features separated API and Worker services with message-based communication for scalable architecture.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages