> ## Documentation Index
> Fetch the complete documentation index at: https://docs.solvice.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Advanced Constraints

> Configure complex business rules and compliance requirements in your routing

# Advanced Constraints

Beyond basic routing constraints, the VRP solver supports sophisticated business rules for compliance, safety, and operational requirements. This guide covers advanced constraints including driving limits, tag matching, vehicle restrictions, and adherence penalties.

## Drive Time Constraints

### Maximum Continuous Drive Time

Enforce legal or safety limits on continuous driving:

```json theme={null}
{
  "resources": [
    {
      "name": "driver-1",
      "maxDriveTimeInSeconds": 14400,  // 4 hours max continuous driving
      "shifts": [{
        "from": "2024-03-15T06:00:00Z",
        "to": "2024-03-15T18:00:00Z",
        "breaks": [{
          "type": "DRIVING",  // Resets drive time counter
          "duration": 2700,   // 45-minute break
          "after": 14400      // After 4 hours driving
        }]
      }]
    }
  ],
  "jobs": [
    {
      "name": "delivery-1",
      "duration": 1800
    }
  ]
}
```

<ParamField path="maxDriveTimeInSeconds" type="integer">
  Maximum seconds of continuous driving before a break is required
</ParamField>

<Warning>
  **Legal Compliance**: Many jurisdictions have mandatory driving time limits. Examples:

  * EU: 4.5 hours continuous driving max
  * US DOT: Complex hours-of-service rules
  * Always verify local regulations
</Warning>

### Maximum Drive Distance

Limit the total distance a vehicle can travel during a trip, useful for electric vehicles with range limitations, mileage-based regulations, or maintenance schedules:

```json theme={null}
{
  "resources": [
    {
      "name": "electric-van",
      "maxDriveDistance": 120000,  // 120km range limit (in meters)
      "shifts": [{
        "from": "2024-03-15T08:00:00Z",
        "to": "2024-03-15T17:00:00Z"
      }]
    }
  ],
  "jobs": [
    {
      "name": "delivery-1",
      "location": {"latitude": 52.52, "longitude": 13.40},
      "duration": 600
    },
    {
      "name": "delivery-2",
      "location": {"latitude": 52.60, "longitude": 13.50},
      "duration": 600
    }
  ]
}
```

<ParamField path="maxDriveDistance" type="integer">
  Maximum driving distance in meters for the entire trip. Hard constraint.
</ParamField>

<Warning>
  **Range-Based Applications**:

  * **Electric Vehicles**: Set based on battery capacity and charging infrastructure
  * **Lease Agreements**: Enforce mileage limits from vehicle leases
  * **Maintenance Windows**: Prevent exceeding service intervals
  * **Regulatory Compliance**: Enforce distance-based driving regulations
</Warning>

<Info>
  **Distance vs Time**: Use `maxDriveDistance` for range constraints (EVs, mileage limits) and `maxDriveTime` for hours-of-service regulations. Both can be combined.
</Info>

### Drive Time Ordering

Ensure jobs are visited in chronological order based on actual drive times:

```json theme={null}
{
  "resources": [
    {
      "name": "driver-1",
      "shifts": [{
        "from": "2024-03-15T08:00:00Z",
        "to": "2024-03-15T18:00:00Z"
      }]
    }
  ],
  "jobs": [
    {
      "name": "morning-appointment",
      "windows": [{"from": "2024-03-15T09:00:00Z", "to": "2024-03-15T10:00:00Z"}]
    },
    {
      "name": "afternoon-appointment", 
      "windows": [{"from": "2024-03-15T14:00:00Z", "to": "2024-03-15T15:00:00Z"}]
    }
  ],
  "options": {
    "constraints": {
      "driveTimeOrder": true
    }
  }
}
```

<Info>
  **Drive Time Ordering** prevents the solver from scheduling later appointments before earlier ones on the same route, even if it might be more efficient.
</Info>

## Tag-Based Constraints

### Hard Tag Matching

