mcpField
Y
yard-management

yard-management

github.com/kishorkukrejaその他8448 回インストール3 週間前に更新
リポジトリ

yard-management について

yard-managementは、ヤード運営チーム向けのトレーラー管理スキルです。ゲート業務、位置把握、ドック予約、ヤード内車両の配車を扱い、滞留、混雑、デテンション費用への対策を案内します。

主な機能

  1. 01ゲートの入退場手順の計画
  2. 02ヤード配置とトレーラー待機
  3. 03トレーラー追跡と滞留監視
  4. 04ドック予約スケジューリング
  5. 05ヤード内車両の配車最適化

活用シーン

  1. 01トレーラー位置の把握向上
  2. 02ゲートとドックの待ち時間削減
  3. 03デテンション費用と滞留時間の管理
  4. 04ドック割り当てとヤード作業の計画

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/kishorkukreja/awesome-supply-chain --skill yard-management

インストール後、Claude Code で/yard-managementを入力して読み込まれたか確認します。

詳細

ヤード管理

ヤード管理とトレーラーロジスティクスのエキスパートとして、効率的なヤード管理の実践とテクノロジーを通じて、ヤード運用の最適化、トレーラーの可視性向上、留置料の削減、ドックドアの稼働率の最大化を支援します。

初期評価

ヤード運用を最適化する前に、以下を把握してください。

  1. 施設の特性

    • ヤードの規模と収容能力はどのくらいですか?(トレーラーの駐車スペース数)
    • ドックドアはいくつありますか?
    • レイアウト上の制約はありますか?(スペース、アクセス、旋回半径)
    • ゲートのセキュリティとチェックイン手順はどうなっていますか?
  2. 運用量

    • 1日あたりの入出庫トレーラー数はどのくらいですか?
    • トレーラー1台あたりの平均滞留時間はどのくらいですか?
    • ピーク時間やパターンはありますか?
    • トレーラーの種類は何ですか?(ドライバン、冷蔵車、フラットベッド)
  3. 現在の課題

    • トレーラーの可視性に問題がありますか?
    • ゲートやドックでの待ち時間が長いですか?
    • 留置料やデマレージのコストが高いですか?
    • ヤード内のトレーラーを見つけるのが困難ですか?
    • ドアが混雑していますか?
  4. リソース

    • ヤードジョッキーは何人いますか?
    • 利用可能なヤードトラクターは何台ありますか?
    • どのようなテクノロジーを導入していますか?(YMS、GPS、RFID)
    • 人員配置やシフトはどうなっていますか?

ヤード管理フレームワーク

ヤード管理の主要機能

1. ゲート管理

  • チェックイン/チェックアウト手順
  • 運送業者の資格情報の確認
  • BOLと書類の確認
  • 安全点検
  • 予約の確認

2. ヤード計画とレイアウト

  • トレーラーの駐車位置
  • 優先度別の待機ゾーン
  • ドックドアの割り当て
  • 交通の流れの最適化

3. トレーラーの移動

  • ヤードジョッキーの配車
  • ドアへのトレーラーの配置
  • 積み込み/荷降ろしのための再配置
  • トレーラープールの管理

4. 追跡と可視性

  • トレーラーのリアルタイム位置
  • 積荷のステータス(空、積載済み、処理中)
  • 滞留時間の監視
  • 例外管理

5. ドックのスケジュール管理

  • 予約の受付
  • ドアの割り当て
  • 積み込み/荷降ろしの調整
  • 運送業者との連絡

ヤードレイアウトの最適化

ヤード設計の原則
import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial import distance

