Files
pm/Diplomarbeitsbuch-individueller-teil-Adam-Gaiswinkler.md
Adam Gaiswinkler bbf3626dcb
Some checks failed
Word Count / count-words (push) Failing after 33s
Diplomarbeitsbuch-individueller-teil-Adam-Gaiswinkler.md aktualisiert
2026-03-05 16:22:52 +00:00

16 KiB
Raw Blame History

Diplomarbeitsbuch


1. Einleitung

Ausgangssituation

Motivation

Kurzbeschreibung des Projekts

Persönlicher Aufgabenbereich

Abgrenzung der Arbeit

Die Datenbankinfrastruktur war zum Projektstart bereits vorhanden und wurde nicht im Rahmen dieser Arbeit konzipiert. Die Diplomarbeit beschränkt sich auf die Entwicklung der Anwendungsschicht, bestehend aus CMS-Konfiguration, Modul- und Theme-Entwicklung.

Individuelle Themenstellung


3. Projektumfeld & Rahmenbedingungen

Einsatz eines bestehenden CMS (Oqtane)

Teamarbeit

Das Projektteam wurde im Verlauf des Projekts von sechs auf drei Personen reduziert.

Schulisches Umfeld (HTL)

Zeitliche Rahmenbedingungen


4. Technologischer Überblick

4.1 Web-Entwicklung mit ASP.NET & C#

Backend-Logik

API-basierte Kommunikation

Zusammenspiel mit Oqtane

4.2 Oqtane Überblick

Grundidee & Architektur

Modul- & Theme-Konzept

Vorteile für das Projekt

4.3 CMS-Grundkonfiguration

Initiale Einrichtung

Modul-Integration

Rollen & Berechtigungen

Grundlegende Systemeinstellungen


5. System- und Lösungsarchitektur

Gesamtarchitektur des Systems

Einordnung von CMS, Modulen und Theme

Datenfluss

Architekturentscheidungen


6. Entwicklung des Oqtane Themes

6.1 Ziel des Themes

Im Rahmen des Projekts AlumniHub wurde ein eigenes Theme für das Content-Management-System Oqtane entwickelt. Ziel dieser Entwicklung war es, das Standarddesign von Oqtane vollständig durch eine projektspezifische Benutzeroberfläche zu ersetzen, die den Anforderungen des Absolventenvereins entspricht. Dabei standen Übersichtlichkeit, Benutzerfreundlichkeit sowie eine moderne und konsistente Gestaltung im Vordergrund. Das Theme sollte zudem auf unterschiedlichen Endgeräten sowohl Desktop als auch mobil optimal dargestellt werden.


6.2 Technische Umsetzung

Als technische Grundlage diente die Theme-Architektur von Oqtane. Das Layout wurde in einer Razor-Datei (Theme.razor) definiert, welche von der Basisklasse ThemeBase erbt. Dadurch stehen zentrale Funktionen wie Seitenzustand (PageState), Navigation und Systemeinstellungen automatisch zur Verfügung.

Navigationsleiste

Im oberen Bereich wurde eine fixierte Navigationsleiste implementiert, die drei Hauptbereiche umfasst: links das Logo der Schule, in der Mitte die dynamisch generierten Navigationspunkte und rechts die Benutzerfunktionen (Login, Registrierung, Profil). Da die Standardkomponente <Menu> von Oqtane auch interne Systemseiten wie Login, Register oder NotFound ausgibt, wurde auf diese verzichtet. Stattdessen wurden eigene Komponenten implementiert, die von MenuBase bzw. MenuItemsBase erben. Die Seitenliste wird dabei über PageState.Pages abgerufen und mittels LINQ gefiltert es werden nur Root-Seiten (ParentId == null) angezeigt, die als Navigationsseite markiert sind und nicht in einer definierten Ausschlussliste (hiddenNames) stehen.

var hiddenNames = new[]
{
    "Login", "Register", "Reset", "Profile",
    "Search", "Privacy", "Terms", "Not Found", "Admin"
};

foreach (var item in PageState.Pages
             .Where(p => p.ParentId == null
                         && !hiddenNames.Contains(p.Name)))
{
    <a class="nav-link text-white" href="@item.Path">
        @item.Name
    </a>
}

Responsive Design / Burger-Menü

Für mobile Endgeräte wurde ein Burger-Menü implementiert. Das Öffnen und Schließen der Sidebar erfolgt über eine CSS-Checkbox-Lösung ohne zusätzliche Frameworks. Die Sidebar zeigt alle Navigationspunkte vertikal untereinander an, wobei Login- und Registrierungsfunktionen am unteren Rand fixiert sind und unabhängig von der Anzahl der Menüpunkte stets sichtbar bleiben.

