Diplomarbeitsbuch-individueller-teil-Adam-Gaiswinkler.md aktualisiert
Some checks failed
Word Count / count-words (push) Failing after 34s

This commit is contained in:
2026-03-09 14:08:03 +00:00
parent b0d67e4d6d
commit 654eeb4590

View File

@@ -76,19 +76,28 @@ Das Projektteam wurde im Verlauf des Projekts von sechs auf drei Personen reduzi
---
## 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.
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 der HTL Ungargasse entspricht. Das Standardtheme von Oqtane ist funktional, jedoch generisch gehalten und bietet keinen Bezug zur Schule oder zum Projekt. Aus diesem Grund wurde frühzeitig die Entscheidung getroffen, ein vollständig eigenes Theme zu entwickeln, das sowohl optisch als auch technisch auf die Bedürfnisse der Plattform zugeschnitten ist.
Das visuelle Design orientiert sich dabei am bestehenden Erscheinungsbild der offiziellen Schulwebseite szu.at. Es wurde bewusst ein schlichtes Grau-Weiß-Farbschema gewählt, das eine klare, professionelle und zeitlose Optik erzeugt. Auf auffällige Farben oder komplexe Animationen wurde verzichtet, um die Inhalte in den Vordergrund zu stellen und eine ruhige Benutzeroberfläche zu schaffen, die für ein breites Publikum von Schülerinnen und Schülern über Lehrkräfte bis hin zu ehemaligen Absolventinnen und Absolventen zugänglich ist.
Neben der visuellen Gestaltung standen auch technische Anforderungen im Mittelpunkt. Das Theme sollte auf unterschiedlichen Endgeräten sowohl auf Desktop-Computern als auch auf Smartphones und Tablets zuverlässig und benutzerfreundlich funktionieren. Responsive Design war daher von Anfang an eine zentrale Anforderung. Darüber hinaus sollte das Theme vollständig in die Oqtane-Architektur integriert sein, sodass alle Standardfunktionen des CMS wie Benutzerverwaltung, Seitenverwaltung und Modulintegration weiterhin ohne Einschränkungen genutzt werden können.
### 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.
Als technische Grundlage diente die Theme-Architektur von Oqtane. Das Layout wurde in einer zentralen Razor-Datei (`Theme.razor`) definiert, welche von der Basisklasse `ThemeBase` erbt. Durch diese Vererbung stehen im Theme automatisch zentrale Funktionen des Frameworks zur Verfügung, darunter der Seitenzustand (`PageState`), Navigationsdaten, Systemeinstellungen sowie Informationen über den aktuell angemeldeten Benutzer. Dies ermöglicht eine tiefe Integration des Themes in das CMS, ohne dass zusätzliche Schnittstellen oder externe Datenzugriffe notwendig sind.
#### 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.
Ein zentrales Element des Themes ist die fixierte Navigationsleiste am oberen Rand der Seite. Sie ist in drei klar voneinander getrennte Bereiche gegliedert: Auf der linken Seite befindet sich das Logo der HTL Ungargasse, das als visuelles Erkennungsmerkmal der Schule dient und beim Klick zur Startseite führt. In der Mitte werden die Navigationspunkte der Plattform angezeigt, die dynamisch aus der Seitenstruktur des CMS generiert werden. Auf der rechten Seite befinden sich die Benutzerfunktionen, also Login, Registrierung und bei angemeldeten Benutzern ein Link zum eigenen Profil.
Die dynamische Generierung der Navigationspunkte stellte dabei eine besondere Herausforderung dar. Das Oqtane-Framework stellt standardmäßig eine `<Menu>`-Komponente bereit, die automatisch alle im System registrierten Seiten in der Navigation anzeigt. Diese Komponente gibt jedoch nicht nur öffentlich sichtbare Inhaltsseiten aus, sondern auch interne Systemseiten wie Login, Register, Reset, Profile, Search, Privacy, Terms, Not Found oder Admin. Diese Seiten sind für den normalen Benutzer nicht relevant und sollten daher nicht in der Hauptnavigation erscheinen.
Da die Standardkomponente das Burger-Menü automatisch generierte und keine Möglichkeit bot, dieses individuell anzupassen, wurde auf sie verzichtet. Da ein eigenes, maßgeschneidertes Burger-Menü benötigt wurde, wurde stattdessen eine vollständig eigene Navigation implementiert. Dabei wurde auf die Basisklassen `MenuBase` und `MenuItemsBase` zurückgegriffen, die von Oqtane bereitgestellt werden und den Zugriff auf die Seitenliste ermöglichen. Die Navigationspunkte werden direkt über `PageState.Pages` abgerufen und anschließend mittels LINQ gefiltert. Dabei werden nur Root-Seiten berücksichtigt, also Seiten ohne übergeordnete Seite (`ParentId == null`), die als Navigationsseite markiert sind und nicht in einer manuell definierten Ausschlussliste (`hiddenNames`) stehen.
```csharp
var hiddenNames = new[]
@@ -101,27 +110,37 @@ 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ü
Durch diesen Ansatz werden ausschließlich die für Benutzer relevanten Inhaltsseiten in der Navigation angezeigt. Gleichzeitig bleibt die Navigation vollständig dynamisch: Werden im CMS neue Seiten angelegt und als Navigationsseiten markiert, erscheinen diese automatisch im Menü, ohne dass eine Anpassung am Theme-Code notwendig ist. Dies reduziert den Wartungsaufwand erheblich und stellt sicher, dass die Navigation stets dem aktuellen Stand der Plattform entspricht.
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.
#### Responsive Design und Burger-Menü
Da die Plattform auch auf mobilen Endgeräten genutzt werden soll, war die Umsetzung eines responsiven Layouts eine wichtige Anforderung. Auf Desktop-Geräten werden alle Navigationspunkte direkt in der Navigationsleiste angezeigt. Auf kleineren Bildschirmen wie Smartphones oder Tablets würde dies jedoch zu Platzproblemen führen, da die Anzahl der Navigationspunkte die verfügbare Breite überschreiten kann.
Aus diesem Grund wurde für mobile Endgeräte ein sogenanntes Burger-Menü implementiert. Dabei handelt es sich um ein Icon mit drei horizontalen Linien, das auf kleinen Bildschirmen anstelle der ausgeschriebenen Navigationspunkte angezeigt wird. Beim Anklicken öffnet sich eine seitliche Sidebar, in der alle Navigationspunkte vertikal untereinander dargestellt werden. Die Sidebar ist so aufgebaut, dass der obere Bereich die Navigationspunkte enthält und bei einer großen Anzahl von Einträgen gescrollt werden kann. Am unteren Rand der Sidebar sind die Login- und Registrierungsfunktionen fixiert, sodass diese unabhängig von der Anzahl der Navigationspunkte immer sichtbar und erreichbar sind.
Die technische Umsetzung des Burger-Menüs basiert auf einer CSS-Checkbox-Lösung. Das Öffnen und Schließen der Sidebar wird über den Zustand einer versteckten Checkbox gesteuert, der mittels CSS-Selektoren ausgewertet wird. Dieser Ansatz ermöglicht eine funktionsfähige mobile Navigation ohne den Einsatz zusätzlicher JavaScript-Frameworks oder komplexer Logik. Die gesamte Darstellungslogik also welche Elemente auf welcher Bildschirmgröße sichtbar sind wird über CSS Media Queries gesteuert, die zwischen der Desktop- und der mobilen Ansicht unterscheiden.
#### 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.
Für den Inhaltsbereich der Plattform wurden mehrere sogenannte Panes definiert. Panes sind in Oqtane Platzhalter-Bereiche innerhalb eines Themes, in die später Module oder Inhalte eingefügt werden können. Durch die Definition mehrerer Panes mit unterschiedlichen Breiten und Positionen können Seiten sehr flexibel und ohne Änderungen am Theme-Code strukturiert werden.
Im entwickelten Theme stehen unter anderem folgende Panes zur Verfügung: ein vollbreiter Bereich oben (`Top 100%`), ein linker Bereich (`Left 50%`), eine rechte Seitenleiste (`Right Sidebar 33%`) sowie ein vollbreiter Bereich am unteren Rand (`Bottom 100%`). Diese Struktur ermöglicht es, Seiten sowohl ein- als auch mehrspaltig aufzubauen, je nach den Anforderungen des jeweiligen Inhalts.
#### 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.
Neben Navigation und Layout wurden weitere Funktionen in das Theme integriert. Die Cookie-Consent-Komponente von Oqtane wurde eingebunden, sodass beim ersten Besuch der Plattform ein Hinweis zur Verwendung von Cookies angezeigt wird. Diese Funktion ist über die Site-Einstellungen von Oqtane steuerbar, das Theme rendert lediglich die entsprechende Komponente.
Darüber hinaus wurde das ControlPanel von Oqtane integriert, das Administratorinnen und Administratoren direkten Zugriff auf Verwaltungsfunktionen bietet. Login- und Registrierungsoptionen werden über den `SettingService` aus den Site-Einstellungen geladen, sodass diese Funktionen ohne Anpassungen am Code aktiviert oder deaktiviert 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.
Die größte Herausforderung bei der Theme-Entwicklung war die Umsetzung einer individuellen Navigation. Die von Oqtane bereitgestellte Standardkomponente generierte das Burger-Menü automatisch und bot keine Möglichkeit, dieses individuell anzupassen. Da ein eigenes, maßgeschneidertes Burger-Menü benötigt wurde, das sich nahtlos in das Theme-Design einfügt, wurde die Standardkomponente vollständig ersetzt und eine eigene Navigation implementiert. Durch den direkten Zugriff auf `PageState.Pages` und eine LINQ-basierte Filterlogik konnte eine vollständig kontrollierbare und flexibel gestaltbare Navigation realisiert werden. Dieser Ansatz erforderte zwar mehr Entwicklungsaufwand, ermöglichte dafür aber die gewünschte individuelle Gestaltung des Burger-Menüs.
---
@@ -143,7 +162,53 @@ Eine der zentralen Herausforderungen bei der Entwicklung des Themes war die korr
### 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.
Das Hall-of-Fame-Modul ist ein zentrales Modul der AlumniHub-Plattform. Es dient dazu, ehemalige Absolventinnen und Absolventen der HTL Ungargasse sichtbar zu machen und ihre beruflichen Werdegänge zu präsentieren. Das Modul wurde als eigenständiges, wiederverwendbares Oqtane-Modul entwickelt und ermöglicht es registrierten Benutzerinnen und Benutzern, sich selbst mit einem persönlichen Profil einzutragen.
#### Benutzeroberfläche
Die Benutzeroberfläche des Moduls besteht aus mehreren Komponenten, die zusammen eine vollständige und benutzerfreundliche Verwaltung der Hall-of-Fame-Einträge ermöglichen.
##### Übersichtsseite (Index.razor)
Die Hauptseite der Hall of Fame ist die erste Seite, die Besucherinnen und Besucher zu sehen bekommen. Sie zeigt alle veröffentlichten Einträge in einem responsiven Kartenlayout. Auf Desktop-Geräten werden die Karten in drei Spalten nebeneinander dargestellt, auf kleineren Bildschirmen passt sich das Layout automatisch an und zeigt die Karten einspaltig untereinander an.
Jede Karte enthält das Foto der jeweiligen Person als großes Vorschaubild im oberen Bereich. Darunter werden Name und Abschlussjahrgang als Überschrift angezeigt. Im unteren Bereich der Karte befindet sich ein Teaser der Beschreibung, also ein kurzer Ausschnitt aus dem Werdegang der Person. Da Beschreibungen unterschiedlich lang sein können, wurde die Kartenhöhe durch eine Kombination aus CSS-Flexbox und einer Maximalhöhe mit `overflow: hidden` vereinheitlicht. Dadurch weisen alle Karten in einer Zeile dieselbe Höhe auf, was ein sauberes und gleichmäßiges Erscheinungsbild der Übersichtsseite gewährleistet. Am unteren Rand jeder Karte befindet sich ein „Details ansehen"-Button, der die Besucherin oder den Besucher zur vollständigen Detailseite des Eintrags weiterleitet.
Über der Kartenliste befindet sich eine Filterleiste mit einer Suchfunktion und einer Sortieroption. Die Suchleiste ermöglicht eine Echtzeit-Suche über Name und Beschreibung aller Einträge die Ergebnisse aktualisieren sich direkt beim Tippen, ohne dass die Seite neu geladen werden muss. Neben der Suchleiste befindet sich ein Sortier-Dropdown, über das zwischen verschiedenen Sortierkriterien gewählt werden kann, darunter Datum, Name und Jahrgang. Ein Toggle-Button mit dynamischem Pfeil-Icon ermöglicht das Umschalten zwischen aufsteigender und absteigender Sortierrichtung.
Für angemeldete Benutzerinnen und Benutzer wird im oberen rechten Bereich der Seite ein zusätzlicher Button angezeigt. Hat die Person noch keinen eigenen Eintrag erstellt, erscheint ein „Eintragen"-Button. Existiert bereits ein Eintrag, ändert sich der Button automatisch zu „Mein Eintrag", über den der bestehende Eintrag bearbeitet werden kann. Administratorinnen und Administratoren sehen zusätzlich Warnhinweise bei gemeldeten Einträgen sowie einen Lösch-Button bei jedem Eintrag.
##### Detailseite (Details.razor)
Die Detailseite zeigt einen einzelnen Hall-of-Fame-Eintrag in seiner vollständigen Form. Das Layout ist zweispaltig aufgebaut: Auf der linken Seite befindet sich das Foto der Person, eingebettet in einen unscharfen Bildhintergrund, der dasselbe Foto in einer größeren, weichgezeichneten Version als Hintergrund verwendet. Dieser Effekt verleiht der Seite eine moderne und ansprechende Optik. Das eigentliche Foto ist dabei als klar umrandetes Porträtbild in der Mitte des linken Bereichs positioniert.
Auf der rechten Seite werden zunächst eine Breadcrumb-Navigation („Hall of Fame / Details") sowie Name und Jahrgang der Person angezeigt. Der Jahrgang wird in blauer Schrift als „Absolvent des Jahrgangs [Jahr]" dargestellt, was einen visuellen Akzent setzt und den Jahrgang klar hervorhebt. Darunter folgt die vollständige Beschreibung unter der Überschrift „Werdegang & Erfolge".
Am unteren Rand der Seite befinden sich je nach Konfiguration des Eintrags bis zu vier Buttons. Der „PDF Vorschau"-Button öffnet einen modalen Dialog mit einer vollständigen Vorschau des generierten PDFs sowie einem „Herunterladen"-Button. Der „Zurück"-Button führt zurück zur Übersichtsseite. Falls die Person einen optionalen Link hinterlegt hat, wird zusätzlich ein „Webseite besuchen"-Button angezeigt, der die Besucherin oder den Besucher direkt zur externen Webseite der Person führt. Für eingeloggte Benutzer gibt es außerdem einen „Melden"-Button, über den ein Eintrag gemeldet werden kann.
##### Edit-Seite (Edit.razor)
Die Edit-Komponente dient sowohl zum Erstellen eines neuen Eintrags als auch zum Bearbeiten eines bestehenden. Das Formular ist klar strukturiert und enthält alle notwendigen Felder für einen vollständigen Hall-of-Fame-Eintrag.
Das Formular enthält zunächst ein Textfeld für den Namen der Person sowie ein Zahlenfeld für den Abschlussjahrgang. Für die Beschreibung wird ein Rich-Text-Editor eingesetzt, der Formatierungsmöglichkeiten wie Fett, Kursiv, Listen und weitere Optionen bietet. Unterhalb des Editors wird ein Live-Zeichenzähler angezeigt, der die aktuelle Zeichenanzahl in Echtzeit aktualisiert und die maximal erlaubte Zeichenanzahl von 504 Zeichen anzeigt. Dadurch sehen Benutzerinnen und Benutzer jederzeit, wie viel Platz noch zur Verfügung steht.
Für das Foto gibt es ein Upload-Feld mit einer Vorschaufunktion. Wird ein Bild ausgewählt, wird es sofort als Vorschau angezeigt, bevor der Eintrag gespeichert wird. Erlaubt sind nur JPG- und PNG-Dateien mit einer maximalen Größe von 5 MB. Zusätzlich gibt es ein optionales Link-Feld, in das eine externe Webseite der Person eingetragen werden kann.
Am unteren Rand des Formulars befinden sich zwei Speicheroptionen: „Als Entwurf speichern" und „Veröffentlichen". Einträge im Entwurfsmodus sind nur für die eigene Person sichtbar und erscheinen nicht in der öffentlichen Übersicht. Erst durch das Veröffentlichen wird der Eintrag für alle Besucherinnen und Besucher sichtbar. Eine Eigentümerprüfung verhindert, dass Benutzerinnen und Benutzer fremde Einträge bearbeiten, und eine Duplikatprüfung stellt sicher, dass pro Person nur ein Eintrag erstellt werden kann.
##### Meldefunktion
Die Meldefunktion ermöglicht es angemeldeten Benutzerinnen und Benutzern, einen Hall-of-Fame-Eintrag zu melden, wenn dieser unangemessene oder falsche Inhalte enthält. Durch Klicken auf den „Melden"-Button auf der Detailseite öffnet sich ein kleines Popup-Fenster, in das der Meldegrund eingetragen werden kann. Nach dem Absenden wird die Meldung in der Datenbank gespeichert und im Admin-Modul angezeigt. Administratorinnen und Administratoren können dort alle eingegangenen Meldungen einsehen und bei Bedarf den betreffenden Eintrag löschen oder freigeben.
Die Meldefunktion ist dabei nicht direkt im Hall-of-Fame-Modul implementiert, sondern wird über eine zentrale Schnittstelle aus einem gemeinsamen Interfaces-Paket eingebunden. Dieses Konzept ermöglicht es, dieselbe Melde-Oberfläche in beliebig vielen weiteren Modulen wiederzuverwenden, ohne die Logik mehrfach implementieren zu müssen.
##### PDF-Export
Der PDF-Export ist eine besondere Funktion des Hall-of-Fame-Moduls. Er ermöglicht es Benutzerinnen und Benutzern, ihren Eintrag als visuell ansprechendes PDF-Dokument herunterzuladen. Die PDF-Generierung wird über die Open-Source-Bibliothek QuestPDF in der Community-Edition realisiert.
Das generierte PDF folgt einem Glasmorphismus-Design und ist im Format DIN A4 gehalten. Das Foto der Person wird als vollflächiges Hintergrundbild verwendet, das die gesamte Seite ausfüllt. Im oberen Bereich der Seite befindet sich ein halbtransparenter dunkler Bereich, in dem der Name der Person in großen Großbuchstaben mit weitem Zeichenabstand dargestellt wird. Darunter wird der Jahrgang mit erhöhtem Zeichenabstand angezeigt. Im unteren Bereich der Seite befindet sich ein weiterer halbtransparenter Bereich mit der vollständigen Beschreibung. Der charakteristische Glaseffekt wird durch mehrschichtige halbtransparente Hintergründe mit abgerundeten Ecken erzeugt, die dem Dokument ein modernes und professionelles Erscheinungsbild verleihen.
Die PDF-Vorschau kann direkt auf der Detailseite über den „PDF Vorschau"-Button geöffnet werden. Es öffnet sich ein modaler Dialog, der das generierte PDF in einer Vorschau anzeigt. Über einen „Herunterladen"-Button kann das PDF direkt auf das Gerät gespeichert werden.
#### Datenmodell
@@ -171,7 +236,7 @@ Die zentrale Entität repräsentiert einen einzelnen Absolventeneintrag und wird
| `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.
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.
**Entität HallOfFameReport**
@@ -187,57 +252,25 @@ Die zweite Entität bildet einzelne Meldungen zu einem Eintrag ab und wird in de
| `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.
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 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.
Die Datenbankstruktur wird über Entity Framework Core Migrationen versioniert verwaltet.
| 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 |
| `InitializeModule` | `01.00.00.00` | Erstellt die Haupttabelle mit allen Grundspalten 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.
In der ursprünglichen Version des Moduls mussten Benutzerinnen und Benutzer eine Bild-URL manuell in ein Textfeld eingeben. Dies war wenig benutzerfreundlich und erforderte, dass Bilder zunächst anderweitig hochgeladen und verlinkt werden mussten. 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**
@@ -251,6 +284,7 @@ Karten hatten ursprünglich unterschiedliche Höhen durch variierende Beschreibu
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
@@ -279,37 +313,57 @@ Die ursprünglich fest codierten Sortierrichtungen wurden durch einen Toggle-But
#### 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.
Da AlumniHub zum Zeitpunkt des ersten Absolventenstreffens im Sommer 2025 noch nicht vollständig fertiggestellt war und das Hosting von Oqtane auf dem Hetzner-Server zu unerwarteten technischen Problemen geführt hatte, wurde im Team die Entscheidung getroffen, eine eigenständige Übergangslösung zu entwickeln. Diese sollte pünktlich zur Veranstaltung einsatzbereit sein und die wichtigsten Funktionen abdecken: die Möglichkeit für Absolventinnen und Absolventen, ihre Teilnahme am Treffen zu bestätigen oder abzusagen, sowie die Möglichkeit, direktes Feedback zum Diplomprojekt AlumniHub abzugeben.
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.
Da für die Entwicklung nur wenig Zeit zur Verfügung stand und eine vollständige Integration in die noch nicht fertige AlumniHub-Plattform nicht realistisch war, wurde bewusst auf einen schlanken, eigenständigen Technologie-Stack gesetzt. Dieser sollte schnell entwickelt, einfach deploybar und zuverlässig betreibbar sein ohne die Komplexität eines vollständigen CMS-Systems.
Das Frontend der Übergangslösung wurde mit den grundlegenden Webtechnologien HTML, CSS und JavaScript umgesetzt. Die Hauptseite (`index.html`) präsentiert den Besucherinnen und Besuchern eine übersichtliche und schlichte Oberfläche, die sich am Erscheinungsbild der HTL Ungargasse orientiert mit dem Schullogo im Header und einem Grau-Weiß-Farbschema. Im Mittelpunkt der Seite befindet sich ein zentraler Button, über den ein modales Overlay-Formular geöffnet werden kann. Über dieses Formular konnten Nutzerinnen und Nutzer ihre E-Mail-Adresse eingeben und ihr Feedback zum Projekt abgeben. Die Steuerung des Overlays erfolgt über JavaScript: Das Formular öffnet sich beim Klick auf den Button und schließt sich automatisch, wenn außerhalb des Formularfensters geklickt wird. Dadurch ist eine intuitive Bedienung ohne zusätzliche Schaltflächen möglich.
Für die Verarbeitung von Zu- und Absagen zum Absolvententreffen wurden zusätzlich zwei separate Bestätigungsseiten erstellt: `zusage.html` und `absage.html`. Diese Seiten werden dem Nutzer nach dem erfolgreichen Absenden des jeweiligen Formulars angezeigt und bestätigen den Eingang der Rückmeldung. Das Design aller drei Seiten ist einheitlich gehalten und folgt dem gleichen Layout-Prinzip mit Header, Logo und zentriertem Hauptinhalt.
Das Backend der Lösung, das für die Verarbeitung der Formulardaten und den Versand von Bestätigungs-E-Mails zuständig war, wurde von einem Teammitglied entwickelt und war nicht Teil des eigenen Aufgabenbereichs. Es wurde mit Node.js und dem Framework Express umgesetzt und auf einem virtuellen Server bei Hetzner Cloud gehostet.
#### 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.
Im direkten Vergleich zur finalen AlumniHub-Plattform unterscheidet sich die Übergangslösung in mehreren wesentlichen Punkten. Während AlumniHub auf dem vollständigen CMS Oqtane basiert und eine umfangreiche Funktionspalette bietet darunter Benutzerverwaltung, Hall of Fame, Anmeldetool, Datenauswertung und ein individuelles Theme beschränkte sich die Übergangslösung bewusst auf das absolut Notwendige.
Es gab keine Benutzerkonten und keine Authentifizierung. Jede Person, die die Seite aufrief, konnte das Formular ausfüllen und absenden, ohne sich vorher registrieren oder anmelden zu müssen. Es gab keine Datenbank im klassischen Sinne die eingegangenen Formulardaten wurden serverseitig als einfache JSON-Dateien gespeichert. Es gab keine administrativen Funktionen, keine Übersichten und keine Möglichkeit, die Daten direkt über eine Benutzeroberfläche auszuwerten.
Diese bewusste Reduktion auf das Wesentliche war jedoch kein Nachteil, sondern eine pragmatische Entscheidung: Die Lösung musste schnell funktionieren und zuverlässig sein und das war sie. Nach dem Absolvententreffen wurde die Seite nicht einfach abgeschaltet, sondern zu einer reinen Feedback-Seite für das Diplomprojekt umfunktioniert. Über diese Seite konnten Interessierte darunter Lehrkräfte, Mitschülerinnen und Mitschüler sowie externe Besucher der Präsentation weiterhin direktes Feedback zum Projekt abgeben. Die Seite blieb so lange in Betrieb, bis die vollständig entwickelte AlumniHub-Plattform diese Funktion nativ ü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.
Eine der größten technischen Herausforderungen im gesamten Projektverlauf war der Zeitdruck, der insbesondere im Vorfeld des ersten Absolventenstreffens spürbar war. Da AlumniHub zu diesem Zeitpunkt noch nicht einsatzbereit war, musste die Übergangslösung in sehr kurzer Zeit konzipiert, entwickelt und in Betrieb genommen werden. Dieser Zeitdruck führte dazu, dass keine ausreichende Zeit für gründliches Testen oder für die Umsetzung zusätzlicher Funktionen blieb.
Ein weiteres technisches Problem betraf das Hosting von Oqtane auf dem Hetzner-Server. Die Einrichtung und der Betrieb von Oqtane auf dem Server bereiteten unerwartete Schwierigkeiten, die den regulären Entwicklungsfortschritt verlangsamten. Da dieser Bereich nicht zum eigenen Aufgabengebiet gehörte, konnten die genauen Ursachen nicht vollständig nachvollzogen werden. Die Probleme wirkten sich jedoch auf den gesamten Zeitplan des Projekts aus und waren mitverantwortlich dafür, dass AlumniHub zum Zeitpunkt des ersten Treffens noch nicht fertig war.
#### 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.
Neben den technischen Herausforderungen gab es auch auf organisatorischer Ebene ein zentrales Problem, das den Projektverlauf im Sommer 2025 erheblich beeinflusste. Während der Sommermonate war die aktive Mitarbeit innerhalb des Teams sehr ungleich verteilt. Ein Großteil der Teammitglieder war urlaubsbedingt nicht oder nur eingeschränkt erreichbar und beteiligte sich in dieser Zeit kaum am Projekt. Nur ein kleiner Teil des Teams arbeitete in dieser Phase aktiv weiter und trieb den Fortschritt voran.
Diese Situation führte zu einer deutlichen Ungleichverteilung der Arbeitsbelastung. Wenige Personen mussten in dieser Zeit deutlich mehr Verantwortung übernehmen als ursprünglich geplant, was zu Frustration und Verzögerungen führte. Im Nachhinein zeigt sich, dass klarere Absprachen und verbindlichere Vereinbarungen zu Beginn des Sommers dazu beigetragen hätten, diese Situation zu vermeiden oder zumindest abzumildern.
### 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.
Das Projekt hat auf technischer Ebene wertvolle praktische Kenntnisse vermittelt, die über den schulischen Rahmen hinausgehen. Der konsequente Einsatz von Git zur Versionskontrolle war dabei eine der wichtigsten Erfahrungen. Durch die tägliche Arbeit mit Branches, Commits und Merges wurde ein tiefes Verständnis für kollaborative Softwareentwicklung aufgebaut. Es wurde deutlich, wie wichtig aussagekräftige Commit-Nachrichten, regelmäßige Commits und eine saubere Branch-Struktur für die Zusammenarbeit im Team sind.
Im Bereich Responsive Design wurden durch die praktische Umsetzung des Themes und der Übergangslösung wichtige Kenntnisse vertieft. Es wurde erfahren, wie man mit CSS Media Queries und Flexbox Layouts baut, die sich zuverlässig an unterschiedliche Bildschirmgrößen anpassen. Besonders die Umsetzung des Burger-Menüs für mobile Geräte war eine lehrreiche Erfahrung, die zeigte, wie man komplexe UI-Funktionen mit minimalem JavaScript-Einsatz realisieren kann.
Auch der Umgang mit JavaScript zur Steuerung von UI-Elementen wurde durch die Arbeit am Projekt verbessert. Die Implementierung der Overlay-Steuerung in der Übergangslösung sowie die Menü-Logik im Theme haben gezeigt, wie JavaScript gezielt und effizient eingesetzt werden kann, um eine bessere Benutzererfahrung zu schaffen.
#### 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.
Auf methodischer Ebene hat das Projekt gezeigt, wie wichtig eine klare und verbindliche Aufgabenverteilung von Beginn an ist. In Phasen, in denen nicht klar war, wer welche Aufgaben übernimmt, entstanden Lücken und Verzögerungen. Eine strukturiertere Planung mit klar definierten Zuständigkeiten hätte in solchen Situationen geholfen, den Überblick zu behalten und die Arbeit effizienter aufzuteilen.
Darüber hinaus hat sich gezeigt, dass regelmäßige Team-Meetings ein wichtiges Werkzeug für den Projekterfolg sind. In Phasen, in denen der Austausch im Team spärlicher war, dauerte es länger, bis Probleme erkannt und gelöst wurden. Kurze, regelmäßige Abstimmungen hätten dazu beigetragen, den aktuellen Stand besser zu kommunizieren und gemeinsam schneller auf Hindernisse zu reagieren.
#### 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.
Auf persönlicher Ebene war die wichtigste Erkenntnis aus diesem Projekt die Bedeutung von Eigeninitiative. In einem größeren Teamprojekt kann man sich nicht immer darauf verlassen, dass andere Aufgaben erledigen oder Entscheidungen treffen. Gerade in den Phasen, in denen nicht alle Teammitglieder aktiv waren, hat sich gezeigt, dass proaktives Handeln entscheidend ist, um das Projekt voranzubringen. Diese Erfahrung hat das Bewusstsein dafür gestärkt, Verantwortung nicht nur für den eigenen Bereich, sondern auch für das Gesamtprojekt zu übernehmen und bei Bedarf auch Aufgaben außerhalb des ursprünglich geplanten Bereichs zu übernehmen.
---