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
The Cartonization bounded context encompasses all aspects of determining optimal packaging solutions for shipments.
Responsibilities (Whatβs IN):
External Dependencies (Whatβs OUT):
Core Domain Terms:
Strategic Importance: HIGH - Core competitive differentiator
This is the heart of the cartonization service and provides significant business value through:
Subdomains:
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:
PackingSolutionCalculatedEventSolutionValidatedEventSolutionAppliedEventDescription: 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:
CartonTypeCreatedEventCartonTypeUpdatedEventCartonTypeDeprecatedEventDescription: 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();
}
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;
}
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);
}
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;
}
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.
}
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);
}
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:
FirstFitDecreasingAlgorithmBestFitAlgorithmGeneticAlgorithm (future)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:
MinimumCostStrategy - Lowest cost cartonMinimumSizeStrategy - Smallest viable cartonMinimumWasteStrategy - Best utilizationWeightOptimizedStrategy - Optimize for carrier weight brackets1
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);
}
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);
}
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
}
}
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);
}
Optimize packaging and cartonization for shipments to minimize costs, reduce waste, and maximize efficiency in the fulfillment process.
Order Management Service
FulfillmentOrderValidatedEventProduct Catalog Service
Warehouse Operations Service
PackingSolutionCalculatedEventOrder Management Service
PackingSolutionCalculatedEventTo 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());
}
}
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"
}
}
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
}
}
}
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).