mirror of
https://github.com/umami-software/umami.git
synced 2026-02-04 04:37:11 +01:00
Update test data generator for Hulu demo
- Change organization from Niteshift to Hulu (hulu.com domain) - Update pages to streaming service structure (browse, watch, plans, etc.) - Add realistic Hulu shows: The Bear, Shogun, Abbott Elementary, etc. - Update custom events for streaming: play_video, complete_episode, etc. - Add realistic referrers: review sites, entertainment news, deal sites - Update revenue tiers to Hulu subscription plans ($7.99-$76.99) - Convert script to TypeScript and use tsx for execution - Update funnels, segments, and cohorts for streaming analytics
This commit is contained in:
parent
23a3c6cf6b
commit
34373f6aae
2 changed files with 289 additions and 163 deletions
|
|
@ -33,7 +33,7 @@
|
||||||
"check-db": "node scripts/check-db.js",
|
"check-db": "node scripts/check-db.js",
|
||||||
"check-env": "node scripts/check-env.js",
|
"check-env": "node scripts/check-env.js",
|
||||||
"copy-db-files": "node scripts/copy-db-files.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",
|
"extract-messages": "formatjs extract \"src/components/messages.ts\" --out-file build/extracted-messages.json",
|
||||||
"merge-messages": "node scripts/merge-messages.js",
|
"merge-messages": "node scripts/merge-messages.js",
|
||||||
"generate-lang": "npm-run-all extract-messages merge-messages",
|
"generate-lang": "npm-run-all extract-messages merge-messages",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
import 'dotenv/config';
|
import 'dotenv/config';
|
||||||
import { PrismaClient } from '../generated/prisma/client.js';
|
import { PrismaClient } from '../src/generated/prisma/client';
|
||||||
import { PrismaPg } from '@prisma/adapter-pg';
|
import { PrismaPg } from '@prisma/adapter-pg';
|
||||||
import { v4 as uuidv4, v5 as uuidv5 } from 'uuid';
|
import { v4 as uuidv4, v5 as uuidv5 } from 'uuid';
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
|
|
@ -102,97 +102,109 @@ const LANGUAGES = [
|
||||||
];
|
];
|
||||||
|
|
||||||
const PAGES = [
|
const PAGES = [
|
||||||
{ path: '/', title: 'Niteshift - Cloud Dev Environments', weight: 30, isEntry: true },
|
{ path: '/', title: 'Hulu - Stream TV and Movies', weight: 30, isEntry: true },
|
||||||
{ path: '/features', title: 'Features - Niteshift', weight: 15, isEntry: false },
|
{ path: '/welcome', title: 'Welcome to Hulu', weight: 15, isEntry: true },
|
||||||
{ path: '/pricing', title: 'Pricing - Niteshift', weight: 12, isEntry: true },
|
{ path: '/plans', title: 'Plans - Hulu', weight: 12, isEntry: true },
|
||||||
{ path: '/docs', title: 'Documentation - Niteshift', weight: 10, 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',
|
path: '/watch/the-handmaids-tale',
|
||||||
title: 'Getting Started - Niteshift Docs',
|
title: "The Handmaid's Tale - Hulu",
|
||||||
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',
|
|
||||||
weight: 5,
|
weight: 5,
|
||||||
isEntry: true,
|
isEntry: true,
|
||||||
},
|
},
|
||||||
{
|
{ path: '/watch/futurama', title: 'Futurama - Hulu', weight: 4, isEntry: true },
|
||||||
path: '/blog/dev-environments-best-practices',
|
{ path: '/watch/greys-anatomy', title: "Grey's Anatomy - Hulu", weight: 4, isEntry: false },
|
||||||
title: 'Dev Environment Best Practices - Niteshift Blog',
|
{ path: '/my-stuff', title: 'My Stuff - Hulu', weight: 5, isEntry: false },
|
||||||
weight: 3,
|
{ path: '/search', title: 'Search - Hulu', weight: 4, isEntry: false },
|
||||||
isEntry: true,
|
{ path: '/account', title: 'Account - Hulu', weight: 3, isEntry: false },
|
||||||
},
|
{ path: '/signup', title: 'Sign Up - Hulu', weight: 8, isEntry: false },
|
||||||
{ path: '/about', title: 'About Us - Niteshift', weight: 3, isEntry: false },
|
{ path: '/subscribe', title: 'Subscribe - Hulu', weight: 4, 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 },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const REFERRERS = [
|
const REFERRERS = [
|
||||||
{ type: 'direct', domain: '', weight: 35 },
|
{ type: 'direct', domain: '', weight: 30 },
|
||||||
|
// Search engines
|
||||||
{ type: 'search', domain: 'google.com', weight: 25 },
|
{ type: 'search', domain: 'google.com', weight: 25 },
|
||||||
{ type: 'search', domain: 'bing.com', weight: 3 },
|
{ type: 'search', domain: 'bing.com', weight: 4 },
|
||||||
{ type: 'search', domain: 'duckduckgo.com', weight: 2 },
|
{ type: 'search', domain: 'yahoo.com', weight: 2 },
|
||||||
{ type: 'social', domain: 'twitter.com', weight: 6 },
|
{ type: 'search', domain: 'duckduckgo.com', weight: 1 },
|
||||||
{ type: 'social', domain: 'linkedin.com', weight: 5 },
|
// 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: 'reddit.com', weight: 2 },
|
||||||
{ type: 'social', domain: 'news.ycombinator.com', weight: 2 },
|
{ type: 'social', domain: 'youtube.com', weight: 2 },
|
||||||
{ type: 'referral', domain: 'dev.to', weight: 3 },
|
// Review & comparison sites
|
||||||
{ type: 'referral', domain: 'medium.com', weight: 2 },
|
{ type: 'referral', domain: 'cnet.com', weight: 2 },
|
||||||
{ type: 'referral', domain: 'indiehackers.com', weight: 2 },
|
{ type: 'referral', domain: 'techradar.com', weight: 1 },
|
||||||
{ type: 'referral', domain: 'producthunt.com', weight: 2 },
|
{ 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 = [
|
const UTM_CAMPAIGNS = [
|
||||||
{
|
{
|
||||||
source: 'google',
|
source: 'google',
|
||||||
medium: 'cpc',
|
medium: 'cpc',
|
||||||
campaign: 'dev_tools_2025',
|
campaign: 'streaming_2025',
|
||||||
content: ['ad_variant_1', 'ad_variant_2'],
|
content: ['ad_variant_1', 'ad_variant_2'],
|
||||||
term: ['cloud dev', 'dev environment', 'remote development'],
|
term: ['stream tv', 'watch movies online', 'hulu subscription'],
|
||||||
weight: 40,
|
weight: 40,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: 'producthunt',
|
source: 'facebook',
|
||||||
medium: 'social',
|
medium: 'social',
|
||||||
campaign: 'ph_launch',
|
campaign: 'new_shows_promo',
|
||||||
content: null,
|
content: ['the_bear', 'shogun'],
|
||||||
term: null,
|
term: null,
|
||||||
weight: 35,
|
weight: 30,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: 'newsletter',
|
source: 'newsletter',
|
||||||
medium: 'email',
|
medium: 'email',
|
||||||
campaign: 'feature_announcement',
|
campaign: 'new_releases',
|
||||||
content: null,
|
content: null,
|
||||||
term: null,
|
term: null,
|
||||||
weight: 25,
|
weight: 20,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
source: 'tiktok',
|
||||||
|
medium: 'social',
|
||||||
|
campaign: 'viral_clips',
|
||||||
|
content: null,
|
||||||
|
term: null,
|
||||||
|
weight: 10,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const CUSTOM_EVENTS = [
|
const CUSTOM_EVENTS = [
|
||||||
{ name: 'click_cta_hero', frequency: 0.4 }, // 40% of homepage visits
|
{ name: 'click_start_trial', frequency: 0.4 }, // 40% of homepage visits
|
||||||
{ name: 'click_start_free_trial', frequency: 0.3 }, // 30% of pricing page visits
|
{ name: 'click_subscribe', frequency: 0.3 }, // 30% of plans page visits
|
||||||
{ name: 'download_whitepaper', frequency: 0.15 },
|
{ name: 'play_video', frequency: 0.5 }, // Video plays
|
||||||
{ name: 'play_demo_video', frequency: 0.2 },
|
{ name: 'add_to_my_stuff', frequency: 0.25 },
|
||||||
{ name: 'submit_contact_form', frequency: 0.1 },
|
{ name: 'search_content', frequency: 0.3 },
|
||||||
{ name: 'click_docs_search', frequency: 0.25 },
|
{ name: 'share_show', frequency: 0.08 },
|
||||||
{ name: 'share_social', 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 =
|
urlQuery =
|
||||||
'q=' +
|
'q=' +
|
||||||
encodeURIComponent(
|
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') {
|
} 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);
|
let currentTime = new Date(startTime);
|
||||||
|
|
@ -389,7 +442,7 @@ function generateUserJourney(session, websiteId, startTime) {
|
||||||
pageTitle: currentPage.title,
|
pageTitle: currentPage.title,
|
||||||
eventType: 1, // pageview
|
eventType: 1, // pageview
|
||||||
eventName: null,
|
eventName: null,
|
||||||
hostname: 'niteshift.dev',
|
hostname: 'hulu.com',
|
||||||
...utmParams,
|
...utmParams,
|
||||||
createdAt: currentTime,
|
createdAt: currentTime,
|
||||||
});
|
});
|
||||||
|
|
@ -401,8 +454,9 @@ function generateUserJourney(session, websiteId, startTime) {
|
||||||
|
|
||||||
// Generate custom event for entry page
|
// Generate custom event for entry page
|
||||||
const entryEvent = CUSTOM_EVENTS.find(e => {
|
const entryEvent = CUSTOM_EVENTS.find(e => {
|
||||||
if (currentPage.path === '/' && e.name === 'click_cta_hero') return true;
|
if (currentPage.path === '/' && e.name === 'click_start_trial') return true;
|
||||||
if (currentPage.path === '/pricing' && e.name === 'click_start_free_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;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -421,7 +475,7 @@ function generateUserJourney(session, websiteId, startTime) {
|
||||||
pageTitle: null,
|
pageTitle: null,
|
||||||
eventType: 2, // custom event
|
eventType: 2, // custom event
|
||||||
eventName: entryEvent.name,
|
eventName: entryEvent.name,
|
||||||
hostname: 'niteshift.dev',
|
hostname: 'hulu.com',
|
||||||
createdAt: currentTime,
|
createdAt: currentTime,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -432,26 +486,60 @@ function generateUserJourney(session, websiteId, startTime) {
|
||||||
for (let i = 0; i < additionalPages; i++) {
|
for (let i = 0; i < additionalPages; i++) {
|
||||||
currentTime = addSeconds(currentTime, randomInt(30, 180)); // 30s - 3min between pages
|
currentTime = addSeconds(currentTime, randomInt(30, 180)); // 30s - 3min between pages
|
||||||
|
|
||||||
// Simple funnel logic
|
// Hulu-style funnel logic
|
||||||
if (currentPage.path === '/') {
|
if (currentPage.path === '/') {
|
||||||
currentPage =
|
// From homepage, users go to browse, plans, or watch content
|
||||||
Math.random() < 0.5 ? PAGES.find(p => p.path === '/features') : weightedRandom(PAGES);
|
const rand = Math.random();
|
||||||
} else if (currentPage.path === '/features') {
|
if (rand < 0.4) {
|
||||||
currentPage =
|
currentPage = PAGES.find(p => p.path === '/browse');
|
||||||
Math.random() < 0.4 ? PAGES.find(p => p.path === '/pricing') : weightedRandom(PAGES);
|
} else if (rand < 0.6) {
|
||||||
} else if (currentPage.path === '/pricing') {
|
currentPage = PAGES.find(p => p.path === '/plans');
|
||||||
currentPage =
|
} else {
|
||||||
Math.random() < 0.3 ? PAGES.find(p => p.path === '/signup') : weightedRandom(PAGES);
|
currentPage = weightedRandom(PAGES);
|
||||||
} else if (currentPage.path === '/signup') {
|
}
|
||||||
// 60% convert to dashboard
|
} 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) {
|
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 {
|
} else {
|
||||||
break; // Exit funnel
|
break; // Exit funnel
|
||||||
}
|
}
|
||||||
} else if (currentPage.path === '/dashboard') {
|
} else if (currentPage.path === '/subscribe') {
|
||||||
// End of conversion funnel
|
// End of conversion funnel - they subscribed!
|
||||||
break;
|
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 {
|
} else {
|
||||||
currentPage = weightedRandom(PAGES);
|
currentPage = weightedRandom(PAGES);
|
||||||
}
|
}
|
||||||
|
|
@ -468,7 +556,7 @@ function generateUserJourney(session, websiteId, startTime) {
|
||||||
pageTitle: currentPage.title,
|
pageTitle: currentPage.title,
|
||||||
eventType: 1,
|
eventType: 1,
|
||||||
eventName: null,
|
eventName: null,
|
||||||
hostname: 'niteshift.dev',
|
hostname: 'hulu.com',
|
||||||
createdAt: currentTime,
|
createdAt: currentTime,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -488,7 +576,7 @@ function generateUserJourney(session, websiteId, startTime) {
|
||||||
pageTitle: null,
|
pageTitle: null,
|
||||||
eventType: 2,
|
eventType: 2,
|
||||||
eventName: evt.name,
|
eventName: evt.name,
|
||||||
hostname: 'niteshift.dev',
|
hostname: 'hulu.com',
|
||||||
createdAt: currentTime,
|
createdAt: currentTime,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -501,16 +589,25 @@ function generateEventData(event) {
|
||||||
if (event.eventType !== 2 || !event.eventName) return null;
|
if (event.eventType !== 2 || !event.eventName) return null;
|
||||||
|
|
||||||
const data = [];
|
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) {
|
switch (event.eventName) {
|
||||||
case 'click_cta_hero':
|
case 'click_start_trial':
|
||||||
data.push(
|
data.push(
|
||||||
{
|
{
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
websiteId: event.websiteId,
|
websiteId: event.websiteId,
|
||||||
websiteEventId: event.id,
|
websiteEventId: event.id,
|
||||||
dataKey: 'button_text',
|
dataKey: 'button_text',
|
||||||
stringValue: 'Start Free Trial',
|
stringValue: 'Start Your Free Trial',
|
||||||
dataType: 1,
|
dataType: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -518,39 +615,29 @@ function generateEventData(event) {
|
||||||
websiteId: event.websiteId,
|
websiteId: event.websiteId,
|
||||||
websiteEventId: event.id,
|
websiteEventId: event.id,
|
||||||
dataKey: 'position',
|
dataKey: 'position',
|
||||||
stringValue: 'above_fold',
|
stringValue: 'hero',
|
||||||
dataType: 1,
|
dataType: 1,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'click_start_free_trial':
|
case 'click_subscribe':
|
||||||
data.push({
|
data.push({
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
websiteId: event.websiteId,
|
websiteId: event.websiteId,
|
||||||
websiteEventId: event.id,
|
websiteEventId: event.id,
|
||||||
dataKey: 'button_text',
|
dataKey: 'plan_type',
|
||||||
stringValue: 'Start Trial',
|
stringValue: ['basic', 'premium', 'bundle'][randomInt(0, 2)],
|
||||||
dataType: 1,
|
dataType: 1,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'download_whitepaper':
|
case 'play_video':
|
||||||
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':
|
|
||||||
data.push(
|
data.push(
|
||||||
{
|
{
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
websiteId: event.websiteId,
|
websiteId: event.websiteId,
|
||||||
websiteEventId: event.id,
|
websiteEventId: event.id,
|
||||||
dataKey: 'video_id',
|
dataKey: 'content_id',
|
||||||
stringValue: 'intro_v2',
|
stringValue: shows[randomInt(0, shows.length - 1)],
|
||||||
dataType: 1,
|
dataType: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -558,35 +645,75 @@ function generateEventData(event) {
|
||||||
websiteId: event.websiteId,
|
websiteId: event.websiteId,
|
||||||
websiteEventId: event.id,
|
websiteEventId: event.id,
|
||||||
dataKey: 'duration_watched',
|
dataKey: 'duration_watched',
|
||||||
numberValue: randomInt(15, 120),
|
numberValue: randomInt(60, 3600), // 1 min to 1 hour
|
||||||
dataType: 2,
|
dataType: 2,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: uuidv4(),
|
||||||
|
websiteId: event.websiteId,
|
||||||
|
websiteEventId: event.id,
|
||||||
|
dataKey: 'genre',
|
||||||
|
stringValue: genres[randomInt(0, genres.length - 1)],
|
||||||
|
dataType: 1,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'submit_contact_form':
|
case 'add_to_my_stuff':
|
||||||
data.push({
|
data.push({
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
websiteId: event.websiteId,
|
websiteId: event.websiteId,
|
||||||
websiteEventId: event.id,
|
websiteEventId: event.id,
|
||||||
dataKey: 'form_type',
|
dataKey: 'content_id',
|
||||||
stringValue: 'contact',
|
stringValue: shows[randomInt(0, shows.length - 1)],
|
||||||
dataType: 1,
|
dataType: 1,
|
||||||
});
|
});
|
||||||
break;
|
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;
|
return data.length > 0 ? data : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateRevenue(event, session) {
|
function generateRevenue(event, session) {
|
||||||
// Only generate revenue for dashboard conversions
|
// Only generate revenue for subscribe conversions
|
||||||
if (event.urlPath !== '/dashboard') return null;
|
if (event.urlPath !== '/subscribe') return null;
|
||||||
|
|
||||||
// Revenue tiers
|
// Hulu subscription tiers
|
||||||
const tiers = [
|
const tiers = [
|
||||||
{ revenue: 29, currency: 'USD', weight: 60 },
|
{ revenue: 7.99, currency: 'USD', weight: 40, name: 'basic' }, // Hulu Basic (with ads)
|
||||||
{ revenue: 79, currency: 'USD', weight: 30 },
|
{ revenue: 17.99, currency: 'USD', weight: 35, name: 'premium' }, // Hulu (No Ads)
|
||||||
{ revenue: 199, currency: 'USD', weight: 10 },
|
{ revenue: 76.99, currency: 'USD', weight: 25, name: 'bundle' }, // Disney Bundle
|
||||||
];
|
];
|
||||||
|
|
||||||
// Different currencies based on country
|
// Different currencies based on country
|
||||||
|
|
@ -724,18 +851,17 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) {
|
||||||
userId,
|
userId,
|
||||||
websiteId,
|
websiteId,
|
||||||
type: 'funnel',
|
type: 'funnel',
|
||||||
name: 'Signup Conversion Funnel',
|
name: 'Subscription Conversion Funnel',
|
||||||
description: 'Track users from homepage to signup completion',
|
description: 'Track users from homepage to subscription',
|
||||||
parameters: {
|
parameters: {
|
||||||
startDate: thirtyDaysAgo.toISOString(),
|
startDate: thirtyDaysAgo.toISOString(),
|
||||||
endDate: now.toISOString(),
|
endDate: now.toISOString(),
|
||||||
window: 30, // 30 minutes to complete
|
window: 30, // 30 minutes to complete
|
||||||
steps: [
|
steps: [
|
||||||
{ type: 'path', value: '/' },
|
{ type: 'path', value: '/' },
|
||||||
{ type: 'path', value: '/features' },
|
{ type: 'path', value: '/plans' },
|
||||||
{ type: 'path', value: '/pricing' },
|
|
||||||
{ type: 'path', value: '/signup' },
|
{ type: 'path', value: '/signup' },
|
||||||
{ type: 'path', value: '/dashboard' },
|
{ type: 'path', value: '/subscribe' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
createdAt: now,
|
createdAt: now,
|
||||||
|
|
@ -746,16 +872,16 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) {
|
||||||
userId,
|
userId,
|
||||||
websiteId,
|
websiteId,
|
||||||
type: 'funnel',
|
type: 'funnel',
|
||||||
name: 'Documentation Journey',
|
name: 'Content Discovery Journey',
|
||||||
description: 'How users navigate through documentation',
|
description: 'How users find and watch content',
|
||||||
parameters: {
|
parameters: {
|
||||||
startDate: thirtyDaysAgo.toISOString(),
|
startDate: thirtyDaysAgo.toISOString(),
|
||||||
endDate: now.toISOString(),
|
endDate: now.toISOString(),
|
||||||
window: 60, // 60 minutes to complete
|
window: 60, // 60 minutes to complete
|
||||||
steps: [
|
steps: [
|
||||||
{ type: 'path', value: '/docs' },
|
{ type: 'path', value: '/browse' },
|
||||||
{ type: 'path', value: '/docs/getting-started' },
|
{ type: 'path', value: '/browse/tv-shows' },
|
||||||
{ type: 'path', value: '/docs/api-reference' },
|
{ type: 'path', value: '/watch/*' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
createdAt: now,
|
createdAt: now,
|
||||||
|
|
@ -766,16 +892,16 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) {
|
||||||
userId,
|
userId,
|
||||||
websiteId,
|
websiteId,
|
||||||
type: 'funnel',
|
type: 'funnel',
|
||||||
name: 'Blog Engagement Flow',
|
name: 'Browse to Watch Flow',
|
||||||
description: 'From blog discovery to documentation',
|
description: 'From browsing to actually watching',
|
||||||
parameters: {
|
parameters: {
|
||||||
startDate: thirtyDaysAgo.toISOString(),
|
startDate: thirtyDaysAgo.toISOString(),
|
||||||
endDate: now.toISOString(),
|
endDate: now.toISOString(),
|
||||||
window: 45,
|
window: 45,
|
||||||
steps: [
|
steps: [
|
||||||
{ type: 'path', value: '/blog' },
|
{ type: 'path', value: '/browse' },
|
||||||
{ type: 'path', value: '/blog/*' }, // Any blog post
|
{ type: 'path', value: '/watch/*' },
|
||||||
{ type: 'path', value: '/docs' },
|
{ type: 'event', value: 'play_video' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
createdAt: now,
|
createdAt: now,
|
||||||
|
|
@ -786,16 +912,16 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) {
|
||||||
userId,
|
userId,
|
||||||
websiteId,
|
websiteId,
|
||||||
type: 'funnel',
|
type: 'funnel',
|
||||||
name: 'CTA Click to Conversion',
|
name: 'Trial to Subscription',
|
||||||
description: 'Track CTA effectiveness',
|
description: 'Track trial CTA to subscription',
|
||||||
parameters: {
|
parameters: {
|
||||||
startDate: thirtyDaysAgo.toISOString(),
|
startDate: thirtyDaysAgo.toISOString(),
|
||||||
endDate: now.toISOString(),
|
endDate: now.toISOString(),
|
||||||
window: 20,
|
window: 20,
|
||||||
steps: [
|
steps: [
|
||||||
{ type: 'event', value: 'click_cta_hero' },
|
{ type: 'event', value: 'click_start_trial' },
|
||||||
{ type: 'path', value: '/pricing' },
|
{ type: 'path', value: '/plans' },
|
||||||
{ type: 'path', value: '/signup' },
|
{ type: 'path', value: '/subscribe' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
createdAt: now,
|
createdAt: now,
|
||||||
|
|
@ -812,7 +938,7 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) {
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
websiteId,
|
websiteId,
|
||||||
type: 'segment',
|
type: 'segment',
|
||||||
name: 'US Mobile Users',
|
name: 'US Mobile Streamers',
|
||||||
parameters: {
|
parameters: {
|
||||||
filters: [
|
filters: [
|
||||||
{ name: 'country', operator: 'eq', value: 'US' },
|
{ name: 'country', operator: 'eq', value: 'US' },
|
||||||
|
|
@ -826,11 +952,11 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) {
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
websiteId,
|
websiteId,
|
||||||
type: 'segment',
|
type: 'segment',
|
||||||
name: 'Chrome Desktop Users',
|
name: 'Smart TV Users',
|
||||||
parameters: {
|
parameters: {
|
||||||
filters: [
|
filters: [
|
||||||
{ name: 'browser', operator: 'eq', value: 'Chrome' },
|
|
||||||
{ name: 'device', operator: 'eq', value: 'desktop' },
|
{ name: 'device', operator: 'eq', value: 'desktop' },
|
||||||
|
{ name: 'screen', operator: 'eq', value: '1920x1080' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
createdAt: now,
|
createdAt: now,
|
||||||
|
|
@ -840,9 +966,9 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) {
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
websiteId,
|
websiteId,
|
||||||
type: 'segment',
|
type: 'segment',
|
||||||
name: 'Blog Readers',
|
name: 'Content Watchers',
|
||||||
parameters: {
|
parameters: {
|
||||||
filters: [{ name: 'path', operator: 'c', value: '/blog/' }],
|
filters: [{ name: 'path', operator: 'c', value: '/watch/' }],
|
||||||
},
|
},
|
||||||
createdAt: now,
|
createdAt: now,
|
||||||
updatedAt: now,
|
updatedAt: now,
|
||||||
|
|
@ -851,7 +977,7 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) {
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
websiteId,
|
websiteId,
|
||||||
type: 'segment',
|
type: 'segment',
|
||||||
name: 'European Visitors',
|
name: 'International Viewers',
|
||||||
parameters: {
|
parameters: {
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
|
|
@ -868,9 +994,9 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) {
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
websiteId,
|
websiteId,
|
||||||
type: 'segment',
|
type: 'segment',
|
||||||
name: 'Documentation Users',
|
name: 'Browse Users',
|
||||||
parameters: {
|
parameters: {
|
||||||
filters: [{ name: 'path', operator: 'c', value: '/docs' }],
|
filters: [{ name: 'path', operator: 'c', value: '/browse' }],
|
||||||
},
|
},
|
||||||
createdAt: now,
|
createdAt: now,
|
||||||
updatedAt: now,
|
updatedAt: now,
|
||||||
|
|
@ -879,13 +1005,13 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) {
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
websiteId,
|
websiteId,
|
||||||
type: 'segment',
|
type: 'segment',
|
||||||
name: 'High-Res Screens',
|
name: 'Tablet Streamers',
|
||||||
parameters: {
|
parameters: {
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
name: 'screen',
|
name: 'device',
|
||||||
operator: 'eq',
|
operator: 'eq',
|
||||||
value: '1920x1080,2560x1440',
|
value: 'tablet',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
@ -903,15 +1029,15 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) {
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
websiteId,
|
websiteId,
|
||||||
type: 'cohort',
|
type: 'cohort',
|
||||||
name: 'January Signups',
|
name: 'November Subscribers',
|
||||||
parameters: {
|
parameters: {
|
||||||
dateRange: {
|
dateRange: {
|
||||||
startDate: '2025-01-01T00:00:00.000Z',
|
startDate: '2025-11-01T00:00:00.000Z',
|
||||||
endDate: '2025-01-31T23:59:59.999Z',
|
endDate: '2025-11-30T23:59:59.999Z',
|
||||||
},
|
},
|
||||||
action: {
|
action: {
|
||||||
type: 'path',
|
type: 'path',
|
||||||
value: '/dashboard',
|
value: '/subscribe',
|
||||||
},
|
},
|
||||||
filters: [],
|
filters: [],
|
||||||
},
|
},
|
||||||
|
|
@ -922,7 +1048,7 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) {
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
websiteId,
|
websiteId,
|
||||||
type: 'cohort',
|
type: 'cohort',
|
||||||
name: 'Product Hunt Traffic',
|
name: 'Social Media Traffic',
|
||||||
parameters: {
|
parameters: {
|
||||||
dateRange: {
|
dateRange: {
|
||||||
startDate: thirtyDaysAgo.toISOString(),
|
startDate: thirtyDaysAgo.toISOString(),
|
||||||
|
|
@ -932,7 +1058,7 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) {
|
||||||
type: 'path',
|
type: 'path',
|
||||||
value: '/',
|
value: '/',
|
||||||
},
|
},
|
||||||
filters: [{ name: 'referrer', operator: 'c', value: 'producthunt' }],
|
filters: [{ name: 'referrer', operator: 'c', value: 'facebook' }],
|
||||||
},
|
},
|
||||||
createdAt: now,
|
createdAt: now,
|
||||||
updatedAt: now,
|
updatedAt: now,
|
||||||
|
|
@ -941,7 +1067,7 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) {
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
websiteId,
|
websiteId,
|
||||||
type: 'cohort',
|
type: 'cohort',
|
||||||
name: 'Google Ads Converters',
|
name: 'Google Ads Subscribers',
|
||||||
parameters: {
|
parameters: {
|
||||||
dateRange: {
|
dateRange: {
|
||||||
startDate: thirtyDaysAgo.toISOString(),
|
startDate: thirtyDaysAgo.toISOString(),
|
||||||
|
|
@ -949,7 +1075,7 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) {
|
||||||
},
|
},
|
||||||
action: {
|
action: {
|
||||||
type: 'path',
|
type: 'path',
|
||||||
value: '/dashboard',
|
value: '/subscribe',
|
||||||
},
|
},
|
||||||
filters: [{ name: 'query', operator: 'c', value: 'utm_source=google' }],
|
filters: [{ name: 'query', operator: 'c', value: 'utm_source=google' }],
|
||||||
},
|
},
|
||||||
|
|
@ -960,7 +1086,7 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) {
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
websiteId,
|
websiteId,
|
||||||
type: 'cohort',
|
type: 'cohort',
|
||||||
name: 'Blog Engaged Users',
|
name: 'Active Viewers',
|
||||||
parameters: {
|
parameters: {
|
||||||
dateRange: {
|
dateRange: {
|
||||||
startDate: subDays(now, 14).toISOString(), // Last 2 weeks
|
startDate: subDays(now, 14).toISOString(), // Last 2 weeks
|
||||||
|
|
@ -968,9 +1094,9 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) {
|
||||||
},
|
},
|
||||||
action: {
|
action: {
|
||||||
type: 'event',
|
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,
|
createdAt: now,
|
||||||
updatedAt: now,
|
updatedAt: now,
|
||||||
|
|
@ -987,8 +1113,8 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) {
|
||||||
userId,
|
userId,
|
||||||
websiteId,
|
websiteId,
|
||||||
type: 'retention',
|
type: 'retention',
|
||||||
name: 'User Retention Analysis',
|
name: 'Viewer Retention Analysis',
|
||||||
description: 'Track returning visitors over 30 days',
|
description: 'Track returning viewers over 30 days',
|
||||||
parameters: {
|
parameters: {
|
||||||
startDate: thirtyDaysAgo.toISOString(),
|
startDate: thirtyDaysAgo.toISOString(),
|
||||||
endDate: now.toISOString(),
|
endDate: now.toISOString(),
|
||||||
|
|
@ -1001,8 +1127,8 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) {
|
||||||
userId,
|
userId,
|
||||||
websiteId,
|
websiteId,
|
||||||
type: 'journey',
|
type: 'journey',
|
||||||
name: 'Top User Journeys',
|
name: 'Top Viewer Journeys',
|
||||||
description: 'Most common navigation paths (5 steps)',
|
description: 'Most common content discovery paths (5 steps)',
|
||||||
parameters: {
|
parameters: {
|
||||||
startDate: thirtyDaysAgo.toISOString(),
|
startDate: thirtyDaysAgo.toISOString(),
|
||||||
endDate: now.toISOString(),
|
endDate: now.toISOString(),
|
||||||
|
|
@ -1030,7 +1156,7 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) {
|
||||||
userId,
|
userId,
|
||||||
websiteId,
|
websiteId,
|
||||||
type: 'revenue',
|
type: 'revenue',
|
||||||
name: 'Revenue by Country',
|
name: 'Subscription Revenue by Country',
|
||||||
description: 'Revenue breakdown by geographic location',
|
description: 'Revenue breakdown by geographic location',
|
||||||
parameters: {
|
parameters: {
|
||||||
startDate: thirtyDaysAgo.toISOString(),
|
startDate: thirtyDaysAgo.toISOString(),
|
||||||
|
|
@ -1046,12 +1172,12 @@ async function createDemoReportsAndSegments(prisma, websiteId, userId) {
|
||||||
websiteId,
|
websiteId,
|
||||||
type: 'goal',
|
type: 'goal',
|
||||||
name: 'Video Play Goal',
|
name: 'Video Play Goal',
|
||||||
description: 'Track video engagement',
|
description: 'Track video streaming engagement',
|
||||||
parameters: {
|
parameters: {
|
||||||
startDate: thirtyDaysAgo.toISOString(),
|
startDate: thirtyDaysAgo.toISOString(),
|
||||||
endDate: now.toISOString(),
|
endDate: now.toISOString(),
|
||||||
type: 'event',
|
type: 'event',
|
||||||
value: 'play_demo_video',
|
value: 'play_video',
|
||||||
},
|
},
|
||||||
createdAt: now,
|
createdAt: now,
|
||||||
updatedAt: now,
|
updatedAt: now,
|
||||||
|
|
@ -1100,7 +1226,7 @@ async function main() {
|
||||||
try {
|
try {
|
||||||
// Get website
|
// Get website
|
||||||
console.log('🔍 Looking up 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`);
|
console.log(`✓ Found website: ${website.name} (${website.id})\n`);
|
||||||
|
|
||||||
// Get admin user for reports
|
// Get admin user for reports
|
||||||
Loading…
Add table
Add a link
Reference in a new issue