Errungenschaften: Abzeichen für erreichte Meilensteine #15

Closed
opened 2026-09-02 09:18:44 +00:00 by florian.wilde · 3 comments
Owner

Worum es geht

Flimmer weiß eine Menge über das eigene Schauverhalten, sagt aber nichts dazu. Wer alle Spider-Man-Filme durch hat, bekommt keine Anerkennung — dabei ist genau das der Moment, in dem man kurz grinst und es jemandem erzählt.

Errungenschaften sollen still belohnen, nicht antreiben. Keine Serien-Streaks, die einen bestrafen, wenn man mal eine Woche nichts schaut. Keine Fortschrittsbalken, die drängeln. Ein Abzeichen taucht auf, wenn etwas erreicht ist — und bleibt dann.

Warum das Fundament schon steht

Alles Nötige liegt im Datenmodell, es wird nur nirgends ausgewertet:

Bedingung Woraus
Reihen (Spider-Man, Herr der Ringe …) Title.tmdbCollectionId — TMDB gruppiert Filmreihen selbst
Eigene Universen getUniverse().progress gibt es schon
Schauzeit, Episoden, Filme getTotals()
Genres, Jahrzehnte Title.genres, Title.releaseDate
Durchläufe LibraryEntry.currentRun
Uhrzeit einer Sichtung Watch.watchedAt
Sammlung LibraryEntry.owned
Bewertungen LibraryEntry.rating

Für „alle Spider-Man gesehen" braucht es also keine gepflegte Liste — TMDB liefert die Zugehörigkeit mit, und Flimmer speichert sie beim Import bereits.

Vorschlag für den Katalog

Symbole als handgezeichnete SVG im Signaturverlauf, wie das Logo — kein Emoji-Zoo, der auf jedem System anders aussieht. Die Emojis unten stehen nur als Platzhalter für die Bildidee.

Anfänge

Name Bedingung
🌱 Erstkontakt Der erste Titel landet in der Bibliothek
✅ Abgehakt Die erste Serie vollständig durchgeschaut
🔑 Schlüsselmeister Ersten Passkey angelegt
🏠 Heimkehrer Ersten Abgleich mit dem Medienserver gemacht

Reihen und Universen — hier sitzt die Spider-Man-Idee

Name Bedingung
🎬 Reihe komplett Alle Filme einer TMDB-Reihe gesehen. Dynamisch benannt: „Reihe komplett — Sternenpfad"
🪐 Universum vollendet Alle Einträge eines eigenen Universums abgeschlossen
🧭 Chronologe Ein Universum in einer selbst gebauten Reihenfolge durchlaufen, nicht in der Erscheinungsreihenfolge

Ausdauer

Name Bedingung
📺 Serientäter 1 000 Episoden
🎞️ Vielseher 100 Filme
☀️ Ein ganzer Tag 24 Stunden Schauzeit insgesamt
🗓️ Eine ganze Woche 168 Stunden
🏃 Marathon 8 Stunden an einem Kalendertag
🧗 Der lange Atem Eine Serie mit mindestens 100 Episoden komplett
💛 Treu geblieben Erste und letzte Sichtung derselben Serie liegen über ein Jahr auseinander
🔁 Wiederholungstäter Ein Titel im dritten Durchlauf

Breite

Name Bedingung
🎭 Feinschmecker Titel aus zehn verschiedenen Genres gesehen
⏳ Zeitreisender Je ein Film aus sieben Jahrzehnten
⭐ Kritiker 50 Bewertungen abgegeben
🧂 Strenges Urteil Einmal eine 1 vergeben

Ordnung

Name Bedingung
📀 Sammler 25 Titel mit „hab ich"
🧹 Aufgeräumt Die Watchlist von mindestens 20 Einträgen auf null gebracht
🌙 Durchgemacht Eine Sichtung zwischen 3 und 5 Uhr — in der Zeitzone des Nutzers, nicht des Servers

Zu entscheiden: generisch oder mit Eigennamen?

Dein Beispiel „Spider Bro" ist der Kern der Frage. Zwei Wege:

a) Generisch, dynamisch benannt (Empfehlung als Basis). „Reihe komplett — Spider-Man". Funktioniert für jede Reihe, auch für die, an die niemand gedacht hat, und braucht keine Pflege.

