Lauschfreunde — Dokumentation
Technische Referenz zum kooperativen Hör-Abenteuerspiel: Architektur, Spielablauf, QR-System, Sprachsynthese-Pipeline, PDF-Generierung und API.
Architektur-Übersicht
Lauschfreunde ist eine React-Single-Page-Application, die das Spiel und den Admin-Bereich in einem gemeinsamen Bundle ausliefert. Sie kommuniziert über eine REST-Schnittstelle mit dem Nexus-Backend — einer Node.js-Anwendung auf Basis von Express, mit eingebetteter SQLite-Datenbank und JWT-basierter Authentifizierung. Als Progressive Web App läuft das Frontend nach dem ersten Laden auch ohne Internetverbindung.
/admin). Frontend und Backend sind klar entkoppelt — das Frontend lässt sich dadurch unabhängig ausliefern.Frontend-Stack
| Komponente | Technologie | Version |
|---|---|---|
| Framework | React | 19.x |
| Build-Tool | Vite | 8.x |
| CSS | TailwindCSS | 4.x |
| Routing | React Router | 7.x |
| QR-Scanner | html5-qrcode + jsQR (Fallback) | 2.x / 1.x |
| Audio-Player | Howler.js | 2.x |
| PWA / Offline | vite-plugin-pwa (Workbox) | 1.x |
| PDF-Generierung | jsPDF + qrcode | 4.x / 1.x |
| Bild-Analyse | node-vibrant (Farbpaletten) | 3.x |
Backend-Stack (Nexus)
Das Nexus-Backend ist eine schlanke Node.js-Anwendung auf einem einzelnen Server — ohne externe Datenbank-Abhängigkeit.
| Komponente | Technologie | Version |
|---|---|---|
| Sprache & Runtime | JavaScript / Node.js | ≥ 18 |
| Web-Framework | Express | 4.21 |
| Echtzeit-Kommunikation | Socket.io (WebSocket) | 4.7 |
| Datenbank | SQLite via better-sqlite3 (eingebettet) | 11.x |
| Authentifizierung | jsonwebtoken (JWT, 30 Tage gültig) | — |
| Datei-Uploads | multer (multipart/form-data) | — |
| Schutz | express-rate-limit · cors | — |
| Sprachsynthese | ElevenLabs API (eleven_multilingual_v2) | v1 |
| Process-Manager | PM2 | — |
| Reverse Proxy | nginx (leitet /api/nexus/ und /socket.io/ an Port 3001) | — |
Dateistruktur
Das Frontend ist nach Feature-Bereichen gegliedert: getrennte Verzeichnisse für pages/game/ und pages/admin/, eigene Hooks bündeln die Spiel-Logik, und lib/ kapselt die API-Aufrufe und externen Anbindungen.
Spielablauf
Ein typisches Abenteuer durchläuft die folgenden Phasen:
Zustands-Übersicht
Der Spielzustand wird über Custom Hooks (vor allem useGameState) verwaltet. Die wichtigsten Zustände im Spielverlauf:
| Zustand | Beschreibung |
|---|---|
| idle | Startseite, noch kein Spiel aktiv |
| selecting | Box oder Abenteuer wird ausgewählt |
| scanning | QR-Scanner ist aktiv und wartet auf eine Karte |
| listening | Audio-Schnipsel wird abgespielt |
| assigning | Karte wird einem Lauschfreund zugeordnet |
| sorting | Karten werden in die richtige Reihenfolge gebracht (nur fortgeschrittene Stufe) |
| solving | Holzfiguren werden auf die Lösungstafel gestellt |
| complete | Abenteuer erfolgreich abgeschlossen |
QR-System
Payload-Format
Jeder QR-Code enthält einen kompakten Identifikator nach folgendem Schema:
lauschfreunde:<box-slug>:<adventure-slug>:<card-slug>
Der Server liefert über GET /cards/resolve?qr=... die zugehörige Karte samt Audio-URL und Charakter-Zuordnung zurück.
lauschfreunde: dient als Marker. Codes ohne dieses Präfix werden vom Scanner ignoriert.Zwei Scanner parallel
Die App nutzt zwei Scanner-Bibliotheken nebeneinander, um auf möglichst vielen Geräten zuverlässig zu funktionieren:
| Scanner | Stärke | Rolle |
|---|---|---|
| html5-qrcode | Nutzt direkt die Kamera-API des Browsers, schnell | Primär |
| jsQR | Canvas-basiert, größere Kompatibilität auf älteren Geräten | Fallback |
TTS-Pipeline
Übersicht
Audio lässt sich direkt aus dem Admin-Editor per ElevenLabs erzeugen. Das Ergebnis wird als MP3 im Storage abgelegt und über eine URL mit der jeweiligen Karte oder dem Abenteuer verknüpft. Für produktive Aufnahmen können alternativ fertige MP3-Dateien hochgeladen werden.
Stimmen-Konfiguration
Jeder Charakter bekommt eine eigene Stimme. Die jeweilige Voice-ID wird pro Charakter in der Datenbank hinterlegt und beim Generieren mitgeschickt.
| Parameter | Wert | Beschreibung |
|---|---|---|
| model_id | eleven_multilingual_v2 | Mehrsprachiges Modell mit guter deutscher Aussprache |
| stability | 0.5 | Natürliche Variation |
| similarity_boost | 0.75 | Stimmkonsistenz |
| output_format | mp3_44100_128 | Hohe Qualität für Kinder-Audio |
PDF-Generierung (optional — nur für selbst angelegte Editor-Inhalte)
Spielkarten
Für Welten, die im Editor selbst angelegt wurden, erzeugt das Admin-Panel druckfertige A4-PDFs mit den Karten, QR-Codes und Schnittmarken. Bei einem Verlagsprodukt entfällt das — die Box wird mit fertig produziertem Material ausgeliefert.
Urkunden
Nach Abschluss eines Abenteuers können die Kinder eine Urkunde als PDF herunterladen. Sie nennt das gelöste Abenteuer, das Datum und trägt ein Siegel mit Lauschfreunde-Branding.
API Endpoints
Übersicht
Die Nexus REST-API ist in zwei Bereiche aufgeteilt: öffentliche Game-Endpoints (kein Auth) und Admin-Endpoints (Bearer Token). Alle Antworten kommen im Envelope { data: ... }; Fehler als { error: "..." }.
| Bereich | Präfix | Auth |
|---|---|---|
| Game | /boxes · /cards/resolve · /crossover-bonus | Keine |
| Auth | /auth/login | Login |
| Admin Content | /admin/boxes · /admin/characters · /admin/adventures · /admin/cards | Bearer |
| Uploads | /admin/upload/audio · /admin/upload/image · /admin/upload/pdf | Bearer |
| TTS | /admin/tts/* | Bearer |
Basis-URL in Produktion: https://cddevapps.com/api/nexus/lauschfreunde
Authentifizierung
Admin-Login über E-Mail + Passwort. Antwort enthält den Bearer Token, der im Frontend in localStorage liegt und bei jedem Admin-Request mitgeschickt wird.
POST /auth/login
Content-Type: application/json
{
"email": "admin@example.com",
"password": "***"
}
Response: { "data": { "token": "eyJhbG...", "user": { ... } } }
/admin/*-Endpoints erfordern Authorization: Bearer <token>. Die App speichert den Token unter dem Key lf_admin_token.Spiel-Routen (öffentlich)
| Methode | Pfad | Beschreibung |
|---|---|---|
| GET | /boxes | Alle verfügbaren Boxen auflisten |
| GET | /boxes/:slug | Vollständige Box-Daten inkl. Charakteren, Abenteuern und Karten |
| GET | /cards/resolve?qr=... | QR-Code auflösen und die zugehörige Karte samt Audio-URL zurückgeben |
| GET | /crossover-bonus | Crossover-Bonus zwischen zwei Boxen abfragen |
Admin: Inhalte verwalten (Bearer Token)
| Methode | Pfad | Beschreibung |
|---|---|---|
| POST | /admin/boxes | Box anlegen |
| PUT | /admin/boxes/:id | Box bearbeiten |
| DELETE | /admin/boxes/:id | Box löschen |
| POST | /admin/boxes/:id/characters | Charakter zu einer Box hinzufügen |
| PUT | /admin/characters/:id | Charakter bearbeiten (inkl. Voice-ID) |
| DELETE | /admin/characters/:id | Charakter löschen |
| POST | /admin/boxes/:id/adventures | Abenteuer zu einer Box hinzufügen |
| PUT | /admin/adventures/:id | Abenteuer bearbeiten (inkl. asset_pdf_url) |
| POST | /admin/adventures/:advId/cards | Karte zu einem Abenteuer hinzufügen |
| PUT | /admin/cards/:id | Karte bearbeiten |
| PUT | /admin/adventures/:id/solution-placements | Felder der Lösungstafel konfigurieren |
| PUT | /admin/adventures/:id/special-sounds | Spezial-Sounds (Sticker-Trigger) konfigurieren |
Admin: Uploads und Sprachsynthese (Bearer Token)
| Methode | Pfad | Beschreibung |
|---|---|---|
| POST | /admin/upload/audio | MP3-Datei hochladen (max. 10 MB) |
| POST | /admin/upload/image | PNG- oder JPG-Bild hochladen |
| POST | /admin/upload/pdf | PDF-Datei hochladen, etwa für Spielmaterial (max. 10 MB) |
| POST | /admin/tts/preview | Vorschau einer Sprachausgabe erzeugen, ohne sie zu speichern |
| POST | /admin/tts/generate-and-save | Sprachausgabe erzeugen, speichern und der Karte zuweisen |
| POST | /admin/tts/sound-effect | Sound-Effekt per ElevenLabs erzeugen |
| GET | /admin/tts/usage | Aktuelles ElevenLabs-Kontingent und Verbrauch abfragen |
multipart/form-data mit den Feldern file und path. Der Browser setzt dabei die Boundary selbst — der Client darf keinen Content-Type explizit setzen.