diff --git a/Chapters/2-Planung.typ b/Chapters/2-Planung.typ index 3f0c987..61e89fc 100644 --- a/Chapters/2-Planung.typ +++ b/Chapters/2-Planung.typ @@ -56,6 +56,7 @@ Es gibt eine schema.prisma-Datei (@moduletable), in der die Struktur der relatio In @moduletable ist beispielsweise zu sehen, wie eine Tabelle mit dem Namen "Module" definiert ist. Die Tabelle hat unter anderem eine Spalte id, mit dem Datentypen Int und einen name mit dem Datentypen String. +#pagebreak() #codeFigure("Auszug aus schema.prisma", , "moduleTablePrisma") @@ -86,7 +87,7 @@ Die kritischste Schwachstelle sind hier Redundanzen. Die Eigenschaften eines Mod Als Vorbereitung für ein neues System wurden vom Studiendekan die zuvor genannten Word Dokumente maschinell eingelesen, in ein JSON-Format umgewandelt und anschließend in eine PostgresSQL-Datenbank eingespielt. Weiterhin wurde ein Python Script erstellt, welches aus den Datensätzen in der Datenbank mithilfe von LaTeX ein PDF-Dokument für die Modulhandbücher generieren kann. Die Datenbank enthält jedoch weiterhin Redundanzen und könnte daher optimiert werden. - +#pagebreak() == Zielgruppen Im folgenden Abschnitt sollen die verschiedenen Zielgruppen eines Modulhandbuches ermittelt und definiert werden. Die Übersicht der Zielgruppen wird für die später folgende Ermittlung der Use Cases benötigt (@usecases). Hierdurch wird ermöglicht zu verstehen, wer das Modulhandbuch verwenden wird und welche Anforderungen die verschiedenen Gruppen haben. Zur Ermittlung wurde zum einen im ECTS User-Guide @ects recherchiert und zum anderen das Interview (@interview) genutzt. @@ -577,5 +578,3 @@ Reges, S., Stepp, M.: Building Java Programs, Prentice Hall", label: , "mockups/Grundgerüst.svg", "Toolbar") +#let toolbarImage = imageFigure(, "mockups/Grundgerüst.svg", "Toolbar") #let boxedToolbarImage = box(toolbarImage, inset: 0.5em) @@ -129,7 +129,7 @@ Um mit möglichst wenig Aufwand (@CLICKS) jederzeit die Suchfunktion (@SEARCH) n Funktionen, die nicht oft benötigt werden, werden in einer ausklappbaren Seitenleiste (Drawer) platziert. Der Drawer kann mithilfe eines Knopfes ausgeklappt werden, welcher sich auf der Toolbar befindet. Somit können auch diese Funktionen mit wenig Aufwand (@CLICKS) von jeder Ansicht aus erreicht werden. Im Drawer sind die Masken zur Verwaltung der Benutzer (@CRUSER), zur Anzeige gelöschter Module (@SOFTDELETE) und zur Ansicht alter Prüfungsordnungen (siehe @drawer). Außerdem wird hier die Versionsnummer angezeigt, damit jederzeit überprüft werden kann, mit welcher Version des Systems gearbeitet wird.] -#let drawerImage = imageFigureNoPad(width: 40%, +#let drawerImage = imageFigure(width: 40%, , "mockups/Drawer.png", "Drawer") //#wrap-content(align: bottom + right, drawerImage, drawerText) @@ -137,14 +137,14 @@ Um mit möglichst wenig Aufwand (@CLICKS) jederzeit die Suchfunktion (@SEARCH) n #drawerImage -#box[ + === Komponenten und Ansichten #heading(level: 4, numbering:none, "Login") #let loginText = [ Wenn ein User administrative Aufgaben übernehmen möchte, muss er sich zunächst über den Login-Button im Drawer (@drawer) anmelden (@LOGIN). Hierzu wird ein Screen benötigt, auf dem der User seine E-Mail und sein Passwort eingeben kann. Da Accounts von der studiengangsverantwortlichen Person erstellt werden (@CRUSER), wird auf dieser Seite keine Möglichkeit benötigt, sich selbst zu registrieren. Damit verständlich ist, wie ein Account erstellt werden kann, wird diese Information als Infotext unter dem Login-Button platziert (siehe @login).] -#let loginImage = imageFigureNoPad(, "mockups/Login.png", "Login", width: 20em) +#let loginImage = imageFigure(, "mockups/Login.png", "Login", width: 20em) //#wrap-content(align: top + right, loginImage, loginText) @@ -152,7 +152,7 @@ Wenn ein User administrative Aufgaben übernehmen möchte, muss er sich zunächs #loginText #loginImage -] + #box[ @@ -171,23 +171,23 @@ Wenn ein User administrative Aufgaben übernehmen möchte, muss er sich zunächs -#box[ + #heading(level: 4, numbering:none, "Navigation") Auf der Startseite der neuen Anwendung soll nicht direkt die Modulübersicht präsentiert werden, weil diese ohne gesetzte Filter überladen wirken könnte. Stattdessen wird der User zunächst auf eine Übersicht aller Fakultäten geleitet (@navigationMockup). Hier kann entweder eine Fakultät ausgewählt werden, oder es kann per Klick auf "Alle Module" direkt zur Modulübersicht gewechselt werden. Die Farben der einzelnen Fakultäten sind dieselben wie auf der Website der #hsh @HochschuleHannover und sollen den User dabei unterstützen, schnell die richtige Fakultät zu finden. Diese Ansicht wird übersprungen, falls der User einen direkten Link zu einem bestimmten Studiengang aufruft. Dieser Link könnte beispielsweise auf der Website der Hochschule platziert sein. Der User wird dann direkt zur Modulübersicht geleitet. -#imageFigureNoPad(, "mockups/Navigation.png", "Startseite - Auswahl Fakultät") -] +#imageFigure(, "mockups/Navigation.png", "Startseite - Auswahl Fakultät") + + -#box[ Wenn in der Fakultätsauswahl eine Fakultät ausgewählt wurde, geht es weiter auf die Detailansicht der jeweiligen Fakultät (@navigationMockupLevel2). Hier werden alle Studiengänge der Fakultät aufgelistet. Die Studiengänge sind gruppiert nach der Abteilung, zu der sie zugehörig sind. Zur besseren Übersicht sind die Bachelorstudiengänge über den Masterstudiengängen angeordnet und zusätzlich farblich markiert. Des Weiteren gibt es die Möglichkeit in der oberen Leiste gezielt nach einem Studiengang zu suchen, oder nach Bachelor/Master zu filtern. Sobald auf dieser Übersicht ein Studiengang angeklickt wird, öffnet sich die Modulübersicht. In der Modulübersicht sind dann die Filter automatisch an die zuvor ausgewählte Fakultät und den ausgewählten Studiengang angepasst. -#imageFigureNoPad(, "mockups/NavigationLevel2.png", "Startseite - Auswahl Studiengang") -] +#imageFigure(, "mockups/NavigationLevel2.png", "Startseite - Auswahl Studiengang") -#box()[ - + + +#pagebreak() #heading(level: 4, numbering:none, "Modulübersicht") #let moduleOverviewText = [ In der Modulübersicht (@moduleoverview) sollen alle Module in einer tabellarischen Übersicht angezeigt werden. In der Tabelle sollen nur die für #link()[Use Case 2] benötigten Daten gezeigt werden. Alle weiteren Informationen sind dann in der detaillierten Ansicht zu finden. Die detaillierte Ansicht soll sich durch Anklicken eines Eintrags öffnen. Über der Tabelle gibt es mehrere Filtermöglichkeiten, um die gesuchten Module schneller finden zu können. @@ -199,7 +199,7 @@ Wenn in der Fakultätsauswahl eine Fakultät ausgewählt wurde, geht es weiter a #wrap-content(align: bottom + right, moduleOverview, moduleOverviewText) //#moduleOverviewText //#moduleOverview -] + #heading(level: 4, numbering:none, "Detailansicht eines Modules") @@ -320,7 +320,7 @@ Der Endpunkt /modules soll zusätzlich POST-Anfragen entgegennehmen können, um Hier sollten alle Informationen zur Verfügung gestellt werden, die für die Änderungshistorie eines Moduls benötigt werden (@changelogImage). Dazu gehört die Auflistung aller vorgenommenen Änderungen, der Autor der Änderung, sowie der erklärende Text, der bei einer Änderung angegeben werden muss (@changeMsgImg). -#heading(level: 4, numbering: none)[/submodules] +#heading(level: 4, numbering: none)[Endpunkt /submodules] Ähnlich wie schon bei /modules wird eine Auflistung aller Teilmodule benötigt. Damit Teilmodule auffindbar sind, sollte die Auflistung den Namen des Teilmodules enthalten. Außerdem könnte die verantwortliche Person enthalten sein, damit Modulverantwortliche Personen nach den Teilmodulen filtern können, für die sie verantwortlich sind. Der Endpunkt /submodules soll zusätzlich POST-Anfragen entgegennehmen können, um neue Teilmodule anzulegen. diff --git a/Chapters/4-Implementierung.typ b/Chapters/4-Implementierung.typ index 58e3ca9..7a1be84 100644 --- a/Chapters/4-Implementierung.typ +++ b/Chapters/4-Implementierung.typ @@ -60,7 +60,7 @@ Prisma bietet weiterhin eine Methode upsert an, die die Update-Methode und die C #pagebreak() #codeFigure("Backend: Erstellen und Bearbeiten von Modulen", , "endpointBefore") - +#pagebreak() Abschließend muss evaluiert werden, ob der entstandene Code verständlich und kompakt genug ist. Das vorgestellte Beispiel ist durch die vielen komplexen Datentypen stark gewachsen. Um den Code also wartbarer, lesbarer und verständlicher zu machen, wurde zuletzt noch die Codequalität optimiert. Hierzu wurden statt einer gemeinsamen Upsert-Methode zwei unterschiedliche Methoden (Create und Update) erstellt. Hierdurch wurde die Zuständigkeit klarer definiert. Außerdem wurden die verschiedenen Zuweisungen der komplexen Datentypen in jeweils eigene Methoden extrahiert. Dies hatte neben des nun weitaus besser lesbaren Codes den zusätzlichen Vorteil, dass die Methoden an verschiedenen Stellen verwendet werden konnten, sodass redundanter Code verringert wurde. Jedoch ergab sich daraus auch ein Nachteil. Durch das sequenzielle Verändern der Daten innerhalb der Methode bestand die Gefahr, dass die ersten Veränderungen erfolgreich sind, aber beispielsweise beim Zuweisen der zuständigen Person ein Fehler auftritt. In diesem Fall wäre das Update nur teilweise erfolgreich. In der früheren Version als alle Updates in einer Abfrage stattfanden, wäre in so einem Fall das gesamte Update fehlgeschlagen. Ein mögliches Teilupdate kann zu unerwarteten Fehlern führen und ist für den Benutzer des Systems entweder nur schwer zu erkennen oder unverständlich. Um dieses Verhalten wiederherzustellen, wurden letztlich alle Anweisungen in einer Transaktion @TransactionsBatchQueries zusammengefasst. Hierdurch konnte der Vorteil der besseren Codequalität bestehen bleiben und dennoch das gewünschte Verhalten erzielt werden. Im Falle eines Fehlers macht Prisma nun automatisch die bisher vorgenommenen Änderungen rückgängig, sodass keine inkonsistenten Daten entstehen können. Der neue Code ist deutlich lesbarer (siehe @endpointAfter). #codeFigure("Backend: Erstellen und Bearbeiten von Modulen (Verbessert)", , "endpointAfter") @@ -91,6 +91,8 @@ Des Weiteren ist es wichtig, zwischen öffentlichen und privaten Endpunkten zu u #codeFigure("public.decorator.ts", , "publicDecorator") +#pagebreak() + #codeFigure("module.controller.ts", , "getModule") #codeFigure("jwt-auth.guard.ts", , "authGuard") @@ -254,6 +256,7 @@ Damit jede Komponente weiß, welche Sprache gerade dargestellt werden soll, wird Der LanguageService hat eine Methode `getLanguages`, mit der an verschiedenen Stellen in der Anwendung angezeigt werden kann, welche Sprachen zur Auswahl stehen. Außerdem sind Getter und Setter für die Eigenschaft `languageCode` implementiert. Im Setter wird die ausgewählte Sprache in den LocalStorage geschrieben, damit die Benutzer der Website nicht bei jedem Besuch erneut ihre Sprache auswählen müssen. Außerdem wird die neu ausgewählte Sprache an das `languageSubject` weitergegeben. Das `languageSubject` ist ein BehaviourSubject aus der Erweiterungsbibliothek RxJS @RxJSBehaviorSubject. Nach dem Observer-Pattern-Prinzip können andere Komponenten und Services das languageSubject beobachten und erhalten im Falle einer Veränderung eine Benachrichtigung. Somit können beim Wechsel der Sprache die neuen Texte geladen werden. + #codeFigure("language.service.ts", , "languageService") @@ -332,6 +335,7 @@ In @components sind die einzelnen Komponenten einer Bearbeitungsmaske (z.B. die #codeFigure("Two-Way-Binding", , "two-way") +#pagebreak() Außerdem lädt das Edit-Component für jede Sprache ein Translator-Component. Das Translator-Component hat die Aufgabe, die benötigte Sprache zu laden und im Translations-Array an die erste Stelle zu schieben. Dies ist notwendig, weil in den folgenden Editor- und Preview-Komponenten immer auf den ersten Eintrag im Array geschaut wird. Wenn im Preview-Component beispielsweise der Name des Moduls gezeigt werden soll, wird `module.translations[0].name` aufgerufen. @@ -408,13 +412,14 @@ Das Backend benötigt außerdem eine Möglichkeit, Daten langfristig aufzubewahr Nachdem die Images nun erstellt sind und die Compose-Datei die Struktur der Container definiert, kann `podman compose up -d` ausgeführt werden, um die Container zu erstellen und zu starten. In der Desktopanwendung von Podman ist dies nachzuvollziehen (@podmanDesktop). In @dockerDiagram ist eine Übersicht der verschiedenen Container zu sehen. Dort sind die verwendeten Port aufgelistet und es kann erkannt werden, in welche Richtung kommuniziert wird. +#pagebreak() + #codeFigure("compose-Datei", , "compose") #imageFigure(, "podman.png", "Podman Desktop") #imageFigure(, "Docker.png", "Diagramm der eingesetzten Dockercontainer", width: 95%) +#pagebreak() == Zwischenfazit Nachdem Frontend und Backend implementiert wurden und eine Dokumentation erstellt wurde, besteht eine erste lauffähige Version des Systems. Diese Version kann im folgenden @review evaluiert werden, um herauszufinden, ob alle Anforderungen umgesetzt wurden. -#pagebreak() -#hide("grr") \ No newline at end of file diff --git a/Chapters/5-Review.typ b/Chapters/5-Review.typ index 0178ff9..e1be155 100644 --- a/Chapters/5-Review.typ +++ b/Chapters/5-Review.typ @@ -50,7 +50,7 @@ Nachdem die kleineren Anpassungen vorgenommen und mit einer erneuten Überprüfu - +#pagebreak() == Überprüfung, ob Anforderungen erfüllt sind @@ -177,7 +177,7 @@ Im Folgenden wird überprüft, welche Anforderungen erfüllt sind und welche Anf - +#pagebreak() == Zwischenfazit Nachdem die aufgestellten Anforderungen überprüft wurden, kann nun eine Aussage zum neuen System getroffen werden. @@ -186,3 +186,4 @@ Von den 64 Anforderungen wurden 15 Anforderungen nicht erfüllt. Unter den nicht #pagebreak() +#hide("grr") \ No newline at end of file diff --git a/Chapters/Planung/use-cases.typ b/Chapters/Planung/use-cases.typ index d2a1bed..0f93b21 100644 --- a/Chapters/Planung/use-cases.typ +++ b/Chapters/Planung/use-cases.typ @@ -48,7 +48,7 @@ ] - +#pagebreak() #useCase(4, "Datensatz anlegen")[ Der Use Case beschreibt, wie ein neuer Datensatz angelegt werden kann. Das System prüft dabei, ob die angegebenen Informationen plausibel sind. Ein Datensatz kann zum Beispiel ein Modul sein, ein Teilmodul oder ein Studiengang. Zur Übersichtlichkeit wurde nicht für jede Art ein einzelner Use Case erstellt. diff --git a/main.typ b/main.typ index 530feb5..d0fcbc5 100644 --- a/main.typ +++ b/main.typ @@ -22,11 +22,12 @@ date: "13. August 2024", glossaryColumns: 1 ) - + + #include "Chapters/1-Einleitung.typ" #include "Chapters/2-Planung.typ" #include "Chapters/3-Entwurf.typ" #include "Chapters/4-Implementierung.typ" #include "Chapters/5-Review.typ" #include "Chapters/6-Fazit.typ" -#include "Chapters/Anhang.typ" \ No newline at end of file +#include "Chapters/Anhang.typ"