Skip to content

Repository files navigation

πŸš€ Event-Driven Order System

A production-oriented event-driven microservices order management system built with NestJS, TypeScript, PostgreSQL, Apache Kafka, Redis, BullMQ, Prisma, and Docker.

This project is primarily designed as a practical backend engineering project to learn and implement real-world distributed-system concepts.

The system focuses on:

  • Microservices Architecture
  • Event-Driven Architecture
  • Apache Kafka
  • Transactional Outbox Pattern
  • Database-per-Service
  • Eventual Consistency
  • Idempotent Consumers
  • Distributed System Reliability
  • Clean Architecture
  • SOLID Principles
  • Redis
  • BullMQ
  • Background Workers
  • Retry & Dead Letter Queues
  • Authentication & Authorization
  • API Gateway
  • Observability
  • Dockerized Deployment
  • Production-oriented Backend Design

πŸ“Œ Project Goal

The goal of this project is to build a realistic order-processing platform where different business capabilities are separated into independent microservices.

A typical order lifecycle will look like:

Customer
   β”‚
   β–Ό
API Gateway
   β”‚
   β–Ό
Order Service
   β”‚
   β”œβ”€β”€ Create Order
   β”œβ”€β”€ Save Order
   └── Create Outbox Event
           β”‚
           β–Ό
         Kafka
           β”‚
     β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”
     β–Ό           β–Ό
 Payment       Inventory
 Service       Service
     β”‚           β”‚
     β–Ό           β–Ό
Payment       Stock
Processing    Reservation
     β”‚           β”‚
     β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
           β–Ό
         Kafka
           β”‚
           β–Ό
     Order Service
           β”‚
           β–Ό
      Order Confirmed
           β”‚
           β–Ό
 Notification Service
           β”‚
           β”œβ”€β”€ Email
           └── WebSocket

πŸ—οΈ Architecture

                                  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                  β”‚    Client    β”‚
                                  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
                                         β”‚
                                         β–Ό
                                β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                β”‚   API Gateway    β”‚
                                β”‚      :3000       β”‚
                                β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                         β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚                          β”‚                          β”‚
              β–Ό                          β–Ό                          β–Ό
      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
      β”‚ Auth Service β”‚          β”‚ Order Serviceβ”‚          β”‚  Inventory   β”‚
      β”‚              β”‚          β”‚              β”‚          β”‚   Service    β”‚
      β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜          β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜          β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
             β”‚                         β”‚                         β”‚
             β–Ό                         β–Ό                         β–Ό
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”               β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚ auth_db β”‚               β”‚order_db β”‚              β”‚ inventory_dbβ”‚
        β”‚Postgres β”‚               β”‚Postgres β”‚              β”‚  Postgres   β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜               β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                       β”‚
                                       β–Ό
                                β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                β”‚    Outbox    β”‚
                                β”‚    Events    β”‚
                                β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
                                       β”‚
                                       β–Ό
                                β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                β”‚    Kafka     β”‚
                                β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
                                       β”‚
                       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                       β”‚               β”‚                β”‚
                       β–Ό               β–Ό                β–Ό
                Payment Service  Inventory Service  Notification
                       β”‚                                  Service
                       β–Ό                                      β”‚
                  payment_db                                 β”‚
                                                            β–Ό
                                                         BullMQ
                                                            β”‚
                                                            β–Ό
                                                          Redis
                                                            β”‚
                                                            β–Ό
                                                        Workers

πŸ“¦ Monorepo Structure

event-driven-order-system/
β”‚
β”œβ”€β”€ apps/
β”‚   β”‚
β”‚   β”œβ”€β”€ api-gateway/
β”‚   β”‚
β”‚   β”œβ”€β”€ auth-service/
β”‚   β”‚
β”‚   β”œβ”€β”€ order-service/
β”‚   β”‚
β”‚   β”œβ”€β”€ payment-service/
β”‚   β”‚
β”‚   β”œβ”€β”€ inventory-service/
β”‚   β”‚
β”‚   └── notification-service/
β”‚
β”œβ”€β”€ libs/
β”‚   β”‚
β”‚   β”œβ”€β”€ auth/
β”‚   β”œβ”€β”€ common/
β”‚   β”œβ”€β”€ events/
β”‚   β”œβ”€β”€ kafka/
β”‚   └── redis/
β”‚
β”œβ”€β”€ infrastructure/
β”‚   β”œβ”€β”€ docker/
β”‚   β”œβ”€β”€ kafka/
β”‚   β”œβ”€β”€ postgres/
β”‚   β”œβ”€β”€ redis/
β”‚   └── nginx/
β”‚
β”œβ”€β”€ docker-compose.yml
β”œβ”€β”€ nest-cli.json
β”œβ”€β”€ package.json
β”œβ”€β”€ pnpm-lock.yaml
└── README.md

