# Phase 3: Creator Tools & VOD - Complete Implementation Guide **Duration**: Weeks 9-13 | **Complexity**: High | **Team Size**: 3 devs ## Executive Summary Phase 3 empowers creators with professional tools for content management. VOD archival enables creators to build libraries of content. Clip creation allows viral moments to be shared. Advanced analytics help creators understand their audience. --- ## Phase 3 Goals ### Primary Goals 1. Automatic VOD archival from live streams 2. Clip creation and sharing system 3. Advanced creator analytics dashboard 4. Stream health monitoring 5. VOD library management and playback ### Success Criteria - 📹 100+ VODs archived - 🎬 50+ clips created and shared - 📊 Analytics dashboard with 10+ metrics - 📈 95% stream uptime with health metrics - 🎥 <2 minute clip generation time --- ## Sprint Breakdown ### Sprint 3.1: VOD Archives **Duration**: Days 1-5 | **Team**: 2 devs #### User Story 3.1.1: Automatic Stream Recording ``` AS A creator I WANT my streams automatically archived SO THAT I don't lose content and can build a VOD library ``` **Tasks**: - [ ] Enable stream recording on Cloudflare/Mux - [ ] Store recordings in R2 storage - [ ] Index VODs in database - [ ] Create VOD metadata storage - [ ] Auto-cleanup old test recordings **Recording Configuration**: ```typescript // config/streaming.ts export const recordingConfig = { enabled: true, minDurationMinutes: 1, // Only record streams >1 min deleteAfterDays: 365, // Keep for 1 year allowUserDelete: true, storage: { provider: 'r2', // Cloudflare R2 bucket: 'aethex-vods', prefix: '{channelId}/{streamId}/', }, formats: ['hls', 'mp4'], // HLS for streaming, MP4 for download } ``` **Database Schema**: ```prisma model VOD { id String @id @default(cuid()) streamId String @unique stream Stream @relation(fields: [streamId], references: [id], onDelete: Cascade) channelId String channel Channel @relation(fields: [channelId], references: [id], onDelete: Cascade) title String // From stream description String? thumbnail String? // Storage paths hlsUrl String // HLS stream URL mp4Url String? // MP4 download link // Duration & stats duration Int // Minutes fileSize Int // Bytes resolution String @default("1080p") // Max resolution // Metadata viewCount Int @default(0) likeCount Int @default(0) clipCount Int @default(0) // Visibility isPublic Boolean @default(true) isDeleted Boolean @default(false) deletedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt clips Clip[] } model Clip { id String @id @default(cuid()) vodId String vod VOD @relation(fields: [vodId], references: [id], onDelete: Cascade) creatorId String creator User @relation(fields: [creatorId], references: [id], onDelete: Cascade) title String description String? // Trim points (in seconds from start of VOD) startTime Int endTime Int duration Int // endTime - startTime // Clip URL and metadata clipUrl String thumbnail String? // Engagement viewCount Int @default(0) likeCount Int @default(0) shareCount Int @default(0) // Status status ClipStatus @default(PROCESSING) // PROCESSING, READY, FAILED createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } enum ClipStatus { PROCESSING READY FAILED DELETED } ``` **API Routes**: - `GET /api/channels/:id/vods` - List creator's VODs - `GET /api/vods/:id` - Get VOD details - `PUT /api/vods/:id` - Update VOD (title, description, visibility) - `DELETE /api/vods/:id` - Delete VOD - `GET /api/vods/:id/comments` - VOD comments (Phase 5) **Background Jobs**: - Record stream when LIVE status set - Stop recording when stream ENDED - Generate thumbnail at 25% mark - Index VOD metadata **Webhook from Cloudflare/Mux**: ```typescript // pages/api/webhooks/recording-ready.ts export async function POST(req) { const event = req.body if (event.type === 'video.ready') { // Update VOD status to READY await db.vod.update({ where: { streamId: event.streamId }, data: { hlsUrl: event.hlsUrl, mp4Url: event.downloadUrl, duration: event.duration, } }) } } ``` **Deliverables**: - [ ] Recording enabled on all streams - [ ] VODs indexed in database - [ ] VOD list page functional - [ ] Webhook processing --- #### User Story 3.1.2: VOD Playback & Library ``` AS A viewer I WANT to watch VODs SO THAT I can catch up on streams I missed ``` **Tasks**: - [ ] VOD library page (`/channel/{username}/vods`) - [ ] VOD playback player (reuse HLS player) - [ ] VOD comments (Phase 5) - [ ] VOD download link (optional) - [ ] Progress tracking (watch time) **Page Structure**: ``` /channel/[username]/vods ├── VOD List │ ├── Grid/List toggle │ ├── Sort: newest, trending, watched │ ├── Filter: date range │ └── Search VODs ├── VOD Cards │ ├── Thumbnail │ ├── Title │ ├── Duration │ ├── View count │ ├── Upload date │ └── Like button └── Pagination (12 per page) ``` **VOD Playback Page**: ``` /vods/[vodId] ├── Player (full width, sticky controls) ├── Sidebar: │ ├── VOD Info (title, date, views) │ ├── Creator Card + Follow │ ├── Like/Share buttons │ └── Comments (Phase 5) └── Related VODs (same channel) ``` **Watch Progress Tracking**: ```prisma model WatchProgress { id String @id @default(cuid()) userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) vodId String vod VOD @relation(fields: [vodId], references: [id], onDelete: Cascade) lastPosition Int // Seconds watched percentage Float // 0-100 createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([userId, vodId]) } ``` **API Routes**: - `GET /api/channels/:id/vods` - List VODs - `GET /api/vods/:id` - Get VOD details - `POST /api/watch-progress` - Save watch progress - `GET /api/watch-progress` - Get user's watch history **Components**: ``` components/vod/ ├── VODLibrary.tsx ├── VODGrid.tsx ├── VODCard.tsx ├── VODPlayer.tsx ├── VODInfo.tsx ├── WatchProgressBar.tsx └── RelatedVODs.tsx ``` **Deliverables**: - [ ] VOD library page - [ ] VOD playback working - [ ] Watch progress tracking - [ ] Search/filter working --- #### User Story 3.1.3: Watch History & Recommendations ``` AS A viewer I WANT to access my watch history SO THAT I can resume videos and get recommendations ``` **Tasks**: - [ ] Watch history page - [ ] Resume button (jump to last position) - [ ] Clear history option - [ ] Recommended VODs from followed creators - [ ] "Continue Watching" section **Routes**: - `GET /api/watch-history` - User's watch history - `DELETE /api/watch-history/:vodId` - Remove from history - `POST /api/watch-history/clear` - Clear all **Deliverables**: - [ ] Watch history page - [ ] Resume functionality - [ ] Continue watching section --- ### Sprint 3.2: Clip Creation **Duration**: Days 6-10 | **Team**: 2 devs #### User Story 3.2.1: In-Stream Clip Button ``` AS A viewer I WANT to create clips while watching SO THAT I can share viral moments with others ``` **Tasks**: - [ ] Add clip button to stream player - [ ] Auto-capture last 30 seconds (configurable) - [ ] Show clip creation feedback - [ ] Redirect to clip editor after creation - [ ] Display creation status **Clip Capture Logic**: ```typescript // When user clicks clip button const clipStream = async (streamId: string) => { const now = Date.now() // Clip last 30 seconds of HLS stream const clipData = { vodId: streamId, // Use stream as VOD startTime: Math.max(0, currentPlaybackPosition - 30), endTime: currentPlaybackPosition, title: `Clip from ${creatorName}'s stream`, } // Queue clip generation job await fetch('/api/clips', { method: 'POST', body: JSON.stringify(clipData) }) } ``` **Deliverables**: - [ ] Clip button visible on stream player - [ ] Clip auto-capture working - [ ] User feedback on clip creation --- #### User Story 3.2.2: Clip Editor ``` AS A creator I WANT to edit and publish clips SO THAT I can curate my best moments ``` **Tasks**: - [ ] Build clip editor page (`/clips/[clipId]/edit`) - [ ] Timeline with trim handles - [ ] Preview scrubber - [ ] Title/description editor - [ ] Thumbnail editor (select frame) - [ ] One-click publish to Twitter/TikTok (Phase 3B) **Page Structure**: ``` /clips/[clipId]/edit ├── Video Preview │ ├── Timeline (full VOD) │ ├── Clip section highlighted │ ├── Trim handles (drag to adjust) │ └── Play button ├── Edit Panel │ ├── Title input │ ├── Description textarea │ ├── Thumbnail selector (frame picker) │ ├── Tags input (Phase 2B) │ └── Visibility toggle └── Publish Action ├── Preview button ├── Save draft button └── Publish button ``` **Components**: ``` components/clips/ ├── ClipEditor.tsx ├── ClipTimeline.tsx ├── TrimHandles.tsx ├── FrameSelector.tsx ├── PreviewPlayer.tsx └── PublishPanel.tsx ``` **API Routes**: - `PUT /api/clips/:id` - Update clip metadata - `POST /api/clips/:id/generate` - Generate clip video - `POST /api/clips/:id/publish` - Publish clip - `POST /api/clips/:id/thumbnail` - Update thumbnail **Background Job**: - FFmpeg or Cloudflare Stream API to cut video segment - Generate MP4 and thumbnail - Upload to R2 - Update clip status to READY **Deliverables**: - [ ] Clip editor page - [ ] Trim functionality - [ ] Preview working - [ ] Publish button functional --- #### User Story 3.2.3: Clip Sharing & Discovery ``` AS A creator I WANT my clips shared widely SO THAT I grow my audience ``` **Tasks**: - [ ] Clip sharing page (`/clips/:id`) - [ ] Social media share buttons - [ ] Embed code for websites - [ ] Clip analytics - [ ] Trending clips section **Clip Page Structure**: ``` /clips/[clipId] ├── Header: Clip title + creator ├── Video Player ├── Share Buttons (Twitter, TikTok, Discord, etc) ├── Embed Code (iframe) ├── Stats (views, likes, shares, datetime) ├── Creator Card + Channel Link ├── Comments (Phase 5) └── Related Clips (trending from channel) ``` **Routes**: - `GET /api/clips/trending` - Trending clips - `GET /api/clips/:id/stats` - Clip analytics - `GET /api/channels/:id/clips` - Creator's clips - `POST /api/clips/:id/like` - Like clip (Phase 5) **Deliverables**: - [ ] Clip sharing page - [ ] Share buttons working - [ ] Trending clips showing - [ ] Embed working --- ### Sprint 3.3: Advanced Analytics **Duration**: Days 11-15 | **Team**: 2 devs #### User Story 3.3.1: Analytics Dashboard ``` AS A creator I WANT detailed analytics SO THAT I can understand and grow my audience ``` **Tasks**: - [ ] Build analytics dashboard (`/dashboard/analytics`) - [ ] Implement data collection - [ ] Graphs and charts - [ ] Filter by date range - [ ] Export analytics (CSV) **Analytics Metrics**: *Stream-level*: - Stream duration - Peak concurrent viewers - Average viewers - Total views - Chat messages - Follow gains - Conversion rate (viewers → followers) *Channel-level*: - Total hours streamed - Total views (all time) - Average peak viewers - Growth (weekly/monthly) - Most watched category - Best performing streams - Top clips **Database Schema**: ```prisma model StreamAnalytics { id String @id @default(cuid()) streamId String @unique stream Stream @relation(fields: [streamId], references: [id], onDelete: Cascade) // Viewers peakConcurrent Int avgConcurrent Int uniqueViewers Int totalWatchMinutes Int // Engagement chatMessages Int newFollowers Int conversionRate Float // followers gained / unique viewers // VOD vodViews Int @default(0) vodEngagement Float @default(0) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model ViewCountSnapshot { id String @id @default(cuid()) streamId String stream Stream @relation(fields: [streamId], references: [id], onDelete: Cascade) viewCount Int timestamp DateTime @@index([streamId, timestamp]) } ``` **Chart Components** (using Recharts or Chart.js): ``` components/analytics/ ├── AnalyticsDashboard.tsx ├── ViewersOverTime.tsx ├── PeakViewersChart.tsx ├── EngagementChart.tsx ├── TopStreamsTable.tsx ├── ChannelGrowthChart.tsx └── ConversionRateMetric.tsx ``` **API Routes**: - `GET /api/analytics/streams/:id` - Stream analytics - `GET /api/analytics/channels/:id` - Channel analytics - `GET /api/analytics/charts/viewers` - Viewer count time series - `POST /api/analytics/export` - CSV export **Data Collection**: ```typescript // Collect viewer count every minute setInterval(async () => { const activeStreams = await db.stream.findMany({ where: { status: 'LIVE' } }) for (let stream of activeStreams) { await db.viewCountSnapshot.create({ data: { streamId: stream.id, viewCount: stream.viewerCount, timestamp: new Date(), } }) } }, 60000) ``` **Deliverables**: - [ ] Analytics dashboard built - [ ] Charts displaying correctly - [ ] Data collection working - [ ] Date range filtering --- #### User Story 3.3.2: Stream Health Monitoring ``` AS A creator I WANT to see stream health metrics SO THAT I can fix quality issues during live streaming ``` **Tasks**: - [ ] Display bitrate, FPS, resolution - [ ] Connection quality indicator - [ ] Bitrate graph - [ ] Issue alerts (bitrate drop, connection loss) - [ ] Guide to fix issues **Metrics**: ```typescript interface StreamHealth { uptime: number // % uptime bitrate: number // Kbps fps: number // Frames per second resolution: string // 1920x1080 latency: number // ms from ingest to edge packetLoss: number // % packets lost bufferingEvents: number // Number of times player buffered } ``` **Dashboard Widget**: ``` Stream Health Status ├── Connection: Excellent (green indicator) ├── Bitrate: 5000 kbps (target 5500) [graph] ├── FPS: 60 [icon good] ├── Resolution: 1920x1080 ├── Latency: 1.2s (acceptable range) └── Alerts: None ``` **Real-time Updates** (via WebSocket): ```typescript socket.on('stream:health-update', (health) => { updateHealthMetrics(health) }) ``` **Deliverables**: - [ ] Health metrics displayed correctly - [ ] Real-time updates working - [ ] Alerts triggering - [ ] Helpful tooltips --- #### User Story 3.3.3: VOD & Clip Analytics ``` AS A creator I WANT to see how my VODs and clips perform SO THAT I can create more of the best content ``` **Tasks**: - [ ] VOD view count tracking - [ ] Clip performance metrics - [ ] Trending clips dashboard - [ ] Best performing content **Metrics**: - VOD views, engagement, average watch time - Clip views, likes, shares, embeds - Which streams generate most clips - Which clips drive most traffic back to channel **API Routes**: - `GET /api/vods/:id/analytics` - `GET /api/clips/:id/analytics` - `GET /api/channels/:id/top-vods` - `GET /api/channels/:id/top-clips` **Deliverables**: - [ ] VOD analytics working - [ ] Clip analytics showing - [ ] Top content identified --- ### Sprint 3.4: Polish & Optimization **Duration**: Days 16-20 | **Team**: 2 devs #### Performance Optimization - [ ] Optimize analytics queries (database indexes) - [ ] Cache analytics data (Redis) - [ ] Lazy load charts - [ ] Implement pagination on clip lists #### Mobile Responsiveness - [ ] Mobile VOD player - [ ] Mobile analytics dashboard - [ ] Mobile clip editor - [ ] Touch-friendly controls #### Testing - [ ] Unit tests for analytics calculations - [ ] E2E tests: record stream → VOD created → viewable - [ ] Clip creation and playback tests - [ ] Analytics accuracy validation --- ## Database Schema - Phase 3 Updates **New Models**: ```prisma model VOD { /* ... */ } model Clip { /* ... */ } model StreamAnalytics { /* ... */ } model ViewCountSnapshot { /* ... */ } model WatchProgress { /* ... */ } ``` **Updated Models**: ```prisma model Stream { // Add VOD relation vod VOD? } model Channel { // Add VOD and clip relations vods VOD[] } model User { // Add clip relation clips Clip[] } ``` --- ## API Routes - Phase 3 Additions ### VODs - `GET /api/channels/:id/vods` - `GET /api/vods/:id` - `PUT /api/vods/:id` - `DELETE /api/vods/:id` - `POST /api/watch-progress` - `GET /api/watch-progress` ### Clips - `POST /api/clips` (create from stream/VOD) - `GET /api/clips/:id` - `PUT /api/clips/:id` - `DELETE /api/clips/:id` - `POST /api/clips/:id/generate` - `GET /api/clips/trending` - `GET /api/channels/:id/clips` ### Analytics - `GET /api/analytics/streams/:id` - `GET /api/analytics/channels/:id` - `GET /api/analytics/charts/viewers` - `POST /api/analytics/export` --- ## Components - Phase 3 Additions ### VOD ``` components/vod/ ├── VODLibrary.tsx ├── VODCard.tsx ├── VODPlayer.tsx └── WatchProgressBar.tsx ``` ### Clips ``` components/clips/ ├── ClipEditor.tsx ├── ClipTimeline.tsx ├── TrimHandles.tsx ├── ClipCard.tsx └── TrendingClips.tsx ``` ### Analytics ``` components/analytics/ ├── AnalyticsDashboard.tsx ├── ViewersChart.tsx ├── EngagementChart.tsx ├── StreamHealth.tsx └── TopContentTable.tsx ``` --- ## Third-Party Services ### Video Processing - **Cloudflare Stream or Mux**: Recording/clipping - **FFmpeg** (self-hosted): Optional for additional processing ### Charts - **Recharts** or **Chart.js**: Graphing library ### Storage - **Cloudflare R2**: VOD and clip storage (already in Phase 1) --- ## Success Metrics ### VOD Metrics - [ ] 100+ VODs created - [ ] 50k+ total VOD views - [ ] 10+ min average VOD watch time - [ ] 30% VOD engagement rate ### Clip Metrics - [ ] 50+ clips created - [ ] 10k+ total clip views - [ ] 5% of viewers create clips - [ ] 100+ clips shared to social media ### Analytics Metrics - [ ] 90%+ creators use analytics dashboard - [ ] Charts load in <2s - [ ] 0 analytics data loss - [ ] Trending clips updated hourly ### Performance Metrics - [ ] VOD playback <2s latency - [ ] Clip generation <2 minutes - [ ] Analytics queries <1s - [ ] Database stays <100GB --- --- ## Phase 3 Timeline | Week | Sprint | Focus | |------|--------|-------| | 9 | 3.1 | VOD archival & playback | | 10 | 3.2 | Clip creation & editing | | 11 | 3.3 | Advanced analytics | | 12-13 | 3.4 | Polish & optimization | --- ## Phase 3 Completion Checklist - [ ] VOD archival working automatically - [ ] VOD playback page functional - [ ] Clip creation from stream working - [ ] Clip editor with trim working - [ ] Clip sharing page built - [ ] Analytics dashboard showing data - [ ] Stream health metrics displaying - [ ] Mobile responsive - [ ] Performance optimized - [ ] Tests passing - [ ] Deployed to production - [ ] 100+ VODs archived - [ ] 50+ clips created --- **Phase 3 Estimated Completion**: Week 13 (by April 18, 2025) **Next Phase**: Phase 4 - Monetization (April 21, 2025) See [PHASE_4_MONETIZATION.md](PHASE_4_MONETIZATION.md) for Phase 4 details.