diff --git a/.env.example b/.env.example index a122a26..d02edf4 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,7 @@ +# Manage environment template +# Copy this file to .env, fill in the required values, and export them in your shell +# before running docker compose. Compose files use interpolation, not env_file. + # App APP_VERSION=0.1.0 APP_BUILD_INFO=dev @@ -44,6 +48,7 @@ VITE_OIDC_REDIRECT_URI=https://manage.example.com/oidc/callback VITE_OIDC_POST_LOGOUT_REDIRECT_URI=https://manage.example.com/ VITE_DEV_API_PROXY_TARGET=http://backend:8000 VITE_GRAFANA_URL=https://grafana.example.com +VITE_PROMETHEUS_URL=https://prometheus.example.com # SMTP SMTP_HOST=smtp.example.com diff --git a/README.md b/README.md index 92f3d86..da6be81 100644 --- a/README.md +++ b/README.md @@ -20,14 +20,15 @@ The project consists of two subprojects: ## Features -- Dashboard with now-playing sessions, server monitoring overview, and per-library media counts -- Server monitoring with CPU, IO wait, RAM, network, and disk I/O charts plus a sortable dashboard table covering all configured machines -- Per-machine monitoring settings with local and remote targets managed in the UI, plus backend-collected recent action history per machine +- Configurable dashboard with persisted widgets (Jellyfin activity, backups summary, Grafana deep-links, Prometheus metrics, SSH task output, static text) and shortcuts +- Thin-dashboard observability: Alertmanager alerts, Prometheus target health, machine status, and Grafana deep-links (no in-app charting) +- Per-machine settings for Jellyfin, Jellyseerr, SSH, and monitoring targets - SQLite-indexed media table with full-library sort/filter - Read-only Users tab with Jellyfin as the base source and optional Jellyseerr enrichment - Remote file browser with ffprobe preview and job execution - Jellyfin API integration for library metadata and user identity data -- SSH-based file inspection and remote job templates +- SSH-based file inspection and safe remote job templates +- Addon pages for Grafana, Prometheus, and SSH tasks at `/addons/:addonId` ## Quick Start @@ -39,7 +40,9 @@ Production-style deployment with the frontend serving the SPA and proxying `/api docker compose up --build ``` -Open the app at http://localhost:8080. +Open the app at . + +The production Compose file requires OIDC and Traefik variables; see [Configuration](#configuration) below. Copy `.env.example` to `.env`, fill in the required values, and export them in your shell before running `docker compose up`. Local development with hot reload: @@ -47,9 +50,9 @@ Local development with hot reload: docker compose -f docker-compose.dev.yml up --build ``` -Frontend runs on http://localhost:5173 and the backend on http://localhost:8000. -The backend media index is persisted in a Docker volume (`backend_cache`) so rebuilds and container restarts do not force a full re-index. -Monitoring machine definitions and recent machine activity are stored in the backend so the UI can show one section per configured machine and preserve history across restarts. +Frontend runs on and the backend on . Dev compose disables OIDC by default (`AUTH_ENABLED=false`), so you can open it directly without an identity provider. + +The backend media index and settings database (including monitoring machines, SSH keys, saved tasks, and dashboard widgets) are persisted in Docker volumes so rebuilds and container restarts do not reset state. ### Manual backend/frontend development @@ -76,13 +79,16 @@ The Compose files use environment-variable interpolation. Export the required va Production-style example with shell exports: ```bash -export BACKEND_APP_HOST=manage.example.com +export BACKEND_APP_HOST=api.manage.example.com export FRONTEND_APP_HOST=manage.example.com +export GRAFANA_APP_HOST=grafana.manage.example.com export CERT_RESOLVER=letsencrypt -export VITE_OIDC_ISSUER=https://authentik.example/application/o/manage/ +export VITE_OIDC_ISSUER=https://auth.example.com/application/o/manage/ export VITE_OIDC_CLIENT_ID=manage -export VITE_OIDC_REDIRECT_URI=https://manage.example.com/ +export VITE_OIDC_REDIRECT_URI=https://manage.example.com/oidc/callback export VITE_OIDC_POST_LOGOUT_REDIRECT_URI=https://manage.example.com/ +export VITE_GRAFANA_URL=https://grafana.manage.example.com +export VITE_PROMETHEUS_URL=https://prometheus.manage.example.com docker compose up --build ``` @@ -90,7 +96,7 @@ docker compose up --build Inline one-liner example: ```bash -BACKEND_APP_HOST=manage.example.com FRONTEND_APP_HOST=manage.example.com CERT_RESOLVER=letsencrypt VITE_OIDC_ISSUER=https://authentik.example/application/o/manage/ VITE_OIDC_CLIENT_ID=manage VITE_OIDC_REDIRECT_URI=https://manage.example.com/ VITE_OIDC_POST_LOGOUT_REDIRECT_URI=https://manage.example.com/ docker compose up --build +BACKEND_APP_HOST=api.manage.example.com FRONTEND_APP_HOST=manage.example.com GRAFANA_APP_HOST=grafana.manage.example.com CERT_RESOLVER=letsencrypt VITE_OIDC_ISSUER=https://auth.example.com/application/o/manage/ VITE_OIDC_CLIENT_ID=manage VITE_OIDC_REDIRECT_URI=https://manage.example.com/oidc/callback VITE_OIDC_POST_LOGOUT_REDIRECT_URI=https://manage.example.com/ VITE_GRAFANA_URL=https://grafana.manage.example.com VITE_PROMETHEUS_URL=https://prometheus.manage.example.com docker compose up --build ``` For local development, no SSH key is required unless you want to connect to remote SSH machines later: @@ -124,27 +130,33 @@ SMTP_TIMEOUT=30 # Authentik / OIDC AUTH_ENABLED=true -OIDC_ISSUER_URL=https://authentik.example/application/o/media-library-viewer/ -OIDC_AUDIENCE=media-library-viewer +OIDC_ISSUER_URL=https://auth.example.com/application/o/manage/ +OIDC_AUDIENCE=manage OIDC_JWKS_URL= OIDC_CLOCK_SKEW_SECONDS=30 # Frontend OIDC settings VITE_OIDC_ENABLED=true -VITE_OIDC_ISSUER=https://authentik.example/application/o/media-library-viewer/ -VITE_OIDC_CLIENT_ID=media-library-viewer +VITE_OIDC_ISSUER=https://auth.example.com/application/o/manage/ +VITE_OIDC_CLIENT_ID=manage VITE_OIDC_SCOPE=openid profile email -VITE_OIDC_REDIRECT_URI=http://localhost:8080/ -VITE_OIDC_POST_LOGOUT_REDIRECT_URI=http://localhost:8080/ +VITE_OIDC_REDIRECT_URI=https://manage.example.com/oidc/callback +VITE_OIDC_POST_LOGOUT_REDIRECT_URI=https://manage.example.com/ + +# Grafana / Prometheus URLs used by widget adapters and frontend deep-links +GRAFANA_URL=http://grafana:3000 +PROMETHEUS_URL=http://prometheus:9090 +VITE_GRAFANA_URL=https://grafana.manage.example.com +VITE_PROMETHEUS_URL=https://prometheus.manage.example.com ``` ## Remote server requirements The remote server needs: -- Linux `/proc` and `/sys/block` for monitoring - `/bin/sh` (POSIX shell) -- `python3`, `ffprobe`, `find`, `stat`, `df`, `awk` +- `python3`, `ffprobe`, `find`, `stat`, `df`, `awk` for file inspection and job templates +- SSH access with a key configured in the app's Settings tab The SSH client rejects unknown host keys. Connect manually once first: @@ -167,5 +179,6 @@ cd frontend && npx tsc --noEmit && npm run build - Jellyfin server root URL required (not `/web`). The client strips trailing `/web` defensively. - SSH commands run through `/bin/sh -c` regardless of remote login shell. - Job templates are shell-quoted. Add new templates in `backend/src/media_library_viewer_api/jobs.py`. -- Monitoring collector uses JSONL in `/tmp`, pruned to 7 days / 70k lines. - Root-level Docker Compose files are provided for production (`docker-compose.yml`) and local development (`docker-compose.dev.yml`), and both rely on Compose interpolation rather than `env_file` entries. +- The configurable dashboard stores widget instances in the backend SQLite settings database. New installs seed default Jellyfin activity and Backups widgets automatically. +- Grafana and Prometheus widget adapters use `GRAFANA_URL` and `PROMETHEUS_URL` (backend) and `VITE_GRAFANA_URL` / `VITE_PROMETHEUS_URL` (frontend) for deep-links; no credentials are stored in widget config. diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index b41a536..ff3b15e 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -40,6 +40,7 @@ services: VITE_OIDC_ENABLED: "false" VITE_DEV_API_PROXY_TARGET: "http://backend:8000" VITE_GRAFANA_URL: "http://localhost:3000" + VITE_PROMETHEUS_URL: "http://localhost:9090" ports: - "5173:5173" volumes: diff --git a/docker-compose.yml b/docker-compose.yml index 5febad9..a4706b9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -72,6 +72,7 @@ services: VITE_OIDC_POST_LOGOUT_REDIRECT_URI: ${VITE_OIDC_POST_LOGOUT_REDIRECT_URI:?set VITE_OIDC_POST_LOGOUT_REDIRECT_URI} VITE_DEV_API_PROXY_TARGET: ${VITE_DEV_API_PROXY_TARGET:-http://backend:8000} VITE_GRAFANA_URL: ${VITE_GRAFANA_URL:-https://grafana.example.com} + VITE_PROMETHEUS_URL: ${VITE_PROMETHEUS_URL:-http://localhost:9090} VITE_APP_VERSION: ${APP_VERSION:-0.1.0} VITE_APP_BUILD_INFO: ${APP_BUILD_INFO:-dev} depends_on: diff --git a/frontend/Dockerfile b/frontend/Dockerfile index da40f75..4bce305 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -16,6 +16,7 @@ ARG VITE_OIDC_REDIRECT_URI= ARG VITE_OIDC_POST_LOGOUT_REDIRECT_URI= ARG VITE_DEV_API_PROXY_TARGET=http://backend:8000 ARG VITE_GRAFANA_URL=https://grafana.example.com +ARG VITE_PROMETHEUS_URL=http://localhost:9090 ARG VITE_APP_VERSION=0.1.0 ARG VITE_APP_BUILD_INFO=dev @@ -28,6 +29,7 @@ ENV VITE_API_URL=${VITE_API_URL} \ VITE_OIDC_POST_LOGOUT_REDIRECT_URI=${VITE_OIDC_POST_LOGOUT_REDIRECT_URI} \ VITE_DEV_API_PROXY_TARGET=${VITE_DEV_API_PROXY_TARGET} \ VITE_GRAFANA_URL=${VITE_GRAFANA_URL} \ + VITE_PROMETHEUS_URL=${VITE_PROMETHEUS_URL} \ VITE_APP_VERSION=${VITE_APP_VERSION} \ VITE_APP_BUILD_INFO=${VITE_APP_BUILD_INFO} @@ -53,6 +55,7 @@ ENV VITE_API_URL=/api \ VITE_OIDC_ENABLED=false \ VITE_DEV_API_PROXY_TARGET=http://backend:8000 \ VITE_GRAFANA_URL=http://localhost:3000 \ + VITE_PROMETHEUS_URL=http://localhost:9090 \ VITE_APP_VERSION=0.1.0 \ VITE_APP_BUILD_INFO=dev