Overview
Modular Mart is a highly scalable, multi-vendor e-commerce platform. It evolved from a single-vendor monolithic structure into a fully distributed microservices architecture to support growing traffic and vendor requirements.
Key focus areas:
- Domain Isolation: Dedicated services for Users, Catalog, Orders, Payments, and Notifications.
- Event-Driven Choreography: Asynchronous saga patterns for complex workflows like checkout.
- Deep Observability: Comprehensive tracing, logging, and metrics using the LGTM stack.
System Architecture & Infrastructure Topology
Explore the distributed microservices architecture: Kong Gateway, 5 isolated domain services with dedicated PostgreSQL databases, RabbitMQ event bus, and the LGTM observability stack.
Checkout Saga Orchestration
Visualizing the distributed transaction flow. This choreography ensures inventory is reserved before payment is processed, with built-in failure compensation.
Observability Architecture
How telemetry data is aggregated from services and pushed to the LGTM stack for professional visualization and debugging.
Domain & Bounded Contexts
Illustrating business boundaries and service ownership based on Domain-Driven Design principles.
Key Architectural Decisions
Why RabbitMQ?
We chose RabbitMQ to implement asynchronous, event-driven communication. This decouples services, allowing the system to remain responsive even if some downstream services (like Notifications) are temporarily unavailable. It also enables the Choreographed Saga pattern for reliable distributed transactions.
Why Database-per-Service?
Each microservice owns its own PostgreSQL database. This ensures strong service ownership and autonomy, prevents accidental coupling through shared tables, and allows each service to scale its persistence layer independently based on its specific load profile.
Why Choreographed Saga?
To manage distributed transactions (like Checkout) without the complexity of a central orchestrator or the overhead of distributed locks. Services listen for events and react accordingly, including executing compensating transactions to maintain eventual consistency if a step fails.
Why Kong Gateway?
Kong acts as our centralized entry point, handling cross-cutting concerns like JWT validation (via Clerk), rate limiting, and request routing. This keeps our service logic clean and focused solely on business domains.
Trade-offs
Pros
- Independent Deployment: Each service can be updated and scaled without affecting the rest of the system.
- Scalability: High-traffic domains like Catalog can be scaled independently of low-traffic ones like Payments.
- Fault Isolation: A failure in the Notification service does not prevent a user from placing an order.
Cons
- Eventual Consistency: The system must handle temporary inconsistencies during cross-service workflows.
- Operational Complexity: Managing multiple services, databases, and a message broker requires robust DevOps and automation.
- Observability Overhead: Distributed tracing is mandatory to understand requests that span multiple service boundaries.
Impact & Results
Features
Technical Challenges
API Reference
All traffic enters through Kong Gateway (JWT via Clerk, rate limiting, routing) and fans out to domain services. Event names are the versioned contracts from @modular-mart/contracts (EVENT_PATTERNS).
Domain Events
The checkout saga and cross-service fan-out run on RabbitMQ. Consumers are idempotent (processed_messages table) with dead-letter routing on repeated failure.
Resiliency & Reliability
Lessons Learned
- Distributed Systems: Managing eventual consistency and saga coordination across service boundaries.
- Infrastructure as Code: Orchestrating complex environments with Docker and Turborepo.
- Observability: The critical importance of centralized logging and distributed tracing for debugging microservices.
- Idempotency: Designing resilient event handlers that safely process duplicate messages.
Screenshots
Liked this project?
Check out more of my work or get in touch.