Files
HousemannandClaude Sonnet 4.6 3f253ffe81 Initial commit: Filebot Media Browser
Vue 3 + FastAPI Webapp zur Anzeige von Filebot/n8n-Medienmetadaten aus PostgreSQL.
Enthält Frontend, API, Nginx-Config, SQL-Migrationen und Docker-Compose-Setup.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-11 05:38:37 +02:00

6.4 KiB
Raw Permalink Blame History

Projekt-Kontext für KI-Assistenten (Filebot Media Browser)

Diese Datei fasst zusammen, was gebaut wurde und wie das Projekt betrieben wird. Bei weiteren Änderungen zuerst hier und in der README.md nachschlagen.


Zweck

Interne Web-App im Heimnetz zum Anzeigen und Verwalten von Filebot/n8n-Medienmetadaten aus PostgreSQL. Schwerpunkt: Original- vs. neuem Dateinamen nebeneinander (Rename-Kontrolle), plus technische Metadaten (Codec, Bitrate, Auflösung, …).

Produktiv nur auf dem Server unter /opt/nginx_filebot nicht lokal auf dem Mac entwickeln/ausführen.


Infrastruktur

Komponente Details
Server-Pfad /opt/nginx_filebot
Docker Compose Projektname nginx_filebot
Web Nginx, Port 8080 → Container 80
API FastAPI (Python 3.12), intern api:8000
PostgreSQL Host typisch 192.168.30.186
Datenbank n8n_filebot (Name in config)
Schema n8n (nicht public!)
Tabelle movie_files (nicht n8n_filebot!)
Vollqualifizierter Name "n8n"."movie_files"

Config: config/config.yaml (nur auf Server, nicht committen). Beispiel: config/config.example.yaml.

Wichtig: Feld schema in YAML funktioniert, intern heißt es db_schema (Pydantic-Konflikt mit BaseModel.schema).


Tech-Stack

  • Frontend: Vue 3, TypeScript, Vite, TanStack Table
  • Backend: FastAPI, asyncpg
  • Webserver: Nginx (Multi-Stage-Build: Node baut Vue, Nginx liefert aus)
  • DB: PostgreSQL

Datenbank-Spalten (relevant)

Standard-Spalten aus n8n/Filebot (siehe api/main.pyCOLUMNS), u. a.:

  • id, file_name_original, file_name_new
  • movie_rating, movie_votes
  • Video/Audio: standard_video_format, video_codec_library, audio_codec, container_format, Bitraten, Auflösung, …
  • created_at

Zusätzlich per Migration:

Spalte Typ Bedeutung
seen_at TIMESTAMPTZ NULL NULL = ungesehen; gesetzt = in UI als gesehen markiert
cover_url TEXT NULL Poster-URL (z. B. TVMaze), erste Tabellenspalte

SQL-Dateien: sql/001_add_seen_at.sql, sql/002_add_cover_url.sql

n8n: Bei INSERT/UPDATE seen_at und cover_url nicht ungewollt überschreiben.


UI-Funktionen (Stand Projektabschluss)

Layout

  • Desktop: Tabelle mit vielen Spalten; erste Spalte Cover (ca. 76×114 px), dann Dateinamen-Paar
  • Mobile (≤900px): Karten mit Cover links
  • Helles Dark-Theme (frontend/src/styles.css, CSS-Variablen)

Dateinamen

  • Immer Original und Neu sichtbar (NamePair.vue)
  • Kein „Rename prüfen“-Badge mehr (Heuristik entfernt)

Filter (FilterBar.vue)

  • Textsuche in Original + Neu
  • Buttons (keine Dropdowns): Format, Codec, Container
  • Datum/Uhrzeit VonBis mit Kalender-Popup + HH:MM-Dropdowns (DateTimeRangeFilter.vue)
  • Gesehen: „Nur ungesehen“, „Alle als gesehen“, Zähler „X neu“
  • Aktualisieren / Zurücksetzen

Gesehen-Status

  • Ungesehene Zeilen: blauer linker Rand + Hintergrund (row-unseen / card-unseen)
  • Tippen auf Zeile (nicht Scroll): Toggle gesehen/ungesehen via PATCH /api/records/{id}/seen
  • Mülleimer löscht Eintrag (kein Toggle)

Tabelle

  • Sortierung Standard: created_at absteigend (neueste oben)
  • Schnellfilter in geladenen Daten
  • Löschen: roter Mülleimer pro Zeile → DELETE /api/records/{id}

Cover

  • CoverImage.vue: lazy load, Platzhalter bei Fehler, URL-Bereinigung (extra " entfernen)

API-Endpunkte

Methode Pfad Beschreibung
GET /api/health DB-Ping
GET /api/status Diagnose (Config, Tabellenliste bei Fehler)
GET /api/columns Spaltenliste
GET /api/records Daten; Query: search, format, codec, container, created_from, created_to, unseen_only
GET /api/filters Distinct-Werte für Filter-Buttons
PATCH /api/records/{id}/seen Body: { "seen": true | false }
POST /api/records/mark-all-seen Alle gefilterten als gesehen
DELETE /api/records/{id} Zeile löschen

Nginx proxied /api/http://api:8000/api/.


Projektstruktur

/opt/nginx_filebot/
├── docker-compose.yml      # absolute Pfade für Server
├── config/
│   ├── config.example.yaml
│   └── config.yaml         # nur Server
├── api/
│   ├── main.py
│   ├── config.py
│   ├── Dockerfile
│   └── scripts/list-tables.py
├── frontend/
│   └── src/
│       ├── App.vue
│       ├── api.ts
│       ├── components/     # DataTable, FilterBar, CoverImage, …
│       ├── composables/     # (useSeenObserver entfernt)
│       └── utils/
├── nginx/
│   ├── Dockerfile          # Multi-Stage Frontend-Build
│   └── nginx.conf
├── sql/                    # DB-Migrationen
├── PROMPT.md               # diese Datei
└── README.md

Deployment (Kurz)

cd /opt/nginx_filebot
docker compose up -d --build
# Browser: http://<server-ip>:8080

Nach Frontend-Änderungen: docker compose up -d --build web
Nach API-Änderungen: docker compose up -d --build api
Oft: komplett --build


Typische Fehler (bereits aufgetreten)

  1. relation "n8n_filebot" does not exist → Tabelle heißt movie_files, DB n8n_filebot
  2. schema: n8n ignoriertdb_schema / API-Fix mit validation_alias
  3. Leere DB-Liste → falsche Datenbank oder leere Tabelle
  4. API 500 ohne seen_at/cover_url → SQL-Migration ausführen
  5. Design ändert sich nichtweb neu bauen + Browser Hard-Reload

Diagnose:

docker compose logs api --tail 50
curl -s http://localhost:8080/api/status
docker compose exec api python /app/scripts/list-tables.py

Konventionen für weitere Entwicklung

  • Antworten an Nutzer oft auf Deutsch
  • Keine Commits unless asked
  • config.yaml nie ins Git
  • Server-only Deployment kommunizieren
  • Nach Änderungen: welche Dateien hochladen + docker compose up -d --build
  • Minimale Diffs, bestehenden Stil beibehalten (Vue 3 Composition API, FastAPI async)

Nutzer-Präferenzen (aus Session)

  • Rename-Kontrolle: file_name_original + file_name_new immer sichtbar
  • Filter als Buttons, nebeneinander (mobil gestapelt)
  • Gesehen per Tap, nicht Scroll
  • Cover in erster Spalte, etwas höhere Zeilen
  • Etwas helleres UI-Theme