Files
unified-media-manager/docs/UX-FLOWS.md
2026-04-24 10:45:19 -07:00

302 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 `ReleaseSearchResults` component
- 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/:id` per 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
- 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
1. **Auth-protected endpoints unreachable from frontend** — Requests, Discover, and Tasks pages will show errors because the API client doesn't pass API keys. The `newAPIKeyAuth` middleware requires `X-API-Key` header or `api_key` query param.
2. **Tasks page route mismatch** — Frontend calls `/api/tasks` but router registers workers at `/api/workers`. Needs alignment.
3. **No indexers configured** — Release search (used by Search page and Media Detail Search tab) returns 500. Expected until indexers are added via Settings.
4. **Frontend CORS** — CORS is configured to allow `cfg.FrontendURL` only. Requests from other origins will be rejected.