🧩 Services

1. API Gateway

The API Gateway is the single public entry point for clients.

Responsibilities

  • HTTP API
  • API versioning
  • Authentication forwarding
  • Authorization
  • Request validation
  • Rate limiting
  • Routing
  • Error handling
  • Correlation ID
  • WebSocket gateway

Important Rule

The API Gateway should remain thin.

It should not contain core business logic.

Client
  ↓
API Gateway
  ↓
Business Service

2. Auth Service

Responsible for:

  • User registration
  • Login
  • Password hashing
  • JWT access token
  • Refresh token
  • Logout
  • Token rotation
  • Role-based authorization
  • User management

Database

auth_db
β”œβ”€β”€ users
β”œβ”€β”€ refresh_tokens
└── sessions

Auth Service owns its database.

No other service should directly access auth_db.


3. Order Service

The Order Service is responsible for the complete order lifecycle.

Responsibilities

  • Create order
  • Retrieve order
  • List user orders
  • Cancel order
  • Order state management
  • Create order items
  • Publish order events
  • Consume payment events
  • Consume inventory events

Database

order_db
β”œβ”€β”€ orders
β”œβ”€β”€ order_items
β”œβ”€β”€ outbox_events
└── processed_events

4. Payment Service

Responsible for:

  • Payment creation
  • Payment processing
  • Payment success
  • Payment failure
  • Refund
  • Payment status
  • Payment idempotency
  • Publishing payment events

Database

payment_db
β”œβ”€β”€ payments
β”œβ”€β”€ refunds
β”œβ”€β”€ outbox_events
└── processed_events

5. Inventory Service

Responsible for:

  • Product management
  • Stock management
  • Stock reservation
  • Stock release
  • Stock adjustment
  • Inventory consistency
  • Publishing inventory events

Database

inventory_db
β”œβ”€β”€ products
β”œβ”€β”€ inventory
β”œβ”€β”€ stock_reservations
β”œβ”€β”€ outbox_events
└── processed_events

6. Notification Service

Responsible for:

  • Kafka event consumption
  • Email notifications
  • WebSocket notifications
  • Notification history
  • Background jobs
  • Retry handling

Flow:

Kafka
  ↓
Notification Consumer
  ↓
BullMQ
  ↓
Redis
  ↓
Notification Worker
  ↓
Email / WebSocket

πŸ—„οΈ Database Architecture

The project follows the Database-per-Service pattern.

Auth Service
     ↓
  auth_db

Order Service
     ↓
 order_db

Payment Service
     ↓
 payment_db

Inventory Service
     ↓
inventory_db

Services must never directly query another service's database.

❌ Wrong

Order Service
      ↓
SELECT FROM payment_db.payments

βœ… Correct

Order Service
      ↓
Kafka Event
      ↓
Payment Service
      ↓
Payment DB

🐘 PostgreSQL Strategy

During development, a single PostgreSQL server/cluster can host multiple databases:

PostgreSQL
β”‚
β”œβ”€β”€ auth_db
β”œβ”€β”€ order_db
β”œβ”€β”€ payment_db
└── inventory_db

This keeps development infrastructure simple.

Later, production workloads can be separated into independent PostgreSQL instances/clusters if required.


πŸ”„ Transactional Outbox Pattern

One of the main learning goals of this project is implementing the Transactional Outbox Pattern.

The Dual-Write Problem

Suppose Order Service does this:

1. Save Order β†’ PostgreSQL βœ…

2. Publish order.created β†’ Kafka ❌

If Kafka fails, the order exists but the event is lost.

