Skip to main content

Overview

The Product Distribution Dashboard provides two levels of metrics: global metrics for high-level overview and detailed metrics for in-depth analysis. All metrics are cached for performance and automatically invalidated when distribution runs.

Global Metrics

Global metrics provide a high-level snapshot of the entire distribution system:
@Cacheable("globalMetrics")
public GlobalMetricsDTO calculateGlobalMetrics() {
    logger.info("Calculating global metrics");
    
    try {
        MetricsRepository.GlobalMetricsProjection projection = metricsRepository.getGlobalMetrics();
        GlobalMetricsDTO result = metricsMapper.toGlobalMetricsDTO(projection);
        
        logger.info("Global metrics calculated: {} shipments, {} units, {} km average, {} unfulfilled units",
            result.totalShipments(), result.fulfilledUnits(), 
            result.averageDistance(), result.unfulfilledUnits());
        
        return result;
        
    } catch (Exception e) {
        logger.error("Error calculating global metrics", e);
        return createEmptyGlobalMetrics();
    }
}

Global Metrics Fields

totalShipments
long
Total number of stock assignments created across all warehouses and stores
fulfilledUnits
long
Total number of product units successfully shipped
unfulfilledUnits
long
Total number of product units that could not be fulfilled due to capacity or stock shortages
averageDistance
double
Average shipping distance in kilometers across all assignments

Detailed Metrics

Detailed metrics support filtering by warehouse, store, or product for granular analysis:
@Cacheable(value = "detailedMetrics", key = "#criteria.warehouseId + '_' + #criteria.storeId + '_' + #criteria.productId")
public DetailedMetricsDTO calculateDetailedMetrics(StockAssignmentCriteria criteria) {
    logger.info("Calculating detailed metrics");
    
    try {
        String warehouseId = criteria.getWarehouseId();
        String storeId = criteria.getStoreId();
        String productId = criteria.getProductId();
        
        MetricsRepository.DetailedMetricsProjection basicMetrics = metricsRepository.getDetailedMetrics(
            warehouseId, storeId, productId);
        Double fulfillmentRate = calculateFulfillmentRate(
            basicMetrics.getTotalFulfilled(), basicMetrics.getTotalUnfulfilled());
        StoresServedDTO storesServed = metricsMapper.toStoresServedDTO(basicMetrics);
        
        // ... additional metric calculations
        
        return new DetailedMetricsDTO(
            efficiencyScore,
            fulfillmentRate,
            basicMetrics.getTotalDistance(),
            basicMetrics.getTotalShipments(),
            storesServed,
            basicMetrics.getAvgShipmentSize(),
            basicMetrics.getUniqueProductsDistributed(),
            basicMetrics.getUniqueProductsRequested(),
            capacityUtilization,
            unfulfilledDemand,
            basicMetrics.getTotalFulfilled(),
            distanceStats,
            unitsByWarehouse,
            topProducts
        );
    } catch (Exception e) {
        logger.error("Error calculating detailed metrics", e);
        return createEmptyDetailedMetrics();
    }
}

Detailed Metrics Fields

efficiencyScore
integer
Composite score (0-100) calculated from fulfillment rate, distance, and capacity utilization
fulfillmentRate
double
Percentage of demand successfully fulfilled (0-100)
totalDistance
double
Total distance covered by all shipments in kilometers
totalShipments
long
Number of stock assignments matching the filter criteria
storesServed
StoresServedDTO
Information about store coverage
avgShipmentSize
double
Average number of units per shipment
uniqueProductsDistributed
integer
Number of distinct products actually shipped
uniqueProductsRequested
integer
Number of distinct products requested (including unfulfilled)

Capacity Utilization

Tracks how efficiently store capacity is being used:
capacityUtilization
CapacityUtilizationDTO
Store capacity usage metrics
High Capacity Utilization (>90%): May indicate need for additional store capacity or product variety adjustment. Low Capacity Utilization (<50%): May indicate overstocking, poor demand forecasting, or insufficient product variety.

Distance Statistics

Provides insights into shipping distances:
distanceStats
DistanceStatsDTO
Statistical breakdown of shipping distances
Weighted Average Distance:
private Double calculateWeightedAverageDistance(List<WarehouseUnitsDTO> unitsByWarehouse) {
    if (unitsByWarehouse == null || unitsByWarehouse.isEmpty()) {
        return 0.0;
    }
    
    double totalWeightedDistance = 0.0;
    long totalUnits = 0;
    
    for (WarehouseUnitsDTO warehouse : unitsByWarehouse) {
        totalWeightedDistance += warehouse.totalUnits() * warehouse.avgDistance();
        totalUnits += warehouse.totalUnits();
    }
    
    if (totalUnits == 0) return 0.0;
    return totalWeightedDistance / totalUnits;
}
Weighted by shipment volumes to reflect actual distribution costs more accurately.

Unfulfilled Demand Analysis

Tracks demand that could not be satisfied:
unfulfilledDemand
UnfulfilledDemandDTO
Breakdown of unfulfilled demand by reason
Analysis Guidelines:

Stock Shortage

High stock shortage indicates:
  • Need to increase warehouse inventory
  • Consider additional suppliers
  • Review demand forecasting

Capacity Shortage

High capacity shortage indicates:
  • Stores need more space
  • Adjust demand expectations
  • Stagger deliveries over time

Top Products Tracking

Identifies most distributed products:
topProducts
TopProductDTO[]
List of top products by volume (limited to top 10)
Useful for:
  • Identifying best-selling products
  • Planning warehouse stock levels
  • Optimizing warehouse product placement
  • Understanding distribution patterns

Units by Warehouse

Breaks down distribution by warehouse:
unitsByWarehouse
WarehouseUnitsDTO[]
Distribution metrics per warehouse
Helps identify:
  • Warehouse utilization balance
  • Geographic coverage effectiveness
  • Potential consolidation opportunities
  • Underutilized distribution centers

Caching Strategy

Metrics are cached to improve performance:
@Cacheable("globalMetrics")
@Cacheable(value = "detailedMetrics", key = "#criteria.warehouseId + '_' + #criteria.storeId + '_' + #criteria.productId")
Cache is automatically invalidated when distribution runs:
@CacheEvict(value = {"globalMetrics", "detailedMetrics"}, allEntries = true)
Cache Configuration:
spring.cache.type=simple
spring.cache.cache-names=globalMetrics,detailedMetrics

Using Metrics for Decision Making

  • Review avgDistance in unitsByWarehouse
  • High average distances suggest need for warehouses closer to stores
  • Compare totalUnits across warehouses to balance distribution load
  • Monitor fulfillmentRate and unfulfilledDemand
  • If dueToStockShortage is high, increase warehouse inventory
  • If dueToCapacityShortage is high, expand store capacity or adjust expectations
  • Track efficiencyScore over time
  • Score below 70 indicates problems with fulfillment, distance, or capacity
  • Focus improvements on the factor with lowest weighted contribution
  • Use capacityUtilization.percentage
  • Target 70-85% utilization for optimal balance
  • Review storesServed.withPartialFulfillment to identify problem stores

API Endpoints

Access metrics via REST API:
GET /api/metrics/global
Query Parameters:
  • warehouseId (optional): Filter by warehouse
  • storeId (optional): Filter by store
  • productId (optional): Filter by product
All filters are optional and can be combined.

Next Steps

Dashboard

View metrics in the interactive dashboard

Data Management

Learn about data sources and refresh cycles

Build docs developers (and LLMs) love