Files
flimmer/CHANGELOG.md
T
Florian Wilde 09625c89ef
CI / pruefen (pull_request) Canceled after 0s
Version 0.9.0
Errungenschaften und die Auswahlliste fuer unbekannte Jellyfin-Titel.
Changelog, Release-Notiz, DEVLOG und Projektgedaechtnis nachgezogen.

Die Anleitung hat ihre beiden Abschnitte schon mit den jeweiligen Issues
bekommen — Errungenschaften mit Screenshot, „Titel, die Flimmer noch nicht
kennt" im Jellyfin-Kapitel.
2026-09-02 14:47:23 +02:00

567 lines
29 KiB
Markdown

# Changelog
Alle nennenswerten Änderungen an Flimmer stehen in dieser Datei.
Das Format folgt [Keep a Changelog](https://keepachangelog.com/de/1.1.0/),
die Versionierung [Semantic Versioning](https://semver.org/lang/de/).
## [Unveröffentlicht]
## [0.9.0] — 2026-09-02
**Errungenschaften** — Abzeichen für erreichte Meilensteine. Dazu die
**Auswahlliste** beim Jellyfin-Abgleich, ohne die die Anbindung auf einer
gewachsenen Mediathek kaum etwas ausrichtete.
> ⚠️ **Beim Aktualisieren kommt eine Migration mit** (`errungenschaften`). Der
> Container spielt sie beim Start selbst ein; `./update.sh` legt vorher eine
> Sicherung an.
### Hinzugefügt
- **Errungenschaften.** Zwanzig feste Abzeichen, dazu dynamische für
vollständig gesehene Filmreihen und abgeschlossene Universen. Zu finden
unten auf der Statistikseite.
Sie tauchen auf, wenn etwas erreicht ist, und bleiben dann — **keine
Streaks**, die reißen, wenn man eine Woche nichts schaut, keine
Fortschrittsbalken, die drängeln. Wer eine Sichtung zurücknimmt, verliert
kein Abzeichen; es wieder einzukassieren wäre kleinlich.
Ein paar davon: *Der lange Atem* (eine Serie mit hundert Episoden komplett),
*Treu geblieben* (über ein Jahr an demselben Titel), *Durchgemacht*
(zwischen drei und fünf Uhr morgens abgehakt), *Zeitreisender* (Titel aus
sieben Jahrzehnten), *Strenges Urteil* (einmal die Note 1 vergeben).
Für **ganze Filmreihen** braucht es keine gepflegte Liste: TMDB gruppiert
sie selbst, und die Zugehörigkeit steht beim Import schon am Titel. Wer alle
Spider-Man-Filme gesehen hat, bekommt sie als Reihe angerechnet. Für
bekannte Reihen gibt es einen eigenen Namen, sonst heißt es schlicht „Reihe
komplett — …".
Beim ersten Öffnen wird die ganze Historie einmal **stumm** ausgewertet —
eine gewachsene Bibliothek soll nicht zwei Dutzend Meldungen auf einmal
auslösen. Erst danach wird gemeldet, was neu dazukommt. Auf dem öffentlichen
Profil lassen sich die Abzeichen zeigen oder ausblenden.
- **Auswahlliste für Jellyfin-Titel, die Flimmer nicht kennt.** Beim ersten
Abgleich einer gewachsenen Mediathek passierte bisher etwas Ernüchterndes:
Jellyfin meldet tausend Einträge, und Flimmer ordnet **keinen einzigen** zu,
weil der Katalog sie nicht kennt.
Jetzt steht unter dem Bericht eine Liste zum Anhaken. Was ausgewählt ist,
holt Flimmer von TMDB — bei Serien samt Staffeln und Episoden — und nimmt es
mit „hab ich · Jellyfin" in die Bibliothek auf.
Die Liste fasst zusammen: Führt Jellyfin drei Dateien zum selben Film
(Extended Edition, zweite Fassung), steht er einmal da, mit dem Vermerk, wie
viele Dateien darauf zeigen. Einträge, denen in Jellyfin die TMDB-Kennung
fehlt, bleiben sichtbar, sind aber nicht auswählbar — dort kann Flimmer
nichts holen.
Geholt werden hundert je Lauf; der Rest bleibt für den nächsten Klick. Ein
einzelner Fehlschlag beendet den Lauf nicht, und **aus der Liste verschwindet
nur, was tatsächlich ankam**.
### Geändert
- Der Bericht des Medienserver-Abgleichs war auf **50 Einträge** gekürzt —
bei über tausend gelesenen ein Blick durchs Schlüsselloch. Jetzt bis 1000,
und was darüber hinausgeht, wird gezählt statt stillschweigend
abgeschnitten.
- Das Häkchen beim Abgleich heißt jetzt „**Bekannte** Titel dabei in die
Bibliothek aufnehmen". Es nimmt auf, was Flimmer *kennt*; die neue
Auswahlliste holt, was es *nicht kennt*. Der Unterschied stand vorher
nirgends — und war der Grund, warum das Häkchen bei einer frischen Instanz
nichts bewirkte.
- Einblendungen kennen einen dritten Ton für Erfolge.
- `npm run screenshots` hebt für Ausschnittaufnahmen die klebende Kopfleiste
auf; sie legte sich sonst über die Überschrift.
### Behoben
- Im Bericht stand eine Serie als **Film**, weil der Typ aus dem Umkehrschluss
„keine Episode, also Film" abgeleitet wurde. Er kommt jetzt aus dem Item.
### Getestet
93 Tests (vorher 78). Neu: der Regelkatalog der Errungenschaften samt
Stummschaltung, Entdopplung und Zeitzonenrechnung; die Auswahlliste samt
Zusammenfassung, Fehlschlägen und Rechteprüfung.
Ein Test hat dabei einen Fehler gefunden, den man leicht übersieht: Die Regel
„zwischen drei und fünf Uhr" las die Stunde aus der formatierten Zeichenkette,
und auf Deutsch liefert das System dafür **„03 Uhr"** — als Zahl gelesen wird
daraus nichts. Das Abzeichen wäre nie vergeben worden.
### Anleitung
`docs/ANLEITUNG.md` hat zwei neue Abschnitte: **Errungenschaften** mit
Screenshot und **Titel, die Flimmer noch nicht kennt** im Jellyfin-Kapitel.
## [0.8.0] — 2026-09-02
Zwei größere Bausteine: **Anmeldung per Passkey** und die **Jellyfin-Anbindung**.
Dazu vier Nacharbeiten aus dem laufenden Betrieb.
> ⚠️ **Beim Aktualisieren kommen zwei Migrationen mit** (`passkeys`,
> `medienserver`). Der Container spielt sie beim Start selbst ein; `./update.sh`
> legt vorher eine Sicherung an.
### Hinzugefügt
- **Anmeldung per Passkey (WebAuthn).** Windows Hello, Face ID, Touch ID oder
ein Sicherheitsschlüssel — statt Passwort. Anlegen und verwalten unter
*Einstellungen → Passkeys*, anmelden über „Mit Passkey anmelden" **ohne
vorherige E-Mail-Eingabe**.
Ein Passkey ist der dritte Weg in denselben Trichter: am Ende steht dieselbe
Sitzung wie bei Passwort und OIDC. Das Passwort bleibt daneben bestehen, und
den letzten verbleibenden Anmeldeweg lässt Flimmer nicht entfernen.
Drei Dinge, die beim Selbsthosten zählen:
- **HTTPS ist Pflicht** (Ausnahme: `localhost`). Läuft die Instanz über
einfaches HTTP, verschwindet die Verwaltung mit einem Hinweis, statt einen
kryptischen Browserfehler zu zeigen.
- Der Hostname kommt aus `APP_URL`, nicht aus dem `Host`-Header — hinter
einem Reverse Proxy hinge er sonst am falschen Namen.
- **Ein Domainwechsel entwertet alle Passkeys.** Sie sind fest an den
Hostnamen gebunden und müssen danach neu angelegt werden.
Abschaltbar über `ENABLE_PASSKEYS`.
- **Jellyfin anbinden** — Bestand und Sichtungen übernehmen, unter
*Einstellungen → Medienserver*.
Zugeordnet wird über die **TMDB-Kennung**, die Jellyfin zu jedem Item
mitliefert; dieselbe Kennung, auf der Flimmers Katalog ohnehin aufbaut. Kein
Raten über Titel und Jahreszahlen — die Zuordnung ist eindeutig oder sie
findet nicht statt. Was Jellyfin ohne Kennung führt, landet im Bericht.
Angemeldet wird mit Benutzername und Passwort, **nicht** mit einem
API-Schlüssel: mit einem Schlüssel liefert Jellyfin den Bestand ohne
Gesehen-Status, und zwar ohne Fehlermeldung. Der Verbindungstest prüft das
ausdrücklich nach und sagt es. Das Zugangstoken liegt verschlüsselt in der
Datenbank (AES-256-GCM, Schlüssel aus `AUTH_SECRET`), das Passwort wird nicht
gespeichert.
Der Abgleich ist eine **Einbahnstraße**: er ergänzt und löscht nie etwas, das
in Flimmer steht. Fehlende Titel werden nur mit gesetztem Häkchen
aufgenommen — im täglichen Lauf also nie. Danach läuft er im
Hintergrundlauf mit.
*Grenze der Quelle:* Jellyfin kennt `PlayCount` und `LastPlayedDate`, aber
keine Liste einzelner Sichtungen. Ein dreimal gesehener Film kommt deshalb
mit **einem** Termin an, nicht mit drei. Das steht auch in der Anleitung.
Das Zurückschreiben nach Jellyfin (Stufe 3) ist noch nicht dabei; das Feld
liegt im Datenmodell bereit.
- **Standardreihenfolge je Universum.** Welche Reihenfolge beim Öffnen
erscheint, lässt sich jetzt festlegen — wer Schreibrecht hat, setzt sie für
alle. Die Rangfolge bleibt schlicht: Adresse schlägt Standard schlägt erste.
Über die Schnittstelle mit `PATCH /api/v1/universen/{id}`.
### Geändert
- **Rückmeldung beim Tippen** in Suche und Bibliothek. Beim Suchen wird das
Trefferraster gedämpft und auf `aria-busy` gesetzt, der Hinweis „sucht …"
steht jetzt auch in der Bibliothek. Die alten Treffer bleiben sichtbar —
sie verschwinden zu lassen ließe die Liste bei jedem Tastendruck springen.
Die Sammelverzögerung liegt einheitlich bei 250 ms.
- **`update.sh` erkennt jetzt den Container-Zustand.** Schlägt die Abfrage über
den veröffentlichten Port fehl, zählt der Healthcheck des Containers —
hinter einem Reverse Proxy ist der App-Port oft gar nicht auf dem Host
veröffentlicht, und das Skript meldete dann einen Fehlschlag, obwohl das
Update sauber durchgelaufen war. Im Fehlerfall nennt es außerdem den Zustand
und ordnet ihn ein.
*Zur Klarstellung:* Der Changelog zu 0.7.1 führte diese Rückfallprüfung
bereits auf. Sie war dort beschrieben, aber nicht umgesetzt — jetzt ist sie
es.
- Die Entwicklungsdatenbank hat einen eigenen Compose-Projektnamen
(`flimmer-dev`). Vorher leiteten beide Compose-Dateien ihn aus dem
Verzeichnis ab, und ein `docker compose down -v` auf dem Produktivstack nahm
das Volume der Entwicklungsdatenbank mit.
### Behoben
- **Ein als gesehen markierter Film ließ sich nicht mehr zurücksetzen.** Im
Zustand „gesehen" stand statt eines Knopfes ein Etikett ohne Klickziel, und
eine Gegenfunktion gab es nicht — Serien hatten längst einen Umschalter,
Filme nur einen Hinweg. Die grüne Plakette ist jetzt klickbar.
Zurückgenommen wird dabei **nur der laufende Durchlauf**: wer einen Film
dreimal gesehen hat, verliert die früheren Sichtungen nicht.
- **Die Beschriftungen im Titelraster sprangen**, sobald ein Titel zweizeilig
umbrach — die Metazeile saß dann eine Zeilenhöhe tiefer als bei den Nachbarn,
und die Reihen waren unterschiedlich hoch. Der Titelblock belegt jetzt immer
zwei Zeilen; in der Bibliothek wird zusätzlich der Platz des
Fortschrittsbalkens freigehalten, den es nur bei Serien gibt.
### Getestet
78 Tests (vorher 52). Neu dazu: Passkey-Verwaltung samt Aussperrsperre, der
Jellyfin-Abgleich gegen nachgebildete Antworten, die Standardreihenfolge samt
Eindeutigkeit, und das Zurücknehmen einer Filmsichtung über
Durchlaufgrenzen hinweg.
Zusätzlich wurden die Klickwege gegen einen **Produktionsbau** geprüft — die
Passkey-Anmeldung mit einem virtuellen Authenticator, der Jellyfin-Abgleich
gegen einen nachgebildeten Server samt des Falls, in dem der Gesehen-Status
fehlt.
## [0.7.1] — 2026-09-01
### Hinzugefügt
- **`update.sh`** für den Betrieb unter Linux — ausführbar im Repository
hinterlegt, also direkt nach dem Klonen startklar. Der Ablauf: Datenbank
sichern, Änderungen holen, Image bauen, neu starten, warten bis die Instanz
wieder antwortet.
Grundhaltung: erst sichern, dann anfassen. Schlägt die Sicherung fehl, bricht
das Skript ab, statt weiterzumachen. Geht danach etwas schief, nennt es den
**konkreten** Weg zurück — mit dem Commit, zu dem man zurückspringt, und der
Datei, die man einspielt, nicht bloß dem Rat, ein Backup zu haben.
Weitere Eigenheiten:
- Lokale Änderungen im Arbeitsverzeichnis werden erkannt; `git pull`
unterbleibt dann, statt sie zu überfahren.
- Erreichbarkeit wird über den veröffentlichten Port geprüft und, falls der
nicht nach außen geht (Reverse Proxy im selben Docker-Netz), über den
Healthcheck des Containers.
- Alte Sicherungen werden aufgeräumt, die letzten zehn bleiben (`--behalte N`).
- Kommt mit `docker compose` und dem alten `docker-compose` zurecht.
- `APP_PORT` in der `.env.example` — der Port stand bisher nur in der
Compose-Datei als Vorgabewert.
## [0.7.0] — 2026-09-01
„Hab ich" — Titel, die in der eigenen Sammlung liegen. Dazu die Nacharbeiten
aus der Abnahme: das Docker-Image wurde zum ersten Mal wirklich gebaut und
gestartet, und dabei kamen Fehler ans Licht, die nur der echte Containerstart
zeigt.
### Hinzugefügt
- **Eigene Sammlung**: Jeder Eintrag lässt sich als „hab ich" markieren, mit
Angabe wo — Jellyfin, Plex, Emby, NAS, Blu-ray, DVD oder frei getippt.
Bewusst getrennt vom Feld „wo schaue ich das": Streaming-Verfügbarkeit kommt
und geht, der gekaufte Film auf dem Heimserver bleibt. Gerade die Titel, die
nirgends mehr laufen, will man ja wiederfinden.
- Abzeichen auf der Posterkachel und im Kopf der Detailseite
- Auf der Detailseite steht die Sammlung **vor** der Streaming-Verfügbarkeit
— was man hat, ist die verlässlichere Antwort auf „wo kann ich das schauen"
- Eigener Filter in der Bibliothek samt Zähler
- In Export (CSV und JSON), CSV-Import und REST-API (`?sammlung=1` beim
Lesen, `owned` und `ownedSource` beim Ändern)
### Behoben
- **Der Container konnte seine Migrationen nicht einspielen.** Das Laufzeitimage
bekam die Prisma-CLI, indem einzelne Ordner aus `node_modules` kopiert wurden
— dabei fehlten transitive Abhängigkeiten von `@prisma/config` (`effect` und
weitere). Die CLI wird jetzt in einer eigenen Build-Stufe vollständig
installiert und liegt im Laufzeitimage unter `/node_modules`, wo sie den
getracten Abhängigkeitsbaum der Anwendung nicht stört.
- **Der Build hing im Container am Schriftabruf.** `next/font/google` lädt
Outfit beim Bauen von Google herunter — das macht den Build von einer
Netzverbindung abhängig und blieb im Container hängen. Die variable Fassung
liegt jetzt als Datei im Repository; weder beim Bauen noch zur Laufzeit geht
eine Anfrage nach außen. Für eine selbst gehostete Anwendung ist das ohnehin
das Richtige.
- **npm blockierte Prismas Install-Skripte** (Voreinstellung seit npm 11),
wodurch im Image die plattformpassende Engine fehlen konnte. Sie sind jetzt
gezielt für `prisma` und `@prisma/engines` erlaubt statt pauschal.
### Hinzugefügt
- **Erscheinungsmeldung für Watchlist-Filme.** Der Schalter dafür stand schon im
Profil, verschickt wurde bisher nichts. Betrachtet wird ein Zeitfenster der
letzten Tage statt eines Zustandswechsels — TMDB verschiebt Termine
gelegentlich, und ein einmal verpasstes Datum soll die Meldung nicht für
immer verhindern.
- **Gitea-Actions-Workflows**: `ci.yml` prüft bei jedem Push Typen, Tests und
Produktionsbuild gegen eine echte PostgreSQL-Instanz; `release.yml` legt beim
Pushen eines Versions-Tags das Release mit den Notizen aus
`releases/vX.Y.Z.md` an.
- Diagrammfarben und ihre Prüfwerte in `docs/DESIGN.md` festgehalten; das
öffentliche Profil in die Anleitung aufgenommen.
### Entfernt
- Die ungenutzte `images`-Konfiguration in `next.config.ts`. `next/image` kommt
nirgends zum Einsatz — damit entfällt auch das sicherheitsrelevant aussehende
`dangerouslyAllowSVG`, das ohnehin wirkungslos war.
## [0.6.0] — 2026-09-01
Der Rest: Benachrichtigungen, Abgleich, Import und Export, Schnittstelle, PWA
— und eine bebilderte Anleitung.
### Hinzugefügt
- **Benachrichtigungen** über vier Wege: E-Mail (SMTP), ntfy, Gotify und ein
generischer Webhook, der zugleich Discord, Slack und Mattermost bedient.
Jeder Nutzer richtet seine Kanäle selbst ein, kann sie einzeln stummschalten
und mit einer Testnachricht ausprobieren. Dieselbe Meldung geht nie zweimal
raus — auch ein Fehlversuch wird protokolliert, sonst spammt der nächste Lauf
den Kanal voll, sobald er wieder erreichbar ist. Die E-Mail-Vorlage trägt
Logo und Farbwelt von Flimmer.
- **Täglicher Abgleich**: frischt laufende Serien bei TMDB auf, meldet neue
Episoden und neu verfügbare Watchlist-Titel, räumt Papierkorb und abgelaufene
Sitzungen. Eingebauter Zeitplan über `ENABLE_SCHEDULER` und `SYNC_HOUR`, von
außen anstoßbar über `/api/cron/sync` mit `CRON_SECRET`, und in der
Verwaltung per Knopfdruck. Ein einzelner Titel kann den Lauf nicht kippen.
- **Import** aus Trakt.tv (JSON, egal ob Watchlist, History, Ratings oder
Collection) und aus CSV mit Komma oder Semikolon. Der Import überschreibt
nichts: was schon in der Bibliothek liegt, bleibt unangetastet.
- **Export** der eigenen Daten als CSV oder als JSON mit allen Sichtungen und
Universen.
- **REST-API** unter `/api/v1` mit persönlichen API-Schlüsseln: Bibliothek
lesen und pflegen, Episoden abhaken und zurücknehmen, suchen, Kalender,
Statistik, Universen, Export. Beschreibung als OpenAPI 3.1 unter
`/api/v1/openapi.json`, dazu `docs/API.md` mit Beispielen.
- **Einstellungsseiten** für Profil, Region, Passwort, Benachrichtigungen,
API-Schlüssel sowie Import und Export.
- **Verwaltungsbereich**: Instanzname, Registrierung öffnen und schließen,
öffentliche Profile erlauben, Konten sperren und Rechte vergeben, Abgleich
anstoßen und der Zustand der Instanz auf einen Blick. Die letzte
Administration lässt sich nicht entmachten.
- **Öffentliche Profilseite** unter `/u/<adresse>` — Zahlen und zuletzt
Gesehenes, aber keine Notizen, keine Watchlist, keine E-Mail-Adresse.
Abschaltbar durch den Nutzer *und* instanzweit durch den Betreiber.
- **PWA-Feinschliff**: eigener Service Worker (Poster aus dem Zwischenspeicher,
Seiten zuerst aus dem Netz, Offline-Rückfall) und eine Offline-Seite.
- **`TMDB_BASE_URL`** für Instanzen hinter einem eigenen Proxy — und für den
mitgelieferten TMDB-Ersatz `scripts/tmdb-stub.mjs`, mit dem sich die Suche
ohne Schlüssel aus den Beispieldaten ausprobieren lässt.
- **Bebilderte Anleitung** `docs/ANLEITUNG.md` mit 18 Screenshots aus der
laufenden Instanz, aufgenommen von `npm run screenshots`.
- **9 weitere Tests** für CSV- und Trakt-Import, Export, das Aufräumen des
Papierkorbs und den Schutz vor Doppelversand — zusammen 49.
## [0.5.0] — 2026-09-01
Übersicht, Kalender und Statistik.
### Hinzugefügt
- **Übersicht** mit „Weiterschauen" (laufende Serien samt nächster Episode,
Fortschritt und „+1 Episode" direkt aus der Kachel), den Ausstrahlungen der
nächsten vier Wochen und den Watchlist-Titeln, die zuletzt auf einem Dienst
verfügbar geworden sind.
- **Kalender** als Monatsraster mit Blättern und Sprung zum heutigen Tag,
darunter die Termine des Monats als Liste. Ausgezeichnet als Tabelle — ein
Kalender *ist* eine Tabelle, und mit Screenreader wird daraus dann
„Woche 3, Donnerstag, 24." statt einer ununterscheidbaren Kachelwüste.
- **Statistikseite** mit Gesamtschauzeit, Episoden und Filmen je Monat als
Diagramm, Verteilung nach Streamingdienst und Genre, Jahresrückblick
(„2026 in Zahlen") sowie den Listen „wo die meiste Zeit hinging" und
„deine besten Bewertungen". Alles aus den Sichtungen gerechnet, Rewatches
zählen mit.
- **Diagramme als handgeschriebenes SVG** — ohne Chart-Bibliothek, dafür an
den Design-Tokens. Die beiden Serienfarben sind abgedunkelte Varianten der
Signaturfarben; sie bestehen in **beiden** Farbschemata die Prüfungen auf
Helligkeitsband, Sättigung, Farbfehlsichtigkeit und Kontrast. Die vollen
Signaturtöne wären auf dunklem Grund zu hell. Legende, Achsenwerte,
Tooltip beim Überfahren und eine für Screenreader hinterlegte Tabelle
sorgen dafür, dass die Aussage nie allein an der Farbe hängt.
- Markenfarben der Streamingdienste in der Verteilung, aber nur, wenn sie auf
hellem *und* dunklem Grund mindestens 3:1 erreichen — sonst der geprüfte
Standardton.
- **7 weitere Tests** für Gesamtzahlen, Monatsgruppierung, Jahresrückblick,
„Weiterschauen" und den Kalenderzeitraum.
### Behoben
- Das Monatsdiagramm blieb leer, obwohl Sichtungen vorlagen: `date_trunc`
liefert Mitternacht in der Zeitzone der Datenbanksitzung, JavaScript legte
beim Abgleich die lokale Zone an — zwei Stunden Versatz genügten, damit kein
einziger Monatsschlüssel mehr passte. Der Schlüssel kommt jetzt als Text
(„2026-04") aus der Datenbank.
- Eine laufende Serie, bei der man auf dem Stand ist, gilt als „abgeschlossen"
und verschwand damit aus dem Kalender — dabei will man die nächste Folge
dort erst recht sehen. Jetzt fällt nur Abgebrochenes heraus.
- Der SVG-Titel des Diagramms brach die Hydration: React behandelt `<title>`
als Dokument-Metadatum und hebt es aus dem SVG heraus. Die Beschriftung
hängt jetzt als `aria-label` am `<svg>`.
## [0.4.0] — 2026-09-01
Universen: zusammengehörige Titel, mehrere Reihenfolgen, ein Gesamtfortschritt.
### Hinzugefügt
- **Universen** aus beliebigen Filmen **und** Serien — MCU, Star Wars,
Wizarding World oder was auch immer zusammengehört.
- **Mehrere Reihenfolgen je Universum**. Die Erscheinungsreihenfolge wird aus
den Erscheinungsdaten berechnet und nie gespeichert — sie stimmt damit immer.
Weitere Reihenfolgen (Story-Chronologie, Einsteiger-Route) sind frei
sortierbar, per Ziehen **und** über Pfeilknöpfe. Reines Drag & Drop wäre mit
Tastatur nicht bedienbar und auf dem Handy fummelig.
- **TMDB-Collections als Startpunkt**: Reihen, die in der eigenen Bibliothek
vorkommen, lassen sich mit einem Klick übernehmen.
- **Universums-Detailseite** mit nummerierter Liste, Gesamtfortschritt
(„4 von 7 abgeschlossen, 21 h 21 min gesehen"), hervorgehobenem
„Als Nächstes dran" und der Restlaufzeit bis zum Ende des Universums.
Bei Serien schrumpft die Restzeit anteilig mit den gesehenen Episoden.
- **Teilen** mit anderen Konten der Instanz, wahlweise nur zum Ansehen oder
zum gemeinsamen Pflegen. Der Fortschritt ist dabei immer der des
jeweiligen Betrachters — ein geteiltes Universum zeigt jeder Person ihren
eigenen Stand. Löschen bleibt dem Besitzer vorbehalten.
- **12 weitere Tests** für Reihenfolgen, Fortschrittsberechnung über Filme und
Serien hinweg, Freigaben und die Rechteprüfung.
- Beispieluniversum im Seed: die Sternenpfad-Reihe mit fünf Filmen, zwei
Serien und einer abweichenden Story-Chronologie.
### Behoben
- Die Posterkachel zog über `lib/images.ts` die serverseitige Cache-Logik in
den Browser-Bundle, sobald sie aus einer Client-Komponente heraus gerendert
wurde — der Build brach ab, sobald eine solche Seite dazukam. Die reine
URL-Bildung liegt jetzt in `lib/image-url.ts`, der Dateicache bleibt
serverseitig.
## [0.3.0] — 2026-09-01
Das Kernstück: Bibliothek, Status und Episodenfortschritt.
### Hinzugefügt
- **Bibliothek** als Posterraster mit Volltextsuche und Filtern nach Status,
Typ, Genre, Streamingdienst und Tag; Sortierung nach zuletzt aktualisiert,
hinzugefügt, Titel, Bewertung oder Erscheinungsjahr. Der gesamte Filterstand
steht in der URL und ist damit teilbar.
- **Fünf Status** je Eintrag (Schaue gerade, Pausiert, Abgeschlossen,
Abgebrochen, Watchlist). Der Status ergibt sich beim Abhaken von selbst:
die erste Episode startet einen Titel, die letzte schließt ihn ab.
Pausiert und Abgebrochen bleiben unangetastet — wer bewusst pausiert hat,
will das nicht durch eine Sichtung aufgehoben bekommen.
- **Episodenfortschritt**: einzeln abhaken, ganze Staffel auf einmal,
„bis hierhin gesehen" für den Einstieg mitten in einer Staffel, und ein
**„+1 Episode"**-Knopf, der genau die nächste offene Episode nimmt.
Häkchen reagieren sofort und werden zurückgedreht, wenn der Server
widerspricht; beim Abhaken glimmt die Zeile einmal warm auf.
- **„Als Nächstes dran"** mit Episodencode, Titel und Ausstrahlungsdatum;
Fortschritt in Prozent auf Basis der echten Episodenzahl, dazu die
verbleibende Laufzeit.
- **Rewatch-Zählung**: ein neuer Durchlauf setzt den Fortschritt zurück, die
Sichtungen des vorherigen bleiben für die Statistik erhalten. Bei Filmen
zählt jeder Durchlauf einzeln.
- **Rückgängig** für jede Sichtungsaktion — die Rückmeldung am unteren Rand
nennt, was passiert ist, und nimmt es auf Klick zurück.
- **Pro Eintrag**: Bewertung von 1 bis 10, Notizfeld, eigene Tags und das Feld
„wo schaue ich das", das beim Aufnehmen einen Vorschlag aus der
Streaming-Verfügbarkeit erhält und jederzeit überschreibbar ist.
- **Papierkorb** statt hartem Löschen: entfernte Titel bleiben 30 Tage liegen
und behalten dabei ihren Fortschritt. Wird ein Titel erneut aufgenommen,
lebt derselbe Eintrag wieder auf.
- **Titel selbst anlegen** für alles, was TMDB nicht kennt. Solche Einträge
haben keine TMDB-ID und werden vom Abgleich nie angefasst.
- **Seed mit Beispielbibliothek**: erfundener Katalog aus 8 Serien und
10 Filmen samt lokal erzeugten Postern, dazu 18 Bibliothekseinträge und
85 Sichtungen über die letzten Monate verteilt.
- **21 Tests** decken Aufnehmen, Abhaken, Fortschritt, Rewatch, Papierkorb und
den Zugriffsschutz zwischen Nutzern ab.
### Geändert
- Die Detailseite liegt jetzt unter `/titel/<id>` und hängt an der internen
Titel-ID statt an der TMDB-ID — nur so bekommen manuell angelegte Titel
dieselbe Seite. Treffer aus der Suche laufen über `/tmdb/<art>/<id>`, das
den Titel holt und weiterleitet.
- Die Zahl der Build-Worker ist auf vier begrenzt: mit einem Worker je Kern
stürzte der Build auf einer 18-Kern-Maschine reproduzierbar ab, weil jeder
Worker eine eigene Prisma-Engine hochzieht.
## [0.2.0] — 2026-09-01
Metadaten: Flimmer spricht mit TMDB.
### Hinzugefügt
- **TMDB-Anbindung** für Suche (gemeinsam über Serien und Filme oder getrennt),
Detailabruf, Staffeln und Episoden, offizielle Collections sowie die
Streaming-Verfügbarkeit in der eingestellten Region. Zugang wahlweise über
den klassischen API-Schlüssel oder das Bearer-Token.
- **Gemeinsamer Katalog**: Titel werden über (Typ, TMDB-ID) dedupliziert — bei
mehreren Nutzern liegt jede Serie samt Episodenliste nur einmal in der
Datenbank. `ensureTitle` holt einen Titel nur, wenn er fehlt oder veraltet ist,
und fällt bei einem TMDB-Ausfall auf den lokalen Stand zurück.
- **Bild-Cache**: Poster und Hintergrundbilder werden einmal geholt und danach
über `/api/image` vom eigenen Server ausgeliefert. Größe und Pfad werden
streng geprüft, damit der Endpunkt kein offener Proxy wird.
- **Suchseite** mit Typfilter; die Anfrage steht in der URL und ist damit
teilbar. Getippte Eingaben werden kurz gesammelt, bevor gesucht wird.
- **Detailseite** je Titel mit Backdrop, Kopfdaten, Genres, Streamingdiensten
(mit den Akzentfarben der großen Anbieter) und aufklappbaren Staffeln samt
Episodenliste.
- **Testlauf ohne Schlüssel**: nachgebildete TMDB-Antworten unter `tests/` und
`npm test` prüfen den kompletten Importpfad gegen eine echte Datenbank.
### Behoben
- `importSeries` gab den Titel zurück, bevor Staffel- und Episodenzähler
geschrieben waren — die Zähler standen dadurch auf 0.
- Poster und Dienstlogos zeigten das kaputte Bildsymbol des Browsers, wenn ein
TMDB-Pfad ins Leere lief. Die Rückfalldarstellung liegt jetzt dauerhaft
darunter statt an einem `onError`-Handler zu hängen, der bei einem früh
gescheiterten Bild gar nicht mehr feuert.
## [0.1.0] — 2026-09-01
Erste lauffähige Etappe: Gerüst, Marke, Datenmodell und Anmeldung.
### Hinzugefügt
- **Projektgerüst** mit Next.js 16 (App Router), TypeScript, Tailwind CSS v4
und `standalone`-Build für schlanke Container.
- **Marke Flimmer**: Logo als SVG in drei Varianten (Bildmarke, Bildmarke mit
Wortmarke, monochrom) plus Maskable-Variante. Die Wortmarke ist aus Pfaden
konstruiert und braucht keine installierte Schrift.
- **Icon-Generator** (`npm run icons`): erzeugt Favicon (SVG und ICO),
PWA-Icons in sieben Größen, Maskable-Icons, Apple-Touch-Icon und OG-Bild
aus den SVG-Quellen.
- **Design-Tokens** als CSS-Variablen, über `@theme inline` an Tailwind
angebunden. Dunkles Standard-Theme und heller Modus mit Umschalter
(Dunkel / Hell / System), ohne Aufblitzen beim Laden. Alle Farbkombinationen
erfüllen WCAG AA; getrennte Verläufe für Flächen und Text sorgen dafür, dass
auch der Signaturverlauf im hellen Modus lesbar bleibt.
- **Datenmodell** (Prisma, PostgreSQL) für Konten, Katalog (Titel, Staffeln,
Episoden, Streamingdienste), persönliches Tracking, Universen mit
Reihenfolgen sowie Benachrichtigungen und Hintergrundläufe.
- **Authentifizierung**: Registrierung und Anmeldung mit E-Mail und Passwort
(bcrypt), Sitzungen als opake Token in der Datenbank mit httpOnly-Cookie.
Der erste registrierte Zugang wird automatisch Administrator; die
Registrierung lässt sich instanzweit abschalten.
- **Optionales SSO** über OIDC (Authorization Code mit PKCE) für Authelia,
Keycloak, Authentik und Verwandte — per Umgebungsvariablen aktivierbar,
mit Zuordnung zu vorhandenen Konten über die E-Mail-Adresse.
- **API-Schlüssel** je Nutzer als Grundlage für die spätere REST-API.
- **Docker-Compose-Setup** für den Selbstbetrieb (App und PostgreSQL,
persistente Volumes, Healthcheck) samt Entrypoint, der ausstehende
Migrationen beim Start einspielt.
- **Healthcheck** unter `/api/health`, der auch die Datenbank prüft.
- **PWA-Manifest** mit allen Icon-Größen.
- **Oberflächentexte** auf Deutsch, gebündelt in `src/i18n` und so aufgebaut,
dass weitere Sprachen als zusätzliche Datei dazukommen können.
- **Seed-Skript** mit Demo-Konten sowie README und Design-Dokumentation.
[Unveröffentlicht]: https://git.wilde-server.de/florian.wilde/flimmer/compare/v0.7.1...HEAD
[0.7.1]: https://git.wilde-server.de/florian.wilde/flimmer/releases/tag/v0.7.1
[0.7.0]: https://git.wilde-server.de/florian.wilde/flimmer/releases/tag/v0.7.0
[0.6.0]: https://git.wilde-server.de/florian.wilde/flimmer/releases/tag/v0.6.0
[0.5.0]: https://git.wilde-server.de/florian.wilde/flimmer/releases/tag/v0.5.0
[0.4.0]: https://git.wilde-server.de/florian.wilde/flimmer/releases/tag/v0.4.0
[0.3.0]: https://git.wilde-server.de/florian.wilde/flimmer/releases/tag/v0.3.0
[0.2.0]: https://git.wilde-server.de/florian.wilde/flimmer/releases/tag/v0.2.0
[0.1.0]: https://git.wilde-server.de/florian.wilde/flimmer/releases/tag/v0.1.0