Platform case study

BaruqMulti-Vendor Marketplace

A production-oriented multi-vendor marketplace platform designed around microservices, event-driven architecture, centralized identity, and containerized infrastructure.

ASP.NET CoreRabbitMQMassTransitgRPCSQL ServerDockerTraefikDuendeNext.jsPWA

Architecture · Backend · Identity · Infrastructure

A system, not a collection of services.

A closer look at the engineering decisions, service boundaries and operational concerns behind the platform. This study describes architecture, without claiming user counts, revenue or unprovided performance metrics.

DISTRIBUTED BY DESIGN
01
Web
PWA
Client
API GatewayOne entry point. Clear boundaries.
HTTPS
02
Identity.NET
Product.NET
Order.NET
RabbitMQ·MassTransitgRPC
03
Identity DB
Product DB
Order DB
Architecture schematic · not live telemetry

01

Overview

Baruq is a multi-vendor marketplace with web and PWA clients. Its engineering concerns span products, sellers, baskets, orders, payment, shipping and identity. The case study focuses on how these responsibilities connect while retaining clear ownership.

02

Architecture

Microservices own their data through a database-per-service approach. Clients enter through an API Gateway rather than coupling directly to every internal service. Service boundaries should reflect business capabilities, with explicit APIs and messages between them.

03

Authentication & Authorization

Centralized identity uses Duende and the OAuth 2.0 / OpenID Connect model. JWT validation protects API access; API scopes describe access boundaries, while authorization checks decide which operations a caller can perform. PKCE protects the authorization-code exchange for public clients.

04

Messaging

RabbitMQ and MassTransit support event-driven communication. Events communicate changes between service boundaries. An event consumer needs to handle duplicate delivery and failure explicitly; messaging is a reliability concern as well as a transport choice.

05

Service Communication

gRPC supports explicit synchronous service contracts where a response is needed in the current operation. Asynchronous messaging serves work that can proceed independently. The choice depends on consistency needs, latency and what should happen when the other service is unavailable.

06

Product & Seller Architecture

Product maintains a local SupplierReadModel instead of reading the Seller database directly. This keeps Seller data ownership intact and lets Product answer its own queries. The local model is a projection of the seller information Product needs, rather than a second source of truth.

Seller↓ Event ↓SupplierReadModel↓ Local query ↓Product

07

Payment

The payment boundary separates order intent from gateway interaction. Checkout needs to retain order identity through retries and callbacks. A redirect alone is not evidence of payment: the application must use server-verified payment state.

08

Shipping

Shipping connects address information, seller ownership and the order workflow. Quotes and selected delivery methods need explicit identifiers so a checkout can be validated against the services responsible for those decisions.

09

Infrastructure

Docker packages application services for Linux environments. Traefik provides reverse-proxy routing and participates in the TLS termination path. DNS, certificates and forwarding configuration must align with application endpoints and authentication redirect URLs.

10

Engineering Challenges

The interesting problems live between boundaries: preserving product and variant identity, keeping seller data decoupled, distinguishing synchronous failure from delayed events, and tracing identity or deployment problems across the request path. Each requires explicit contracts and end-to-end validation.

Engineering Notes

Contact

Have a difficult .NET problem?

Need help with a microservices architecture, production issue, authentication problem, or distributed system?

Let’s Talk