Projekteinblick: CMS für Coaching App – Architektur, Authentifikation und Data Management

Juli 20, 2023Einblick

Willkommen zurück zu unserer fortlaufenden Beitragsreihe über die Entwicklung eines Content Management Systems (CMS) für eine Coaching-App. Nachdem wir uns im ersten Teil auf die Konzeption, die Anforderungen und die User Story konzentriert haben, tauchen wir in diesem zweiten Beitrag tiefer in die technischen Aspekte des Projekts ein.

Begleiten Sie uns auf dieser spannenden technischen Reise und gewinnen Sie tiefere Einblicke in die Mechanismen, die hinter der Gestaltung und Umsetzung eines effektiven und benutzerfreundlichen CMS stehen. Ob Sie ein Entwickler, ein Technologieenthusiast oder einfach nur neugierig sind – dieser Beitrag bietet wertvolle Einblicke in den Prozess der Softwareentwicklung.

Architektur

Zuerst lenken wir unseren Fokus auf die Architektur des CMS, ein Kernelement, das entscheidend ist für die Funktionalität und die Leistungsfähigkeit unserer Anwendung. Wir werden Ihnen Einblicke in unsere Entscheidungen bezüglich des Designs und der Struktur der App geben und erklären, wie wir eine solide und skalierbare Architektur aufgebaut haben.

Für den Aufbau der Software haben wir uns für ein modulares Schichten basierte Architektur entschieden. Semantisch zusammenhängende Elemente werden in Komponenten zusammengefasst. Diese Elemente besitzen eine Präsentations-, sowie eine Geschäftslogikschicht. Die Presistenzschicht wird in der jeweiligen Handlerklasse abgebildet und regelt die Kommunikation mit der Presistenzschicht.

Komponenten (Präsentations- & Geschäftslogikschicht)

Die Komponenten bilden durch ihre definierten Schnittstellen eine modulare Struktur. Diese Schnittstellen werden im „Kopf“ der Komponenten definiert:

