Low-Level Design: Warehouse Management System — Receiving, Put-Away, Picking, and Shipping

Core Entities

Warehouse: warehouse_id, name, address, total_locations, is_active. Location: location_id, warehouse_id, zone (RECEIVING, STORAGE, STAGING, SHIPPING), aisle, bay, level, bin, location_type (PALLET, SHELF, FLOOR, RACK), capacity_units, current_units, is_active. Product: product_id, sku, name, unit_weight_kg, unit_volume_cm3, storage_type (AMBIENT, REFRIGERATED, FROZEN, HAZMAT). LocationProduct: location_product_id, location_id, product_id, quantity, lot_number, expiry_date, received_at. InboundShipment: shipment_id, supplier_id, expected_arrival, status (SCHEDULED, ARRIVED, RECEIVING, RECEIVED), line_items (JSON: [{product_id, expected_qty}]). OutboundOrder: order_id, customer_id, status (PENDING, PICKING, PACKED, SHIPPED, DELIVERED), priority (STANDARD, EXPRESS, SAME_DAY), shipping_address. PickTask: task_id, order_id, picker_id, location_id, product_id, quantity, status (ASSIGNED, IN_PROGRESS, COMPLETED, EXCEPTION), assigned_at, completed_at. WorkerTask: worker_id, task_id, task_type (RECEIVE, PUTAWAY, PICK, PACK, SHIP), started_at, completed_at.

Receiving and Put-Away

Inbound flow: (1) Truck arrives at the receiving dock. (2) Worker scans InboundShipment barcode → system opens the shipment for receiving. (3) Worker scans each product’s barcode + enters quantity. System records the actual received quantity. Discrepancies (over/under-shipment) are flagged. (4) Quality check: if product requires inspection, move to QC zone. QC result: PASS (proceed to put-away) or FAIL (initiate return). (5) Put-Away: system recommends an optimal storage location based on: product storage type (refrigerated product → refrigerated zone), location capacity (must have sufficient free space), proximity to picking zones for fast-moving SKUs (A-class items closer to shipping), lot rotation: FEFO (First Expired First Out) for perishables, FIFO for non-perishables. Worker scans the destination location barcode to confirm put-away. System updates LocationProduct. ABC analysis: classify SKUs by velocity: A-class (top 20% by volume) = 80% of picks. Store in prime locations (shortest travel path from shipping). B-class (next 30%) = middle zones. C-class (bottom 50%) = farthest zones. Reduces average pick travel time significantly.

Order Picking and Optimization

class PickingService:
    def create_pick_tasks(self, order_id: int) -> list[PickTask]:
        order = self.order_repo.get(order_id)
        tasks = []
        for item in order.line_items:
            # Find best location: FEFO for perishables, else FIFO
            locations = self.db.query("""
                SELECT lp.*, l.aisle, l.bay, l.level
                FROM location_products lp
                JOIN locations l ON lp.location_id = l.location_id
                WHERE lp.product_id = :p AND lp.quantity >= :q
                  AND l.zone = 'STORAGE'
                ORDER BY
                  CASE WHEN :perishable THEN lp.expiry_date ELSE lp.received_at END ASC
                LIMIT 1
            """, p=item.product_id, q=item.quantity,
                 perishable=item.is_perishable)
            if not locations:
                raise StockoutError(item.product_id)
            tasks.append(PickTask(
                order_id=order_id, location_id=locations[0].location_id,
                product_id=item.product_id, quantity=item.quantity,
                status=PickTaskStatus.ASSIGNED
            ))
        # Optimize pick sequence: sort by aisle, then bay, then level
        # (S-shaped or Z-shaped traversal minimizes travel distance)
        tasks.sort(key=lambda t: (t.aisle, t.bay, t.level))
        return self.task_repo.save_all(tasks)

Wave picking: group multiple orders into a “wave” and generate interleaved pick tasks. A picker collects items for 10+ orders simultaneously (multi-order cart). The WMS assigns order items to cart slots. After picking: items are sorted to individual order staging areas. Increases throughput 3-5x versus single-order picking. Zone picking: divide the warehouse into zones; each picker works only their zone. Each order visits each zone (pick-and-pass) or orders are split by zone and consolidated (pick-and-sort). Reduces travel distance per picker significantly.

Packing and Shipping

After all PickTasks for an order are COMPLETED, the order moves to packing. Packing station: worker scans each picked item (barcode verification). System suggests optimal box size based on item dimensions and weights. Generates packing slip and shipping label (via carrier API: UPS, FedEx, USPS). Weight is recorded for billing reconciliation. Carrier selection: choose the cheapest carrier that meets the required delivery window. Shipping label printed and affixed. Order status → PACKED. Truck loading (shipping): system generates a load plan: group packages by destination region and truck capacity. Worker scans each package during loading. System verifies all expected packages are loaded. Order status → SHIPPED. Tracking update: publish SHIPPED event to the notification service. Customer receives tracking number via email/SMS. Exception handling: if a package is damaged during picking, the picker raises an exception. System triggers: re-pick from alternate location (if stock available), substitute product (if configured), or partial fulfillment with notification.

See also: Shopify Interview Prep

See also: Stripe Interview Prep

See also: LinkedIn Interview Prep

See also: Scale AI Interview Guide 2026: Data Infrastructure, RLHF Pipelines, and ML Engineering

See also: Uber Interview Guide 2026: Dispatch Systems, Geospatial Algorithms, and Marketplace Engineering

Scroll to Top