Files
watchlist/README.md
T
ki 0bca2eaaa2
CI / test (push) Has been cancelled
CI / docker (push) Has been cancelled
chore: beta release v0.5.0-beta
- 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
2026-07-21 23:34:01 +02:00

164 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# WatchStack
> **v0.5.0-beta** — eine Watchlist für **Bücher, Serien & mehr** — inspiriert von MyAnimeList, aber mit eigenem Konzept.
[![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)
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.
## ✨ Features
- 📚 **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
## ⚠️ 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
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --reload
```
## 🔧 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/
│ ├── __init__.py # __version__
│ ├── main.py # FastAPI-App + Routen
│ ├── database.py # Engine + Session
│ ├── models.py # SQLAlchemy-Modelle
│ ├── schemas.py # Pydantic-Schemas
│ ├── 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
```
## 🛠 Entwicklung
```bash
# Tests (bisher Smoke-Tests ad-hoc; pytest-Suite ist Roadmap)
python -c "from app.main import app; print(app.title, app.version)"
# Code-Style
ruff check app/ # (optional, nicht in requirements)
```
## 📜 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