Enforce strict requirements for skills, certifications, or equipment:

```json theme={null}
{
  "jobs": [
    {
      "name": "hazmat-delivery",
      "tags": [
        {"name": "hazmat-certified", "hard": true},
        {"name": "truck-required", "hard": true}
      ]
    }
  ],
  "resources": [
    {
      "name": "certified-driver",
      "shifts": [{
        "from": "2024-03-15T08:00:00Z",
        "to": "2024-03-15T17:00:00Z"
      }],
      "tags": ["hazmat-certified", "truck-required", "experienced"]
    },
    {
      "name": "regular-driver",
      "shifts": [{
        "from": "2024-03-15T08:00:00Z",
        "to": "2024-03-15T17:00:00Z"
      }],
      "tags": ["truck-required"]
    }
  ]
}
```

### Soft Tag Preferences

Create preferences without hard requirements:

```json theme={null}
{
  "jobs": [
    {
      "name": "vip-service",
      "tags": [
        {"name": "premium-service", "needed": false, "preferred": true},
        {"name": "experienced", "needed": false, "preferred": true}
      ]
    }
  ],
  "resources": [
    {
      "name": "premium-driver",
      "shifts": [{
        "from": "2024-03-15T08:00:00Z",
        "to": "2024-03-15T17:00:00Z"
      }],
      "tags": ["premium-service", "experienced"]
    }
  ],
  "weights": {
    "tagViolationWeight": 10  // Global multiplier for tag mismatches
  }
}
```

### Tag Matching Rules

<Steps>
  <Step title="Hard Tags Must Match">
    Job with hard tag → Resource must have same hard tag
  </Step>

  <Step title="Soft Tags Create Preference">
    Mismatched soft tags incur penalties based on weight
  </Step>

  <Step title="Resource Tags Don't Restrict">
    Resources can have tags that jobs don't require
  </Step>

  <Step title="Weight Calculation">
    Penalty = tagWeight × tagViolationWeight × mismatchCount
  </Step>
</Steps>

## Vehicle Restrictions

### Disallowed Vehicles

Explicitly prevent certain resources from servicing specific jobs:

```json theme={null}
{
  "resources": [
    {
      "name": "employee-1",
      "shifts": [{
        "from": "2024-03-15T08:00:00Z",
        "to": "2024-03-15T17:00:00Z"
      }]
    },
    {
      "name": "contractor-1",
      "shifts": [{
        "from": "2024-03-15T08:00:00Z",
        "to": "2024-03-15T17:00:00Z"
      }]
    }
  ],
  "jobs": [
    {
      "name": "competitor-location",
      "disallowedResources": ["contractor-1", "contractor-2"],
      "allowedResources": ["employee-1", "employee-2", "employee-3"]
    }
  ]
}
```

<Info>
  **Restriction Priority**:

  1. `disallowedResources` - Never assign these (hard constraint)
  2. `allowedResources` - Only assign from this list (hard constraint)
  3. `preferredResources` - Try these first (soft constraint)
</Info>

### Complex Restriction Example

```json theme={null}
{
  "jobs": [
    {
      "name": "secure-facility",
      "tags": [
        {"name": "security-clearance", "hard": true}
      ],
      "disallowedResources": ["temp-driver-1", "temp-driver-2"],
      "allowedResources": ["secure-driver-1", "secure-driver-2"]
    }
  ],
  "resources": [
    {
      "name": "secure-driver-1",
      "shifts": [{
        "from": "2024-03-15T08:00:00Z",
        "to": "2024-03-15T17:00:00Z"
      }],
      "tags": ["security-clearance"]
    }
  ]
}
```

## Overtime Constraints

### Overtime Penalties

Configure penalties for work beyond regular hours:

```json theme={null}
{
  "resources": [
    {
      "name": "driver-1",
      "shifts": [{
        "from": "2024-03-15T08:00:00Z",
        "to": "2024-03-15T17:00:00Z",        // Regular hours
        "overtimeEnd": "2024-03-15T20:00:00Z" // Can work until 8 PM
      }],
      "hourlyCost": 25      // Regular rate
    }
  ],
  "jobs": [
    {
      "name": "late-delivery",
      "duration": 1800
    }
  ],
  "weights": {
    "overtimeWeight": 100  // Strong penalty for overtime
  }
}
```

