|
All checks were successful
CI Pipeline / lint-and-test (push) Successful in 2m42s
Reviewed-on: https://owgit.duckdns.org/DrunkenPinguin/LernApp/pulls/11 |
||
|---|---|---|
| .github/workflows | ||
| docs | ||
| gradle | ||
| src | ||
| .editorconfig | ||
| .gitignore | ||
| build.gradle.kts | ||
| gradle.properties | ||
| gradlew | ||
| gradlew.bat | ||
| img.png | ||
| README.md | ||
| settings.gradle.kts | ||
Kidio Backend
Das Kidio-Backend ist eine gamifizierte Lösung zur Verwaltung von Bildschirmzeit für Kinder.
Die Anwendung basiert auf dem Ktor-Framework in Kotlin und kombiniert PostgreSQL für die persistente Datenhaltung mit Redis als Caching-Layer für schnelle Zugriffszeiten.
Kinder können durch das Lösen von Lernaufgaben, beispielsweise Mathematikaufgaben, zusätzliche Bildschirmzeit erwerben. Gleichzeitig synchronisiert das System die verbrauchte Bildschirmzeit und sperrt das Gerät automatisch, sobald keine verfügbare Bildschirmzeit mehr vorhanden ist.
Features
| Feature | Beschreibung |
|---|---|
| JWT-Authentifizierung | Sichere API-Endpunkte für authentifizierte Benutzer über JSON Web Tokens (JWT). |
| Lernaufgaben (Tasks) | Abrufen von interaktiven Lernaufgaben mit vordefinierten Antwortmöglichkeiten, Filterung nach Fach und Alter sowie Belohnungen in Minuten. |
| Antwort-Verifizierung | Überprüfung der vom Kind ausgewählten Antworten. Bei korrekter Antwort wird die Belohnung direkt auf die verbleibende Bildschirmzeit aufgerechnet. |
| OER / H5P Ingestion Pipeline | Automatisierter Live-Crawler und Batch-Import von freien Bildungsinhalten (ZUM.de / H5P) inklusive HTML-Bereinigung und Lizenzattributierung (CC-BY). |
| Bildschirmzeit-Synchronisation | Laufender Datenabgleich der verbrauchten Bildschirmzeit. Sinkt die verbleibende Zeit auf oder unter null, wird der Status automatisch auf isBlocked = true gesetzt. |
| Zwei-Ebenen-Speicher | PostgreSQL als persistente Datenbank, kombiniert mit Redis-Caching für schnelle Screentime-Abfragen. |
| Fallback-Mechanismus | Ist Redis nicht erreichbar, fällt das System automatisch und transparent auf PostgreSQL zurück. |
Technologiestack
- Framework: Ktor
- Programmiersprache: Kotlin
- Datenbank-ORM: JetBrains Exposed
- Persistenz: PostgreSQL
- Caching: Redis via Jedis
- Authentifizierung: JWT via Java JWT (Auth0)
- Serialisierung: Kotlinx Serialization
- Code Quality / Linter: KtLint
- Testing: Ktor Server Testing, JUnit
- CI/CD: Forgejo Actions (Gitea / Act Runner)
API-Endpunkte
Alle API-Endpunkte befinden sich unter dem Präfix:
/api/v1
Öffentliche Endpunkte
1. Health-Check
Methode: GET
Pfad:
/api/v1/health
Beschreibung:
Prüft, ob der Backend-Server ordnungsgemäß läuft.
Antwort:
{
"status": "OK",
"message": "Kidio Backend läuft!"
}
2. Benutzer-Registrierung
Methode: POST
Pfad:
/api/v1/auth/register
Request-Body:
{
"email": "test@family.de",
"passwordPlain": "strengGeheim1",
"familyName": "Familie Schmidt",
"childAge": 8,
"parentPin": "4321"
}
Antwort – 201 Created:
{
"token": "eyJhbGciOiJIUzI1NiIsIn...",
"userId": "6380776f-88d3-4e9f-a2be-0d9cacae447e",
"message": "Registrierung erfolgreich"
}
3. Benutzer-Login
Methode: POST
Pfad:
/api/v1/auth/login
Request-Body:
{
"email": "test@family.de",
"passwordPlain": "strengGeheim1"
}
Antwort – 200 OK:
{
"token": "eyJhbGciOiJIUzI1NiIsIn...",
"userId": "6380776f-88d3-4e9f-a2be-0d9cacae447e",
"familyName": "Familie Schmidt",
"childAge": 8
}
Geschützte Endpunkte
Die folgenden Endpunkte erfordern ein gültiges JWT im HTTP-Header:
Authorization: Bearer <Token>
4. Bildschirmzeit abrufen
Methode: GET
Pfad:
/api/v1/screentime
Beschreibung:
Liefert die aktuell verbleibende Bildschirmzeit sowie den aktuellen Sperrstatus des authentifizierten Benutzers.
Antwort – 200 OK:
{
"remainingSeconds": 1800,
"isBlocked": false
}
5. Bildschirmzeit synchronisieren
Methode: POST
Pfad:
/api/v1/screentime/sync
Beschreibung:
Zieht die seit dem letzten Abgleich vom Endgerät verbrauchten Sekunden von der verfügbaren Bildschirmzeit ab.
Request-Body:
{
"usedSecondsSinceLastSync": 30
}
Antwort – 200 OK:
{
"remainingSeconds": 1770,
"isBlocked": false
}
6. Lernaufgaben abrufen (mit Fach- & Altersfilter)
Methode: GET
Pfad:
/api/v1/tasks
Optionale Query-Parameter:
| Parameter | Typ | Standardwert | Beschreibung |
|---|---|---|---|
subject |
String | null |
Schulfach (z. B. Mathematik, Deutsch, Sachunterricht, Englisch, Biologie, Geographie, Geschichte). |
age |
Integer | null |
Zielalter des Kindes (filtert nach minAge <= age AND maxAge >= age). |
limit |
Integer | 10 |
Maximale Anzahl an zurückgegebenen Aufgaben. |
Beispiel-Anfrage:
GET /api/v1/tasks?subject=Mathematik&age=8&limit=5
Beschreibung:
Liefert kuratierte oder aus OER/H5P importierte Lernaufgaben. Die korrekte Lösung (correctAnswer) wird zum Schutz vor Manipulationen serverseitig geheim gehalten und niemals an den Client übertragen.
Antwort – 200 OK:
[
{
"id": "zum-math-001",
"subject": "Mathematik",
"minAge": 8,
"maxAge": 9,
"question": "Was ist das Ergebnis von 6 × 8?",
"options": [
"42",
"48",
"54",
"56"
],
"rewardMinutes": 5,
"license": "CC BY-SA 4.0"
}
]
7. Antwort überprüfen und Belohnung verbuchen
Methode: POST
Pfad:
/api/v1/tasks/verify
Request-Body:
{
"taskId": "zum-math-001",
"selectedAnswer": "48"
}
Antwort – korrekte Lösung (200 OK):
{
"isCorrect": true,
"earnedMinutes": 5,
"message": "Super gemacht! Du hast 5 Minuten gewonnen."
}
Antwort – falsche Lösung (200 OK):
{
"isCorrect": false,
"earnedMinutes": 0,
"message": "Schade, das war leider falsch. Versuche es nochmal!"
}
H5P / ZUM.de Aufgaben-Import (Standalone CLI)
Das Backend verfügt über ein integriertes CLI-Tool zum automatisierten Importieren und Crawlen interaktiver Lernaufgaben von ZUM.de / OER (H5P).
Batch-Import ausführen
# Alle Fächer importieren (z. B. 100 Aufgaben)
./gradlew runIngestion --args="--limit=100"
# Gezielt ein Schulfach importieren (z. B. Mathematik)
./gradlew runIngestion --args="--subject=Mathematik --limit=50"
# Deutsch für Grundschüler importieren
./gradlew runIngestion --args="--subject=Deutsch --limit=30"
CLI-Optionen
| Argument | Standardwert | Beschreibung |
|---|---|---|
--subject=<Name> |
(alle Fächer) | Filtert Aufgaben nach Fach (z. B. Mathematik, Deutsch, Englisch, Sachunterricht). |
--limit=<Zahl> |
50 |
Maximale Anzahl an Aufgaben, die im Durchlauf importiert/aktualisiert werden. |
Funktionsweise der Ingestion-Pipeline
- Live-Crawler & Discovery: Durchsucht
apps.zum.denach interaktiven Inhalten (H5P.MultiChoice,H5P.TrueFalse,H5P.QuestionSet). - Textbereinigung: Entfernt störende HTML-Tags (
<p>,<strong>, ) für native mobile Darstellung. - Taxonomie- & Alters-Mapping: Weist Altersgrenzen (
minAge,maxAge) basierend auf Klassenstufen automatisch zu. - Idempotenter Upsert: Speichert Fragen, Optionen, geheime Lösungen und CC-Lizenzen direkt relational in PostgreSQL (
TasksTable). Duplikate werden vermieden.
Projektkonfiguration und Umgebungsvariablen
Die Anwendung wird über folgende Konfigurationsdatei konfiguriert:
src/main/resources/application.yaml
Für eine flexible Konfiguration in lokalen Entwicklungsumgebungen, Docker-Containern oder Deployments können folgende Umgebungsvariablen gesetzt werden:
| Variable | Beschreibung | Standardwert |
|---|---|---|
DB_HOST |
Hostname der PostgreSQL-Datenbank | localhost |
DB_PORT |
Port der PostgreSQL-Datenbank | 5432 |
DB_NAME |
Name der PostgreSQL-Datenbank | kidio_db |
DB_USER |
PostgreSQL-Benutzername | kidio_admin |
DB_PASSWORD |
PostgreSQL-Passwort | learning |
REDIS_HOST |
Hostname der Redis-Instanz | localhost |
REDIS_PORT |
Port der Redis-Instanz | 6379 |
JWT_SECRET |
Geheimer Schlüssel zur Signierung der JWTs | super-geheimes-secret-fuer-dev |
Hinweis: Die angegebenen Standardwerte sind für die lokale Entwicklung gedacht. Für produktive Umgebungen sollten insbesondere
DB_PASSWORDundJWT_SECRETüber sichere Secrets bzw. Umgebungsvariablen gesetzt werden.
Lokale Entwicklung
Voraussetzungen
Für die lokale Entwicklung werden benötigt:
- JDK / Java
- Kotlin bzw. Gradle Wrapper
- PostgreSQL
- Redis
Die konkreten Versionen richten sich nach der im Projekt konfigurierten Gradle- und Kotlin-Version.
Bauen und Ausführen
Das Projekt verwendet den Gradle Wrapper, sodass Gradle nicht global installiert sein muss.
Anwendung starten
./gradlew run
Der Ktor-Server ist anschließend standardmäßig unter folgender Adresse erreichbar:
http://localhost:8080
Projekt bauen
./gradlew build
Tests ausführen
./gradlew test
Code Quality
Für die Einhaltung der Kotlin-Coding-Standards wird KtLint verwendet.
Code automatisch formatieren
./gradlew ktlintFormat
Code Style prüfen
./gradlew ktlintCheck
Der KtLint-Check wird ebenfalls innerhalb der CI-Pipeline ausgeführt.
Empfohlener Workflow vor Commits / Pull Requests
Vor einem Commit oder Pull Request sollte der folgende Workflow ausgeführt werden:
# 1. Kotlin-Code automatisch formatieren
./gradlew ktlintFormat
# 2. Code Style überprüfen
./gradlew ktlintCheck
# 3. Tests ausführen
./gradlew test
# 4. Projekt bauen
./gradlew build
# 5. Server lokal starten
./gradlew run
Der Server ist anschließend unter:
http://localhost:8080
erreichbar.
CI/CD Pipeline
Das Repository verwendet Forgejo Actions für Continuous Integration.
Bei jedem Push oder Pull Request auf den main-Branch wird automatisch ein Workflow ausgeführt.
Die Pipeline führt unter anderem folgende Prüfungen durch:
-
Code Style
./gradlew ktlintCheck -
Automatisierte Tests
./gradlew test
Dadurch wird sichergestellt, dass Änderungen den bestehenden Code-Style einhalten und die automatisierten Tests weiterhin erfolgreich ausgeführt werden können.
Architektur
Das Backend besteht im Wesentlichen aus folgenden Komponenten:
┌───────────────────┐
│ Client │
│ Web / Mobile / │
│ Device │
└─────────┬─────────┘
│
│ HTTP / JSON
▼
┌───────────────────┐
│ Ktor │
│ REST API │
└─────────┬─────────┘
│
┌────────────┴────────────┐
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ Redis │ │ PostgreSQL │
│ Cache │ │ Persistence │
└────────┬────────┘ └────────┬────────┘
│ │
└────────────┬────────────┘
│
▼
┌───────────────────┐
│ Exposed ORM │
└───────────────────┘
Redis-Fallback
Redis wird für schnelle Zugriffe auf häufig benötigte Daten, insbesondere die verbleibende Bildschirmzeit, verwendet.
Sollte Redis nicht erreichbar sein, greift das Backend automatisch auf PostgreSQL zurück.
Dadurch bleibt die Anwendung auch bei einem Ausfall des Caches funktionsfähig.
Bildschirmzeit-Logik
Die Bildschirmzeit wird intern in Sekunden verwaltet.
Beispielsweise:
Start:
1800 Sekunden
= 30 Minuten
Verbrauch:
200 Sekunden
Verbleibend:
1600 Sekunden
= 26 Minuten 40 Sekunden
Sobald die verbleibende Bildschirmzeit auf 0 oder darunter fällt, wird der Benutzer automatisch gesperrt:
{
"remainingSeconds": 0,
"isBlocked": true
}
Durch das Lösen einer Aufgabe kann zusätzliche Bildschirmzeit erworben werden.
Beispiel:
Verbleibend: 0 Sekunden
Aufgaben-Belohnung: 10 Minuten
↓
Neue Bildschirmzeit: 600 Sekunden
Lizenz
Falls für das Projekt eine bestimmte Lizenz verwendet wird, sollte diese hier ergänzt werden, beispielsweise:
MIT License
Eine entsprechende LICENSE-Datei sollte sich im Root-Verzeichnis des Repositorys befinden.
Kidio Ökosystem
Für Kinder (Der spielerische Teil - "Kid"):
-
Kidio Learn: Interaktive Lernspiele (Mathe, Sprachen, Logik), die sich dem Alter und Lernfortschritt des Kindes anpassen.
-
Kidio Create: Tools und Plattformen, um eigene Ideen, Kunstwerke oder kleine Projekte zu entwickeln und zu teilen.
-
Kidio Media: Ein sicherer Bereich mit kindgerechten Videos, Hörspielen und Büchern (ähnlich wie YouTube Kids).
