{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/vigotime-com/json-schema/vigotime-com-solve-request-schema.json",
  "title": "SolveRequest",
  "description": "Self-contained solve request — all data travels in the payload, no server-side lookups.",
  "x-generated": "2026-10-30",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/vigotime-com-openapi.json#/components/schemas/SolveRequest",
  "properties": {
    "area_groups": {
      "anyOf": [
        {
          "items": {
            "additionalProperties": true,
            "type": "object"
          },
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "description": "Area groups (vigotime entity format)",
      "title": "Area Groups"
    },
    "availability": {
      "anyOf": [
        {
          "additionalProperties": {
            "additionalProperties": {
              "type": "boolean"
            },
            "type": "object"
          },
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "description": "Verfügbarkeit je Mitarbeiter und Datum: {employeeId: {'2026-09-01': true}}. false = an dem Tag nicht einsetzbar.",
      "title": "Availability"
    },
    "collective_agreements": {
      "anyOf": [
        {
          "additionalProperties": {
            "additionalProperties": true,
            "type": "object"
          },
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "description": "Collective agreements (agreement_id -> agreement; vigotime entity format). Carries the FR-239 tariff working-time limits so a tariff-bound stateless solve enforces them (DEF-BRAVO-STATELESS-COLLECTIVE-AGREEMENT-01).",
      "title": "Collective Agreements"
    },
    "config": {
      "anyOf": [
        {
          "$ref": "#/$defs/GenerationConfigSchema"
        },
        {
          "type": "null"
        }
      ],
      "description": "Solver configuration"
    },
    "cycle_history": {
      "anyOf": [
        {
          "additionalProperties": {
            "$ref": "#/$defs/CycleHistorySchema"
          },
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "description": "Optional #500 own published selected-duty facts: ruleId:consequenceId (legacy: selector) -> asOf, dated anchors by employee, previousEmployees. Missing context is unknown; no phase is inferred from generic worked dates.",
      "title": "Cycle History"
    },
    "department": {
      "additionalProperties": true,
      "description": "Department as JSON object in the vigotime entity format (camelCase)",
      "title": "Department",
      "type": "object"
    },
    "employee_boundary_week_hours": {
      "anyOf": [
        {
          "additionalProperties": {
            "type": "number"
          },
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "description": "Bereits gearbeitete Stunden in der ISO-Woche des Fensterstarts, VOR dem Start, je MA. Für die Wochenkappe der angeschnittenen Woche.",
      "title": "Employee Boundary Week Hours"
    },
    "employee_history": {
      "anyOf": [
        {
          "additionalProperties": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "description": "Gearbeitete Tage vor dem Fenster je MA (ISO-Daten). Für Folgetage- und datums-gekoppelte Regeln über die Plangrenze.",
      "title": "Employee History"
    },
    "employee_last_shift_end": {
      "anyOf": [
        {
          "additionalProperties": {
            "type": "string"
          },
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "description": "Endzeitpunkt der letzten Schicht vor dem Fenster je MA (ISO-Datetime, tz-aware empfohlen). Für die Mindestruhe am ersten Plantag.",
      "title": "Employee Last Shift End"
    },
    "employee_next_shift_types": {
      "anyOf": [
        {
          "additionalProperties": {
            "additionalProperties": {
              "items": {
                "enum": [
                  "early",
                  "late",
                  "night",
                  "custom"
                ],
                "type": "string"
              },
              "type": "array"
            },
            "type": "object"
          },
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "description": "Known published following whole services: employee -> ISO day -> declared shift types (early/late/night/custom), within ten days after end_date. Missing dates are unknown, never inferred free days. Optional backward-compatible #294/#315 seam facts.",
      "title": "Employee Next Shift Types"
    },
    "employee_prior_night_run": {
      "anyOf": [
        {
          "additionalProperties": {
            "type": "integer"
          },
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "description": "Länge der am Vortag endenden Nachtserie je MA. Für Nachterholung über die Plangrenze.",
      "title": "Employee Prior Night Run"
    },
    "employee_prior_shift_type_runs": {
      "anyOf": [
        {
          "additionalProperties": {
            "additionalProperties": {
              "minimum": 0.0,
              "type": "integer"
            },
            "propertyNames": {
              "enum": [
                "early",
                "late",
                "night",
                "custom"
              ]
            },
            "type": "object"
          },
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "description": "Ununterbrochene veröffentlichte Vorplanfolge je MA und Schichttyp (early/late/night/custom). Zählt für MUSS/SOLLTE/HÖCHSTENS über die Plangrenze. Bei vorhandener MA-Zuordnung ersetzt sie nur den älteren Block-Nachtzähler; Nachterholung verwendet weiterhin employee_prior_night_run.",
      "title": "Employee Prior Shift Type Runs"
    },
    "employee_prior_shift_types": {
      "anyOf": [
        {
          "additionalProperties": {
            "additionalProperties": {
              "items": {
                "enum": [
                  "early",
                  "late",
                  "night",
                  "custom"
                ],
                "type": "string"
              },
              "type": "array"
            },
            "type": "object"
          },
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "description": "All declared types from published prior whole services: employee -> ISO day -> types. Dates must precede start_date by at most 62 days. Unlike a consecutive run, this retains earlier same-ISO-week types for diversity and direct boundary rotation (#282).",
      "title": "Employee Prior Shift Types"
    },
    "employees": {
      "description": "Employees as JSON objects in the vigotime entity format (camelCase). Set isSubstitute=true explicitly for need-only automatic planning. Contract type and reactive invitation-pool membership do not imply this role.",
      "items": {
        "additionalProperties": true,
        "type": "object"
      },
      "title": "Employees",
      "type": "array"
    },
    "end_date": {
      "description": "Last day of the planning window (inclusive)",
      "format": "date",
      "title": "End Date",
      "type": "string"
    },
    "fairness_history": {
      "anyOf": [
        {
          "$ref": "#/$defs/FairnessHistorySchema"
        },
        {
          "type": "null"
        }
      ],
      "description": "Rolling annual load account for weekend/distributeEvenly fairness. Pass published facts, including absences and dated preferences. {} starts a new account; omission preserves window-local fairness. No additional database reads."
    },
    "holiday_dates": {
      "anyOf": [
        {
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "description": "Feiertage als ISO-Datumsliste (z. B. ['2026-12-25']). Steuert holiday/isHoliday-Regeln; ohne Angabe gilt der eingebaute deutsche Feiertags-Superset.",
      "title": "Holiday Dates"
    },
    "hourly_rates": {
      "anyOf": [
        {
          "additionalProperties": {
            "type": "number"
          },
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "description": "Per-employee hourly rate",
      "title": "Hourly Rates"
    },
    "locked_assignments": {
      "anyOf": [
        {
          "items": {
            "additionalProperties": true,
            "type": "object"
          },
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "description": "Vorbelegte/handgesetzte Schichten, die fix bleiben. Je Eintrag {employeeId, shiftDefinitionId, date}. Der Solver plant um sie herum.",
      "title": "Locked Assignments"
    },
    "planning_rules": {
      "anyOf": [
        {
          "items": {
            "additionalProperties": true,
            "type": "object"
          },
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "description": "Planning rules (vigotime entity format)",
      "title": "Planning Rules"
    },
    "preferences": {
      "anyOf": [
        {
          "additionalProperties": {
            "additionalProperties": true,
            "type": "object"
          },
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "description": "Per-employee preferences",
      "title": "Preferences"
    },
    "previous_assignments": {
      "anyOf": [
        {
          "items": {
            "additionalProperties": true,
            "type": "object"
          },
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "description": "Zuweisungen des Vorplans (Stabilität/Replan): {employeeId, shiftId, date}. Der Solver bleibt möglichst nah daran (minimale Änderung).",
      "title": "Previous Assignments"
    },
    "qualifications": {
      "anyOf": [
        {
          "additionalProperties": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "description": "Employee qualifications (employee_id -> qualification ids); derived from employees if omitted",
      "title": "Qualifications"
    },
    "shifts": {
      "description": "Shift definitions as JSON objects in the vigotime entity format (camelCase)",
      "items": {
        "additionalProperties": true,
        "type": "object"
      },
      "title": "Shifts",
      "type": "array"
    },
    "sick_leaves": {
      "anyOf": [
        {
          "additionalProperties": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "description": "Sick-leave dates per employee",
      "title": "Sick Leaves"
    },
    "social_points": {
      "anyOf": [
        {
          "additionalProperties": {
            "type": "number"
          },
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "description": "Social-Points-GUTHABEN je Mitarbeiter: {employeeId: 100}. Die Punkte, die eine Person für Wunscherfüllungen 'ausgeben' kann. Überschreibt ein ggf. am Mitarbeiter gesetztes socialPoints-Feld. Zusammen mit wish_costs aktiv → weiches Budget: die Summe der gewährten Wunschkosten SOLL das Guthaben nicht übersteigen (Überschreitung = Strafe, nie unlösbar). Ohne wish_costs wirkungslos.",
      "title": "Social Points"
    },
    "soft_code_assignments": {
      "anyOf": [
        {
          "additionalProperties": {
            "items": {
              "additionalProperties": true,
              "type": "object"
            },
            "type": "array"
          },
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "description": "Kürzel als weiche Vorgaben, gruppiert nach {'should': [...], 'may': [...]}. Je Eintrag {employeeId, date, ...}.",
      "title": "Soft Code Assignments"
    },
    "staffing_rules": {
      "anyOf": [
        {
          "items": {
            "additionalProperties": true,
            "type": "object"
          },
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "description": "Staffing rules (vigotime entity format)",
      "title": "Staffing Rules"
    },
    "start_date": {
      "description": "First day of the planning window (inclusive)",
      "format": "date",
      "title": "Start Date",
      "type": "string"
    },
    "vacations": {
      "anyOf": [
        {
          "additionalProperties": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "description": "Full vacation calendar days per employee (00:00-24:00). Every overlapping original shift is blocked, including a previous-day night. Include known vacation on the day after end_date for overnight shifts. Shifts are never split; missing vacation data cannot be inferred.",
      "title": "Vacations"
    },
    "webhook_secret": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "description": "Optional shared secret. If set, the webhook request carries an HMAC-SHA256 signature in the X-Vigotime-Signature header.",
      "title": "Webhook Secret"
    },
    "webhook_url": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "description": "Optional https URL that is POSTed once the solve finishes (completed or failed).",
      "title": "Webhook Url"
    },
    "wish_costs": {
      "anyOf": [
        {
          "additionalProperties": {
            "additionalProperties": {
              "type": "number"
            },
            "type": "object"
          },
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "description": "KOSTEN (pointCost) einer Wunscherfüllung je Mitarbeiter und Datum: {employeeId: {'2026-09-03': 20}}. Der bezahlte Preis eines gewünschten freien Tages (z. B. baseCostPerDay × dayTypeMultiplier × priorityMultiplier). Wenn gesetzt, gewichtet der Solver das Honorieren PROPORTIONAL zum Preis (mehr bezahlt → stärker honoriert), statt nur nach grobem low/normal/high-Label. Speist zudem das Social-Points-Budget.",
      "title": "Wish Costs"
    },
    "wish_priorities": {
      "anyOf": [
        {
          "additionalProperties": {
            "additionalProperties": {
              "type": "string"
            },
            "type": "object"
          },
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "description": "Wunsch-Priorität je Mitarbeiter und Datum: {employeeId: {'2026-09-03': 'high'}}. low/normal/high → Gewicht 0.5/1.0/2.0 (Social-Points-Gewichtung).",
      "title": "Wish Priorities"
    },
    "wish_specs": {
      "anyOf": [
        {
          "additionalProperties": {
            "items": {
              "additionalProperties": true,
              "type": "object"
            },
            "type": "array"
          },
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "description": "Differenzierte Wunsch-Spezifikationen je MA (z. B. Wochenend-Atomarität, Serien). Feinere Steuerung als die flache wishes-Map.",
      "title": "Wish Specs"
    },
    "wishes": {
      "anyOf": [
        {
          "additionalProperties": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "description": "Wished dates per employee",
      "title": "Wishes"
    },
    "workplace_duration_rules": {
      "anyOf": [
        {
          "items": {
            "additionalProperties": true,
            "type": "object"
          },
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "description": "Workplace duration rules (vigotime entity format): target/covered duration per person at a workplace on the wp_assign axis. severity 'must' -> HARD bound, 'should' -> SOFT target. Omitted/empty -> inert (B0 Phase 3, Issue #57 Feature-2/B1).",
      "title": "Workplace Duration Rules"
    },
    "workplaces": {
      "anyOf": [
        {
          "items": {
            "additionalProperties": true,
            "type": "object"
          },
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "description": "Workplaces (vigotime entity format)",
      "title": "Workplaces"
    }
  },
  "required": [
    "start_date",
    "end_date",
    "employees",
    "shifts",
    "department"
  ],
  "type": "object",
  "$defs": {
    "CycleHistorySchema": {
      "description": "Dated own published selected-duty facts, keyed per rule/consequence.",
      "properties": {
        "anchors": {
          "additionalProperties": {
            "format": "date",
            "type": "string"
          },
          "title": "Anchors",
          "type": "object"
        },
        "asOf": {
          "format": "date",
          "title": "Asof",
          "type": "string"
        },
        "previousDayKnown": {
          "default": true,
          "title": "Previousdayknown",
          "type": "boolean"
        },
        "previousEmployees": {
          "items": {
            "type": "string"
          },
          "title": "Previousemployees",
          "type": "array"
        },
        "unknownAnchors": {
          "items": {
            "type": "string"
          },
          "title": "Unknownanchors",
          "type": "array"
        }
      },
      "required": [
        "asOf"
      ],
      "title": "CycleHistorySchema",
      "type": "object"
    },
    "FairnessHistorySchema": {
      "description": "Published facts supplied by a stateless caller, never read from other tenants.",
      "properties": {
        "absences": {
          "additionalProperties": {
            "items": {
              "format": "date",
              "type": "string"
            },
            "type": "array"
          },
          "description": "Historical absence dates by employee, excluded from the expected load share.",
          "title": "Absences",
          "type": "object"
        },
        "assignments": {
          "description": "Published assignments BEFORE start_date: employeeId, shiftDefinitionId, date. Only the preceding 12 calendar months count; drafts must be excluded by the caller.",
          "items": {
            "additionalProperties": true,
            "type": "object"
          },
          "title": "Assignments",
          "type": "array"
        },
        "preferences": {
          "description": "Dated employeePreferences records (active prefer shift/weekday). Voluntary load counts at half weight; weekdays use Sunday=0.",
          "items": {
            "additionalProperties": true,
            "type": "object"
          },
          "title": "Preferences",
          "type": "array"
        },
        "shift_definitions": {
          "description": "Historical shift definitions, including retired types, in the normal entity format. Needed for historical shifts absent from the current window.",
          "items": {
            "additionalProperties": true,
            "type": "object"
          },
          "title": "Shift Definitions",
          "type": "array"
        }
      },
      "title": "FairnessHistorySchema",
      "type": "object"
    },
    "GenerationConfigSchema": {
      "description": "Configuration for schedule generation.",
      "properties": {
        "enabled_constraints": {
          "anyOf": [
            {
              "items": {
                "type": "string"
              },
              "type": "array"
            },
            {
              "type": "null"
            }
          ],
          "description": "List of constraint names to enable (None = all)",
          "title": "Enabled Constraints"
        },
        "enabled_objectives": {
          "anyOf": [
            {
              "items": {
                "type": "string"
              },
              "type": "array"
            },
            {
              "type": "null"
            }
          ],
          "description": "List of objective names to enable (None = all)",
          "title": "Enabled Objectives"
        },
        "max_solutions": {
          "default": 1,
          "description": "Number of alternative solutions to generate (1-5)",
          "maximum": 5.0,
          "minimum": 1.0,
          "title": "Max Solutions",
          "type": "integer"
        },
        "num_workers": {
          "default": 0,
          "description": "Number of solver threads (0 = auto)",
          "maximum": 16.0,
          "minimum": 0.0,
          "title": "Num Workers",
          "type": "integer"
        },
        "objective_weights": {
          "anyOf": [
            {
              "additionalProperties": {
                "type": "integer"
              },
              "type": "object"
            },
            {
              "type": "null"
            }
          ],
          "description": "Custom weights for objectives",
          "title": "Objective Weights"
        },
        "timeout_seconds": {
          "default": 60,
          "description": "Maximum solving time in seconds (5-600)",
          "maximum": 600.0,
          "minimum": 5.0,
          "title": "Timeout Seconds",
          "type": "integer"
        }
      },
      "title": "GenerationConfigSchema",
      "type": "object"
    }
  }
}