### Overtime Behavior

<Tabs>
  <Tab title="Soft Overtime">
    ```json theme={null}
    {
      "resources": [{
        "name": "driver-1",
        "shifts": [{
          "from": "2024-03-15T08:00:00Z",
          "to": "2024-03-15T17:00:00Z",
          "overtimeEnd": "2024-03-15T20:00:00Z"  // Allowed but penalized
        }]
      }],
      "jobs": [{
        "name": "job-1"
      }],
      "weights": {
        "overtimeWeight": 50
      }
    }
    ```

    Work past regular hours incurs penalties
  </Tab>

  <Tab title="Hard Limit">
    ```json theme={null}
    {
      "resources": [{
        "name": "driver-1",
        "shifts": [{
          "from": "2024-03-15T08:00:00Z",
          "to": "2024-03-15T17:00:00Z"
          // No overtimeEnd = hard stop at 17:00
        }]
      }],
      "jobs": [{
        "name": "job-1"
      }]
    }
    ```

    Cannot work past shift end
  </Tab>

  <Tab title="Graduated Penalties">
    ```json theme={null}
    {
      "resources": [{
        "name": "driver-1",
        "shifts": [{
          "from": "2024-03-15T08:00:00Z",
          "to": "2024-03-15T17:00:00Z",
          "overtimeEnd": "2024-03-15T20:00:00Z"
        }]
      }],
      "jobs": [{
        "name": "job-1"
      }],
      "weights": {
        "overtimeWeight": 50
      }
    }
    ```

    Increasing penalties for more overtime
  </Tab>
</Tabs>

## Planning Adherence

### Maintaining Planned Schedules

Penalize deviations from existing plans:

```json theme={null}
{
  "jobs": [
    {
      "name": "scheduled-maintenance",
      "plannedArrival": "2024-03-15T14:00:00Z",
      "plannedResource": "technician-1",
      "windows": [{
        "from": "2024-03-15T13:00:00Z",
        "to": "2024-03-15T15:00:00Z"
      }]
    }
  ],
  "resources": [
    {
      "name": "technician-1",
      "shifts": [{
        "from": "2024-03-15T08:00:00Z",
        "to": "2024-03-15T17:00:00Z"
      }]
    }
  ],
  "weights": {
    "plannedWeight": 50,         // Arrival time adherence
    "plannedResourceWeight": 100  // Resource assignment adherence
  }
}
```

### Adherence Calculation

<Note>
  **Planned Arrival Penalty** = |actual\_arrival - planned\_arrival| × plannedWeight

  **Resource Change Penalty** = (resource\_changed ? 1 : 0) × plannedResourceWeight
</Note>

### Use Cases for Planning Adherence

<AccordionGroup>
  <Accordion title="Customer Communications">
    When customers have been notified of arrival times, minimize changes to maintain trust.
  </Accordion>

  <Accordion title="Incremental Optimization">
    Re-optimize routes while keeping most assignments stable.
  </Accordion>

  <Accordion title="Partial Replanning">
    Add new jobs while minimizing disruption to existing schedule.
  </Accordion>
</AccordionGroup>

## Job Proximity Scoring

### Overview

Job proximity scoring encourages the solver to visit geographically nearby jobs consecutively on the same route. This feature is particularly valuable for dense urban delivery scenarios where multiple jobs exist within close proximity, such as apartment buildings, office complexes, or dense neighborhoods.

**Key Benefits**:

* More efficient route clustering
* Improved customer satisfaction (same-area deliveries)
* Better utilization of local knowledge

<Info>
  **When to Use Proximity Scoring**:

  * Dense urban delivery areas
  * Multi-unit buildings or complexes
  * Neighborhood-based service routes
  * Campus or facility management
  * Any scenario with naturally occurring job clusters
