Files
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

10 KiB

Flimmer — Arbeitsauftrag & Projektgedächtnis

Diese Datei ist mein (Claude) Gedächtnis für dieses Projekt. Sie hält fest, was gebaut werden soll, wie gearbeitet wird und wo ich gerade stehe. Nach jeder Etappe wird der Abschnitt „Fortschritt" aktualisiert.

Was ist Flimmer?

Selbst hostbarer Serien- & Film-Tracker (angelehnt an „Flimmerkiste"). Multi-User, TMDB-Metadaten, Episodenfortschritt, eigene Universen mit mehreren Reihenfolgen, Statistiken, Benachrichtigungen, REST-API, PWA. Oberflächensprache Deutsch.

Verbindliche Entscheidungen (nicht ohne Rückfrage ändern)

Bereich Entscheidung Begründung
Framework Next.js 15, App Router, TypeScript UI + REST-API + Cron in einem Deployment; Server Components halten Prisma serverseitig; output: "standalone" ergibt ein schlankes Docker-Image
DB PostgreSQL + Prisma (Schema + Migrationen) vorgegeben
Styling Tailwind CSS v4 (@theme, CSS-Variablen) Design-Tokens sind in v4 nativ CSS-Variablen → Dark/Light/Themes bauen sauber darauf auf
Auth eigene Session-Schicht: bcryptjs + opake Tokens in DB-Tabelle Session, httpOnly-Cookie; OIDC optional über jose + Discovery DB-Sessions erlauben Sperren/Abmelden durch Admin; kein Beta-API-Risiko von next-auth v5; Credentials + OIDC parallel möglich
Passwort-Hash bcryptjs (pure JS) keine nativen Build-Abhängigkeiten im Docker-Image
Scheduler in-process über instrumentation.ts (ENABLE_SCHEDULER) plus /api/cron/* mit CRON_SECRET kein zweiter Container nötig, externe Scheduler trotzdem möglich
Bild-Cache Dateien unter DATA_DIR/images, ausgeliefert über /api/image kein TMDB-Abruf pro Seitenaufruf
Charts handgeschriebene SVG-Komponenten volle Kontrolle über Design-Tokens, keine Chart-Lib-Abhängigkeit
PWA eigenes sw.js + manifest.webmanifest keine zusätzliche Abhängigkeit
i18n Dictionary src/i18n/de.ts + t()-Helper mit Punkt-Keys weitere Sprachen ergänzbar
API /api/v1/**, Bearer-API-Keys pro Nutzer, OpenAPI unter /api/v1/openapi.json für spätere Mobile-App/Skripte

Branding (fix)

  • Name Flimmer, Motiv: warmes Flimmern des Bildschirms
  • Logo als SVG: abgerundetes Bildschirm-Rechteck, weiches warmes Glühen (Gradient), dezentes Play-Dreieck; Wortmarke in moderner, leicht gerundeter Sans
  • Drei Varianten: Icon, Icon + Wortmarke horizontal, monochrom
  • Favicon + PWA-Icons (inkl. maskable) aus dem Icon generiert
  • Farbwelt: sehr dunkles Blauviolett/Anthrazit als Grund, Signatur = Glow-Gradient Bernstein → Magenta; Light Mode = dieselben Akzente auf warmgrauem Grund
  • Alle Kombinationen müssen WCAG AA erfüllen
  • UI: posterlastig, großzügige Karten mit sanftem Hover-Glow, runde Ecken, weiche Verläufe, ruhige Mikro-Animationen (Aufglimmen beim Abhaken)
  • Logo + Name konsistent in Header, Login, E-Mail-/Notification-Templates, README

Arbeitsregeln

  • Git-Repo mit Remote origin → https://git.wilde-server.de/florian.wilde/flimmer.git, Branch main
  • Conventional Commits (feat:, fix:, chore:, docs: …), Nachrichten deutsch
  • Kleine Commits nach jedem abgeschlossenen Schritt — kein Riesen-Commit
  • .env niemals committen (nur .env.example)
  • CHANGELOG.md im Keep-a-Changelog-Format, SemVer ab 0.1.0; jede Etappe = neue Minor-Version
  • Pro Version: Git-Tag vX.Y.Z + Gitea-Release (via Gitea-MCP, gh/tea sind nicht installiert), Titel = Version, Notes = Changelog-Abschnitt; zusätzlich releases/vX.Y.Z.md ablegen
  • DEVLOG.md: pro Arbeitsphase Start-/Endzeit per date-Befehl (nicht schätzen) + Kurzbeschreibung; je Etappe Summe, am Ende Gesamtübersicht
  • Versionsnummer aus package.json im UI anzeigen (Footer/Einstellungen)
  • Umgebung: Windows + PowerShell/Git-Bash, VS Code. curl → curl.exe. Keine Desktop-Benachrichtigungen.

Etappen

  1. Projektgerüst, Branding, Docker-Compose, DB-Schema, Auth → v0.1.0
  2. TMDB-Anbindung: Suche, Detailimport, Episodendaten, Bild-Cache → v0.2.0
  3. Kern-Tracking: Bibliothek, Status, Episodenfortschritt, Watchlist → v0.3.0
  4. Universen mit Reihenfolgen und Fortschritt → v0.4.0
  5. Dashboard, Kalender, Statistiken → v0.5.0
  6. Benachrichtigungen, Sync-Job, Import/Export, REST-API, PWA-Feinschliff → v0.6.0

Ausdrücklich gewünscht (nicht vergessen!)

  • Bebilderte Anleitung docs/ANLEITUNG.md mit Screenshots der laufenden App (Playwright gegen die geseedete Instanz, Bilder nach docs/screenshots/)
  • Papierkorb (30 Tage) statt hartem Löschen + Undo für „als gesehen markiert"
  • Seed-Skript mit Beispieldaten
  • Backup-Hinweise (DB-Dump) in der README
  • Healthcheck /api/health
  • Öffentliche Profilseite (abschaltbar)
  • Rewatch-Tracking (Durchläufe, bei Serien pro Durchlauf)
  • Streaming-Verfügbarkeit (TMDB Watch Providers), Region konfigurierbar, Standard DE
  • Import: Trakt.tv-Export + CSV; Export: CSV/JSON
  • Benachrichtigungen: SMTP, ntfy, Gotify, generischer Webhook — pro Nutzer
  • Streamingdienste mit konsistenten Akzentfarben/Badges im ganzen UI
  • Optional per ENV: OIDC/SSO (Authelia, Keycloak)
  • Registrierung durch Admin abschaltbar; erster Nutzer wird Admin

Wichtige technische Merkposten

  • Next 16: Request-APIs sind async (cookies(), headers(), params, searchParams). middleware.ts heißt jetzt proxy.ts. Turbopack ist Standard. Breaking Changes stehen in node_modules/next/dist/docs/01-app/02-guides/upgrading/version-16.md.
  • Prisma 7: keine url im Schema — Treiber-Adapter (@prisma/adapter-pg) im Client, URL in prisma.config.mjs. Generator ist prisma-client (TypeScript-Ausgabe nach src/generated/prisma, gitignored). Config bewusst .mjs, damit die CLI im Produktionsimage ohne TS-Loader läuft.
  • Tailwind v4: @theme inline reicht die --fl-*-Variablen durch, @custom-variant dark hängt an [data-theme="dark"].
  • Zwei Verläufe: --fl-gradient für Flächen, --fl-gradient-ink für Text (im Light Mode abgedunkelt, sonst kein AA). Logo-Stops --fl-brand-1/2/3.
  • Dev-Umgebung: Postgres auf localhost:5439 (docker-compose.dev.yml), Dev-Server auf Port 3011 (3000 und 3010 sind von anderen Projekten belegt).
  • Screenshots: node scripts/shot.mjs <url> <ziel.png> [w] [h] [theme]. Achtung: das Skript meldet sich nicht an — bei geschützten Seiten entsteht kommentarlos ein Bild der Anmeldemaske. Für angemeldete Ansichten den Login-Weg aus scripts/screenshots.mjs nachbauen.
  • Next hängt selbst einen Block an diese Datei an — der bleibt drin.

Fortschritt

  • ✅ Etappe 1 (v0.1.0) — Gerüst, Branding, Docker, Schema, Auth. 38 min.
  • ✅ Etappe 2 (v0.2.0) — TMDB: Suche, Import, Episoden, Bild-Cache. 14 min.
  • ✅ Etappe 3 (v0.3.0) — Bibliothek, Status, Episodenfortschritt, Papierkorb. 24 min.
  • ✅ Etappe 4 (v0.4.0) — Universen mit Reihenfolgen, Freigaben. 14 min.
  • ✅ Etappe 5 (v0.5.0) — Übersicht, Kalender, Statistik. 15 min.
  • ✅ Etappe 6 (v0.6.0) — Benachrichtigungen, Abgleich, Import/Export, REST-API, PWA, Anleitung. 31 min.

Alle sechs Etappen abgeschlossen. Gesamtzeit: 2 h 16 min.

  • ✅ Nacharbeiten (v0.7.0/0.7.1) — Docker verifiziert, „hab ich", update.sh. 51 min.
  • ✅ Issue-Runde (v0.8.0) — Passkeys, Jellyfin-Anbindung, Standardreihenfolge, Rückmeldung beim Tippen, Titelraster, Filmsichtung zurücknehmen. 77 min.
  • ✅ Zweite Runde (v0.9.0) — Errungenschaften, Auswahlliste für unbekannte Jellyfin-Titel. 37 min.

Ab v0.8.0 wird issue-getrieben gearbeitet: eigener Branch je Issue, Zeiterfassung in Gitea, Freigabe durch Florian. Details im DEVLOG.

Nützliches für spätere Arbeiten

  • Suche ohne TMDB-Schlüssel ausprobieren: npm run tmdb:stub und dann TMDB_API_KEY=stub TMDB_BASE_URL=http://127.0.0.1:3099/3 PORT=3011 npm run dev
  • Screenshots neu aufnehmen: npm run screenshots (nimmt auf und verkleinert)
  • npm test läuft seriell gegen die Dev-Datenbank, braucht keinen TMDB-Schlüssel
  • Deutsche Anführungszeichen („…") niemals in JS-String-Literalen — das ASCII-Schlusszeichen beendet den String. In JSX-Text und Kommentaren ok.
  • Heredocs im Bash-Tool sind bei langen TSX-Dateien unzuverlässig — dann das Write-Werkzeug benutzen.
  • Wenn Klicks unter Playwright wirkungslos bleiben, liegt es meist nicht am eigenen Code. Beobachtet: gegen npm run dev reagierte unter headless Chromium keine Seite — kein Knopf, nicht einmal der Theme-Umschalter, ohne Seitenfehler und ohne fehlgeschlagene Anfrage. Begleitet vom scheiternden HMR-Socket (ERR_INVALID_HTTP_RESPONSE). Der Zustand ist aber nicht dauerhaft: in einem späteren Lauf gegen denselben Dev-Server funktionierten dieselben Klicks. Der HMR-Fehler tritt in beiden Fällen auf, taugt also nicht als Erklärung. Vorgehen: erst mit Object.keys(el).some(k => k.startsWith("__react")) prüfen, ob überhaupt hydratisiert wurde. Bleibt es dabei, gegen einen Produktionsbau prüfen (npm run build, PORT=3012 npm start) — dort trat es nie auf. Formulare täuschen zusätzlich: die Anmeldung funktioniert auch ohne JavaScript und wirkt deshalb intakt.
  • Vor npm start prüfen, ob der Port noch von einem früheren Lauf belegt ist — sonst startet der neue Server gar nicht und man testet den alten Bau.
  • APP_URL muss zum tatsächlich aufgerufenen Port passen. In der .env steht http://localhost:3010; wer gegen 3011 oder 3012 testet, muss APP_URL mitgeben. Passkeys scheitern sonst am Ursprungsabgleich (500), und der OIDC-Rücksprung zeigt auf die falsche Adresse.
  • Testdaten nach Klickproben wieder herstellen: die Proben schreiben in die geseedete Entwicklungsdatenbank.

This is NOT the Next.js you know

This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in node_modules/next/dist/docs/ (resolved from this file's directory; in monorepos the next package may not be visible from the repo root) before writing any code. Heed deprecation notices.

This block is written and re-added by next dev — verify at node_modules/next/dist/server/lib/generate-agent-files.js. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.