b) Kuratierte Namen obendrauf. Eine Datendatei, die TMDB-Reihen-Kennungen auf Namen und Symbole abbildet: { "556": { "name": "Spider Bro", "symbol": "spinne" } }. Charmanter, aber Geschmackssache, nur für bekannte Reihen sinnvoll, und jemand muss sie pflegen.

Vorschlag: beides — (a) als Grundlage, (b) als kleine JSON-Datei, die ohne Codeänderung wachsen kann. Fehlt ein Eintrag, greift der generische Name. Dann ist „Spider Bro" drin, ohne dass alles andere davon abhängt.

Umzusetzen

Datenmodell

model Achievement {
  id     String @id @default(cuid())
  userId String
  user   User   @relation(fields: [userId], references: [id], onDelete: Cascade)

  /// Stabiler Schlüssel: "serientaeter-1000", "reihe:556", "universum:<id>"
  key String
  /// Bei dynamisch benannten der Name zum Zeitpunkt des Erreichens —
  /// eingefroren, damit ein umbenanntes Universum das Abzeichen nicht ändert.
  label String?

  unlockedAt DateTime @default(now())

  @@unique([userId, key])
}

Dazu User.showAchievements für die öffentliche Profilseite.

Auswertung

  • Ein Modul src/lib/achievements.ts mit einem Katalog aus Regeln; jede Regel bekommt einen vorbereiteten Datensatz und gibt zurück, welche Schlüssel erreicht sind
  • Ausgelöst nach Sichtungsaktionen (nur die billigen Regeln) und einmal täglich vollständig im vorhandenen Abgleich
  • Einmal erreicht, bleibt erreicht. Wer eine Sichtung zurücknimmt, verliert das Abzeichen nicht — Abzeichen wieder einzukassieren wäre kleinlich und lädt zu Ärger ein

Oberfläche

  • Eigene Seite oder Abschnitt in der Statistik: erreichte Abzeichen mit Datum, darunter die noch offenen mit ihrer Bedingung
  • Eine dezente Einblendung beim Erreichen, kein Konfetti
  • Optional auf der öffentlichen Profilseite

Zwei Fallstricke

Der erste Lauf entriegelt alles auf einmal. Bestehende Konten haben Jahre an Daten — die erste Auswertung würde zwei Dutzend Abzeichen gleichzeitig vergeben und ebenso viele Benachrichtigungen verschicken. Der erste Durchlauf je Konto muss deshalb stumm sein; erst danach wird gemeldet.

Zeitzonen. „Zwischen 3 und 5 Uhr" und „an einem Kalendertag" müssen in der Zeitzone des Nutzers gerechnet werden, nicht in der des Servers. Bei den Monatsstatistiken hat genau das schon einmal für einen leeren Chart gesorgt.

Abnahme

  • Abzeichen werden vergeben, sobald die Bedingung erfüllt ist, und tauchen in der Übersicht mit Datum auf
  • „Reihe komplett" funktioniert über die TMDB-Reihe und trägt deren Namen; ein kuratierter Name überschreibt ihn, falls hinterlegt
  • Ein zweiter Auswertungslauf vergibt nichts doppelt
  • Eine zurückgenommene Sichtung nimmt kein Abzeichen weg
  • Der erste Lauf eines Kontos verschickt keine Benachrichtigungen
  • Uhrzeit- und Tagesbedingungen rechnen in der Zeitzone des Nutzers (Test)
  • Abzeichen sind auf dem öffentlichen Profil abschaltbar
  • Symbole erfüllen WCAG AA und tragen einen Namen — nicht nur Farbe

Aufwand

Mittel. Das Datenmodell ist winzig, der Aufwand steckt im Regelkatalog und darin, ihn billig auswertbar zu halten: die meisten Bedingungen lassen sich aus wenigen Aggregaten beantworten, wenn man sie einmal gemeinsam holt statt je Regel einzeln zu fragen.

Sinnvoll wäre, mit einer kleinen Auswahl anzufangen — Anfänge, Reihen, Ausdauer — und den Rest nachzuziehen, wenn sich zeigt, was Spaß macht.


Angelegt auf ausdrücklichen Wunsch direkt in Gitea, ohne Verknüpfung zu einem Nebula-Task.

