# S04: Review Queue Admin UI — UAT

**Milestone:** M001
**Written:** 2026-03-29T23:35:54.561Z

## UAT: S04 — Review Queue Admin UI

### Preconditions
- Backend running with PostgreSQL and Redis available
- At least one video processed through the pipeline (stages 2-5) with KeyMoments in DB
- Frontend built and served (or `npm run dev` for development)

---

### Test 1: Queue Page Loads with Stats
1. Navigate to `/admin/review`
2. **Expected:** Stats bar shows counts for Pending, Approved, Edited, Rejected
3. **Expected:** Queue cards display moment title, summary excerpt, video filename, creator name, status badge
4. **Expected:** Default filter shows Pending moments

### Test 2: Status Filter Tabs
1. On queue page, click "Approved" tab
2. **Expected:** Only moments with status=approved are shown
3. Click "All" tab
4. **Expected:** All moments across all statuses are shown
5. Click "Rejected" tab with no rejected moments
6. **Expected:** Empty state message displayed

### Test 3: Pagination
1. Ensure >20 moments exist in queue
2. Navigate to `/admin/review`
3. **Expected:** First 20 moments shown, "Next" button visible, "Previous" disabled
4. Click "Next"
5. **Expected:** Next page of moments shown, "Previous" now enabled

### Test 4: Approve Moment
1. Click a pending moment card to navigate to detail page
2. Verify moment displays: title, summary, content_type, timestamps (mm:ss format), status badge
3. Click "Approve" button
4. **Expected:** Navigated back to queue, moment now shows "approved" status badge
5. Stats bar pending count decreased by 1, approved count increased by 1

### Test 5: Reject Moment
1. Click a pending moment card
2. Click "Reject" button
3. **Expected:** Navigated back to queue, moment now shows "rejected" status badge

### Test 6: Edit Moment
1. Click a pending moment card
2. Click "Edit" button
3. **Expected:** Title, summary, content_type fields become editable inline
4. Change the title to "Edited Test Title"
5. Click "Save"
6. **Expected:** Moment title updated, status changes to "edited"
7. Click "Cancel" during edit
8. **Expected:** Fields revert to original values

### Test 7: Split Moment
1. Click a moment with start_time=10.0, end_time=60.0
2. Click "Split" button
3. **Expected:** Modal opens with timestamp input field
4. Enter split time: 35.0, click "Split"
5. **Expected:** Two moments created: [10.0, 35.0) and [35.0, 60.0]. Second has "(split)" suffix in title.
6. Retry with split_time=5.0 (below start_time)
7. **Expected:** Error message — split time must be between start and end

### Test 8: Merge Moments
1. Click a moment from video "example.mp4"
2. Click "Merge" button
3. **Expected:** Modal opens with dropdown showing other moments from same video
4. Select a target moment, click "Merge"
5. **Expected:** Merged moment has combined summary, min(start_time), max(end_time). Target moment deleted.

### Test 9: Mode Toggle
1. On queue page, observe mode toggle in header
2. **Expected:** Shows current mode with colored dot indicator (green=review, amber=auto)
3. Click toggle to switch mode
4. **Expected:** Mode changes, API confirms new mode via GET /api/v1/review/mode
5. Refresh page
6. **Expected:** Mode persists (stored in Redis)

### Test 10: Error Handling
1. Navigate to `/admin/review/99999` (nonexistent moment)
2. **Expected:** Error state displayed (moment not found)
3. Attempt to merge moments from different source videos via API
4. **Expected:** 400 response with validation error message

### Edge Cases
- **Empty queue:** Navigate to `/admin/review` with no moments — empty state message shown
- **Split at boundary:** Try split_time = start_time or end_time — 400 error returned
- **Merge with self:** Try merging moment with itself — 400 error returned
- **Redis down:** Mode toggle falls back to config default; mode set returns 503
- **Concurrent actions:** Approve then immediately approve again — idempotent, no error