</Info>

### Configuration

Job proximity scoring is controlled by three parameters in the request:

```json theme={null}
{
  "jobs": [
    {
      "name": "building-a-apt-101",
      "location": {"lat": 52.5200, "lon": 13.4050},
      "duration": 300
    },
    {
      "name": "building-a-apt-205",
      "location": {"lat": 52.5202, "lon": 13.4051},
      "duration": 300
    },
    {
      "name": "building-b-unit-5",
      "location": {"lat": 52.5250, "lon": 13.4100},
      "duration": 300
    }
  ],
  "resources": [
    {
      "name": "driver-1",
      "shifts": [{
        "from": "2024-03-15T08:00:00Z",
        "to": "2024-03-15T17:00:00Z"
      }]
    }
  ],
  "options": {
    "jobProximityRadius": 500,              // 500 meters
    "jobProximityDistanceType": "HAVERSINE" // or "REAL"
  },
  "weights": {
    "jobProximityWeight": 1000  // Penalty for not visiting neighbors consecutively
  }
}
```

<ParamField path="options.jobProximityRadius" type="integer" default="0">
  The radius in meters to consider two jobs as neighbors. Jobs within this distance are expected to be visited consecutively. Set to 0 to disable proximity scoring.
</ParamField>

<ParamField path="options.jobProximityDistanceType" type="enum" default="HAVERSINE">
  The distance calculation method:

  * `HAVERSINE`: Fast straight-line distance (great-circle distance)
  * `REAL`: Actual road network distance from routing engine
</ParamField>

<ParamField path="weights.jobProximityWeight" type="integer" default="0">
  Penalty applied when a job with nearby neighbors is not visited immediately after one of those neighbors. Higher values create stronger clustering.
</ParamField>

### Distance Type Options

#### Haversine Distance (Default)

Uses great-circle distance calculation based on latitude/longitude coordinates:

<Tabs>
  <Tab title="Advantages">
    * **Fast**: No external API calls required
    * **Simple**: Works with just coordinates
    * **Reliable**: No dependency on routing service availability
    * **Consistent**: Same calculation every time
  </Tab>

  <Tab title="Best For">
    * Dense urban areas where roads follow grid patterns
    * Initial optimization passes
    * When routing engine is not available
  </Tab>

  <Tab title="Limitations">
    * Doesn't account for actual road networks
    * May over-estimate walkable distances in complex layouts
    * Ignores barriers (rivers, highways, etc.)
  </Tab>
</Tabs>

#### Real Road Distance

Uses actual road network distances from your configured routing engine:

<Tabs>
  <Tab title="Advantages">
    * **Accurate**: Reflects true travel distances
    * **Road-aware**: Considers actual street networks
    * **Barrier-aware**: Accounts for physical obstacles
  </Tab>

  <Tab title="Best For">
    * Areas with complex road networks
    * Locations with significant barriers
    * When routing engine is already configured
    * Final optimization for deployment
  </Tab>

  <Tab title="Limitations">
    * Depends on routing engine availability
    * May vary with traffic data
  </Tab>
</Tabs>

```json theme={null}
{
  "options": {
    "routingEngine": "OSM",
    "jobProximityRadius": 500,
    "jobProximityDistanceType": "REAL"  // Use actual road distances
  },
  "weights": {
    "jobProximityWeight": 1500
  }
}
```

### Practical Examples

#### Example 1: Apartment Building Deliveries

Multiple deliveries in the same building should be handled together:

```json theme={null}
{
  "jobs": [
    {
      "name": "tower-a-floor-2-apt-201",
      "location": {"lat": 52.5200, "lon": 13.4050}
    },
    {
      "name": "tower-a-floor-5-apt-502",
      "location": {"lat": 52.5201, "lon": 13.4050}
    },
    {
      "name": "tower-b-floor-3-apt-301",
      "location": {"lat": 52.5300, "lon": 13.4150}
    }
  ],
  "options": {
    "jobProximityRadius": 100,  // Same building = 100m radius
    "jobProximityDistanceType": "HAVERSINE"
  },
  "weights": {
    "jobProximityWeight": 2000  // Strong penalty for splitting building visits
  }
}
```