//Bsp.: /components/modular/ImageUpload.tsx
export default function ImageUpload(props: { backgroundImageUrl: string; onUpload: any }) {

Im oberen Teil der Komponenten werden die Funktionen und Elemente definiert, die für die Geschäftslogik zuständig sind:

//Bsp.: /components/modular/ImageUpload.tsx
function handleCoverPhotoInput(file: File | undefined) {
...
const handleDragEnter: React.DragEventHandler<HTMLDivElement> = (e) => {
...

Anschließend wird im returnWert das GUI und somit die Präsentationsschicht definiert:

//Bsp.: /components/modular/ImageUpload.tsx
return (
<div>
...
<span>Upload a file</span>
<input onChange={(e) => handleCoverPhotoInput(e.target.files?.[0])}/>
...
</div>
)

Hier ist ein Klassendiagramm der großen Hauptkomponenten, die als Seiten dienen:

Für die kleineren modularen Komponenten haben wir ein separates Klassendiagramm erstellt.

Handler (Persistenzschicht)

Die einzelnen Handler (Bsp.: dbHandler.tsx) standardisieren die Kommunikation mit der Persistenzschicht für die anderen Komponenten. Die Funktionen sind einheitlich definiert und dank der Typisierung vor fehlerhaften Objekten geschützt:

Bsp.: /handler/dbHandler.tsx

export function writeBeitraegeData(userId: string, beitraegeData: Beitraege) {
...

Die Handler kümmern sich dabei um den Aufbau der Datenbankverbindung und behandeln eventuelle Probleme, wie dass angefragte Daten nicht vorhanden sind. Wenn dies der Fall ist, werden leere Objektvorlagen aus dem dataPresetsHandler.tsx geladen.

export async function getKurseData(userId: string) {
	try {
		const dbRef = ref(getDatabase());
		const snapshot = await get(child(dbRef, "users/" + userId + "/kurse"));

		if (snapshot.exists()) {
			console.log(snapshot.val());
			return snapshot.val();
		} else {
			console.log("No data available");
			return getKurseDataPreset();
		}
	} catch (e) {
		console.error(e);
		return undefined;
	}
}

Das Klassendiagramm der Handler Komponenten sehen Sie hier:

Firebase (Datenbankschicht)

Unser Firebase Backend ist in drei Teilbereiche unterteilt. Die noSQL Datenbank, der File-Storage und der Auth-Service. Die Kommunikation der Software mit der Datenbankschicht läuft ausschließlich über die zwischengeschaltete Datenbankschicht. Die Daten werden in Firebase gespeichert und durch definierte Sicherheitsregeln geschützt. Diese Regeln wurden so definiert, dass ein eingeloggter Nutzer nur seine eigenen Daten lesen und schreiben darf.

Authentication & Authorisation

Nun werfen wir einen Blick auf die Authentifizierungsprozesse. Diese spielen eine wesentliche Rolle, um die Sicherheit der Nutzerdaten zu gewährleisten und den Zugriff auf die verschiedenen Bereiche des CMS angemessen zu steuern.

Allgemein

Für die Athentifizierung udn Authorifikation nutzen wir den Auth Service von Firebase. Dies stellt sicher, dass auf die Datenbank auch nur von berechtigten Nutzer zugegriffen werden kann. Dies wurde in den Datenbankregeln definiert.

Grundsätzlich sollen alle Seite nur im eingloggten Zustand aufrufbar sein. Außgenommen sind hierbei die Start-, Login- und Registrierungsseite.

authHandler.js

Der authHandler.js stellt die benötigten Funktionen zur Verfügung, um neue Nutzer anzulegen registerNewUser(…), sich einzuloggen signInUser(…), sich auszuloggen, das Passwort zurückzusetzen und die NutzerID des eingeloggten Nutzers abzufragen getCurrentUserId().

Zugangsbeschränkung in _app.js

Die oben genannte Zugangsbeschränkung wurde in der _app.jsumgesetzt. Dabei wird beim Aufruf der Login Status und die Nutzer ID abgefragt und überprüft. Wenn der Nuzter nicht eingeloggt ist, wird der Zugang verweigert und eine Nachricht angezeigt, dass der Nutzer sich einloggen soll. Die Startseite, die Loginseite und die Registrierungsseite sind von der Zugangsbeschränkung ausgenommen.

Data Management

Schließlich widmen wir uns dem Thema Data Management, einem zentralen Aspekt in jeder digitalen Anwendung. Wie haben wir die Datenverwaltung in unserem CMS organisiert, um eine effiziente und sichere Handhabung der vielfältigen Inhalte zu ermöglichen?

Für das Speichern der Daten haben wir uns für die Firebase Realtime Database entschieden. Diese ist eine NoSQL Datenbank, die von unserer Persistenzschicht angesprochen, gelesen und beschrieben wird. Mehr dazu finden sie hier

Um die Daten des Nutzers lesen und schreiben zu können, muss sich der Nutzer zunächst authentifizieren. Dies funktioniert über den Authentifikation Service von Firebase. Dieser liefert eine einzigartige User-ID, die für die Zugriffe auf die Daten benötigt wird.

Die gespeicherten Daten werden in mehrere Bereiche unterteilt. Zum einen die Konto- und Profildaten sowie Kurse- und Beitragsdaten

Der dbHandler.js stellt sämtliche Methoden zur Verfügung, um die Daten sicher an die Datenbank zu senden, oder diese von dort abzufragen. Der dbHandler vereinheitlicht hierbei die Kommunikation über die von ihm definierten Schnittstellen und sorgt für valide Anfragen und Antworten.

Die folgenden Methoden können von dbHandler aufgerufen werden:

  • getCourseData(userId)
  • writeCourseData(userId,data)
  • getBeitraegeData(userId)
  • writeBeitraegeData(userId,data)
  • getKontoData(userId)
  • writeKontoData(userId,data)
  • getProfileData(userId)
  • writeProfileData(userId)

Let’s talk business

Kontaktieren Sie uns und lassen Sie sich bei einem kostenlosen Erstgespräch von uns beraten. Wir freuen uns darauf, Sie kennenzulernen.

“Gemeinsam gestalten wir ihre digitale Identität”

Philipp Zimmermann

Philipp Zimmermann

Ihr Ansprechpartner

11 + 7 =