Files
manage/docs/REQUIREMENTS.md
T
2026-05-07 10:17:58 +02:00

28 KiB

Manage - Requirements and Decision Log

This is a living document for the project. Update it whenever requirements, UX expectations, architecture, 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.
  • Dense management surfaces such as Actions and Settings should prefer compact tabbed or split-pane layouts over long single-column forms when that improves scanning and editing speed.
  • Tab rails and subtabs should feel like a polished admin console: compact, clearly selected, and visually consistent across the app.
  • When a setting subsection is not applicable to the currently selected mode or service, the UI should hide those fields rather than leaving them visible but disabled.
  • 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.
  • The Media tab should persist its search/filter/sort/pagination state across reloads and tab switches.
  • The File Browser should persist its current directory and selected file across reloads and tab switches.
  • 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, but synthesize and persist the managed known_hosts file from configured SSH machines instead of requiring users to mount their own known_hosts file.
  • 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 a sortable table-style server resource overview covering all configured monitoring machines.
  • 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.
  • SSH private keys should be managed as reusable saved secrets in Settings, independent of any one machine, and SSH machines should select from that saved-key list.
  • The web UI should allow both importing an existing private key and generating a new SSH keypair for that saved-key list.
  • Saved SSH keys should display their derived public key, fingerprint, and machine usage count so administrators can audit them at a glance.
  • The app should support optional SSH private key passphrases alongside the stored key material.
  • The Settings tab should include a destructive local-database reset action protected by multiple acknowledgements and a typed confirmation phrase.
  • 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.
  • Compose deployment should not require env_file; required values should be supplied through environment interpolation or inline shell exports.
  • The SSH key configuration should move from machine-local text areas to a saved SSH key registry; directory/name inputs remain only as legacy compatibility fields.
  • 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, raw samples, and per-machine recent action history gathered automatically by the backend.
  • Expose backend poller status/configuration so the dashboard and Monitoring page can surface whether monitoring snapshots are being gathered automatically.
  • The Monitoring tab should present one section per configured machine, and local vs remote machines should be treated the same in the UI with different connection/configuration data.
  • Provide a Settings tab where monitoring machines can be added, edited, enabled/disabled, or deleted persistently.
  • The app should start with no pre-seeded monitoring machines; users must explicitly add a local or SSH target before Monitoring shows anything.
  • 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.
  • Machine definitions for monitoring should persist in backend-owned storage so local and remote monitoring targets survive restarts.
  • Monitoring machine actions/history should also persist in backend-owned storage so each machine section can show recent status/metrics/disk/collector activity.
  • The backend should periodically poll defined monitoring machines itself; no remote agent or push model should be required.
  • 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.

