Skip to main content

Overview

This example demonstrates restaurant scheduling where diverse staff roles must be coordinated across kitchen, floor, and bar positions. The solution balances skill requirements, prevents fatigue-inducing shift sequences, and ensures fair distribution of premium shifts.
This example showcases multi-skill employees, role-based shift requirements, pattern prohibitions for work-life balance, and tip-shift fairness.

Business Scenario

A restaurant manages:
  • 20 employees across kitchen, floor, and bar roles
  • Split shifts for lunch and dinner service
  • Multi-skilled staff who can work multiple positions
  • Premium evening/weekend shifts with fair distribution
  • No close-then-open (clopening) sequences
  • Minimum rest between late nights and early mornings

Quick Example

A minimal hospitality request with multi-skilled staff and split shifts:
{
  "employees": [
    { "name": "Chef-Marco", "skills": [{ "name": "kitchen", "level": 5 }], "wage": 28 },
    { "name": "Server-James", "skills": [{ "name": "floor", "level": 5 }, { "name": "bar", "level": 3 }], "wage": 12 }
  ],
  "shifts": [
    { "name": "mon-lunch-kitchen", "from": "2024-04-01T10:00:00", "to": "2024-04-01T15:00:00", "skills": [{ "name": "kitchen" }], "min": 2 },
    { "name": "mon-dinner-floor", "from": "2024-04-01T17:00:00", "to": "2024-04-01T23:00:00", "skills": [{ "name": "floor" }], "min": 3 }
  ],
  "patterns": [
    { "type": "MULTI_DAY", "satisfy": "PROHIBITED", "elements": [{ "type": "ON", "tags": ["EVENING"] }, { "type": "ON", "tags": ["MORNING"] }] }
  ]
}

Complete Implementation