## Worum es geht Flimmer weiß eine Menge über das eigene Schauverhalten, sagt aber nichts dazu. Wer alle Spider-Man-Filme durch hat, bekommt keine Anerkennung — dabei ist genau das der Moment, in dem man kurz grinst und es jemandem erzählt. Errungenschaften sollen **still belohnen, nicht antreiben**. Keine Serien-Streaks, die einen bestrafen, wenn man mal eine Woche nichts schaut. Keine Fortschrittsbalken, die drängeln. Ein Abzeichen taucht auf, wenn etwas erreicht ist — und bleibt dann. ## Warum das Fundament schon steht Alles Nötige liegt im Datenmodell, es wird nur nirgends ausgewertet: | Bedingung | Woraus | |---|---| | Reihen (Spider-Man, Herr der Ringe …) | `Title.tmdbCollectionId` — TMDB gruppiert Filmreihen selbst | | Eigene Universen | `getUniverse().progress` gibt es schon | | Schauzeit, Episoden, Filme | `getTotals()` | | Genres, Jahrzehnte | `Title.genres`, `Title.releaseDate` | | Durchläufe | `LibraryEntry.currentRun` | | Uhrzeit einer Sichtung | `Watch.watchedAt` | | Sammlung | `LibraryEntry.owned` | | Bewertungen | `LibraryEntry.rating` | Für „alle Spider-Man gesehen" braucht es also **keine gepflegte Liste** — TMDB liefert die Zugehörigkeit mit, und Flimmer speichert sie beim Import bereits. ## Vorschlag für den Katalog Symbole als handgezeichnete SVG im Signaturverlauf, wie das Logo — kein Emoji-Zoo, der auf jedem System anders aussieht. Die Emojis unten stehen nur als Platzhalter für die Bildidee. ### Anfänge | | Name | Bedingung | |---|---|---| | 🌱 | **Erstkontakt** | Der erste Titel landet in der Bibliothek | | ✅ | **Abgehakt** | Die erste Serie vollständig durchgeschaut | | 🔑 | **Schlüsselmeister** | Ersten Passkey angelegt | | 🏠 | **Heimkehrer** | Ersten Abgleich mit dem Medienserver gemacht | ### Reihen und Universen — hier sitzt die Spider-Man-Idee | | Name | Bedingung | |---|---|---| | 🎬 | **Reihe komplett** | Alle Filme einer TMDB-Reihe gesehen. **Dynamisch benannt:** „Reihe komplett — Sternenpfad" | | 🪐 | **Universum vollendet** | Alle Einträge eines eigenen Universums abgeschlossen | | 🧭 | **Chronologe** | Ein Universum in einer **selbst gebauten** Reihenfolge durchlaufen, nicht in der Erscheinungsreihenfolge | ### Ausdauer | | Name | Bedingung | |---|---|---| | 📺 | **Serientäter** | 1 000 Episoden | | 🎞️ | **Vielseher** | 100 Filme | | ☀️ | **Ein ganzer Tag** | 24 Stunden Schauzeit insgesamt | | 🗓️ | **Eine ganze Woche** | 168 Stunden | | 🏃 | **Marathon** | 8 Stunden an einem Kalendertag | | 🧗 | **Der lange Atem** | Eine Serie mit mindestens 100 Episoden komplett | | 💛 | **Treu geblieben** | Erste und letzte Sichtung derselben Serie liegen über ein Jahr auseinander | | 🔁 | **Wiederholungstäter** | Ein Titel im dritten Durchlauf | ### Breite | | Name | Bedingung | |---|---|---| | 🎭 | **Feinschmecker** | Titel aus zehn verschiedenen Genres gesehen | | ⏳ | **Zeitreisender** | Je ein Film aus sieben Jahrzehnten | | ⭐ | **Kritiker** | 50 Bewertungen abgegeben | | 🧂 | **Strenges Urteil** | Einmal eine 1 vergeben | ### Ordnung | | Name | Bedingung | |---|---|---| | 📀 | **Sammler** | 25 Titel mit „hab ich" | | 🧹 | **Aufgeräumt** | Die Watchlist von mindestens 20 Einträgen auf null gebracht | | 🌙 | **Durchgemacht** | Eine Sichtung zwischen 3 und 5 Uhr — in der Zeitzone des Nutzers, nicht des Servers | ## Zu entscheiden: generisch oder mit Eigennamen? Dein Beispiel „**Spider Bro**" ist der Kern der Frage. Zwei Wege: **a) Generisch, dynamisch benannt (Empfehlung als Basis).** „Reihe komplett — Spider-Man". Funktioniert für **jede** Reihe, auch für die, an die niemand gedacht hat, und braucht keine Pflege. **b) Kuratierte Namen obendrauf.** Eine Datendatei, die TMDB-Reihen-Kennungen auf Namen und Symbole abbildet: `{ "556": { "name": "Spider Bro", "symbol": "spinne" } }`. Charmanter, aber Geschmackssache, nur für bekannte Reihen sinnvoll, und jemand muss sie pflegen. Vorschlag: **beides** — (a) als Grundlage, (b) als kleine JSON-Datei, die ohne Codeänderung wachsen kann. Fehlt ein Eintrag, greift der generische Name. Dann ist „Spider Bro" drin, ohne dass alles andere davon abhängt. ## Umzusetzen **Datenmodell** ```prisma model Achievement { id String @id @default(cuid()) userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) /// Stabiler Schlüssel: "serientaeter-1000", "reihe:556", "universum:<id>" key String /// Bei dynamisch benannten der Name zum Zeitpunkt des Erreichens — /// eingefroren, damit ein umbenanntes Universum das Abzeichen nicht ändert. label String? unlockedAt DateTime @default(now()) @@unique([userId, key]) } ``` Dazu `User.showAchievements` für die öffentliche Profilseite. **Auswertung** - Ein Modul `src/lib/achievements.ts` mit einem Katalog aus Regeln; jede Regel bekommt einen vorbereiteten Datensatz und gibt zurück, welche Schlüssel erreicht sind - Ausgelöst **nach Sichtungsaktionen** (nur die billigen Regeln) und **einmal täglich vollständig** im vorhandenen Abgleich - **Einmal erreicht, bleibt erreicht.** Wer eine Sichtung zurücknimmt, verliert das Abzeichen nicht — Abzeichen wieder einzukassieren wäre kleinlich und lädt zu Ärger ein **Oberfläche** - Eigene Seite oder Abschnitt in der Statistik: erreichte Abzeichen mit Datum, darunter die noch offenen mit ihrer Bedingung - Eine dezente Einblendung beim Erreichen, kein Konfetti - Optional auf der öffentlichen Profilseite ## Zwei Fallstricke **Der erste Lauf entriegelt alles auf einmal.** Bestehende Konten haben Jahre an Daten — die erste Auswertung würde zwei Dutzend Abzeichen gleichzeitig vergeben und ebenso viele Benachrichtigungen verschicken. Der erste Durchlauf je Konto muss deshalb **stumm** sein; erst danach wird gemeldet. **Zeitzonen.** „Zwischen 3 und 5 Uhr" und „an einem Kalendertag" müssen in der Zeitzone des Nutzers gerechnet werden, nicht in der des Servers. Bei den Monatsstatistiken hat genau das schon einmal für einen leeren Chart gesorgt. ## Abnahme - [ ] Abzeichen werden vergeben, sobald die Bedingung erfüllt ist, und tauchen in der Übersicht mit Datum auf - [ ] „Reihe komplett" funktioniert über die TMDB-Reihe und trägt deren Namen; ein kuratierter Name überschreibt ihn, falls hinterlegt - [ ] Ein zweiter Auswertungslauf vergibt nichts doppelt - [ ] Eine zurückgenommene Sichtung nimmt kein Abzeichen weg - [ ] Der erste Lauf eines Kontos verschickt keine Benachrichtigungen - [ ] Uhrzeit- und Tagesbedingungen rechnen in der Zeitzone des Nutzers (Test) - [ ] Abzeichen sind auf dem öffentlichen Profil abschaltbar - [ ] Symbole erfüllen WCAG AA und tragen einen Namen — nicht nur Farbe ## Aufwand Mittel. Das Datenmodell ist winzig, der Aufwand steckt im Regelkatalog und darin, ihn billig auswertbar zu halten: die meisten Bedingungen lassen sich aus wenigen Aggregaten beantworten, wenn man sie einmal gemeinsam holt statt je Regel einzeln zu fragen. Sinnvoll wäre, mit einer kleinen Auswahl anzufangen — Anfänge, Reihen, Ausdauer — und den Rest nachzuziehen, wenn sich zeigt, was Spaß macht. --- *Angelegt auf ausdrücklichen Wunsch direkt in Gitea, ohne Verknüpfung zu einem Nebula-Task.*
florian.wilde added the in-arbeit label 2026-09-02 09:47:32 +00:00
florian.wilde started working 2026-09-02 09:47:37 +00:00
Author
Owner

