DEV Community

Dev Cookies
Dev Cookies

Posted on

Spring Boot DDD E-Commerce Order Management System - Detailed Walkthrough

๐Ÿ—๏ธ Project Architecture Overview

This project implements a complete e-commerce order management system using Domain-Driven Design (DDD) principles with Spring Boot. The architecture follows the classic DDD layered approach with clear separation of concerns.

๐Ÿ“‚ Project Structure

src/main/java/com/ecommerce/
โ”œโ”€โ”€ ECommerceApplication.java          # Main Spring Boot application
โ”œโ”€โ”€ shared/                            # Shared kernel across domains
โ”‚   โ”œโ”€โ”€ domain/                        # Base domain abstractions
โ”‚   โ”œโ”€โ”€ infrastructure/                # Cross-cutting infrastructure
โ”‚   โ””โ”€โ”€ application/                   # Base application interfaces
โ”œโ”€โ”€ customer/                          # Customer bounded context
โ”œโ”€โ”€ product/                           # Product bounded context
โ”œโ”€โ”€ order/                             # Order bounded context (main focus)
โ””โ”€โ”€ web/                              # Web/REST layer
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ Core DDD Concepts Implemented

1. Bounded Contexts

The system is divided into three main bounded contexts:

  • Customer Context: User management and authentication concerns
  • Product Context: Inventory and catalog management
  • Order Context: Order processing and fulfillment (primary context)

2. Aggregate Roots

Each context has its own aggregate root that maintains consistency:

  • Customer - manages customer data and behavior
  • Product - handles product lifecycle and inventory
  • Order - orchestrates order creation and status management

3. Value Objects

Immutable objects that represent concepts without identity:

  • Email - with built-in validation
  • Money - with currency support and arithmetic operations
  • CustomerId, ProductId, OrderId - strongly-typed identifiers

๐Ÿ” Deep Dive into Each Layer

Shared Domain Layer

The foundation that provides common abstractions:

Base Classes:

  • Entity<T>: Base class for domain entities with identity
  • ValueObject: Abstract base for value objects
  • AggregateRoot<T>: Extends Entity and manages domain events
  • DomainEvent: Base for all domain events with timestamp

Key Features:

  • Identity Management: Proper equals/hashCode based on ID
  • Domain Events: Event sourcing capabilities for cross-aggregate communication
  • Event Publishing: Infrastructure abstraction for event handling

Customer Domain

Core Components:

// Strong-typed identifier
CustomerId customerId = CustomerId.generate();

// Validated email value object
Email email = Email.of("john@example.com"); // Throws if invalid

// Domain entity with business logic
Customer customer = Customer.create("John Doe", email);
customer.updateEmail(Email.of("newemail@example.com"));
Enter fullscreen mode Exit fullscreen mode

Business Rules Enforced:

  • Email format validation using regex
  • Immutable value objects prevent invalid state
  • Factory methods ensure proper object creation

Product Domain

Sophisticated Money Handling:

// Type-safe money operations
Money price = Money.usd(new BigDecimal("99.99"));
Money total = price.multiply(5); // $499.95
Money combined = price.add(otherPrice); // Same currency required
Enter fullscreen mode Exit fullscreen mode

Inventory Management:

Product laptop = Product.create("Laptop", "Gaming laptop", 
                               Money.usd(new BigDecimal("1299.99")), 10);

// Business logic encapsulated in domain
if (laptop.isAvailable(3)) {
    laptop.reduceStock(3); // Atomic operation with validation
}
Enter fullscreen mode Exit fullscreen mode

Order Domain - The Heart of the System

This is the most complex aggregate, demonstrating advanced DDD patterns:

Order Aggregate Structure:

Order order = Order.create(customerId);
order.addItem(new OrderItem(productId, "Laptop", price, 2));
order.confirm(); // State transition with business rules
Enter fullscreen mode Exit fullscreen mode

