feat: complete marketing command center with pipeline, UI, and asset generation

- 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>
This commit is contained in:
Trey t
2026-03-23 21:05:26 -05:00
parent 6b08cfb73a
commit 66c2bbec8b
113 changed files with 12741 additions and 138 deletions
+199
View File
@@ -0,0 +1,199 @@
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());