What is CloudMart?

CloudMart is a robust, highly scalable microservices architecture built to demonstrate modern backend engineering. It splits traditional monolithic e-commerce features (Auth, Cart, Orders, Payments, Inventory) into 9 independent Node.js services.

By leveraging an event-driven Pub/Sub model via RabbitMQ, the system guarantees resilience. For instance, if the Notification Service goes down, the Payment and Order services continue operating flawlessly, and emails are simply processed later when the service recovers.

Core Technologies

  • Backend: Node.js, Express.js
  • Frontend: React, Vite
  • Databases: PostgreSQL (relational data), Redis (caching/carts)
  • Message Broker: RabbitMQ (AMQP)
  • Infrastructure: Docker, Kubernetes (Azure AKS), Terraform, Azure Container Registry

The Engineering Team

Building 9 microservices simultaneously requires intense coordination. To prevent bottlenecks, CloudMart is being built via Contract-First Development by two lead engineers:

Nischal Khanal

Leads Operations, Orchestration, and Infrastructure. Owns the API Gateway, Order Saga Orchestrator, Inventory Management, and Analytics.

Gajananda Mani Adhikari

Leads Data, Users, Finance, and UI. Owns Auth, Product Catalog, Redis Carts, Stripe Payments, and Notifications.

By locking down the API Contracts (visible in the sidebar), Nischal and Gajananda can build their services locally, mock out external dependencies, and integrate flawlessly via Docker Compose on day one.

Strategy: Contract-First Development. Lock the API request/response contracts below, then use mocks to simulate other team members' services while building your own.

RabbitMQ Event Architecture Explained

The Fanout Exchange & Dedicated Queues

CloudMart uses a Pub-Sub pattern using RabbitMQ Exchanges. A single event (like OrderCreatedEvent) is published to the cloudmart.events exchange.

CRITICAL CONCEPT: Independent Consumers
A common misconception is that multiple services consume from one shared queue, stealing messages from each other. That is wrong.

In CloudMart, every service creates its own dedicated queue and binds it to the exchange. For example, when OrderCreatedEvent is published:

  1. The Exchange duplicates the message.
  2. One copy goes to queue.payment
  3. One copy goes to queue.notification
  4. One copy goes to queue.analytics

This allows Payment Service, Notification Service, and Analytics Service to ALL process the exact same order simultaneously, without affecting each other. If Notification crashes, Payment and Analytics continue normally. When Notification reboots, its queue is waiting with the backlog.

All Event Contracts

Defined centrally in packages/shared-contracts.

1. OrderCreatedEvent

{
  "eventType": "OrderCreatedEvent",
  "eventId": "evt-a1b2c3",
  "timestamp": "2026-07-21T10:00:00Z",
  "payload": {
    "orderId": "ord-556677",
    "userId": "user-abc123",
    "email": "nischal@cloudmart.dev",
    "totalAmount": 59.98,
    "items": [{ "productId": "prod-001", "quantity": 2, "price": 29.99 }],
    "shippingAddress": { "city": "Kathmandu", "country": "Nepal" },
    "paymentMethodId": "pm_1234"
  }
}

2. PaymentSuccessEvent

{
  "eventType": "PaymentSuccessEvent",
  "eventId": "evt-b2c3d4",
  "timestamp": "2026-07-21T10:01:00Z",
  "payload": {
    "orderId": "ord-556677",
    "paymentIntentId": "pi_123abc",
    "amountCharged": 5998
  }
}

3. PaymentFailedEvent

{
  "eventType": "PaymentFailedEvent",
  "eventId": "evt-c3d4e5",
  "timestamp": "2026-07-21T10:01:00Z",
  "payload": {
    "orderId": "ord-556677",
    "reason": "card_declined"
  }
}

4. UserRegisteredEvent

{
  "eventType": "UserRegisteredEvent",
  "eventId": "evt-d4e5f6",
  "timestamp": "2026-07-21T09:30:00Z",
  "payload": {
    "userId": "user-abc123",
    "email": "nischal@cloudmart.dev",
    "firstName": "Nischal"
  }
}