#### Example 2: Neighborhood Service Routes

Cluster service calls in residential neighborhoods:

```json theme={null}
{
  "jobs": [
    // Oak Street cluster
    {"name": "123-oak-st", "location": {"lat": 52.5200, "lon": 13.4050}},
    {"name": "125-oak-st", "location": {"lat": 52.5202, "lon": 13.4051}},
    {"name": "127-oak-st", "location": {"lat": 52.5204, "lon": 13.4052}},

    // Maple Avenue cluster (2km away)
    {"name": "45-maple-ave", "location": {"lat": 52.5380, "lon": 13.4250}},
    {"name": "47-maple-ave", "location": {"lat": 52.5382, "lon": 13.4251}}
  ],
  "options": {
    "jobProximityRadius": 300,  // Typical neighborhood block size
    "jobProximityDistanceType": "HAVERSINE"
  },
  "weights": {
    "jobProximityWeight": 1000
  }
}
```

**Result**: The solver will tend to complete all Oak Street deliveries before moving to Maple Avenue.

#### Example 3: Campus or Facility Management

Service multiple locations within a campus or complex:

```json theme={null}
{
  "jobs": [
    {"name": "main-building-hvac", "location": {"lat": 52.5200, "lon": 13.4050}},
    {"name": "main-building-electrical", "location": {"lat": 52.5201, "lon": 13.4051}},
    {"name": "warehouse-inspection", "location": {"lat": 52.5220, "lon": 13.4070}},
    {"name": "parking-structure-lights", "location": {"lat": 52.5210, "lon": 13.4055}}
  ],
  "options": {
    "jobProximityRadius": 800,  // Entire campus radius
    "jobProximityDistanceType": "REAL"  // Account for walking paths
  },
  "weights": {
    "jobProximityWeight": 1500
  }
}
```

### Weight Tuning Guide

The `jobProximityWeight` determines how strongly the solver prioritizes neighbor clustering:

<Tabs>
  <Tab title="Low Weight (100-500)">
    ```json theme={null}
    {
      "weights": {
        "jobProximityWeight": 300
      }
    }
    ```

    **Effect**: Soft preference for clustering

    * Neighbors visited together when convenient
    * Other constraints take priority
    * More flexibility in route construction

    **Use When**:

    * Proximity is a nice-to-have
    * Other constraints are more important
    * Testing the feature initially
  </Tab>

  <Tab title="Medium Weight (500-1500)">
    ```json theme={null}
    {
      "weights": {
        "jobProximityWeight": 1000
      }
    }
    ```

    **Effect**: Strong preference for clustering

    * Neighbors usually visited together
    * Balanced with other soft constraints
    * Typical production setting

    **Use When**:

    * Proximity is important but not critical
    * Balancing multiple objectives
    * Standard delivery scenarios
  </Tab>

  <Tab title="High Weight (1500+)">
    ```json theme={null}
    {
      "weights": {
        "jobProximityWeight": 2500
      }
    }
    ```

    **Effect**: Very strong clustering enforcement

    * Neighbors almost always grouped
    * May override other soft constraints
    * Near-mandatory clustering behavior

    **Use When**:

    * Same-building deliveries must be together
    * Customer expectations are strong
    * Clustering is business-critical
    * Multi-unit residential buildings
  </Tab>
</Tabs>

### Choosing the Right Proximity Radius

