chore: M022/S01 complete — highlight queue UI shipped

This commit is contained in:
jlightner 2026-04-04 07:06:17 +00:00
parent ce08d729cd
commit 3bea232a1c
5 changed files with 269 additions and 1 deletions

42
.gsd/STATE.md Normal file
View file

@ -0,0 +1,42 @@
# GSD State
**Active Milestone:** M022: Creator Tools & Personality
**Active Slice:** S02: [A] Follow System + Tier UI (Demo Placeholders)
**Phase:** planning
**Requirements Status:** 0 active · 0 validated · 0 deferred · 0 out of scope
## Milestone Registry
- ✅ **M001:** Chrysopedia Foundation - Infrastructure, Pipeline Core, and Skeleton UI
- ✅ **M002:** M002:
- ✅ **M003:** M003:
- ✅ **M004:** M004:
- ✅ **M005:** M005:
- ✅ **M006:** M006:
- ✅ **M007:** M007:
- ✅ **M008:** M008:
- ✅ **M009:** Homepage & First Impression
- ✅ **M010:** Discovery, Navigation & Visual Identity
- ✅ **M011:** M011:
- ✅ **M012:** M012:
- ✅ **M013:** M013:
- ✅ **M014:** M014:
- ✅ **M015:** M015:
- ✅ **M016:** M016:
- ✅ **M017:** M017:
- ✅ **M018:** M018:
- ✅ **M019:** Foundations — Auth, Consent & LightRAG
- ✅ **M020:** Core Experiences — Player, Impersonation & Knowledge Routing
- ✅ **M021:** Intelligence Online — Chat, Chapters & Search Cutover
- 🔄 **M022:** Creator Tools & Personality
- ⬜ **M023:** MVP Integration — Demo Build
- ⬜ **M024:** Polish, Shorts Pipeline & Citations
- ⬜ **M025:** Hardening & Launch Prep
## Recent Decisions
- None recorded
## Blockers
- None
## Next Action
Slice S02 has a plan file but no tasks. Add tasks to the plan.

View file