Saved Actions / Remote Jobs

  • Provide an Actions tab for predefined server tasks that users can save and run later.
  • The initial task types should support shell commands and Python scripts, while keeping the design flexible for future task types.
  • Avoid arbitrary free-form command execution for ad-hoc execution; tasks should be stored records with an explicit name, type, content, enabled flag, default machine, and notes.
  • Support running tasks against either the local API host or a configured SSH machine using the same machine registry used by Monitoring.
  • Command/script content should be executed through the existing safe process helpers and shell-quoted where applicable.
  • Future destructive actions should require explicit confirmations or dry-run style safeguards.
  • Job templates should remain centralized in jobs.py for future extension.
  • Remote job template values must be shell-quoted before execution.

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 Media tab now persists search/filter/sort/pagination state, and the File Browser now persists the current directory plus selected file across reloads and tab switches.
  • 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.
  • 2026-05-04: Oversized frontend/backend modules were split into thin re-export entrypoints plus implementation modules to keep page/router/service code maintainable without changing behavior.
  • 2026-05-04: The Monitoring charts and File Browser were also split into implementation modules behind thin entrypoints so the larger UI surfaces stay easier to navigate without changing runtime behavior.
  • 2026-05-06: Monitoring became machine-based: a Settings tab now persists local/remote machine definitions, and the Monitoring tab renders a section per configured machine so API-host and remote targets are handled through the same UI model.
  • 2026-05-06: Compose files were switched away from env_file and now rely on environment-variable interpolation, so deployments can be driven entirely by shell exports or inline environment values.
  • 2026-05-06: Monitoring endpoints now translate machine-specific transport/runtime failures into user-facing HTTP errors so a broken machine only affects its own section instead of taking down the whole Monitoring page.
  • 2026-05-06: Documentation now includes explicit Compose interpolation examples plus a monitoring-machine configuration workflow showing how to add local and SSH machines in the Settings tab.
  • 2026-05-06: Monitoring machine action history was added so each machine section can display recent operation results, durations, and failures alongside the charts.
  • 2026-05-06: Monitoring history collection was shifted to a backend-scheduled poller that reads the defined machines over SSH/local shell and stores snapshots in SQLite, avoiding any remote agent or push requirement.
  • 2026-05-06: The dashboard monitoring section was converted from summary cards into a table of all configured machines, paired with backend poller status so the whole fleet can be reviewed at a glance.
  • 2026-05-06: The dashboard monitoring table now shows 10-minute averages with min/max subtext and can be sorted by machine, status, and metric columns.
  • 2026-05-06: The Monitoring page now includes a poller-health badge in the header so users can quickly see whether backend collection is active.
  • 2026-05-06: The dashboard monitoring table now renders each metric summary with compact stacked low/high lines to keep the table narrower, and the activity/session table no longer hides columns on mobile so all details remain available.
  • 2026-05-06: The dashboard monitoring table now renders the 10-minute value as the visual focus and keeps the low/high lines smaller as supporting detail.
  • 2026-05-06: The file browser and media routes now support machine-specific SSH/Jellyfin selection via the request machine id, and the backend resolves clients from configured machines before falling back to legacy env-based defaults.
  • 2026-05-06: Application settings now include per-machine Jellyfin/Jellyseerr configuration and multi-select service roles so the UI can manage app hosts from the same machine registry.
  • 2026-05-06: The app shell now uses an Applications top-level tab with a Jellyfin subtab for media/library work and a placeholder Nextcloud subtab for future expansion.
  • 2026-05-06: The settings model now treats Jellyfin/Jellyseerr as machine-level configuration instead of global env-only values, so app hosts can be edited alongside other machine services.
  • 2026-05-06: The backend now synthesizes a managed known_hosts file from configured SSH machines at startup, avoiding a mounted SSH directory while keeping strict host-key verification enabled.
  • 2026-05-06: SSH credentials were moved toward reusable saved key records in Settings, so machines can point at a shared SSH key instead of storing their own duplicate private key text.
  • 2026-05-06: The Settings page now includes an SSH key registry UI with create/edit/delete flows and a generate-key action so users can make a reusable key directly in the web interface.
  • 2026-05-06: Saved SSH keys now surface a derived public key, fingerprint, and per-key machine usage count in the Settings UI for easier auditing.
  • 2026-05-06: The dev Compose stack now starts without any SSH key material at all unless a user later configures remote SSH machines.
  • 2026-05-06: The Settings page now exposes a protected local-database reset flow that requires several explicit acknowledgements and a typed confirmation phrase before it can delete the cached app databases.
  • 2026-05-06: The Actions page was redesigned into a compact tabbed workspace with a left tab rail of saved actions, and both new-action creation and editing now open in popups instead of inline forms.
  • 2026-05-06: Closing an edited Action popup now warns before discarding unsaved changes.
  • 2026-05-06: The Settings page was reworked into a compact tabbed layout with separate Machines, SSH Keys, and Danger Zone sections, and irrelevant machine/service fields now hide when that mode or service is not selected.
  • 2026-05-06: The Settings machine list was converted into a compact table with popup editing so the page no longer repeats the full machine form for every entry.
  • 2026-05-06: The Monitoring page was reworked into an overview tab plus one tab per configured machine, so each machine gets its own monitoring page.
  • 2026-05-06: The Actions page now shows a visible empty-state container when no action is selected, and the Monitoring tabs were returned to the app's standard tab styling.
  • 2026-05-06: The Monitoring tab spacing was tightened and the Applications page was updated to match the app's standard card-and-tab design.
  • 2026-05-06: The dashboard library stats were moved into the Jellyfin Applications tab above the media table, and the dashboard activity panel was relabeled as Jellyfin activity.
  • 2026-05-06: The dashboard, Monitoring overview, Applications, and File Browser layouts were normalized around shared titled containers, with Monitoring showing the fleet overview before machine tabs and File Browser using machine tabs with Browser/Media info/Jobs stacked in each machine view.
  • 2026-05-06: The Applications and Monitoring tab containers were refactored into a reusable bordered tab-card pattern so the active tab's content sits inside the same card as the tab rail.
  • 2026-05-06: The Settings Machines tab was changed from a repeated form layout to a left-hand machine list with a right-hand details panel and popup editing.
  • 2026-05-06: The app no longer seeds a default local monitoring machine; a fresh database starts with an empty machine list until the user creates one.
  • 2026-05-06: The File Browser was reworked into Browser / Media info / Jobs subtabs.
  • 2026-05-06: The app shell received a small density pass that tightened container padding and tab widths to make the whole site feel more compact.
  • 2026-05-06: The tab rails across Actions, Monitoring, Settings, and Files were restyled to be more enterprise-console-like with compact pills, clearer active states, and reduced visual noise.
  • 2026-05-06: Added an Actions tab for saved server tasks, with backend persistence, per-task run history, and support for shell/Python task types on either local or SSH machines.
  • 2026-05-06: Reusable dialog footers now keep cancel on the left and confirm on the right, and hover edit buttons now appear on the right edge of editable list rows in Actions and Settings.
  • 2026-05-06: Library stats, Jellyfin activity, and Monitoring overview now use shared section-container patterns so subcontainers stay consistent across the app.