Shift dependency rules let you define "if X exists, then Y must exist" relationships. When a shift with specific tags is scheduled, the solver automatically ensures related shifts are also assigned.
The problem
Some scenarios require paired or supporting shifts:
- If you schedule a surgery, you need an anesthesiologist on call
- If you assign a trainee shift, you need a supervisor present
- If you open a high-acuity ward, you need a charge nurse
Without dependency rules, you'd manually coordinate these requirements. Dependency rules automate it.
How dependency rules work
Define rules at the request level using shift tags and a single anchor/required tag per rule:
{
"shiftDependencyRules": [
{
"id": 1,
"departmentId": 7,
"anchorShiftTag": "surgery",
"requiredShiftTag": "oncall-anesthesia",
"minRequiredCount": 1
}
]
}
When the solver assigns any shift tagged surgery, it ensures at least one shift tagged oncall-anesthesia overlaps (or otherwise matches the overlap scope) with it.
Rule structure
{
"id": 1,
"departmentId": 7,
"anchorShiftTag": "icu",
"requiredShiftTag": "supervisor",
"minRequiredCount": 1,
"overlapScope": "TIME_OVERLAP",
"withinHours": null,
"constraintLevel": "hard",
"weight": 1
}
Fields
- id - Unique identifier for this rule
- departmentId - Associates rule with your organizational unit
- anchorShiftTag - Tag on the trigger shift (one tag per rule)
- requiredShiftTag - Tag on the required shift (one tag per rule)
- minRequiredCount - Minimum number of required shifts that must match when the anchor occurs (default: 1)
- overlapScope - How required shifts must align in time with the anchor:
"TIME_OVERLAP"– any time overlap between anchor and required shift"SAME_DAY"– required shift must start on the same calendar day as the anchor"SAME_SHIFT"– required shift must have identical start/end times as the anchor"WITHIN_HOURS"– required shift start must be within a rolling window of the anchor start
- withinHours - Window in hours used when
overlapScopeis"WITHIN_HOURS"nullor<= 0uses a sensible default window of 24 hours (for backwards compatibility)
- constraintLevel - Advisory label for how strict this rule is (for now, global weights in
settings.shiftDependencyRulesstill control the actual constraint priorities) - weight - Per-rule weight multiplier (default
1). Higher values cause violations of this rule to contribute more to the globalshiftDependencyRulespenalty.
Logic
- Trigger: Any shift with
anchorShiftTag - Requirement: At least
minRequiredCountshifts withrequiredShiftTagmust match the chosenoverlapScope(andwithinHoursif applicable)
Enabling dependency rules
Add the constraint weight to settings:
{
"settings": {
"shiftDependencyRules": {
"firstPriorityWeight": 15,
"secondPriorityWeight": 0,
"thirdPriorityWeight": 0,
"fourthPriorityWeight": 0
}
}
}
Higher weights make dependencies harder constraints. Use first priority (15-20) for critical safety or regulatory requirements.
Complete example
A hospital surgery department:
{
"shiftTags": [
{
"id": 1,
"tag": "surgery",
"category": "service",
"description": "Operating room procedure"
},
{
"id": 2,
"tag": "oncall-anesthesia",
"category": "support",
"description": "Anesthesiologist on call"
},
{
"id": 3,
"tag": "trainee",
"category": "role",
"description": "Resident or fellow"
},
{
"id": 4,
"tag": "attending",
"category": "role",
"description": "Supervising physician"
}
],
"shiftDependencyRules": [
{
"id": 1,
"departmentId": 10,
"anchorShiftTag": "surgery",
"requiredShiftTag": "oncall-anesthesia",
"minRequiredCount": 1,
"overlapScope": "TIME_OVERLAP",
"constraintLevel": "hard",
"weight": 1
},
{
"id": 2,
"departmentId": 10,
"anchorShiftTag": "trainee",
"requiredShiftTag": "attending",
"minRequiredCount": 1,
"overlapScope": "TIME_OVERLAP",
"constraintLevel": "hard",
"weight": 1
}
],
"shifts": [
{
"id": 301,
"spot": 15,
"start": "2024-09-15T08:00:00Z",
"end": "2024-09-15T16:00:00Z",
"importance": "MANDATORY",
"tags": ["surgery"]
},
{
"id": 302,
"spot": 16,
"start": "2024-09-15T07:00:00Z",
"end": "2024-09-15T19:00:00Z",
"importance": "OPTIONAL",
"tags": ["oncall-anesthesia"]
},
{
"id": 303,
"spot": 17,
"start": "2024-09-15T09:00:00Z",
"end": "2024-09-15T17:00:00Z",
"importance": "MANDATORY",
"tags": ["trainee"]
},
{
"id": 304,
"spot": 18,
"start": "2024-09-15T08:00:00Z",
"end": "2024-09-15T18:00:00Z",
"importance": "OPTIONAL",
"tags": ["attending"]
}
],
"settings": {
"shiftDependencyRules": {
"firstPriorityWeight": 18,
"secondPriorityWeight": 0,
"thirdPriorityWeight": 0,
"fourthPriorityWeight": 0
}
}
}
With these rules:
- Shift 301 (surgery) triggers rule 1, requiring shift 302 (anesthesia) to be filled
- Shift 303 (trainee) triggers rule 2, requiring shift 304 (attending) to be filled
The solver ensures both dependencies are satisfied.
Advanced patterns
Multiple trigger or required tags
The current API uses one anchor tag and one required tag per rule. To model more complex OR logic, define multiple rules:
{
"shiftDependencyRules": [
{
"id": 1,
"departmentId": 7,
"anchorShiftTag": "icu",
"requiredShiftTag": "supervisor"
},
{
"id": 2,
"departmentId": 7,
"anchorShiftTag": "ccu",
"requiredShiftTag": "supervisor"
},
{
"id": 3,
"departmentId": 7,
"anchorShiftTag": "high-acuity",
"requiredShiftTag": "supervisor"
}
]
}
The combined effect is: if ANY of icu, ccu, or high-acuity is present, a supervisor is required.
Cascading rules
[
{
"id": 1,
"departmentId": 10,
"anchorShiftTag": "complex-surgery",
"requiredShiftTag": "senior-surgeon"
},
{
"id": 2,
"departmentId": 10,
"anchorShiftTag": "senior-surgeon",
"requiredShiftTag": "surgical-tech"
}
]
Complex surgery requires a senior surgeon, which in turn requires a surgical tech. Rules can chain.
Practical use cases
Teaching hospital
{
"anchorShiftTag": "resident",
"requiredShiftTag": "attending",
"description": "Trainees require attending or chief resident supervision"
}
Ensures educational compliance and patient safety.
24/7 facility
{
"anchorShiftTag": "night-shift",
"requiredShiftTag": "manager-oncall",
"description": "Night shifts require manager on call for emergencies"
}
Guarantees leadership availability during off-hours.
Specialized equipment
{
"anchorShiftTag": "mri",
"requiredShiftTag": "radiology-tech",
"description": "Imaging procedures require certified technician"
}
Links equipment use to qualified operators.
Team-based care
{
"anchorShiftTag": "pediatrics",
"requiredShiftTag": "child-life-specialist",
"description": "Pediatric care requires child specialist or social worker"
}
Enforces multidisciplinary care models.
Important notes
Timing flexibility
Dependency rules don't require exact time overlap. The solver interprets "required" broadly:
- Same shift period
- Overlapping hours
- Same day/night (depending on your tags)
If you need strict overlap, use shift collisions or adjust your tag granularity (e.g., "night-oncall-anesthesia" vs "day-oncall-anesthesia").
Optional vs. mandatory shifts
The trigger shift must be scheduled (usually MANDATORY). The required shift can be:
MANDATORY- Will definitely be filledOPTIONAL- Solver will fill it to satisfy the dependency
Mark supporting shifts as optional if they're only needed when the trigger occurs.
Backward compatibility
Dependency rules are completely optional:
- Omit
shiftDependencyRulesarray → no dependencies enforced - Set weight to
[0,0,0,0]→ dependencies ignored - Deactivate individual rules →
"active": false
This feature doesn't affect existing payloads.
Combining with other features
Dependency rules work well with:
- Shift tagging - Foundation for defining relationships
- Shift collisions - Allow trigger and required shifts to overlap
- Settings - Balance dependencies against other constraints
For questions about modeling complex dependencies, contact [email protected].