diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index e47a68b..56e8ae4 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -55,11 +55,11 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 15 needs: [changes] - # Only run when security-relevant files changed (not a required check — - # branch protection only requires "security-status" which handles skips). + # Always run on PRs (Code Scanning Security ruleset requires CodeQL results). + # On push/schedule, only run when security-relevant files changed. if: | !inputs.skip_codeql && - (needs.changes.outputs.security_relevant == 'true' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') + (github.event_name == 'pull_request' || needs.changes.outputs.security_relevant == 'true' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') permissions: security-events: write steps: diff --git a/docs/api.md b/docs/api.md index f394c40..2ddd7ac 100644 --- a/docs/api.md +++ b/docs/api.md @@ -73,7 +73,7 @@ Response: { "clips": [...], "hasMore": true } ``` Only returns clips with `status: 'ready'`. Default sort is `oldest` (chronological). `round-robin` interleaves clips across members so no single poster dominates the feed. The `watched` filter sorts by most-recently-watched instead. -Each clip includes: id, originalUrl, title, addedByUsername, addedByAvatar, status, durationSeconds, platform, contentType, createdAt, watched, favorited, reactions, commentCount, unreadCommentCount, viewCount, seenByOthers. +Each clip includes: id, originalUrl, title, addedByUsername, addedByAvatar, status, durationSeconds, platform, contentType, creatorName, creatorUrl, createdAt, watched, favorited, reactions, commentCount, unreadCommentCount, viewCount, seenByOthers. ### POST /api/clips ``` @@ -92,7 +92,7 @@ Response: { "ok": true, "clipId": "...", "status": "downloading" } (201 Create ### GET /api/clips/[id] Returns full clip detail with user context, interaction state, and metadata. ``` -Response: { id, originalUrl, videoPath, audioPath, thumbnailPath, title, artist, albumArt, spotifyUrl, appleMusicUrl, youtubeMusicUrl, addedBy, addedByUsername, addedByAvatar, platform, status, contentType, durationSeconds, watched, favorited, reactions, commentCount, unreadCommentCount, viewCount, seenByOthers, createdAt, canEditCaption } +Response: { id, originalUrl, videoPath, audioPath, thumbnailPath, title, artist, albumArt, spotifyUrl, appleMusicUrl, youtubeMusicUrl, addedBy, addedByUsername, addedByAvatar, platform, status, contentType, durationSeconds, creatorName, creatorUrl, watched, favorited, reactions, commentCount, unreadCommentCount, viewCount, seenByOthers, createdAt, canEditCaption } ``` ### PATCH /api/clips/[id] @@ -134,7 +134,7 @@ Response: { "watched": true } ``` ### POST /api/clips/[id]/favorite -Toggles favorite on/off. +Toggles favorite on/off. Also syncs with reactions: favoriting creates a ❤️ reaction (with notification), unfavoriting removes the paired ❤️ reaction and its notification. ``` Response: { "favorited": true } ``` diff --git a/docs/architecture.md b/docs/architecture.md index 2672859..a88fc02 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -84,7 +84,7 @@ scrolly/ │ │ │ ├── BaseSheet.svelte # Shared drag-to-dismiss bottom sheet base │ │ │ ├── ClipOverlay.svelte # Full-screen single-clip overlay view │ │ │ ├── CommentsSheet.svelte # Bottom sheet for comments -│ │ │ ├── ViewersSheet.svelte # Bottom sheet for view list +│ │ │ ├── ViewersSheet.svelte # Floating panel for view list │ │ │ ├── ActivitySheet.svelte # Bottom sheet for in-app notifications │ │ │ ├── GifPicker.svelte # GIPHY search/picker (full or compact carousel mode) │ │ │ ├── AddVideo.svelte # Add video form diff --git a/docs/data-model.md b/docs/data-model.md index ba24314..4f06664 100644 --- a/docs/data-model.md +++ b/docs/data-model.md @@ -61,6 +61,8 @@ SQLite database via Drizzle ORM. All IDs are UUIDs stored as text. Timestamps ar | apple_music_url | text | Nullable. Cross-platform Apple Music link (music clips). | | youtube_music_url | text | Nullable. Cross-platform YouTube Music link (music clips). | | file_size_bytes | integer | Nullable. File size for storage tracking. | +| creator_name | text | Nullable. Original content creator name (from yt-dlp metadata). | +| creator_url | text | Nullable. Original content creator profile URL. | | created_at | integer | Unix timestamp | Unique index on `(group_id, original_url)` — prevents duplicate URLs within a group.