<AccordionGroup>
  <Accordion title="Small Radius (50-200m)">
    **Best For**:

    * Single building or complex
    * Multi-unit residential
    * Office tower floors

    **Example**: Apartment building deliveries where all units should be served together.

    ```json theme={null}
    {"jobProximityRadius": 100}
    ```
  </Accordion>

  <Accordion title="Medium Radius (200-500m)">
    **Best For**:

    * City blocks
    * Small neighborhoods
    * Shopping centers
    * Campus buildings

    **Example**: Street-level deliveries in a dense urban area.

    ```json theme={null}
    {"jobProximityRadius": 300}
    ```
  </Accordion>

  <Accordion title="Large Radius (500-1000m)">
    **Best For**:

    * Large neighborhoods
    * Suburban areas
    * Business parks
    * Service territories

    **Example**: Service calls in a residential subdivision.

    ```json theme={null}
    {"jobProximityRadius": 800}
    ```
  </Accordion>

  <Accordion title="Very Large Radius (1000m+)">
    **Best For**:

    * District-level clustering
    * Regional grouping
    * Large facilities

    **Example**: Grouping jobs by general geographic region.

    ```json theme={null}
    {"jobProximityRadius": 1500}
    ```
  </Accordion>
</AccordionGroup>

<Warning>
  **Radius Selection Tips**:

  * **Too Small**: May miss natural clusters, reducing effectiveness
  * **Too Large**: May create unwanted groupings, reducing route efficiency
  * **Rule of Thumb**: Start with typical walking distance between locations in your service area
</Warning>

### Interaction with Other Constraints

Proximity scoring works alongside other constraints:

<Steps>
  <Step title="Hard Constraints Take Priority">
    Time windows, capacity limits, and hard tags always take precedence over proximity scoring.
  </Step>

  <Step title="Balanced with Soft Constraints">
    Proximity penalties are weighed against other soft constraints like travel time, urgency, and planning adherence.
  </Step>

  <Step title="Does Not Guarantee Clustering">
    High proximity weight encourages but doesn't force clustering. Hard constraints or severe penalties from other factors may prevent it.
  </Step>
</Steps>

**Example with Time Windows**:

```json theme={null}
{
  "jobs": [
    {
      "name": "building-a-am",
      "location": {"lat": 52.5200, "lon": 13.4050},
      "windows": [{"from": "2024-03-15T09:00:00Z", "to": "2024-03-15T11:00:00Z"}]
    },
    {
      "name": "building-a-pm",
      "location": {"lat": 52.5201, "lon": 13.4051},
      "windows": [{"from": "2024-03-15T14:00:00Z", "to": "2024-03-15T16:00:00Z"}]
    }
  ],
  "options": {
    "jobProximityRadius": 100
  },
  "weights": {
    "jobProximityWeight": 1000
  }
}
```

Despite being neighbors, these jobs cannot be visited consecutively due to time windows. The solver will accept the proximity penalty.

### Troubleshooting

<AccordionGroup>
  <Accordion title="Neighbors Not Being Visited Together">
    **Possible Causes**:

    * Proximity weight too low compared to other constraints
    * Conflicting time windows prevent consecutive visits
    * Hard constraints forcing separation
    * Insufficient resources to handle clusters

    **Solutions**:

    * Increase `jobProximityWeight`
    * Review time window constraints
    * Check resource availability
    * Use explanation endpoint to see actual penalties
  </Accordion>

  <Accordion title="Unexpected Neighbor Groupings">
    **Possible Causes**:

    * Proximity radius too large
    * Distance type not appropriate for area
    * Geography has unexpected characteristics

    **Solutions**:

    * Reduce `jobProximityRadius`
    * Try different `jobProximityDistanceType`
    * Review actual job locations
    * Test with representative samples
  </Accordion>
</AccordionGroup>

### Best Practices

<Steps>
  <Step title="Start with Analysis">
    Analyze your job locations to understand natural clustering:

    * Plot jobs on a map
    * Identify typical cluster sizes
    * Measure distances between related locations
  </Step>

  <Step title="Test Radius Values">
    Experiment with different proximity radii:

    * Start conservative (smaller radius)
    * Gradually increase until desired grouping achieved
    * Monitor impact on total route efficiency
  </Step>

  <Step title="Balance with Business Goals">
    Consider trade-offs:

    * Tighter clustering may increase total travel time
    * Looser clustering may miss efficiency opportunities
    * Find the sweet spot for your operation
  </Step>

  <Step title="Use Appropriate Distance Type">
    Choose based on your environment:

    * Dense urban grids → HAVERSINE often sufficient
    * Complex road networks → REAL provides better accuracy
    * High-volume operations → HAVERSINE for speed
  </Step>

  <Step title="Monitor and Adjust">
    Track key metrics over time:

    * Actual clustering rates
    * Total route efficiency
    * Customer feedback
    * Driver convenience
  </Step>
