Compare commits

..

24 commits

Author SHA1 Message Date
DrunkenPinguin b77d7b7fdc Merge pull request 'deleted space to check security' (#12) from feat/fixing-security-patches into main
All checks were successful
CI Pipeline / lint-and-test (push) Successful in 3m9s
Reviewed-on: https://owgit.duckdns.org/DrunkenPinguin/LernApp/pulls/12
2026-09-21 20:20:16 +00:00
Oliver Wallisch a57870f880 style: fix ktlint missing blank line in Models.kt
All checks were successful
CI Pipeline / lint-and-test (push) Successful in 1m29s
CI Pipeline / lint-and-test (pull_request) Successful in 1m31s
2026-09-16 11:27:37 +02:00
Oliver Wallisch 7c21886bfa fix: update ci workflow triggers and disable daemon
Some checks failed
CI Pipeline / lint-and-test (push) Failing after 43s
CI Pipeline / lint-and-test (pull_request) Failing after 42s
2026-09-16 11:25:24 +02:00
Oliver Wallisch 4cc7af16b1 trigger: force ci pipeline run with gradle 8.11
Some checks failed
CI Pipeline / lint-and-test (pull_request) Failing after 42s
2026-09-16 11:20:53 +02:00
Oliver Wallisch 8dfe542acd chore: update wrapper to gradle 8.11 using system gradle
Some checks failed
CI Pipeline / lint-and-test (pull_request) Failing after 41s
2026-09-16 11:18:00 +02:00
Oliver Wallisch a56db8856b fix: restore clean gradle wrapper binary and scripts
Some checks failed
CI Pipeline / lint-and-test (pull_request) Failing after 34s
2026-09-16 11:15:11 +02:00
Oliver Wallisch b6237fcb2f deleted space to check security
Some checks failed
CI Pipeline / lint-and-test (pull_request) Failing after 6s
2026-09-16 11:07:57 +02:00
DrunkenPinguin 2caf2d4734 Merge pull request 'feat/task10 - Verify PIN, Architektur-Refactoring & Sonar Fixes' (#11) from feat/task10 into main
All checks were successful
CI Pipeline / lint-and-test (push) Successful in 2m42s
Reviewed-on: https://owgit.duckdns.org/DrunkenPinguin/LernApp/pulls/11
2026-09-16 08:42:18 +00:00
aldemirm 118677d960 - fixed sonar issues
All checks were successful
CI Pipeline / lint-and-test (pull_request) Successful in 4m3s
- extracted data classes (ZumOerItem, ParsedH5PTask)
- moved hardcoded fallback OER tasks into a dedicated JSON resource file
- removed hardcoded tasks from InMemoryKidioRepository
2026-09-16 10:17:32 +02:00
aldemirm b3a01a4f16 - add verify pin
- restructuring of the backend architecture
2026-09-16 08:21:44 +02:00
DrunkenPinguin c8032cbf62 Merge pull request 'feat/adding-h5p-tasks' (#10) from feat/adding-h5p-tasks into main
All checks were successful
CI Pipeline / lint-and-test (push) Successful in 2m35s
Reviewed-on: https://owgit.duckdns.org/DrunkenPinguin/LernApp/pulls/10
Reviewed-by: mt <aldemir.mt@icloud.com>
2026-09-15 13:00:22 +00:00
DrunkenPinguin 0696ce409f Merge branch 'main' into feat/adding-h5p-tasks
All checks were successful
CI Pipeline / lint-and-test (pull_request) Successful in 2m30s
2026-09-15 10:42:30 +00:00
Oliver Wallisch ce18dfb93e chore: remove build artifacts from git tracking
All checks were successful
CI Pipeline / lint-and-test (pull_request) Successful in 2m32s
2026-09-15 12:39:05 +02:00
Oliver Wallisch b082df962f fix: fixed h5p integration and api call for the age
All checks were successful
CI Pipeline / lint-and-test (pull_request) Successful in 2m38s
2026-09-15 11:38:36 +02:00
Oliver Wallisch 396b34d5ca fixed linting
All checks were successful
CI Pipeline / lint-and-test (pull_request) Successful in 2m43s
2026-09-14 23:33:11 +02:00
Oliver Wallisch bc166cae62 feat: integrated h5p, new endpoints and cli tool to generate new tasks
Some checks failed
CI Pipeline / lint-and-test (pull_request) Failing after 1m19s
2026-09-14 23:29:37 +02:00
Oliver Wallisch 576ed74ad4 feat: adding h5p task integration, updated database schema and data 2026-09-14 22:45:02 +02:00
mt 5f256a03d8 Merge pull request 'feat/gitignore' (#9) from feat/gitignore into main
All checks were successful
CI Pipeline / lint-and-test (push) Successful in 2m13s
Reviewed-on: https://owgit.duckdns.org/DrunkenPinguin/LernApp/pulls/9
Reviewed-by: DrunkenPinguin <wallisch.o@freenet.de>
2026-09-14 10:13:12 +00:00
aldemirm 0eb3ce33d0 - password validation
All checks were successful
CI Pipeline / lint-and-test (pull_request) Successful in 2m12s
- Adding and refactoring tests
2026-09-14 12:10:33 +02:00
aldemirm aabf94941a - password validation
Some checks failed
CI Pipeline / lint-and-test (pull_request) Failing after 1m16s
- Adding and refactoring tests
2026-09-14 11:11:14 +02:00
aldemirm a8f30d7ef2 fix: Merge-Konflikte in Routing und ServerTest gelöst
Some checks failed
CI Pipeline / lint-and-test (pull_request) Failing after 1m14s
2026-09-14 10:46:58 +02:00
DrunkenPinguin 87a820ef03 Merge pull request 'feat: new endpoint for seeing remainnig screentime, test integration' (#8) from feat/add-new-endpoint-for-sreentime into main
All checks were successful
CI Pipeline / lint-and-test (push) Successful in 2m19s
Reviewed-on: https://owgit.duckdns.org/DrunkenPinguin/LernApp/pulls/8
Reviewed-by: mt <aldemir.mt@icloud.com>
2026-09-14 08:15:25 +00:00
aldemirm b71ce98ede - password validation
- Adding and refactoring tests
2026-09-14 09:58:46 +02:00
aldemirm c3fc1e3178 fix: .gitignore angewendet und Build-Dateien entfernt 2026-09-14 09:56:12 +02:00
308 changed files with 8364 additions and 2608 deletions

View file

@ -2,7 +2,7 @@ name: CI Pipeline
on:
push:
branches: [ "main" ]
branches: [ "main", "feat/*" ]
pull_request:
branches: [ "main" ]
@ -12,10 +12,10 @@ jobs:
steps:
- name: Code auschecken
uses: https://github.com/actions/checkout@v4 # <-- Vollständige URL oder github/ Prefix
uses: https://github.com/actions/checkout@v4
- name: Java 21 einrichten
uses: https://github.com/actions/setup-java@v4 # <-- Vollständige URL oder github/ Prefix
uses: https://github.com/actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '21'
@ -24,10 +24,10 @@ jobs:
run: chmod +x gradlew
- name: 1. Code-Style (Linter) prüfen
run: ./gradlew ktlintCheck
run: ./gradlew ktlintCheck --no-daemon
- name: 2. Tests ausführen
run: ./gradlew test
run: ./gradlew test --no-daemon
- name: 3. Backend bauen
run: ./gradlew build -x test --max-workers=2 -Dorg.gradle.jvmargs="-Xmx1024m"
run: ./gradlew build -x test --max-workers=2 --no-daemon -Dorg.gradle.jvmargs="-Xmx1024m"

1
.gitignore vendored
View file

@ -11,3 +11,4 @@ build/
*.iws
*.ipr
out/
build/

Binary file not shown.

View file

@ -1,2 +0,0 @@
#Wed Sep 02 15:03:29 CEST 2026
gradle.version=9.5.1

Binary file not shown.

10
.idea/.gitignore vendored
View file

@ -1,10 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Ignored default folder with query files
/queries/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="21" />
</component>
</project>

View file

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="kidio_db@82.165.11.162" uuid="c8ad70de-d5fc-407a-9165-4f24328fa311">
<driver-ref>postgresql</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
<jdbc-url>jdbc:postgresql://82.165.11.162:5432/kidio_db</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>

View file

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

View file

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="externalSystemId" value="Gradle" />
<option name="version" value="2.4.0" />
</component>
</project>

View file

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" project-jdk-name="homebrew-26" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View file

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

118
README.md
View file

@ -13,8 +13,9 @@ Kinder können durch das Lösen von Lernaufgaben, beispielsweise Mathematikaufga
| 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 und Belohnungen in Minuten. |
| **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. |
@ -98,7 +99,8 @@ Prüft, ob der Backend-Server ordnungsgemäß läuft.
```json
{
"token": "eyJhbGciOiJIUzI1NiIsIn...",
"familyName": "Familie Schmidt"
"userId": "6380776f-88d3-4e9f-a2be-0d9cacae447e",
"message": "Registrierung erfolgreich"
}
```
@ -128,7 +130,9 @@ Prüft, ob der Backend-Server ordnungsgemäß läuft.
```json
{
"token": "eyJhbGciOiJIUzI1NiIsIn...",
"familyName": "Familie Schmidt"
"userId": "6380776f-88d3-4e9f-a2be-0d9cacae447e",
"familyName": "Familie Schmidt",
"childAge": 8
}
```
@ -156,9 +160,9 @@ Authorization: Bearer <Token>
**Beschreibung:**
Liefert die aktuell verbleibende Bildschirmzeit sowie den aktuellen Sperrstatus.
Liefert die aktuell verbleibende Bildschirmzeit sowie den aktuellen Sperrstatus des authentifizierten Benutzers.
**Antwort:**
**Antwort – `200 OK`:**
```json
{
@ -181,29 +185,28 @@ Liefert die aktuell verbleibende Bildschirmzeit sowie den aktuellen Sperrstatus.
**Beschreibung:**
Zieht die seit dem letzten Abgleich verbrauchten Sekunden von der verfügbaren Bildschirmzeit ab.
Zieht die seit dem letzten Abgleich vom Endgerät verbrauchten Sekunden von der verfügbaren Bildschirmzeit ab.
**Request-Body:**
```json
{
"userId": "default_user",
"usedSecondsSinceLastSync": 200
"usedSecondsSinceLastSync": 30
}
```
**Antwort:**
**Antwort – `200 OK`:**
```json
{
"remainingSeconds": 1600,
"remainingSeconds": 1770,
"isBlocked": false
}
```
---
#### 6. Alle verfügbaren Aufgaben abrufen
#### 6. Lernaufgaben abrufen (mit Fach- & Altersfilter)
**Methode:** `GET`
@ -213,24 +216,42 @@ Zieht die seit dem letzten Abgleich verbrauchten Sekunden von der verfügbaren B
/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:**
```text
GET /api/v1/tasks?subject=Mathematik&age=8&limit=5
```
**Beschreibung:**
Liefert eine Liste aller verfügbaren Lernaufgaben.
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:**
**Antwort – `200 OK`:**
```json
[
{
"id": "t1",
"question": "Was ist 12 + 15?",
"id": "zum-math-001",
"subject": "Mathematik",
"minAge": 8,
"maxAge": 9,
"question": "Was ist das Ergebnis von 6 × 8?",
"options": [
"25",
"27",
"30",
"22"
"42",
"48",
"54",
"56"
],
"rewardMinutes": 10
"rewardMinutes": 5,
"license": "CC BY-SA 4.0"
}
]
```
@ -251,22 +272,22 @@ Liefert eine Liste aller verfügbaren Lernaufgaben.
```json
{
"taskId": "t1",
"selectedAnswer": "27"
"taskId": "zum-math-001",
"selectedAnswer": "48"
}
```
**Antwort – korrekte Lösung:**
**Antwort – korrekte Lösung (`200 OK`):**
```json
{
"isCorrect": true,
"earnedMinutes": 10,
"message": "Super gemacht! Du hast 10 Minuten gewonnen."
"earnedMinutes": 5,
"message": "Super gemacht! Du hast 5 Minuten gewonnen."
}
```
**Antwort – falsche Lösung:**
**Antwort – falsche Lösung (`200 OK`):**
```json
{
@ -278,6 +299,38 @@ Liefert eine Liste aller verfügbaren Lernaufgaben.
---
## 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
```bash
# 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
1. **Live-Crawler & Discovery:** Durchsucht `apps.zum.de` nach interaktiven Inhalten (`H5P.MultiChoice`, `H5P.TrueFalse`, `H5P.QuestionSet`).
2. **Textbereinigung:** Entfernt störende HTML-Tags (`<p>`, `<strong>`, `&nbsp;`) für native mobile Darstellung.
3. **Taxonomie- & Alters-Mapping:** Weist Altersgrenzen (`minAge`, `maxAge`) basierend auf Klassenstufen automatisch zu.
4. **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:
@ -517,3 +570,16 @@ 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).
![img.png](img.png)

View file

@ -11,6 +11,12 @@ version = "1.0.0-SNAPSHOT"
application {
mainClass = "io.ktor.server.netty.EngineMain"
}
ktor {
openApi {
enabled = true // Aktiviert die OpenAPI-Code-Generierung
codeInferenceEnabled = true
}
}
kotlin {
jvmToolchain(21)
@ -20,7 +26,7 @@ dependencies {
implementation(ktorLibs.server.config.yaml)
implementation(ktorLibs.server.core)
implementation(ktorLibs.server.netty)
implementation("io.ktor:ktor-server-openapi")
// JWT Authentication
implementation("io.ktor:ktor-server-auth")
implementation("io.ktor:ktor-server-auth-jwt")
@ -46,3 +52,11 @@ dependencies {
// redis
implementation("redis.clients:jedis:5.1.2")
}
tasks.register<JavaExec>("runIngestion") {
group = "application"
description = "Runs the standalone H5P/ZUM task ingestion CLI tool"
mainClass.set("com.oliver.kidio.backend.ingestion.H5PIngestionCli")
classpath = sourceSets["main"].runtimeClasspath
standardInput = System.`in`
}

Some files were not shown because too many files have changed in this diff Show more