12 KiB
UMM UX Flows — Implemented & Tested
Last verified: 2026-04-22 (deployed build, backend healthy)
Navigation
| Route | Page | Nav Label |
|---|---|---|
/ |
Dashboard | Dashboard |
/library |
Library | Library |
/library/:type/:id |
Media Detail | (via Library click) |
/discover |
Discover | Discover |
/calendar |
Calendar | Calendar |
/queue |
Download Queue | Queue |
/search |
Search Indexers | Search |
/activity |
Activity | Activity |
/requests |
Requests | Requests |
/blocklist |
Blocklist | Blocklist |
/settings |
Settings | Settings |
Page-by-Page Flows
Dashboard (/)
API: GET /api/dashboard (200 OK)
- 8 stat cards: Movies, TV Series, Music, Books, Active Downloads, Missing, Upgrades Available, Total Storage
- Auto-fetches on mount
- Skeleton loading while fetching
- Error banner with retry on failure
Library (/library)
API: GET /api/media?page=1&page_size=50 (200 OK)
- Search input with 300ms debounce
- Type filter: All, Movie, Series, Music, Book, Audiobook, Podcast, Photo, Other
- Status filter: All, Available, Unavailable, Downloading, Failed
- Paginated table (50 per page)
- Each row: Title (click → detail), Type, Status badge, Quality, Monitor toggle
- Monitor toggle: optimistic update, rollback on error with toast
- Empty state messages for no results vs empty library
Media Detail (/library/:type/:id)
API: GET /api/media/:type/:id/detail (200 OK)
5 tabs (4 for non-series):
Overview tab:
- Poster image (or letter placeholder)
- Title, year, original title
- Status badge, monitored indicator
- TMDB rating, genres
- Quality profile name
- Current quality / desired quality
- Synopsis text
Search tab:
- Auto-searches indexers for media title
- Results via
ReleaseSearchResultscomponent - Sortable by quality, size, seeders, age
Files tab:
- File table: name, quality, size, source, codec, subtitles
- Per-file subtitle badges (language code, SDH, Forced, source)
- "Search" button per file → subtitle search modal
- "Download" button per subtitle result
- "Extract All Subtitles" button (extracts embedded subs)
Episodes tab (series only):
- Episodes grouped by season
- Columns: episode #, title, status, monitored, has file, quality
History tab:
- Timeline with color-coded badges: Grab, Import, Download, Failed, Upgrade, Blocked, Error
- Relative timestamps (Xm ago, Xh ago, Xd ago)
Header actions:
- "Refresh Metadata" button →
POST /api/media/:type/:id/refresh-metadata - "Delete" button → confirmation modal →
DELETE /api/media/:type/:id→ redirect to Library
Discover (/discover)
API: GET /api/discover/trending?type=movie&page=1 (401 — requires API key auth)
API: GET /api/discover/popular?type=movie&page=1 (401 — requires API key auth)
- Trending / Popular tab toggle
- Movie / Series type filter
- Poster grid with hover overlay (title, year, rating, "Add to Library" button)
- Green checkmark badge for items already in library
- "Add to Library" →
POST /api/discover/add→ toast feedback - Paginated (prev/next, up to page 10)
Note: Requires API key authentication. Frontend does not currently send API keys, so this flow will 401 in production.
Calendar (/calendar)
API: GET /api/calendar?month=2026-04 (200 OK)
- Monthly grid (6 rows × 7 cols)
- Navigation: prev/next month, "Today" button
- Events color-coded by type: movie (indigo), series (emerald), music (amber), audiobook (rose), podcast (violet)
- Click event → navigate to media detail
- "Today" date highlighted with indigo ring
- "+N more" for days with >3 events
Download Queue (/queue)
API: GET /api/queue (200 OK)
- Tabs: All, Downloading, Pending, Failed, Imported, History
- Auto-refresh every 5 seconds
- Per-item: release title, status badge, download client, quality, size
- Progress bar for downloading items
- Error message display for failed items
- Actions: Cancel (with confirmation modal), Retry, Retry All Failed, Clear Completed
- "Check for Completed Downloads" →
POST /api/imports/trigger - Import History tab with pagination (
GET /api/imports/history)
Search Indexers (/search)
API: GET /api/releases/search?query=... (500 — "no enabled indexers available" when none configured)
- Free-text search across all enabled indexers
- Sortable columns: Quality, Title, Size, Indexer, Seeders, Age
- "Select & Grab" button per result → opens media selector modal
- Modal: debounced library search
- Select media item →
POST /api/releases/grab→ toast
- Empty state for no query, no results, loading skeleton
Note: Returns 500 when no indexers are configured. This is expected behavior.
Activity (/activity)
API: GET /api/activity?page=1&page_size=50 (200 OK)
- Paginated event log (50 per page)
- Type filter dropdown: All, Grabs, Imports, Downloads, Failures, Upgrades, Safety Blocks, Errors
- Color-coded badges: Grab (blue), Import/Download (green), Failed/Error (red), Upgrade (purple), Blocked (orange)
- Relative timestamps
Requests (/requests)
API: GET /api/requests?page=1&page_size=20 (401 — requires API key auth)
- Filter tabs: All, Pending, Approved, Fulfilled, Rejected
- "+ New Request" modal:
- Title (required), Type (7 options), Year, Quality Profile dropdown, Root Folder dropdown
- Submit →
POST /api/requests
- Per-request card: title, year, status badge, requester, time ago, quality profile, root folder
- Actions for pending: Approve (green) →
PUT /api/requests/:id/approve, Reject (red, with confirmation) →PUT /api/requests/:id/reject - Withdraw link for pending/approved →
DELETE /api/requests/:id
Note: Requires API key authentication. Frontend does not currently send API keys.
Blocklist (/blocklist)
API: GET /api/blocklist?page=1&page_size=50 (200 OK)
- Paginated table (50 per page)
- Checkboxes for bulk selection (select all toggle)
- Per-row: release title, indexer, quality, reason, date, delete button
- Bulk "Delete Selected" →
DELETE /api/blocklist/:idper item - "Clear Expired" →
DELETE /api/blocklist/expired - "Clear All" → confirmation modal →
DELETE /api/blocklist
Settings (/settings)
8 sections in 2-column grid layout:
Notifications
API: GET /api/notifications/channels (200 OK)
- List channels with enable/disable dot, name, type badge (webhook/telegram), config preview
- Inline edit: name, URL/bot token/chat ID, event type checkboxes (8 types), save/cancel/test/delete
- Add channel: name, type selector, URL or bot token + chat ID, event type checkboxes
- Test button →
POST /api/notifications/channels/:id/test
Indexers
API: GET /api/indexers (200 OK)
- List with enable/disable dot, name, implementation badge (torznab/newznab/cardigann), URL
- Inline edit: name, URL, API key (masked), enable toggle, save/cancel/test/delete
- Add indexer: name, implementation selector (Newznab, Torznab, Cardigann)
- Cardigann: YAML textarea, validate button →
POST /api/indexers/validate-cardigann, settings fields from definition
- Cardigann: YAML textarea, validate button →
- Test →
POST /api/indexers/:id/test
Download Clients
API: GET /api/download-clients (200 OK)
- List with enable/disable dot, name, implementation, URL
- Inline edit: name, URL, API key, category, priority, enable toggle, save/cancel/test/delete
- Add: name, implementation (SABnzbd, qBittorrent), URL, API key
- Test →
POST /api/download-clients/:id/test
Quality Profiles
API: GET /api/quality-profiles (200 OK)
- List with name, media type badges
- Inline edit: name, cutoff quality, allowed qualities (comma-sep), save/cancel/delete
- Add: name, media types (comma-sep), cutoff quality, allowed qualities
Root Folders
API: GET /api/root-folders (200 OK)
- List with path, media type, free space
- Inline edit: path, media type (delete + re-create pattern), save/cancel/delete
- Add: path, media type
Tags
API: GET /api/tags (200 OK — fixed)
- List with name, color swatch
- Inline edit: name, color, save/cancel/delete
- Add: name, color (hex)
Tasks
API: GET /api/workers (401 — requires API key auth, different from /api/tasks)
- Scheduled tasks list with name, cron expression, enabled toggle, last run, next run
- Enable/disable toggle per task
Note: Frontend calls /api/tasks but router registers /api/workers. May result in 404.
Metadata
API: POST /api/media/refresh-all (200 OK, no auth required)
- Description text about refresh scope
- "Refresh All Metadata" button → confirmation modal → POST
- Loading state while refreshing
Shared Components
| Component | Used By | Purpose |
|---|---|---|
Toast |
All pages | Success/error feedback (top-right, auto-dismiss) |
ConfirmModal |
Queue, Blocklist, Media Detail, Settings, Requests | Confirmation for destructive/batch actions |
Pagination |
Library, Queue, Activity, Blocklist, Requests | Page navigation with total/pages display |
StatusBadge |
Library, Queue, Media Detail, Requests | Color-coded status labels |
ErrorBanner |
All pages | Error display with retry button |
Loading |
Dashboard, Queue, Activity, Blocklist, Settings | Skeleton/spinner loading states |
ReleaseSearchResults |
Media Detail, Search | Release result table with grab actions |
API Test Results (2026-04-22)
Working (200 OK)
| Endpoint | Status | Notes |
|---|---|---|
GET /health/live |
200 | {"status":"alive"} |
GET /api/dashboard |
200 | Stats returned, all zeros (empty DB) |
GET /api/media |
200 | Paginated, empty |
GET /api/queue |
200 | Empty |
GET /api/blocklist |
200 | Paginated, empty |
GET /api/activity |
200 | Paginated, empty |
GET /api/indexers |
200 | Empty |
GET /api/download-clients |
200 | Empty |
GET /api/quality-profiles |
200 | Empty |
GET /api/root-folders |
200 | Empty |
GET /api/tags |
200 | Empty (fixed: removed created_at column ref) |
GET /api/notifications/channels |
200 | Empty |
GET /api/calendar |
200 | Empty events |
GET /api/search |
200 | Empty results |
GET /api/imports/history |
200 | Empty |
POST /api/media/refresh-all |
200 | Triggers refresh |
Auth-Required (401 Unauthorized)
| Endpoint | Notes |
|---|---|
GET /api/requests |
API key auth middleware |
GET /api/discover/trending |
API key auth middleware |
GET /api/discover/popular |
API key auth middleware |
GET /api/workers |
API key auth middleware |
Root cause: Frontend client.ts does not send X-API-Key header or api_key query param. These flows (Requests, Discover, Tasks) will 401 in production unless auth is configured or the frontend is updated to pass API keys.
Expected Errors (500)
| Endpoint | Error | Cause |
|---|---|---|
GET /api/releases/search |
"no enabled indexers available" | No indexers configured yet |
Known Issues
-
Auth-protected endpoints unreachable from frontend — Requests, Discover, and Tasks pages will show errors because the API client doesn't pass API keys. The
newAPIKeyAuthmiddleware requiresX-API-Keyheader orapi_keyquery param. -
Tasks page route mismatch — Frontend calls
/api/tasksbut router registers workers at/api/workers. Needs alignment. -
No indexers configured — Release search (used by Search page and Media Detail Search tab) returns 500. Expected until indexers are added via Settings.
-
Frontend CORS — CORS is configured to allow
cfg.FrontendURLonly. Requests from other origins will be rejected.