This creates inconsistency.


βœ… Transactional Outbox Solution

The database change and event are written inside the same PostgreSQL transaction.

BEGIN

INSERT INTO orders

INSERT INTO outbox_events

COMMIT

Both succeed or both fail.

Then a separate publisher sends the event to Kafka.

PostgreSQL
    β”‚
    β–Ό
outbox_events
    β”‚
    β–Ό
Outbox Publisher
    β”‚
    β–Ό
Kafka

πŸ“‹ Outbox Table

Example:

outbox_events
β”œβ”€β”€ id
β”œβ”€β”€ aggregate_type
β”œβ”€β”€ aggregate_id
β”œβ”€β”€ event_type
β”œβ”€β”€ payload
β”œβ”€β”€ version
β”œβ”€β”€ created_at
β”œβ”€β”€ published_at
β”œβ”€β”€ attempts
β”œβ”€β”€ last_error
β”œβ”€β”€ locked_at
└── locked_by

Example event:

{
  "id": "event-id",
  "aggregateType": "Order",
  "aggregateId": "order-id",
  "eventType": "order.created",
  "version": 1,
  "payload": {
    "orderId": "order-id",
    "userId": "user-id",
    "total": 1500,
    "items": []
  },
  "createdAt": "2026-08-09T00:00:00Z"
}

πŸ”₯ Kafka Architecture

Kafka is the central event backbone of the system.

Producer
   β”‚
   β–Ό
Kafka Topic
   β”‚
   β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β–Ό               β–Ό
Consumer A      Consumer B

πŸ“¨ Domain Events

Main events:

order.created
order.cancelled
order.confirmed
order.failed
order.completed

payment.created
payment.completed
payment.failed
payment.refunded

inventory.reserved
inventory.released
inventory.insufficient

πŸ—‚οΈ Kafka Topics

Recommended topics:

order.events.v1
payment.events.v1
inventory.events.v1
notification.events.v1

For failed messages:

order.events.v1.DLQ
payment.events.v1.DLQ
inventory.events.v1.DLQ

πŸ” Order Processing Flow

Successful Order

POST /api/v1/orders
        β”‚
        β–Ό
API Gateway
        β”‚
        β–Ό
Order Service
        β”‚
        β”œβ”€β”€ INSERT order
        β”œβ”€β”€ INSERT order_items
        └── INSERT outbox_event
                β”‚
                β–Ό
             COMMIT
                β”‚
                β–Ό
        Outbox Publisher
                β”‚
                β–Ό
              Kafka
                β”‚
                β–Ό
         order.created
          β”‚           β”‚
          β–Ό           β–Ό
       Payment     Inventory
       Service      Service
          β”‚           β”‚
          β–Ό           β–Ό
payment.completed inventory.reserved
          β”‚           β”‚
          β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
                β–Ό
              Kafka
                β”‚
                β–Ό
          Order Service
                β”‚
                β–Ό
        Order CONFIRMED
                β”‚
                β–Ό
      Notification Service

❌ Payment Failure Flow

order.created
      β”‚
      β–Ό
Payment Service
      β”‚
      β–Ό
payment.failed
      β”‚
      β–Ό
Order Service
      β”‚
      β–Ό
Order FAILED
      β”‚
      β–Ό
Inventory Service
      β”‚
      β–Ό
Release Reservation
      β”‚
      β–Ό
Notification Service

This demonstrates eventual consistency and compensating actions.


πŸ” Idempotent Consumers

Kafka provides at-least-once delivery in common production designs.

Therefore, consumers must be idempotent.

Example:

Kafka Event
    β”‚
    β–Ό
Consumer
    β”‚
    β–Ό
Check processed_events
    β”‚
    β”œβ”€β”€ Event exists
    β”‚       ↓
    β”‚     Ignore
    β”‚
    └── Event does not exist
            β”‚
            β–Ό
       Process Event
            β”‚
            β–Ό
    Save processed_event

Example table:

processed_events
β”œβ”€β”€ event_id
β”œβ”€β”€ event_type
β”œβ”€β”€ processed_at
└── consumer

The same event must not produce duplicate business effects.


πŸ” Retry Strategy

Temporary failures should be retried.

Consumer
   β”‚
   β–Ό