{
  "employees": [
    {
      "name": "Chef-Marco",
      "skills": [
        { "name": "kitchen", "level": 5 },
        { "name": "head-chef", "level": 5 },
        { "name": "prep", "level": 4 }
      ],
      "availability": ["2024-04-01T00:00:00/2024-04-07T23:59:59"],
      "wage": 28
    },
    {
      "name": "Cook-Lisa",
      "skills": [
        { "name": "kitchen", "level": 4 },
        { "name": "prep", "level": 5 },
        { "name": "pastry", "level": 3 }
      ],
      "availability": ["2024-04-01T00:00:00/2024-04-07T23:59:59"],
      "wage": 20
    },
    {
      "name": "Server-James",
      "skills": [
        { "name": "floor", "level": 5 },
        { "name": "bar", "level": 3 },
        { "name": "sommelier", "level": 2 }
      ],
      "availability": ["2024-04-01T00:00:00/2024-04-07T23:59:59"],
      "preference": ["fri-dinner-floor", "sat-dinner-floor"],
      "wage": 12
    },
    {
      "name": "Server-Emma",
      "skills": [{ "name": "floor", "level": 4 }, { "name": "host", "level": 5 }],
      "availability": [
        "2024-04-01T10:00:00/2024-04-01T22:00:00",
        "2024-04-02T10:00:00/2024-04-02T22:00:00",
        "2024-04-03T10:00:00/2024-04-03T22:00:00",
        "2024-04-04T10:00:00/2024-04-04T22:00:00",
        "2024-04-05T16:00:00/2024-04-05T24:00:00",
        "2024-04-06T16:00:00/2024-04-06T24:00:00"
      ],
      "wage": 12
    },
    {
      "name": "Bartender-Mike",
      "skills": [
        { "name": "bar", "level": 5 },
        { "name": "floor", "level": 2 },
        { "name": "mixology", "level": 5 }
      ],
      "availability": ["2024-04-01T00:00:00/2024-04-07T23:59:59"],
      "preference": ["fri-bar", "sat-bar"],
      "wage": 15
    },
    {
      "name": "Flex-Alex",
      "skills": [
        { "name": "kitchen", "level": 2 },
        { "name": "floor", "level": 3 },
        { "name": "bar", "level": 2 },
        { "name": "host", "level": 3 }
      ],
      "availability": ["2024-04-01T00:00:00/2024-04-07T23:59:59"],
      "wage": 14
    }
  ],
  "shifts": [
    { "name": "mon-lunch-kitchen", "from": "2024-04-01T10:00:00", "to": "2024-04-01T15:00:00", "skills": [{ "name": "kitchen" }], "min": 2, "max": 3, "tags": [{ "name": "LUNCH" }, { "name": "KITCHEN" }], "priority": 2 },
    { "name": "mon-dinner-kitchen", "from": "2024-04-01T17:00:00", "to": "2024-04-01T23:00:00", "skills": [{ "name": "kitchen" }], "min": 3, "max": 4, "tags": [{ "name": "DINNER" }, { "name": "KITCHEN" }], "priority": 1 },
    { "name": "mon-lunch-floor", "from": "2024-04-01T11:00:00", "to": "2024-04-01T15:00:00", "skills": [{ "name": "floor" }], "min": 2, "max": 3, "tags": [{ "name": "LUNCH" }, { "name": "FLOOR" }], "priority": 2 },
    { "name": "mon-dinner-floor", "from": "2024-04-01T17:00:00", "to": "2024-04-01T23:00:00", "skills": [{ "name": "floor" }], "min": 4, "max": 5, "tags": [{ "name": "DINNER" }, { "name": "FLOOR" }], "priority": 1 },
    { "name": "mon-bar", "from": "2024-04-01T17:00:00", "to": "2024-04-01T24:00:00", "skills": [{ "name": "bar" }], "min": 1, "max": 2, "tags": [{ "name": "EVENING" }, { "name": "BAR" }], "priority": 1 },
    { "name": "fri-dinner-floor", "from": "2024-04-05T17:00:00", "to": "2024-04-06T00:00:00", "skills": [{ "name": "floor" }], "min": 5, "max": 6, "tags": [{ "name": "DINNER" }, { "name": "FLOOR" }, { "name": "PREMIUM" }], "priority": 1 },
    { "name": "fri-bar", "from": "2024-04-05T18:00:00", "to": "2024-04-06T01:00:00", "skills": [{ "name": "bar" }], "min": 2, "max": 3, "tags": [{ "name": "EVENING" }, { "name": "BAR" }, { "name": "PREMIUM" }], "priority": 1 },
    { "name": "sat-dinner-floor", "from": "2024-04-06T17:00:00", "to": "2024-04-07T00:00:00", "skills": [{ "name": "floor" }], "min": 6, "max": 7, "tags": [{ "name": "DINNER" }, { "name": "FLOOR" }, { "name": "PREMIUM" }], "priority": 1 },
    { "name": "sat-bar", "from": "2024-04-06T18:00:00", "to": "2024-04-07T01:00:00", "skills": [{ "name": "bar" }], "min": 2, "max": 3, "tags": [{ "name": "EVENING" }, { "name": "BAR" }, { "name": "PREMIUM" }], "priority": 1 },
    { "name": "sat-lunch-prep", "from": "2024-04-06T08:00:00", "to": "2024-04-06T12:00:00", "skills": [{ "name": "prep" }], "min": 1, "max": 2, "tags": [{ "name": "MORNING" }, { "name": "PREP" }], "priority": 2 }
  ],
  "rules": [
    { "constraint": "COUNTER", "type": "HOURS_WORKED", "max": 45, "period": { "duration": "P7D" } },
    { "constraint": "SEQUENCE", "type": "WORKING_DAYS", "max": 6 },
    { "constraint": "COUNTER", "type": "WORKING_SHIFT_TYPE", "shifts": ["PREMIUM"], "min": 1, "max": 3, "period": { "duration": "P7D" } }
  ],
  "rests": [{ "tags": ["EVENING"], "sequence": "AFTER", "min": "PT10H" }],
  "patterns": [
    { "type": "MULTI_DAY", "satisfy": "PROHIBITED", "elements": [{ "type": "ON", "tags": ["EVENING"] }, { "type": "ON", "tags": ["MORNING"] }], "weight": 100 },
    { "type": "SINGLE_DAY", "satisfy": "PREFERRED", "elements": [{ "type": "ON", "tags": ["LUNCH"] }, { "type": "OFF" }, { "type": "ON", "tags": ["DINNER"] }], "weight": 10 }
  ],
  "requirements": [
    { "shifts": ["mon-dinner-kitchen", "fri-dinner-kitchen", "sat-dinner-kitchen"], "skill": "head-chef", "value": 1 },
    { "shifts": ["fri-dinner-floor", "sat-dinner-floor"], "skill": "host", "value": 1 }
  ],
  "fairnessBuckets": [
    { "employees": ["Server-James", "Server-Emma", "Flex-Alex"], "shifts": ["fri-dinner-floor", "sat-dinner-floor", "fri-bar", "sat-bar"], "period": { "from": "2024-04-01", "to": "2024-04-30" }, "target": "PT20H" }
  ],
  "options": { "hardAvailability": true, "hardSkill": true },
  "weights": { "skills": "100hard", "minRest": "50hard", "pref": "15medium", "wages": "2soft" }
}
{
  "id": "restaurant-schedule-001",
  "status": "SOLVED",
  "score": { "hardScore": 0, "mediumScore": -1, "softScore": -650, "feasible": true },
  "assignments": [
    { "shift": "mon-lunch-kitchen", "employee": "Chef-Marco" },
    { "shift": "mon-lunch-kitchen", "employee": "Cook-Lisa" },
    { "shift": "mon-dinner-kitchen", "employee": "Chef-Marco" },
    { "shift": "mon-dinner-kitchen", "employee": "Cook-Lisa" },
    { "shift": "mon-dinner-kitchen", "employee": "Flex-Alex" },
    { "shift": "mon-lunch-floor", "employee": "Server-James" },
    { "shift": "mon-lunch-floor", "employee": "Server-Emma" },
    { "shift": "mon-dinner-floor", "employee": "Server-James" },
    { "shift": "mon-dinner-floor", "employee": "Server-Emma" },
    { "shift": "mon-bar", "employee": "Bartender-Mike" },
    { "shift": "fri-dinner-floor", "employee": "Server-James" },
    { "shift": "fri-bar", "employee": "Bartender-Mike" },
    { "shift": "sat-dinner-floor", "employee": "Server-Emma" },
    { "shift": "sat-dinner-floor", "employee": "Flex-Alex" },
    { "shift": "sat-bar", "employee": "Bartender-Mike" },
    { "shift": "sat-lunch-prep", "employee": "Cook-Lisa" }
  ],
  "unassigned": [],
  "violations": [
    { "name": "Shift Preference", "value": 1, "level": "MEDIUM" },
    { "name": "Wage Costs", "value": 650, "level": "SOFT" }
  ]
}
The solution addresses key hospitality scheduling challenges:
  1. Role Coverage: Head chef present for all dinner services
  2. No Clopening: Evening→morning pattern prohibited
  3. Premium Fair Distribution: Weekend shifts distributed across servers
  4. Multi-Skill Usage: Flex-Alex assigned based on need (kitchen or floor)
  5. Split Shift Support: Same employees can work lunch and dinner with break
