Cartonization Service - Domain Architecture & Business Capabilities

Service Overview

The Cartonization Service is a critical component of the PakLog fulfillment ecosystem, responsible for optimizing shipment packaging through advanced 3D bin-packing algorithms. It minimizes shipping costs, reduces material waste, and ensures optimal space utilization.

Architecture Pattern: Hexagonal Architecture (Ports & Adapters) Technology Stack: Spring Boot 3.2, MongoDB, Apache Kafka, Redis Integration Pattern: Event-Driven Architecture with CloudEvents


Domain Model & Bounded Context

Bounded Context: Cartonization

The Cartonization bounded context encompasses all aspects of determining optimal packaging solutions for shipments.

Context Boundaries

Responsibilities (What’s IN):

External Dependencies (What’s OUT):

Ubiquitous Language

Core Domain Terms:


Subdomain Classification

Core Domain: Packing Optimization

Strategic Importance: HIGH - Core competitive differentiator

This is the heart of the cartonization service and provides significant business value through:

Subdomains:

1. 3D Bin-Packing Computation (Core)

2. Carton Catalog Management (Supporting)

3. Performance Optimization (Supporting)


Domain Model

Aggregates

1. PackingSolution (Aggregate Root)

Description: Represents the complete solution for packing a set of items, including all selected cartons and item placements.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@AggregateRoot
public class PackingSolution {
    private String solutionId;
    private String orderId;
    private List<CartonAssignment> cartonAssignments;
    private UtilizationMetrics utilizationMetrics;
    private BigDecimal totalCost;
    private SolutionStatus status;
    private LocalDateTime calculatedAt;

    // Business methods
    public void addCartonAssignment(CartonAssignment assignment);
    public BigDecimal calculateTotalCost();
    public double calculateAverageUtilization();
    public boolean meetsBusinessRules();
}

Invariants:

Domain Events:


2. Carton (Aggregate Root)

Description: Represents a carton type available for packing with specifications and constraints.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@AggregateRoot
public class Carton {
    private String cartonTypeId;
    private String name;
    private Dimensions internalDimensions;
    private Dimensions externalDimensions;
    private Weight maxWeight;
    private BigDecimal cost;
    private CartonAttributes attributes;
    private boolean active;

    // Business methods
    public boolean canAccommodate(List<Item> items);
    public double calculateUtilization(List<Item> items);
    public boolean isHeavyDuty();
    public boolean supportsFragileItems();
}

Invariants:

Domain Events:


Entities

CartonAssignment

Description: Represents the assignment of items to a specific carton within a packing solution.

1
2
3
4
5
6
7
8
9
10
11
12
@Entity
public class CartonAssignment {
    private String assignmentId;
    private String cartonTypeId;
    private List<ItemPlacement> itemPlacements;
    private double utilizationPercentage;
    private BigDecimal cartonCost;

    public void addItemPlacement(ItemPlacement placement);
    public boolean hasCapacityFor(Item item);
    public Volume remainingVolume();
}

ItemPlacement

Description: Represents the specific placement of an item within a carton.

1
2
3
4
5
6
7
8
@Entity
public class ItemPlacement {
    private String sku;
    private int quantity;
    private Position position; // 3D coordinates
    private Orientation orientation; // rotation
    private Volume occupiedVolume;
}

Value Objects

Dimensions

1
2
3
4
5
6
7
8
9
10
11
@ValueObject
public class Dimensions {
    private BigDecimal length;
    private BigDecimal width;
    private BigDecimal height;
    private DimensionUnit unit;

    public Volume calculateVolume();
    public boolean fitsWithin(Dimensions container);
    public DimensionalWeight calculateDimensionalWeight(int dimFactor);
}

UtilizationMetrics

1
2
3
4
5
6
7
8
@ValueObject
public class UtilizationMetrics {
    private double spaceUtilization; // percentage
    private double weightUtilization; // percentage
    private int numberOfCartons;
    private BigDecimal totalCost;
    private BigDecimal costPerItem;
}

CartonAttributes