Processing
   β”‚
   β”œβ”€β”€ Success β†’ Commit
   β”‚
   └── Failure
        β”‚
        β–Ό
      Retry
        β”‚
        β”œβ”€β”€ Success
        β”‚
        └── Failure
              β”‚
              β–Ό
             DLQ

Example retry schedule:

Retry 1 β†’ 1 second
Retry 2 β†’ 5 seconds
Retry 3 β†’ 30 seconds
Retry 4 β†’ 2 minutes

☠️ Dead Letter Queue

Events that cannot be processed after the configured retry limit are moved to a DLQ.

Main Topic
    ↓
Consumer
    ↓
Retry
    ↓
Retry
    ↓
Retry
    ↓
DLQ

DLQ messages should preserve:

  • Original event
  • Error message
  • Retry count
  • Consumer name
  • Timestamp

🧠 Idempotency

The system should support idempotency for operations such as:

Create Order
Payment
Refund
Inventory Reservation

Example:

Idempotency-Key: abc123

Repeated requests using the same key should not create duplicate business operations.


🧱 Clean Architecture

Each business service should follow a clean architecture structure.

Example:

order-service/

src/
β”œβ”€β”€ modules/
β”‚   └── order/
β”‚       β”‚
β”‚       β”œβ”€β”€ domain/
β”‚       β”‚   β”œβ”€β”€ entities/
β”‚       β”‚   β”œβ”€β”€ value-objects/
β”‚       β”‚   └── repositories/
β”‚       β”‚
β”‚       β”œβ”€β”€ application/
β”‚       β”‚   β”œβ”€β”€ use-cases/
β”‚       β”‚   └── dto/
β”‚       β”‚
β”‚       β”œβ”€β”€ infrastructure/
β”‚       β”‚   β”œβ”€β”€ persistence/
β”‚       β”‚   └── messaging/
β”‚       β”‚
β”‚       └── presentation/
β”‚           β”œβ”€β”€ controllers/
β”‚           └── consumers/
β”‚
β”œβ”€β”€ config/
β”œβ”€β”€ health/
└── main.ts

🧩 SOLID Principles

The project intentionally follows SOLID.

Single Responsibility

Separate responsibilities:

OrderController
OrderService
OrderRepository
OrderEventPublisher

Open/Closed

Example payment providers:

PaymentProvider
β”‚
β”œβ”€β”€ StripeProvider
β”œβ”€β”€ PayPalProvider
└── MockPaymentProvider

Liskov Substitution

Implementations should be replaceable through abstractions.


Interface Segregation

Prefer small interfaces:

OrderReader
OrderWriter
OrderCanceller

instead of one huge interface.


Dependency Inversion

Business logic depends on abstractions.

Order Use Case
      β”‚
      β–Ό
OrderRepository
      β–²
      β”‚
PrismaOrderRepository

πŸ“š Shared Libraries

libs/common

Reusable cross-service utilities.

Possible contents:

common/
β”œβ”€β”€ constants/
β”œβ”€β”€ decorators/
β”œβ”€β”€ exceptions/
β”œβ”€β”€ filters/
β”œβ”€β”€ interceptors/
β”œβ”€β”€ pipes/
└── types/

Only truly generic functionality should go here.


πŸ” libs/auth

Shared authentication contracts/utilities.

Possible contents:

auth/
β”œβ”€β”€ decorators/
β”œβ”€β”€ guards/
β”œβ”€β”€ interfaces/
└── types/

Business-specific authentication logic stays inside auth-service.


πŸ“¨ libs/events

Shared domain event contracts.

Example:

events/
β”œβ”€β”€ order/
β”‚   β”œβ”€β”€ order-created.event.ts
β”‚   β”œβ”€β”€ order-cancelled.event.ts
β”‚   └── order-confirmed.event.ts
β”‚
β”œβ”€β”€ payment/
β”‚   β”œβ”€β”€ payment-completed.event.ts
β”‚   └── payment-failed.event.ts
β”‚
└── inventory/
    β”œβ”€β”€ inventory-reserved.event.ts
    └── inventory-released.event.ts

πŸ“¨ libs/kafka

Reusable Kafka infrastructure.

