14 KiB
LeanderShiftPlannerV2 – Technische Dokumentation
Version: 2.0.1
Sprache: C# / .NET 9.0
Framework: Avalonia UI 11.2.1
Repository: https://gitea.leanderserver.de/leander19961/LeanderShiftPlannerV2
Inhaltsverzeichnis
- Projektübersicht
- Systemvoraussetzungen & Abhängigkeiten
- Projektstruktur
- Datenmodell
- 4.1 Person
- 4.2 Shift (Schicht)
- 4.3 ShiftPlan
- 4.4 Timesheet (Stundenzettel)
- 4.5 Filter
- Services (Geschäftslogik)
- 5.1 AppService
- 5.2 PersonService
- 5.3 ShiftService
- 5.4 ShiftPlanService
- 5.5 FilterService
- 5.6 TimesheetService
- 5.7 ViewService
- Berechnungsalgorithmus
- Datei-I/O (FileIO)
- Benutzeroberfläche (View)
- Ausgabedateien
- Hinweise & Einschränkungen
1. Projektübersicht
LeanderShiftPlannerV2 ist eine Desktop-Anwendung zur automatisierten Erstellung von Schichtplänen. Das Tool erlaubt das Anlegen, Verwalten und Verknüpfen von Personen und Schichten, die anschließende Berechnung aller validen Schichtplankombinationen sowie die automatische Generierung von Stundenzetteln.
Kernfunktionen:
- Verwaltung von Personen (inkl. Wochenstunden und Stundenzettel-Quelle)
- Verwaltung von Schichten (Wochentag, Uhrzeit, Min./Max.-Personenanzahl)
- Bidirektionale Verknüpfung von Personen und Schichten
- Parallele Berechnung aller gültigen Schichtplankombinationen
- Filterung der berechneten Pläne
- Ausgabe als PNG und/oder Textdatei
- Automatische Generierung von Stundenzetteln (Excel-Format, optional Google Calendar-Integration)
Wichtig: Alle Stundenangaben müssen im Wochenstunden-Format erfolgen!
2. Systemvoraussetzungen & Abhängigkeiten
| Anforderung | Details |
|---|---|
| .NET-Version | .NET 9.0 |
| UI-Framework | Avalonia UI 11.2.1 (Cross-Platform: Windows, Linux, macOS) |
| Ausgabetyp | WinExe (Desktop-Anwendung) |
NuGet-Pakete:
| Paket | Version | Verwendung |
|---|---|---|
| Avalonia | 11.2.1 | UI-Framework |
| Avalonia.Desktop | 11.2.1 | Desktop-Unterstützung |
| Avalonia.Themes.Fluent | 11.2.1 | Fluent Design Theme |
| Avalonia.Fonts.Inter | 11.2.1 | Schriftarten |
| EPPlus | 7.5.3 | Excel-Generierung (Stundenzettel) |
| Google.Apis.Calendar.v3 | 1.69.0.3746 | Google Calendar Integration |
| SkiaSharp | 3.118.0-preview | PNG-Rendering der Schichtpläne |
3. Projektstruktur
LeanderShiftPlannerV2/
├── LeanderShiftPlannerV2.sln
└── LeanderShiftPlannerV2/
├── App.axaml / App.axaml.cs # Avalonia-Anwendungseinstieg
├── Program.cs # Main-Einstiegspunkt
├── app.manifest
├── LeanderShiftPlannerV2.csproj
├── Model/ # Datenmodelle (POCOs)
│ ├── Person.cs
│ ├── Shift.cs
│ ├── ShiftPlan.cs
│ ├── Timesheet.cs
│ └── Filter.cs
├── Service/ # Geschäftslogik / Services
│ ├── AppService.cs # Zentraler Service-Container
│ ├── PersonService.cs
│ ├── ShiftService.cs
│ ├── ShiftPlanService.cs # Kernalgorithmus
│ ├── FilterService.cs
│ ├── TimesheetService.cs
│ └── ViewService.cs
├── FileIO/ # Laden/Speichern von Daten
├── View/ # Avalonia AXAML Views
├── Util/ # Hilfsfunktionen
└── Resources/
├── icon/ # Anwendungssymbol
├── font/ # Eingebettete Schriften (Emblem.ttf, Roboto.ttf)
└── templates/
├── timesheet.xlsx # Excel-Vorlage für Stundenzettel
└── googleapi.txt # Google API-Konfiguration
4. Datenmodell
4.1 Person
Datei: Model/Person.cs
Implementiert: INotifyPropertyChanged, [Serializable]
Repräsentiert eine Person, die in Schichten eingeteilt werden kann.
| Eigenschaft | Typ | Beschreibung |
|---|---|---|
FirstName |
string |
Vorname der Person |
Surname |
string |
Nachname der Person |
Hours |
int |
Wöchentliche Arbeitsstunden (Pflichtangabe) |
TimeSheetSource |
string |
Pfad/Quelle für die Stundenzettel-Daten |
Shifts |
ObservableCollection<Shift> |
Liste verknüpfter Schichten (nicht serialisiert) |
Timesheets |
List<Timesheet> |
Liste der Stundenzettel (nicht serialisiert) |
ShiftsString |
string (readonly) |
Lesbare Darstellung aller Schichten für die UI |
Methoden:
AddShift(Shift)/RemoveShift(Shift)/ClearShifts()– Verwaltung der Schichtverknüpfungen (lösen jeweilsPropertyChangedaus)GetTimeSheetByMonth(string month)– Gibt den Stundenzettel für einen bestimmten Monat zurück
4.2 Shift (Schicht)
Datei: Model/Shift.cs
Implementiert: INotifyPropertyChanged, [Serializable]
Repräsentiert eine einzelne Schicht an einem bestimmten Wochentag.
| Eigenschaft | Typ | Beschreibung |
|---|---|---|
Day |
string |
Wochentag (z.B. "Montag") |
StartTime |
string |
Startzeit (Format: "HH:mm") |
EndTime |
string |
Endzeit (Format: "HH:mm") |
Duration |
int |
Dauer der Schicht in Stunden |
ShiftInDay |
int |
Position der Schicht am Tag (1 = erste, 2 = zweite, 3 = dritte) |
MaxPersonCount |
int |
Maximale Anzahl Personen pro Schicht |
MinPersonCount |
int |
Minimale Anzahl Personen pro Schicht |
Persons |
ObservableCollection<Person> |
Verknüpfte Personen (nicht serialisiert) |
PersonsString |
string (readonly) |
Lesbare Darstellung aller Personen für die UI |
Time |
string (readonly) |
Formatierte Zeitanzeige "HH:MM - HH:MM" |
Methoden:
AddPerson(Person)/RemovePerson(Person)/ClearPersons()– Verwaltung der Personenverknüpfungen
4.3 ShiftPlan
Datei: Model/ShiftPlan.cs
Repräsentiert einen vollständigen Schichtplan, der aus einer Kombination von Schichten über alle konfigurierten Wochentage besteht. Wird vom ShiftPlanService erzeugt.
4.4 Timesheet (Stundenzettel)
Datei: Model/Timesheet.cs
Repräsentiert den Stundenzettel einer Person für einen bestimmten Monat. Beinhaltet die Arbeitszeiterfassung und wird wahlweise aus einer lokalen Quelle oder über Google Calendar bezogen.
| Eigenschaft | Typ | Beschreibung |
|---|---|---|
Month |
string |
Monat im Format "MM.YYYY" o.ä. |
4.5 Filter
Datei: Model/Filter.cs
Hält die aktuell gesetzten Filterkriterien für die Anzeige der berechneten Schichtpläne.
5. Services (Geschäftslogik)
5.1 AppService
Datei: Service/AppService.cs
Zentraler Service-Container, der alle anderen Services hält und als einheitlicher Zugriffspunkt dient. Wird bei Anwendungsstart instanziiert und an alle abhängigen Komponenten weitergegeben.
Hält Referenzen auf: PersonService, ShiftService, ShiftPlanService, FilterService, TimesheetService, ViewService
5.2 PersonService
Datei: Service/PersonService.cs
Verwaltet die Liste aller Personen sowie deren Stundenzettel-Daten.
Kernfunktionen:
- CRUD-Operationen für
Person-Objekte - Laden von Stundenzetteln aus einer externen Quelle (
TimeSheetSource) GenerateRandomTimeSheets()– Generiert zufällige Stundenzettel auf Basis von Google Calendar-Einträgen und passt sie an die Wochenstunden der Person an
5.3 ShiftService
Datei: Service/ShiftService.cs
Verwaltet die Liste aller Schichten.
Kernfunktionen:
- CRUD-Operationen für
Shift-Objekte GetShiftList()– Gibt alle konfigurierten Schichten zurück
5.4 ShiftPlanService
Datei: Service/ShiftPlanService.cs
Der Kernservice der Anwendung. Enthält den gesamten Berechnungsalgorithmus für Schichtpläne.
Wichtige Methoden:
| Methode | Beschreibung |
|---|---|
StartCalculation(CancellationToken) |
Startet die vollständige Berechnung (Listen initialisieren → Schichten generieren → Pläne berechnen) |
GeneratePlannedShifts() |
Erzeugt alle möglichen Schichtkombinationen (Permutationen nach Personenanzahl: 1, 2 oder 3 Personen pro Schicht) |
CalculateShiftPlans(CancellationToken) |
Kombiniert die Tagesschichten zu vollständigen Wochenplänen, parallel mit Parallel.ForEach |
CheckShift(List<...>) |
Prüft, ob ein Schichtplan die Wochenstunden aller Personen exakt erfüllt (nicht über- oder unterschreitet) |
GetShiftPlans() |
Gibt die aktuell gefilterte ObservableCollection<ShiftPlan> zurück |
GetAllShiftPlans() |
Gibt alle berechneten Pläne (ungefiltert) zurück |
ResetShiftPlanList() |
Setzt den gefilterten Stand auf alle berechneten Pläne zurück |
5.5 FilterService
Datei: Service/FilterService.cs
Wendet einen Filter auf die Liste der Schichtpläne an und reduziert die angezeigte Liste entsprechend.
5.6 TimesheetService
Datei: Service/TimesheetService.cs
Generiert Stundenzettel-Dateien im Excel-Format (Data/Output/Timesheets) auf Basis der Timesheet-Daten der Personen und der bereitgestellten timesheet.xlsx-Vorlage.
5.7 ViewService
Datei: Service/ViewService.cs
Übernimmt die Darstellung eines ShiftPlan als PNG-Bild mittels SkiaSharp. Speichert alle Pläne im Verzeichnis Data/Output/ShiftPlans.
6. Berechnungsalgorithmus
Der Algorithmus in ShiftPlanService arbeitet in drei Phasen:
Phase 1 – Generierung der Einzelschicht-Varianten (GeneratePlannedShifts)
Für jede konfigurierte Schicht werden alle Kombinationen von Personen gebildet, die dieser Schicht zugewiesen sind – von MinPersonCount bis MaxPersonCount. Das Ergebnis ist eine Liste aller möglichen "besetzten Einzelschichten":
- 1 Person: Jede Person einzeln
- 2 Personen: Alle Zweier-Kombinationen (ohne Wiederholung)
- 3 Personen: Alle Dreier-Kombinationen (ohne Wiederholung)
Phase 2 – Aufbau der Tagesschichten (GenerateDayShifts)
Die Einzelschicht-Varianten werden nach Wochentag gruppiert. Innerhalb eines Tages werden die bis zu 3 möglichen Positionen (ShiftInDay = 1, 2, 3) zu Dreier-Tupeln (Shift, Shift, Shift) kombiniert. Fehlt eine Position, wird null eingesetzt.
Phase 3 – Kombination zum Wochenplan & Validierung (CalculateShiftPlans)
Alle Tagesschichten werden durch verschachtelte Parallel.ForEach-Schleifen kombiniert (je ein Level pro Wochentag). Für jede entstehende Wochenplan-Kombination wird CheckShift aufgerufen:
- Es werden die kumulierten Stunden aller Personen berechnet.
- Ein Plan gilt nur dann als gültig, wenn jede Person exakt ihre konfigurierten Wochenstunden arbeitet (weder mehr noch weniger).
- Gültige Pläne werden in die
ObservableCollection<ShiftPlan>eingetragen.
Hinweis zur Performance: Die Berechnung ist exponentiell in der Anzahl der Schichten und Personen. Die parallele Ausführung über
Parallel.ForEachnutzt alle verfügbaren CPU-Kerne. Bei komplexen Konfigurationen kann die Berechnung dennoch mehrere Sekunden bis Minuten dauern.
7. Datei-I/O (FileIO)
Das FileIO-Verzeichnis enthält Klassen zum Laden und Speichern des Anwendungszustands (Personen, Schichten) als XML-Dateien mittels XmlSerializer.
- Personen und Schichten werden als XML serialisiert/deserialisiert.
- Verknüpfungen (
Shiftsin Person,Personsin Shift) sind mit[XmlIgnore]dekoriert und werden nach dem Laden aus dem XML neu aufgebaut, um zirkuläre Referenzen zu vermeiden.
8. Benutzeroberfläche (View)
Die Oberfläche ist mit Avalonia UI und dem Fluent Theme umgesetzt. Sie besteht aus mehreren Tabs:
| Tab | Funktion |
|---|---|
| Persons | Personen anlegen (Add new person), bearbeiten (Edit person), löschen (Delete person), Schichten zuweisen (Select shifts for person) |
| Shifts | Schichten anlegen (Add new shift), bearbeiten (Edit shift), löschen (Delete shift), Personen zuweisen (Select persons for shift) |
| ShiftPlans | Berechnung starten (Start calculation), Pläne filtern (Filter shiftplans), Filter zurücksetzen (Reset all filters), Plan öffnen (Open selected ShiftPlan), alle Pläne speichern (Save all ShiftPlans), Stundenzettel generieren (Generate Timesheets) |
Bidirektionale Verknüpfung: Die Zuweisung von Personen und Schichten erfolgt stets automatisch in beide Richtungen. Eine über "Select shifts for person" hinzugefügte Schicht wird der Person und gleichzeitig der Person zur Schicht hinzugefügt – ohne manuellen Zweischritt.
9. Ausgabedateien
| Pfad | Inhalt |
|---|---|
Data/Output/ShiftPlans/ |
Alle Schichtpläne als .png-Dateien (via Save all ShiftPlans) |
Data/Output/Timesheets/ |
Stundenzettel als .xlsx-Dateien (via Generate Timesheets) |
10. Hinweise & Einschränkungen
- Stundenformat: Alle Stunden müssen als Wochenstunden angegeben werden. Tagesstunden oder Monatsstunden werden nicht unterstützt.
- Personenanzahl pro Schicht: Der Algorithmus unterstützt aktuell maximal 3 Personen pro Schicht. Höhere Werte für
MaxPersonCountwerden im Code nicht berücksichtigt. - Anzahl Wochentage: Der Algorithmus ist für genau 5 Wochentage ausgelegt (die Schleifentiefe in
CalculateShiftPlansist auf 5 verschachtelt). - Stundenzettel-Quelle: Die
TimeSheetSourceeiner Person verweist auf eine externe Datenquelle (Google Calendar oder lokale Datei), die vor der Generierung verfügbar sein muss. - Google API: Die Konfiguration der Google Calendar API erfolgt über die eingebettete Ressource
Resources/templates/googleapi.txt. - Performance: Bei sehr vielen Personen und Schichten kann die Anzahl der Permutationen exponentiell wachsen. Eine Abbruchmöglichkeit via
CancellationTokenist implementiert.
Dokumentation erstellt am 22.04.2026