All service periods covered with appropriate skill levels while respecting rest requirements.

Key Hospitality Features

Multi-Skill Employees

Leverage cross-trained staff:
{
  "employees": [{
    "name": "Flex-Worker",
    "skills": [
      { "name": "kitchen", "level": 2 },
      { "name": "floor", "level": 3 },
      { "name": "bar", "level": 2 }
    ]
  }]
}

Clopening Prevention

Prohibit close-then-open sequences:
{
  "patterns": [
    {
      "type": "MULTI_DAY",
      "satisfy": "PROHIBITED",
      "elements": [
        { "type": "ON", "tags": ["EVENING"] },
        { "type": "ON", "tags": ["MORNING"] }
      ]
    }
  ]
}
“Clopening” (closing then opening) shifts are a major cause of employee burnout. Always prohibit these patterns.

Premium Shift Limits

Ensure fair access to high-tip shifts:
{
  "rules": [
    {
      "constraint": "COUNTER",
      "type": "WORKING_SHIFT_TYPE",
      "shifts": ["PREMIUM"],
      "min": 1,
      "max": 3,
      "period": { "duration": "P7D" }
    }
  ]
}

Role Requirements by Service

Ensure key roles during busy periods:
{
  "requirements": [
    {
      "shifts": ["fri-dinner", "sat-dinner"],
      "skill": "head-chef",
      "value": 1
    },
    {
      "shifts": ["fri-dinner-floor", "sat-dinner-floor"],
      "skill": "host",
      "value": 1
    }
  ]
}