kafka/
β”œβ”€β”€ kafka.module.ts
β”œβ”€β”€ kafka.producer.ts
β”œβ”€β”€ kafka.consumer.ts
β”œβ”€β”€ kafka.client.ts
└── kafka.types.ts

Kafka infrastructure should be separated from business events.


⚑ libs/redis

Reusable Redis infrastructure.

redis/
β”œβ”€β”€ redis.module.ts
β”œβ”€β”€ redis.service.ts
└── redis.types.ts

Redis can support:

  • Cache
  • BullMQ
  • Rate limiting
  • Distributed locks

Redis is not the primary source of truth.


πŸ›£οΈ API Routes

Authentication

POST   /api/v1/auth/register
POST   /api/v1/auth/login
POST   /api/v1/auth/refresh
POST   /api/v1/auth/logout
GET    /api/v1/auth/me

Products

GET    /api/v1/products
GET    /api/v1/products/:productId

POST   /api/v1/products
PATCH  /api/v1/products/:productId
DELETE /api/v1/products/:productId

Orders

POST   /api/v1/orders
GET    /api/v1/orders
GET    /api/v1/orders/:orderId
POST   /api/v1/orders/:orderId/cancel

Payments

POST   /api/v1/orders/:orderId/payments
GET    /api/v1/orders/:orderId/payments
GET    /api/v1/payments/:paymentId
POST   /api/v1/payments/:paymentId/refund

Notifications

GET    /api/v1/notifications
GET    /api/v1/notifications/unread
PATCH  /api/v1/notifications/:id/read
PATCH  /api/v1/notifications/read-all

❀️ Health Checks

Every service should expose:

GET /health
GET /health/live
GET /health/ready

Readiness should verify dependencies such as:

PostgreSQL
Kafka
Redis

πŸ“Š Metrics

Expose:

GET /metrics

Metrics can later be collected by Prometheus.

Important metrics:

HTTP request count
HTTP latency
HTTP error rate
Kafka consumer lag
Kafka throughput
Database connections
Redis usage
Queue size
Worker failures

⚑ Redis & BullMQ

Notification processing:

Kafka
  ↓
Notification Consumer
  ↓
BullMQ Queue
  ↓
Redis
  ↓
Notification Worker
  ↓
Email Provider

Possible queues:

email
notifications
websocket
cleanup

BullMQ will provide:

  • Background processing
  • Retry
  • Delayed jobs
  • Failed jobs
  • Job prioritization

πŸ”’ Authentication & Security

The system should implement:

  • JWT access tokens
  • Refresh tokens
  • Password hashing
  • RBAC
  • Request validation
  • Rate limiting
  • CORS
  • Helmet
  • Secure headers
  • Environment-based secrets
  • Service authentication
  • Database least privilege

Roles:

USER
ADMIN

πŸ”­ Observability

The system should implement:

Structured Logging
        β”‚
        β–Ό
Correlation ID
        β”‚
        β–Ό
API Gateway
        β”‚
        β–Ό
Microservice
        β”‚
        β–Ό
Kafka Event
        β”‚
        β–Ό
Consumer

A correlation ID should be propagated across the event lifecycle whenever possible.


🐳 Docker Infrastructure

Development environment:

Docker Compose
β”‚
β”œβ”€β”€ PostgreSQL
β”œβ”€β”€ Redis
β”œβ”€β”€ Kafka
β”œβ”€β”€ Kafka UI
β”œβ”€β”€ Prometheus
└── Grafana

Application services:

β”œβ”€β”€ api-gateway
β”œβ”€β”€ auth-service
β”œβ”€β”€ order-service
β”œβ”€β”€ payment-service
β”œβ”€β”€ inventory-service
└── notification-service

🌍 Environment Configuration

Each service should manage its own environment configuration.

Example:

NODE_ENV=development

APP_NAME=order-service
PORT=3001

DATABASE_URL=postgresql://...

KAFKA_BROKERS=localhost:9092
KAFKA_CLIENT_ID=order-service
KAFKA_GROUP_ID=order-service-group

REDIS_HOST=localhost
REDIS_PORT=6379

Never commit secrets to Git.

Use:

.env
.env.example

and secret management in production.