The gateway routes based on URL paths:

  • /api/auth/* → Auth Service (3002)
  • /api/products/* → Product Service (3003)
  • /api/cart/* → Cart Service (3004)
  • /api/orders/* → Order Service (3005)
  • /api/payments/* → Payment Service (3006)
  • /api/inventory/* → Inventory Service (3007)
POST/api/auth/register
Bodyemail *, password *, firstName *, lastName *
Response 201Returns JWT token and user info.
{
  "id": "usr-123",
  "email": "user@example.com",
  "firstName": "John",
  "token": "eyJhbG..."
}
POST/api/auth/login
Bodyemail *, password *
Response 200Returns JWT token.
{
  "token": "eyJhbG...",
  "expiresIn": 3600
}
GET/api/auth/profile
HeadersAuthorization: Bearer <token> *
Response 200Current logged in user profile.
{
  "id": "usr-123",
  "email": "user@example.com",
  "firstName": "John",
  "lastName": "Doe"
}
GET/api/products
Querycategory (string), page (number), limit (number)
Response 200List of products.
{
  "total": 3,
  "items": [
    {
      "id": "prod-001",
      "name": "Wireless Mouse",
      "price": 29.99,
      "stock": 150
    }
  ]
}
GET/api/products/:id
Paramsid *
Response 200Single product.
{
  "id": "prod-001",
  "name": "Wireless Mouse",
  "price": 29.99,
  "stock": 150
}
POST/api/products
HeadersAuthorization: Bearer <admin_token> *
Bodyname *, price *, description, categoryId *
Response 201Created product object.
PUT/api/products/:id
HeadersAuthorization: Bearer <admin_token> *
BodyAny product fields to update.
Response 200Updated product object.
DEL/api/products/:id
HeadersAuthorization: Bearer <admin_token> *
Response 204No content.
GET/api/cart
HeadersAuthorization: Bearer <token> *
Response 200Current user's cart.
{
  "cartId": "cart-user123",
  "totalAmount": 59.98,
  "items": [
    { "productId": "prod-001", "quantity": 2, "price": 29.99 }
  ]
}
POST/api/cart/items
HeadersAuthorization: Bearer <token> *
BodyproductId *, quantity *
Response 200Updated cart with new total.
DEL/api/cart/items/:productId
HeadersAuthorization: Bearer <token> *
Response 204Item removed.
DEL/api/cart
HeadersAuthorization: Bearer <token> *
Response 204Cart cleared entirely.
POST/api/orders
HeadersAuthorization: Bearer <token> *
BodycartId *, shippingAddressId *, paymentMethodId *
Response 201Pending order creation. Publishes OrderCreatedEvent.
{
  "orderId": "ord-9876",
  "status": "PENDING_PAYMENT",
  "totalAmount": 59.98,
  "createdAt": "2026-07-21T10:15:00Z"
}
GET/api/orders
HeadersAuthorization: Bearer <token> *
Response 200List of orders for current user.
GET/api/orders/:id
HeadersAuthorization: Bearer <token> *
Response 200Detailed order state including items and payment status.
POST/api/payments/intent
HeadersAuthorization: Bearer <token> *
BodyorderId *, amount *
Response 201Returns a Stripe client secret for frontend checkout.
{
  "clientSecret": "pi_123_secret_456"
}
POST/api/payments/webhook
HeadersStripe-Signature *
BodyStripe raw payload
Response 200{ "received": true } - Publishes PaymentSuccessEvent.
GET/api/inventory/:productId
Response 200Current stock levels.
{
  "productId": "prod-001",
  "availableStock": 150,
  "reservedStock": 0,
  "totalStock": 150
}
POST/api/inventory/reserve
BodyorderId *, items: [{ productId, quantity }] *
Response 200Success or 422 if stock insufficient.
{
  "success": true,
  "reservationId": "res-1234",
  "reservedUntil": "2026-07-21T10:30:00Z"
}
POST/api/inventory/release
BodyreservationId *
Response 200Releases reserved stock back to available pool (e.g. if payment fails).
GET/api/notifications/preferences
HeadersAuthorization: Bearer <token> *
Response 200User notification preferences.
{
  "emailMarketing": true,
  "orderUpdates": true,
  "smsAlerts": false
}
PUT/api/notifications/preferences
HeadersAuthorization: Bearer <token> *
BodyemailMarketing, orderUpdates, smsAlerts
Response 200Updated preferences.
GET/api/analytics/dashboard
HeadersAuthorization: Bearer <admin_token> *
Querytimeframe (day, week, month)
Response 200Aggregated metrics.
{
  "totalRevenue": 45290.50,
  "ordersCount": 1240,
  "topProducts": [
    { "productId": "prod-001", "sales": 300 }
  ]
}