From bf1fa04f1180c366641d659268012e8939670457 Mon Sep 17 00:00:00 2001 From: Mathieu Moran Date: Mon, 14 Sep 2026 19:41:35 -0400 Subject: [PATCH] Document the new FastAPI server and WebUI --- README.md | 77 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 5880218..ade08b4 100644 --- a/README.md +++ b/README.md @@ -404,52 +404,68 @@ Requirements & behaviour: ## Server setup -The catalog + store API is a single-file, stdlib-only HTTP server -(`app/api.py`) — no pip install needed on the server. +The server is a **FastAPI** app (`server/`) with an admin **WebUI** and a +JSON API. It owns the catalog, metadata, covers, and the game/video store +archives, and serves them to the desktop app. Users log in with a username + +password; the app holds a **per-user API token** (roles: `admin`, `editor`, +`user`). + +Run it directly (dev): ```bash -PSP_DATA_DIR=/data \ -PSP_DATS_DIR=/data/dats \ +pip install -r requirements-server.txt PSP_DB_PATH=/data/library.sqlite \ PSP_COVERS_DIR=/data/covers \ -PSP_GAMES_ROOTS=/data/umd_games \ -PSP_VIDEO_ROOTS=/data/umd_videos \ PSP_STORE_DIR=/data/store \ -PSP_API_TOKEN= \ -python3 -m app.api --host 0.0.0.0 --port 8000 +PSP_STORE_VIDEOS_DIR=/data/store_videos \ +PSP_ADMIN_USERNAME=admin \ +PSP_ADMIN_PASSWORD= \ +uvicorn server.main:app --host 0.0.0.0 --port 8000 ``` -Endpoints: +On first boot it creates the `PSP_ADMIN_USERNAME` account (log in and change +the password). The admin WebUI lives at `/`: + +- **Dashboard** — storage, catalog counts, recent downloads. +- **Games & Videos** — browse the catalog, edit metadata, upload covers. +- **Store** — upload/delete game and video archives. +- **Users** — create users, assign roles, reset passwords. + +API endpoints: | Endpoint | Description | |---|---| -| `GET /api/summary` | release counts per system | +| `POST /api/auth/login` | username/password → API token | +| `GET /api/auth/me` | current user | +| `GET /api/users`, `POST`, `PATCH`, `DELETE` | user management *(admin)* | | `GET /api/releases?system=&q=&limit=&offset=` | search the catalog | -| `GET /api/releases/` | one release + its rom hashes | -| `GET /api/library?system=&refresh=` | your scanned library | -| `GET /api/cover/` | cover image (fetched on demand) | -| `GET /api/covers/.zip` | offline cover bundle (public) | -| `GET /api/store` | list store archives *(token)* | -| `GET /api/store/download/` | stream one archive *(token)* | +| `GET /api/releases/` | release detail + metadata + rom hashes | +| `PATCH /api/releases/` | edit metadata *(editor+)* | +| `GET /api/cover/` | cover image | +| `POST /api/cover/` | upload/replace cover *(editor+)* | +| `GET /api/store?system=games|videos` | list store archives | +| `GET /api/store/download//` | stream an archive *(user+)* | +| `POST /api/store/upload`, `DELETE /api/store//` | manage archives *(editor+)* | +| `GET /api/stats` | dashboard numbers *(admin)* | -Token protection: set `PSP_API_TOKEN`; the client sends -`Authorization: Bearer `. Leave it unset to allow anonymous access -(not recommended). +Authentication is `Authorization: Bearer ` for the API and a session +cookie for the WebUI. ### Docker (Unraid) -`docker-compose.yml` builds the API image and attaches it to Unraid's `br0` -macvlan bridge so it gets its own LAN IP (e.g. `192.168.1.100`, plain HTTP on 8000): +`docker-compose.yml` builds the server image and attaches it to Unraid's `br0` +macvlan bridge so it gets its own LAN IP: ```bash # in /path/to/psppt/ -cp .env.example .env # then edit: LAN IP, share paths, API token +cp .env.example .env # then edit: LAN IP, share paths, admin password docker compose up -d --build ``` -The compose file reads the LAN IP and Unraid share paths from `.env` and -mounts them into `/data/store`, `/data/umd_games` and `/data/umd_videos` -(the store is mounted read-only). +The compose file reads the LAN IP and Unraid share paths from `.env` and mounts +them into `/data/store`, `/data/store_videos`, `/data/umd_games` and +`/data/umd_videos` (the store mounts are writable so the WebUI can manage +archives). ### TLS (optional) @@ -460,10 +476,13 @@ ports 80/443 on your router to it. ### Client -In the GUI: **Settings → Store** → enter the **Server URL** (e.g. -`http://:8000` or `https://psp.example.com`) and the same **API -token**, then pick **Server** in the Store tab's source selector. Use -**Archive.org** or **Local folder** the same way. +In the GUI: **Settings → Store** → enter the **Server URL**, **Server +username**, and **Server password**, then **Save settings** (the app logs in +and stores the per-user token). Pick **Server** in the Store tab's source +selector. When a server is configured it is authoritative for covers and +metadata — if it's unreachable the app shows an error instead of falling back +to public sources. Use **Archive.org**, **Local folder**, or **NoPayStation** +the same way as before. ## PSP Sync