Files
LeanderShiftPlannerV2/Full-Doc.md
T
2026-04-22 10:33:41 +02:00

347 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
1. [Projektübersicht](#1-projektübersicht)
2. [Systemvoraussetzungen & Abhängigkeiten](#2-systemvoraussetzungen--abhängigkeiten)
3. [Projektstruktur](#3-projektstruktur)
4. [Datenmodell](#4-datenmodell)
- 4.1 [Person](#41-person)
- 4.2 [Shift (Schicht)](#42-shift-schicht)
- 4.3 [ShiftPlan](#43-shiftplan)
- 4.4 [Timesheet (Stundenzettel)](#44-timesheet-stundenzettel)
- 4.5 [Filter](#45-filter)
5. [Services (Geschäftslogik)](#5-services-geschäftslogik)
- 5.1 [AppService](#51-appservice)
- 5.2 [PersonService](#52-personservice)
- 5.3 [ShiftService](#53-shiftservice)
- 5.4 [ShiftPlanService](#54-shiftplanservice)
- 5.5 [FilterService](#55-filterservice)
- 5.6 [TimesheetService](#56-timesheetservice)
- 5.7 [ViewService](#57-viewservice)
6. [Berechnungsalgorithmus](#6-berechnungsalgorithmus)
7. [Datei-I/O (FileIO)](#7-datei-io-fileio)
8. [Benutzeroberfläche (View)](#8-benutzeroberfläche-view)
9. [Ausgabedateien](#9-ausgabedateien)
10. [Hinweise & Einschränkungen](#10-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 jeweils `PropertyChanged` aus)
- `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.ForEach` nutzt 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 (`Shifts` in Person, `Persons` in 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 `MaxPersonCount` werden im Code nicht berücksichtigt.
- **Anzahl Wochentage:** Der Algorithmus ist für genau **5 Wochentage** ausgelegt (die Schleifentiefe in `CalculateShiftPlans` ist auf 5 verschachtelt).
- **Stundenzettel-Quelle:** Die `TimeSheetSource` einer 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 `CancellationToken` ist implementiert.
---
*Dokumentation erstellt am 22.04.2026*