πŸ§ͺ Testing Strategy

Unit Tests

Test:

  • Domain logic
  • Use cases
  • Services
  • Event handlers
  • Validation

Integration Tests

Test:

  • PostgreSQL repositories
  • Kafka producers
  • Kafka consumers
  • Redis
  • BullMQ

E2E Tests

Test complete workflows.

Register
   ↓
Login
   ↓
Create Order
   ↓
Payment
   ↓
Inventory Reservation
   ↓
Order Confirmation
   ↓
Notification

πŸ“ˆ Reliability Goals

The system should handle:

  • Duplicate Kafka messages
  • Kafka downtime
  • Consumer crashes
  • Database failures
  • Network failures
  • Payment failures
  • Inventory failures
  • Worker failures
  • Notification failures

The design prioritizes:

At-Least-Once Delivery
+
Idempotent Consumers
+
Retry
+
DLQ

rather than assuming that every distributed operation can be exactly-once.


🧠 Learning Objectives

By completing this project, the following concepts should become practical rather than theoretical:

NestJS

  • Modules
  • Dependency Injection
  • Guards
  • Interceptors
  • Pipes
  • Filters
  • Custom decorators
  • Configuration
  • Microservices

PostgreSQL

  • Transactions
  • Isolation
  • Indexing
  • Constraints
  • Locking
  • Concurrency
  • Migrations

Prisma

  • Schema design
  • Relations
  • Transactions
  • Migrations
  • Repository pattern

Kafka

  • Producers
  • Consumers
  • Topics
  • Partitions
  • Consumer Groups
  • Offsets
  • Rebalancing
  • Retry
  • DLQ
  • Event ordering

Distributed Systems

  • Eventual consistency
  • Idempotency
  • At-least-once delivery
  • Failure handling
  • Compensation
  • Distributed transactions
  • Outbox Pattern

Redis

  • Caching
  • Rate limiting
  • Queue infrastructure
  • Distributed locks

BullMQ

  • Workers
  • Retry
  • Delayed jobs
  • Failed jobs
  • Job queues

Architecture

  • SOLID
  • Clean Architecture
  • Dependency Inversion
  • Repository Pattern
  • Event-Driven Architecture
  • Database-per-Service
  • API Gateway

πŸ—ΊοΈ Implementation Roadmap

Phase 1 β€” Foundation

  • NestJS monorepo
  • Configure applications
  • Configure shared libraries
  • ESLint
  • Prettier
  • Environment configuration
  • Docker development environment

Phase 2 β€” Authentication

  • Auth Service
  • User registration
  • Login
  • Password hashing
  • JWT
  • Refresh token
  • RBAC
  • Redis integration

Phase 3 β€” Order Service

  • Order domain
  • Order entity
  • Order items
  • Order repository
  • Create order
  • Get orders
  • Cancel order
  • Order state machine

Phase 4 β€” Kafka

  • Kafka Docker setup
  • Kafka client library
  • Producer
  • Consumer
  • Topics
  • Consumer groups
  • Event contracts
  • Event versioning

Phase 5 β€” Transactional Outbox

  • Outbox table
  • Atomic DB + outbox transaction
  • Outbox publisher
  • Kafka publishing
  • Retry failed events
  • Publisher concurrency handling
  • Published event tracking

Phase 6 β€” Payment Service

  • Payment domain
  • Payment DB
  • Payment creation
  • Payment processing
  • Payment success
  • Payment failure
  • Refund
  • Idempotency

Phase 7 β€” Inventory Service

  • Product model
  • Inventory model
  • Stock management
  • Reservation
  • Release
  • Concurrency handling
  • Inventory events

Phase 8 β€” Eventual Consistency

Implement:

Order Created
      ↓
Payment
      ↓
Inventory
      ↓
Order Confirmation

Handle failures with compensating actions.


Phase 9 β€” Idempotency & Reliability

  • Processed events
  • Idempotent consumers
  • Retry
  • Exponential backoff
  • DLQ
  • Timeouts
  • Circuit breaker
  • Graceful shutdown

Phase 10 β€” Redis & BullMQ

  • Redis module
  • Product cache
  • Rate limiting
  • BullMQ
  • Workers
  • Retry jobs
  • Failed jobs