</Steps>

### Complete Example

Here's a comprehensive example combining proximity scoring with other features:

```json theme={null}
{
  "resources": [
    {
      "name": "driver-1",
      "shifts": [{
        "from": "2024-03-15T08:00:00Z",
        "to": "2024-03-15T17:00:00Z"
      }]
    },
    {
      "name": "driver-2",
      "shifts": [{
        "from": "2024-03-15T08:00:00Z",
        "to": "2024-03-15T17:00:00Z"
      }]
    }
  ],
  "jobs": [
    // Downtown cluster
    {
      "name": "downtown-100-main",
      "location": {"lat": 52.5200, "lon": 13.4050},
      "duration": 600,
      "priority": 5
    },
    {
      "name": "downtown-102-main",
      "location": {"lat": 52.5202, "lon": 13.4051},
      "duration": 600,
      "priority": 5
    },
    {
      "name": "downtown-200-elm",
      "location": {"lat": 52.5205, "lon": 13.4055},
      "duration": 600,
      "priority": 3
    },

    // Suburb cluster (5km away)
    {
      "name": "suburb-45-oak",
      "location": {"lat": 52.5600, "lon": 13.4500},
      "duration": 600,
      "priority": 2
    },
    {
      "name": "suburb-47-oak",
      "location": {"lat": 52.5602, "lon": 13.4501},
      "duration": 600,
      "priority": 2
    }
  ],
  "options": {
    "routingEngine": "OSM",
    "jobProximityRadius": 400,
    "jobProximityDistanceType": "HAVERSINE",
    "minimizeResources": false
  },
  "weights": {
    "jobProximityWeight": 1200,
    "travelTimeWeight": 10,
    "priorityWeight": 100
  }
}
```

**Expected Behavior**:

* Downtown jobs will be grouped together
* Suburb jobs will be grouped together
* Priority still influences which cluster is visited first
* Travel time minimization within each cluster

## Constraint Interactions

### Constraint Priority Hierarchy

<Steps>
  <Step title="Hard Constraints (Absolute)">
    1. Time windows (hard)
    2. Capacity limits
    3. Disallowed resources
    4. Hard tags
    5. Shift boundaries (without overtime)
  </Step>

  <Step title="Soft Constraints (Weighted)">
    1. Soft time windows
    2. Overtime penalties
    3. Tag preferences
    4. Planning adherence
    5. Preferred resources
  </Step>

  <Step title="Optimization Objectives">
    1. Minimize total cost
    2. Minimize travel time
    3. Balance workload
    4. Maximize urgency satisfaction
  </Step>
</Steps>

### Complex Constraint Example

```json theme={null}
{
  "jobs": [
    {
      "name": "complex-service",
      // Hard constraints
      "tags": [
        {"name": "certified", "needed": true},
        {"name": "heavy-equipment", "needed": true},
        {"name": "premium-service", "needed": false, "preferred": true}
      ],
      "disallowedResources": ["junior-tech-1", "junior-tech-2"],
      "windows": [{
        "from": "2024-03-15T09:00:00Z", "to": "2024-03-15T17:00:00Z"
      }],
      
      // Soft constraints
      "plannedArrival": "2024-03-15T14:00:00Z",
      "urgency": 80
    }
  ],
  "resources": [
    {
      "name": "senior-tech-1",
      "tags": ["certified", "heavy-equipment", "premium-service"],
      "maxDriveTimeInSeconds": 14400,
      "shifts": [{
        "from": "2024-03-15T08:00:00Z", "to": "2024-03-15T17:00:00Z",
        "overtimeEnd": "2024-03-15T19:00:00Z"
      }]
    }
  ],
  "weights": {
    "overtimeWeight": 100,
    "plannedWeight": 50,
    "tagViolationWeight": 10,
    "urgencyWeight": 20
  }
}
```

