Files
Adminator 1e51ef7def Nachtrag: alle bisher untracked Ordner + hängende Änderungen mit-committen
- Konzept/, didaktik_geografie/, didaktik_simulation/, v2-modules/, v2-platform/
- 12 code-workspace-Files
- STATUS-*.md
- viele M/D/R-Änderungen an bereits getrackten Files
- .gitignore verstärkt: **/.humaninput/, **/secret_keys.txt

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-08 02:27:02 +02:00

118 lines
4.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# V2 Plattform-Bibliotheken
Helfer-Libs für V2-Module, sparen Boilerplate. ESM, keine Build-Step,
keine Dependencies.
## Verfügbar
| Lib | Zweck |
|---|---|
| [telemetry-client.js](telemetry-client.js) | Telemetry, Profil, runtime-config, State, Result. Spec-Vollständig. |
## TelemetryClient — Quickstart
```js
import { TelemetryClient } from '../../../v2-platform/lib/telemetry-client.js';
// 1. Instanz
const tc = new TelemetryClient({
moduleSlug: 'hallo-welt',
moduleVersion: '1.0.0',
specVersion: '1.0',
});
// 2. Init (holt runtime-config + profile, startet Heartbeat + Stuck-Detection)
await tc.init();
// 3. Profil + Session sind jetzt verfügbar
console.log(tc.profile); // { displayName, avatarUrl, easyLanguage, nachteilsausgleich, levelUnlocks, ... }
console.log(tc.session); // { mode, difficulty, lang, classId, studentId, isMock, ... }
// 4. Phase wechseln (Lehrperson-Dashboard sieht das live)
tc.setPhase('welcome', 'Begrüßung');
// 5. Milestone emittieren
tc.milestone('welcome-shown', 'Begrüßung gesehen', /* scoreDelta */ 1);
// 6. Score aktualisieren (fließt in nächste Heartbeats)
tc.updateScore(42, 100);
// 7. Resume-State speichern (regelmäßig oder bei Milestones)
await tc.saveState({ ...modulInternerState }, 'Tag 3, Level 2');
// 8. Modul abschließen (sendet Result-POST + cleanup)
await tc.complete({
completed: true,
lehrplanCoverage: { 'AT-GW-1.4.2': 'full' },
freeTextAnswers: [],
moduleSpecificData: { /* modul-eigene Kennzahlen */ },
});
// 9. Bei manuellem Abbruch (z.B. ✕-Klick)
tc.exit('user-cancelled');
```
## Was die Lib für dich erledigt
- **URL-Param-Parsing** — `session_token`, `mode`, `difficulty`, `lang`, `class_id`, `student_id`, `mock=1`
- **Runtime-Config** — Heartbeat-Frequenz wird auf Plattform-Grenzen geclampt (Default 1030s)
- **Heartbeat-Loop** — alle X Sekunden automatisch, pausiert bei AFK (>60s ohne Eingabe)
- **Stuck-Detection** — bei >90s ohne Eingabe wird Stuck-Event gefeuert (Schwellwert aus runtime-config)
- **Tab-Close-Beacon** — navigator.sendBeacon-Final-Heartbeat
- **Fehlertoleranz** — Telemetry-Fetches die scheitern blockieren das Modul nicht (silent fail)
- **Token-Expired-Handling** — bei 401 default Redirect zu `/v2beta/`, im iframe wird nur Warnung geloggt
- **Mock-Erkennung** — wenn `?mock=1`, geht alles automatisch gegen die Mock-Plattform
## Was du selbst tun musst
- **Activity-Tracking** für `click/touchstart/keydown` macht die Lib automatisch (an `document` registriert)
- **A11y-Profil auswerten** — `tc.profile.preferences.highContrast` etc. → Modul setzt `body[data-high-contrast="…"]`
- **Easy-Sprache laden** — `tc.session.lang` zeigt was geladen werden soll
- **Level-Unlock-Sicht** — `tc.profile.levelUnlocks[moduleSlug]` für freien Modus
- **Nachteilsausgleich** — `tc.profile.nachteilsausgleich === true` → Level-Wähler statt Auftrags-Vorgabe
## API-Referenz
### Konstruktor
```js
new TelemetryClient({
moduleSlug: string, // PFLICHT
moduleVersion: string, // PFLICHT
specVersion: string, // PFLICHT
heartbeatPreferenceS?: number, // default 15
onProfileLoaded?: (profile) => void,
onError?: (err) => void,
onTokenExpired?: (reason) => void,
})
```
### Methoden
| Methode | Zweck |
|---|---|
| `init()` | Async. Holt runtime-config + profile, startet Heartbeat + Stuck-Loop. |
| `setPhase(phase, label?, step?)` | Phase wechseln; löst sofort einen Heartbeat aus. |
| `updateScore(score, scoreMax?)` | Score aktualisieren. Wird in nächsten Heartbeats mitgesendet. |
| `milestone(id, label, scoreDelta?)` | Milestone-Event posten (id muss im Manifest deklariert sein). |
| `accessibilityBlocker({blockerType, hint})` | A11y-Blocker melden. |
| `saveState(state, summary?)` | Resume-State speichern (PUT `/api/module/state`). |
| `complete(result)` | Result-POST + Cleanup. Ruft destroy() automatisch. |
| `exit(reason?)` | Abbruch melden + Cleanup. |
| `destroy()` | Manueller Cleanup (Timer + Listener entfernen). |
| `elapsedTotalS()`, `elapsedPhaseS()` | Hilfs-Getter für Sekunden seit Start / Phase-Start. |
### Properties (nach `await init()`)
| Property | Inhalt |
|---|---|
| `tc.profile` | Schüler*innen-Profil (`/api/student/me`-Response inkl. Nachteilsausgleich + Level-Unlocks) |
| `tc.config` | Runtime-Config-Werte (`heartbeat`, `stuck`, `telemetry`, `auth`) |
| `tc.session` | URL-Param-Werte (`sessionToken`, `studentId`, `classId`, `mode`, `difficulty`, `lang`, `resume`, `isMock`) |
## Bekannte Limitierungen
- **Token-Auto-Refresh** ist Stub. Echte Refresh-Logik kommt mit V2-Login. Aktuell: bei Token-Ablauf (401) → Redirect zu `/v2beta/`.
- **`onTokenExpired` Callback** kann das überschreiben, falls Modul eigene Handhabung will (z.B. iframe-Eltern benachrichtigen).
- **Mock-Erkennung** über `?mock=1`-URL-Param. Wenn dein Modul-Wrapper-Pfad nicht `v2-modules/<slug>/public/` ist, musst du `apiBase` selbst überschreiben (nicht in der API vorgesehen — am besten Pfad anpassen).