66c2bbec8b
- Dashboard with campaign management, asset gallery, and publishing queue - 7-agent pipeline: trend scout, research, scripts, ad creative, video, copy, distribution - Campaign form with screenshot upload, goal picker, platform selection - Campaign detail view with Details/Pipeline/Assets/Chat tabs - Two-set image generation: Gemini AI (NanoBanana MCP) + Canvas Design posters - Remotion video rendering with phone.png frame and real screenshot alignment - honeyDue branding: blue #0079FF, orange #FF9400, Inter font, warm off-white - Asset cards with source badges (Gemini/Canvas/Remotion/Playwright) - Markdown/JSON render endpoint for viewing pipeline outputs as HTML - Settings page with Tavily, Gemini, Postiz, Nextdoor integration management - Claude Chat for campaign feedback loop with streaming SSE - Postiz publishing modal with scheduling - Auth with NextAuth credentials + JWT sessions - SQLite via Prisma with better-sqlite3 adapter Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
200 lines
10 KiB
TypeScript
200 lines
10 KiB
TypeScript
import { PrismaClient } from "../lib/generated/prisma/client";
|
||
import { PrismaBetterSqlite3 } from "@prisma/adapter-better-sqlite3";
|
||
|
||
const adapter = new PrismaBetterSqlite3({
|
||
url: process.env.DATABASE_URL || "file:./data/marketing.db",
|
||
});
|
||
const prisma = new PrismaClient({ adapter });
|
||
|
||
async function main() {
|
||
// Campaign 1: Completed with assets
|
||
const campaign1 = await prisma.campaign.create({
|
||
data: {
|
||
name: "Spring Launch Campaign",
|
||
status: "review",
|
||
platforms: JSON.stringify(["instagram", "tiktok", "nextdoor"]),
|
||
config: JSON.stringify({
|
||
goal: "app_downloads",
|
||
keyMessage: "Your morning routine just got an upgrade. The smartest productivity app of 2026.",
|
||
socialProof: "50K+ downloads, 4.8 star rating, Featured in App Store",
|
||
variations: 5,
|
||
useTrendReport: true,
|
||
}),
|
||
outputPath: "outputs/spring_launch_campaign_20260323",
|
||
prompt: "Create a campaign batch for Spring Launch...",
|
||
},
|
||
});
|
||
|
||
// Agent runs for campaign 1
|
||
const agents = [
|
||
{ name: "trend-scout", duration: 12000, summary: "5 trending hooks found: 'POV: you just found...', 'Why is nobody talking about...'" },
|
||
{ name: "marketing-research-agent", duration: 128000, summary: "Market report generated. 3 competitor angles identified, 8 pain points mapped." },
|
||
{ name: "script-writer", duration: 95000, summary: "15 scripts written — 5 hooks × 3 platform styles (polished, authentic, local)." },
|
||
{ name: "ad-creative-designer", duration: 187000, summary: "8 static ads generated: 4 Instagram (1080x1080), 2 Nextdoor spotlight, 2 Nextdoor display." },
|
||
{ name: "video-ad-producer", duration: 312000, summary: "6 video ads rendered: 2 Instagram Reels (polished), 2 TikTok (authentic), 2 Nextdoor (local)." },
|
||
{ name: "copywriter-agent", duration: 67000, summary: "Platform-tuned captions written for all 14 creatives. Hashtag sets included." },
|
||
{ name: "distribution-agent", duration: 23000, summary: "Publish manifest created. 14 assets ready for review." },
|
||
];
|
||
|
||
for (const agent of agents) {
|
||
await prisma.agentRun.create({
|
||
data: {
|
||
campaignId: campaign1.id,
|
||
agentName: agent.name,
|
||
status: "completed",
|
||
startedAt: new Date(Date.now() - 3600000),
|
||
completedAt: new Date(Date.now() - 3600000 + agent.duration),
|
||
durationMs: agent.duration,
|
||
outputSummary: agent.summary,
|
||
},
|
||
});
|
||
}
|
||
|
||
// Assets for campaign 1
|
||
const assets = [
|
||
{ type: "image", platform: "instagram", format: "png", fileName: "instagram_feed_hook_a_1080x1080.png", dimensions: "1080x1080", status: "approved", metadata: { caption: "Your morning just got an upgrade. ✨\n\nThe smartest productivity app of 2026 is here — and it's free.\n\nDownload now — link in bio.\n\n#ProductivityApp #MorningRoutine #AppOfTheDay", hook: "Still doing it the hard way?" } },
|
||
{ type: "image", platform: "instagram", format: "png", fileName: "instagram_feed_hook_b_1080x1080.png", dimensions: "1080x1080", status: "approved", metadata: { caption: "POV: you just found the app everyone's been hiding from you. 🚀\n\n50K+ downloads can't be wrong.\n\n#ProductivityTips #TechLife", hook: "POV: you just found this app" } },
|
||
{ type: "image", platform: "instagram", format: "png", fileName: "instagram_stories_hook_a_1080x1920.png", dimensions: "1080x1920", status: "draft", metadata: { caption: "Swipe up to download free 🔥", hook: "Your workflow is about to change" } },
|
||
{ type: "image", platform: "nextdoor", format: "png", fileName: "nextdoor_spotlight_1200x1200.png", dimensions: "1200x1200", status: "approved", metadata: { caption: "Your neighbors are already using this app to simplify their mornings. Join them — it's free.", hook: "Your neighbors love this app" } },
|
||
{ type: "image", platform: "nextdoor", format: "png", fileName: "nextdoor_display_1200x628.png", dimensions: "1200x628", status: "draft", metadata: { caption: "The productivity app trusted by your community. Learn more.", hook: "Trusted locally" } },
|
||
{ type: "video", platform: "instagram", format: "mp4", fileName: "instagram_reel_polished_1080x1920.mp4", dimensions: "1080x1920", status: "approved", metadata: { caption: "3 seconds to change your morning ⚡\n\nDownload free — link in bio.\n\n#Reels #ProductivityHack", hook: "Still doing it the hard way?", duration: "15s" } },
|
||
{ type: "video", platform: "tiktok", format: "mp4", fileName: "tiktok_ad_authentic_1080x1920.mp4", dimensions: "1080x1920", status: "approved", metadata: { caption: "okay i HAVE to share this app with you guys 😭 #fyp #productivity #appoftiktok", hook: "I need to talk about this app", duration: "9s" } },
|
||
{ type: "video", platform: "tiktok", format: "mp4", fileName: "tiktok_ad_hook_b_1080x1920.mp4", dimensions: "1080x1920", status: "draft", metadata: { caption: "why is nobody talking about this?? #fyp #lifehack", hook: "Why is nobody talking about this?", duration: "12s" } },
|
||
{ type: "video", platform: "nextdoor", format: "mp4", fileName: "nextdoor_video_local_1080x1080.mp4", dimensions: "1080x1080", status: "draft", metadata: { caption: "See why your neighbors love this app. Simple, free, and made for busy mornings.", hook: "Your neighbors love this app", duration: "15s" } },
|
||
{ type: "copy", platform: "instagram", format: "json", fileName: "instagram_captions.json", status: "approved", metadata: { caption: "5 caption variations for Instagram" } },
|
||
{ type: "copy", platform: "tiktok", format: "json", fileName: "tiktok_captions.json", status: "approved", metadata: { caption: "5 caption variations for TikTok" } },
|
||
{ type: "copy", platform: "nextdoor", format: "json", fileName: "nextdoor_posts.json", status: "approved", metadata: { caption: "3 post variations for Nextdoor" } },
|
||
{ type: "research", platform: null, format: "html", fileName: "interactive_report.html", status: "approved", metadata: { caption: "Market research dashboard with competitor analysis" } },
|
||
{ type: "script", platform: null, format: "md", fileName: "ad_scripts_all_platforms.md", status: "approved", metadata: { caption: "15 ad scripts — 5 hooks × 3 platform styles" } },
|
||
];
|
||
|
||
for (const asset of assets) {
|
||
await prisma.asset.create({
|
||
data: {
|
||
campaignId: campaign1.id,
|
||
type: asset.type,
|
||
platform: asset.platform,
|
||
format: asset.format,
|
||
filePath: `outputs/spring_launch_campaign_20260323/${asset.type === "image" ? "ads" : asset.type === "video" ? "video" : asset.type === "copy" ? "copy" : ""}/${asset.fileName}`,
|
||
fileName: asset.fileName,
|
||
dimensions: asset.dimensions || null,
|
||
status: asset.status,
|
||
metadata: JSON.stringify(asset.metadata),
|
||
},
|
||
});
|
||
}
|
||
|
||
// Campaign 2: Running
|
||
const campaign2 = await prisma.campaign.create({
|
||
data: {
|
||
name: "Summer Feature Drop",
|
||
status: "running",
|
||
platforms: JSON.stringify(["instagram", "tiktok"]),
|
||
config: JSON.stringify({
|
||
goal: "engagement",
|
||
keyMessage: "The feature you've been asking for is finally here.",
|
||
variations: 3,
|
||
}),
|
||
},
|
||
});
|
||
|
||
// Partial agent runs for campaign 2
|
||
const partialAgents = [
|
||
{ name: "trend-scout", status: "completed", duration: 9000, summary: "4 trending hooks found" },
|
||
{ name: "marketing-research-agent", status: "completed", duration: 110000, summary: "Research complete. 5 angles identified." },
|
||
{ name: "script-writer", status: "running", duration: null, summary: null },
|
||
];
|
||
|
||
for (const agent of partialAgents) {
|
||
await prisma.agentRun.create({
|
||
data: {
|
||
campaignId: campaign2.id,
|
||
agentName: agent.name,
|
||
status: agent.status,
|
||
startedAt: new Date(),
|
||
completedAt: agent.status === "completed" ? new Date() : null,
|
||
durationMs: agent.duration,
|
||
outputSummary: agent.summary,
|
||
},
|
||
});
|
||
}
|
||
|
||
// Campaign 3: Draft
|
||
await prisma.campaign.create({
|
||
data: {
|
||
name: "Back to School Promo",
|
||
status: "draft",
|
||
platforms: JSON.stringify(["instagram", "nextdoor"]),
|
||
config: JSON.stringify({
|
||
goal: "app_downloads",
|
||
keyMessage: "Get organized before school starts. The app students and parents love.",
|
||
}),
|
||
},
|
||
});
|
||
|
||
// Campaign 4: Published
|
||
const campaign4 = await prisma.campaign.create({
|
||
data: {
|
||
name: "Valentine's Day Push",
|
||
status: "published",
|
||
platforms: JSON.stringify(["instagram", "tiktok"]),
|
||
config: JSON.stringify({
|
||
goal: "brand_awareness",
|
||
keyMessage: "Share the love — share the app.",
|
||
}),
|
||
},
|
||
});
|
||
|
||
// A few published assets for campaign 4
|
||
for (const asset of [
|
||
{ fileName: "ig_valentines_1080x1080.png", platform: "instagram", type: "image", dimensions: "1080x1080" },
|
||
{ fileName: "tiktok_valentines_1080x1920.mp4", platform: "tiktok", type: "video", dimensions: "1080x1920" },
|
||
]) {
|
||
await prisma.asset.create({
|
||
data: {
|
||
campaignId: campaign4.id,
|
||
type: asset.type,
|
||
platform: asset.platform,
|
||
format: asset.fileName.split(".").pop()!,
|
||
filePath: `outputs/valentines_push_20260214/ads/${asset.fileName}`,
|
||
fileName: asset.fileName,
|
||
dimensions: asset.dimensions,
|
||
status: "published",
|
||
postizPostId: `postiz_${Math.random().toString(36).slice(2, 10)}`,
|
||
metadata: JSON.stringify({ caption: "Share the love 💕 Download free — link in bio." }),
|
||
},
|
||
});
|
||
}
|
||
|
||
// Trend report
|
||
await prisma.trendReport.create({
|
||
data: {
|
||
name: "Weekly Trends — March 17-23, 2026",
|
||
filePath: "outputs/trend_reports/weekly_20260323.html",
|
||
summary: "Top hooks: 'POV: you just found...', 'Why is nobody talking about...'. Competitor analysis: 3 apps gaining traction with UGC-style Reels. Recommended themes: morning routine, before/after transformations.",
|
||
},
|
||
});
|
||
|
||
await prisma.trendReport.create({
|
||
data: {
|
||
name: "Weekly Trends — March 10-16, 2026",
|
||
filePath: "outputs/trend_reports/weekly_20260316.html",
|
||
summary: "Trending format: split-screen comparisons. Rising hashtag: #AppTok. Competitor spotlight: rival app launched TikTok campaign with 2M views.",
|
||
},
|
||
});
|
||
|
||
console.log("Demo data seeded:");
|
||
console.log(" 4 campaigns (review, running, draft, published)");
|
||
console.log(" 14 assets on Spring Launch");
|
||
console.log(" 2 published assets on Valentine's");
|
||
console.log(" 7 completed agent runs + 3 partial");
|
||
console.log(" 2 trend reports");
|
||
}
|
||
|
||
main()
|
||
.catch((e) => {
|
||
console.error(e);
|
||
process.exit(1);
|
||
})
|
||
.finally(() => prisma.$disconnect());
|