This gitup-repository contains the source code of the akcore frontend app and backend api developed as part of the the A&K-Project of ${PARTICIPANTS} at the University of Potsdam in the winter semester of 2022/2023.
npm, version > 9.2.0
node, version > 19.3.0
The frontend is developed with the Vue.js frontend web-framework. To run the Vue development server, while in the directory "/akcoreapp/", run
npm install
npm run serve
This will run a development server listening at port 8081.
In a production environment, the vue app is deployed to a static web server, such as apache2, to be served over http. This can be done by running the command npm run build, which will create a "dist" directory at /var/www/html/akcore/dist/, containing a single page application ready to be deployed. The webserver needs to be properly setup to be able to serve the site correctly. (How to setup: TBD)
- Die Website wurde mit dem Vue.js Frontend Framework gebaut
- das CSS-Styling wurde mit dem Bootstrap Framework realisiert
- für http-requests wurde das AXIOS Framework genutzt
- die Navigationbar und die RouterView wurden in App.js eingebaut, der main file des Vue-Frameworks
- Die Ansichten wie der Login-Screen, die Mitarbeiter-Ansicht und Projekt-Ansicht wurden über das Vue-RouterView Konzept als Views in die main file App.js eingebunden; klickt man auf einen Nav-Link, um beispielsweise zur Mitarbeiter-View zu gelangen, wird die aktuelle RouterView durch die MitarbeiterView ersetzt
- häufig wiederverwendeter Code wurde als Component in die Views integriert, wie zum Beispiel der Loading-Anzeiger, um Code-Redundanz zu minimieren
- müssen einzelne Views mit dem Backend kommunizieren, tun sie das über Funktionen, die die app.js Datei bereitstellt. Hierzu wird die api.js file in jede View imporiert. Es werden alle nötigen Daten an diese Funktionen weitergegeben
- die Funktionen der api starten dann die http requests über axios (einer http request library für nodejs), indem sie die korrekten API-URIS aufrufen und im request body die daten aus den views an das backend übergeben
- über einen Login-Screen, der angezeigt wird, wenn ein Nutzer nicht eingeloggt ist, kann sich ein Nutzer anmelden
- dem Backend werden Nutzername und Passwort übergeben
- das Backend übergibt bei Erfolg alle Daten des Accounts, unter anderem den Account-Typ, der festlegt, welche Funktionen einem Nutzer im Frontend angezeigt werden und die organisationId, die dem Backend bei jeder Operation übergeben wird
- in Zukunft kann Authentifizierung durch eine JWT-Session-Token Authentifizierung ersetzt werden, aber für das PoC reicht diese Funktionalität vollkommen aus
- ermöglicht Anlegen und Bearbeiten von Mitarbeitern und Abteilungen
- Mitarbeiter werden für eine bestimmte Abteilung erstellt; sie können nicht abteilungslos sein
- Mitarbeiter benötigen die Attribute Name und E-Mail und Abteilung
- Abteilungen benötigen einen Namen
- Mitarbeiter und Abteilungen existieren nach dem Erstellen in der Datenbank
- Mitarbeiterattribute können aktualisiert werden
- Abteilungen können nur gelöscht werden, falls die Abteilung leer ist
Mitarbeiter können nur gelöscht werden, wenn sie gerade an keinem aktiven Projekt teilnehmen. Wird trotzdem der Versuch unternommen, wird eine Warnmeldung ausgegeben, und bei Bestätigung der Mitarbeiter rekursiv aus allen Projekten gelöscht.Achtung! Noch nicht umgesetzt.- - es findet (noch) keine Frontend-Validierung statt
- ermöglicht Anlegen und Bearbeiten von Projekten und Umfragen für ein Projekt
- Projekte benötigen einen Namen, eine Beschreibung, ein Start- und End-Datum
- es können beliebig viele Umfragen hinzugefügt werden; Umfragen benötigen ein Start- und End-Datum, das Startdatum darf nicht in der Vergangenheit und das Enddatum nicht vor dem Startdatum liegen
- es können bereits existierende Teilnehmer ausgewählt werden; ihnen muss eine der 3 Mitarbeiter Rollen Key-User, Change-Manager, User zugeordnet werden (evtl. bearbeiten dieser Rollen ermöglichen?)
- es werden alle Eingaben im Frontend validiert
- dem Backend werden die vom User eingegebenen Projekt-Informationen sowie der organisationId des Users übergeben
- das Backend übergibt nach dem Erfolg durch den Location-Header die projektId des erstellten Projekts und das Frontend leitet den User zur Projektansicht des erstellten Projekts
- ermöglicht das Darstellen eines Projekts
- hier können alle Informationen, Umfragen und Teilnehmer eingesehen werden
- über einen Button kann die Bearbeitungsansicht aufgerufen werden
- über einen Button kann das dem Projekt zugeordnete Kibana-Dashboard angezeigt werden
- ermöglicht das Bearbeiten eines Projekts
- es können Umfragen und Teilnehmer hinzugefügt werden
- es können (noch) keine Umfragen und Teilnehmer gelöscht werden
- über einen Button kann das Projekt gelöscht werden (evtl. verschieben dieser Funktionalität in Bearbeiten-Ansicht?)
- dem Backend werden die Projekt-Informationen sowie die organisationId des Users übergeben; die Projekt-Informationen enthalten die alten sowie die neuen Projektinformationen gleichermaßen
- das Backend übergibt eine Erfolgsmeldung nach Erfolg und das Frontend leitet zur Projektansicht weiter
- Die Nutzerverwaltung ist zur Zeit noch nicht umgesetzt. Es können keine Nutzeraccounts angesehen, erstellt oder bearbeitet werden
- Das Freischalten bzw. Beschränken einiger Funktionen basierend auf dem Account-Typ (Change-Manager sollen keine Nutzeraccounts einsehen und Projekte oder Mitarbeiter bearbeiten können) ist noch nicht umgesetzt
npm, version > 9.2.0
node, version > 19.3.0
The backend is developed with express.js for node. To run the express.js api server, while in the directory "/akcoreapi/", run
npm install
npm run serve
This will run a exprees.js api server listening at port 3001.
In a production environment, the node app is run as a daemon (system service) on a Linux system. This will automatically restart the server if it crashes and logs any stdin/stderr output to a specified log-file. This project is setup through a systemd-daemon called "nodeapi", logging stdin/stderr via rsyslog to /akcoreapi/logs/service.log. To follow the content of the log live in a terminal, while the service is active, you can run less -f /home/nifranz/dev/git/akcore_stable/logs/error.log. To start or stop the service, you can run with appropriate privileges systemctl [start | stop | restart] nodeapi.
- Der HTTP-API-Server wurde mit dem node.js-Framework express.js gebaut
- Es wurde das ORM-Package Sequelize genutzt, um alle persistenten Daten zu modellieren und Datenbankfuntionen umzusetzen
- Die Daten werden in einer mariadb Datenbank des Linux-Servers gespeichert
- Um die Elasticsearch-API anzusprechen, wurde der elastic-search client für node.js genutzt
- Es wurde das uuid-Package genutzt, um uuids generieren zu können
- Der Server bietet mehrere API-Endpoints an, um Backend-Funktionalitäten bereitzustellen
- Einige dieser Endpoints sind über die express.js router-Funktionalität eingebunden, andere werden direkt (z.b mit app.get()) definiert
- Die routes wurden in src/routes/ definiert und im router der app in server.js-file eingebunden.
- Routes leiten eine eingehende Anfrage an die Controller weiter, welche dann die Durchführung der angefragten Funktionen steuern
- Die CRUD-Operationen der Controller werden durch folgende HTTP API-Endpoints nach dem REST-Schema angestoßen:
| CRUD Funktion | API-Endpoint |
|---|---|
ModelController.list() |
GET /model/ |
ModelController.create() |
POST /model/ |
ModelController.read() |
GET /model/:id |
ModelController.update() |
PUT /model/:id |
ModelController.delete() |
DELETE /model/:id |
- Ein Beispiel: Es soll eine Abteilung gelöscht werden. Die CRUD Operationen für Abteilungen werden durch den ModelController
AbteilungControllergesteuert, weshalb die Abteilung durch den Aufruf der FunktionAbteilungController.delete()gelöscht werden kann. Um dies durch einen API-Aufruf durchzuführen, muss mit einem HTTP-DELETE-Request die URL/abteilung/abteilungIdmit der enstprechenden abteilungId der zu löschenden Abteilung aufgerufen werden. - Erwartet ein Controller Daten für die Operation (beim Erstellen einer Abteilung zum Beispiel einen Abteilungsnamen), werden diese vom Router, der den HTTP-Request entgegen nimmt, durch den Request-Body oder den Request-Query-String an den Controller übergeben
- Nicht alle ModelController modellieren alle CRUD-Operationen auf den DataModels, daher sind die dazugehörigen API-Endpoints der nicht realisierten CRUD-Operationen enstprechend nicht über das HTTP-Protokoll erreichbar
- Welche Routes und Operationen implementiert sind, ergibt sich aus dem dokumentierten Code der Routes und Controller in
src/routes/undsrc/controller/
- Wie oben erwähnt, werden die Funktionalitäten des Backends durch Controller gesteuert, welche in
src/controller/definiert sind - Für jedes Data-Model (und damit alle implementierten Datenbankoperationen) existiert ein Controller
- Zur Zeit existieren nur für Datenbankoperationen Controller, alle anderen Funktionalitäten werden noch in der server.js-file gesteuert und umgesetzt
- Zur Zeit findet die Durchführung der Business-Logic (wie zum Beispiel das Erstellen eines Projekts) ebenfalls im Controller statt. In Zukunft können und sollte die Business-Logic von den Controllern in express-helper-services und -middlewares ausgelagert werden
- Die Funktionen der Controller werden unter dem Punkt 2.1 genauer beschrieben
- Die Daten werden in der mariadb Datenbank des Linux-Servers gespeichert. Hierfür existiert die Database "akcoredb" in mariadb
- Die Verbindung zur Datenbank wird über Sequelize hergestellt
- Die Datenmodellierung und Datenbankoperationen werden über Sequelize realisiert. Das generieren der Entity-Ids (bspw. die mitarbeiterId oder projektId) übernimmt Sequelize automatisch
- Die Sequelize Entity-Models und ihre Relationen wurden in src/models/ definiert
- Soll eine Datenbankoperation durchgeführt werden, werden enstprechende Methoden der Sequelize-Models ausgeführt (z. B. erstellt die Methode MitarbeiterModel.create(mitarbeiterData) einen Mitarbeiter in der mariadb-Datenbank)
- Die Struktur der Daten wird durch folgendes ERM illustriert:
In die Funktionen des Backends sind mehrere Aufrufe zu den APIs von LimeSurvey (LRPC), Elasticsearch (ESAPI) und Kibana (KIBAPI) eingebunden. Die Einbettung der externen API-Funktionen wurde durch API-Client-Klassen realisiert, welche Funktionen bereitstellen, die HTTP-Aufrufe an die API-Endpoints durchführen können und die zurückgegebenen Daten verarbeiten. Im Fall der Elasticsearch API wurde der bereits existierende Elasticsearch-API-Client für nodejs in einer eigenen Klasse gekapselt, um das Vorgehen bei Funktionsaufrufen innerhalb des Projekts zu vereinheitlichen. Eine Übersicht der Funktionsweise und der genutzten API-Endpoints ergibt sich aus dem dokumentierten Code der Klassen, welche in src/apis/ definiert sind.
Diese Auflistung der Controller-Funktionen der DataModels stellt lediglich eine Übersicht der Vorgehensweise des Systems bei der Durchführung der genannten Operationen dar. Eine ausführliche Deskription der Funktionsweise sowie weiterer Informationen wie Funktions-Parameter und -Rückgabewerte ergibt sich aus dem dokumentierten Code der einzelnen Controller in src/controller/ sowie der DataModels selbst in src/models/.
Abteilungen können aufgelistet, erstellt und gelöscht werden
Abteilung.list() - Auflisten
Abteilung.create() - Erstellen
- Durch die Controller-Funktion
Abteilung.create()wird eine Abteilung mit dem Attribut Name in der Datenbank angelegt Sollte bereits eine Abteilung mit dem Namen für die aktuelle Organisation existieren, wird die Abteilung nicht erstellt
Achtung! Noch nicht umgesetzt!
Abteilung.delete() - Löschen
- Durch die Funktion
Abteilung.delete()kann ein Abteilung aus der Datenbank gelöscht werden - Wird das Löschen einer Abteilung angefragt, welche Mitarbeiter enthält, wird die Abteilung nicht gelöscht
Mitarbeiter können aufgelistet, erstellt, bearbeitet und gelöscht werden
Mitarbeiter.list() - Auflisten
- Durch die Controller-Funktion
Mitarbeiter.list()werden alle Mitarbeiter einer gegebenen Organisation aufgelistet
Mitarbeiter.create() - Erstellen
- Durch die Controller-Funktion
Mitarbeiter.create()wird ein Mitarbeiter mit den Attributen Name, E-Mail und Abteilung in der Datenbank angelegt
Mitarbeiter.update() - Bearbeiten
- Durch die Controller-Funktion
Mitarbeiter.update()können alle Mitarbeiterattribute eines Mitarbeiters in der Datenbank aktualisiert werden. Für jede Umfrage, an der der Mitarbeiter teilnimmt, werden die neuen Attribute über LRPC auch in der LimeSurvey-Datenbank aktualisiert
Achtung! Da die LimesurveyRPC eine nicht gelöste Fehlermeldung zurückgibt, wenn ein Participant über die funktion set_participant_attributes geupdated wird, werden die Attribute zur Zeit nicht in Limesurvey aktualisiert
Mitarbeiter.delete() - Löschen
- Durch die Controller-Funktion
Mitarbeiter.delete()kann ein Mitarbeiter aus der Datenbank gelöscht werden. Die dem Mitarbeiter zugehörigen LimesurveyParticipantTokens werden daraufhin aus allen Surveys gelöscht.
Achtung! Noch nicht umgesetzt!
Projekte können aufgelistet, asugegeben, erstellt, überarbeitet und gelöscht werden
Projekt.list() - Auflisten
- Durch die Controller-Funktion
Projekt.list()werden alle Projekte und ihre Informationen für eine gegebene Organisation aufgelistet
Projekt.create() - Erstellen
- Durch die Controller-Funktion
Projekt.create()wird ein Projekt mit den Attributen Projektname, Projektbeschreibung sowie Start- und Enddatum in der Datenbank angelegt - Außerdem werden für alle übergebenen Umfragen-Datensätze Umfragen mit den Attributen Start- und Enddatum in der Datenbank angelegt und über die Assoziationsbeziehung mit dem Projekt verlinkt
- Für jede Umfrage wird eine Survey in Limesurvey angelegt. Hierfür wird eine zuvor von LimeSurvey exportierte LimeSurvey-LSS-Datei ("assets/base_survey_2.lss") dupliziert und so angepasst, dass sie den Projekt- und Umfrageattributen entspricht. Anschließend wird sie durch das LRPC in LimeSurvey importiert. Die durch das LRPC zurückgegebene surveyId der importierten5 Survey wird unter dem Umfrage-Attribut "umfrageLimesurveyId" in der Datenbank hinterlegt
- Für jeden Mitarbeiter wird die Projektteilnahme über die Assoziationsbeziehung in der Datenbank verlinkt
- Für jeden Mitarbeiter wird für jede Umfrage durch LRPC ein Limesurvey-Participant erstellt. Der resultierende Token, der den Mitarbeiter als Participant eindeutig einer Survey zuweisbar macht, wird über die Assoziationsbeziehung in der Datenbank unter dem Attribut "mitarbeiterLimesurveyTokenId" hinterlegt
- Für das Projekt werden in Elastic durch die Elastic API drei Indices angelegt: responses, count und pie. Um die Indices zu referenzieren, enthalten die Indices die projektId
- Für das Projekt wird durch die Kibana API in Kibana ein Space angelegt; die id des Space' ist die projektId. Das Kibana source-Dashboard wird in den neuen Space hineinkopiert. Das DataView des kopierten Dashboards wird angepasst, sodass es nun die Elastic Indices des Projekts referenziert. Die Id des Dashboards wird im Projekt-Attribut "projektKibanaViewId" hinterlegt
Projekt.read() - Ausgeben
- Durch die Controller-Funktion
Projekt.read()wird ein Projekt und zugehörige Informationen ausgegeben
Projekt.update() - Bearbeiten
- Durch die Controller-Funktion
Projekt.update()können alle Projektattribute in der Datenbank aktualisiert werden. - Es können weitere Teilnehmer und Umfragen dem Projekt hinzugefügt werden. Umfragen werden in der Datenbank hinterlegt, Teilnehmer über die Assoziationsbeziehung dem Projekt in der Datenbank zugeordnet
- Werden neue Teilnehmer hinzugefügt, werden für die neuen Teilnehmer Survey-Participants in allen dem Projekt zugehörigen Surveys durch LRPC nach dem selben Vorgehen wie in
Projekt.create()angelegt - Werden Umfragen hinzugefügt, werden für sie neue Umfragen durch LRPC angelegt und für alle Teilnehmer des Projekts Survey-Participants angelegt (siehe
Projekt.create()) Es können Umfragen aus einem Projekt entfernt werden. Werden Umfragen entfernt, wird die entsprechende Survey aus LimeSurvey und der Datenbank gelöscht.
Achtung! Noch nicht umgesetzt!Es können Teilnehmer aus einem Projekt entfernt werden. Dabei wird die Assoziationsbeziehung in der Datenbank zwischen Projekt und Mitarbeiter aufgehoben und alle Survey-Participants des Teilnehmers in den Surveys des Projekts gelöscht
Achtung! Noch nicht umgesetzt!
Projekt.delete() - Löschen
- Durch die Controller-Funktion
Projekt.delete()wird ein Projekt aus der Datenbank gelöscht, die Assoziationen von Teilnehmern und dem Projekt gelöscht sowie alle Surveys des Projekts durch LRPC in LimeSurvey gelöscht
- Achtung! Das Konzept der Nutzer (Accounts) ist noch nicht vollständig umgesetzt
- Zur Zeit sind alle Nutzer in der server.js-File hardcoded und werden nur zur Verifizierung eines Benutzers beim Login verwendet
- Als nächster Schritt werden die Nutzeraccounts in die Datenbank durch neue Sequelize DataModels verlagert und API-Endpoints für die Nutzerverwaltung ähnlich der bereits existierenden API-Endpoints für Mitarbeiter geschrieben, um dem Frontend diese Funktionalität bereitzustellen
- Durch einen Linux Cron-Job wird täglich um 9:30 Uhr die route
/utils/ls/emailtriggeraufgerufen - Der Service prüft für alle Projekte in der Datenbank, welche Umfragen zur Zeit aktiv sind
- Für alle aktiven Umfragen werden durch die LRPC-Funktion
LRPC.remindParticipants()zunächst alle bereits eingeladenen Teilnehmer an die Teilnahme erinnert und anschließend alle nocht nicht eingeladenen Teilnehmer zur Teilnahme eingeladen (LRPC.mailRegisteredParticipants())
- Durch einen Linux Cron-Job wird alle 10 Minuten die route
/utils/es/datainjectaufgerufen - Der Service prüft für alle Projekte in der Datenbank, welche Umfragen zur Zeit aktiv sind
- Für alle aktiven Umfragen wird ein JSON-Objekt mit den Attributen Rolle, Abteilung und mitarbeiterLimesurveyTokenId für alle Teilnehmer einer Umfrage erstellt
- Dieses Objekt wird in eine Datei gespeichert und der Dateipfad an das python-Datentransformationsskript übergeben, welches die Response-Daten der Teilnehmer aus Limesurvey extrahiert und für die Injection in die ElasticSearch Indices vorbereitet
- Über eine Datei, die das python-Skript erstellt hat, werden die transformierten Daten geladen und anschließend für jeden Daten-Eintrag (= elasticsearch document) die inject-Methode der ESAPI-Klasse
ESAPI.writeDataToDocument()aufgerufen, wodurch die Daten in die Elasticsearch Indices des Projekts geschrieben werden
- Wenn vom Frontend eine Login-Verifizierung über die route
/utils/verifyLoginangefragt wird, überprüft das Backend, ob ein Account existiert, das übergebene Passwort mit dem Passwort aus der Datenbank übereinstimmt und gibt bei Erfolg den Account mit weiteren Attributen wie dem Account-Typ und der organisationId des Accounts zurück