Common Hospitality Patterns

{
  "shifts": [
    {
      "name": "lunch-service",
      "from": "11:00",
      "to": "15:00",
      "tags": [{ "name": "LUNCH" }]
    },
    {
      "name": "dinner-service",
      "from": "17:00",
      "to": "23:00",
      "tags": [{ "name": "DINNER" }]
    }
  ],
  "patterns": [{
    "type": "SINGLE_DAY",
    "satisfy": "PREFERRED",
    "elements": [
      { "type": "ON", "tags": ["LUNCH"] },
      { "type": "OFF" },
      { "type": "ON", "tags": ["DINNER"] }
    ]
  }]
}
{
  "shifts": [{
    "name": "private-event",
    "from": "2024-04-15T18:00:00",
    "to": "2024-04-16T02:00:00",
    "skills": [{ "name": "floor" }],
    "min": 8,
    "max": 10,
    "tags": [{ "name": "EVENT" }, { "name": "PREMIUM" }],
    "cost": 200
  }]
}
{
  "requirements": [
    { "shifts": ["dinner-kitchen"], "skill": "head-chef", "value": 1 },
    { "shifts": ["dinner-kitchen"], "skill": "sous-chef", "value": 1 },
    { "shifts": ["dinner-kitchen"], "skill": "line-cook", "value": 2 }
  ]
}
{
  "shifts": [{
    "name": "bar-shift",
    "skills": [
      { "name": "bar" },
      { "name": "alcohol-license" }
    ]
  }],
  "options": { "hardSkill": true }
}

Hospitality-Specific Constraints

Late Night Rest

Enforce rest after late closes:
{
  "rests": [
    {
      "tags": ["LATE"],
      "sequence": "AFTER",
      "min": "PT11H"
    }
  ]
}

Weekend Rotation

Ensure staff get some weekends off:
{
  "rules": [
    {
      "constraint": "COUNTER",
      "type": "WEEKENDS_IDLE",
      "min": 1,
      "period": { "from": "2024-04-01", "to": "2024-04-30" }
    }
  ],
  "options": {
    "idleWeekend": {
      "fromDayOfWeek": "FRIDAY",
      "fromTime": "17:00:00",
      "toDayOfWeek": "SUNDAY",
      "toTime": "23:59:00"
    }
  }
}

Tip Pool Fairness

Balance access to high-earning shifts:
{
  "fairnessBuckets": [
    {
      "employees": ["Server-1", "Server-2", "Server-3", "Server-4"],
      "shifts": ["fri-dinner", "sat-dinner", "sun-brunch"],
      "period": { "from": "2024-04-01", "to": "2024-04-30" },
      "target": "PT24H"
    }
  ]
}