Web UI rework. Shared-components slice (drift prevention): - Migrate SectionCard, SelectionRailCard, TabbedCard, MetricCard, DiskSpaceCard, HoverEditButton, DialogFooter, ConfirmDialog, LibraryOverview, NowPlaying, SessionActivityPanel off @mui - HoverEditButton: MUI IconButton + EditOutlined -> Button + lucide Pencil - Status mapping uses the success Badge variant (chart-2) for healthy - Exported APIs preserved so consuming pages still compile (no page edits) - 11 behavioral Vitest component tests added Gate: build + lint + test green.
Manage
Manage is a media and server operations tool with Jellyfin integration, SSH file inspection, server monitoring, and safe remote job templates.
See docs/REQUIREMENTS.md for the living requirements, decisions, and planning history.
See docs/MIGRATION_PLAN.md for the FastAPI + React architecture plan.
Project policy/docs:
- License:
LICENSE(MIT) - Contributing guide:
CONTRIBUTING.md
Architecture
The project consists of two subprojects:
backend/— FastAPI Python API (seebackend/README.md)frontend/— React + TypeScript SPA (seefrontend/README.md)archive/— Original Streamlit prototype (preserved for reference)
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
- 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
Quick Start
Docker Compose (recommended)
Production-style deployment with the frontend serving the SPA and proxying /api to the backend. The compose files rely on environment-variable interpolation, so export the required values in your shell before running them (no env_file is needed):
docker compose up --build
Open the app at http://localhost:8080.
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.
Manual backend/frontend development
cd backend
python -m venv .venv
source .venv/bin/activate
pip install -e '.[dev]'
uvicorn media_library_viewer_api.main:app --reload --port 8000
cd frontend
npm install
npm run dev
Configuration
The Compose files use environment-variable interpolation. Export the required variables in your shell or pass them inline; a .env file is optional, not required.
Compose examples
Production-style example with shell exports:
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
Inline one-liner example:
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
For local development, no SSH key is required unless you want to connect to remote SSH machines later:
docker compose -f docker-compose.dev.yml up --build
Example environment variables:
# 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.
#
# Remote SSH machines can store their private key and optional passphrase directly in Settings,
# so no SSH key mount is required for normal use.
# 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
# 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_SCOPE=openid profile email
VITE_OIDC_REDIRECT_URI=http://localhost:8080/
VITE_OIDC_POST_LOGOUT_REDIRECT_URI=http://localhost:8080/
Remote server requirements
The remote server needs:
- Linux
/procand/sys/blockfor monitoring /bin/sh(POSIX shell)python3,ffprobe,find,stat,df,awk
The SSH client rejects unknown host keys. Connect manually once first:
ssh user@host
Development
# Backend
cd backend && PYTHONPATH=src python -m py_compile src/media_library_viewer_api/main.py
# Frontend
cd frontend && npx tsc --noEmit && npm run build
Notes
- Jellyfin server root URL required (not
/web). The client strips trailing/webdefensively. - SSH commands run through
/bin/sh -cregardless 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 thanenv_fileentries.