Shifty Dokumentation
AdministrationCustom configurations

Compatibility Checks Algorithm

Compatibility Checks Algorithm

Compatibility Checks sind automatische Prüfungen, die beim Zuweisen von Schichten durchgeführt werden. Sie helfen Admins, sichere und passende Zuweisungen zu treffen.

Für Admins

Was ist eine Kompatibilitätsprüfung?

Wenn du einen Mitarbeiter zu einer Schicht zuordnen möchtest, prüft das System automatisch, ob es Probleme gibt:

  • Overlapping Shifts — Hat der Mitarbeiter an diesem Datum bereits eine andere Schicht?
  • Position Mismatch — Passt die Position des Mitarbeiters zur Schicht?
  • Required Custom Fields — Hat der Mitarbeiter alle erforderlichen Felder ausgefüllt?
  • Rest Time — Genug Ruhezeiten zwischen Schichten?
  • Working Hours — Überschreitet die tägliche Arbeitszeit?
  • Availability — Ist der Mitarbeiter für diesen Zeitraum verfügbar?

Warnung vs. Blocker

Die Kompatibilitätsprüfung hat zwei Modi:

1. Warnung-Modus (Standard — Strict Mode OFF)

⚠️ Warnung: Position "Koch" erforderlich, Mitarbeiter hat "Aushilfe"
→ [Trotzdem zuweisen]  [Abbrechen]
  • Admin KANN trotzdem zuweisen
  • Das System zeigt nur eine Warnung
  • Sinnvoll für flexible Pläne oder Notfälle

2. Blocker-Modus (Strict Mode ON)

❌ Fehler: Position "Koch" erforderlich, Mitarbeiter hat "Aushilfe"
→ [Abbrechen]
  • Admin KANN NICHT zuweisen
  • Das System blockiert die Zuweisung
  • Sinnvoll für strikte Anforderungen (Lizenz, Sicherheit)

Wie Strict Mode die Kompatibilität beeinflusst

Strict Mode OFF (Standard):

  • Position Mismatch → Warnung (Admin kann ignorieren)
  • Required Custom Fields missing → Warnung
  • Overlap with other shift → Warnung
  • Working Hours too high → Warnung

Strict Mode ON:

  • Position Mismatch → Blocker (Zuweisung nicht möglich)
  • Required Custom Fields missing → Blocker
  • Overlap with other shift → Blocker
  • Working Hours too high → Warnung (bleibt Warnung)

Kritische Probleme (immer Blocker, unabhängig von Strict Mode):

  • Mitarbeiter ist bereits zu dieser Schicht zugewiesen
  • Mitarbeiter Vertrag endet vor der Schicht
  • Externe API-Anforderung fehlgeschlagen

Kompatibilitätsprüfungen im Detail

1. Überlappende Schichten (Blocking — immer)

Problem: Der Mitarbeiter hat bereits eine andere Schicht zu dieser Zeit

Bestehendes Shift:   Montag 09:00 - 17:00
Neue Schicht:        Montag 16:00 - 22:00
                             ^^^^^^ Überlappung!

Aktion: System blockiert (egal welcher Modus)

Lösung: Wähle einen anderen Mitarbeiter oder ändere die neue Schicht

2. Position Mismatch (Warning or Blocker)

Problem: Mitarbeiter hat die erforderliche Position nicht

Schicht erforderlich: Position "Koch"
Mitarbeiter hat:     Position "Aushilfe"

Strict Mode OFF: ⚠️ Warnung Strict Mode ON: ❌ Blocker

Lösung:

  • Position zum Mitarbeiter hinzufügen, ODER
  • Andere Schicht/Mitarbeiter wählen

3. Erforderliche Custom Fields (Warning or Blocker)

Problem: Schicht erfordert ein Custom Field, Mitarbeiter hat es nicht

Schicht erfordert: "Gabelstaplerführerschein" = true
Mitarbeiter hat:   "Gabelstaplerführerschein" = false/leer

Strict Mode OFF: ⚠️ Warnung Strict Mode ON: ❌ Blocker

Lösung:

  • Mitarbeiter-Profil aktualisieren und Feld ausfüllen, ODER
  • Andere Anforderung für die Schicht setzen

4. Ruhezeit zwischen Schichten (Warning or Blocker)