1
2
3
4
5
6
7
8
@ValueObject
public class CartonAttributes {
    private boolean heavyDuty;
    private boolean fragileApproved;
    private boolean hazmatApproved;
    private boolean insulated;
    private String material; // cardboard, plastic, etc.
}

Domain Services

PackingSolutionService

Responsibility: Orchestrate the calculation of optimal packing solutions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@DomainService
public class PackingSolutionService {

    public PackingSolution calculateOptimalSolution(
        List<Item> items,
        List<Carton> availableCartons,
        PackingConstraints constraints
    );

    public PackingSolution calculateMultiCartonSolution(
        List<Item> items,
        List<Carton> availableCartons
    );

    public void validateSolution(PackingSolution solution);
}

BinPackingAlgorithm

Responsibility: Core 3D bin-packing algorithm implementation.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@DomainService
public interface BinPackingAlgorithm {

    PackingResult packItems(
        List<Item> items,
        Carton carton,
        PackingStrategy strategy
    );

    List<ItemPlacement> optimizePlacements(
        List<Item> items,
        Dimensions containerDimensions
    );
}

Implementations:


CartonSelectionStrategy

Responsibility: Select the most appropriate carton based on business rules.

1
2
3
4
5
6
7
8
9
@DomainService
public interface CartonSelectionStrategy {

    Carton selectOptimalCarton(
        List<Item> items,
        List<Carton> candidates,
        SelectionCriteria criteria
    );
}

Strategies:


Application Layer

Ports (Interfaces)

Input Ports (Use Cases)

1
2
3
4
5
6
7
8
9
10
11
12
// Commands
public interface CalculatePackingSolutionCommand {
    PackingSolution execute(CalculatePackingRequest request);
}

public interface CreateCartonCommand {
    Carton execute(CreateCartonRequest request);
}

public interface UpdateCartonCommand {
    Carton execute(UpdateCartonRequest request);
}

Output Ports (Dependencies)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Repository ports
public interface CartonRepository {
    Optional<Carton> findById(String cartonTypeId);
    List<Carton> findAllActive();
    void save(Carton carton);
}

public interface PackingSolutionRepository {
    Optional<PackingSolution> findById(String solutionId);
    void save(PackingSolution solution);
}

// External service ports
public interface ProductCatalogClient {
    ProductDimensions getProductDimensions(String sku);
    List<ProductDimensions> getProductDimensions(List<String> skus);
}

public interface EventPublisher {
    void publish(DomainEvent event);
}

Infrastructure Layer

Adapters

Inbound Adapters

REST Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
@RequestMapping("/api/v1/cartonization")
public class CartonizationController {

    @PostMapping("/calculate")
    public ResponseEntity<PackingSolutionResponse> calculatePacking(
        @RequestBody CalculatePackingRequest request
    );

    @GetMapping("/solutions/{solutionId}")
    public ResponseEntity<PackingSolutionResponse> getSolution(
        @PathVariable String solutionId
    );
}

Event Listener

1
2
3
4
5
6
7
8
@Component
public class OrderEventListener {

    @KafkaListener(topics = "fulfillment.order.v1.events")
    public void handleOrderValidated(FulfillmentOrderValidatedEvent event) {
        // Automatically calculate packing solution
    }
}

Outbound Adapters

MongoDB Adapter

1
2
3
4
@Repository
public class MongoCartonRepository implements CartonRepository {
    // Implementation using Spring Data MongoDB
}

Kafka Event Publisher

1
2
3
4
5
6
7
8
@Component
public class KafkaEventPublisher implements EventPublisher {

    @Override
    public void publish(DomainEvent event) {
        // Publish CloudEvents format to Kafka
    }
}

Product Catalog Client

1
2
3
4
5
6
7
8
@Component
public class RestProductCatalogClient implements ProductCatalogClient {

    @Override
    public ProductDimensions getProductDimensions(String sku) {
        // REST call to Product Catalog service
    }
}

Redis Cache Adapter

1
2
3
4
5
6
7
@Component
public class PackingSolutionCacheService {

    public Optional<PackingSolution> getCachedSolution(String cacheKey);
    public void cacheSolution(String cacheKey, PackingSolution solution);
    public void invalidate(String cacheKey);
}

