From 3c99084eb2829977ca0ea19fc279fe4daec9abae Mon Sep 17 00:00:00 2001 From: jlightner Date: Sat, 4 Apr 2026 10:44:45 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20Replaced=20thin=203px=20line=20markers?= =?UTF-8?q?=20with=2012px=20color-coded=20circle=20pins,=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - "frontend/src/components/ChapterMarkers.tsx" - "frontend/src/components/PlayerControls.tsx" - "frontend/src/App.css" GSD-Task: S02/T01 --- .gsd/milestones/M024/M024-ROADMAP.md | 2 +- .../milestones/M024/slices/S01/S01-SUMMARY.md | 103 ++++++++++++++++++ .gsd/milestones/M024/slices/S01/S01-UAT.md | 55 ++++++++++ .../M024/slices/S01/tasks/T02-VERIFY.json | 16 +++ .gsd/milestones/M024/slices/S02/S02-PLAN.md | 82 +++++++++++++- .../M024/slices/S02/S02-RESEARCH.md | 80 ++++++++++++++ .../M024/slices/S02/tasks/T01-PLAN.md | 57 ++++++++++ .../M024/slices/S02/tasks/T01-SUMMARY.md | 79 ++++++++++++++ .../M024/slices/S02/tasks/T02-PLAN.md | 70 ++++++++++++ frontend/src/App.css | 55 ++++++++-- frontend/src/components/ChapterMarkers.tsx | 44 +++++++- frontend/src/components/PlayerControls.tsx | 2 +- 12 files changed, 625 insertions(+), 20 deletions(-) create mode 100644 .gsd/milestones/M024/slices/S01/S01-SUMMARY.md create mode 100644 .gsd/milestones/M024/slices/S01/S01-UAT.md create mode 100644 .gsd/milestones/M024/slices/S01/tasks/T02-VERIFY.json create mode 100644 .gsd/milestones/M024/slices/S02/S02-RESEARCH.md create mode 100644 .gsd/milestones/M024/slices/S02/tasks/T01-PLAN.md create mode 100644 .gsd/milestones/M024/slices/S02/tasks/T01-SUMMARY.md create mode 100644 .gsd/milestones/M024/slices/S02/tasks/T02-PLAN.md diff --git a/.gsd/milestones/M024/M024-ROADMAP.md b/.gsd/milestones/M024/M024-ROADMAP.md index 64df4e0..dcd4b90 100644 --- a/.gsd/milestones/M024/M024-ROADMAP.md +++ b/.gsd/milestones/M024/M024-ROADMAP.md @@ -6,7 +6,7 @@ Shorts pipeline goes end-to-end with captioning and templates. Player gets key m ## Slice Overview | ID | Slice | Risk | Depends | Done | After this | |----|-------|------|---------|------|------------| -| S01 | [A] Shorts Publishing Flow | medium | — | ⬜ | Creator approves a short → it renders → gets a shareable URL and embed code | +| S01 | [A] Shorts Publishing Flow | medium | — | ✅ | Creator approves a short → it renders → gets a shareable URL and embed code | | S02 | [A] Key Moment Pins on Player Timeline | low | — | ⬜ | Key technique moments appear as clickable pins on the player timeline | | S03 | [A] Embed Support (iframe Snippet) | low | — | ⬜ | Creators can copy an iframe embed snippet to put the player on their own site | | S04 | [B] Auto-Captioning + Template System | medium | — | ⬜ | Shorts have Whisper-generated animated subtitles and creator-configurable intro/outro cards | diff --git a/.gsd/milestones/M024/slices/S01/S01-SUMMARY.md b/.gsd/milestones/M024/slices/S01/S01-SUMMARY.md new file mode 100644 index 0000000..1758d8b --- /dev/null +++ b/.gsd/milestones/M024/slices/S01/S01-SUMMARY.md @@ -0,0 +1,103 @@ +--- +id: S01 +parent: M024 +milestone: M024 +provides: + - Public short URL pattern: /shorts/{token} + - share_token field on GeneratedShort model and API response + - Public shorts API endpoint: GET /api/v1/public/shorts/{share_token} +requires: + [] +affects: + - S03 + - S06 +key_files: + - backend/models.py + - alembic/versions/026_add_share_token.py + - backend/pipeline/stages.py + - backend/routers/shorts_public.py + - backend/routers/shorts.py + - backend/main.py + - frontend/src/pages/ShortPlayer.tsx + - frontend/src/pages/ShortPlayer.module.css + - frontend/src/api/shorts.ts + - frontend/src/App.tsx + - frontend/src/pages/HighlightQueue.tsx +key_decisions: + - Public endpoint returns 404 for both missing and non-complete shorts — avoids leaking short status + - fetchPublicShort uses raw fetch() to avoid injecting auth token on public endpoint + - Share/embed buttons only render when share_token is non-null — graceful for pre-migration shorts +patterns_established: + - Token-based public access pattern: model gets share_token column, pipeline generates on completion, public router resolves by token with no auth +observability_surfaces: + - none +drill_down_paths: + - .gsd/milestones/M024/slices/S01/tasks/T01-SUMMARY.md + - .gsd/milestones/M024/slices/S01/tasks/T02-SUMMARY.md +duration: "" +verification_result: passed +completed_at: 2026-04-04T10:37:15.032Z +blocker_discovered: false +--- + +# S01: [A] Shorts Publishing Flow + +**Shorts get shareable public URLs with token-based access, a standalone video player page, and copy-to-clipboard share/embed buttons on the admin queue.** + +## What Happened + +This slice adds the complete shorts publishing flow: from token generation at pipeline completion through to a public-facing player page. + +**Backend (T01):** Added `share_token` column (String(16), nullable, unique-indexed) to the `GeneratedShort` model with Alembic migration 026 that also backfills existing complete shorts. Token generation (`secrets.token_urlsafe(8)`) is wired into `stage_generate_shorts` at the completion point. A new unauthenticated endpoint `GET /api/v1/public/shorts/{share_token}` resolves the token via selectinload joins through HighlightCandidate → KeyMoment → SourceVideo → Creator to return metadata (format, dimensions, duration, creator name, highlight title) and a fresh MinIO presigned download URL. Returns 404 for both missing and non-complete shorts to avoid leaking status info. + +**Frontend (T02):** Created `ShortPlayer.tsx` — a public page at `/shorts/:token` that fetches metadata via unauthenticated API call, renders a `