Advanced Features:

  • State Management: Orders have well-defined states (PENDING โ†’ CONFIRMED โ†’ SHIPPED โ†’ DELIVERED)
  • Business Invariants: Cannot modify confirmed orders, cannot confirm empty orders
  • Aggregate Consistency: All order items are managed within the order boundary
  • Domain Events: Publishes OrderCreatedEvent for downstream processing

Order Item Value Object:

OrderItem item = new OrderItem(productId, "Laptop", unitPrice, quantity);
Money itemTotal = item.getTotalPrice(); // quantity * unitPrice
Enter fullscreen mode Exit fullscreen mode

๐Ÿ”„ Application Layer - Use Cases and Orchestration

CreateOrderUseCase - Complex Business Process:

This use case demonstrates sophisticated orchestration:

@Transactional
public Order execute(CreateOrderRequest request) {
    // 1. Validate customer exists
    Customer customer = customerRepository.findById(customerId)
        .orElseThrow(() -> new IllegalArgumentException("Customer not found"));

    // 2. Create order aggregate
    Order order = Order.create(customerId);

    // 3. Process each item with validation
    for (OrderItemRequest itemRequest : request.getItems()) {
        Product product = productRepository.findById(productId)
            .orElseThrow(() -> new IllegalArgumentException("Product not found"));

        // 4. Check availability (business rule)
        if (!product.isAvailable(quantity)) {
            throw new IllegalStateException("Insufficient stock");
        }

        // 5. Add to order and update inventory atomically
        order.addItem(new OrderItem(productId, product.getName(), 
                                   product.getPrice(), quantity));
        product.reduceStock(quantity);
        productRepository.save(product);
    }

    // 6. Confirm order (triggers state transition)
    order.confirm();
    Order savedOrder = orderRepository.save(order);

    // 7. Publish domain events for downstream processing
    savedOrder.getDomainEvents().forEach(eventPublisher::publish);
    savedOrder.clearDomainEvents();

    return savedOrder;
}
Enter fullscreen mode Exit fullscreen mode

Key Patterns Demonstrated:

  • Transaction Boundaries: Entire use case is transactional
  • Domain Event Publishing: Decoupled communication
  • Error Handling: Domain-specific exceptions
  • Aggregate Coordination: Multiple aggregates working together

๐Ÿ—„๏ธ Infrastructure Layer - Persistence & Implementation

Repository Pattern Implementation

Clean separation between domain and infrastructure:

Domain Interface (in domain layer):

public interface OrderRepository {
    Order save(Order order);
    Optional<Order> findById(OrderId id);
    List<Order> findByCustomerId(CustomerId customerId);
}
Enter fullscreen mode Exit fullscreen mode

Infrastructure Implementation:

The repository implementation handles the complex object-relational mapping:

@Repository
public class OrderRepositoryImpl implements OrderRepository {
    // Converts between domain objects and JPA entities
    private Order toDomain(OrderEntity entity) {
        List<OrderItem> items = entity.getItems().stream()
            .map(itemEntity -> new OrderItem(
                ProductId.of(itemEntity.getProductId()),
                itemEntity.getProductName(),
                Money.of(itemEntity.getUnitPrice(), itemEntity.getCurrency()),
                itemEntity.getQuantity()
            ))
            .collect(Collectors.toList());

        return Order.restore(OrderId.of(entity.getId()),
                           CustomerId.of(entity.getCustomerId()),
                           items, entity.getStatus(), entity.getOrderDate());
    }
}
Enter fullscreen mode Exit fullscreen mode

JPA Entity Mapping

Sophisticated mapping that preserves domain model integrity:

  • OrderEntity: Main aggregate root entity
  • OrderItemEntity: Child entities with proper cascade relationships
  • Value Object Flattening: Money mapped to separate amount/currency columns
  • Enum Mapping: OrderStatus stored as string for readability

๐ŸŒ Web Layer - REST API Design

RESTful Design Principles:

  • Resource-based URLs: /api/orders, /api/customers, /api/products
  • HTTP Status Codes: 201 for creation, 404 for not found, 400 for bad requests
  • Content Negotiation: JSON request/response bodies
  • Error Handling: Consistent error responses

Order Controller Example:

@PostMapping
public ResponseEntity<OrderResponse> createOrder(@RequestBody CreateOrderRequest request) {
    try {
        Order order = createOrderUseCase.execute(request);
        return ResponseEntity.status(HttpStatus.CREATED)
                           .body(OrderResponse.from(order));
    } catch (IllegalArgumentException | IllegalStateException e) {
        return ResponseEntity.badRequest().build();
    }
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿงช Testing Strategy

Domain-Driven Testing:

The project includes comprehensive unit tests focusing on business logic:

@Test
void shouldNotConfirmEmptyOrder() {
    Order order = Order.create(CustomerId.generate());
    assertThrows(IllegalStateException.class, order::confirm);
}

@Test
void shouldCalculateTotalAmount() {
    Order order = Order.create(CustomerId.generate());
    order.addItem(new OrderItem(productId, "Product", Money.usd(99.99), 2));

    Money total = order.getTotalAmount();
    assertEquals(new BigDecimal("199.98"), total.getAmount());
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿš€ Running the Application

Development Setup:

  1. Database: H2 in-memory database for rapid development
  2. Sample Data: Pre-loaded customers and products via data.sql
  3. H2 Console: Available at /h2-console for database inspection
  4. API Documentation: RESTful endpoints with clear request/response formats

Configuration Highlights:

spring:
  datasource:
    url: jdbc:h2:mem:testdb
  jpa:
    hibernate:
      ddl-auto: create-drop
    show-sql: true
  h2:
    console:
      enabled: true
Enter fullscreen mode Exit fullscreen mode

๐Ÿ“Š Business Scenarios Supported

Complete Order Flow:

  1. Customer Registration: Create customer with validated email
  2. Product Catalog: Browse available products with pricing
  3. Cart Management: Add multiple items to order
  4. Inventory Check: Real-time stock validation
  5. Order Confirmation: Atomic order processing with inventory updates
  6. Event Publishing: Downstream notifications for fulfillment

Sample API Usage:

# Create customer
POST /api/customers
{
    "name": "John Doe",
    "email": "john@example.com"
}

# Create order with multiple items
POST /api/orders
{
    "customerId": "cust-001",
    "items": [
        {"productId": "prod-001", "quantity": 1},
        {"productId": "prod-002", "quantity": 2}
    ]
}
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ DDD Benefits Demonstrated

1. Ubiquitous Language:

  • Domain experts can read and understand the code
  • Business terminology used throughout (Order, Customer, Product, not generic entities)

2. Business Logic Encapsulation:

  • Rules like "cannot modify confirmed orders" are enforced by the domain model
  • Calculations like order totals are handled by the appropriate aggregates

3. Bounded Context Isolation:

  • Customer logic is separate from order logic
  • Each context can evolve independently

4. Domain Events for Integration:

  • Loose coupling between contexts
  • Eventual consistency through event-driven architecture

5. Rich Domain Model:

  • Objects have behavior, not just data
  • Business invariants are maintained automatically

๐Ÿ”ฎ Extension Points

This architecture supports easy extension:

  • New Bounded Contexts: Payment, Shipping, Inventory
  • Additional Aggregates: ShoppingCart, Wishlist, Review
  • Event Sourcing: Complete audit trail of domain events
  • CQRS: Separate read/write models for complex queries
  • Integration Events: External system notifications

๐Ÿ“ˆ Production Considerations

For production deployment, consider:

  • Database: Replace H2 with PostgreSQL/MySQL
  • Caching: Redis for frequently accessed data
  • Message Queues: RabbitMQ/Apache Kafka for event processing
  • Security: Spring Security for authentication/authorization
  • Monitoring: Actuator endpoints for health checks
  • API Documentation: Swagger/OpenAPI specification

This project serves as a solid foundation for a production e-commerce system while demonstrating sophisticated DDD implementation patterns.

Top comments (0)