Phase 11 β€” Notification Service

  • Kafka consumers
  • Notification domain
  • Email queue
  • Email worker
  • WebSocket notifications
  • Notification history

Phase 12 β€” Observability

  • Structured logging
  • Correlation IDs
  • Health checks
  • Prometheus
  • Grafana
  • Kafka metrics
  • Queue metrics
  • Database metrics

Phase 13 β€” Testing

  • Unit tests
  • Integration tests
  • Kafka tests
  • Repository tests
  • E2E tests
  • Failure scenario tests
  • Load testing

Phase 14 β€” Production

  • Dockerize all services
  • Production Docker Compose
  • Nginx
  • TLS
  • Secrets management
  • Database backups
  • Kafka persistence
  • Monitoring
  • Logging
  • Graceful deployment
  • CI/CD

🎯 Definition of Done

The project will be considered complete when this workflow works reliably:

User
 β”‚
 β”œβ”€β”€ Register
 β”‚
 β”œβ”€β”€ Login
 β”‚
 └── Create Order
          β”‚
          β–Ό
      API Gateway
          β”‚
          β–Ό
      Order Service
          β”‚
          β”œβ”€β”€ PostgreSQL Transaction
          β”‚      β”œβ”€β”€ Order
          β”‚      β”œβ”€β”€ Order Items
          β”‚      └── Outbox Event
          β”‚
          β–Ό
        Kafka
          β”‚
     β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β”
     β–Ό         β–Ό
 Payment    Inventory
 Service     Service
     β”‚         β”‚
     β–Ό         β–Ό
  Payment    Reserve
  Result     Stock
     β”‚         β”‚
     β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
          β–Ό
        Kafka
          β”‚
          β–Ό
    Order Service
          β”‚
          β–Ό
    Order Confirmed
          β”‚
          β–Ό
 Notification Service
          β”‚
          β–Ό
    BullMQ + Redis
          β”‚
          β–Ό
       Worker
          β”‚
          β–Ό
    Email / WebSocket

The system must also correctly handle:

Kafka failure
Database failure
Duplicate event
Consumer crash
Payment failure
Inventory failure
Notification failure
Worker failure

without corrupting business data.


πŸ† Main Engineering Principles

This project follows these principles:

1. Each service owns its data.

2. Never share business databases between services.

3. Use Kafka for asynchronous domain events.

4. Use REST only when synchronous communication is actually required.

5. Use Transactional Outbox for reliable event publishing.

6. Consumers must be idempotent.

7. Expect failures.

8. Use retries for transient failures.

9. Use DLQ for unrecoverable events.

10. Business logic should not depend directly on infrastructure.

11. Keep API Gateway thin.

12. Prefer eventual consistency over distributed transactions.

13. Keep shared libraries truly generic.

14. Do not create abstractions without a real reason.

15. Optimize for correctness before performance.

πŸ“š Project Learning Order

Recommended order for learning this project:

NestJS
  ↓
PostgreSQL + Prisma
  ↓
Clean Architecture
  ↓
SOLID
  ↓
Microservices
  ↓
Kafka Basics
  ↓
Kafka Producer / Consumer
  ↓
Event Design
  ↓
Transactional Outbox
  ↓
Idempotency
  ↓
Eventual Consistency
  ↓
Redis
  ↓
BullMQ
  ↓
Retry + DLQ
  ↓
Observability
  ↓
Docker
  ↓
Production Deployment

πŸ“Œ Final Project Objective

This project is not intended to be a simple CRUD application.

The primary objective is to understand how a production backend behaves when:

multiple services
        +
multiple databases
        +
asynchronous events
        +
network failures
        +
duplicate messages
        +
background processing
        +
eventual consistency

are combined into one system.

The final result should demonstrate practical knowledge of NestJS microservices, Kafka, PostgreSQL transactions, Transactional Outbox, Redis, BullMQ, SOLID, Clean Architecture, and distributed-system reliability patterns.


πŸ“„ License

This project is created for learning, experimentation, and portfolio purposes.

About

A scalable, event-driven order processing system built using modern architecture patterns. Designed to handle asynchronous workflows, reliable message brokering, and seamless order lifecycle management.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages