Files
manage/docs/REQUIREMENTS.md
T
2026-05-04 22:25:23 +02:00

193 lines
18 KiB
Markdown

# Manage - Requirements and Decision Log
This is a living document for the project. Update it whenever requirements, UX expectations, architecture decisions, constraints, or implementation plans change.
## Product Goal
Build Manage, a compact web application for browsing a remote Jellyfin media library and inspecting the corresponding media files on disk over SSH. The app should support library metadata review, direct file-system navigation, detailed media metadata inspection, and safe remote maintenance/job workflows.
## Current Phase
Phase 1: Jellyfin media index, SSH-based remote filesystem inspection, server monitoring, and safe job templates.
## Core Requirements
### Jellyfin Library
- Connect to a remote Jellyfin server using an API key.
- Use the Jellyfin server root URL, not the `/web` UI URL.
- Handle API-key auth correctly:
- use `GET /Users` to list available users;
- allow a manual `JELLYFIN_USER_ID` override;
- do not rely on `/Users/Me` for API-key auth.
- List Jellyfin libraries for the selected user.
- Browse library items with search, pagination, media type filtering, and poster cards.
- Show item details including overview, genres, ratings where available, file path, media sources/streams, and raw Jellyfin JSON.
- Provide a Media tab with a paginated inventory table for large libraries.
- Media inventory should show title, series name, season, episode number, type, year, runtime, file size, bitrate, explicit HDR yes/no flag, video codec, resolution, date added, and path where available.
- Media inventory should use Jellyfin metadata only for now; full ffprobe enrichment for all media should be deferred to a cached/background scan to avoid expensive per-item SSH probing.
- Media inventory should support multi-library selection, type, search, full-index sort/order, HDR filter, page size, and page controls.
- Media inventory should use a local SQLite index so sorting/filtering by nested/derived fields such as size, bitrate, HDR, codec, resolution, series, season, and episode can apply to the whole indexed library instead of only one Jellyfin page.
- Media inventory table should be read-only; full-index sorting/filtering should be handled by the service/query layer rather than relying on frontend table sorting.
- Media inventory should use row-based table selection and automatically sync the File browser tab to the selected row's containing directory.
- Media row selection should update both Media selected-row state and File browser location without requiring an extra action button.
- File browser interaction should stay explicit and simple: read-only listing plus explicit Open/Select actions rather than another row-selection grid.
- Use valid Jellyfin `Fields` query values only, because invalid field names can cause `400 Bad Request` responses.
### Users & Communication
- Provide a Users tab that lists all available users the system knows about.
- Use Jellyfin as the base source of truth for the user list.
- Optionally enrich Jellyfin users with Jellyseerr data when Jellyseerr is configured and reachable.
- Be tolerant of Jellyseerr response-shape differences across versions; for example, some endpoints may return a wrapped `{ users: [...] }` payload instead of a raw list.
- Surface whatever contact/identity fields are available from the configured source(s), such as email, avatar/thumb, role/permissions, and notification/contact eligibility.
- Email should only render actual email addresses; usernames or other non-email identifiers should be suppressed instead of shown as email.
- Keep communication actions separate from listing/identity data so the UI can support future email/notification workflows without redesigning the user list.
- SMTP-backed user messages should be queued asynchronously and return immediately; delivery must not block the rest of the API request path.
- The Users tab should expose a live queue status indicator so users can see when the outbound email queue is idle, busy, stopped, or failing.
- The queue status indicator should clearly show the current queue item count.
- The Users tab should include a one-click SMTP test action that validates connectivity/authentication without sending a real message.
- The SMTP test action should visibly show when it is running.
- The SMTP test should surface the chosen protocol/port and, for Fastmail, try both 465/SSL and 587/STARTTLS so configuration mismatches are easier to diagnose.
- Rework the Users data into an internal merged state so user identity can be combined with related now-playing/session data.
- Clicking a now-playing row should navigate to the Users tab and open the matching user detail drawer, keeping the selection deep-linkable.
- Provide an explicit "Open in Users" action in now-playing rows in addition to row-click navigation.
- Provide a compact per-field source summary for the Users detail drawer so it is obvious which backend source supplied name, email, avatar, and access data.
- Jellyseerr user list pagination must use `take`/`skip`, not `page`/`pageSize`.
- The Users tab table should stay compact and readable: center the avatar and email cells, keep backend source diagnostics out of the table itself, and prefer a simpler hand-built row layout when a dense grid makes text positioning awkward.
- The Users table activity column should stay compact and show only a brief status badge for playing/paused/idle/no-session state instead of a multi-line activity summary.
- The Dashboard activity panel should reuse the same compact session-table styling as the Users activity details so the two views feel consistent.
- In the shared session activity table, the user column should come before state, title/type, and device because the user is the most relevant identifier.
- The shared session table should keep a compact overall status summary line above the rows that reports total sessions plus playing, paused, and idle counts.
- The shared session table should keep the session identifier under the user name in a caption instead of giving it a full column, to keep the table tighter.
- The Users tab may open a read-only detail drawer for a selected user, but any communication actions in that drawer should remain clearly disabled/placeholders until the workflow is implemented.
- The frontend shell should use a polished two-row header with branding on the left, user/logout controls on the right, and primary navigation in a dedicated tab row beneath.
- The frontend shell and primary pages should remain responsive and mobile-safe, with compact navigation, stacked controls on narrow screens, and reduced table column density where needed.
- The frontend should hydrate the API bearer token from persisted OIDC user storage immediately on reload so early requests do not race the auth provider lifecycle.
- Backend startup should log a secret-safe configuration summary and request/activity diagnostics so configuration issues can be debugged without exposing API keys.
### Remote Filesystem over SSH
- Connect to a remote media server via SSH.
- Use strict SSH host key behavior; users should connect manually once to populate `known_hosts`.
- Browse remote directories and files rooted at a configurable default media path.
- File browser handoff should map Jellyfin paths to `REMOTE_MEDIA_ROOT` when possible (for example `/media/...` -> `/srv/media/...` when root is `/srv/media`).
- Media index paths should be stored in the SSH-visible form by default, using the same Jellyfin-to-SSH mapping so the Media tab and file browser agree on paths.
- Support a configurable Jellyfin-to-SSH fallback path prefix for cases where `REMOTE_MEDIA_ROOT` mapping alone is not sufficient.
- Support manual path entry and refresh.
- Remote file listing must be compact, structured, and navigable.
- The file table should be read-only.
- The file table should use row selection (single-select) in an AG Grid format consistent with the Media tab.
- The file table should not expose a visible checkbox selection column.
- The file table should not show a visible `selected` column.
- Include a top `[UP] ..` row, when not at `/`, to navigate to the parent directory.
- The selected path should be visibly shown outside the table.
- Selecting a directory row (including `[UP] ..`) should open it immediately.
- Selecting a file row should set the selected file target for metadata/jobs.
- Avoid emojis and hard-to-render characters in labels.
### Remote Listing Controls
- Show compact listing summary information:
- total entries;
- directories;
- files;
- total file size for files in the current directory.
- Support filtering by:
- all entries;
- directories;
- files;
- file extension.
- Support case-insensitive filename search.
- Support sorting by:
- name;
- kind/type;
- size;
- modified time.
- Support ascending/descending sort order.
- Support pagination and configurable rows per page.
### Disk-Level Metadata
- Run `ffprobe` on selected remote files to inspect authoritative media metadata directly from disk.
- When a known video/movie file is selected in the remote file browser, automatically run a blocking `ffprobe` preview and show a spinner while it completes.
- Cache preview results briefly to keep repeated Streamlit reruns responsive; allow users to reload the preview manually.
- Display `ffprobe` results in separate sections instead of one sparse all-streams table:
- container/format summary;
- video streams;
- audio streams;
- subtitle streams.
- Video metadata should include codec, profile, resolution, pixel format, bitrate, frame rate, color range/space/transfer/primaries, side data/HDR-related metadata where available, language, title, and default flag.
- Audio metadata should include codec, profile, channels/layout, sample rate, bitrate, language, title, default, and forced flags.
- Subtitle metadata should include codec, language, title, default, forced, and hearing-impaired flags where available.
- Expose raw `ffprobe` JSON for deeper inspection.
- Keep a manual `ffprobe` action available for selected paths.
- Support `stat` on selected paths.
### Dashboard / Server Monitoring
- Provide a dashboard tab with a compact Jellyfin media library overview and server resource overview.
- Support OIDC login in the frontend using an OIDC client library, with backend JWT validation for protected API requests.
- Persist frontend OIDC auth state across tab reloads by storing the OIDC user and request state in browser localStorage.
- Provide Docker Compose deployment files at the repository root for production and local development.
- Backend Docker deployment should mount a private SSH key and a known_hosts file into the container rather than baking them into the image.
- Production compose should also pass the root `.env` into the backend container so runtime auth settings like `OIDC_ISSUER_URL` are available there, not just at compose interpolation time.
- The backend media index should persist in a Docker volume so a container restart or image rebuild does not force a new full index build.
- The SSH key configuration should support separate directory/name inputs so Docker Compose can mount an arbitrary host SSH directory into `/root/.ssh` while the app assembles the full key path.
- Show Jellyfin media counts for movies, series, and series episodes on the dashboard.
- Show dashboard session activity from Jellyfin, including both currently playing sessions and logged-in idle sessions.
- Activity rows should include user, media title (or `(idle)`), playback state (`playing`/`paused`/`idle`), and whether transcoding is active.
- Provide a dashboard tab with a compact server resource overview over SSH.
- Provide a separate Monitoring tab for detailed resource charts, collector controls, diagnostics, and raw samples.
- The Monitoring tab should request all retained collector samples by default, while the dashboard overview can continue to use a shorter recent window.
- Show CPU and RAM usage for the last hour.
- Show IO wait percentage for the last hour.
- On the dashboard overview, summarize monitoring metrics as 10-minute averages with high/low values for quick inspection.
- Show average and spike/peak values for network throughput and disk I/O.
- Show used, available, and total disk space for the configured media root, falling back to `/`.
- The dashboard should present disk space as a single combined card with the progress/fill bar embedded inside the card and the size breakdown laid out clearly, with centered sub-card text for the Used/Free/Total breakdown and consistent vertical spacing across the dashboard cards.
- The disk usage bar should change color as usage increases so high utilization is easy to notice at a glance.
- The disk usage card should avoid redundant percentage labels next to the bar if the bar itself already communicates the value.
- Render Monitoring charts directly with D3 so the UI can support brush-based range selection, hover tooltips with a moving vertical cursor and snapped point markers, summary chips, and moving averages without a separate wrapper library.
- Use a lightweight remote collector that reads Linux `/proc`, `/sys/block`, and `df` data into a JSONL file under `/tmp`.
- The collector should rotate/prune its JSONL metrics file so it does not grow unbounded; default retention is 7 days with a 70,000-line safety cap.
- The collector should be startable/stoppable/restartable from the dashboard and should not require installing a full monitoring stack.
- Last-hour charts require the collector to have been running long enough to collect samples.
- Because the collector keeps only a bounded history, the Monitoring tab can safely load all retained samples up to the retention/max-lines cap.
- Network throughput should be shown as a combined traffic chart with download and upload lines.
- Network throughput should use bytes-per-second display units such as KB/s, MB/s, and GB/s to avoid bit/byte ambiguity.
- Disk throughput should be shown as a combined I/O chart with read and write lines.
- Network and disk throughput charts should scale values into readable units such as KB/s, MB/s, and GB/s.
- Each Monitoring chart should show compact summary chips such as min/avg/max for quick inspection.
- The Monitoring toolbar should offer quick time-range buttons such as 1h, 8h, 1 day, and 7 days in addition to free brush selection.
- The Monitoring brush selection should persist across data refreshes and tab reloads instead of resetting whenever new samples arrive, and the zoom buttons should stay in sync with the visible brush range.
- The Monitoring brush UI should be stable and remain visible after drags or zoom changes; it should be rendered independently from the chart redraw cycle, with usable resize handles for left/right edges.
### Remote Jobs
- Support running remote jobs over SSH using explicit templates.
- Phase 1 jobs should be safe/read-only by default.
- Avoid arbitrary free-form command execution in the UI.
- Job templates should be centralized in `jobs.py` for future extension.
- Command template values must be shell-quoted before execution.
- Future destructive jobs should require explicit confirmation.
## Decision Log
- 2026-05-03: Reaffirmed that the Monitoring tab charts should be rendered directly with D3 and expose brush-based time-range selection plus moving averages.
- 2026-05-03: Added hover tooltips, summary chips, a moving vertical cursor, snapped point markers, and a selected-range label to the D3 Monitoring charts for faster visual inspection.
- 2026-05-03: Combined network download/upload into one traffic chart and disk read/write into one I/O chart for clearer Monitoring layout.
- 2026-05-03: Confirmed the shared session activity table should keep the session identifier as a caption under the user name instead of a full column.
- 2026-05-03: Confirmed the shared session table should keep the compact overall status summary line above the rows.
- 2026-05-03: Updated the dashboard monitoring cards to show 10-minute averages with high/low subtext instead of only the latest sample.
- 2026-05-03: Added OIDC/JWT auth support plus root-level Docker Compose deployment files for production and dev workflows.
- 2026-05-04: Backend Docker Compose now mounts a host SSH directory into `/root/.ssh` so Paramiko can use a private key and strict host-key checking without baking secrets into the image.
- 2026-05-04: The frontend was adjusted to be more mobile-safe by making the app shell tabs scrollable, stacking header controls on narrow screens, and hiding low-priority table columns on smaller displays.
- 2026-05-04: The dashboard disk space area was consolidated into a single combined card with the progress bar embedded inside the card and the space stats reorganized into clearer, centered sub-panels with consistent vertical spacing.
- 2026-05-04: The disk usage bar was color-coded to shift from green to yellow to red as utilization increases, and the redundant percentage label beside the bar was removed.
- 2026-05-04: The Monitoring brush now persists its selected range in browser storage, avoids resetting when fresh monitoring data streams in, keeps the zoom buttons synchronized with the brush state, and renders the brush UI independently so data refreshes do not make it disappear.
- 2026-05-04: The Monitoring brush was rebuilt as a React overlay with explicit resize handles so mouse dragging is more reliable.
- 2026-05-04: The app header was upgraded to a two-row branded layout with a left logo mark, right-side username/logout controls, and a separate navigation row.
- 2026-05-04: Frontend OIDC storage was switched from session-only defaults to localStorage-backed user/state stores so reloads keep the auth flow intact.
- 2026-05-04: API requests now fall back to the persisted OIDC user store for the bearer token so the first render after reload can avoid spurious 401s.