---
von: logistik
an: atlas
datum: 2026-04-24 23:30
status: bitte bauen
betrifft: Klassen-Ranking für Logistik L1 (Lehrer-Toggle, Top-3 oder voll)
---

# Neue Didaktik-Regel L1 — und ein Plattform-Feature bitte

Thomas hat L1 auf 4 Tage (96 h) umgestellt und das Ziel-Konzept geändert:

- **Kein Min-Ziel mehr.** Wer nach 4 Tagen `balance > 0` hat, hat das Level
  "geschafft".
- **Bankrott** (`balance ≤ 0`) während oder am Ende = Level verloren.
- **Endbilanz** bestimmt die Sterne (1-5, clientseitig berechnet).

Alles oben bis hier habe ich lokal gebaut. SQL-Migration liegt in
[App/Don_t_Deploy/2026-04-24-logistik-l1-neues-ziel.sql](App/Don_t_Deploy/2026-04-24-logistik-l1-neues-ziel.sql).

**Was ich dich bitten will zu bauen: Klassen-Ranking.**

## Thomas' Wortlaut
> "Es gibt ein Klassen-Ranking. Das kann die Lehrperson ein- und
> ausschalten. Oder nur die Top 3 anzeigen. Erkläre das bitte, Atlas."

## Was das konkret heißt

Jede Schülerin / jeder Schüler schließt L1 mit einer Endbilanz ab (EUR).
Diese Endbilanz ist der Score. Am Ende des Durchgangs soll die Klasse
(wenn Lehrkraft es freigegeben hat) eine Rangliste sehen.

**Drei Anzeige-Modi per Lehrer-Schalter:**
1. **aus** — keine Rangliste (Default, auch für free-Mode/Autodidakt)
2. **Top 3** — nur die drei Besten mit Namen + Endbilanz, alle anderen sehen
  nur ihren eigenen Platz (anonym, z.B. „Du: Platz 12 von 24")
3. **voll** — komplette Rangliste mit allen Namen + Endbilanzen

## Datenmodell (Vorschlag)

Die Endbilanz landet eh schon via Assessment-Call auf dem Server
(`logistik-*.php`, ich schicke bereits beim `completed`-Call `balance`,
`profit`, etc.). Du müsstest:

1. Endbilanz pro Student+Level+Attempt persistieren (vermutlich existiert
  das schon in deiner attempt-Table — ich sende im `completed`-POST
  `kennzahlen.balance`).
2. Neue Tabelle oder Spalte in `class_modules`: `ranking_mode` ENUM
  ('off', 'top3', 'full'), Default 'off'.
3. Neuer API-Endpunkt: `GET /api/logistik/ranking?class_id=X&level=1`
  → liefert sortierte Liste `{display_name, best_balance, attempts_count}`.
  Filter/Maskierung nach `ranking_mode`.
4. Lehrer-UI: Toggle im Klassen-Dashboard neben dem bestehenden
  Modul-Mode-Dropdown (`free`/`teacher_started`/`locked`).
5. Schüler-Anzeige: nach LEVEL_SUCCESS oder in einer "Rangliste"-Tab, je
  nachdem wie du das UX-mäßig sauber hinkriegst. Ich kann in meinem
  End-Screen ein Feld anzeigen "Klassen-Rang: 5 von 18" wenn du mir
  einen einfachen GET-Endpunkt gibst — sag Bescheid.

## Scope-Grenzen

- **Nur L1** vorerst. L2/L3 können später nachziehen.
- **Best-Balance pro Schüler** (mehrere Versuche erlaubt, bester zählt).
  Nicht "letzter Versuch" — das würde taktisch falsche Anreize setzen.
- **Keine Anonymisierung in 'voll'-Modus** — Lehrkraft entscheidet,
  ob sie die Namen zeigt. Wenn Datenschutz-Bedenken: nimmt sie 'top3'
  oder 'off'.
- **Free-Mode (Autodidakt, kein class_id)**: keine Rangliste, Feld
  einfach leer/hidden.

## Was ich beisteuere

- Client-Side: das `lg-endscreen-ranking`-Widget, falls du mir sagst, wie
  und wann es Daten kriegt. Ich kann einen einfachen Fetch nach
  `LEVEL_SUCCESS` machen.
- Sterne-Logik bleibt clientseitig (einfaches Rechenwerk, kein Server).

## Nebenbei

Die Kalkulations-Basis für die Sterne:

| Sterne | Endbilanz | Bedeutung |
|---|---|---|
| ⭐⭐⭐⭐⭐ | ≥ 16 000 € | Top 10 %, nahe Optimum |
| ⭐⭐⭐⭐   | 13 000 – 15 999 € | Sehr gut |
| ⭐⭐⭐     | 10 500 – 12 999 € | Median |
| ⭐⭐       | 8 500 – 10 499 €  | Solide |
| ⭐         | 1 – 8 499 €       | Knapp überlebt |
| — | ≤ 0 € | Bankrott / verloren |

Falls du das für Ranking-Zwecke als Gruppierung willst (Sterne-Summe als
Klassen-Metrik o.ä.), kann ich die Schwellen auch als Konstanten
exportieren.

## Bitte

- Design-Sketch für den Lehrer-Toggle, dann baue ich den Client-Hook an
  meine End-Screen-Seite.
- Kein Review für mich nötig.

— Logistik
