diff --git a/package.json b/package.json index 48deaa17..7d028427 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "check-db": "node scripts/check-db.js", "check-env": "node scripts/check-env.js", "copy-db-files": "node scripts/copy-db-files.js", - "generate-test-data": "node scripts/generate-test-data.js", + "generate-test-data": "npx tsx scripts/generate-test-data.ts", "extract-messages": "formatjs extract \"src/components/messages.ts\" --out-file build/extracted-messages.json", "merge-messages": "node scripts/merge-messages.js", "generate-lang": "npm-run-all extract-messages merge-messages", diff --git a/scripts/generate-test-data.js b/scripts/generate-test-data.ts similarity index 71% rename from scripts/generate-test-data.js rename to scripts/generate-test-data.ts index 38fd4a94..9fa6a9ef 100644 --- a/scripts/generate-test-data.js +++ b/scripts/generate-test-data.ts @@ -1,6 +1,6 @@ /* eslint-disable no-console */ import 'dotenv/config'; -import { PrismaClient } from '../generated/prisma/client.js'; +import { PrismaClient } from '../src/generated/prisma/client'; import { PrismaPg } from '@prisma/adapter-pg'; import { v4 as uuidv4, v5 as uuidv5 } from 'uuid'; import crypto from 'crypto'; @@ -23,9 +23,9 @@ const SCALES = { description: '14 days, ~10,000 events (~5 min)', }, full: { - days: 30, - avgSessionsPerDay: 666, // ~50,000 total events - description: '30 days, ~50,000 events (~15-20 min)', + days: 60, + avgSessionsPerDay: 500, // ~75,000 total events + description: '60 days, ~75,000 events (~20-25 min)', }, }; @@ -102,97 +102,109 @@ const LANGUAGES = [ ]; const PAGES = [ - { path: '/', title: 'Niteshift - Cloud Dev Environments', weight: 30, isEntry: true }, - { path: '/features', title: 'Features - Niteshift', weight: 15, isEntry: false }, - { path: '/pricing', title: 'Pricing - Niteshift', weight: 12, isEntry: true }, - { path: '/docs', title: 'Documentation - Niteshift', weight: 10, isEntry: true }, + { path: '/', title: 'Hulu - Stream TV and Movies', weight: 30, isEntry: true }, + { path: '/welcome', title: 'Welcome to Hulu', weight: 15, isEntry: true }, + { path: '/plans', title: 'Plans - Hulu', weight: 12, isEntry: true }, + { path: '/browse', title: 'Browse - Hulu', weight: 18, isEntry: true }, + { path: '/browse/movies', title: 'Movies - Hulu', weight: 10, isEntry: false }, + { path: '/browse/tv-shows', title: 'TV Shows - Hulu', weight: 12, isEntry: false }, + { path: '/browse/originals', title: 'Hulu Originals', weight: 8, isEntry: false }, + { path: '/browse/sports', title: 'Sports - Hulu', weight: 6, isEntry: false }, + { path: '/watch/the-bear', title: 'The Bear - Hulu', weight: 8, isEntry: true }, + { path: '/watch/shogun', title: 'Shogun - Hulu', weight: 7, isEntry: true }, + { path: '/watch/abbott-elementary', title: 'Abbott Elementary - Hulu', weight: 6, isEntry: true }, { - path: '/docs/getting-started', - title: 'Getting Started - Niteshift Docs', - weight: 6, - isEntry: false, - }, - { - path: '/docs/api-reference', - title: 'API Reference - Niteshift Docs', - weight: 4, - isEntry: false, - }, - { - path: '/docs/deployment', - title: 'Deployment Guide - Niteshift Docs', - weight: 3, - isEntry: false, - }, - { path: '/blog', title: 'Blog - Niteshift', weight: 8, isEntry: true }, - { - path: '/blog/introducing-niteshift', - title: 'Introducing Niteshift - Niteshift Blog', + path: '/watch/the-handmaids-tale', + title: "The Handmaid's Tale - Hulu", weight: 5, isEntry: true, }, - { - path: '/blog/dev-environments-best-practices', - title: 'Dev Environment Best Practices - Niteshift Blog', - weight: 3, - isEntry: true, - }, - { path: '/about', title: 'About Us - Niteshift', weight: 3, isEntry: false }, - { path: '/contact', title: 'Contact - Niteshift', weight: 2, isEntry: false }, - { path: '/signup', title: 'Sign Up - Niteshift', weight: 6, isEntry: false }, - { path: '/dashboard', title: 'Dashboard - Niteshift', weight: 1, isEntry: false }, + { path: '/watch/futurama', title: 'Futurama - Hulu', weight: 4, isEntry: true }, + { path: '/watch/greys-anatomy', title: "Grey's Anatomy - Hulu", weight: 4, isEntry: false }, + { path: '/my-stuff', title: 'My Stuff - Hulu', weight: 5, isEntry: false }, + { path: '/search', title: 'Search - Hulu', weight: 4, isEntry: false }, + { path: '/account', title: 'Account - Hulu', weight: 3, isEntry: false }, + { path: '/signup', title: 'Sign Up - Hulu', weight: 8, isEntry: false }, + { path: '/subscribe', title: 'Subscribe - Hulu', weight: 4, isEntry: false }, ]; const REFERRERS = [ - { type: 'direct', domain: '', weight: 35 }, + { type: 'direct', domain: '', weight: 30 }, + // Search engines { type: 'search', domain: 'google.com', weight: 25 }, - { type: 'search', domain: 'bing.com', weight: 3 }, - { type: 'search', domain: 'duckduckgo.com', weight: 2 }, - { type: 'social', domain: 'twitter.com', weight: 6 }, - { type: 'social', domain: 'linkedin.com', weight: 5 }, + { type: 'search', domain: 'bing.com', weight: 4 }, + { type: 'search', domain: 'yahoo.com', weight: 2 }, + { type: 'search', domain: 'duckduckgo.com', weight: 1 }, + // Social media + { type: 'social', domain: 'facebook.com', weight: 8 }, + { type: 'social', domain: 'twitter.com', weight: 4 }, + { type: 'social', domain: 'instagram.com', weight: 3 }, + { type: 'social', domain: 'tiktok.com', weight: 3 }, { type: 'social', domain: 'reddit.com', weight: 2 }, - { type: 'social', domain: 'news.ycombinator.com', weight: 2 }, - { type: 'referral', domain: 'dev.to', weight: 3 }, - { type: 'referral', domain: 'medium.com', weight: 2 }, - { type: 'referral', domain: 'indiehackers.com', weight: 2 }, - { type: 'referral', domain: 'producthunt.com', weight: 2 }, + { type: 'social', domain: 'youtube.com', weight: 2 }, + // Review & comparison sites + { type: 'referral', domain: 'cnet.com', weight: 2 }, + { type: 'referral', domain: 'techradar.com', weight: 1 }, + { type: 'referral', domain: 'tomsguide.com', weight: 1 }, + { type: 'referral', domain: 'pcmag.com', weight: 1 }, + { type: 'referral', domain: 'theverge.com', weight: 1 }, + // Entertainment news + { type: 'referral', domain: 'ew.com', weight: 1 }, + { type: 'referral', domain: 'variety.com', weight: 1 }, + { type: 'referral', domain: 'deadline.com', weight: 1 }, + { type: 'referral', domain: 'tvline.com', weight: 1 }, + // Deal sites + { type: 'referral', domain: 'slickdeals.net', weight: 2 }, + { type: 'referral', domain: 'retailmenot.com', weight: 1 }, + // Aggregators + { type: 'referral', domain: 'justwatch.com', weight: 2 }, + { type: 'referral', domain: 'reelgood.com', weight: 1 }, ]; const UTM_CAMPAIGNS = [ { source: 'google', medium: 'cpc', - campaign: 'dev_tools_2025', + campaign: 'streaming_2025', content: ['ad_variant_1', 'ad_variant_2'], - term: ['cloud dev', 'dev environment', 'remote development'], + term: ['stream tv', 'watch movies online', 'hulu subscription'], weight: 40, }, { - source: 'producthunt', + source: 'facebook', medium: 'social', - campaign: 'ph_launch', - content: null, + campaign: 'new_shows_promo', + content: ['the_bear', 'shogun'], term: null, - weight: 35, + weight: 30, }, { source: 'newsletter', medium: 'email', - campaign: 'feature_announcement', + campaign: 'new_releases', content: null, term: null, - weight: 25, + weight: 20, + }, + { + source: 'tiktok', + medium: 'social', + campaign: 'viral_clips', + content: null, + term: null, + weight: 10, }, ]; const CUSTOM_EVENTS = [ - { name: 'click_cta_hero', frequency: 0.4 }, // 40% of homepage visits - { name: 'click_start_free_trial', frequency: 0.3 }, // 30% of pricing page visits - { name: 'download_whitepaper', frequency: 0.15 }, - { name: 'play_demo_video', frequency: 0.2 }, - { name: 'submit_contact_form', frequency: 0.1 }, - { name: 'click_docs_search', frequency: 0.25 }, - { name: 'share_social', frequency: 0.08 }, + { name: 'click_start_trial', frequency: 0.4 }, // 40% of homepage visits + { name: 'click_subscribe', frequency: 0.3 }, // 30% of plans page visits + { name: 'play_video', frequency: 0.5 }, // Video plays + { name: 'add_to_my_stuff', frequency: 0.25 }, + { name: 'search_content', frequency: 0.3 }, + { name: 'share_show', frequency: 0.08 }, + { name: 'complete_episode', frequency: 0.35 }, + { name: 'pause_video', frequency: 0.4 }, ]; // ============================================================================ @@ -355,10 +367,51 @@ function generateUserJourney(session, websiteId, startTime) { urlQuery = 'q=' + encodeURIComponent( - ['cloud dev', 'dev environment', 'remote development', 'niteshift'][randomInt(0, 3)], + [ + 'hulu', + 'hulu free trial', + 'stream tv online', + 'watch movies online', + 'the bear hulu', + 'hulu subscription', + 'hulu vs netflix', + 'best streaming service', + 'hulu plans', + 'shogun where to watch', + ][randomInt(0, 9)], ); } else if (referrer.type === 'social') { - referrerPath = referrer.domain === 'news.ycombinator.com' ? '/item?id=123456' : '/posts/123'; + // Different paths for different social platforms + if (referrer.domain === 'reddit.com') { + referrerPath = ['/r/cordcutters', '/r/television', '/r/Hulu', '/r/streaming'][ + randomInt(0, 3) + ]; + } else if (referrer.domain === 'youtube.com') { + referrerPath = '/watch?v=' + Math.random().toString(36).substring(2, 13); + } else if (referrer.domain === 'tiktok.com') { + referrerPath = '/@hulureviews/video/' + randomInt(1000000, 9999999); + } else { + referrerPath = '/posts/' + randomInt(100000, 999999); + } + } else if (referrer.type === 'referral') { + // Different paths for different referral sites + if (referrer.domain === 'justwatch.com' || referrer.domain === 'reelgood.com') { + referrerPath = ['/us/provider/hulu', '/us/movie/the-bear', '/us/tv-show/shogun'][ + randomInt(0, 2) + ]; + } else if (referrer.domain.includes('slickdeals') || referrer.domain.includes('retailmenot')) { + referrerPath = '/coupons/hulu'; + } else { + // News/review sites - article paths + referrerPath = + '/streaming/' + + [ + 'hulu-review', + 'best-streaming-services-2025', + 'hulu-vs-netflix', + 'the-bear-season-3-review', + ][randomInt(0, 3)]; + } } let currentTime = new Date(startTime); @@ -389,7 +442,7 @@ function generateUserJourney(session, websiteId, startTime) { pageTitle: currentPage.title, eventType: 1, // pageview eventName: null, - hostname: 'niteshift.dev', + hostname: 'hulu.com', ...utmParams, createdAt: currentTime, }); @@ -401,8 +454,9 @@ function generateUserJourney(session, websiteId, startTime) { // Generate custom event for entry page const entryEvent = CUSTOM_EVENTS.find(e => { - if (currentPage.path === '/' && e.name === 'click_cta_hero') return true; - if (currentPage.path === '/pricing' && e.name === 'click_start_free_trial') return true; + if (currentPage.path === '/' && e.name === 'click_start_trial') return true; + if (currentPage.path === '/plans' && e.name === 'click_subscribe') return true; + if (currentPage.path.startsWith('/watch/') && e.name === 'play_video') return true; return false; }); @@ -421,7 +475,7 @@ function generateUserJourney(session, websiteId, startTime) { pageTitle: null, eventType: 2, // custom event eventName: entryEvent.name, - hostname: 'niteshift.dev', + hostname: 'hulu.com', createdAt: currentTime, }); } @@ -432,26 +486,60 @@ function generateUserJourney(session, websiteId, startTime) { for (let i = 0; i < additionalPages; i++) { currentTime = addSeconds(currentTime, randomInt(30, 180)); // 30s - 3min between pages - // Simple funnel logic + // Hulu-style funnel logic if (currentPage.path === '/') { - currentPage = - Math.random() < 0.5 ? PAGES.find(p => p.path === '/features') : weightedRandom(PAGES); - } else if (currentPage.path === '/features') { - currentPage = - Math.random() < 0.4 ? PAGES.find(p => p.path === '/pricing') : weightedRandom(PAGES); - } else if (currentPage.path === '/pricing') { - currentPage = - Math.random() < 0.3 ? PAGES.find(p => p.path === '/signup') : weightedRandom(PAGES); - } else if (currentPage.path === '/signup') { - // 60% convert to dashboard + // From homepage, users go to browse, plans, or watch content + const rand = Math.random(); + if (rand < 0.4) { + currentPage = PAGES.find(p => p.path === '/browse'); + } else if (rand < 0.6) { + currentPage = PAGES.find(p => p.path === '/plans'); + } else { + currentPage = weightedRandom(PAGES); + } + } else if (currentPage.path === '/browse') { + // From browse, drill into categories or watch content + const rand = Math.random(); + if (rand < 0.3) { + currentPage = PAGES.find(p => p.path === '/browse/tv-shows'); + } else if (rand < 0.5) { + currentPage = PAGES.find(p => p.path === '/browse/movies'); + } else if (rand < 0.7) { + currentPage = weightedRandom(PAGES.filter(p => p.path.startsWith('/watch/'))); + } else { + currentPage = weightedRandom(PAGES); + } + } else if (currentPage.path.startsWith('/browse/')) { + // From category pages, watch content if (Math.random() < 0.6) { - currentPage = PAGES.find(p => p.path === '/dashboard'); + currentPage = weightedRandom(PAGES.filter(p => p.path.startsWith('/watch/'))); + } else { + currentPage = weightedRandom(PAGES); + } + } else if (currentPage.path === '/plans') { + // From plans, go to signup + if (Math.random() < 0.4) { + currentPage = PAGES.find(p => p.path === '/signup'); + } else { + currentPage = weightedRandom(PAGES); + } + } else if (currentPage.path === '/signup') { + // 50% convert to subscribe + if (Math.random() < 0.5) { + currentPage = PAGES.find(p => p.path === '/subscribe'); } else { break; // Exit funnel } - } else if (currentPage.path === '/dashboard') { - // End of conversion funnel + } else if (currentPage.path === '/subscribe') { + // End of conversion funnel - they subscribed! break; + } else if (currentPage.path.startsWith('/watch/')) { + // From watching, go to my-stuff or browse more + if (Math.random() < 0.3) { + currentPage = PAGES.find(p => p.path === '/my-stuff'); + } else { + currentPage = weightedRandom(PAGES); + } } else { currentPage = weightedRandom(PAGES); } @@ -468,7 +556,7 @@ function generateUserJourney(session, websiteId, startTime) { pageTitle: currentPage.title, eventType: 1, eventName: null, - hostname: 'niteshift.dev', + hostname: 'hulu.com', createdAt: currentTime, }); @@ -488,7 +576,7 @@ function generateUserJourney(session, websiteId, startTime) { pageTitle: null, eventType: 2, eventName: evt.name, - hostname: 'niteshift.dev', + hostname: 'hulu.com', createdAt: currentTime, }); } @@ -501,16 +589,25 @@ function generateEventData(event) { if (event.eventType !== 2 || !event.eventName) return null; const data = []; + const shows = [ + 'the-bear', + 'shogun', + 'abbott-elementary', + 'the-handmaids-tale', + 'futurama', + 'greys-anatomy', + ]; + const genres = ['drama', 'comedy', 'action', 'thriller', 'documentary', 'sci-fi', 'romance']; switch (event.eventName) { - case 'click_cta_hero': + case 'click_start_trial': data.push( { id: uuidv4(), websiteId: event.websiteId, websiteEventId: event.id, dataKey: 'button_text', - stringValue: 'Start Free Trial', + stringValue: 'Start Your Free Trial', dataType: 1, }, { @@ -518,39 +615,29 @@ function generateEventData(event) { websiteId: event.websiteId, websiteEventId: event.id, dataKey: 'position', - stringValue: 'above_fold', + stringValue: 'hero', dataType: 1, }, ); break; - case 'click_start_free_trial': + case 'click_subscribe': data.push({ id: uuidv4(), websiteId: event.websiteId, websiteEventId: event.id, - dataKey: 'button_text', - stringValue: 'Start Trial', + dataKey: 'plan_type', + stringValue: ['basic', 'premium', 'bundle'][randomInt(0, 2)], dataType: 1, }); break; - case 'download_whitepaper': - data.push({ - id: uuidv4(), - websiteId: event.websiteId, - websiteEventId: event.id, - dataKey: 'document', - stringValue: 'dev-tools-guide-2025.pdf', - dataType: 1, - }); - break; - case 'play_demo_video': + case 'play_video': data.push( { id: uuidv4(), websiteId: event.websiteId, websiteEventId: event.id, - dataKey: 'video_id', - stringValue: 'intro_v2', + dataKey: 'content_id', + stringValue: shows[randomInt(0, shows.length - 1)], dataType: 1, }, { @@ -558,35 +645,75 @@ function generateEventData(event) { websiteId: event.websiteId, websiteEventId: event.id, dataKey: 'duration_watched', - numberValue: randomInt(15, 120), + numberValue: randomInt(60, 3600), // 1 min to 1 hour dataType: 2, }, + { + id: uuidv4(), + websiteId: event.websiteId, + websiteEventId: event.id, + dataKey: 'genre', + stringValue: genres[randomInt(0, genres.length - 1)], + dataType: 1, + }, ); break; - case 'submit_contact_form': + case 'add_to_my_stuff': data.push({ id: uuidv4(), websiteId: event.websiteId, websiteEventId: event.id, - dataKey: 'form_type', - stringValue: 'contact', + dataKey: 'content_id', + stringValue: shows[randomInt(0, shows.length - 1)], dataType: 1, }); break; + case 'search_content': + data.push({ + id: uuidv4(), + websiteId: event.websiteId, + websiteEventId: event.id, + dataKey: 'search_term', + stringValue: ['action movies', 'comedy series', 'new releases', 'the bear'][ + randomInt(0, 3) + ], + dataType: 1, + }); + break; + case 'complete_episode': + data.push( + { + id: uuidv4(), + websiteId: event.websiteId, + websiteEventId: event.id, + dataKey: 'content_id', + stringValue: shows[randomInt(0, shows.length - 1)], + dataType: 1, + }, + { + id: uuidv4(), + websiteId: event.websiteId, + websiteEventId: event.id, + dataKey: 'episode_number', + numberValue: randomInt(1, 10), + dataType: 2, + }, + ); + break; } return data.length > 0 ? data : null; } function generateRevenue(event, session) { - // Only generate revenue for dashboard conversions - if (event.urlPath !== '/dashboard') return null; + // Only generate revenue for subscribe conversions + if (event.urlPath !== '/subscribe') return null; - // Revenue tiers + // Hulu subscription tiers const tiers = [ - { revenue: 29, currency: 'USD', weight: 60 }, - { revenue: 79, currency: 'USD', weight: 30 }, - { revenue: 199, currency: 'USD', weight: 10 }, + { revenue: 7.99, currency: 'USD', weight: 40, name: 'basic' }, // Hulu Basic (with ads) + { revenue: 17.99, currency: 'USD', weight: 35, name: 'premium' }, // Hulu (No Ads) + { revenue: 76.99, currency: 'USD', weight: 25, name: 'bundle' }, // Disney Bundle ]; // Different currencies based on country @@ -724,18 +851,17 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) { userId, websiteId, type: 'funnel', - name: 'Signup Conversion Funnel', - description: 'Track users from homepage to signup completion', + name: 'Subscription Conversion Funnel', + description: 'Track users from homepage to subscription', parameters: { startDate: thirtyDaysAgo.toISOString(), endDate: now.toISOString(), window: 30, // 30 minutes to complete steps: [ { type: 'path', value: '/' }, - { type: 'path', value: '/features' }, - { type: 'path', value: '/pricing' }, + { type: 'path', value: '/plans' }, { type: 'path', value: '/signup' }, - { type: 'path', value: '/dashboard' }, + { type: 'path', value: '/subscribe' }, ], }, createdAt: now, @@ -746,16 +872,16 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) { userId, websiteId, type: 'funnel', - name: 'Documentation Journey', - description: 'How users navigate through documentation', + name: 'Content Discovery Journey', + description: 'How users find and watch content', parameters: { startDate: thirtyDaysAgo.toISOString(), endDate: now.toISOString(), window: 60, // 60 minutes to complete steps: [ - { type: 'path', value: '/docs' }, - { type: 'path', value: '/docs/getting-started' }, - { type: 'path', value: '/docs/api-reference' }, + { type: 'path', value: '/browse' }, + { type: 'path', value: '/browse/tv-shows' }, + { type: 'path', value: '/watch/*' }, ], }, createdAt: now, @@ -766,16 +892,16 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) { userId, websiteId, type: 'funnel', - name: 'Blog Engagement Flow', - description: 'From blog discovery to documentation', + name: 'Browse to Watch Flow', + description: 'From browsing to actually watching', parameters: { startDate: thirtyDaysAgo.toISOString(), endDate: now.toISOString(), window: 45, steps: [ - { type: 'path', value: '/blog' }, - { type: 'path', value: '/blog/*' }, // Any blog post - { type: 'path', value: '/docs' }, + { type: 'path', value: '/browse' }, + { type: 'path', value: '/watch/*' }, + { type: 'event', value: 'play_video' }, ], }, createdAt: now, @@ -786,16 +912,16 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) { userId, websiteId, type: 'funnel', - name: 'CTA Click to Conversion', - description: 'Track CTA effectiveness', + name: 'Trial to Subscription', + description: 'Track trial CTA to subscription', parameters: { startDate: thirtyDaysAgo.toISOString(), endDate: now.toISOString(), window: 20, steps: [ - { type: 'event', value: 'click_cta_hero' }, - { type: 'path', value: '/pricing' }, - { type: 'path', value: '/signup' }, + { type: 'event', value: 'click_start_trial' }, + { type: 'path', value: '/plans' }, + { type: 'path', value: '/subscribe' }, ], }, createdAt: now, @@ -812,7 +938,7 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) { id: uuidv4(), websiteId, type: 'segment', - name: 'US Mobile Users', + name: 'US Mobile Streamers', parameters: { filters: [ { name: 'country', operator: 'eq', value: 'US' }, @@ -826,11 +952,11 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) { id: uuidv4(), websiteId, type: 'segment', - name: 'Chrome Desktop Users', + name: 'Smart TV Users', parameters: { filters: [ - { name: 'browser', operator: 'eq', value: 'Chrome' }, { name: 'device', operator: 'eq', value: 'desktop' }, + { name: 'screen', operator: 'eq', value: '1920x1080' }, ], }, createdAt: now, @@ -840,9 +966,9 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) { id: uuidv4(), websiteId, type: 'segment', - name: 'Blog Readers', + name: 'Content Watchers', parameters: { - filters: [{ name: 'path', operator: 'c', value: '/blog/' }], + filters: [{ name: 'path', operator: 'c', value: '/watch/' }], }, createdAt: now, updatedAt: now, @@ -851,7 +977,7 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) { id: uuidv4(), websiteId, type: 'segment', - name: 'European Visitors', + name: 'International Viewers', parameters: { filters: [ { @@ -868,9 +994,9 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) { id: uuidv4(), websiteId, type: 'segment', - name: 'Documentation Users', + name: 'Browse Users', parameters: { - filters: [{ name: 'path', operator: 'c', value: '/docs' }], + filters: [{ name: 'path', operator: 'c', value: '/browse' }], }, createdAt: now, updatedAt: now, @@ -879,13 +1005,13 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) { id: uuidv4(), websiteId, type: 'segment', - name: 'High-Res Screens', + name: 'Tablet Streamers', parameters: { filters: [ { - name: 'screen', + name: 'device', operator: 'eq', - value: '1920x1080,2560x1440', + value: 'tablet', }, ], }, @@ -903,15 +1029,15 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) { id: uuidv4(), websiteId, type: 'cohort', - name: 'January Signups', + name: 'November Subscribers', parameters: { dateRange: { - startDate: '2025-01-01T00:00:00.000Z', - endDate: '2025-01-31T23:59:59.999Z', + startDate: '2025-11-01T00:00:00.000Z', + endDate: '2025-11-30T23:59:59.999Z', }, action: { type: 'path', - value: '/dashboard', + value: '/subscribe', }, filters: [], }, @@ -922,7 +1048,7 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) { id: uuidv4(), websiteId, type: 'cohort', - name: 'Product Hunt Traffic', + name: 'Social Media Traffic', parameters: { dateRange: { startDate: thirtyDaysAgo.toISOString(), @@ -932,7 +1058,7 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) { type: 'path', value: '/', }, - filters: [{ name: 'referrer', operator: 'c', value: 'producthunt' }], + filters: [{ name: 'referrer', operator: 'c', value: 'facebook' }], }, createdAt: now, updatedAt: now, @@ -941,7 +1067,7 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) { id: uuidv4(), websiteId, type: 'cohort', - name: 'Google Ads Converters', + name: 'Google Ads Subscribers', parameters: { dateRange: { startDate: thirtyDaysAgo.toISOString(), @@ -949,7 +1075,7 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) { }, action: { type: 'path', - value: '/dashboard', + value: '/subscribe', }, filters: [{ name: 'query', operator: 'c', value: 'utm_source=google' }], }, @@ -960,7 +1086,7 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) { id: uuidv4(), websiteId, type: 'cohort', - name: 'Blog Engaged Users', + name: 'Active Viewers', parameters: { dateRange: { startDate: subDays(now, 14).toISOString(), // Last 2 weeks @@ -968,9 +1094,9 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) { }, action: { type: 'event', - value: 'click_cta_hero', + value: 'play_video', }, - filters: [{ name: 'path', operator: 'c', value: '/blog' }], + filters: [{ name: 'path', operator: 'c', value: '/watch' }], }, createdAt: now, updatedAt: now, @@ -987,8 +1113,8 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) { userId, websiteId, type: 'retention', - name: 'User Retention Analysis', - description: 'Track returning visitors over 30 days', + name: 'Viewer Retention Analysis', + description: 'Track returning viewers over 30 days', parameters: { startDate: thirtyDaysAgo.toISOString(), endDate: now.toISOString(), @@ -1001,8 +1127,8 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) { userId, websiteId, type: 'journey', - name: 'Top User Journeys', - description: 'Most common navigation paths (5 steps)', + name: 'Top Viewer Journeys', + description: 'Most common content discovery paths (5 steps)', parameters: { startDate: thirtyDaysAgo.toISOString(), endDate: now.toISOString(), @@ -1030,7 +1156,7 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) { userId, websiteId, type: 'revenue', - name: 'Revenue by Country', + name: 'Subscription Revenue by Country', description: 'Revenue breakdown by geographic location', parameters: { startDate: thirtyDaysAgo.toISOString(), @@ -1046,12 +1172,12 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) { websiteId, type: 'goal', name: 'Video Play Goal', - description: 'Track video engagement', + description: 'Track video streaming engagement', parameters: { startDate: thirtyDaysAgo.toISOString(), endDate: now.toISOString(), type: 'event', - value: 'play_demo_video', + value: 'play_video', }, createdAt: now, updatedAt: now, @@ -1100,7 +1226,7 @@ async function main() { try { // Get website console.log('🔍 Looking up website...'); - const website = await getWebsite(prisma, 'niteshift.dev'); + const website = await getWebsite(prisma, 'hulu.com'); console.log(`✓ Found website: ${website.name} (${website.id})\n`); // Get admin user for reports