Business Capabilities

L1: Shipment Optimization

Optimize packaging and cartonization for shipments to minimize costs, reduce waste, and maximize efficiency in the fulfillment process.


L2: Packing Solution Calculation

L3.1: 3D Bin-Packing Algorithm

L3.2: Multi-Carton Optimization

L3.3: Carton Selection Strategy

L3.4: Weight-Based Optimization

L3.5: Packing Solution Caching


L2: Carton Catalog Management

L3.6: Carton Type Registration

L3.7: Carton Specification Retrieval

L3.8: Carton Cost Management


L2: Event-Driven Integration

L3.9: Packing Solution Calculated Event

L3.10: Carton Catalog Change Events


L2: Performance & Scalability

L3.11: Asynchronous Processing

L3.12: Multi-Layer Caching

L3.13: Solution Pre-calculation


Integration Patterns

Upstream Integration (Consumers)

Order Management Service

Product Catalog Service

Downstream Integration (Producers)

Warehouse Operations Service

Order Management Service


Context Mapping

Relationship with Other Bounded Contexts

Product Catalog (Upstream - Customer/Supplier)

Order Management (Upstream - Published Language)

Warehouse Operations (Downstream - Customer/Supplier)

Shipment & Transportation (Downstream - Customer/Supplier)


Anti-Corruption Layer

Product Catalog Integration

To protect the Cartonization domain from changes in Product Catalog:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Component
public class ProductCatalogAntiCorruptionLayer {

    private final ProductCatalogClient client;
    private final ProductDimensionMapper mapper;

    public Dimensions getItemDimensions(String sku) {
        // Call external service
        ProductCatalogResponse response = client.getProduct(sku);

        // Map to our domain model
        return mapper.toDomainDimensions(response);
    }

    public List<Dimensions> getItemDimensions(List<String> skus) {
        // Batch retrieval with mapping
        List<ProductCatalogResponse> responses = client.getProducts(skus);
        return responses.stream()
            .map(mapper::toDomainDimensions)
            .collect(toList());
    }
}

Event Schemas

PackingSolutionCalculatedEvent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
  "specversion": "1.0",
  "type": "com.paklog.cartonization.solution.calculated",
  "source": "cartonization-service",
  "id": "solution-12345",
  "time": "2025-10-18T10:30:00Z",
  "datacontenttype": "application/json",
  "data": {
    "solutionId": "solution-12345",
    "orderId": "ORD-67890",
    "cartonAssignments": [
      {
        "cartonTypeId": "SMALL-BOX-001",
        "items": [
          {"sku": "PROD-123", "quantity": 2},
          {"sku": "PROD-456", "quantity": 1}
        ],
        "utilizationPercentage": 0.85,
        "cartonCost": 2.50
      }
    ],
    "totalCost": 2.50,
    "averageUtilization": 0.85,
    "calculatedAt": "2025-10-18T10:30:00Z"
  }
}

CartonTypeCreatedEvent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
  "specversion": "1.0",
  "type": "com.paklog.cartonization.carton.created",
  "source": "cartonization-service",
  "id": "carton-type-update-123",
  "time": "2025-10-18T10:30:00Z",
  "datacontenttype": "application/json",
  "data": {
    "cartonTypeId": "LARGE-BOX-002",
    "name": "Large Shipping Box",
    "internalDimensions": {
      "length": 40.0,
      "width": 30.0,
      "height": 20.0,
      "unit": "CM"
    },
    "maxWeight": {
      "value": 25.0,
      "unit": "KG"
    },
    "cost": 3.50,
    "attributes": {
      "heavyDuty": true,
      "fragileApproved": true,
      "hazmatApproved": false
    }
  }
}

Quality Attributes

Performance

Scalability

Reliability

Maintainability


Summary

The Cartonization Service is a well-defined bounded context within the PakLog ecosystem, focused on optimal packaging solutions. It demonstrates:

The service provides significant business value through cost reduction (15-30%), waste reduction (25-40%), and operational efficiency (sub-second calculations).