8bc209b27e
Refreshes the docs that were actively misleading about the current FastAPI + React + service-registry app, and deletes one obsolete design. - CONTRIBUTING.md: full rewrite — Streamlit-era guidance replaced with the current backend (ruff/pytest, src/ layout) + frontend (npm lint/build/test) workflow, service-registry model, and shadcn/Tailwind stack. Mirrors AGENTS.md. - README.md: removed the non-existent /addons/:addonId route (Services page is current); fixed the per-machine Jellyfin wording; replaced the py_compile dev snippet with ruff + pytest / npm lint+build+test. - backend/README.md: updated the structure tree (removed deleted clients/resources.py; added routers backups/services/tasks/widgets, integrations/, models/, widgets/, workers/); dropped the "starts the collector" sentence (MonitoringPoller is decommissioned). - frontend/README.md: corrected the uvicorn module path (main:app -> media_library_viewer_api.main:app). - Deleted docs/superpowers/specs/2026-05-08-obsidian-documentation-design.md (Obsidian vault never built; stack refs MUI/D3/AG Grid all removed). Historical docs (MIGRATION_PLAN, superpowers backup-monitoring, the bannered design/runbook/context files) deferred to a later banner pass.
180 lines
8.0 KiB
Markdown
180 lines
8.0 KiB
Markdown
# Manage Backend API
|
|
|
|
FastAPI backend serving the REST API for Jellyfin media browsing, SSH file inspection, server monitoring, and JWT-protected access for Manage.
|
|
|
|
## Project structure
|
|
|
|
```
|
|
backend/
|
|
├── pyproject.toml
|
|
├── README.md
|
|
├── src/
|
|
│ └── media_library_viewer_api/
|
|
│ ├── __init__.py
|
|
│ ├── main.py # FastAPI app entrypoint
|
|
│ ├── config.py # pydantic-settings config
|
|
│ ├── auth.py # OIDC/JWT + API key auth
|
|
│ ├── dependencies.py # Dependency injection
|
|
│ ├── observability.py # Prometheus metrics + request IDs
|
|
│ ├── logging_utils.py # Structured JSON/text logging
|
|
│ ├── path_utils.py # Jellyfin→SSH path resolution
|
|
│ ├── jobs.py # Job templates
|
|
│ ├── utils.py # Formatting helpers
|
|
│ ├── routers/
|
|
│ │ ├── backups.py
|
|
│ │ ├── dashboard.py
|
|
│ │ ├── files.py
|
|
│ │ ├── jobs.py
|
|
│ │ ├── media.py
|
|
│ │ ├── monitoring.py
|
|
│ │ ├── services.py
|
|
│ │ ├── settings.py
|
|
│ │ ├── tasks.py
|
|
│ │ ├── users.py (+ users_impl.py)
|
|
│ │ └── widgets.py
|
|
│ ├── clients/
|
|
│ │ ├── jellyfin.py
|
|
│ │ ├── jellyseerr.py
|
|
│ │ ├── local.py
|
|
│ │ └── ssh.py
|
|
│ ├── integrations/ # Service-registry definitions
|
|
│ ├── domain/
|
|
│ │ └── media.py
|
|
│ ├── models/ # Pydantic request/response models
|
|
│ ├── services/
|
|
│ │ ├── media_index.py (+ _impl.py)
|
|
│ │ ├── settings_store.py
|
|
│ │ ├── secrets.py # Fernet encryption at rest
|
|
│ │ ├── targets.py # Node Exporter target discovery
|
|
│ │ ├── task_runner.py
|
|
│ │ ├── mail_queue.py (+ mailer.py/_impl.py)
|
|
│ │ ├── backup_alert_engine.py (+ backup_poller.py)
|
|
│ │ ├── known_hosts.py
|
|
│ │ └── db_maintenance.py
|
|
│ ├── widgets/ # Widget sources (dashboard data adapters)
|
|
│ └── workers/ # Background workers (media index)
|
|
└── tests/
|
|
```
|
|
|
|
## Setup
|
|
|
|
```bash
|
|
cd backend
|
|
python -m venv .venv
|
|
source .venv/bin/activate
|
|
pip install -e '.[dev]'
|
|
```
|
|
|
|
## Configuration
|
|
|
|
Set environment variables directly in your shell or a wrapper script before running the app or Compose. The Docker Compose files use interpolation and do not require an `env_file` entry.
|
|
|
|
For local `.env` development, you can still create one if you prefer, but it is optional.
|
|
|
|
```bash
|
|
# Optional backend logging level
|
|
LOG_LEVEL=INFO
|
|
|
|
# Optional SMTP settings for the Users -> message popup
|
|
SMTP_HOST=smtp.example.com
|
|
SMTP_PORT=587
|
|
SMTP_USERNAME=your-smtp-username
|
|
SMTP_PASSWORD=your-smtp-password
|
|
SMTP_FROM_ADDRESS=no-reply@example.com
|
|
SMTP_FROM_NAME=Manage
|
|
SMTP_USE_TLS=true
|
|
SMTP_USE_SSL=false
|
|
SMTP_TIMEOUT=30
|
|
|
|
# Jellyfin, Jellyseerr, and SSH targets are now configured per machine in the app's Settings tab.
|
|
# The backend seeds a local machine automatically, so no global Jellyfin or SSH env vars are required.
|
|
|
|
# Versioning
|
|
# The backend tries to auto-detect its version from installed package metadata.
|
|
# If needed, you can override the displayed version/build markers with APP_VERSION and APP_BUILD_INFO.
|
|
APP_VERSION=0.1.0
|
|
APP_BUILD_INFO=dev
|
|
|
|
# Authentik / OIDC
|
|
AUTH_ENABLED=true
|
|
OIDC_ISSUER_URL=https://authentik.example/application/o/media-library-viewer/
|
|
OIDC_AUDIENCE=media-library-viewer
|
|
OIDC_JWKS_URL=
|
|
OIDC_CLOCK_SKEW_SECONDS=30
|
|
```
|
|
|
|
## Running
|
|
|
|
```bash
|
|
cd backend
|
|
uvicorn media_library_viewer_api.main:app --reload --port 8000
|
|
```
|
|
|
|
Or with PYTHONPATH if not installed:
|
|
|
|
```bash
|
|
PYTHONPATH=src uvicorn media_library_viewer_api.main:app --reload --port 8000
|
|
```
|
|
|
|
API docs available at: <http://localhost:8000/docs>
|
|
|
|
## Docker
|
|
|
|
The repository root includes a production `docker-compose.yml` and a development `docker-compose.dev.yml`.
|
|
The backend media index is stored in the `backend_cache` Docker volume so it survives container restarts and image rebuilds.
|
|
The production compose file expects required environment variables to be supplied via interpolation (shell exports or inline `VAR=value docker compose ...`).
|
|
|
|
### Configuration workflow examples
|
|
|
|
1. Export your runtime variables before launching Compose:
|
|
|
|
```bash
|
|
export BACKEND_APP_HOST=manage.example.com
|
|
export FRONTEND_APP_HOST=manage.example.com
|
|
export CERT_RESOLVER=letsencrypt
|
|
export VITE_OIDC_ISSUER=https://authentik.example/application/o/manage/
|
|
export VITE_OIDC_CLIENT_ID=manage
|
|
export VITE_OIDC_REDIRECT_URI=https://manage.example.com/
|
|
export VITE_OIDC_POST_LOGOUT_REDIRECT_URI=https://manage.example.com/
|
|
|
|
docker compose up --build
|
|
```
|
|
|
|
1. After the API is running, open the app, go to **Settings**, and add machine entries:
|
|
- **Local**: monitors the API host itself without SSH.
|
|
- **SSH**: monitors another machine using a host, username, and a private key pasted directly into the machine settings, with an optional passphrase.
|
|
- The machine editor groups Connection, Monitoring / Files, Jellyfin, Jellyseerr, and Notes under separate headings so each service area is easier to scan.
|
|
- Saving a monitoring machine validates the banner/auth flow and records the first trusted host key into the backend-managed `known_hosts` file.
|
|
- If the host cannot be reached or authenticated, the save flow surfaces the SSH error directly in the dialog.
|
|
- Use **Validate SSH + trust host** in the machine editor before saving if you want to test the banner/auth flow explicitly.
|
|
- The first successful SSH connection uses trust-on-first-use: the backend records that machine's host key into its managed `known_hosts` file automatically, then continues verifying it strictly on later connects.
|
|
|
|
2. Open **Observability** to see Alertmanager alerts, Prometheus scrape targets, and Grafana deep-links for configured machines. Alertmanager, Grafana, and Prometheus are configured as service instances on the **Services** page; system metrics (disk, CPU, memory) are owned by the external observability stack (Prometheus + node_exporter + Grafana), not by the Manage backend.
|
|
|
|
For local development, `docker compose -f docker-compose.dev.yml up --build` does not require an SSH key unless you configure remote SSH machines in the Settings tab.
|
|
|
|
## API Endpoints
|
|
|
|
- `GET /api/dashboard/counts` — Movie/series/episode totals
|
|
- `GET /api/dashboard/libraries` — Per-library breakdown
|
|
- `GET /api/dashboard/now-playing` — Active playback sessions
|
|
- `GET /api/monitoring/machines` — Persistent monitoring machine definitions
|
|
- `GET /api/monitoring/prometheus-targets` — Prometheus scrape targets for remote Node Exporters (consumed by external Prometheus via `http_sd_configs`)
|
|
- `GET /api/monitoring/alerts` — Active Alertmanager alerts summary (resolves the configured alertmanager service)
|
|
- `GET /api/monitoring/alertmanager-status` — Alertmanager cluster/status
|
|
- `GET /api/monitoring/grafana-status` — Grafana service health
|
|
- `GET /api/monitoring/prometheus-status` — Prometheus service health
|
|
- `POST /api/monitoring/alertmanager-webhook` — Receive Alertmanager webhooks (log-only)
|
|
- `GET /api/settings/machines` — Manage machine definitions
|
|
- `GET /api/media/status` — Index status
|
|
- `POST /api/media/build` — Rebuild index
|
|
- `GET /api/media/query` — Query with filters/sort/pagination
|
|
- `GET /api/files/list?path=` — Directory listing
|
|
- `GET /api/files/ffprobe?path=` — ffprobe JSON
|
|
- `GET /api/files/stat?path=` — stat output
|
|
- `GET /api/files/resolve-path?path=` — Path resolution
|
|
- `GET /api/jobs/templates` — Available jobs
|
|
- `POST /api/jobs/run` — Execute a job
|
|
- `GET /api/users` — Jellyfin users with optional Jellyseerr enrichment
|
|
- `GET /api/version` — Backend version/build metadata for the UI
|