🤖 Claude Code hat mit der Umsetzung begonnen.

  • Branch: feat/15-errungenschaften
  • Verstanden als: Abzeichen, die still auftauchen, wenn etwas erreicht ist, und dann bleiben — ohne Streaks, ohne Drängeln.
  • Geplantes Vorgehen:
    • Modell Achievement (Schlüssel, eingefrorener Name, Datum) samt User.showAchievements
    • src/lib/achievements.ts: ein gemeinsam geholter Datensatz, darauf der Regelkatalog — sonst fragt jede Regel einzeln die Datenbank
    • Auswertung nach Sichtungsaktionen und einmal täglich; erster Lauf je Konto stumm
    • Abzeichen in der Statistik, abschaltbar auf dem öffentlichen Profil; Symbole als eigene SVG
    • Tests: Entdopplung, Stummschaltung beim ersten Lauf, Zeitzonen, „einmal erreicht bleibt erreicht"

Zur offenen Frage im Issue (generische oder kuratierte Namen): Ich setze meinen Vorschlag um — generisch als Grundlage, dazu eine kleine Datendatei für Eigennamen wie „Spider Bro". Fehlt dort ein Eintrag, greift der generische Name. Sag Bescheid, wenn du das anders willst.

Den Katalog baue ich vollständig, nicht in Etappen: die Regeln sind Einzeiler, sobald der gemeinsame Datensatz steht — der Aufwand steckt in diesem, nicht in der Anzahl.

