summaryrefslogtreecommitdiff
path: root/20-implementierungsheft/sections
diff options
context:
space:
mode:
Diffstat (limited to '20-implementierungsheft/sections')
-rw-r--r--20-implementierungsheft/sections/anforderungsanalyse.tex185
-rw-r--r--20-implementierungsheft/sections/apidoc.tex191
-rw-r--r--20-implementierungsheft/sections/aufbau.tex47
-rw-r--r--20-implementierungsheft/sections/backend.tex28
-rw-r--r--20-implementierungsheft/sections/changes.tex241
-rw-r--r--20-implementierungsheft/sections/einleitung.tex11
-rw-r--r--20-implementierungsheft/sections/features.tex43
-rw-r--r--20-implementierungsheft/sections/features.tex.orig82
-rw-r--r--20-implementierungsheft/sections/frontend.tex196
-rw-r--r--20-implementierungsheft/sections/glossar.tex371
-rw-r--r--20-implementierungsheft/sections/methodology.tex16
-rw-r--r--20-implementierungsheft/sections/tests.tex21
-rw-r--r--20-implementierungsheft/sections/timeline.tex7
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}