Problem: Nicht genug Ruhezeit zwischen Schichten

Gestrige Schicht:   Sonntag 08:00 - 17:00
Neue Schicht:       Montag 06:00 - 14:00
                    ↑ Nur 13 Stunden Ruhe (mindestens 10 erforderlich)

Strict Mode OFF: ⚠️ Warnung Strict Mode ON: ❌ Blocker (bei 10+ Stunden Anforderung)

5. Tägliche Arbeitszeit (Warning — immer)

Problem: Zu viele Stunden an einem Tag

Mitarbeiter hat bereits: 7 Stunden heute
Neue Schicht:           6 Stunden
Gesamt:                 13 Stunden (max. 12 erlaubt)

Aktion: ⚠️ Warnung (immer, auch mit Strict Mode OFF)

Grenze: Maximal 12 Stunden pro Tag

6. Verfügbarkeit (Warning or Blocker)

Problem: Mitarbeiter hat für diese Zeit keine Verfügbarkeit eingegeben

Mitarbeiter Verfügbarkeit: Montag 09:00 - 17:00
Neue Schicht:              Montag 16:00 - 22:00
                                   ↑ Ab 17 Uhr nicht verfügbar

Strict Mode OFF: ⚠️ Warnung (nur wenn availabilitiesEnabled = true) Strict Mode ON: ⚠️ Warnung (bleibt Warnung)


Konfigurationsbeispiele

Szenario 1: Restaurant — Flexible Aushilfen

Strict Mode:                OFF
Verfügbarkeiten:           AN
Position Restrictions:    OFF
Required Custom Fields:   Keine

Auswirkung:
- Admins können relativ frei zuweisen
- Warnungen erinnern an Probleme, blockieren aber nicht
- Ideal für schnelle, flexible Planung

Szenario 2: Klinik — Strikte Anforderungen

Strict Mode:                ON
Verfügbarkeiten:            AN
Position Restrictions:      ON
Required Custom Fields:
  - "Erste Hilfe Kurs" (required = true)
  - "Ärztliche Freigabe" (required = true)

Auswirkung:
- Nur qualifiziertes Personal kann Schichten sehen (Position Restrict ON)
- Admins können nur zuweisen wenn beide Zertifikate vorhanden
- Strikte Einhaltung von Ruhezeiten und Arbeitszeiten

Szenario 3: Events — Projekt-Teams

Strict Mode:                OFF
Verfügbarkeiten:            AUS (Event-spezifisch geplant)
Position Restrictions:      ON
Required Custom Fields:
  - "Event-Rolle" (required = true)

Auswirkung:
- Mitarbeiter sehen nur Schichten ihrer Position
- Event-Rolle beschreibt spezifische Funktion beim Event
- Admins haben Flexibilität bei Zuweisungen

Häufige Probleme & Lösungen

Problem: "Mitarbeiter kann dieser Schicht nicht zugewiesen werden" Mögliche Gründe:

  1. Position passt nicht (check mit Position Restrictions)
  2. Strict Mode ist ON und ein Feld passt nicht
  3. Mitarbeiter hat Konflikt mit anderer Schicht
  4. Zu viele Arbeitszeiten bereits eingeplant

Lösung:

  1. Lies die Fehlermeldung genau
  2. Bethe den Grund (Position, Feld, Zeit, Verfügbarkeit)
  3. Behebe das Problem (Position ändern, Feld ausfüllen, andere Schicht wählen)

For Developers

Overview

The compatibility check algorithm is implemented in src/sections/admin-calendar-v2/daily-planning/utils/compatibility-check.ts.

Main function:

export const checkCompatibility = (props: CompatibilityProps): CompatibilityResult

Input props:

type CompatibilityProps = {
    team: Partial<DBTeam>; // Team config
    employee: any; // Employee data
    shift: KanbanBoardShift; // Shift being assigned
    todaysShiftData?: KanbanBoardShift[];
    yesterdaysShiftData: DBShift<true>[];
    tomorrowsShiftData: DBShift<true>[];
    availabilityTimeSpan?: { from: Date | string | null; to: Date | string | null };
    scheduleType?: DBScheduleType;
    eventCustomers?: Array<{ id: number; name: string }>;
};

Output:

type CompatibilityResult = {
    isCompatible: boolean; // No issues
    isBlocking: boolean; // Has blocking issues (from isBlocking flag)
    reasons: IncompatibilityReason[]; // Sorted: critical → warning → info
};

type IncompatibilityReason = {
    id: string;
    summary: string;
    details: string;
    severity: '1-critical' | '2-warning' | '3-info';
    isBlocking?: boolean; // If true, cannot assign (regardless of strictMode)
};

Critical Checks (Always Blocking)

These checks set isBlocking: true unconditionally:

  1. Contract End Date

    • If employee.lockedAt <= shift.dateTo, block entire assignment
    • Code: L110-125
  2. Already Assigned

    • If shift.assignments.some(a => a.userId === employee.userId), block
    • Code: L128-134
  3. Shift Overlap

    • If new shift overlaps with any existing assignment, block
    • Calculated using areIntervalsOverlapping() with date-fns
    • Code: L137-166

Warning/Info Checks (Affected by strictModeEnabled)

These checks add warnings; if strictModeEnabled = true, they become blocking:

  1. Rest Time Between Shifts

    • Minimum minHoursBetweenShifts (typically 10 hours)
    • Code: L170-200
  2. Daily Working Hours

    • Warning threshold: 10 hours
    • Maximum: 12 hours (warning even without strict mode)
    • Code: L203-230
  3. Position Mismatch

    • If positionIds.length > 0 and !positionIds.includes(shift.positionId)
    • Code: L387-393
    • if (positionIds && positionIds.length > 0 && !positionIds.includes(shift.positionId)) {
          incompatibilities.push({
              id: 'not-qualified',
              severity: '2-warning',
          });
      }
  4. Availability Time Span Mismatch (if availabilitiesEnabled)

    • If availability times don't cover shift times
    • Code: L354-382
  5. Required Custom Fields

    • Checks shift.requiredUserFields against team.customUserFields
    • For each required field, checks if employee.user.customFields[fieldId] === true
    • Code: L396-407
    • for (const requiredField of shift.requiredUserFields) {
          const field = team?.customUserFields?.find((f) => f.id === requiredField);
          if (employee.user.customFields?.[requiredField] !== true) {
              incompatibilities.push({
                  id: `missing-${requiredField}`,
                  severity: '2-warning',
              });
          }
      }

Converting Warnings to Blockers

When strictModeEnabled = true:

const strictModeEnabled = team.strictModeEnabled ?? true;

// After collecting all incompatibilities:
if (strictModeEnabled) {
    incompatibilities.forEach((reason) => {
        if (reason.severity !== '1-critical') {
            reason.isBlocking = true; // Convert warning → blocker
        }
    });
}

Then the UI checks:

if (compatibilityResult.isBlocking) {
    // Show error dialog, prevent assignment
} else {
    // Show warning, allow "Proceed anyway" button
}

Usage in DnD & Assignment UI

Called from:

  • src/sections/admin-calendar-v2/daily-planning/hooks/use-admin-calendar-dnd.ts — Drag-and-drop feedback
  • src/sections/admin-calendar-v2/dialogs/quick-assign-dialog-staff.tsx — Staff quick-assign
  • src/sections/admin-calendar-v2/dialogs/bulk-assign-dialog.tsx — Bulk operations

Each caller passes the full context (today, yesterday, tomorrow shift data) so compatibility can consider adjacent days for rest-time checks.

Key Design Insights

  1. Separation of Concerns:

    • Position filtering (visibility) is separate from compatibility (assignment feedback)
    • Restrict Positions hides shifts; Compatibility warns/blocks assignment
  2. Strictness Levels:

    • Critical = always blocking
    • Warnings = blocking if strict mode, allowed with warning if not
    • Info = never blocking
  3. Custom Field Integration:

    • Custom fields are treated like other binary checks
    • requiredUserFields array in shift definition
    • Customizable per shift, enforced per-team via customUserFields config
  4. Time-Aware Checks:

    • All checks account for shift time spans, not just dates
    • interval() and areIntervalsOverlapping() from date-fns for precise comparisons

Future Extensions

  • Add skill-based compatibility (not just position/fields)
  • Add customer affinity checks (User-Customer Relations for filtering)
  • Add workload balancing (fair distribution of hours)
  • Add external API validation (third-party qualification checks)

On this page