Files
pm/Diplomarbeitsbuch-individueller-teil-Adam-Gaiswinkler.md
Adam Gaiswinkler 23c27600ef
Some checks failed
Word Count / count-words (push) Failing after 31s
Diplomarbeitsbuch-individueller-teil-Adam-Gaiswinkler.md aktualisiert
2026-03-05 20:55:14 +00:00

19 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

Da AlumniHub zum Zeitpunkt des ersten Absolventenstreffens im Sommer 2025 noch nicht fertig war und das Hosting von Oqtane auf dem Hetzner-Server zu Problemen geführt hat, wurde im Team eine einfache Übergangslösung entwickelt. Ziel war es, pünktlich zur Veranstaltung eine funktionierende Lösung bereitzustellen, über die Absolventinnen und Absolventen ihre Teilnahme bestätigen oder absagen sowie Feedback zum Projekt abgeben konnten.

Das Frontend wurde mit HTML, CSS und JavaScript umgesetzt. Die Hauptseite (index.html) zeigt einen Button, über den ein modales Overlay-Formular geöffnet wird. Darüber konnten Nutzer ihre E-Mail-Adresse und ihr Feedback eingeben und absenden. Für Zu- und Absagen wurden separate Bestätigungsseiten erstellt (zusage.html und absage.html). Das Overlay schließt sich automatisch beim Klick außerhalb des Formulars. Das Design orientiert sich am Erscheinungsbild der HTL Ungargasse.

Differenzen zur finalen Lösung

Im Vergleich zu AlumniHub ist die Übergangslösung deutlich schlichter gehalten. Es gibt keine Benutzerkonten, keine Datenbank und keine Verwaltungsfunktionen. Nach dem Absolvententreffen wurde die Seite nicht abgeschaltet, sondern als Feedback-Seite für das Diplomprojekt weitergenutzt. Lehrkräfte, Mitschülerinnen und Mitschüler sowie externe Besucher konnten darüber Feedback abgeben, bis AlumniHub diese Funktion selbst übernahm.

9.2 Probleme

Technische Probleme

Ein großes Problem war der Zeitdruck vor dem ersten Absolvententreffen. Da AlumniHub zu dem Zeitpunkt noch nicht einsatzbereit war, musste die Übergangslösung schnell entwickelt und in Betrieb genommen werden. Außerdem gab es beim Hosting von Oqtane auf dem Hetzner-Server technische Schwierigkeiten, die den Entwicklungsfortschritt gebremst haben.

Organisatorische Probleme

Im Sommer 2025 war die Mitarbeit im Team sehr ungleich verteilt. Viele Teammitglieder waren nicht erreichbar oder haben nicht aktiv am Projekt weitergearbeitet. Nur ein kleiner Teil des Teams hat in dieser Zeit wirklich weitergemacht. Das hat zu einer ungleichen Arbeitsbelastung geführt und den Fortschritt in dieser Phase deutlich verlangsamt.

9.3 Learnings

Technisch

Durch das Projekt wurden praktische Kenntnisse in Git zur Versionskontrolle gewonnen, was besonders für die Zusammenarbeit im Team wichtig war. Außerdem wurde Responsive Design vertieft also wie man Layouts baut, die auf verschiedenen Bildschirmgrößen gut aussehen. Auch der Umgang mit JavaScript für UI-Elemente wie Overlays und Menüs wurde durch die praktische Arbeit besser verstanden.

Methodisch

Es hat sich gezeigt, dass eine klare Aufgabenverteilung von Anfang an wichtig ist. Wenn nicht klar ist, wer was macht, entstehen Verzögerungen. Regelmäßige Team-Meetings wären hilfreich gewesen, um den Stand abzugleichen und Probleme früh zu erkennen.

Persönlich

Eine wichtige persönliche Erkenntnis war, dass Eigeninitiative in einem Teamprojekt entscheidend ist. Besonders in Phasen, wo nicht alle aktiv waren, hat sich gezeigt, dass man Aufgaben selbst in die Hand nehmen muss, damit das Projekt vorankommt.


10. Testen & Qualitätssicherung

Funktionstests der Module

Theme-Tests

Usability-Tests

Bekannte Einschränkungen


11. Fazit & Ausblick

Zielerreichung & Zusammenfassung

Persönliche Reflexion

Erweiterungsmöglichkeiten