Zeiterfassung läuft.

🤖 **Claude Code hat mit der Umsetzung begonnen.** - Branch: `feat/15-errungenschaften` - Verstanden als: Abzeichen, die still auftauchen, wenn etwas erreicht ist, und dann bleiben — ohne Streaks, ohne Drängeln. - Geplantes Vorgehen: - Modell `Achievement` (Schlüssel, eingefrorener Name, Datum) samt `User.showAchievements` - `src/lib/achievements.ts`: **ein** gemeinsam geholter Datensatz, darauf der Regelkatalog — sonst fragt jede Regel einzeln die Datenbank - Auswertung nach Sichtungsaktionen und einmal täglich; erster Lauf je Konto stumm - Abzeichen in der Statistik, abschaltbar auf dem öffentlichen Profil; Symbole als eigene SVG - Tests: Entdopplung, Stummschaltung beim ersten Lauf, Zeitzonen, „einmal erreicht bleibt erreicht" **Zur offenen Frage im Issue** (generische oder kuratierte Namen): Ich setze meinen Vorschlag um — generisch als Grundlage, dazu eine kleine Datendatei für Eigennamen wie „Spider Bro". Fehlt dort ein Eintrag, greift der generische Name. Sag Bescheid, wenn du das anders willst. Den Katalog baue ich vollständig, nicht in Etappen: die Regeln sind Einzeiler, sobald der gemeinsame Datensatz steht — der Aufwand steckt in diesem, nicht in der Anzahl. Zeiterfassung läuft.
florian.wilde worked for 3 minutes 2026-09-02 09:51:06 +00:00
florian.wilde started working 2026-09-02 09:51:45 +00:00
florian.wilde worked for 18 minutes 2026-09-02 10:09:58 +00:00
florian.wilde added zu-testen and removed in-arbeit labels 2026-09-02 10:10:44 +00:00
Author
Owner

✅ Umsetzung abgeschlossen — bereit zum Testen.

