chore: beta release v0.5.0-beta
CI / test (push) Has been cancelled
CI / docker (push) Has been cancelled

- Bump version to 0.5.0-beta
- Add Apache-2.0 LICENSE (official text) + NOTICE
- Add Docker support: multi-stage Dockerfile + docker-compose
  * non-root user, tini PID 1, gunicorn + uvicorn workers
  * healthcheck, OCI labels, persistent /data volume
- Add GitHub Actions CI (lint/import-check + Docker smoke-test)
- Backend polish:
  * modern lifespan handler (replaces deprecated on_event)
  * explicit sort validation (400 instead of 500)
  * title min_length=1 schema validation
  * configurable data dir + http timeout via env
  * avg_rating helper extracted (DRY)
- Frontend polish:
  * beta badge in title, footer with live version
  * loading spinner on initial fetch
  * updated README, badges, config table, roadmap
This commit is contained in:
ki
2026-07-21 23:34:01 +02:00
parent 56a8d5d302
commit 0bca2eaaa2
19 changed files with 736 additions and 124 deletions
+136 -48
View File
@@ -1,75 +1,163 @@
# WatchStack
Eine Watchlist für **Bücher, Serien & mehr** — inspiriert von MyAnimeList, aber mit eigenem Konzept.
> **v0.5.0-beta** — eine Watchlist für **Bücher, Serien & mehr** — inspiriert von MyAnimeList, aber mit eigenem Konzept.
## Features
[![License: Apache-2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
[![Repo](https://img.shields.io/badge/repo-Vibecode%2Fwatchlist-blue)](https://git.pkop.de/Vibecode/watchlist)
[![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue)](https://www.python.org)
[![Docker](https://img.shields.io/badge/docker-ready-blue)](#-docker)
- 📚 **Bücher**: Titel, Autor, Bände, Kapitel, Seiten, ISBN-Cover von Open Library, Status, Bewertung, Notizen, Genre, Tags
- 📺 **Serien**: Titel, Staffeln, Episoden, Sendezeitraum, Sender/Streaming, Status, Bewertung, Notizen, Genre, Tags
- 🔎 **Suche & Filter**: Volltext, Status, Genre, Tag, Bewertung, Sortierung
- 📊 **Dashboard**: Statistik pro Medium (Anzahl, verteilte Status, Durchschnittsbewertung)
-**Bewertungen**: 110 Skala
- 🏷️ **Genres & Tags**: frei verwaltbar, vielen Einträgen zuweisbar
- 🌙 **Dark Theme** als Default
- 💾 **Lokal**: SQLite, single-user, kein Login nötig
- 🐳 Optional: Docker
WatchStack ist eine **single-user-lokale** Watchlist-App. Bücher und Serien teilen sich eine Oberfläche, ein Datenmodell und eine Such- und Filterlogik. Keine Anmeldung, kein Cloud-Zwang — läuft komplett auf deiner Maschine oder in einem Docker-Container.
## Tech-Stack
## ✨ Features
- **Backend**: Python 3.11+, FastAPI, SQLAlchemy 2.x, SQLite
- **Frontend**: Vanilla HTML + CSS + JavaScript (kein Build-Step), HTMX-light Pattern
- **Cover**: Open Library API (Bücher), URL (Serien)
- 📚 **Bücher**: Titel, Autor, Bände / Kapitel / Seiten, ISBN, Cover via Open Library
- 📺 **Serien**: Staffeln, Episoden, Sender / Streaming, Sendezeitraum, Cover-URL
- 🗂 **Status**: Plan · Laufend · Abgeschlossen · Pausiert · Abgebrochen (5 Stufen, MAL-ähnlich)
-**Bewertungen** 110 mit Auto-Status: 0% → Plan, 100% → Done (+ `end_date`)
- 🔎 **Suche & Filter**: Volltext, Status, Genre, Tag, Sortierung
- 📊 **Dashboard**: Verteilung pro Medium, Durchschnittsbewertung
- 🏷 **Genres & Tags** frei verwaltbar
- 🌙 **Dark Theme** Default, modernes UI mit Hero + Drawer + Modals
- 🐳 **Docker-ready**: Multi-stage Build, non-root, gunicorn + uvicorn-Worker, healthcheck
- 🌐 **CORS offen** für lokale Entwicklung; in Produktion via Reverse-Proxy einschränken
## Quickstart
## ⚠️ Beta-Hinweis
**v0.5.0-beta** bedeutet:
- Kernfunktionalität (CRUD, Suche, Stats, Progress) ist stabil und getestet
- Datenmodell kann sich noch ändern (siehe `models.py` — additive Änderungen wahrscheinlich)
- Datenbank-Migrationen sind **nicht** enthalten — bei Major-Upgrades DB sichern
- Public-API-Pfade stabil; Sub-Ressourcen (Genres/Tags) noch in Bewegung
Bitte Issues und Wünsche im [Repo](https://git.pkop.de/Vibecode/watchlist) melden.
## 🚀 Quickstart
### Option A: Docker (empfohlen)
```bash
docker compose up -d
# → http://localhost:8000
# Oder direkt:
docker build -t watchstack:beta .
docker run -d --name watchstack -p 8000:8000 -v watchstack-data:/data watchstack:beta
```
Die SQLite-DB liegt im benannten Volume `watchstack-data` (Pfad `/data/watchstack.db` im Container). Backups: `docker run --rm -v watchstack-data:/data -v $PWD:/backup alpine tar czf /backup/ws-$(date +%F).tgz /data`.
### Option B: Lokal (Python 3.11+)
```bash
git clone https://git.pkop.de/Vibecode/watchlist.git
cd watchlist
./run.sh # legt venv an, installiert deps, startet auf 127.0.0.1:8000
```
### Option C: Manuell
```bash
# 1) Backend-Env
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
# 2) Starten (legt data/watchstack.db automatisch an + seedet Beispieldaten)
uvicorn app.main:app --reload --host 127.0.0.1 --port 8000
# 3) Browser öffnen
xdg-open http://127.0.0.1:8000 # oder einfach manuell
uvicorn app.main:app --reload
```
## Projektstruktur
## 🔧 Konfiguration (Umgebungsvariablen)
| Variable | Default | Zweck |
|---|---|---|
| `WATCHSTACK_DATA_DIR` | `./data` | Pfad für SQLite-DB (im Container: `/data`) |
| `WATCHSTACK_HOST` | `127.0.0.1` | Bind-Adresse (Docker: `0.0.0.0`) |
| `WATCHSTACK_PORT` | `8000` | HTTP-Port |
| `WATCHSTACK_WORKERS` | `2` | gunicorn-Worker (nur Docker) |
| `WATCHSTACK_HTTP_TIMEOUT` | `8` | Timeout für Open-Library-Lookup (Sek.) |
## 📚 API-Übersicht
| Methode | Pfad | Zweck |
|---|---|---|
| GET | `/api/health` | Service-Info + Version |
| GET | `/api/media` | Liste, Filter via Query-Params |
| POST | `/api/media` | Anlegen (201) |
| GET | `/api/media/{id}` | Detail |
| PATCH | `/api/media/{id}` | Teil-Update |
| DELETE | `/api/media/{id}` | Löschen (204) |
| POST | `/api/media/{id}/progress` | `{"delta":1}` oder `{"set_to":N}` |
| GET | `/api/genres`, `/api/tags` | Taxonomien |
| GET | `/api/stats` | Verteilungen + ⌀-Bewertung |
| GET | `/api/lookup/book?isbn=…` | Cover via Open Library |
**Beispiel** — neuen Eintrag anlegen:
```bash
curl -X POST http://localhost:8000/api/media \
-H 'Content-Type: application/json' \
-d '{
"kind": "book",
"title": "Der Name des Windes",
"author": "Patrick Rothfuss",
"total_pages": 662, "pages_read": 100,
"status": "reading", "rating": 9.0,
"genres": ["Fantasy"], "tags": ["Königsmörder"]
}'
```
Vollständige interaktive Doku: <http://localhost:8000/docs> (Swagger UI, von FastAPI generiert).
## 🏗 Projektstruktur
```
watchlist/
├── app/
│ ├── main.py # FastAPI-App + Routes
│ ├── __init__.py # __version__
│ ├── main.py # FastAPI-App + Routen
│ ├── database.py # Engine + Session
│ ├── models.py # SQLAlchemy-Modelle
│ ├── schemas.py # Pydantic-Schemas
│ ├── crud.py # DB-Logik
│ ├── seed.py # Beispieldaten
│ ├── external.py # Open-Library-API
│ └── static/
│ ├── css/style.css
│ ├── js/app.js
│ └── img/
├── data/ # SQLite-DB (gitignored)
├── tests/
├── requirements.txt
│ ├── crud.py # DB-Operationen
│ ├── external.py # Open-Library-Client
│ ├── seed.py # Demo-Daten
│ └── static/ # Frontend (HTML/CSS/JS)
├── data/ # SQLite-DB (gitignored, Volume im Container)
├── .github/workflows/ # CI
├── Dockerfile # Multi-stage Build
├── docker-compose.yml
├── LICENSE # Apache-2.0 (offizieller Volltext)
├── NOTICE # Copyright + Drittanbieter
└── README.md
```
## API-Übersicht (Auszug)
## 🛠 Entwicklung
| Methode | Pfad | Zweck |
| ------- | --------------------------------- | ------------------------------ |
| GET | `/api/media?type=book\|series` | Liste mit Filter & Suche |
| POST | `/api/media` | Neuen Eintrag anlegen |
| GET | `/api/media/{id}` | Detail |
| PATCH | `/api/media/{id}` | Ändern (Status, Bewertung …) |
| DELETE | `/api/media/{id}` | Löschen |
| GET | `/api/stats` | Aggregierte Stats |
| GET | `/api/lookup/book?isbn=…` | Cover per Open Library |
| GET | `/` | Web-UI |
```bash
# Tests (bisher Smoke-Tests ad-hoc; pytest-Suite ist Roadmap)
python -c "from app.main import app; print(app.title, app.version)"
## Lizenz
# Code-Style
ruff check app/ # (optional, nicht in requirements)
```
MIT
## 📜 Lizenz
**Apache License 2.0** — siehe [LICENSE](./LICENSE) (vollständiger Text) und [NOTICE](./NOTICE) (Drittanbieter-Hinweise).
Kurzfassung: Du darfst das Projekt privat und kommerziell nutzen, verändern, weitergeben — unter Beibehaltung des Copyright-Hinweises und der Lizenz. Es gibt **keine** Patent-Gewähr; Änderungen müssen markiert werden. Volltext in der LICENSE-Datei.
## 🤝 Contributing
PRs willkommen — am besten mit Issue vorab. Bitte:
- Coding-Style einhalten (PEP 8, KISS, DRY)
- Keine externen Tracker; Issues im Gitea-Repo
- Tests für neue Logik (pytest-Suite kommt)
## 🔮 Roadmap
- [ ] pytest-Suite mit Coverage-Report
- [ ] Backup-/Restore-Endpoint
- [ ] Import von MAL-XML / Trakt-Listen
- [ ] Manga als dritte Medienart (Volumes, Chapters)
- [ ] Multi-User mit OIDC-Login (optional, hinter Feature-Flag)
- [ ] Cover-Caching-Proxy
- [ ] Deutsche Übersetzungen der Status-Labels i18n-ready