Pane-Struktur

Für den Inhaltsbereich wurden mehrere Panes definiert (z.B. Top 100%, Left 50%, Right Sidebar 33%, Bottom 100%), die als flexible Platzhalter für Module dienen. Dadurch können Seiteninhalte ohne Änderungen am Theme-Code strukturiert werden.

Weitere Integrationen

Zusätzlich wurden die Cookie-Consent-Komponente sowie das ControlPanel für Administratoren integriert. Login- und Registrierungsoptionen werden über den SettingService aus den Site-Einstellungen geladen, sodass diese ohne Code-Anpassung gesteuert werden können.


6.3 Herausforderungen

Eine der zentralen Herausforderungen bei der Entwicklung des Themes war die korrekte Filterung der Navigationsseiten. Die von Oqtane bereitgestellten Blazor-Standardkomponenten für die Navigation verhielten sich dabei nicht wie erwartet, da sie auch interne Systemseiten wie Login, Register oder NotFound in der Hauptnavigation ausgaben und keine ausreichende Möglichkeit boten, diese gezielt auszublenden. Aus diesem Grund wurde auf die Standardkomponenten verzichtet und stattdessen eine eigene Implementierung entwickelt. Durch den direkten Zugriff auf PageState.Pages sowie eine LINQ-basierte Filterlogik konnten die anzuzeigenden Seiten vollständig kontrolliert und Systemseiten zuverlässig ausgeblendet werden.


7. Umsetzung der Module

7.1 Anmeldetool

Ziel des Moduls

Frontend (Eingabemaske)

Backend-Logik

API-Schnittstelle

Datenauswertung

UX-Überlegungen


7.2 Hall of Fame

Das Hall-of-Fame-Modul ist ein Oqtane-Modul, das ehemalige Absolventinnen und Absolventen der Schule auf der Vereinswebseite präsentiert. Es wurde als eigenständiges, wiederverwendbares Modul innerhalb des Oqtane-Frameworks entwickelt und ermöglicht registrierten Benutzerinnen und Benutzern, sich selbst mit einem persönlichen Profil einzutragen. Die Einträge werden erst nach bewusster Veröffentlichung durch die jeweilige Person auf der öffentlichen Seite angezeigt, können als PDF exportiert werden und unterliegen einem Meldesystem zur Qualitätssicherung.

Datenmodell

Das Modul verwendet zwei Entitäten, die in der Datenbank als Tabellen abgebildet werden. Entität HallOfFame Die zentrale Entität repräsentiert einen einzelnen Absolventeneintrag und wird in der Datenbanktabelle SZUAbsolventenvereinHallOfFame gespeichert.

Spalte Datentyp Beschreibung
HallOfFameId int (PK, Auto-Inkrement) Primärschlüssel
ModuleId int (FK → Module) Fremdschlüssel zur Oqtane-Modulinstanz
Name string Name der Person
Year int Abschlussjahrgang
Description string Beschreibung bzw. Werdegang
Image string Relativer Pfad zum hochgeladenen Foto
Link string Optionaler externer Link
Status string (max. 50) Veröffentlichungsstatus: „Draft" oder „Published"
UserId int ID der Benutzerin bzw. des Benutzers, der den Eintrag erstellt hat
IsReported bool Kennzeichnung, ob der Eintrag gemeldet wurde
ReportReason string (Legacy) Ursprüngliches Feld für Meldegrund, abgelöst durch die Report-Tabelle
CreatedBy string Erstellt von (Audit)
CreatedOn DateTime Erstellzeitpunkt (Audit)
ModifiedBy string Zuletzt geändert von (Audit)
ModifiedOn DateTime Zeitpunkt der letzten Änderung (Audit)
Die Entität implementiert das Oqtane-Interface IAuditable, wodurch die Audit-Felder automatisch vom Framework befüllt werden. Der Fremdschlüssel ModuleId verknüpft jeden Eintrag mit einer bestimmten Modulinstanz und ermöglicht so den Multi-Tenant-Betrieb: Mehrere Hall-of-Fame-Module auf verschiedenen Seiten der Website verwalten jeweils unabhängige Datensätze.
Entität HallOfFameReport
Die zweite Entität bildet einzelne Meldungen zu einem Eintrag ab und wird in der Tabelle SZUAbsolventenvereinHallOfFameReport gespeichert.
Spalte Datentyp Beschreibung
-------- ---------- --------------
HallOfFameReportId int (PK, Auto-Inkrement) Primärschlüssel
HallOfFameId int (FK → SZUAbsolventenvereinHallOfFame) Zugehöriger Eintrag
Reason string Meldegrund
CreatedBy string Erstellt von (Audit)
CreatedOn DateTime Erstellzeitpunkt (Audit)
ModifiedBy string Zuletzt geändert von (Audit)
ModifiedOn DateTime Zeitpunkt der letzten Änderung (Audit)
Der Fremdschlüssel zu SZUAbsolventenvereinHallOfFame ist mit kaskadierendem Löschen konfiguriert, sodass beim Löschen eines Eintrags automatisch alle zugehörigen Meldungen entfernt werden. Zwischen den beiden Entitäten besteht somit eine 1:n-Beziehung: Ein Eintrag kann beliebig viele Meldungen besitzen.

