Projekt im Rahmen des Masters »Angewandte Informatik«
im Modul »Funktionale Fullstack Webentwicklung mit Elixir«
an der Hochschule Flensburg
3. Features
Der FireBubble Chat ist im Rahmen des Kurses »Funktionale Fullstack Webentwicklung« mit Elixir entstanden und wurde mit Elixir und Phoenix LiveView entwickelt.
FireBubble Chat ist ein soziales Netzwerk, das Menschen mit gleichen Interessen verbindet. Nutzer:innen können "Bubbles" zu bestimmten Themen erstellen, um einen Austauschort für Interessierte zu schaffen. Innerhalb einer Bubble können Chaträume für verschiedene Diskussionsthemen erstellt werden.
npm installum FlowBite zu installierendocker compose upzum Einrichten der Docker-Datenbankmix setupzum Einrichten des Elixir-Projektesmix phx.serverzum Starten des Projektes
Nun sollte die Seite über localhost:4000 aufrufbar sein.
Diese LiveView wird bei allen Seiten (bis auf Login und Registrierung) an der linken Seite angezeigt. Sie beinhaltet alle Server, in denen der/die akteulle Nutzer:in Mitglied ist. Zudem wird gekennzeichnet, in welchem Server sich der/die aktuelle Nutzer:in befindet und es können Benachrichtigungen zugehörig zu dem entsprechenden Server angezeigt werden. Zudem wird eine Verlinkungen zum eigenen Profil angezeigt.
Diese LiveView bietet eine Übersicht über alle erstellen Server. Die Server können nach dem Beitrittsstatus gefiltert werden. Der Beitrittsstatus wird entsprechend live aktualisiert. Der/die aktuelle Nutzer:in kann zu den bereits beigetretenen Servern navigieren oder ihnen beitreten.
In dieser LiveView kann ein neuer Server angelegt werden. Der/die aktuelle Nutzer:in, die den Server erstellt, bekommt automatisch die Server-Rolle des »Administrators« und tritt dieser automatisch bei.
Diese LiveView können nur Admins des aktuellen Servers einsehen, da hier Einstellungen am Server vorgenommen werden können.
Zu den Einstellungen zählen:
- Server löschen
- Bearbeitung Name, Beschreibung, Bild
- Erstellung neuer Chatrooms mit Name, Beschreibung
- Löschen von Chatrooms
- Erstellung von Server Rollen mit Name, Beschreibung
- Löschen von Server Rollen
- Hinzufügen von Mitgliedern
- Löschen von Mitgliedern
- Bearbeitung der Server Rolle eines Mitglieds
Diese LiveView zeigt den aktuell geöffneten Chatroom. Neben der Server Sidebar befindet sich nun eine zweite Ansicht – die Chatroom Liste.
Diese Komponente beinhaltet viele Informationen zu dem aktuellen Server. Darunter zählen:
- Auflistung der aktuell verfügbaren Chatrooms, zu die der/die aktuelle Nutzer:in die Leserechte besitzt.
- Neue Benachrichtigungen in einem Chatroom werden mit einem kleinen orangenen Punkt neben dem Chatroom-Namen angezeigt. Diese Hervorhebung verschwindet nach einer Zeit, sobald die neuen Nachrichten gelesen wurden.
- Auflistung der Mitglieder des aktuellen Servers
- Darstellung des Online-Status jedes Mitglieds
Auf der rechten Seite der Ansicht befindet sich das Chatfenster. Hier können Nachrichten je nach vergebener Chatroom-Rolle gelesen, empfangen und/oder gelöscht werden. Zusätzlich kann zu einer Nachricht eine Datei angehängt und verschickt werden, die andere Nutzer:innen zur Ansicht herunterladen können. Die Nachrichten sind mithilfe eines Dialog-Fensters durchsuchbar und falls gewünscht, kann zu der gesuchten Nachricht navigiert werden.
Neue Nachrichten werden mit einem kleinen orangenen Punkt hervorgehoben. Diese Hervorhebung verschwindet jedoch nach einer Zeit, sobald die Nachricht gelesen wurde.
Falls die aktuelle Nutzer:in über das entsprechende Recht verfügt, die Chatroom zu verwalten, wird oben in der rechten Ecke ein Button angezeigt, der die Chatroom-Einstellungen aufruft.
Diese LiveView können nur Nutzer:innen sehen, die auch die nötigen Rechte zum Verwalten dieses Chatrooms vorweisen können. Hier können Einstellungen am Chatroom vorgenommen werden.
Zu den Einstellungen zählen:
- Chatroom löschen (solange der aktuelle Chatroom nicht protected ist)
- Bearbeitung Name, Beschreibung
- Hinzufügen von Server Rollen zur Chatroom
- Entfernen von Server Rollen vom Chatroom
- Bearbeitung der Berechtigungen einer Server Rolle
In dieser LiveView werden die Informationen des eigenen Profils angezeigt und der/die akteulle Nutzer:in kann sich ausloggen. Zu den dargestellten Informationen zählen das Bild, der Name, die Beschreibung und die E-Mail Adresse. Zudem kann der/die akteulle Nutzer:in von dieser Ansicht aus zu den Profil-Einstellungen navigieren.
Hier können die eigenen Nutzer:innen-Daten bearbeitet werden.
Darunter fallen:
- Öffentliche Daten bearbeiten: Bild, Name, Beschreibung
- E-Mail Adresse ändern: mit Passwort-Eingabe zur Bestätigung
- Passwort ändern: Eingabe des alten Passwortes und Wiederholung des neuen Passwortes
Diese beiden LiveViews wurden mithilfe des Authentication Generators von Phoenix erstellt. Diese wurden dem Design entsprechend angepasst und vereinfacht.
Alle Echtzeitaktualisierungen wurden mithilfe von PubSub (als Event publisher/subscriber service), LiveViews und deren Assignments bzw Streams verwirklicht.
Dadurch werden folgende Stellen automatisch aktualisiert:
- Update der Server Sidebar und der Server-Übersicht, sobald der/die aktuelle Nutzer:in zu einem Server hinzugefügt wurde oder aus einem Server entfernt wurde
- Update der Chatroom-Liste, sobald ein neuer Chatroom von einem selbst oder von anderen Nutzer:innen erstellt, entfernt oder Leserechte der eigenen Rolle geändert wurden.
- Update der Mitglieder Liste, sobald ein Mitglied den Server beigetreten ist oder verlassen hat
- Verschicken, Empfangen und Löschen von Nachrichten (mit Dateien)
- Benachrichtigungen
Die Endpunkte werden durch ein Berechtigungssystem geschützt. Die Funktionalität der Rollen und Berechtigungen orientiert sich stark an dem Messagingdienst »Discord«. Es können serverweite Rollen erstellt werden, wobei die Rollen »Administrator« und »Mitglied« bei der Servererstellung automatisch angelegt werden. Die Rolle des Administrators hat die höchste Berechtigungsstufe und ermöglicht die Verwaltung des gesamten Servers und aller Chatrooms. Nur Nutzer:innen mit der Administrator-Rolle können einen Server löschen. Zudem kann ihnen die Administrator-Rolle nicht entzogen und ihre Berechtigungen nicht degradiert werden. Die Rolle Mitglied hat keine weiteren Berechtigungen, mit Ausnahme des Zugriffs auf einen Standardkanal »General«.
Weiterhin existieren noch Berechtigungen für jede Server-Rolle pro Chatroom. Es kann pro Server Rolle entschieden werden, welche Berechtigungen und Zugriffsrechte die entsprechenden Nutzer:innen im Chatroom haben.
Dabei wird unterschieden zwischen folgenden Berechtigungen:
:allow_chatroom_manage(Chatroom verwalten):allow_message_read(Nachrichten in Chatroom lesen bzw. den Chatroom sehen):allow_message_write(Nachrichten in Chatroom schreiben):allow_message_delete_all(Nachrichten in Chatroom von anderen Nutzer:innen löschen)
Je nach entsprechender Berechtigung werden im Frontend entsprechende Features nicht angezeigt und Routen geschützt, sodass nur autorisierte Zugriffe zugelassen werden. Bei der Aktualisierung von Berechtigungen werden die sichtbaren Elemente angepasst.
Bei Erstellung eines Servers wird zudem automatisch der Chatroom »General« erstellt. Dieser kann nicht gelöscht werden, da er als Einstiegspunkt des Servers gilt.
Serverseitig wurden bereits Vorbereitungen getroffen, dass Nutzer:innen mehrere Rollen zugewiesen werden können, dies wurde auf Komplexitätsgründen mit Frontend noch nicht implementiert.
Das Versenden und Empfangen von Textnachrichten wurde mithilfe von PubSubs (als Event-Dispatcher bzw. Subscriber) und Streams entwickelt. So wird es ermöglicht, dass der Chatverlauf live aktualisiert wird. Das Verhalten der Chatansicht wurde mit Hilfe von JavaScript-Hooks erweitert, so dass die Liste der Nachrichten nach unten zur neusten Nachricht scrollt, sobald eine neue Nachricht gesendet wird oder die Chatroom-Ansicht geöffnet wird. Beim Versenden bzw. Empfangen von Nachrichten werden die Rechte der/die aktuelle Nutzer:in berücksichtigt. Die Abwicklung des Prozesses erfolgt durch den MessageManager.
Einer Textnachricht können Dateien angehängt werden. Dafür öffnet sich ein Dialog-Fenster, welches dem/der Nutzer:in erlaubt, eine Datei im Format .png, .jpg, .jpeg, .gif oder .pdf hochzuladen. Diese wird bei Bestätigung versendet. Empfänger:innen der Nachricht können diese dann herunterladen.
Nachrichten können mithilfe einer integrierten Suchfunktion nach Schlagworten durchsucht werden. Der gesuchte Inhalt wird an den MessageManager weitergegeben, der mithilfe des Repos die verschickten Nachrichten in einem Chatroom nach dem gesuchten Inhalt durchsucht und die Ergebnisse zurückgibt. Diese werden in einer Liste live angezeigt. Falls der/die Nutzer:in eine Nachricht genauer untersuchen möchte, kann diese per Sprunglink im Chatverlauf angezeigt werden. Um Sprunglinks zu ermöglichen, wurde ein JavaScript-Hook erstellt.
Die Daten werden mit dem ORM »Ecto« persistiert. Es wurden Schemata sowie Repos für die verschiedenen zu persistierenden Daten geschrieben. Für die Einhaltung von Zugangsbeschränkung wurde eine Geschäftslogik-Schicht (wo geeignet) in Form von Managern implementiert, welche nach Berechtigungsprüfung die Informationen an implementierte Repositories weitergibt und auch für das Event-Dispatching zuständig sind.
Es werden Benachrichtigungen angezeigt, sobald eine Nachricht verschickt und noch nicht gelesen wurde. Die Benachrichtigungen werden in Form von orangenen kleinen Kreisen dargestellt.
- Server Sidebar: Die Benachrichtigung zeigt an, in welchem Server eine ungelesene Nachricht empfangen wurde. Zu dem Chatroom, der die Nachricht zugeordnet ist, muss der/die aktuelle Nutzer:in allerdings mind. Leserechte besitzen, ansonsten wird keine Benachrichtigung erstellt bzw. visualisiert.
- Chatroom-Seitenleiste: Die Benachrichtigung zeigt an, in welchem Chatroom sich die ungelesene Nachricht befindet. Zu dem Chatroom muss der/die aktuelle Nutzer:in allerdings mind. Leserechte besitzen.
- Nachricht: Die Benachrichtigung zeigt an, welche Nachricht alles als ungelesen markiert ist.
Bei erfolgreicher Übermittlung einer Nachricht in einem Chatroom wird nach der erfolgreichen Persistierung für alle autorisierten Nutzer des entsprechenden Chatrooms überprüft, ob diese online sind und sich aktuell im Chatroom befinden. Sind diese nicht online bzw. nicht im selben Chatroom aktiv, wird eine neue Benachrichtigung erstellt. Mittels PubSubs werden die entsprechenden Stellen benachrichtigt, die sich aktualisieren müssen, um die neue Beanchrichtigung visualisieren zu können.
Um eine Nachricht als gelesen zu markieren, wird mittels eines JavaScript-Hooks überprüft, ob sich die ungelesene Nachricht sich im ViewPort befindet. Nach 2 Sekunden wird ein Event ausgelöst, welches die Nachricht als gelesen markiert.
Dieses Feature könnte ihn Zukunft auch ausgebaut werden, um beispielweise die anderen Nutzer zu informieren, ob eine Nachricht von einem/einer bestimmten Nutzer:in gelesen wurde.
Die Strukturierung des Elixir-Codes bzw. der Phoenix-Applikation war initial ein Problem, da sich dynamisch wachsend verschiedene Konventionen entwickelt haben. Es wurde darauf folgend entschlossen, das Backend aufzuteilen in Repo, Schema und Manager, wobei der Manager auf beide zugreift und als Ansprechpunkt für das Frontend dient. Alternativ dazu, bestand das Konzept der Kontext-basierten Aufteilung des Codes. Dies wurde aber verworfen, um den Code besser strukturieren zu können.
Hilfsfunktionen wurden in Utils-Module ausgelagert um beispielweise die Authentifizierung bei jeder Anfrage zu erleichtern und allgemein modul-übergreifende Funktionen zur Verfügung zu stellen.
Das Implementieren von Avataren bzw. der Uploadfunktion hat einige Herausforderungen mit sich gebracht. Es gibt verschiedene Guidelines bzw. Ansätze für das Hochladen von Dateien, wie beispielweise das Plug.Upload-Feature (multipart HTTP file uploads). Dieses ist auch für File-Upload gedacht, aber nicht für die Nutzung mit LiveViews geeignet. Verwendet wurde schließlich ein live_file_input (asynchronous websocket chunk uploads).
Das Speichern in der Datenbank war die nächste Avatar-bezogene Herausforderung, da das Teammitglied, welches sich um die Umsetzung gekümmert hat, keine Erfahrung im Arbeiten mit File-Uploads besaß. Auch die recherchierten LiveView-Umsetzungen waren für das Persistieren der Daten als Datei im Dateisystem und nicht das für das Speichern einer Datei in einer Datenbank. Auch der mime-type musste persistiert werden.
Das Speichern des Bildes in die Datenbank wurde über das Enkodieren in Base64 gelöst. So konnte es als Binärdaten-String abgespeichert werden. Das encodierte Bild wurde in folgender Form abgelegt: data:#{mime_type};base64,#{base64_encoded_image}. Dies ermöglicht auch das direkte Einbinden aus der Datenbank in die Website.
Streams zeigten sich als hilfreiches Werkzeug für das Verwalten von Mengen für die Echtzeitdarstellung. Im Allgmeinen funktionierten diese auch wie erwartet. Die erste Herausforderung war die Nutzung von Steams innerhalb von Kind-LiveViews einer anderen LiveView. Dies wurde benötigt um eine sich selbstverwaltende seitenübergreifende LiveView für die Server-Sidebar zu implementieren. Aufgrund dieser Struktur sind gleich mehrere Probleme aufgetreten.
Um die Liste der Server in der Übersicht filtern zu können, muss der verwendete Stream zurückgesetzt werden. Das Zurücksetzen verhindert, dass die gleichen Inhalte nicht mehrmals aneinander gekettet werden. Dies hat jedoch auch dazu geführt, dass alle genutzten Streams in den Kind-LiveViews ebenfalls resettet wurden. Dieses Phönomen konnte repliziert werden, indem ein beliebiger (verwendeter) Stream in der Eltern-LiveView resettet wurde. Dies hatte immer zur Folge, dass der Stream in der Kind-LiveView ebenfalls zurückgesezt wurde. Das Problem konnte mit einem Workaround gelöst werden, indem die DOM-ID des Kind-Streams manipuliert wurde. Die Phoenix-Community hat dieses Problem auch schon teilweise bearbeitet.
Hier ist die Auflistung der grundlegenden Beiträge der einzelnen Teammitglieder. Es ist wichtig anzumerken, dass als Team gemeinsam am Projekt gearbeitet wurde und Probleme des Öfteren nicht alleine gelöst wurden.
Philipp Borucki
- Erstellung und Strukturierung der Datenbank
- Erstellung aller Repo-Funktionen & Schemata
- Presence von Nutzer:innen
- Implementierung der Chat-Funktionalität
- Echtzeitaktualisierung bzw. Interaktion mithilfe von PubSubs
- Implementierung von Rechten & Rollen
- Implementierung von Benachrichtigungen
Pascal Friedrichsen
- Erstellung und Strukturierung der Datenbank
- Implementierung der Avatare (Uploads und Nutzung)
- Implementierung der Suchfunktion von Nachrichten
- Implementierung von Rechten & Rollen
- Erstellung der Dokumentation
Dorien Grönwald
- Erstellung des Designs
- Umsetzung des Frontends mit LiveViews
- Erstellung & Filterung der Server-Liste als LiveView
- Darstellung & Editierbarkeit der Server & der Chatrooms
- Editierbarkeit des eigenen Profils
- Anpassungen der Suchfunktion & Dateianhänge
- Presence von Nutzer:innen
- Implementierung von Rechten & Rollen
- Implementierung von Benachrichtigungen
Dominik Heckner
- Erstellung und Strukturierung der Datenbank
- Implementierung von Dateianhängen bei Nachrichten
- Anzeigen der Nutzer:innen-Informationen
- Darstellung der Chatroom-Namen
- Anpassung des Server-Erstellungs-Formulars
- Erstellung der Dokumentation
Anforderungen:
- ✓ Nutzt Phoenix zur Erstellung der Anwendung und Ecto zur Datenpersistenz.
- ✓ Die Anwendung sollte Nutzer:innenregistrierung und -anmeldung unterstützen.
- ✓ Nutzer:innen sollten in der Lage sein, Chatrooms zu erstellen und anderen Chatrooms beizutreten.
- ✓ Innerhalb eines Chatrooms sollte jede/r Nutzer:in in Echtzeit Nachrichten senden und empfangen können.
- ✓ Nachrichten in einem Chatroom sollten persistent sein und beim Betreten des Chatrooms angezeigt werden.
- ✓ Nutzt Phoenix LiveView, um die Echtzeit-Interaktionen zu ermöglichen.
Bonuspunkte:
- ✓ Fügt Rollen und Berechtigungen hinzu (z.B. Moderatoren, Administratoren).
- ✓ Ermöglicht das Senden und Empfangen von Dateianhängen in den Chatrooms.
- ✓ Baut eine Suchfunktion ein, um alte Nachrichten nach Schlüsselwörtern zu durchsuchen.
Weitere Features außerhalb der Anforderungen:
- ✓ Notifikationen, wenn jemand eine neue Nachricht schreibt (siehe 7.3.2)
- ✓ Online-Status der Mitglieder eines Servers/Chatrooms (siehe 7.3.3)
- ✓ Navigation zur gesuchten Nachricht bei der Suchfunktion (siehe 7.3.6.2)
Der vorgeschlagene Bonuspunkt "Implementiert @Erwähnungen von Nutzer:innen in Chatnachrichten." wurde von uns nicht implementiert.
Folgend sind die von uns verwendeten Datentypen in unserer Datenbank.
| Name | Datentyp | Beschreibung |
|---|---|---|
| id | binary_id (uuid) | Der Kennzeichner des Servers |
| name | string | Der Name des Servers |
| description | string | Die Beschreibung des Servers |
| avatar | bytea (binary) | Das Bild des Servers gespeichert als Base64-Binär mit mime-type |
| Name | Datentyp | Beschreibung |
|---|---|---|
| id | binary_id (uuid) | Der Kennzeichner des Chatrooms |
| name | string | Der Name des Chatrooms |
| description | string | Die Beschreibung des Chatrooms |
| type | string | Typ des Chatrooms. Auswahl zwischen [ text, voice ], wobei voice nicht implementiert ist. |
| is_default | boolean | Ob der Chatroom ganz oben angezeigt werden soll. Wird ausschließlich für den Standard-Chatroom genutzt. |
| is_protected | boolean | Ob der Chatroom gelöscht werden darf. Wird ausschließlich für den Standard-Chatroom genutzt. |
| server_id | binary_id | Referenz zum Server, zu dem der Chatroom gehört |
| inserted_at | timestamp | Die Zeit, zu der erstellt wurde |
| updated_at | timestamp | Die Zeit, zu der aktualisiert wurde |
| Name | Datentyp | Beschreibung |
|---|---|---|
| id | binary_id (uuid) | Der Kennzeichner des Users |
| string | Die E Mail-Adresse des Users | |
| hashed_password | string | Das Passwort des User |
| confirmed_at | timestamp | Nicht implementiert |
| name | string | Der Name des User |
| description | string | Die Beschreibung des User |
| avatar | bytea (binary) | Das Bild des Servers gespeichert als Base64-Binär mit mime-type |
| inserted_at | timestamp | Die Zeit, zu der erstellt wurde |
| updated_at | timestamp | Die Zeit, zu der aktualisiert wurde |
| Name | Datentyp | Beschreibung |
|---|---|---|
| id | binary_id (uuid) | Der Kennzeichner der ServerRole |
| name | string | Der Name der ServerRole |
| description | string | Die Beschreibung der ServerRole |
| is_default | boolean | Gibt an, ob die ServerRole beim erstellen des Servers mit generiert wird |
| is_protected | boolean | Gibt an, ob die ServerRole bearbeitet oder gelöscht werden kann |
| is_admin | boolean | Gibt an, ob die ServerRole Adminrechte hat |
| server_id | binary_id (uuid) | Referenz zum Server, zu dem der ServerRole gehört |
| inserted_at | timestamp | Die Zeit, zu der erstellt wurde |
| updated_at | timestamp | Die Zeit, zu der aktualisiert wurde |
| Name | Datentyp | Beschreibung |
|---|---|---|
| id | binary_id (uuid) | Der Kennzeichner der Messages |
| text | string | Der Textinhalt der Messages |
| chatroom_id | binary_id (uuid) | Referenz zum Chatroom, zu dem die Nachricht gehört |
| user_id | binary_id (uuid) | Referenz zum Chatroom, zu dem die Nachricht gehört |
| inserted_at | timestamp | Die Zeit, zu der erstellt wurde |
| updated_at | timestamp | Die Zeit, zu der aktualisiert wurde |
| Name | Datentyp | Beschreibung |
|---|---|---|
| id | binary_id (uuid) | Kennzeichner der File |
| size | int | Größe der File |
| type | string | Auswahl aus [file, voice, image], wobei voice nicht implementiert ist |
| path | string | Pfad zur File |
| description | string | Beschreibung der File |
| mime | string | mime-type der File (z.b. image/png) |
| message_id | binary_id (uuid) | Referenz zur Message, zu dem die File gehört |
| inserted_at | timestamp | Die Zeit, zu der erstellt wurde |
| updated_at | timestamp | Die Zeit, zu der aktualisiert wurde |
| Name | Datentyp | Beschreibung |
|---|---|---|
| id | binary_id (uuid) | Der Kennzeichner der Notification |
| read | boolean | Gibt an, ob die Notification gesehen wurde |
| message_id | binary_id (uuid) | Referenz zur Massage der Notification |
| user_id | binary_id (uuid) | Referenz zum User |
| inserted_at | timestamp | Die Zeit, zu der erstellt wurde |
| updated_at | timestamp | Die Zeit, zu der aktualisiert wurde |
| Name | Datentyp | Beschreibung |
|---|---|---|
| id | binary_id (uuid) | Der Kennzeichner der ChatroomRolePermissions |
| allow_chatroom_manage | boolean | Die Role ist berechtigt den Chatroom zu verwalten |
| allow_chatroom_read | boolean | Die Role ist berechtigt Messages zu lesen |
| allow_chatroom_write | boolean | Die Role ist berechtigt Messages zu schreiben |
| allow_chatroom_delete_all | boolean | Die Role ist berechtigt Messages von anderen zu löschen |
| chatroom_id | binary_id (uuid) | Referenz zum Chatroom, zu dem die ChatroomRolePermission gehört |
| server_role_id | binary_id (uuid) | Referenz zur ServerRole, zu dem die ChatroomRolePermission gehört |
| inserted_at | timestamp | Die Zeit, zu der erstellt wurde |
| updated_at | timestamp | Die Zeit, zu der aktualisiert wurde |
| Name | Datentyp | Beschreibung |
|---|---|---|
| server_id | binary_id (uuid) | Referenz zum Server, zu dem der ServerUser gehört |
| user_id | binary_id (uuid) | Referenz zum User, zu dem der ServerUser gehört |
| inserted_at | timestamp | Die Zeit, zu der erstellt wurde |
| updated_at | timestamp | Die Zeit, zu der aktualisiert wurde |
| Name | Datentyp | Beschreibung |
|---|---|---|
| server_role_id | binary_id (uuid) | Referenz zur ServerRole |
| user_id | binary_id (uuid) | Referenz zum User |
| inserted_at | timestamp | Die Zeit, zu der erstellt wurde |
| updated_at | timestamp | Die Zeit, zu der aktualisiert wurde |
Anmerkung: Auch wenn ServerRole und User eine many-to-many relation in der Datenbank haben, hat jeder Nutzer nur eine Role. Es wurde sich aus zeitlichen Gründen gegen die Frontend-Implementierung mehrere Roles pro User entschieden. Das Backend ist dafür aber technisch bereits voll vorbereitet.
Hier sind Bilder unserer Anwendung um das Design festzuhalten. Alle visuell-interessanten Features sind in den Screenshots vertreten.
| 8.4 Profil |
|---|
8.4.1 - Profil des Users |
8.4.2 - Profil bearbeiten |
8.4.2.1 - Profil bearbeiten (heruntergescrollt) - E-Mail und Passwort ändern |



