## Performance Considerations

<Warning>
  **Constraint Complexity Impact**:

  **Low Impact**:

  * Basic tag matching
  * Disallowed resources
  * Simple overtime penalties

  **Medium Impact**:

  * Many soft constraints
  * Complex tag hierarchies
  * Planning adherence with many jobs

  **High Impact**:

  * Drive time ordering
  * Many overlapping soft constraints
  * Complex overtime structures
</Warning>

### Optimization Tips

1. **Use Hard Constraints Sparingly**: Each hard constraint reduces solution space
2. **Balance Weights**: Keep soft constraint weights in reasonable ratios
3. **Test Incrementally**: Add constraints one at a time to identify conflicts
4. **Monitor Infeasibility**: Too many constraints can make problems unsolvable

## Troubleshooting

### Common Issues

<AccordionGroup>
  <Accordion title="Jobs Not Assigned Due to Constraints">
    **Symptoms**: High unassigned job count

    **Check**:

    * Tag requirements vs available resources
    * Disallowed resource lists
    * Time window compatibility
    * Capacity constraints

    **Solutions**:

    * Review tag assignments
    * Verify resource capabilities
    * Consider soft constraints instead of hard
    * Enable partial planning
  </Accordion>

  <Accordion title="Unexpected Constraint Violations">
    **Symptoms**: Soft constraints violated despite high weights

    **Check**:

    * Competing constraint weights
    * Hard constraint conflicts
    * Resource availability

    **Solutions**:

    * Increase specific constraint weights
    * Review weight ratios
    * Check for conflicting requirements
    * Add more resources
  </Accordion>

  <Accordion title="Poor Solution Quality">
    **Symptoms**: Valid but inefficient routes

    **Check**:

    * Too many hard constraints
    * Conflicting soft constraints
    * Insufficient optimization time

    **Solutions**:

    * Convert some hard constraints to soft
    * Adjust weight balance
    * Increase solve time limit
    * Simplify constraint model
  </Accordion>
</AccordionGroup>

### Debugging Constraints

Use the explanation endpoint to understand constraint impacts:

```bash theme={null}
GET /v2/vrp/jobs/{jobId}/explanation
```

Response includes:

* Active constraints for each assignment
* Constraint violations and penalties
* Why certain assignments weren't made

## Best Practices

<Steps>
  <Step title="Start Simple">
    Begin with essential constraints only:

    * Basic time windows
    * Required capacities
    * Critical tags
  </Step>

  <Step title="Add Incrementally">
    Layer in advanced constraints:

    * Soft preferences
    * Overtime rules
    * Planning adherence
  </Step>

  <Step title="Monitor Impact">
    Track key metrics:

    * Constraint violation counts
    * Solution quality scores
    * Computation time
    * Unassigned job reasons
  </Step>

  <Step title="Document Rules">
    Maintain clear documentation:

    * Business reason for each constraint
    * Weight selection rationale
    * Expected behavior
    * Fallback strategies
  </Step>
</Steps>

## Related Features

<CardGroup cols={2}>
  <Card title="Tag & Ranking" icon="tags" href="/guides/vrp/features/tag-ranking">
    Advanced tag matching and preferences
  </Card>

  <Card title="Time Windows" icon="clock" href="/guides/vrp/features/time-scheduling-advanced">
    Time-based constraints
  </Card>

  <Card title="Period Rules" icon="calendar" href="/guides/vrp/features/resource-period-rules">
    Long-term resource constraints
  </Card>

  <Card title="Cost Optimization" icon="dollar-sign" href="/guides/vrp/features/cost-optimization">
    How constraints affect costs
  </Card>
</CardGroup>