Datenbankmigrationen

Die Datenbankstruktur wird über Entity Framework Core Migrationen versioniert verwaltet. Oqtane verwendet ein eigenes Migrationssystem, das auf der Klasse MultiDatabaseMigration basiert und die Kompatibilität mit verschiedenen Datenbankanbietern sicherstellt.

Migration Versionsnummer Inhalt
InitializeModule 01.00.00.00 Erstellt die Haupttabelle mit allen Grundspalten (Name, Year, Description, Image, Link, Status, UserId) sowie den Audit-Spalten
AddReportingColumns 01.00.00.02 Erweitert die Haupttabelle um die Spalten IsReported und ReportReason
AddReportTable 01.00.00.03 Erstellt die eigenständige Report-Tabelle mit Fremdschlüssel zur Haupttabelle
Jede Migration definiert sowohl eine Aufwärts- als auch eine Abwärtsmethode, sodass ein Rollback möglich ist.

Benutzeroberfläche (Razor-Komponenten)

Das Modul umfasst vier Blazor-Razor-Komponenten. Index.razor Übersichtsseite Die Übersichtsseite zeigt alle veröffentlichten Einträge in einem responsiven Kartenlayout mit drei Spalten auf Desktop-Breite. Die Funktionalität umfasst eine Echtzeit-Textsuche über Name und Beschreibung, eine umschaltbare Sortierung nach Datum, Name oder Jahrgang sowie eine Kartenanzeige mit Bild, Name, Jahrgang und gekürzter Beschreibung. Administratorinnen und Administratoren sehen zusätzlich Warnmeldungen bei gemeldeten Einträgen und einen Lösch-Button. Angemeldete Benutzerinnen und Benutzer können über einen eigenen Button ihren Eintrag erstellen oder bearbeiten. Edit.razor Erstellungs- und Bearbeitungsseite Die Edit-Komponente dient sowohl zum Erstellen als auch zum Bearbeiten eines Eintrags. Sie bietet Formularfelder für Name, Jahrgang, Beschreibung (mit Live-Zeichenzähler), Foto-Upload und Link. Über zwei Speicheroptionen kann zwischen Entwurf und Veröffentlichung gewählt werden. Eine Eigentümerprüfung verhindert das Bearbeiten fremder Einträge, und eine Duplikatprüfung verhindert das Erstellen mehrerer Einträge pro Person. Details.razor Detailseite Die Details-Komponente zeigt einen einzelnen Eintrag in einem zweispaltigen Layout mit unscharfem Bildhintergrund. Administratorinnen und Administratoren sehen bei gemeldeten Einträgen eine Liste aller Meldungen mit Lösch-Button. Ein modaler Dialog ermöglicht die PDF-Vorschau sowie den Download. Die Meldefunktion wird über die zentrale IReportUI-Komponente eingebunden. Settings.razor Moduleinstellungen Die Settings-Komponente bietet eine einfache Oberfläche für Moduleinstellungen über Oqtanes Setting-Service.

Gemeinsame Melde-Komponente (IReportUI)

Die Meldefunktion in der Detailseite ist nicht direkt im Hall-of-Fame-Modul implementiert, sondern wird über eine zentrale Schnittstelle aus dem Interfaces-Paket eingebunden. Das Hall-of-Fame-Modell implementiert das Interface IReportable, das eine Entität als meldbar kennzeichnet. In der Detailseite wird per Dependency Injection eine IReportUI-Implementierung injiziert die konkrete ReportComponent stammt dabei aus dem Admin-Modul und stellt den Melden-Button samt modalem Dialog bereit. Die Komponente wird über Blazors DynamicComponent dynamisch gerendert. Ist keine Implementierung im Container registriert, wird die Meldefunktion schlicht nicht angezeigt. Dieses Konzept ermöglicht es, die Melde-Oberfläche zentral zu pflegen und in beliebig vielen weiteren Modulen wiederzuverwenden, ohne dass die einzelnen Module die Melde-Logik selbst implementieren müssen.