Was geändert wurde

  • Modell Achievement samt Migration, dazu User.showAchievements
  • src/lib/achievements.ts: ein gemeinsam geholter Datensatz, darauf 20 feste Regeln plus dynamische für Filmreihen und Universen
  • src/lib/achievement-names.ts: kuratierte Eigennamen wie „Spider Bro", abgesichert gegen falsche Kennungen
  • Auswertung nach Sichtungsaktionen und einmal täglich; erster Lauf je Konto stumm, angestoßen beim ersten Öffnen der Übersicht
  • Abschnitt in der Statistik, Abzeichen auf dem öffentlichen Profil (abschaltbar), eigene SVG-Symbole
  • Einblendung in eigenem Ton beim Erreichen
  • docs/ANLEITUNG.md mit eigenem Abschnitt und Screenshot

Geänderte Dateien

  • prisma/schema.prisma, prisma/migrations/20260902094830_errungenschaften/
  • src/lib/achievements.ts, src/lib/achievement-names.ts, src/lib/sync.ts
  • src/components/AchievementBadge.tsx, src/components/Toasts.tsx, src/components/settings/Forms.tsx
  • src/app/statistik/page.tsx, src/app/u/[slug]/page.tsx, src/app/einstellungen/page.tsx
  • src/app/actions/library.ts, src/app/actions/settings.ts
  • tests/achievements.test.ts, docs/ANLEITUNG.md, scripts/screenshots.mjs

Zur offenen Frage: umgesetzt ist beides — generische Namen als Grundlage, kuratierte obendrauf.

Eine Absicherung, die ich für nötig hielt: Die TMDB-Collection-Kennungen habe ich aus dem Gedächtnis geschrieben und kann sie hier nicht prüfen. Jeder kuratierte Eintrag trägt deshalb ein Stück des erwarteten TMDB-Namens; passt er nicht, greift der generische Name. Eine falsche Kennung bleibt damit folgenlos, statt jemandem „Spider Bro" für Ocean's zu geben.

Ein Fehler, den ein Test gefunden hat: Die Regel „zwischen drei und fünf Uhr" las die Stunde aus der formatierten Zeichenkette. Auf Deutsch liefert Intl aber „03 Uhr" — Number("03 Uhr") ist NaN, das Abzeichen wäre nie vergeben worden.

Geprüft

88 Tests grün (zehn neue), Typecheck sauber. Screenshot gegen die geseedete Instanz: 3 von 20 erreicht, Erreichtes farbig mit Datum, Offenes blass mit Bedingung.

So testest du es

  1. git switch feat/15-errungenschaften
  2. npm run db:migrate — es kommt eine neue Migration
  3. npm run dev, dann /statistik öffnen und ganz nach unten scrollen
  4. Erwartet: Der Abschnitt „Errungenschaften" zeigt beim ersten Aufruf sofort mehrere erreichte Abzeichen mit Datum — deine Historie wird einmal stumm ausgewertet
  5. Eine Episode abhaken, die ein neues Abzeichen auslöst → Einblendung „Errungenschaft: …" in Grün
  6. Gegenprobe: dieselbe Sichtung zurücknehmen — das Abzeichen bleibt
  7. Einstellungen → öffentliches Profil: der Schalter „Errungenschaften zeigen" steuert, ob sie unter /u/<adresse> erscheinen

Aufgewendete Zeit: 00:22
Pull Request: #17

Nach Freigabe: /issue-freigabe 15

