Initial commit: YouTube Studio Flow (backend, frontend, infrastructure, docs)

This commit is contained in:
2026-08-11 12:27:44 +02:00
commit d5af006443
304 changed files with 74604 additions and 0 deletions
@@ -0,0 +1,56 @@
# Video Management
## User Perspective
The Videos page (`/videos`) is the main workspace. It displays the team's full video library in a paginated, sortable table. Users can filter by status, search by title, switch between predefined tabs, and click any video to open the editor.
### Video List Features
- **Tabs**: All Content, Published, Private, Scheduled, Conflicts, Push Pending, Lint Issues, Deleted (conditionally shown)
- **Columns**: YouTube ID, Title, Privacy Status, Published Date, Lint Status, Playlists, Sync Status
- **Sorting**: Click column headers
- **Pagination**: Page size selector + prev/next
- **Search**: Title search via URL param `search=`
- **Middle-click**: Opens video in background tab (native anchor overlay)
- **Lint status badges**: OK (no badge), WARNING (amber), ERROR (pink/red)
- **Sync status badges**: In sync (green), Push pending (amber), Conflict (red)
### Video Editor Features
The video editor (`/videos/[id]`) provides:
- **Combined header**: thumbnail, YouTube/Studio links, meta info (ID, date, privacy, sync status), lint badge, action buttons
- **Sortable two-column layout**: sections (Basic Info, Language, Audience & Content, Playlists, Description) can be dragged between columns. Layout persists to user preferences.
- **Basic Info**: title, tags (chip input), privacy status, category, scheduled publish date, recording date, game title
- **Language**: title/description language, video language
- **Audience & Content**: Made for Kids toggle, Allow Embedding toggle, License selector
- **Playlists**: add/remove from channel playlists via search dropdown
- **Description**: description block config editor (see [[02 - Description Engine]])
- **Actions**: Apply Template, Refresh from YouTube, Push to YouTube, Save Changes
- **Diff view**: "See what changed" shows field-level diff against last synced YouTube state
### Game Title Field
`gameTitle` is a **custom metadata field** — it is not a YouTube API field and is never populated during channel import. Users enter it manually in the video editor's Basic Info section.
It serves two purposes:
1. **Token `{video.gameTitle}`** — resolves in description blocks, allowing game name to appear in descriptions automatically.
2. **Canva search link** — when `Team.showCanvaLink` is enabled in team settings, the video editor shows a "Search Canva" link that opens `https://www.canva.com/search?q={gameTitle}`, helping creators find thumbnail templates for their game.
It can also be set as a template default via `Template.videoFields.gameTitle`, so assigning a template pre-fills the game name.
## Developer Perspective
### Backend
- **Module**: `backend/src/modules/videos/`
- **Key service methods**: `findAll(query, teamId)`, `findOne(id)`, `update(id, dto)`, `syncVideo(id)`, `refreshFromYouTube(id)`, `renderDescription(id)`
- **Sync flow**: `POST /videos/:id/sync` enqueues a `youtube-sync` BullMQ job. The processor renders description, checks hash, calls YouTube API, updates `lastSyncedHash` and `renderedDescription`.
- **`hasPendingChanges`**: Computed in `findAll` by comparing `hashMetadata(currentFields)` against `lastSyncedHash`. If `lastSyncedHash` is null, falls back to comparing against YouTube baseline using `youtubeDescription`.
- **Filters** (`GET /videos`): `search`, `lintStatus`, `privacyStatus`, `scheduled`, `notScheduled`, `remoteConflict`, `pendingSync`, `deletedOnYouTube`, `hasLintIssues` (matches ERROR or WARNING)
### Frontend
- **Pages**: `frontend/src/app/(dashboard)/videos/page.tsx` (list) and `videos/[id]/page.tsx` (editor)
- **Table component**: `VideoTable.tsx` uses TanStack Table v8
- **URL state**: Tab, page, sort, and search are persisted in URL params
- **Column layout persistence**: Saved to `User.preferences` via `PATCH /users/me/preferences` using keys `videoEditLeftCol` and `videoEditRightCol`
## Related
- [[02 - Description Engine]]
- [[03 - Metadata Linting]]
- [[02 - Videos API]]