PDF-Export mit QuestPDF

Für die Generierung der PDF-Dokumente wird die Open-Source-Bibliothek QuestPDF in der Community-Edition eingesetzt. Im Server-Projekt wurde ein benutzerdefiniertes MSBuild-Target erstellt, das nach jedem Build automatisch die QuestPDF-DLL sowie die plattformspezifischen nativen Bibliotheken in das bin-Verzeichnis des Oqtane-Servers kopiert. Dies ist notwendig, weil Oqtane Module zur Laufzeit dynamisch lädt und QuestPDF native Abhängigkeiten (unter anderem die SkiaSharp-Rendering-Engine) benötigt. Das PDF-Design folgt einem Glasmorphismus-Ansatz. Jede Seite hat das Format DIN A4 ohne Ränder. Über die Layers-API von QuestPDF wird das Hintergrundbild von der Inhaltsebene getrennt. Der Name wird in 36 Punkt ExtraBold mit Großbuchstaben und Zeichenabstand dargestellt, der Jahrgang in 15 Punkt mit erhöhtem Zeichenabstand und die Beschreibung in 11 Punkt mit 1,5-fachem Zeilenabstand. Der Glaseffekt wird durch halbtransparente dunkle Hintergründe mit mehrschichtigen Rahmen unterschiedlicher Transparenz erzeugt.

Implementierungsdetails und Problemlösungen

Während der Entwicklung traten mehrere technische Herausforderungen auf, die im Folgenden zusammen mit ihren Lösungen beschrieben werden. Bild-Upload-System In der ursprünglichen Version des Moduls mussten Benutzerinnen und Benutzer eine Bild-URL manuell in ein Textfeld eingeben. Das implementierte Bild-Upload-System ersetzt dies durch eine Blazor-InputFile-Komponente mit Live-Vorschau, Fortschrittsanzeige und Lösch-Button. Die Upload-Methode prüft die Dateigröße (maximal 5 MB), öffnet die Datei als Stream und übermittelt sie als MultipartFormDataContent an den Server, der den Dateityp serverseitig validiert, einen UUID-Dateinamen generiert und die Datei speichert. Das System unterstützt beide Blazor-Rendering-Modi. Concurrency Exception beim Löschen Beim Löschen von Einträgen mit vorhandenen Meldungen trat eine DbUpdateConcurrencyException auf, verursacht durch Konflikte im Entity Framework Change Tracker. Die Lösung bestand in der Aufteilung der Löschoperation in zwei separate Transaktionen mit jeweils eigenem DbContext: zuerst werden alle zugehörigen Meldungen gelöscht, danach der Haupteintrag. Kartendesign-Optimierung Karten hatten ursprünglich unterschiedliche Höhen durch variierende Beschreibungslängen. Die Lösung kombiniert CSS-Flexbox auf dem Kartenelement mit einer Maximalhöhe von 150 Pixeln und overflow: hidden auf dem Beschreibungscontainer, sodass alle Karten einer Zeile dieselbe Höhe aufweisen. Sortier-Toggle Die ursprünglich fest codierten Sortierrichtungen wurden durch einen Toggle-Button neben dem Sortier-Dropdown ersetzt, der mit einem dynamischen Pfeil-Icon zwischen aufsteigender und absteigender Sortierung umschaltet. Die Sortierlogik ist in einer berechneten Eigenschaft gekapselt, die Suche und Sortierung kombiniert.

8. Projektorganisation & Teamarbeit

8.1 Planung & Meilensteine

Meilensteine

Soll-/Ist-Vergleich

Zeitverzug

8.2 Teamverkleinerung

Downsizing von 6 auf 3 Personen

Neue Aufgabenverteilung

Auswirkungen auf Theme-Entwicklung, Module und Zeitplanung


9. Übergangslösung, Probleme & Learnings

9.1 Übergangslösung (Sommer 2025)

Gründe & Technische Umsetzung

Differenzen zur finalen Lösung

9.2 Probleme

Technische Probleme

Organisatorische Probleme

9.3 Learnings

Technisch

Methodisch

Persönlich


10. Testen & Qualitätssicherung

Funktionstests der Module

Theme-Tests

Usability-Tests

Bekannte Einschränkungen


11. Fazit & Ausblick

Zielerreichung & Zusammenfassung

Persönliche Reflexion

Erweiterungsmöglichkeiten