✅ **Umsetzung abgeschlossen — bereit zum Testen.** <!-- claude-status branch: feat/15-errungenschaften pr: 17 zeit_sekunden: 1302 --> **Was geändert wurde** - Modell `Achievement` samt Migration, dazu `User.showAchievements` - `src/lib/achievements.ts`: ein gemeinsam geholter Datensatz, darauf 20 feste Regeln plus dynamische für Filmreihen und Universen - `src/lib/achievement-names.ts`: kuratierte Eigennamen wie „Spider Bro", abgesichert gegen falsche Kennungen - Auswertung nach Sichtungsaktionen und einmal täglich; erster Lauf je Konto stumm, angestoßen beim ersten Öffnen der Übersicht - Abschnitt in der Statistik, Abzeichen auf dem öffentlichen Profil (abschaltbar), eigene SVG-Symbole - Einblendung in eigenem Ton beim Erreichen - `docs/ANLEITUNG.md` mit eigenem Abschnitt und Screenshot **Geänderte Dateien** - `prisma/schema.prisma`, `prisma/migrations/20260902094830_errungenschaften/` - `src/lib/achievements.ts`, `src/lib/achievement-names.ts`, `src/lib/sync.ts` - `src/components/AchievementBadge.tsx`, `src/components/Toasts.tsx`, `src/components/settings/Forms.tsx` - `src/app/statistik/page.tsx`, `src/app/u/[slug]/page.tsx`, `src/app/einstellungen/page.tsx` - `src/app/actions/library.ts`, `src/app/actions/settings.ts` - `tests/achievements.test.ts`, `docs/ANLEITUNG.md`, `scripts/screenshots.mjs` **Zur offenen Frage:** umgesetzt ist beides — generische Namen als Grundlage, kuratierte obendrauf. **Eine Absicherung, die ich für nötig hielt:** Die TMDB-Collection-Kennungen habe ich aus dem Gedächtnis geschrieben und kann sie hier nicht prüfen. Jeder kuratierte Eintrag trägt deshalb ein Stück des erwarteten TMDB-Namens; passt er nicht, greift der generische Name. Eine falsche Kennung bleibt damit folgenlos, statt jemandem „Spider Bro" für Ocean's zu geben. **Ein Fehler, den ein Test gefunden hat:** Die Regel „zwischen drei und fünf Uhr" las die Stunde aus der formatierten Zeichenkette. Auf Deutsch liefert `Intl` aber „03 Uhr" — `Number("03 Uhr")` ist `NaN`, das Abzeichen wäre nie vergeben worden. **Geprüft** 88 Tests grün (zehn neue), Typecheck sauber. Screenshot gegen die geseedete Instanz: 3 von 20 erreicht, Erreichtes farbig mit Datum, Offenes blass mit Bedingung. **So testest du es** 1. `git switch feat/15-errungenschaften` 2. `npm run db:migrate` — es kommt eine neue Migration 3. `npm run dev`, dann `/statistik` öffnen und ganz nach unten scrollen 4. Erwartet: Der Abschnitt „Errungenschaften" zeigt beim ersten Aufruf sofort mehrere erreichte Abzeichen mit Datum — deine Historie wird einmal stumm ausgewertet 5. Eine Episode abhaken, die ein neues Abzeichen auslöst → Einblendung „Errungenschaft: …" in Grün 6. Gegenprobe: dieselbe Sichtung zurücknehmen — das Abzeichen bleibt 7. Einstellungen → öffentliches Profil: der Schalter „Errungenschaften zeigen" steuert, ob sie unter `/u/<adresse>` erscheinen **Aufgewendete Zeit:** 00:22 **Pull Request:** #17 Nach Freigabe: `/issue-freigabe 15`
florian.wilde removed the zu-testen label 2026-09-02 11:29:46 +00:00
Author
Owner

🚀 Freigegeben und nach main übernommen.

  • Merge-Commit: 6847d08
  • Pull Request: #17 (gemergt)
  • Gesamtaufwand: 00:22

Nach dem Merge auf main geprüft — zusammen mit #16, dessen Änderungen dieselben Dateien berühren: 93 Tests grün, Typecheck sauber, Bau erfolgreich. Kein Konflikt zwischen den beiden.

⚠️ Beim Aktualisieren kommt eine neue Migration mit (20260902094830_errungenschaften).

Das Issue wurde durch das Closes #15 im Merge automatisch geschlossen; die Statuslabels sind geräumt.

🚀 **Freigegeben und nach `main` übernommen.** <!-- claude-status merge: 6847d08011c55f3ab89d2cbec10281346c3aae2e pr: 17 zeit_sekunden: 1302 --> - Merge-Commit: `6847d08` - Pull Request: #17 (gemergt) - Gesamtaufwand: 00:22 Nach dem Merge auf `main` geprüft — zusammen mit #16, dessen Änderungen dieselben Dateien berühren: **93 Tests grün**, Typecheck sauber, Bau erfolgreich. Kein Konflikt zwischen den beiden. ⚠️ Beim Aktualisieren kommt eine neue Migration mit (`20260902094830_errungenschaften`). Das Issue wurde durch das `Closes #15` im Merge automatisch geschlossen; die Statuslabels sind geräumt.
Sign in to join this conversation.
1 Participants
Notifications
Total Time Spent: 21 minutes
florian.wilde
21 minutes
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: florian.wilde/flimmer#15