@ -6,7 +6,7 @@ Creator-facing tools take shape: shorts queue, follow system, chat widget (UI on
## Slice Overview
| ID | Slice | Risk | Depends | Done | After this |
|----|-------|------|---------|------|------------|
| S01 | [A] Highlight Reel + Shorts Queue UI | medium | — | | Creator reviews auto-detected highlights and short candidates in a review queue — approve, trim, discard |
| S01 | [A] Highlight Reel + Shorts Queue UI | medium | — | | Creator reviews auto-detected highlights and short candidates in a review queue — approve, trim, discard |
| S02 | [A] Follow System + Tier UI (Demo Placeholders) | medium | — | ⬜ | Users can follow creators. Tier config page has styled Coming Soon payment placeholders. |
| S03 | [A] Chat Widget Shell (UI Only) | low | — | ⬜ | Chat bubble on creator profile pages with conversation UI, typing indicator, suggested questions |
| S04 | [B] Multi-Turn Conversation Memory | medium | — | ⬜ | Multi-turn conversations maintain context across messages using Redis-backed history |

View file

@ -0,0 +1,103 @@
---
id: S01
parent: M022
milestone: M022
provides:
- Creator highlight review endpoints (GET list/detail, PATCH status/trim)
- HighlightQueue frontend page with filter/action UI
- Highlights link in creator SidebarNav
requires:
[]
affects:
- S07
key_files:
- backend/models.py
- alembic/versions/021_add_highlight_trim_columns.py
- backend/routers/creator_highlights.py
- backend/main.py
- frontend/src/api/highlights.ts
- frontend/src/pages/HighlightQueue.tsx
- frontend/src/pages/HighlightQueue.module.css
- frontend/src/App.tsx
- frontend/src/pages/CreatorDashboard.tsx
key_decisions:
- Pydantic schemas defined inline in creator_highlights router — keeps module self-contained
- Score breakdown fetched lazily on expand, not on list load — avoids N+1 detail calls
patterns_established:
- Creator-scoped router pattern with ownership verification (reusable for future creator endpoints)
- Lazy detail fetch pattern for expensive nested data in list views
observability_surfaces:
- chrysopedia.creator_highlights logger — info-level on status changes and trim actions, warning-level on 403/404 errors
drill_down_paths:
- .gsd/milestones/M022/slices/S01/tasks/T01-SUMMARY.md
- .gsd/milestones/M022/slices/S01/tasks/T02-SUMMARY.md
duration: ""
verification_result: passed
completed_at: 2026-04-04T07:03:08.166Z
blocker_discovered: false
---
# S01: [A] Highlight Reel + Shorts Queue UI
**Creator-scoped highlight review queue with backend endpoints (list/detail/status/trim) and full frontend page (filter tabs, score bars, approve/discard/trim actions) wired into creator dashboard.**
## What Happened
This slice delivered the complete highlight review workflow — backend and frontend — enabling creators to review auto-detected highlights and short candidates.
**T01 (Backend):** Added `trim_start` and `trim_end` nullable Float columns to `HighlightCandidate` model with Alembic migration 021. Created `creator_highlights` router with four endpoints: GET list (with status/shorts_only filters, ordered by score DESC), GET detail (with score_breakdown and key_moment), PATCH status (approve/reject with ownership verification), and PATCH trim (with validation: non-negative, start < end). Auth follows the established `creator_chapters.py` pattern exactly. Router registered in main.py. Logger `chrysopedia.creator_highlights` added.
**T02 (Frontend):** Created TypeScript API layer (`highlights.ts`) with 4 functions matching backend endpoints. Built `HighlightQueue` page with filter tabs (All/Shorts/Approved/Rejected), candidate cards showing key_moment title/duration/score/status, 7-dimension score breakdown bars, approve/discard action buttons, and inline trim panel with validated number inputs. CSS module follows ChapterReview patterns. Route lazy-loaded in App.tsx with ProtectedRoute. "Highlights" star-icon link added to SidebarNav in CreatorDashboard.
One notable design choice: score breakdown is fetched lazily when the user expands the trim panel (via `fetchHighlightDetail`), avoiding N+1 detail calls on initial list load.
## Verification
All slice-level verification checks passed:
- `npx tsc --noEmit` — zero errors (frontend compiles cleanly)
- `python -c "from models import HighlightCandidate; assert hasattr(HighlightCandidate,'trim_start')"` — model columns present
- `grep -q creator_highlights backend/main.py` — router registered
- `python -c "import ast; ast.parse(open('alembic/versions/021_add_highlight_trim_columns.py').read())"` — migration syntax valid
- `grep -q HighlightQueue frontend/src/App.tsx` — route wired
- `grep -q Highlights frontend/src/pages/CreatorDashboard.tsx` — sidebar link added
- All frontend source files exist (API layer, page, CSS module)
## Requirements Advanced
None.
## Requirements Validated
None.
## New Requirements Surfaced
None.
## Requirements Invalidated or Re-scoped
None.
## Deviations
Score breakdown fetched lazily via fetchHighlightDetail on expand rather than included in list response — avoids N+1 detail calls on initial load. Pydantic schemas defined inline in the router file rather than a separate schemas.py.
## Known Limitations
None.
## Follow-ups
None.
## Files Created/Modified
- `backend/models.py` — Added trim_start and trim_end nullable Float columns to HighlightCandidate
- `alembic/versions/021_add_highlight_trim_columns.py` — New migration adding trim columns to highlight_candidates table
- `backend/routers/creator_highlights.py` — New router with 4 creator-scoped highlight endpoints
- `backend/main.py` — Registered creator_highlights router
- `frontend/src/api/highlights.ts` — New TypeScript API layer with 4 highlight functions
- `frontend/src/pages/HighlightQueue.tsx` — New highlight review queue page with filter tabs, cards, actions
- `frontend/src/pages/HighlightQueue.module.css` — New CSS module for highlight queue page
- `frontend/src/App.tsx` — Added lazy-loaded HighlightQueue route
- `frontend/src/pages/CreatorDashboard.tsx` — Added Highlights link to SidebarNav

View file

@ -0,0 +1,81 @@
# S01: [A] Highlight Reel + Shorts Queue UI — UAT
**Milestone:** M022
**Written:** 2026-04-04T07:03:08.166Z
## UAT: Highlight Reel + Shorts Queue UI
### Preconditions
- User is logged in as a creator with at least one processed video that has highlight candidates
- Database has highlight_candidates rows with varying scores, durations, and statuses
### Test 1: Navigate to Highlight Queue
1. Log in as a creator
2. Open the creator dashboard
3. **Expected:** SidebarNav shows "Highlights" link with star icon
4. Click "Highlights" link
5. **Expected:** Navigates to `/creator/highlights`, HighlightQueue page renders with filter tabs and candidate cards
### Test 2: Filter Tabs
1. On the HighlightQueue page, note all highlights displayed under "All" tab
2. Click "Shorts" tab
3. **Expected:** Only highlights with duration ≤ 60 seconds displayed
4. Click "Approved" tab
5. **Expected:** Only highlights with status "approved" displayed
6. Click "Rejected" tab
7. **Expected:** Only highlights with status "rejected" displayed
8. Click "All" tab
9. **Expected:** All highlights shown again
### Test 3: Empty State
1. Switch to "Approved" tab when no highlights have been approved yet
2. **Expected:** Empty state message displayed (no blank page or error)
### Test 4: Candidate Card Display
1. View a highlight card on the queue
2. **Expected:** Card shows key moment title, formatted duration, composite score as percentage bar, content type badge, and status badge
3. **Expected:** Shorts-eligible candidates (≤60s) show a shorts badge
### Test 5: Approve a Highlight
1. Find a highlight with pending/detected status
2. Click the "Approve" button (green)
3. **Expected:** API call to PATCH `/api/v1/creator/highlights/{id}` with `{"status": "approved"}`
4. **Expected:** Card updates to show approved status badge
5. **Expected:** Highlight appears under "Approved" tab
### Test 6: Discard a Highlight
1. Find a highlight with pending/detected status
2. Click the "Discard" button (red)
3. **Expected:** API call to PATCH `/api/v1/creator/highlights/{id}` with `{"status": "rejected"}`
4. **Expected:** Card updates to show rejected status badge
### Test 7: Trim Panel
1. Click "Trim" button on a highlight card
2. **Expected:** Inline trim panel opens with two number inputs (start seconds, end seconds) pre-filled with key_moment start_time/end_time
3. Enter valid trim values (e.g., start=10.0, end=45.0)
4. Click "Save"
5. **Expected:** API call to PATCH `/api/v1/creator/highlights/{id}/trim` with trim values
6. **Expected:** Trim panel closes, card reflects updated state
### Test 8: Trim Validation
1. Open trim panel
2. Enter trim_start = 50, trim_end = 10 (start > end)
3. Click "Save"
4. **Expected:** Validation error displayed, API not called
### Test 9: Score Breakdown
1. Expand a highlight card detail view
2. **Expected:** 7 horizontal score bars displayed (one per scoring dimension) with labels and percentage values
### Test 10: Ownership Enforcement (API level)
1. Using API directly, try to GET/PATCH a highlight belonging to a different creator
2. **Expected:** 404 response (highlight not found for this creator)
### Test 11: Backend — Migration
1. Run `alembic upgrade head` on a fresh database
2. **Expected:** Migration 021 applies cleanly, `trim_start` and `trim_end` columns exist on `highlight_candidates` table
### Edge Cases
- Creator with no videos/highlights sees empty state on all tabs
- Highlight with null trim_start/trim_end shows key_moment times as defaults in trim panel
- Rapidly clicking approve/discard does not cause race conditions (optimistic UI update)

View file

@ -0,0 +1,42 @@
{
"schemaVersion": 1,
"taskId": "T02",
"unitId": "M022/S01/T02",
"timestamp": 1775286117545,
"passed": false,
"discoverySource": "task-plan",
"checks": [
{
"command": "cd /home/aux/projects/content-to-kb-automator/frontend",
"exitCode": 0,
"durationMs": 7,
"verdict": "pass"
},
{
"command": "npx tsc --noEmit",
"exitCode": 1,
"durationMs": 814,
"verdict": "fail"
},
{
"command": "grep -q HighlightQueue src/App.tsx",
"exitCode": 2,
"durationMs": 6,
"verdict": "fail"
},
{
"command": "grep -q Highlights src/pages/CreatorDashboard.tsx",
"exitCode": 2,
"durationMs": 5,
"verdict": "fail"
},
{
"command": "echo 'All checks pass'",
"exitCode": 0,
"durationMs": 4,
"verdict": "pass"
}
],
"retryAttempt": 1,
"maxRetries": 2
}