class YardLayoutOptimizer:
    """
    Optimize yard layout and trailer positioning

    Minimize jockey moves and door spotting time
    """

    def __init__(self, num_doors, yard_capacity, dock_positions):
        """
        Parameters:
        - num_doors: number of dock doors
        - yard_capacity: total trailer parking spots
        - dock_positions: list of (x, y) coordinates for each door
        """
        self.num_doors = num_doors
        self.yard_capacity = yard_capacity
        self.dock_positions = np.array(dock_positions)

    def design_staging_zones(self, zone_types=['inbound', 'outbound',
                                              'live', 'empty']):
        """
        Design staging zones based on trailer status

        Returns optimal zone assignments
        """

        # Allocate yard capacity by zone
        # Typical allocation:
        # - Inbound waiting: 30%
        # - Outbound ready: 25%
        # - Live loading/unloading: 20%
        # - Empty/drop trailers: 25%

        allocations = {
            'inbound': int(self.yard_capacity * 0.30),
            'outbound': int(self.yard_capacity * 0.25),
            'live': int(self.yard_capacity * 0.20),
            'empty': int(self.yard_capacity * 0.25)
        }

        # Position zones near relevant doors
        zones = {}

        # Inbound zone: Near inbound doors (first half)
        zones['inbound'] = {
            'capacity': allocations['inbound'],
            'preferred_doors': list(range(self.num_doors // 2)),
            'avg_distance_to_door': 50  # feet
        }

        # Outbound zone: Near outbound doors (second half)
        zones['outbound'] = {
            'capacity': allocations['outbound'],
            'preferred_doors': list(range(self.num_doors // 2, self.num_doors)),
            'avg_distance_to_door': 50
        }

        # Live zone: Immediately adjacent to doors
        zones['live'] = {
            'capacity': allocations['live'],
            'preferred_doors': list(range(self.num_doors)),
            'avg_distance_to_door': 20  # Closest
        }

        # Empty zone: Furthest from doors
        zones['empty'] = {
            'capacity': allocations['empty'],
            'preferred_doors': [],
            'avg_distance_to_door': 150  # Furthest
        }

        return zones

    def calculate_optimal_spot_locations(self, num_spots, zone_center,
                                        spacing=60):
        """
        Calculate grid of trailer parking spots

        Parameters:
        - num_spots: number of spots needed
        - zone_center: (x, y) center of zone
        - spacing: feet between trailers
        """

        # Create grid layout
        spots_per_row = 10  # Standard configuration
        num_rows = int(np.ceil(num_spots / spots_per_row))

        spots = []
        for row in range(num_rows):
            for col in range(spots_per_row):
                if len(spots) >= num_spots:
                    break

                x = zone_center[0] + (col * spacing)
                y = zone_center[1] + (row * spacing)

                spots.append({
                    'spot_id': f'S{len(spots)+1:03d}',
                    'position': (x, y),
                    'row': row,
                    'col': col
                })

        return spots

    def assign_trailer_to_spot(self, trailer_status, trailer_door_assignment,
                              available_spots):
        """
        Assign trailer to optimal parking spot

        Minimize distance to assigned door

        Parameters:
        - trailer_status: 'inbound', 'outbound', 'live', 'empty'
        - trailer_door_assignment: door number (if assigned)
        - available_spots: list of available spot dictionaries
        """

        # Filter spots by zone preference
        zone_spots = [
            spot for spot in available_spots
            if spot.get('zone') == trailer_status
        ]

        if not zone_spots:
            zone_spots = available_spots  # Use any available

        if not zone_spots:
            return None  # Yard full

        # If door assigned, find closest spot to that door
        if trailer_door_assignment is not None:
            door_position = self.dock_positions[trailer_door_assignment]

            # Calculate distances
            distances = [
                distance.euclidean(spot['position'], door_position)
                for spot in zone_spots
            ]

            # Select closest spot
            best_spot_idx = np.argmin(distances)
            assigned_spot = zone_spots[best_spot_idx]

        else:
            # No door assigned, use first available in zone
            assigned_spot = zone_spots[0]

        return assigned_spot

    def analyze_yard_utilization(self, occupied_spots, total_spots):
        """
        Calculate yard utilization metrics

        Returns utilization by zone and overall
        """

        utilization = {
            'total_spots': total_spots,
            'occupied_spots': len(occupied_spots),
            'utilization_pct': len(occupied_spots) / total_spots * 100,
            'available_spots': total_spots - len(occupied_spots)
        }

        # By zone
        zones = {}
        for spot in occupied_spots:
            zone = spot.get('zone', 'unknown')
            if zone not in zones:
                zones[zone] = 0
            zones[zone] += 1

        utilization['by_zone'] = zones

        return utilization

# Example usage
optimizer = YardLayoutOptimizer(
    num_doors=40,
    yard_capacity=200,
    dock_positions=[(i*20, 0) for i in range(40)]  # Doors in a line
)

zones = optimizer.design_staging_zones()
print("Staging Zones:")
for zone_name, zone_info in zones.items():
    print(f"  {zone_name}: {zone_info['capacity']} spots, "
          f"avg distance {zone_info['avg_distance_to_door']} ft")

ドックドアのスケジュール管理

予約スケジュール管理システム
import pandas as pd
from datetime import datetime, timedelta

class DockSchedulingSystem:
    """
    Manage dock door appointments and scheduling

    Optimize door utilization and minimize wait times
    """

    def __init__(self, num_doors, hours_of_operation=(6, 22)):
        """
        Parameters:
        - num_doors: number of dock doors
        - hours_of_operation: (start_hour, end_hour) tuple
        """
        self.num_doors = num_doors
        self.start_hour = hours_of_operation[0]
        self.end_hour = hours_of_operation[1]
        self.schedule = {}

    def create_time_slots(self, date, slot_duration_hours=2):
        """
        Create available time slots for a date

        Returns list of time slots
        """

        slots = []
        current_time = datetime.combine(date, datetime.min.time()).replace(
            hour=self.start_hour
        )
        end_time = datetime.combine(date, datetime.min.time()).replace(
            hour=self.end_hour
        )

        while current_time < end_time:
            slot_end = current_time + timedelta(hours=slot_duration_hours)

            slots.append({
                'start_time': current_time,
                'end_time': slot_end,
                'available_doors': list(range(self.num_doors))
            })

            current_time = slot_end

        return slots

    def book_appointment(self, carrier, appointment_type, requested_time,
                        duration_hours=2, door_preference=None):
        """
        Book dock appointment

        Parameters:
        - carrier: carrier name
        - appointment_type: 'inbound' or 'outbound'
        - requested_time: datetime
        - duration_hours: expected duration
        - door_preference: specific door number (optional)
        """

        date = requested_time.date()

        # Get or create slots for date
        if date not in self.schedule:
            self.schedule[date] = self.create_time_slots(date)

        # Find matching time slot
        for slot in self.schedule[date]:
            if (slot['start_time'] <= requested_time <
                slot['end_time'] and
                len(slot['available_doors']) > 0):

                # Assign door
                if door_preference and door_preference in slot['available_doors']:
                    assigned_door = door_preference
                else:
                    assigned_door = slot['available_doors'][0]

                # Remove door from available
                slot['available_doors'].remove(assigned_door)

                appointment = {
                    'appointment_id': f"APT{len(self.schedule)*100 + 1}",
                    'carrier': carrier,
                    'type': appointment_type,
                    'scheduled_time': slot['start_time'],
                    'door': assigned_door,
                    'duration': duration_hours,
                    'status': 'scheduled'
                }

                return appointment

        # No available slot found
        return {
            'error': 'No available slot',
            'requested_time': requested_time,
            'suggestion': 'Try different time or date'
        }

    def check_availability(self, date, appointment_type=None):
        """
        Check door availability for a date

        Returns available slots
        """

        if date not in self.schedule:
            self.schedule[date] = self.create_time_slots(date)

        availability = []

        for slot in self.schedule[date]:
            if len(slot['available_doors']) > 0:
                availability.append({
                    'time_slot': f"{slot['start_time'].strftime('%H:%M')} - "
                                f"{slot['end_time'].strftime('%H:%M')}",
                    'available_doors': len(slot['available_doors']),
                    'door_numbers': slot['available_doors'][:5]  # Show first 5
                })

        return availability

    def calculate_utilization(self, date):
        """
        Calculate door utilization for a date

        Returns utilization percentage
        """

        if date not in self.schedule:
            return {'utilization': 0, 'message': 'No appointments scheduled'}

        total_door_slots = 0
        used_door_slots = 0

        for slot in self.schedule[date]:
            # Each slot has potential of all doors
            total_door_slots += self.num_doors

            # Count used doors (initially available - currently available)
            used_doors = self.num_doors - len(slot['available_doors'])
            used_door_slots += used_doors

        utilization = used_door_slots / total_door_slots * 100 if total_door_slots > 0 else 0

        return {
            'date': date,
            'utilization_pct': utilization,
            'total_door_slots': total_door_slots,
            'used_door_slots': used_door_slots,
            'target_utilization': 75  # Best practice target
        }

    def optimize_door_assignments(self, appointments):
        """
        Re-optimize door assignments to minimize moves

        Group similar appointment types on adjacent doors
        """

        # Separate by type
        inbound = [a for a in appointments if a['type'] == 'inbound']
        outbound = [a for a in appointments if a['type'] == 'outbound']

        # Assign inbound to first half of doors
        inbound_doors = list(range(self.num_doors // 2))
        outbound_doors = list(range(self.num_doors // 2, self.num_doors))

        # Reassign
        for idx, appt in enumerate(inbound):
            if idx < len(inbound_doors):
                appt['door'] = inbound_doors[idx]

        for idx, appt in enumerate(outbound):
            if idx < len(outbound_doors):
                appt['door'] = outbound_doors[idx]

        return appointments

# Example usage
scheduler = DockSchedulingSystem(num_doors=40)

# Book appointments
appt1 = scheduler.book_appointment(
    carrier='ABC Trucking',
    appointment_type='inbound',
    requested_time=datetime.now().replace(hour=8, minute=0)
)

print(f"Appointment booked: Door {appt1.get('door')} at "
      f"{appt1.get('scheduled_time')}")

# Check availability
tomorrow = datetime.now().date() + timedelta(days=1)
availability = scheduler.check_availability(tomorrow)
print(f"\nAvailability for {tomorrow}:")
for slot in availability[:3]:
    print(f"  {slot['time_slot']}: {slot['available_doors']} doors available")

トレーラーの追跡と可視性

ヤード管理システム(YMS)の主要機能
class YardManagementSystem:
    """
    Core yard management system functionality

    Track trailers, manage moves, monitor dwell time
    """

    def __init__(self):
        self.trailers = {}  # trailer_id -> trailer info
        self.yard_spots = {}  # spot_id -> trailer_id
        self.move_history = []
        self.alerts = []

    def check_in_trailer(self, trailer_id, carrier, seal_number,
                        trailer_type='dry_van', is_loaded=True):
        """
        Check in trailer at gate

        Creates trailer record in system
        """

        check_in_time = datetime.now()

        trailer_info = {
            'trailer_id': trailer_id,
            'carrier': carrier,
            'seal_number': seal_number,
            'trailer_type': trailer_type,
            'is_loaded': is_loaded,
            'status': 'in_yard',
            'check_in_time': check_in_time,
            'current_location': 'gate',
            'dock_door': None,
            'moves': 0
        }

        self.trailers[trailer_id] = trailer_info

        # Log move
        self.move_history.append({
            'trailer_id': trailer_id,
            'timestamp': check_in_time,
            'action': 'check_in',
            'location': 'gate'
        })

        return trailer_info

    def assign_yard_spot(self, trailer_id, spot_id):
        """
        Assign trailer to yard parking spot

        Parameters:
        - trailer_id: unique trailer identifier
        - spot_id: yard spot identifier
        """

        if trailer_id not in self.trailers:
            return {'error': f'Trailer {trailer_id} not found'}

        if spot_id in self.yard_spots and self.yard_spots[spot_id] is not None:
            return {'error': f'Spot {spot_id} already occupied'}

        # Update trailer location
        trailer = self.trailers[trailer_id]
        old_location = trailer['current_location']
        trailer['current_location'] = spot_id
        trailer['moves'] += 1

        # Update spot
        if old_location in self.yard_spots:
            self.yard_spots[old_location] = None  # Free old spot

        self.yard_spots[spot_id] = trailer_id

        # Log move
        self.move_history.append({
            'trailer_id': trailer_id,
            'timestamp': datetime.now(),
            'action': 'move_to_spot',
            'from': old_location,
            'to': spot_id
        })

        return {
            'trailer_id': trailer_id,
            'assigned_spot': spot_id,
            'moves': trailer['moves']
        }

    def spot_trailer_at_door(self, trailer_id, door_number):
        """
        Spot trailer at dock door for loading/unloading

        Parameters:
        - trailer_id: trailer to spot
        - door_number: dock door number
        """

        if trailer_id not in self.trailers:
            return {'error': f'Trailer {trailer_id} not found'}

        trailer = self.trailers[trailer_id]
        old_location = trailer['current_location']

        # Update trailer
        trailer['current_location'] = f'door_{door_number}'
        trailer['dock_door'] = door_number
        trailer['status'] = 'at_door'
        trailer['door_arrival_time'] = datetime.now()
        trailer['moves'] += 1

        # Free old spot if in yard
        if old_location in self.yard_spots:
            self.yard_spots[old_location] = None

        # Log move
        self.move_history.append({
            'trailer_id': trailer_id,
            'timestamp': datetime.now(),
            'action': 'spot_at_door',
            'door': door_number,
            'from': old_location
        })

        return {
            'trailer_id': trailer_id,
            'door': door_number,
            'spotted_time': trailer['door_arrival_time']
        }

    def complete_door_activity(self, trailer_id):
        """
        Complete loading/unloading at door

        Move trailer back to yard or check out
        """

        if trailer_id not in self.trailers:
            return {'error': f'Trailer {trailer_id} not found'}

        trailer = self.trailers[trailer_id]

        if trailer['status'] != 'at_door':
            return {'error': 'Trailer not at door'}

        # Calculate door dwell time
        door_dwell = (datetime.now() - trailer['door_arrival_time']).total_seconds() / 3600

        trailer['status'] = 'completed'
        trailer['door_departure_time'] = datetime.now()
        trailer['door_dwell_hours'] = door_dwell

        # Log
        self.move_history.append({
            'trailer_id': trailer_id,
            'timestamp': datetime.now(),
            'action': 'complete_door_activity',
            'door_dwell_hours': door_dwell
        })

        # Check for excessive door time (>2 hours)
        if door_dwell > 2:
            self.alerts.append({
                'alert_type': 'excessive_door_dwell',
                'trailer_id': trailer_id,
                'door_dwell_hours': door_dwell,
                'timestamp': datetime.now()
            })

        return {
            'trailer_id': trailer_id,
            'door_dwell_hours': door_dwell,
            'status': 'completed'
        }

    def check_out_trailer(self, trailer_id):
        """
        Check out trailer from facility

        Final step before trailer leaves
        """

        if trailer_id not in self.trailers:
            return {'error': f'Trailer {trailer_id} not found'}

        trailer = self.trailers[trailer_id]

        # Calculate total yard dwell
        total_dwell = (datetime.now() - trailer['check_in_time']).total_seconds() / 3600

        trailer['status'] = 'checked_out'
        trailer['check_out_time'] = datetime.now()
        trailer['total_yard_dwell_hours'] = total_dwell

        # Log
        self.move_history.append({
            'trailer_id': trailer_id,
            'timestamp': datetime.now(),
            'action': 'check_out',
            'total_dwell_hours': total_dwell
        })

        # Alert if excessive yard dwell (>24 hours)
        if total_dwell > 24:
            self.alerts.append({
                'alert_type': 'excessive_yard_dwell',
                'trailer_id': trailer_id,
                'total_dwell_hours': total_dwell,
                'timestamp': datetime.now()
            })

        return {
            'trailer_id': trailer_id,
            'total_yard_dwell_hours': total_dwell,
            'total_moves': trailer['moves']
        }

    def get_yard_status(self):
        """
        Get current yard status summary

        Returns counts by status
        """

        status_counts = {}
        for trailer in self.trailers.values():
            status = trailer['status']
            status_counts[status] = status_counts.get(status, 0) + 1

        total_trailers = len(self.trailers)
        occupied_spots = sum(1 for spot in self.yard_spots.values()
                           if spot is not None)

        return {
            'total_trailers_in_yard': total_trailers,
            'occupied_spots': occupied_spots,
            'by_status': status_counts,
            'active_alerts': len(self.alerts)
        }

    def find_trailer(self, trailer_id):
        """
        Locate trailer in yard

        Returns current location
        """

        if trailer_id not in self.trailers:
            return {'error': 'Trailer not found'}

        trailer = self.trailers[trailer_id]

        return {
            'trailer_id': trailer_id,
            'current_location': trailer['current_location'],
            'status': trailer['status'],
            'carrier': trailer['carrier'],
            'dwell_time_hours': (datetime.now() - trailer['check_in_time']).total_seconds() / 3600
        }

    def calculate_performance_metrics(self):
        """
        Calculate yard performance metrics

        Returns KPIs
        """

        if not self.trailers:
            return {'message': 'No data available'}

        # Average dwell time
        dwell_times = []
        for trailer in self.trailers.values():
            if 'total_yard_dwell_hours' in trailer:
                dwell_times.append(trailer['total_yard_dwell_hours'])

        avg_dwell = np.mean(dwell_times) if dwell_times else 0

        # Average moves per trailer
        moves = [t['moves'] for t in self.trailers.values()]
        avg_moves = np.mean(moves) if moves else 0

        # Door dwell times
        door_dwells = []
        for trailer in self.trailers.values():
            if 'door_dwell_hours' in trailer:
                door_dwells.append(trailer['door_dwell_hours'])

        avg_door_dwell = np.mean(door_dwells) if door_dwells else 0

        return {
            'avg_yard_dwell_hours': avg_dwell,
            'avg_moves_per_trailer': avg_moves,
            'avg_door_dwell_hours': avg_door_dwell,
            'total_trailers': len(self.trailers),
            'total_alerts': len(self.alerts),
            'target_yard_dwell_hours': 24,
            'target_door_dwell_hours': 2
        }

# Example usage
yms = YardManagementSystem()

# Check in trailer
trailer = yms.check_in_trailer(
    trailer_id='TRL12345',
    carrier='ABC Trucking',
    seal_number='SEAL987',
    is_loaded=True
)
print(f"Trailer {trailer['trailer_id']} checked in at {trailer['check_in_time']}")

# Assign to yard spot
yms.assign_yard_spot('TRL12345', 'S045')
print("Trailer assigned to spot S045")

# Spot at door
yms.spot_trailer_at_door('TRL12345', door_number=12)
print("Trailer spotted at door 12")

# Get yard status
status = yms.get_yard_status()
print(f"\nYard Status: {status['total_trailers_in_yard']} trailers in yard")

ヤードジョッキーの最適化

ジョッキーの配車とタスク管理
class YardJockeyDispatcher:
    """
    Optimize yard jockey task assignment

    Minimize moves and maximize productivity
    """

    def __init__(self, num_jockeys, yard_layout):
        self.num_jockeys = num_jockeys
        self.yard_layout = yard_layout
        self.jockeys = {
            f'Jockey_{i+1}': {
                'current_location': 'office',
                'status': 'available',
                'tasks_completed': 0,
                'total_distance': 0
            }
            for i in range(num_jockeys)
        }
        self.task_queue = []

    def add_move_task(self, trailer_id, from_location, to_location, priority='normal'):
        """
        Add trailer move task to queue

        Parameters:
        - priority: 'urgent', 'normal', 'low'
        """

        task = {
            'task_id': f'TASK{len(self.task_queue)+1:04d}',
            'trailer_id': trailer_id,
            'from': from_location,
            'to': to_location,
            'priority': priority,
            'status': 'queued',
            'created_time': datetime.now()
        }

        self.task_queue.append(task)

        # Sort by priority
        priority_order = {'urgent': 0, 'normal': 1, 'low': 2}
        self.task_queue.sort(
            key=lambda x: priority_order.get(x['priority'], 1)
        )

        return task

    def assign_next_task(self):
        """
        Assign next task to available jockey

        Uses nearest jockey to minimize deadhead
        """

        # Find available jockey
        available_jockeys = [
            (jid, jinfo) for jid, jinfo in self.jockeys.items()
            if jinfo['status'] == 'available'
        ]

        if not available_jockeys or not self.task_queue:
            return None

        # Get next task
        task = self.task_queue[0]

        # Find nearest jockey
        nearest_jockey = None
        min_distance = float('inf')

        for jockey_id, jockey_info in available_jockeys:
            # Calculate distance from jockey to task start location
            distance = self._calculate_distance(
                jockey_info['current_location'],
                task['from']
            )

            if distance < min_distance:
                min_distance = distance
                nearest_jockey = jockey_id

        if nearest_jockey:
            # Assign task
            self.jockeys[nearest_jockey]['status'] = 'busy'
            self.jockeys[nearest_jockey]['current_task'] = task['task_id']

            task['status'] = 'in_progress'
            task['assigned_jockey'] = nearest_jockey
            task['start_time'] = datetime.now()

            self.task_queue.pop(0)

            return {
                'task_id': task['task_id'],
                'jockey': nearest_jockey,
                'trailer': task['trailer_id'],
                'move': f"{task['from']} -> {task['to']}"
            }

        return None

    def complete_task(self, task_id):
        """
        Mark task as completed

        Update jockey status and location
        """

        # Find task
        for task in self.task_queue:
            if task['task_id'] == task_id:
                task['status'] = 'completed'
                task['completion_time'] = datetime.now()

                # Update jockey
                jockey_id = task.get('assigned_jockey')
                if jockey_id:
                    self.jockeys[jockey_id]['status'] = 'available'
                    self.jockeys[jockey_id]['current_location'] = task['to']
                    self.jockeys[jockey_id]['tasks_completed'] += 1

                    # Calculate distance
                    distance = self._calculate_distance(task['from'], task['to'])
                    self.jockeys[jockey_id]['total_distance'] += distance

                return {
                    'task_id': task_id,
                    'jockey': jockey_id,
                    'status': 'completed'
                }

        return {'error': 'Task not found'}

    def _calculate_distance(self, location1, location2):
        """Calculate distance between two locations (simplified)"""

        # In practice, use actual yard coordinates
        # Simplified: random distance 50-500 feet
        return np.random.randint(50, 500)

    def get_jockey_productivity(self):
        """
        Calculate jockey productivity metrics

        Returns moves per hour, utilization
        """

        productivity = []

        for jockey_id, jockey_info in self.jockeys.items():
            productivity.append({
                'jockey_id': jockey_id,
                'tasks_completed': jockey_info['tasks_completed'],
                'total_distance': jockey_info['total_distance'],
                'current_status': jockey_info['status']
            })

        return pd.DataFrame(productivity)

    def optimize_task_sequence(self, tasks):
        """
        Optimize sequence of tasks to minimize total distance

        Uses greedy nearest-neighbor approach
        """

        if not tasks:
            return []

        optimized_sequence = []
        remaining_tasks = tasks.copy()
        current_location = 'office'

        while remaining_tasks:
            # Find nearest task
            nearest_task = None
            min_distance = float('inf')

            for task in remaining_tasks:
                distance = self._calculate_distance(
                    current_location,
                    task['from']
                )

                if distance < min_distance:
                    min_distance = distance
                    nearest_task = task

            if nearest_task:
                optimized_sequence.append(nearest_task)
                remaining_tasks.remove(nearest_task)
                current_location = nearest_task['to']

        return optimized_sequence

よくある課題と解決策

課題:トレーラーの可視性

問題:

  • ヤード内のトレーラーが見つからない
  • ドライバーが探すのに15~30分かかる
  • 時間の浪費とストレスが生じる

解決策:

  • GPS/RFID追跡機能を備えたYMSを導入する
  • ゾーン別のヤードレイアウトと明確な標識を整備する
  • ドライバー向けのモバイルアプリ(トレーラー検索機能)を導入する
  • リアルタイムで更新されるデジタルヤードマップを導入する
  • ステータス別の専用待機ゾーンを設ける
  • ヤードの駐車スペースを色分けする
  • 定期的にヤードを監査し、位置を確認する
課題:高額な留置料

問題:

  • 留置料を支払っている(1時間あたり50~100ドル)
  • トレーラーがドアに長時間とどまっている
  • 積み込み/荷降ろしに時間がかかる

解決策:

  • ドアでの滞留時間に厳格な上限を設ける(2時間未満)
  • 留置料の発生が近づいたら監視して通知する
  • 積荷を事前に準備する(トラックの到着前に準備完了)
  • 可能な場合はライブで積み込み/荷降ろしを行う
  • 留置料の猶予期間を交渉する
  • ドックのスケジュールを最適化する(過剰予約を避ける)
  • 複数業務のトレーニングを行い、ドア作業に人員を柔軟に配置する
  • 無料時間の75%に達した時点で自動通知する
課題:ヤードの混雑

問題:

  • トレーラーが多すぎて、スペースが足りない
  • ヤードジョッキーが移動しづらい
  • トレーラーへのアクセスが妨げられている

解決策:

  • ドロップトレーラープログラムを導入する(事前積み込み済みの出荷分)
  • 空トレーラー専用のオフサイトプールを設ける
  • ジャストインタイムの到着スケジュールを導入する
  • 予約なしで到着した車両を受け入れない
  • ヤードの収容能力を拡張するか、臨時の駐車場を利用する
  • トレーラーの回転時間を改善する(滞留時間を短縮する)
  • 予約スケジュールを改善する(到着を分散させる)
課題:ゲートでの待ち時間が長い

問題:

  • トラックがゲートで30~60分待機している
  • 手作業のチェックインに時間がかかる
  • 書類の誤りや遅延が発生する

解決策:

  • オンライン事前チェックインポータルを導入する
  • セルフチェックイン用のキオスクを設置する
  • 事前登録済みのドライバー専用レーンを設ける
  • BOLのスキャンと検証を自動化する
  • 予約を事前承認する(資格情報を事前確認する)
  • ゲートの処理能力を増強する(レーンを増やす)
  • 到着前にモバイルチェックインできるようにする
課題:ジョッキーの稼働率が低い

問題:

  • ジョッキーが待機していたり、不要な移動をしたりしている
  • 空車での移動距離が長い
  • タスクの優先順位付けが不十分

解決策:

  • ジョッキーの配車システムを導入する
  • ゾーンごとにジョッキーを割り当てる
  • 優先順位付きのリアルタイムタスクキューを用意する
  • タスクの順序を最適化する(移動距離を最小限にする)
  • ジョッキーの人員配置を適正化する
  • 倉庫スタッフにバックアップ要員として相互トレーニングを実施する
  • パフォーマンス指標とインセンティブを設ける
課題:予約の遵守率が低い

問題:

  • 運送会社が予約なしで到着する
  • 早着や遅着がスケジュールを乱す
  • ドアの予約が過剰になる

解決策:

  • 予約を必須にする(方針を徹底する)
  • 予約なしでの到着には追加料金を課す
  • 予約の重要性を伝える
  • 運送会社と連携して遵守を促す
  • 予約のリマインダーを送信する(前日と当日朝)
  • 運送会社の遵守状況を追跡し、報告する
  • 繰り返し違反する運送会社へのサービスを拒否する

ヤード管理テクノロジー

ヤード管理システム(YMS)の選定

エンタープライズ向けYMSプラットフォーム:

  • C3 Solutions:業界リーダー
  • Zebra(旧Yard Management Solutions):RFIDベース
  • Manhattan Associates YMS:WMSと統合
  • Oracle Yard Management:クラウドベース
  • Blue Yonder YMS:AIを活用
  • 4Sight Yard Management:中堅市場向け

YMSの主な機能:

  • トレーラーのリアルタイム追跡(GPS、RFID、手動)
  • ゲートでのチェックイン/チェックアウトの自動化
  • ドック予約のスケジュール管理
  • ジョッキーのタスク管理と配車
  • 滞留時間の監視とアラート
  • レポートと分析
  • WMSおよびTMSとの連携
追跡テクノロジー

RFIDタグ:

  • トレーラーに取り付けるパッシブタグ
  • ゲートや主要地点にリーダーを設置
  • 位置情報を自動更新
  • 費用:タグ1個あたり5~10ドル、リーダー1台あたり1,000~5,000ドル

GPS追跡:

  • トレーラーに取り付けるアクティブGPSデバイス
  • 位置情報をリアルタイムで高精度に把握
  • コストが高く、電源が必要
  • 費用:デバイス1台あたり50~150ドル+月額料金

ジオフェンシング:

  • ヤード内に仮想境界を設定
  • 境界を越えたときにアラートを発生
  • GPSまたはRFIDと連携して動作

バーコード/QRスキャン:

  • ローテクで、手動でスキャンする方式
  • ジョッキー向けのモバイルアプリ
  • 精度が低く、運用ルールの遵守が必要

出力形式

ヤード管理分析レポート

エグゼクティブサマリー:

  • ヤード滞留時間の平均:18.5時間(目標:<12時間)
  • 拘束料金:月額$18,500(目標:<$10,000)
  • ドア稼働率:62%(目標:75%)
  • ヤード収容率:85%(収容能力に近い状態)
  • 推奨事項:YMSを導入し、ドックのスケジュール管理を改善する

現状の指標:

指標現状目標状況
ヤード滞留時間の平均18.5 hrs<12 hrs⚠️ 54%超過
ドア滞留時間の平均2.8 hrs<2 hrs⚠️ 40%超過
月額拘束料金$18.5K<$10K⚠️ 85%超過
ゲート待ち時間22 min<10 min⚠️ 120%超過
ドア稼働率62%75%⚠️ 目標未達
ヤード占有率85%80%⚠️ 収容能力に近い状態

拘束料金の分析:

運送会社月額料金発生件数平均所要時間根本原因
運送会社 A$6,200423.2 hrs荷降ろしの遅れ
運送会社 B$4,800352.9 hrsドックの混雑
運送会社 C$3,500282.6 hrs予約の欠落
その他$4,000322.5 hrsさまざま

ステータス別のヤード滞留時間:

トレーラーのステータス台数平均滞留時間最大滞留時間24時間超の割合
入庫済み・待機中4512.5 hrs38 hrs15%
ドア接車中(積み込み)182.8 hrs4.5 hrs0%
出庫準備完了3228.0 hrs72 hrs45% ⚠️
空車/ドロップ済み2536.0 hrs120 hrs60% ⚠️

根本原因:出庫の遅延

  • 混載待ち(3日以上)
  • 運送会社の集荷予定が未設定
  • 推奨事項:毎日の集荷スケジュールを設定するか、3PLを利用する

曜日・時間帯別のドア稼働率:

時間帯月火水木金平均
6-9 AM85%82%88%90%85%86%
9-12 PM75%70% 72%78%75%74%
12-3 PM55%52%58%60%55%56% ⚠️
3-6 PM48%45%50%52%48%49% ⚠️

推奨事項:午後の稼働率を高めるため、夕方シフトを導入する

改善施策:

  1. YMSを導入 - 効果:滞留時間を30%削減、拘束料金を40%削減

    • トレーラーをリアルタイムで追跡
    • ドアのスケジュールを自動化
    • ヤードトラクターの配車を最適化
    • 投資額:$180K、投資回収期間:14か月
  2. ドックのスケジュール管理を最適化 - 効果:ドア稼働率を13%向上

    • 予約システムを導入
    • 予約遵守を徹底
    • 1日を通じて到着を平準化
    • 投資額:$25K(ソフトウェア)
  3. 出庫時の滞留を削減 - 効果:ヤードの混雑を50%削減

    • 運送会社の毎日の集荷スケジュール
    • 出庫貨物を事前に積載して待機
    • ドロップトレーラープログラム
    • 年間削減額:$120K
  4. ゲートの処理能力を拡大 - 効果:待ち時間を60%削減

    • ゲートレーンを1つ追加
    • セルフサービス端末でチェックイン
    • 事前登録ポータル
    • 投資額:$75K

期待される結果(12か月後):

指標現状目標改善
ヤード滞留時間の平均18.5 hrs12 hrs-35%
拘束料金$18.5K/mo$9K/mo-51%
ドア稼働率62%75%+13 pts
ゲート待ち時間22 min8 min-64%
ヤード占有率85%70%-15 pts

確認すべき質問

さらに詳しい情報が必要な場合:

  1. ドックのドアとヤードの駐車スペースはいくつありますか?
  2. 1日あたりのトレーラーの入出庫台数はどれくらいですか?
  3. YMSまたは追跡システムを導入していますか?
  4. ヤード滞留時間の平均はどれくらいですか?
  5. 拘束料金を支払っていますか?金額はいくらですか?
  6. 予約スケジュール管理システムはありますか?
  7. ヤードトラクターの運転手/トラクターは何人/何台いますか?
  8. 主な課題は何ですか?(可視性、混雑、拘束料金、待ち時間)

関連スキル

  • dock-door-assignment:ドックドアのスケジュールと割り当てを最適化します
  • cross-docking:クロスドック業務と通過型物流
  • warehouse-design:施設のレイアウトと設計
  • route-optimization:出荷ルートと配送
  • freight-optimization:運送業者の管理と輸送
  • supply-chain-automation:自動化とテクノロジーの選定
  • process-optimization:業務プロセスの改善
  • maintenance-planning:設備とヤードトラクターの保守

コメント