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>
This commit is contained in:
Housemann
2026-07-11 05:38:37 +02:00
co-authored by Claude Sonnet 4.6
commit 3f253ffe81
45 changed files with 4791 additions and 0 deletions
+201
View File
@@ -0,0 +1,201 @@
# 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.py``COLUMNS`), 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
```text
/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)
```bash
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` ignoriert** → `db_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 nicht**`web` neu bauen + Browser Hard-Reload
Diagnose:
```bash
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