diff options
| author | Orangerot <purple@orangerot.dev> | 2024-05-24 17:42:08 +0200 | 
|---|---|---|
| committer | Orangerot <purple@orangerot.dev> | 2024-05-24 17:47:22 +0200 | 
| commit | 7fcdc1c788725f866de71fc9dfd8c4d1cb132b57 (patch) | |
| tree | 89931c85ae3f149884ba02c69862558e93f01531 /20-implementierungsheft/sections | |
Diffstat (limited to '20-implementierungsheft/sections')
| -rw-r--r-- | 20-implementierungsheft/sections/anforderungsanalyse.tex | 185 | ||||
| -rw-r--r-- | 20-implementierungsheft/sections/apidoc.tex | 191 | ||||
| -rw-r--r-- | 20-implementierungsheft/sections/aufbau.tex | 47 | ||||
| -rw-r--r-- | 20-implementierungsheft/sections/backend.tex | 28 | ||||
| -rw-r--r-- | 20-implementierungsheft/sections/changes.tex | 241 | ||||
| -rw-r--r-- | 20-implementierungsheft/sections/einleitung.tex | 11 | ||||
| -rw-r--r-- | 20-implementierungsheft/sections/features.tex | 43 | ||||
| -rw-r--r-- | 20-implementierungsheft/sections/features.tex.orig | 82 | ||||
| -rw-r--r-- | 20-implementierungsheft/sections/frontend.tex | 196 | ||||
| -rw-r--r-- | 20-implementierungsheft/sections/glossar.tex | 371 | ||||
| -rw-r--r-- | 20-implementierungsheft/sections/methodology.tex | 16 | ||||
| -rw-r--r-- | 20-implementierungsheft/sections/tests.tex | 21 | ||||
| -rw-r--r-- | 20-implementierungsheft/sections/timeline.tex | 7 | 
13 files changed, 1439 insertions, 0 deletions
diff --git a/20-implementierungsheft/sections/anforderungsanalyse.tex b/20-implementierungsheft/sections/anforderungsanalyse.tex new file mode 100644 index 0000000..9af8d4d --- /dev/null +++ b/20-implementierungsheft/sections/anforderungsanalyse.tex @@ -0,0 +1,185 @@ +\newcommand{\newrequirementlist}[1]{ +    % https://www.overleaf.com/learn/latex/Lists#Creating_a_new_list_with_enumitem +    \newlist{#1list}{enumerate}{1} +    \setlist[#1list, 1] +    { +        before=\leavevmode, +        label=\upshape\textlangle #1\arabic*\textrangle, +        ref=\upshape\textlangle #1\arabic*\textrangle, +        resume=#1list +    } +} + +\newrequirementlist{RM} +\newrequirementlist{RS} +\newrequirementlist{RC} +\newrequirementlist{RW} + +\section{Anforderungsanalyse} + +\subsection{ Musskriterien }\label{r:musskriterien} + +Musskriterien: unabdingbare Leistungen der Software. + +\subsubsection*{ Funktionale Anforderungen } + +\begin{RMlist} +    \item\label{r:login} Der Benutzer kann sich im Webfrontend mit einer +    E-Mail-Adresse und einem Pass\-wort erstmalig registrieren und bei +    abgeschlossener Registrierung fortan mit denselben Informationen +    anmelden. +    Für eine erfolgreiche Registrierung muss die angegebene +    E-Mail-Adresse zuerst verifiziert werden.\\ +    \item\label{r:store} Die Liste der \Glspl{abo} eines Benutzers sowie +    der zeitliche Fortschritt beim Anhören(/Ansehen) von jeder begonnen +    \Gls{episode} werden für jeden Benutzer gespeichert. +    \item\label{r:sync} Die Liste der \Glspl{abo} eines Benutzers +    sowie der zeitliche Fortschritt beim Anhören(/Ansehen) von jeder +    begonnenen \Gls{episode} wird automatisch über alle von einem Benutzer +    verknüpften \Gls{podcatcher} aktualisiert. +    Dabei sind der zu synchronisierende Stand der \Glspl{abo} und der +    zeitliche Fortschritt jeweils definiert als derjenige Stand, der +    zeitlich am kürzesten zurückliegt.\\ +    \item\label{r:ui} Das Webfrontend bietet dem Benutzer eine graphische +    Benutzeroberfläche zur Navigation und zur Ansteuerung einzelner +    Funktionalitäten.\\ +    \item\label{r:reset-pw} Der Benutzer kann sein Passwort ändern und es +    gibt eine ,,Passwort vergessen''-Funktion. +    So kann ein angemeldeter Benutzer sein Passwort direkt im Webfrontend +    ändern. +    Im nicht angemeldeten Zustand kann der Benutzer sein Passwort über +    die registrierte E-Mail-Adresse zurücksetzen.\\ +    \item\label{r:show-podcasts} Das Webfrontend bietet dem Benutzer die +    Möglichkeit, sich die Liste seiner \Glspl{abo} anzeigen zu +    lassen. +    Die dabei dargestellten Informationen beinhalten den Namen des +    \Glspl{abo} und eine gerundete Angabe darüber, wie lange es her ist, +    dass der Benutzer das letzte Mal eine \Gls{episode} dieses \Glspl{abo} +    konsumiert hat.\\ +\end{RMlist} + +\subsubsection*{ Nicht-funktionale Anforderungen } + +\begin{RMlist} +    \item\label{r:requests} Der Synchronisations-Server kann mindestens +    50 Anfragen pro Sekunde verarbeiten.\\ +    \item\label{r:desktop-first} Das Webfrontend ist primär für +    Desktop-Benutzer ausgelegt. +    \item\label{r:gpodder} Der Datenaustausch erfolgt über die Gpodder +    \Gls{rest-api} unter Verwendung des Datenformats \Gls{json}. +    \item\label{r:persistent-storage} Die Speicherung der Daten eines +    Benutzers \ref{r:store} über den Synchronisations-Server erfolgt +    persistent in einer \Gls{db}. Diese Daten des Benutzers sind die +    Liste seiner \Glspl{abo} und der zeitliche Fortschritt beim Anhören +    (/Ansehen) aller begonnenen \Glspl{episode}. +    \item\label{r:api-extension} Die \Gls{gpodder} wird um Funktionalitäten +    zur verbesserten Kommunikation zwischen Front- und Backend erweitert +    (siehe \ref{r:login}).\\ +\end{RMlist} + + +\subsection{ Sollkriterien }\label{r:sollkriterien} + +Sollkriterien: erstrebenswerte Leistungen. + +\subsubsection*{ Funktionale Anforderungen } + +\begin{RSlist} +    \item\label{r:man} Das Webfrontend bietet die Möglichkeit eine nicht +    ausgefüllte Benutzeranleitung für das Synchronisieren von \Glspl{podcast} +    anzuzeigen.\\ +    \item\label{r:delete-acc} Der Benutzer kann seinen Account löschen. +    Daraufhin werden alle auf diesen Benutzer bezogenen Daten gelöscht.\\ +\end{RSlist} + +\subsubsection*{ Nicht-funktionale Anforderungen } + +\begin{RSlist} +    \item\label{r:backend-libs} Das Backend wird in \Gls{java} unter Verwendung des +    quelloffenen Frameworks \Gls{spring} implementiert. Weiter wird für die +    \Gls{db} das relationale Open-Source Datenbankverwaltungssystem MariaDB +    eingesetzt. +    \item\label{r:ui-libs} Die Weboberfläche wird mithilfe der +    \Gls{ui-lib} React oder des Webframeworks Vue in JavaScript und +    mit dem Frontend-CSS-Framework Bootstrap entwickelt. +    \item\label{r:ui-source} +    Verwendete \Glspl{ui-lib} werden von einem \Gls{packagemanager}, wie dem Node +    Package Manager (npm) bezogen. Ein \Gls{bundler}, wie vite oder Webpack, +    stellt ein minimiertes Skript von den Teilen der Bibliotheken zusammen, +    die vom Code verwendet werden. Das minimierte Skript wird dann auf einem +    eigenen Server für die Weboberfläche bereitgestellt. +    \item\label{r:spa} Die Weboberfläche wird als \Gls{spa} +    entworfen und aktualisiert dynamisch ihren Inhalt, sobald es eine +    Antwort auf eine Anfrage an die \Gls{gpodder} \ref{r:api-compat} erhält. +    \item\label{r:parse-metadata} Das Backend kann die Metadaten von +    \Gls{podcast} aus +    deren \Gls{rss}-Feeds (XML-Dateien) für die Anzeige im Webfrontend +    \ref{r:show-podcasts} parsen. +    \item\label{r:pw-requirements} Verwendete Passwörter müssen mindestens 8 Zeichen, +    ein Sonderzeichen, eine Zahl sowie einen Klein- und einen Großbuchstaben +    enthalten. +    Diese Anforderungen gelten also insbesondere für über die Funktionen +    \ref{r:login} und \ref{r:reset-pw} neu gewählte Passwörter.\\ +    \item\label{r:save-pw} Passwörter werden sicher mittels \Gls{salt-hash} +    gespeichert. +    \item\label{r:session} Im Webfrontend angemeldete Benutzer bleiben dort +    angemeldet. Hierfür wird eine Kombination aus einem \Gls{session-token} und +    einem \Gls{cookie} verwendet.\\ +\end{RSlist} + +\subsection{ Kannkriterien } + +Kannkriterien: Leistungen, die enthalten sein können. + +\subsubsection*{ Funktionale Anforderungen } + +\begin{RClist} +    \item\label{r:subscribe} Ein Benutzer kann über die Weboberfläche einen +    abonnierten \Gls{podcast} über einen generierten Link teilen. +    Öffnet nun ein anderer Nutzer den Link wird dieser zur Weboberfläche +    weitergeleitet und mit einem Pop-up gefragt, ob dieser den +    \Gls{podcast} abonnieren +    möchte, falls noch nicht geschehen. +    Akzeptiert der Nutzer, so wird der \Gls{podcast} zur Liste der +    \Glspl{abo} des +    Nutzers hinzugefügt. +    Gegebenenfalls muss sich der Benutzer dafür zuerst anmelden. +    Der Link setzt sich dabei unter anderem aus der URL des Webfrontends oder +    einem \Gls{pseudoprotocol} und dem \Gls{podcast}-Link des Providers zusammen. +    \item\label{r:unsubscribe} Das Webfrontend bietet dem Benutzer die Möglichkeit, +    \Glspl{abo} zu entfernen beziehungsweise \Glspl{podcast} zu deabonnieren. +    \item\label{r:import} Das Importieren und Exportieren aller benutzerbezogenen +    Daten wird unterstützt (siehe \ref{r:dsgvo}). +    \item\label{r:import-other} Das Umsiedeln von anderen \Gls{gpodder}-Plattformen und +    damit insbesondere der damit verbundene Datenimport wird unterstützt. +    \item\label{r:api-compat} Die Weboberfläche ist kompatibel mit beliebigen +    \Glspl{gpodder}. +    \item\label{r:responsive} Die Weboberfläche ist \gls{responsive}. +    \item\label{r:admin} Es gibt Administrator Benutzerkonten. Eine angestrebte +    Funktionalität dieser privilegierten Konten ist das Einsehen von Statistiken, +    wie der Anzahl von Benutzern, und dem Abruf der Metadaten eines +    \Glspl{abo}. +\end{RClist} + +\subsubsection*{ Nicht-funktionale Anforderungen } + +\begin{RClist} +    \item\label{r:login-provider} Die Anmeldung im Webfrontend kann mit dem +    offenen Protokoll \Gls{oauth} 2.0 über Google, Apple oder Facebook erfolgen. +    Die bei der Verknüpfung eines \Gls{podcatcher}s mit dem Synchronisationsserver +    geforderten Anmeldedaten werden dann automatisch für den betreffenden +    Benutzer generiert. +    Diese kann er im Webfrontend einsehen. +    \item\label{r:live-update} Im Webfrontend angemeldete Benutzer bleiben dort +    angemeldet, wenn das Backend ein Update bekommt. +    \item\label{r:language} Die Benutzeroberfläche kann in mehreren Sprachen +    angezeigt werden, wobei neben der standardmäßig deutschen +    Benutzeroberfläche die zusätzliche Bereitstellung einer englischen +    Version gegenüber anderen Fremdsprachen priorisiert angestrebt wird. +    \item\label{r:dsgvo} Der Umgang mit personenbezogenen Daten ist konform mit +    der \\\Gls{dsgvo} der Europäischen Union. +    \item\label{r:docker} Die Benutzung von \Gls{docker} vereinfacht das Deployment auf +    einen Server, da Abhängigkeiten bereits im \Gls{docker}-Image enthalten sind. +    Außerdem bleibt bei einer Kompromittierung der Software das Host-System +    durch Virtualisierung der Container sicher.\\ +\end{RClist} diff --git a/20-implementierungsheft/sections/apidoc.tex b/20-implementierungsheft/sections/apidoc.tex new file mode 100644 index 0000000..0cce48c --- /dev/null +++ b/20-implementierungsheft/sections/apidoc.tex @@ -0,0 +1,191 @@ +\newenvironment{urlParameter} +{ +	\newcommand{\urlParamItem}[2] +	{ +		\rowcolor{\methodLightColor} ##1 & ##2 \\ +	} +	\newcommand{\noUrlParameter}[1] +	{ +		\small{\textit{##1}} +	} +	%\vspace{-0.61em} +	 +	\arrayrulecolor{\methodColor} +	 +	\begin{tabularx}{\textwidth}{X} +		\rowcolor{\methodLightColor!20} +		\textbf{URL-Parameter} \\ \hline +	\end{tabularx} +	 +	\tabularx{\textwidth}{l X} +} + +\newenvironment{pathParameter} +{ +	\newcommand{\pathParamItem}[2] +	{ +		\rowcolor{\methodLightColor} ##1 & ##2 \\ +	} +	\newcommand{\noPathParameter}[1] +	{ +		\small{\textit{##1}} +	} +	%\vspace{-0.61em} +	 +	\arrayrulecolor{\methodColor} +	 +	\begin{tabularx}{\textwidth}{X} +		\rowcolor{\methodLightColor!20} +		\textbf{Pfad-Parameter} \\ \hline +	\end{tabularx} +	 +	\tabularx{\textwidth}{l X} +} + +\newenvironment{jsonKeys} +{ +	\newcommand{\jsonKeyItem}[2] +	{ +		\rowcolor{\methodLightColor} ##1 & ##2 \\ +	} +	\newcommand{\nojsonKeys}[1] +	{ +		\small{\textit{##1}} +	} +	%\vspace{-0.61em} +	 +	\arrayrulecolor{\methodColor} +	 +	\begin{tabularx}{\textwidth}{X} +		\rowcolor{\methodLightColor!20} +		\textbf{Json-Keys} \\ \hline +	\end{tabularx} +	 +	\tabularx{\textwidth}{l X} +} + +\section{\Gls{api}} + +\subsection{Authentication API}\label{a:auth} + +\subsubsection{Registrierung}\label{a:register} + +\begin{apiRoute}{post}{/api/2/auth/register.json} +    {Registriert einen Nutzer mit einer E-Mail-Adresse und Passwort. +     +	Versendet E-Mail mit Bestätigungslink an die angegebene E-Mail-Adresse.} +    \begin{routeRequest}{application/json} +            \begin{routeRequestBody} +{ +	username: "jeff" +    email: "jeff@example.com", +    password: "MyNameIsJeff" +} +            \end{routeRequestBody} +    \end{routeRequest} +    \begin{routeResponse}{application/json} +        \begin{routeResponseItem}{200} +            {OK: Nutzer wurde erfolgreich angelegt und E-Mail versendet.} +        \end{routeResponseItem} + +        \begin{routeResponseItem}{400} +            {Bad Request: Fehler beim Parsen oder Eingabe nicht anforderungsgemäß.} +        \end{routeResponseItem} +    \end{routeResponse} +\end{apiRoute} + +Es wird nun sowohl ein Benutzername als auch eine E-Mail-Adresse für einen Nutzer gespeichert. +Der Benutzername wird in der Folge für die Authentifizierung und die Zuordnung der Anfragen verwendet. +Die E-Mail-Adresse wird vor dem Speichern mit einem festen Geheimschlüssel gesalted und gehashed. +Sie ist zum Ableich der bei der bei (ref an forgot) anzugebenden E-Mail-Adresse + +\newpage +\subsubsection{E-Mail verifizieren}\label{a:resetpassword} + +\begin{apiRoute}{get}{/api/2/auth/\{username\}/verify.json} +    {Verifiziere die bei der Registrierung angegebene E-Mail-Adresse durch diese, per E-Mail versendete, URL.} +    \begin{pathParameter} +        \pathParamItem{username}{Nutzername des betreffenden Nutzers} +    \end{pathParameter} +    \begin{urlParameter} +        \urlParamItem{token}{JSON-Web-Token (24h gültig)} +    \end{urlParameter} +    \begin{routeResponse}{application/json} +        \begin{routeResponseItem}{200} +            {OK: Der Benutzer wurde erfolgreich aktiviert und kann sich nun anmelden.} +        \end{routeResponseItem} + +        \begin{routeResponseItem}{400} +            {Bad Request: Der Nutzer mit dem angegebenen Namen ist bereits verifiziert. } +        \end{routeResponseItem} + +        \begin{routeResponseItem}{401} +            {Unauthorized: Der JWT ist ungültig. } +        \end{routeResponseItem} + +		\begin{routeResponseItem}{404} +            {Not Found: Es exisitiert kein Nutzer mit dem angegebenen Benutzernamen. } +        \end{routeResponseItem} +    \end{routeResponse} +\end{apiRoute} + +Dieser Endpunkt wurde zur Verifizierung der bei der Registrierung angegebenen E-Mail-Adresse hinzugefügt. +Nach der Registrierung wird dem Benutzer eine E-Mail mit der URL dieses Endpunkts (inklusive Benutzernamen und JWT)  +zugesendet. Klickt der Benutzer auf den Link wird die Anfrage im Backend verarbeitet und der Nutzer automatisch +zum Webfrontend weitergeleitet. Erst nach der Verifizierung der E-Mail-Adresse ist die Registrierung vollständig +abgeschlossen und der Account aktiviert - nun kann sich der Nutzer anmelden. + +\newpage +\subsubsection{Passwort vergessen}\label{a:forgot} + +\begin{apiRoute}{post}{/api/2/auth/\{email\}/forgot.json} +    {Sende eine E-Mail zum Zurücksetzen des Passworts.} +	\begin{pathParameter} +        \pathParamItem{email}{E-Mail-Adresse des betreffenden Nutzers} +    \end{pathParameter} +    \begin{routeResponse}{application/json} +        \begin{routeResponseItem}{200} +            {OK: E-Mail wurde erfolgreich versendet.} +        \end{routeResponseItem} + +        \begin{routeResponseItem}{404} +            {Not Found: Es exisitiert kein Nutzer mit der angegeben E-Mail-Adresse.} +        \end{routeResponseItem} +    \end{routeResponse} +\end{apiRoute} + +Die E-Mail-Adresse des Benutzers, der sein Passwort vergessen hat, wird nicht mehr im Request-Body +als \GLS{json}-Payload, sondern als Pfadvariable in der URL übergeben.  + +\subsubsection{Passwort zurücksetzen}\label{a:resetpassword} + +\begin{apiRoute}{put}{/api/2/auth/\{username\}/resetpassword.json} +    {Passwort des gegebenen Nutzers ändern nachdem dieser sein Passwort +    vergessen hat. } +    \begin{pathParameter} +        \pathParamItem{username}{Nutzername des betreffenden Nutzers} +    \end{pathParameter} +    \begin{urlParameter} +        \urlParamItem{token}{JSON-Web-Token} +    \end{urlParameter} +    \begin{routeRequest}{application/json} +            \begin{routeRequestBody} +{ +    password: "APasswordIWontForgetAgain" +} +            \end{routeRequestBody} +    \end{routeRequest} +    \begin{routeResponse}{application/json} +        \begin{routeResponseItem}{200} +            {OK: Das Passwort wurde erfolgreich geändert.} +        \end{routeResponseItem} + +        \begin{routeResponseItem}{400} +            {Bad Request: Fehler beim Parsen der Anfragen. } +        \end{routeResponseItem} + +        \begin{routeResponseItem}{401} +            {Unauthorized: JWT ist ungültig. } +        \end{routeResponseItem} +    \end{routeResponse} +\end{apiRoute}
\ No newline at end of file diff --git a/20-implementierungsheft/sections/aufbau.tex b/20-implementierungsheft/sections/aufbau.tex new file mode 100644 index 0000000..41a5839 --- /dev/null +++ b/20-implementierungsheft/sections/aufbau.tex @@ -0,0 +1,47 @@ +\section{Aufbau} + +\begin{landscape} + +\subsection{Klassendiagramm Backend} +Das Klassendiagramm zeigt alle für den Entwurf relevanten Klassen des Backends mit ihren öffentlichen Methoden. +Weiter zeigt das Diagramm die Aufteilung der Klassen in Pakete sowie schemenhaft dargestellte Verbindungen zu \Gls{db} und Webserver. + +% \input{assets/diagrams/classdiagram.latex} +\includegraphics[width=\linewidth]{assets/diagrams/classdiagram} +\end{landscape} + +\subsection{Sequenzdiagramme} + +\subsubsection{Authentication \Gls{api}} +\subsubsection*{Registrierung \scriptsize{(\ref{a:register})}} +\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-register} +\subsubsection*{Passwort vergessen und zurücksetzen \scriptsize{(\ref{a:forgot}, \ref{a:resetpassword})}} +\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-forgotAndResetPW} + +\subsubsection{Subscriptions \Gls{api}} +\subsubsection*{Abonnements hochladen \scriptsize{(\ref{a:uploadSubs})}} +\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-uploadSubscriptions} + +\subsubsection*{Abrufen aller Abonnements \scriptsize{(\ref{a:getSubs})}} +\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-getSubscriptions} + +\subsubsection{Episode Actions \Gls{api}} +\subsubsection*{Episode Actions hochladen \scriptsize{(\ref{a:uploadEpisodeActions})}} +\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-uploadEpisodeActions} + +\subsubsection*{Abrufen aller Episode Actions seit einem Zeitpunkt \scriptsize{(\ref{a:getEpisodeActions})}} +\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince} + +\subsubsection*{Abrufen aller Episode Actions \scriptsize{(\ref{a:getEpisodeActions})}} +\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-getEpisodeActions} + +\subsection{Komponentendiagramm Backend} +\includegraphics[width=\textwidth]{assets/diagrams/backendComponentDiagram} + +\subsection{Verteilungsdiagram} +\includegraphics[width=\textwidth]{assets/diagrams/deployment} + +\subsection{\Gls{db}-Modell} + +\includegraphics[width=\textwidth]{assets/diagrams/db} + diff --git a/20-implementierungsheft/sections/backend.tex b/20-implementierungsheft/sections/backend.tex new file mode 100644 index 0000000..19efd65 --- /dev/null +++ b/20-implementierungsheft/sections/backend.tex @@ -0,0 +1,28 @@ +\section{Backend} + +Für das Backend wird das \Gls{java}-Framework \Gls{spring} verwendet. Neben seiner Modularität, +bietet es viele Funktionen, die unter +anderem die Entwicklung von Backend-Anwendungen vereinfachen. +Darunter fällt zum Beispiel die Unterstützung von Dependency Injection, dessen  +Vorteile bereits beschrieben wurden. +Außerdem unterstützt \Gls{java} \Gls{spring} intern eine Verwaltung von \Glspl{db}, sodass +sich nicht mit dem \Gls{SQL}-Code an sich befasst werden muss.  +Auch bezüglich Authentifizierung und Sicherheit bietet \Gls{spring} eigene Funktionalitäten. + +Zusätzlich dazu wird als Build-System für das \Gls{java}-\Gls{spring}-Backend Maven verwendet. +Maven hilft dabei alle Abhängigkeiten des Projekts zu verwalten und automatisiert  +den Build Prozess. +Durch die zusätzliche Unterstützung von Versionskontrollsystemen und der Kompatibilität +zu vielen Continuous Integration-Tools wird außerdem die Entwicklung in einem Team erleichtert +und optimiert. Denn dadurch können Build- und Deployment-Prozesse automatisiert werden. +Außerdem bietet Maven Bibliotheken zum Testen sowie zur Generierung von Dokumentationen an. + +Vom Backend benötigte Abhängigkeiten: +\begin{itemize} +    \item \Gls{spring} Web +    \item \Gls{spring} Security +    \item \Gls{spring} Mail Sender +    \item \Gls{spring} Data JPA +    \item Lombok +    \item Rome (\Gls{rss} parsing/fetching) +\end{itemize}
\ No newline at end of file diff --git a/20-implementierungsheft/sections/changes.tex b/20-implementierungsheft/sections/changes.tex new file mode 100644 index 0000000..20df017 --- /dev/null +++ b/20-implementierungsheft/sections/changes.tex @@ -0,0 +1,241 @@ +\newenvironment{urlParameter} +{ +	\newcommand{\urlParamItem}[2] +	{ +		\rowcolor{\methodLightColor} ##1 & ##2 \\ +	} +	\newcommand{\noUrlParameter}[1] +	{ +		\small{\textit{##1}} +	} +	%\vspace{-0.61em} +	 +	\arrayrulecolor{\methodColor} +	 +	\begin{tabularx}{\textwidth}{X} +		\rowcolor{\methodLightColor!20} +		\textbf{URL-Parameter} \\ \hline +	\end{tabularx} +	 +	\tabularx{\textwidth}{l X} +} + +\newenvironment{pathParameter} +{ +	\newcommand{\pathParamItem}[2] +	{ +		\rowcolor{\methodLightColor} ##1 & ##2 \\ +	} +	\newcommand{\noPathParameter}[1] +	{ +		\small{\textit{##1}} +	} +	%\vspace{-0.61em} +	 +	\arrayrulecolor{\methodColor} +	 +	\begin{tabularx}{\textwidth}{X} +		\rowcolor{\methodLightColor!20} +		\textbf{Pfad-Parameter} \\ \hline +	\end{tabularx} +	 +	\tabularx{\textwidth}{l X} +} + +\newenvironment{jsonKeys} +{ +	\newcommand{\jsonKeyItem}[2] +	{ +		\rowcolor{\methodLightColor} ##1 & ##2 \\ +	} +	\newcommand{\nojsonKeys}[1] +	{ +		\small{\textit{##1}} +	} +	%\vspace{-0.61em} +	 +	\arrayrulecolor{\methodColor} +	 +	\begin{tabularx}{\textwidth}{X} +		\rowcolor{\methodLightColor!20} +		\textbf{Json-Keys} \\ \hline +	\end{tabularx} +	 +	\tabularx{\textwidth}{l X} +} + + +\section{Änderungen zum Entwurfsheft} + +Im Folgenden werden die Änderungen zum Entwurfsheft aufgelistet und erläutert warum diese  +Änderungen gemacht wurden. + + +\subsection{Kompatibilität mit \Glspl{podcatcher}} + +Um die Kompatibilität mit \Glspl{podcatcher} - insbesondere AntennaPod und Kasts - sicherzustellen, mussten einige Änderungen vorgenommen werden. + +\subsubsection*{Speicherung von Benutzernamen und E-Mail-Adressen} + +AntennaPod erlaubt bei der Verknüpfung mit einem Synchronisations-Server nur die Anmeldung mit einem Benutzername, der keine E-Mail-Adresse ist. +Deshalb werden nun sowohl ein Benutzername als auch eine E-Mail-Adresse für jeden Nutzer gespeichert. +Der Benutzername wird dabei unverschlüsselt gespeichert.  +Er wird zur Authentifizierung sowie für die Zuordnung der Anfragen verwendet. +Die E-Mail-Adresse hingegen, wird vor der Speicherung mit einem festen Geheimschlüssel gesalted und anschließend gehashed. +Sie existiert lediglich um bei einer Passwort-vergessen-Anfrage denjenigen Nutzer zu finden, zu dem die übergebene E-Mail-Adresse gehört, beziehungsweise dessen Existenz zu überprüfen. +Diese Änderung impliziert eine Anpassung des Formats, in dem Registrierungsanfragen als \GLS{json}-Payload übergeben werden. +Wie in der folgenden aktualisierten Spezifikation zu sehen existiert nun ein zusätzliches \GLS{json}-Attribut namens \enquote{username}. +\newline + +\begin{apiRoute}{post}{/api/2/auth/register.json} +    {Registriert einen Nutzer mit einer E-Mail-Adresse und Passwort. +     +	Versendet E-Mail mit Bestätigungslink an die angegebene E-Mail-Adresse.} +    \begin{routeRequest}{application/json} +            \begin{routeRequestBody} +{ +	"username": "jeff", +    "email": "jeff@example.com", +    "password": "MyNameIsJeff" +} +            \end{routeRequestBody} +    \end{routeRequest} +    \begin{routeResponse}{application/json} +        \begin{routeResponseItem}{200} +            {OK: Nutzer wurde erfolgreich angelegt und E-Mail versendet.} +        \end{routeResponseItem} + +        \begin{routeResponseItem}{400} +            {Bad Request: Fehler beim Parsen oder Eingabe nicht anforderungsgemäß.} +        \end{routeResponseItem} +    \end{routeResponse} +\end{apiRoute} + +\subsubsection*{Device API} + +Beim Einrichten eines Synchronisations-Servers rufen sowohl AntennaPod als auch Kasts statt einem anfänglichen Login sofort den List-Devices-Endpunkt der \gls{gpodder}.net API auf. +Dieser Endpunkt wurde entsprechend hinzugefügt. +Da jedoch explizit keine Unterscheidung von Geräten bei der Synchronisation unterstützt wird, wird dieser intern wie ein Login-Aufruf behandelt. +\newline + +\begin{apiRoute}{get}{/api/2/devices/\{username\}.json} +    {Gegebenen Nutzer des gegebenen Geräts mithilfe HTTP Basic Auth einloggen oder Gültigkeit des im \enquote{sessionid} \Gls{cookie} gespeicherten JWTs bestätigen. +	 +	Gibt außerdem eine Liste mit einem Dummy-Device zurück, damit die Einrichtung der Synchronisation mit AntennaPod und Kasts möglich ist.} +    \begin{pathParameter} +            \pathParamItem{username}{Nutzername des einzuloggenden Nutzers} +    \end{pathParameter} +    \begin{routeResponse}{application/json} +        \begin{routeResponseItem}{200} +            {OK: Der Benutzer wurde erfolgreich mittles HTTP Basic Auth oder JWT eingeloggt und das \enquote{sessionid} Cookie wurde auf ein gültiges JWT gesetzt.} +			\newline +			\begin{routeResponseItemBody} +[ +	{ +		"id": "dummy", +		"caption": "device", +		"type": "other", +		"subscriptions": 0 +	} +] +			\end{routeResponseItemBody} +        \end{routeResponseItem} +         +        \begin{routeResponseItem}{401} +            {Unauthorized: Es liegen falsche Anmeldedaten oder ein ungültiges JWT vor.} +        \end{routeResponseItem} +    \end{routeResponse} +	\begin{jsonKeys} +        \jsonKeyItem{id}{Geräte-ID} +        \jsonKeyItem{caption}{Ein für Menschen lesbarer Name für das Gerät} +        \jsonKeyItem{type}{Typ des Geräts - mögliche Typen: desktop, laptop, mobile, server, other} +        \jsonKeyItem{subscriptions}{Anzahl der Subscriptions auf dem Gerät} +    \end{jsonKeys} +\end{apiRoute} + +\newpage +\subsection{Verifizierung der E-Mail-Adresse} + +Dieser Endpunkt wurde zur Verifizierung der bei der Registrierung angegebenen E-Mail-Adresse hinzugefügt. +Nach der Registrierung wird dem Benutzer eine E-Mail mit der URL dieses Endpunkts (inklusive Benutzernamen und JWT)  +zugesendet. Klickt der Benutzer auf den Link wird die Anfrage im Backend verarbeitet und der Nutzer automatisch +zum Webfrontend weitergeleitet. Erst nach der Verifizierung der E-Mail-Adresse ist die Registrierung vollständig +abgeschlossen und der Account aktiviert - nun kann sich der Nutzer anmelden. +\newline + +\begin{apiRoute}{get}{/api/2/auth/\{username\}/verify.json} +    {Verifiziere die bei der Registrierung angegebene E-Mail-Adresse durch diese, per E-Mail versendete, URL.} +    \begin{pathParameter} +        \pathParamItem{username}{Nutzername des betreffenden Nutzers} +    \end{pathParameter} +    \begin{urlParameter} +        \urlParamItem{token}{JSON-Web-Token (24h gültig)} +    \end{urlParameter} +    \begin{routeResponse}{application/json} +        \begin{routeResponseItem}{200} +            {OK: Der Benutzer wurde erfolgreich aktiviert und kann sich nun anmelden.} +        \end{routeResponseItem} + +        \begin{routeResponseItem}{400} +            {Bad Request: Der Nutzer mit dem angegebenen Namen ist bereits verifiziert. } +        \end{routeResponseItem} + +        \begin{routeResponseItem}{401} +            {Unauthorized: Der JWT ist ungültig. } +        \end{routeResponseItem} + +		\begin{routeResponseItem}{404} +            {Not Found: Es exisitiert kein Nutzer mit dem angegebenen Benutzernamen. } +        \end{routeResponseItem} +    \end{routeResponse} +\end{apiRoute} + + +\newpage +\subsection{RSSParser} + +Das primäre Ziel beim Entwurf des RSSParsers war es den Rest der Anwendung nicht  +aufzuhalten, da das fetchen und parsen länger dauert. Daher soll der RSSParser asynchron  +ausgeführt werden. +Damit das für die Implementierung verwendete Framework \Gls{spring} dies unterstützt müssen  +mehr Bedingungen erfüllt sein als im Entwurf berücksichtigt wurden, weshalb dieser abgeändert werden musste. + +Unter anderem können nur Komponenten die von \Gls{spring} verwaltet werden asynchron ausgeführt werden.  +Weiter können nur öffentliche Methoden von \Gls{spring} als asynchron erkannt werden und bei  +dem Aufruf einer asynchronen Methode muss die Klasse gewechselt werden damit diese asynchron  +ausgeführt wird. + +Um diese Bedingungen zu erfüllen ruft der SubscriptionService oder der EpisodeActionService  +die Validate Methode des RSSParsers mit der Subscription die überprüft werden  +soll auf. Dies geschieht asynchron nach dem \enquote{Fire and Forget} Prinzip. Daher können  +die Services unmittelbar weiter arbeiten und dem Nutzer so möglichst schnell eine Antwort  +liefern. + +Die Validate Methode fragt den aktuellen \GLS{rss}-Feed der Subscription ab und parsed diesen. +Erfüllt der Feed die von Apple und Google für \Glspl{podcast} definierten Anforderungen  +werden die Informationen aus dem Feed gespeichert. Dabei werden nur die \Glspl{episode} gespeichert,   +die von mindestens einem Nutzer gehört wurden. Ist der Feed der Subscription nicht  +valide wird die Subscription gelöscht. Um das Löschen und Speichern ausführen zu können  +hält der Parser Referenzen auf das SubscriptionDao und EpisodeDao. + +Die im Entwurfsheft definierten Getter werden nicht mehr oder nur  +noch als private Hilfsmethoden benötigt. + +\subsection{Reduzierte Datenzugriffsschicht} + +Mithilfe von JPA Repositories können Datenbankzugriffe und Abfragen ohne weitere Logik in den DAO-Schnittstellen einfach implementiert werden. +Wird beispielsweise nach einem \Gls{abo} anhand einer URL gesucht, so wird eine Methode der Form \textit{Optional<Subscription> findByUrl(String url)} in der SubscriptionDao deklariert. +Um die Implementierung dieser Abfrage kümmert sich JPA. + +Damit fallen alle ursprünglich geplanten DAO-Implementierungen weg, was für eine bessere Übersicht in der Datenzugriffsschicht sorgt. +\newpage + +\begin{landscape} + +\subsection{Überarbeitetes Klassendiagramm des Backends} +Das Klassendiagramm zeigt alle den überarbeiteten Entwurf des Backends. +Weiter zeigt das Diagramm die Aufteilung der Klassen in Pakete sowie schemenhaft dargestellte Verbindungen zu \Gls{db} und Webserver. + +% \input{assets/diagrams/classdiagram.latex} +\includegraphics[width=\linewidth]{assets/diagrams/class_after} +\end{landscape}
\ No newline at end of file diff --git a/20-implementierungsheft/sections/einleitung.tex b/20-implementierungsheft/sections/einleitung.tex new file mode 100644 index 0000000..5f6080d --- /dev/null +++ b/20-implementierungsheft/sections/einleitung.tex @@ -0,0 +1,11 @@ +\section{Einleitung} + +Im vorangegangenen Pflichtenheft und Entwurfsheft wurde zuerst abstrahiert  +die Idee des Podcast Synchronisationsservers beschrieben und die Ziele in Form von  +Anforderungen definiert. Dabei soll sowohl ein Backend mit \Gls{db} als auch ein Frontend  +zur Dateneinsicht und Verwaltung entstehen. Dann wurde die Implementierung diese Projekts  +mittels eines Entwurfs geplant. + +In diesem Dokument wird die Implementierung des entworfenen Produkts dokumentiert. +Dabei wird auf Probleme und Änderungen gegenüber dem Pflichtenheft und Entwurfsheft eingegangen, +die Testfälle erläutert und der geplante und tatsächliche zeitliche Ablauf der Implementierung dokumentiert.
\ No newline at end of file diff --git a/20-implementierungsheft/sections/features.tex b/20-implementierungsheft/sections/features.tex new file mode 100644 index 0000000..0ccf47e --- /dev/null +++ b/20-implementierungsheft/sections/features.tex @@ -0,0 +1,43 @@ +\section{Implementierte Muss-, Soll- und Kannkriterien} + +Nachdem nun die vorgenommenen Änderungen des Entwurfs behandelt wurden, geht es nun zu der eigentlichen Frage: +Was wurde umgesetzt? + +In der folgenden Tabelle werden alle im Pflichtenheft vorgestellten und im Entwurfsheft überarbeiteten Kriterien mit der Kriterienbezeichnung, einer kleinen Zusammenfassung und einer Info, ob die Kriterien implementiert wurden, aufgelistet. + +\begin{tabular}{l|c|c} +	Bezeichner & Zusammenfassung & Implementiert\\\hline +	RM1 & \makecell{Registrierung, Bestätigung und Anmeldung\\ eines Accounts über das Frontend} & Ja\\ +	RM2 & Speichern von \Glspl{abo} und \Glspl{episode} auf dem Server & Ja\\ +	RM3 & Synchronisierung zwischen \Glspl{podcatcher} & Ja\\ +	RM4 & Eine Weboberfläche & Ja\\ +	RM5 & Möglichkeit das eigene Passwort zu ändern / zurückzusetzen & Ja\\ +	RM6 & \Gls{abo}liste in der Weboberfläche & Ja\\ +	RM7 & 50 Anfragen / Sekunde bearbeiten & Zu testen\\ +	RM8 & Primäre Auslegung des Webfrontends für Desktop-Nutzer & Ja\\ +	RM9 & Unterstützung der \gls{gpodder}.net \Gls{rest-api} & Ja\\ +	RM10 & Das Nutzen einer \Gls{db} zur Speicherung von Daten & Ja\\ +	RM11 & Erweiterte \GLS{api} für Kommunikation zwischen Front- und Backend & Ja\\\hline +	RS1 & Eine Anleitung (Platzhalter) & Ja\\ +	RS2 & Die Möglichkeit einen Account zu löschen & Ja\\ +	RS3 & \Gls{spring} für das Backend und MariaDB als \Gls{db} & Ja\\ +	RS4 & Vue.js und Bootstrap für das Frontend & Ja\\ +	RS5 & npm und vite für das Frontend & Ja\\ +	RS6 & \makecell{Eine \Gls{spa} als Frontend\\mit dynamischer Aktualisierung} & Ja\\ +	RS7 & Ein \GLS{rss}-Parser um Daten aus einem \GLS{rss}-Feed zu lesen & Ja\\ +	RS8 & Mindestanforderungen an ein Passwort & Ja\\ +	RS9 & \Gls{salt-hash} für Verschlüsselung der Personenbezogenen Daten & Ja\\ +	RS10 & Nutzer bleibt über JWT angemeldet und authentifiziert & Ja\\\hline +	RC1 & Abonnierten \Gls{podcast} in Weboberfläche über Link teilen und hinzufügen & Ja\\ +	RC2 & \Glspl{abo} in Weboberfläche deabonnieren & Nein\\ +	RC3 & Importieren und Exportieren aller benutzerbezogenen Daten & Ja\\ +	RC4 & Umsiedeln von anderen \Gls{gpodder}-Plattformen & Ja\\ +	RC5 & Kompatible Weboberfläche für beliebige \gls{gpodder}.net APIs & Entfernt\\ +	RC6 & \Gls{responsive} designte Weboberfläche & Ja\\ +	RC7 & Administratorkonten mit privilegierten Funktionen & Nein\\ +	RC8 & \Gls{oauth} 2.0 im Webfrontend & Nein\\ +	RC9 & Bei Ausfall des Backends im Frontend angemeldet bleiben & Ja\\ +	RC10 & Mehrsprachige Weboberfläche & Ja\\ +	RC11 & Erfüllung der DSGVO & Teils\\ +	RC12 & \Gls{docker} für einfaches Deployment und Sicherheit & Ja  +\end{tabular}
\ No newline at end of file diff --git a/20-implementierungsheft/sections/features.tex.orig b/20-implementierungsheft/sections/features.tex.orig new file mode 100644 index 0000000..78839cf --- /dev/null +++ b/20-implementierungsheft/sections/features.tex.orig @@ -0,0 +1,82 @@ +\section{Implementierte Muss-, Soll- und Kannkriterien} + +Nachdem nun die vorgenommenen Änderungen des Entwurfs behandelt wurden, geht es nun zu der eigentlichen Frage: +Was wurde umgesetzt? + +In der folgenden Tabelle werden alle im Pflichtenheft vorgestellten und im Entwurfsheft überarbeiteten Kriterien mit der Kriterienbezeichnung, einer kleinen Zusammenfassung und einer Info, ob die Kriterien implementiert wurden, aufgelistet. + +\hspace{-1cm} +\begin{tabular}{l|c|c} +<<<<<<< HEAD +	Bezeichner & Zusammenfassung                                                                        & Implementiert\\\hline +	\textlangle RM1 \textrangle       & \makecell{Registrierung, Bestätigung und Anmeldung\\ eines Accounts über das Frontend} & Ja\\ +	\textlangle RM2 \textrangle       & Speichern von Abonnements und Episoden auf dem Server                                  & Ja\\ +	\textlangle RM3 \textrangle       & Synchronisierung zwischen Podcatchern                                                  & Ja\\ +	\textlangle RM4 \textrangle       & Eine Weboberfläche                                                                     & Ja\\ +	\textlangle RM5 \textrangle       & Möglichkeit das eigene Passwort zu ändern / zurückzusetzen                             & Ja\\ +	\textlangle RM6 \textrangle       & Abonnementliste in der Weboberfläche                                                   & Ja\\ +	\textlangle RM7 \textrangle       & 50 Anfragen / Sekunde bearbeiten                                                       & Zu testen\\ +	\textlangle RM8 \textrangle       & Primäre Auslegung des Webfrontends für Desktop-Nutzer                                  & Ja\\ +	\textlangle RM9 \textrangle       & Unterstützung der gpodder.net RESTful-API                                              & Ja\\ +	\textlangle RM10\textrangle       & Das Nutzen einer Datenbank zur Speicherung von Daten                                   & Ja\\ +	\textlangle RM11\textrangle       & Erweiterte API für Kommunikation zwischen Front- und Backend                           & Ja\\\hline\hline +	\textlangle RS1 \textrangle       & Eine Anleitung (Platzhalter)                                                           & Ja\\ +	\textlangle RS2 \textrangle       & Die Möglichkeit einen Account zu löschen                                               & Ja\\ +	\textlangle RS3 \textrangle       & Spring für das Backend und MariaDB als Datenbank                                       & Ja\\ +	\textlangle RS4 \textrangle       & Vue.js und Bootstrap für das Frontend                                                  & Ja\\ +	\textlangle RS5 \textrangle       & npm und vite für das Frontend                                                          & Ja\\ +	\textlangle RS6 \textrangle       & \makecell{Eine Single-Page-Application als Frontend\\mit dynamischer Aktualisierung}   & Ja\\ +	\textlangle RS7 \textrangle       & Ein RSS-Parser um Daten aus einem RSS-Feed zu lesen                                    & Ja\\ +	\textlangle RS8 \textrangle       & Mindestanforderungen an ein Passwort                                                   & Ja\\ +	\textlangle RS9 \textrangle       & Salting und Hashing für Verschlüsselung der Personenbezogenen Daten                    & Ja\\ +	\textlangle RS10\textrangle       & Nutzer bleibt über JWT angemeldet und authentifiziert                                  & Ja\\\hline\hline +	\textlangle RC1 \textrangle       & Abonnierten Podcast in Weboberfläche über Link teilen und hinzufügen                   & Ja\\ +	\textlangle RC2 \textrangle       & Abonnements in Weboberfläche deabonnieren                                              & Nein\\ +	\textlangle RC3 \textrangle       & Importieren und Exportieren aller benutzerbezogenen Daten                              & Ja\\ +	\textlangle RC4 \textrangle       & Umsiedeln von anderen Gpodder-Plattformen                                              & Ja\\ +	\textlangle RC5 \textrangle       & Kompatible Weboberfläche für beliebige gpodder.net APIs                                & Entfernt\\ +	\textlangle RC6 \textrangle       & Responsive designte Weboberfläche                                                      & Ja\\ +	\textlangle RC7 \textrangle       & Administratorkonten mit privilegierten Funktionen                                      & Nein\\ +	\textlangle RC8 \textrangle       & OAuth 2.0 im Webfrontend                                                               & Nein\\ +	\textlangle RC9 \textrangle       & Bei Ausfall des Backends im Frontend angemeldet bleiben                                & Ja\\ +	\textlangle RC10\textrangle       & Mehrsprachige Weboberfläche                                                            & Ja\\ +	\textlangle RC11\textrangle       & Erfüllung der DSGVO                                                                    & Teils\\ +	\textlangle RC12\textrangle       & Docker für einfaches Deployment und Sicherheit                                         & Ja  +\end{tabular} +======= +	Bezeichner & Zusammenfassung & Implementiert\\\hline +	RM1 & \makecell{Registrierung, Bestätigung und Anmeldung\\ eines Accounts über das Frontend} & Ja\\ +	RM2 & Speichern von \Glspl{abo} und \Glspl{episode} auf dem Server & Ja\\ +	RM3 & Synchronisierung zwischen \Glspl{podcatcher} & Ja\\ +	RM4 & Eine Weboberfläche & Ja\\ +	RM5 & Möglichkeit das eigene Passwort zu ändern / zurückzusetzen & Ja\\ +	RM6 & \Gls{abo}liste in der Weboberfläche & Ja\\ +	RM7 & 50 Anfragen / Sekunde bearbeiten & Zu testen\\ +	RM8 & Primäre Auslegung des Webfrontends für Desktop-Nutzer & Ja\\ +	RM9 & Unterstützung der \gls{gpodder}.net \Gls{rest-api} & Ja\\ +	RM10 & Das Nutzen einer \Gls{db} zur Speicherung von Daten & Ja\\ +	RM11 & Erweiterte \GLS{api} für Kommunikation zwischen Front- und Backend & Ja\\\hline +	RS1 & Eine Anleitung (Platzhalter) & Ja\\ +	RS2 & Die Möglichkeit einen Account zu löschen & Ja\\ +	RS3 & \Gls{spring} für das Backend und MariaDB als \Gls{db} & Ja\\ +	RS4 & Vue.js und Bootstrap für das Frontend & Ja\\ +	RS5 & npm und vite für das Frontend & Ja\\ +	RS6 & \makecell{Eine \Gls{spa} als Frontend\\mit dynamischer Aktualisierung} & Ja\\ +	RS7 & Ein \GLS{rss}-Parser um Daten aus einem \GLS{rss}-Feed zu lesen & Ja\\ +	RS8 & Mindestanforderungen an ein Passwort & Ja\\ +	RS9 & \Gls{salt-hash} für Verschlüsselung der Personenbezogenen Daten & Ja\\ +	RS10 & Nutzer bleibt über JWT angemeldet und authentifiziert & Ja\\\hline +	RC1 & Abonnierten \Gls{podcast} in Weboberfläche über Link teilen und hinzufügen & Ja\\ +	RC2 & \Glspl{abo} in Weboberfläche deabonnieren & Nein\\ +	RC3 & Importieren und Exportieren aller benutzerbezogenen Daten & Ja\\ +	RC4 & Umsiedeln von anderen \Gls{gpodder}-Plattformen & Ja\\ +	RC5 & Kompatible Weboberfläche für beliebige \gls{gpodder}.net APIs & Entfernt\\ +	RC6 & \Gls{responsive} designte Weboberfläche & Ja\\ +	RC7 & Administratorkonten mit privilegierten Funktionen & Nein\\ +	RC8 & \Gls{oauth} 2.0 im Webfrontend & Nein\\ +	RC9 & Bei Ausfall des Backends im Frontend angemeldet bleiben & Ja\\ +	RC10 & Mehrsprachige Weboberfläche & Ja\\ +	RC11 & Erfüllung der DSGVO & Teils\\ +	RC12 & \Gls{docker} für einfaches Deployment und Sicherheit & Ja  +\end{tabular} +>>>>>>> main diff --git a/20-implementierungsheft/sections/frontend.tex b/20-implementierungsheft/sections/frontend.tex new file mode 100644 index 0000000..ae5be0e --- /dev/null +++ b/20-implementierungsheft/sections/frontend.tex @@ -0,0 +1,196 @@ +\section{Weboberfläche} + +Die Weboberfläche wird mit dem Frontend-Web-Framework Vue.js erstellt. Mit Vue +werden wiederverwendbare, auf Datenänderungen reagierende Komponenten erstellt. +Die Komponenten nutzen ein fertiges Aussehen von dem Frontend-CSS-Framework +Bootstrap. Außerdem werden Icons der freien Schriftart fontawesome +verwendet.  + +An der generellen Struktur und wichtigen Komponenten hat sich in der +Implementierung nichts großes zum Entwurf geändert. Einige Komponenten konnten +in der Implementierung allerdings abstrahiert werden, sodass weniger Code +dupliziert werden musste. Dazu gehören zum Beispiel die Komponenten, welche ein +Eingabefeld bereit stellen.  + +Durch eine gute Arbeitsteilung blieb genug Zeit, um auch einige Kann-Kriterien +zu implementieren, weshalb ein paar Abhängigkeiten hinzugekommen sind. So werden +jszip und file-saver benötigt, um das Kann-Kriterium RC3 umzusetzen, durch +welches man Nutzerdaten im- und exportieren kann.  + +Pinia konnten wir als Abhängigkeit entfernen, weil Vue von sich aus genügend +Funktionalität bietet die Nutzerdaten global allen Komponenten bereit zu +stellen.  + +Anfangs überlegten wir den Wrapper \texttt{bootstrap-vue} zu verwenden, welcher +Bootstrap-HTML-Strukturen als Vue-Komponenten bereit stellt. Dies hätte des +Vorteil, dass man nur jene Komponenten importieren müsste, die man auch +benötigt. Es stellte sich heraus, dass \texttt{vue-bootstrap} nicht mit neusten +Version Vue3 kompatibel ist, weshalb wir uns entschieden Bootstrap wie gewohnt +komplett einzubinden.  + +Während der Implementierung sind wir auf die Bibliothek \texttt{VueUse} +gestoßen, mit der man die Abhängigkeit \texttt{file-saver} und mehrere eigene +Wrapper für Browser-\Gls{api}s ersetzen könnte. So kann man das \Gls{dashboard} auch in +Zukunft noch weiter verbessern.  + +Vom Frontend benötigte Abhängigkeiten: +\begin{itemize} +    \item vite +    \item vue +    \item vue-router +    \item \textcolor{red}{\sout{Pinia} wird durch globale Vue-Interne \texttt{ref} ersetzt} +    \item bootstrap +    \item fontawesome +    \item vue-i18n (Support für mehrere Sprachen) +    \item \textcolor{Green}{dayjs (Rechnen und formatieren von Zeiten)} +    \item \textcolor{Green}{jszip (erstellen von Im-/Exports)} +    \item \textcolor{Green}{file-saver (Abstraktion für Datei-Speichern-Dialog)} +\end{itemize} + +\subsection{Komponentendiagramm Web-Frontend} +\includegraphics[width=\textwidth]{assets/diagrams/componentdiagram} + +\subsection{Hinzugefügte Komponenten} + +% PasswordInput +% PasswordValidator +% FloatingLabelInput +% Loading +% ErrorLog +% ProgressTime + +\begin{minipage}{.7\linewidth} + +\subsubsection*{FloatingLabelInput} + +\begin{description} +\item[Tag] \texttt{<FloatingLabelInput type label>} +\item[Props] \mbox{} \\ +    \emph{type} \mbox{} Beschreibt den Inhalt des Eingabefelder. Handelt es sich +        um eine E-Mail, ein Passwort oder nur Text? \\ +    \emph{label} \mbox{} Das Label wird als Platzhalter und kleine Überschrift +        angezeigt.   +\item[Beschreibung] Abstrahiert eine HTML-Struktur von Bootstrap, um ein schönes +    Eingabefeld anzuzeigen.  +\end{description}  +\end{minipage} +\begin{minipage}{.3\linewidth} +    \begin{figure}[H] +        \includegraphics[width=\textwidth]{assets/floatinglabelinput.png} +    \end{figure} +\end{minipage} + + +\vspace{.5cm} + +\begin{minipage}{.7\linewidth} + +\subsubsection*{PasswordInput} + +\begin{description} +\item[Tag] \texttt{<PasswordInput type label>} +\item[Props] \mbox{} \\ +    \emph{label} \mbox{} Das Label wird als Platzhalter und kleine Überschrift +        angezeigt.   +\item[Beschreibung] Erweitert den FloatingLabelInput um einen Knopf mit dem die +    Sichtbarkeit des Eingabefeldes gewechselt werden kann. Dabei wird intern der +        Typ des Eingabefeldes zwischen Text and Passwort gewechselt.  +\end{description}  +\end{minipage} +\begin{minipage}{.3\linewidth} +    \begin{figure}[H] +        \includegraphics[width=\textwidth]{assets/passwordinput.png} +    \end{figure} +\end{minipage} + + +\vspace{.5cm} + +\begin{minipage}{.7\linewidth} + +\subsubsection*{PasswordValidator} + +\begin{description} +\item[Tag] \texttt{<PasswordValidator>} +\item[Beschreibung] Besteht aus zwei PasswordInputs und überprüft diese auf +    Gleichheit und Kriterien für eine gutes Passwort.  +\end{description}  +\end{minipage} +\begin{minipage}{.3\linewidth} +    \begin{figure}[H] +        \includegraphics[width=\textwidth]{assets/passwordvalidator.png} +    \end{figure} +\end{minipage} + + +\vspace{.5cm} + +\begin{minipage}{.7\linewidth} + +\subsubsection*{Loading} + +\begin{description} +\item[Tag] \texttt{<Loading waitingFor>...<Loading/>} +\item[Props] \mbox{} \\ +    \emph{waitingFor} \mbox{} Eine Referenz auf eine Bedingung wann die Kinder +        der Komponente gezeigt werden sollen.  +\item[Beschreibung] Zeigt solange ein Ladesymbol an, bis die Bedingung in +    \texttt{waitingFor} erfüllt ist und stattdessen die Kinder der Komponente +        gezeigt werden.  +\end{description}  +\end{minipage} +\begin{minipage}{.3\linewidth} +    \begin{figure}[H] +        \includegraphics[width=\textwidth]{assets/loading.png} +    \end{figure} +\end{minipage} + + +\vspace{.5cm} + +\begin{minipage}{.7\linewidth} + +\subsubsection*{ProgressTime} + +\begin{description} +\item[Tag] \texttt{<ProgressTime unix>} +\item[Props] \mbox{} \\ +    \emph{unix} \mbox{} Anzahl an Sekunden.  +\item[Beschreibung] Nimmt eine Anzahl an Sekunden und gibt an wie viele Stunden, +    Minuten und Sekunden die Anzahl entspricht.  +\end{description}  +\end{minipage} +\begin{minipage}{.3\linewidth} +    \begin{figure}[H] +        \includegraphics[width=\textwidth]{assets/progresstime.png} +    \end{figure} +\end{minipage} + + +\vspace{.5cm} + +\begin{minipage}{.7\linewidth} + +\subsubsection*{ErrorLog} + +\begin{description} +\item[Tag] \texttt{<ErrorLog>} +\item[Beschreibung] Zeigt eine Liste von Warnungen an, welche aus einem globalen +    Zustandsspeicher geladen werden.  +\end{description}  +\end{minipage} +\begin{minipage}{.3\linewidth} +    \begin{figure}[H] +        \includegraphics[width=\textwidth]{assets/errorlog.png} +    \end{figure} +\end{minipage} + + +\vspace{.5cm} + +\subsubsection*{Dashboard/FormLayout} + +\begin{description} +\item[Tag] \texttt{<DashboardLayout> <FormLayout>} +\item[Beschreibung] Fügt den Kindern einen Seitenabstand hinzu.  +\end{description}  diff --git a/20-implementierungsheft/sections/glossar.tex b/20-implementierungsheft/sections/glossar.tex new file mode 100644 index 0000000..9caad87 --- /dev/null +++ b/20-implementierungsheft/sections/glossar.tex @@ -0,0 +1,371 @@ +\makeglossaries + +\newglossaryentry{spa} +{ +    name=Single-Page-Application, +    description={ +        ist ein Webseiten-Modell, bei welchem dem Nutzer nur ein Webdokument +        bereitgestellt wird. Mit einem Skript wird der Inhalt der Seite +        dynamisch mit Daten einer API befüllt. Außerdem verwaltet die Seite +        (nicht der Server), welcher Inhalt bei welchem Pfad angezeigt wird. Dies +        erzeugt geringere Serverlast und eine bessere Nutzererfahrung, da die +        Seitenstruktur beim Laden von neuen Inhalten erhalten bleibt} +} + +\newglossaryentry{packagemanager} +{ +    name=Paketmanager, +    description={ +        ist ein Programm, welches Pakete und dessen Abhängigkeiten verwaltet, +        installiert, entfernt und aktualisiert. Pakete können andere Programme, +        Plugins oder Software-Bibliotheken sein} +} + +\newglossaryentry{bundler} +{ +    name=Bundler, +    description={ +        ist ein Programm, welches genutzte Teile von Abhängigkeiten eines +        Software-Projekts in passender Reihenfolge zusammensucht und daraus +        Dateien erstellt, die für den Nutzer bereitgestellt werden können. Dabei +        kann der Bundler mit zusätzlichen Modulen Dateien erzeugen, die +        rückwärtskompatibel oder für den Nutzer schwerer einsehbar sind} +} + +\newglossaryentry{java} +{ +    name=Java, +    description={ +        ist eine objekt-orientierte interpretierte kompilierte +        Programmiersprache, welche plattformunabhängig auf einer virtuellen +        Maschine ausgeführt wird} +} + +\newglossaryentry{db} +{ +    name=Datenbank, +    plural=Datenbanken, +    description={ +        ist ein System um Daten persistent zu speichern und effizient zu +        verwalten. Am meisten verbreitet sind relationale Datenbanken, welche +        Daten in Tabellen mit Referenzen zu Einträgen anderer Tabellen +        speichern. Programme können dann über eine Anfragesprache (Structured +        Query Language - \Gls{SQL}) komplexe Operationen auf den Daten ausführen} +} + +\newglossaryentry{docker} +{ +    name=Docker, +    description={ +        ist ein Programm, das virtualisierte Container ausführt. Ein Programm in +        so einem Container läuft in seiner eigenen virtuellen Umgebung, wodurch +        das Host-System sicher bleibt. Zudem lassen sich die Container leicht +        auf andere Systeme verteilen} +} + +% RESTfull-API, JSON, RSS-Feed, Salting and Hasing, OAuth, Cookie, Garbage +% Collection, DSGVO, Podcast, Podcatcher, Episode, Gpodder,  + +\newglossaryentry{podcatcher} +{ +    name=Podcatcher, +    plural=Podcatchern, +    description={ +        ist ein Programm, über welches man Podcasts entdecken, abonnieren und +        Episoden von Podcasts hören kann. Mit einem Account auf einer Plattform, +        welche eine Gpodder-API zur Verfügung stellt, können Ereignisse, die von +        einem Nutzer ausgehen, auf anderen Podcatchern des Nutzers +        synchronisiert werden} +} + +\newglossaryentry{podcast} +{ +    name=Podcast, +    description={ +        ist ein RSS-Feed, dessen Einträge die Episoden darstellen} +} + +\newglossaryentry{episode} +{ +    name=Episode, +    plural=Episoden, +    description={ +        ist ein Eintrag in einem Podcast. Eine URL in dem Eintrag zeigt auf eine +        Medien-Datei, welche vom Podcatcher abgespielt werden kann} +} + +\newglossaryentry{rest-api} +{ +    name=RESTful-API, +    description={ +        ist ein Schnittstellenentwurf über das Hypertext Transfer Protocol +        (HTTP), bei dem die Schnittstellen strukturiert als Pfad an einem +        Endpunkt erreichbar sind. Mittels verschiedener HTTP-Methoden können an +        der Schnittstelle Daten abgefragt (GET), gesendet (PUT), gelöscht +        (DELETE) oder geändert (POST) werden. Die Daten, die über die +        Schnittstelle gesendet werden liegen meist im JSON-Format vor} +} + + +\newglossaryentry{gpodder} +{ +    name=Gpodder-API, +    description={ +        wird von gpodder.net benutzt und entwickelt. Die API wird als +        Schnittstelle zwischen Podcatchern und Podcast Synchronisationsservern +        verwendet. Weitere Details sind unter +        "https://gpoddernet.readthedocs.io/en/latest/api/" zu finden} +} + +\newglossaryentry{json} +{ +    name=JSON, +    description={ +        (JavaScript Object Notation) ist ein Datenformat und wird zur +        Übertragung von Strukturen und Daten eingesetzt. JSON besteht dabei aus +        grundlegenden Datentypen sowie Objekten mit Schlüssel-Wert Paaren und +        Listen} +} + +\newglossaryentry{oauth} +{ +    name=OAuth, +    description={ +        (Open Authorization) ist ein offenes Protokoll, welches es Nutzern +        ermöglicht, sich mit bereits bestehenden Accounts bei anderen Diensten +        zu registrieren. Dabei werden benötigte Daten für die Registrierung über +        die bereitgestellte Schnittstelle zur Verfügung gestellt} +} + +\newglossaryentry{garbage-collection} +{ +    name=Garbage Collection, +    description={ +        ist eine automatische Speicherbereinigung, welche nicht mehr benötigten +        Speicherplatz wieder freigibt. Die Bereinigung kann dabei in determinierten +        Zeitintervallen erfolgen oder durch bestimmte Ereignisse ausgelöst +        werden} +} + +\newglossaryentry{salt-hash} +{ +    name=Salting und Hashing, +    description={ +        ist eine Methode um Passwörter so zu kodieren, dass sie nicht als +        Klartext gespeichert werden und auch sicher vor Hash-Wörterbüchern sind.  +        Dafür wird dem Passwort ein bekanntes Wort, der Salt, angefügt, bevor +        aus dem kompletten Wort eine Prüfsumme, ein Hash, generiert wird. Beim +        Anmelden wird die Prüfsumme der Anmeldung mit der bekannten +        Prüfsumme des Passworts verglichen} +} + +\newglossaryentry{rss} +{ +    name=RSS, +    description={ +        (Really Simple Syndication) zeigt strukturiert Listen von Nachrichten +        an. Die Änderungen werden im XML-Format in sogenannte RSS-Dateien +        geschrieben, welche über einen Link abgerufen werden können} +} + +\newglossaryentry{dsgvo} +{ +    name=Datenschutz-Grundverordnung, +    description={ +        (DSGVO) ist eine im europäischen Wirtschaftsraum +        geltende Verordnung. Sie sorgt für eine Reglementierung bei der +        Verarbeitung personenbezogener Daten. Unter anderem muss einsehbar sein, +        welche Daten von Nutzern erhoben werden. Außerdem muss für einen Nutzer +        die Möglichkeit bestehen, seine erhobenen Daten abrufen zu können} +} + +\newglossaryentry{push-pull} +{ +    name=Push und Pull, +    description={ +        sind Methoden, um Daten auszutauschen. Bei der Pull-Methode +        stellt Akteur A einem Akteur B eine Anfrage auf Daten und erhält diese +        als Antwort. Damit Akteur A und B immer auf dem selben Stand sind, muss +        Akteur A chronisch Anfragen an Akteur B stellen. Im Gegensatz dazu steht +        die Push-Methode, bei der Akteur B den Akteuren mitteilt, dass er neue +        Änderungen hat. Dafür muss Akteur B allerdings wissen mit welchen +        anderen Akteuren er in Verbindung steht und diese Verbindung aufrecht +        erhalten} +} + +\newglossaryentry{ui-lib} +{ +    name=UI-Bibliothek, +    plural=UI-Bibliotheken, +    description={ +        kümmert sich um das Layout einer Webseite. Dabei unterscheidet man +        zwischen Design-Bibliotheken (wie Bootstrap), welche fertige +        UI-Komponenten bereitstellen, und Layout-Bibliotheken (wie Vue oder +        React.js), welche die Komponenten basierend auf Daten dynamisch +        anzeigen} +} + +\newglossaryentry{responsive} +{ +    name=Responsive, +    description={ +        Design ist ein Design-Prinzip für Webseiten, bei dem die selbe Webseite ihre +        Komponenten dynamisch der Bildschirmbreite anpasst} +} + +\newglossaryentry{pseudoprotocol} +{ +    name=Pseudoprotokoll, +    description={ +        ist ein URL-Schema, auf das Webseiten hören können, wenn sie sich das +        URL-Schema im Browser anmelden. Bekannt Pseudoprotokolle sind: +        ,,mailto:'', ,,tel:'' oder ,,irc:''} +} + +\newglossaryentry{dashboard} +{ +    name=Dashboard, +    description={ +        ist die erste Seite auf der man landet, wenn man angemeldet ist} +} + +\newglossaryentry{abo} +{ +    name=Abonnement, +    description={ +        ist ein abonnierter Podcast} +} + +\newglossaryentry{discovery} +{ +    name=Discovery, +    description={ +        ist ein Feature der Gpodder-API, welches dem Nutzer eine Reihe von +        Podcasts zum abonnieren anbietet} +} + +\newglossaryentry{session-token} +{ +    name=Session-Token, +    description={ +        ist ein Wort, dass vom Client gespeichert wird solange der Nutzer +        eingeloggt ist und bei jeder Anfrage an den Server mitgeschickt wird.  +        Der Server kann den Session-Token einem Nutzer zuordnen und so mit +        nutzerspezifischen Daten antworten} +} + +\newglossaryentry{cookie} +{ +    name=Cookie, +    description={ +        ist ein kleiner webseitenspezifischer Speicher im Browser, welcher vom +        Server und von der Webseite gesetzt werden kann und bei jeder weiteren +        Anfrage an den Server mitgesendet wird. Cookies bleiben entweder +        temporär im Browserspeicher, bis der Browser geschlossen wird oder +        permanent, bis ein optionales Verfallsdatum erreicht ist} +} + +\newglossaryentry{uiComponent} +{ +    name=UI-Komponente, +    plural=UI-Komponenten, +    description={ +        In Vue.js werden die grafischen Elemente einer Webseite in einzelne +        Komponenten zerteilt.  +        Diese reagieren automatisch auf Änderungen und können ohne Neuladen +        der Seite ihr Aussehen verändern und somit Änderungen direkt anzeigen} +} + +\newglossaryentry{spring} +{ +	name=Spring, +	description={ +		Ein Java-Framework, welches die Entwicklung von Web-Applikationen erleichtert. +		Dazu wird eine Reihe von Werkzeugsets zur Verfügung gestellt. +		Unter anderem sind das Spring Web für das Erstellen von Webanwendungen, +		Spring Security für die Verwaltung von Benutzerauthentifizierungen und +		Spring Data JPA für die Arbeit mit relationalen Datenbanken +    } +} + +\newglossaryentry{api} +{ +	name=API, +    plural=APIs, +	description={ +		Eine Schnittstelle, welche es ermöglicht auf Funktionalitäten einer Anwendung +        zuzugreifen. APIs für Webanwendungen heißen WebAPIs. +        Ein Beispiel für eine WebAPI ist die REST-API +    } +} + +\newglossaryentry{business} +{ +	name=Geschäftslogik, +	description={ +		Eine Schicht in der Anwendungsentwicklung, in der die Art und Weise, wie das +        Programm auf Eingaben reagiert, wie Daten verarbeitet und wie sie gespeichert +        werden sollen, festgelegt ist +    } +} + +\newglossaryentry{solid} +{ +	name=SOLID, +	description={ +		Eine Sammlung an Prinzipien, welche zu gutem objektorientierten Design führen soll. +        Jedes Prinzip steht für einen Buchstaben in SOLID: +        \textbf{S}ingle-Responsibility Prinzip, +        \textbf{O}pen-Closed Prinzip, +        \textbf{L}iskovsches Substitutionsprinzip, +        \textbf{I}nterface Segregation Prinzip und +        \textbf{D}ependency Inversion Prinzip +    } +} + +\newglossaryentry{crud} +{ +	name=CRUD, +	description={ +		CRUD steht für \textbf{C}reate, \textbf{R}ead, \textbf{U}pdate und \textbf{D}elete. +        Hierbei handelt es sich um die grundlegenden Funktionen einer Anwendung, +        die mit einer Datenbank arbeitet. +        Hierbei können Daten angelegt, abgerufen, aktualisiert und gelöscht werden. +        Auch in Web-Applikationen ist CRUD mit HTTP über die Anfragen POST, GET, PUT und DELETE +        vertreten +    } +} + +\newglossaryentry{SQL} +{ +    name=SQL, +    description={ +        SQL (Structured Query Language) ist eine Sprache, die einen strukturierten Zugriff auf Datenbanken ermöglicht. +        Daten können hierbei hinzugefügt, abgefragt, geändert und gelöscht werden. +        Das besondere hierbei ist der strukturierte Zugriff auf Daten, indem explizit Daten mit bestimmten Kriterien und +        Relationen ausgewählt und bearbeitet werden können. +        SQL wird fast von allen verbreiteten Datenbanksystemen unterstützt +    } +} + +\newglossaryentry{Base64} +{ +    name=Base64, +    description={ +        Mithilfe von Base64 können 8-Bit-Binärdaten in eine ASCII-Zeichenkette +        kodiert werden. So werden zum Beispiel E-Mail-Anhänge versendet +    } +} + +\newglossaryentry{JSONP} +{ +    name=JSONP, +    description={ +        JSONP ermöglicht die Übertragung von JSON-Daten zwischen verschiedenen Domains. +        Dies wäre durch die Same-Origin-Policy nicht möglich. +        JSONP nutzt allerdings die Tatsache aus, +        dass sich Skripte domainübergreifend übertragen lassen. +        Dazu werden die JSON-Daten als Argument einer übergebenen Funktion über +        ein Skript-Element eingebunden +    } +} diff --git a/20-implementierungsheft/sections/methodology.tex b/20-implementierungsheft/sections/methodology.tex new file mode 100644 index 0000000..87b8176 --- /dev/null +++ b/20-implementierungsheft/sections/methodology.tex @@ -0,0 +1,16 @@ +\section{Integrationsstrategie} + +Bei der Implementierung wurde nach dem Outside-In Prinzip vorangegangenen. +Dabei handelt es sich um eine inkrementelle und vorgehensorientierte Integrationsstrategie.  +Sie versucht die Vorteile des Top-Down und des Bottom-Up Prinzips zu vereinen und die jeweiligen  +Nachteile zu mindern. + +Bei der Outside-In Integration wird gleichzeitig auf höchster und niedrigster logischer  +Ebene mit der Implementation begonnen. Das passt gut zu der gewählten Systemarchitektur.  +Es wird sowohl frühzeitig die \Gls{db} eingebunden als auch das Frontend und die  +Controller implementiert. Dafür wird erst später an der Service-Schicht gearbeitet. +Dieses Vorgehen wurde gewählt um die frühe Verfügbarkeit von testbaren Endpunkten zu haben.  +Somit können das Front- und Backend schon nach kurzer Zeit miteinander Integriert werden,  +wenn auch ohne funktionierende Serviceschicht. Außerdem wird für lange Zeit an verschiedenen  +Punkten gearbeitet, sodass der Prozess dank des vorrausgegangenen Entwurfs gut auf das ganze  +Team parallelisierbar ist.   diff --git a/20-implementierungsheft/sections/tests.tex b/20-implementierungsheft/sections/tests.tex new file mode 100644 index 0000000..cdbf163 --- /dev/null +++ b/20-implementierungsheft/sections/tests.tex @@ -0,0 +1,21 @@ +\section{Testfälle} + +Für die Erstellung der Testfälle wurde die SpringBoot Testumgebung verwendet und  +diese durch JUnit Testfälle ergänzt. + +Für das Testen wurde eine BaseTest Klasse erstellt, die grundlegende Funktionalität  +einiger Kern Komponenten sicherstellt. Weiter Initialisiert sie die Anwendungsumgebung auf  +der alle weiteren Tests aufbauen. + +Die Unit Tests erweitern diese BaseTest Klasse und können daher von gewisser Grundfunktionalität  +ausgehen, die durch den BaseTest abgedeckt ist. Dadurch müssen nicht große Teile der  +Anwendung durch Mock Objekte simuliert werden. + +Grundsätzlich wurde beim Entwurf der Testfälle nach dem Inside-Out-Prinzip vorangegangenen.  +Die bisher geschriebenen Testfälle haben dabei nicht das Ziel Korrektheit zu garantieren,  +sondern einen gewissen Qualitätsstandart zu sichern und gleichzeitig genug  +Arbeitspunkte bereit zu stellen um im ganzen Team an diesem Projekt parallel arbeite zu können.  + +Zusätzlich wurden bei der Implementierung auf ausgiebig getestete Annotationen von Spring und  +Lombok zurückgegriffen die helfen die Anzahl an Fehlern bei standardisierten  +\enquote{Boilerplater-Code} Aufgaben zu vermeiden. 
\ No newline at end of file diff --git a/20-implementierungsheft/sections/timeline.tex b/20-implementierungsheft/sections/timeline.tex new file mode 100644 index 0000000..7fa084d --- /dev/null +++ b/20-implementierungsheft/sections/timeline.tex @@ -0,0 +1,7 @@ +\section{Zeitlicher Verlauf} + +\subsection{Plan} +\includegraphics[width=\textwidth]{assets/diagrams/gantt-plan} + +\subsection{Realität} +\includegraphics[width=\textwidth]{assets/diagrams/gantt-reality}  | 
