Initialize v2 work

This commit is contained in:
Fatih Kadir Akın
2025-12-10 15:41:23 +03:00
parent 728789c54c
commit 85a5f3bed7
181 changed files with 28216 additions and 9750 deletions

View File

@@ -0,0 +1,228 @@
-- CreateEnum
CREATE TYPE "UserRole" AS ENUM ('ADMIN', 'USER');
-- CreateEnum
CREATE TYPE "PromptType" AS ENUM ('TEXT', 'IMAGE', 'VIDEO', 'AUDIO');
-- CreateEnum
CREATE TYPE "ChangeRequestStatus" AS ENUM ('PENDING', 'APPROVED', 'REJECTED');
-- CreateTable
CREATE TABLE "users" (
"id" TEXT NOT NULL,
"email" TEXT NOT NULL,
"username" TEXT NOT NULL,
"name" TEXT,
"password" TEXT,
"avatar" TEXT,
"role" "UserRole" NOT NULL DEFAULT 'USER',
"locale" TEXT NOT NULL DEFAULT 'en',
"emailVerified" TIMESTAMP(3),
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "users_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "accounts" (
"id" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"type" TEXT NOT NULL,
"provider" TEXT NOT NULL,
"providerAccountId" TEXT NOT NULL,
"refresh_token" TEXT,
"access_token" TEXT,
"expires_at" INTEGER,
"token_type" TEXT,
"scope" TEXT,
"id_token" TEXT,
"session_state" TEXT,
CONSTRAINT "accounts_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "sessions" (
"id" TEXT NOT NULL,
"sessionToken" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"expires" TIMESTAMP(3) NOT NULL,
CONSTRAINT "sessions_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "verification_tokens" (
"identifier" TEXT NOT NULL,
"token" TEXT NOT NULL,
"expires" TIMESTAMP(3) NOT NULL
);
-- CreateTable
CREATE TABLE "prompts" (
"id" TEXT NOT NULL,
"title" TEXT NOT NULL,
"description" TEXT,
"content" TEXT NOT NULL,
"type" "PromptType" NOT NULL DEFAULT 'TEXT',
"isPrivate" BOOLEAN NOT NULL DEFAULT false,
"mediaUrl" TEXT,
"viewCount" INTEGER NOT NULL DEFAULT 0,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"authorId" TEXT NOT NULL,
"categoryId" TEXT,
CONSTRAINT "prompts_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "prompt_versions" (
"id" TEXT NOT NULL,
"version" INTEGER NOT NULL,
"content" TEXT NOT NULL,
"changeNote" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"promptId" TEXT NOT NULL,
"createdBy" TEXT NOT NULL,
CONSTRAINT "prompt_versions_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "change_requests" (
"id" TEXT NOT NULL,
"proposedContent" TEXT NOT NULL,
"proposedTitle" TEXT,
"reason" TEXT,
"status" "ChangeRequestStatus" NOT NULL DEFAULT 'PENDING',
"reviewNote" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"promptId" TEXT NOT NULL,
"authorId" TEXT NOT NULL,
CONSTRAINT "change_requests_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "categories" (
"id" TEXT NOT NULL,
"name" TEXT NOT NULL,
"slug" TEXT NOT NULL,
"description" TEXT,
"icon" TEXT,
"order" INTEGER NOT NULL DEFAULT 0,
"parentId" TEXT,
CONSTRAINT "categories_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "tags" (
"id" TEXT NOT NULL,
"name" TEXT NOT NULL,
"slug" TEXT NOT NULL,
"color" TEXT NOT NULL DEFAULT '#6366f1',
CONSTRAINT "tags_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "prompt_tags" (
"promptId" TEXT NOT NULL,
"tagId" TEXT NOT NULL,
CONSTRAINT "prompt_tags_pkey" PRIMARY KEY ("promptId","tagId")
);
-- CreateIndex
CREATE UNIQUE INDEX "users_email_key" ON "users"("email");
-- CreateIndex
CREATE UNIQUE INDEX "users_username_key" ON "users"("username");
-- CreateIndex
CREATE UNIQUE INDEX "accounts_provider_providerAccountId_key" ON "accounts"("provider", "providerAccountId");
-- CreateIndex
CREATE UNIQUE INDEX "sessions_sessionToken_key" ON "sessions"("sessionToken");
-- CreateIndex
CREATE UNIQUE INDEX "verification_tokens_token_key" ON "verification_tokens"("token");
-- CreateIndex
CREATE UNIQUE INDEX "verification_tokens_identifier_token_key" ON "verification_tokens"("identifier", "token");
-- CreateIndex
CREATE INDEX "prompts_authorId_idx" ON "prompts"("authorId");
-- CreateIndex
CREATE INDEX "prompts_categoryId_idx" ON "prompts"("categoryId");
-- CreateIndex
CREATE INDEX "prompts_type_idx" ON "prompts"("type");
-- CreateIndex
CREATE INDEX "prompts_isPrivate_idx" ON "prompts"("isPrivate");
-- CreateIndex
CREATE INDEX "prompt_versions_promptId_idx" ON "prompt_versions"("promptId");
-- CreateIndex
CREATE UNIQUE INDEX "prompt_versions_promptId_version_key" ON "prompt_versions"("promptId", "version");
-- CreateIndex
CREATE INDEX "change_requests_promptId_idx" ON "change_requests"("promptId");
-- CreateIndex
CREATE INDEX "change_requests_authorId_idx" ON "change_requests"("authorId");
-- CreateIndex
CREATE INDEX "change_requests_status_idx" ON "change_requests"("status");
-- CreateIndex
CREATE UNIQUE INDEX "categories_slug_key" ON "categories"("slug");
-- CreateIndex
CREATE INDEX "categories_parentId_idx" ON "categories"("parentId");
-- CreateIndex
CREATE UNIQUE INDEX "tags_name_key" ON "tags"("name");
-- CreateIndex
CREATE UNIQUE INDEX "tags_slug_key" ON "tags"("slug");
-- AddForeignKey
ALTER TABLE "accounts" ADD CONSTRAINT "accounts_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "sessions" ADD CONSTRAINT "sessions_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "prompts" ADD CONSTRAINT "prompts_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "prompts" ADD CONSTRAINT "prompts_categoryId_fkey" FOREIGN KEY ("categoryId") REFERENCES "categories"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "prompt_versions" ADD CONSTRAINT "prompt_versions_promptId_fkey" FOREIGN KEY ("promptId") REFERENCES "prompts"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "prompt_versions" ADD CONSTRAINT "prompt_versions_createdBy_fkey" FOREIGN KEY ("createdBy") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "change_requests" ADD CONSTRAINT "change_requests_promptId_fkey" FOREIGN KEY ("promptId") REFERENCES "prompts"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "change_requests" ADD CONSTRAINT "change_requests_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "categories" ADD CONSTRAINT "categories_parentId_fkey" FOREIGN KEY ("parentId") REFERENCES "categories"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "prompt_tags" ADD CONSTRAINT "prompt_tags_promptId_fkey" FOREIGN KEY ("promptId") REFERENCES "prompts"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "prompt_tags" ADD CONSTRAINT "prompt_tags_tagId_fkey" FOREIGN KEY ("tagId") REFERENCES "tags"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@@ -0,0 +1,20 @@
-- CreateTable
CREATE TABLE "category_subscriptions" (
"userId" TEXT NOT NULL,
"categoryId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "category_subscriptions_pkey" PRIMARY KEY ("userId","categoryId")
);
-- CreateIndex
CREATE INDEX "category_subscriptions_userId_idx" ON "category_subscriptions"("userId");
-- CreateIndex
CREATE INDEX "category_subscriptions_categoryId_idx" ON "category_subscriptions"("categoryId");
-- AddForeignKey
ALTER TABLE "category_subscriptions" ADD CONSTRAINT "category_subscriptions_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "category_subscriptions" ADD CONSTRAINT "category_subscriptions_categoryId_fkey" FOREIGN KEY ("categoryId") REFERENCES "categories"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "postgresql"

313
prisma/schema.prisma Normal file
View File

@@ -0,0 +1,313 @@
// Prisma schema for prompts.chat
// https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
// ============================================
// User & Authentication
// ============================================
enum UserRole {
ADMIN
USER
}
model User {
id String @id @default(cuid())
email String @unique
username String @unique
name String?
password String? // For credentials auth
avatar String?
role UserRole @default(USER)
locale String @default("en")
emailVerified DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
prompts Prompt[] @relation("PromptAuthor")
contributions Prompt[] @relation("PromptContributors")
promptVersions PromptVersion[]
changeRequests ChangeRequest[]
accounts Account[]
sessions Session[]
subscriptions CategorySubscription[]
votes PromptVote[]
pinnedPrompts PinnedPrompt[]
@@map("users")
}
model Account {
id String @id @default(cuid())
userId String
type String
provider String
providerAccountId String
refresh_token String? @db.Text
access_token String? @db.Text
expires_at Int?
token_type String?
scope String?
id_token String? @db.Text
session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId])
@@map("accounts")
}
model Session {
id String @id @default(cuid())
sessionToken String @unique
userId String
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@map("sessions")
}
model VerificationToken {
identifier String
token String @unique
expires DateTime
@@unique([identifier, token])
@@map("verification_tokens")
}
// ============================================
// Prompts & Content
// ============================================
enum PromptType {
TEXT
IMAGE
VIDEO
AUDIO
STRUCTURED
}
enum StructuredFormat {
JSON
YAML
}
enum ChangeRequestStatus {
PENDING
APPROVED
REJECTED
}
enum RequiredMediaType {
IMAGE
VIDEO
DOCUMENT
}
model Prompt {
id String @id @default(cuid())
title String
description String?
content String @db.Text
type PromptType @default(TEXT)
structuredFormat StructuredFormat? // For STRUCTURED type: JSON or YAML
isPrivate Boolean @default(false)
mediaUrl String? // For non-text prompts
// Media requirements (user needs to upload media to use this prompt)
requiresMediaUpload Boolean @default(false)
requiredMediaType RequiredMediaType?
requiredMediaCount Int?
// Metadata
viewCount Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
authorId String
author User @relation("PromptAuthor", fields: [authorId], references: [id], onDelete: Cascade)
categoryId String?
category Category? @relation(fields: [categoryId], references: [id], onDelete: SetNull)
versions PromptVersion[]
changeRequests ChangeRequest[]
tags PromptTag[]
votes PromptVote[]
contributors User[] @relation("PromptContributors")
pinnedBy PinnedPrompt[]
@@index([authorId])
@@index([categoryId])
@@index([type])
@@index([isPrivate])
@@map("prompts")
}
model PromptVersion {
id String @id @default(cuid())
version Int
content String @db.Text
changeNote String?
createdAt DateTime @default(now())
// Relations
promptId String
prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade)
createdBy String
author User @relation(fields: [createdBy], references: [id], onDelete: Cascade)
@@unique([promptId, version])
@@index([promptId])
@@map("prompt_versions")
}
model ChangeRequest {
id String @id @default(cuid())
originalContent String @db.Text
originalTitle String
proposedContent String @db.Text
proposedTitle String?
reason String?
status ChangeRequestStatus @default(PENDING)
reviewNote String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
promptId String
prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade)
authorId String
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
@@index([promptId])
@@index([authorId])
@@index([status])
@@map("change_requests")
}
// ============================================
// Categories & Tags
// ============================================
model Category {
id String @id @default(cuid())
name String
slug String @unique
description String?
icon String?
order Int @default(0)
// Self-referential for hierarchy
parentId String?
parent Category? @relation("CategoryHierarchy", fields: [parentId], references: [id], onDelete: SetNull)
children Category[] @relation("CategoryHierarchy")
prompts Prompt[]
subscribers CategorySubscription[]
@@index([parentId])
@@map("categories")
}
model Tag {
id String @id @default(cuid())
name String @unique
slug String @unique
color String @default("#6366f1")
prompts PromptTag[]
@@map("tags")
}
model PromptTag {
promptId String
tagId String
prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade)
tag Tag @relation(fields: [tagId], references: [id], onDelete: Cascade)
@@id([promptId, tagId])
@@map("prompt_tags")
}
// ============================================
// Subscriptions
// ============================================
model CategorySubscription {
userId String
categoryId String
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
category Category @relation(fields: [categoryId], references: [id], onDelete: Cascade)
@@id([userId, categoryId])
@@index([userId])
@@index([categoryId])
@@map("category_subscriptions")
}
model PromptVote {
userId String
promptId String
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade)
@@id([userId, promptId])
@@index([userId])
@@index([promptId])
@@map("prompt_votes")
}
model PinnedPrompt {
userId String
promptId String
order Int @default(0)
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade)
@@id([userId, promptId])
@@index([userId])
@@map("pinned_prompts")
}
// ============================================
// Webhook Integration
// ============================================
enum WebhookEvent {
PROMPT_CREATED
PROMPT_UPDATED
PROMPT_DELETED
}
model WebhookConfig {
id String @id @default(cuid())
name String // e.g. "Slack Notifications"
url String // Webhook URL
method String @default("POST") // HTTP method
headers Json? // Custom headers as JSON object
payload String @db.Text // JSON template with placeholders
events WebhookEvent[] // Which events trigger this webhook
isEnabled Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("webhook_configs")
}

616
prisma/seed.ts Normal file
View File

@@ -0,0 +1,616 @@
import { PrismaClient } from "@prisma/client";
import bcrypt from "bcryptjs";
const prisma = new PrismaClient();
async function main() {
console.log("🌱 Seeding database...");
// Create users
const password = await bcrypt.hash("password123", 12);
const admin = await prisma.user.upsert({
where: { email: "admin@prompts.chat" },
update: {},
create: {
email: "admin@prompts.chat",
username: "admin",
name: "Admin User",
password: password,
role: "ADMIN",
locale: "en",
},
});
const demo = await prisma.user.upsert({
where: { email: "demo@prompts.chat" },
update: {},
create: {
email: "demo@prompts.chat",
username: "demo",
name: "Demo User",
password: password,
role: "USER",
locale: "en",
},
});
const alice = await prisma.user.upsert({
where: { email: "alice@example.com" },
update: {},
create: {
email: "alice@example.com",
username: "alice",
name: "Alice Johnson",
password: password,
role: "USER",
locale: "en",
},
});
const bob = await prisma.user.upsert({
where: { email: "bob@example.com" },
update: {},
create: {
email: "bob@example.com",
username: "bob",
name: "Bob Smith",
password: password,
role: "USER",
locale: "tr",
},
});
const charlie = await prisma.user.upsert({
where: { email: "charlie@example.com" },
update: {},
create: {
email: "charlie@example.com",
username: "charlie",
name: "Charlie Brown",
password: password,
role: "USER",
locale: "en",
},
});
const users = [admin, demo, alice, bob, charlie];
console.log("✅ Created", users.length, "users");
// Create parent categories
const coding = await prisma.category.upsert({
where: { slug: "coding" },
update: {},
create: { name: "Coding", slug: "coding", description: "Programming and development prompts", icon: "💻", order: 1 },
});
const writing = await prisma.category.upsert({
where: { slug: "writing" },
update: {},
create: { name: "Writing", slug: "writing", description: "Content writing and copywriting", icon: "✍️", order: 2 },
});
const business = await prisma.category.upsert({
where: { slug: "business" },
update: {},
create: { name: "Business", slug: "business", description: "Business strategy and operations", icon: "💼", order: 3 },
});
const creative = await prisma.category.upsert({
where: { slug: "creative" },
update: {},
create: { name: "Creative", slug: "creative", description: "Art, design, and creative work", icon: "🎨", order: 4 },
});
const education = await prisma.category.upsert({
where: { slug: "education" },
update: {},
create: { name: "Education", slug: "education", description: "Learning and teaching prompts", icon: "📚", order: 5 },
});
// Create nested categories (children)
const webDev = await prisma.category.upsert({
where: { slug: "web-development" },
update: {},
create: { name: "Web Development", slug: "web-development", description: "Frontend and backend web development", parentId: coding.id, order: 1 },
});
const mobileDev = await prisma.category.upsert({
where: { slug: "mobile-development" },
update: {},
create: { name: "Mobile Development", slug: "mobile-development", description: "iOS and Android development", parentId: coding.id, order: 2 },
});
const devops = await prisma.category.upsert({
where: { slug: "devops" },
update: {},
create: { name: "DevOps", slug: "devops", description: "CI/CD, cloud, and infrastructure", parentId: coding.id, order: 3 },
});
const dataScience = await prisma.category.upsert({
where: { slug: "data-science" },
update: {},
create: { name: "Data Science", slug: "data-science", description: "ML, AI, and data analysis", parentId: coding.id, order: 4 },
});
const blogWriting = await prisma.category.upsert({
where: { slug: "blog-writing" },
update: {},
create: { name: "Blog Writing", slug: "blog-writing", description: "Blog posts and articles", parentId: writing.id, order: 1 },
});
const copywriting = await prisma.category.upsert({
where: { slug: "copywriting" },
update: {},
create: { name: "Copywriting", slug: "copywriting", description: "Sales and marketing copy", parentId: writing.id, order: 2 },
});
const technicalWriting = await prisma.category.upsert({
where: { slug: "technical-writing" },
update: {},
create: { name: "Technical Writing", slug: "technical-writing", description: "Documentation and guides", parentId: writing.id, order: 3 },
});
const marketing = await prisma.category.upsert({
where: { slug: "marketing" },
update: {},
create: { name: "Marketing", slug: "marketing", description: "Marketing and advertising prompts", parentId: business.id, order: 1 },
});
const sales = await prisma.category.upsert({
where: { slug: "sales" },
update: {},
create: { name: "Sales", slug: "sales", description: "Sales strategies and outreach", parentId: business.id, order: 2 },
});
const hr = await prisma.category.upsert({
where: { slug: "hr" },
update: {},
create: { name: "HR & Recruiting", slug: "hr", description: "Human resources and hiring", parentId: business.id, order: 3 },
});
const imageGen = await prisma.category.upsert({
where: { slug: "image-generation" },
update: {},
create: { name: "Image Generation", slug: "image-generation", description: "AI image prompts", parentId: creative.id, order: 1 },
});
const music = await prisma.category.upsert({
where: { slug: "music" },
update: {},
create: { name: "Music", slug: "music", description: "Music and audio generation", parentId: creative.id, order: 2 },
});
// Create Workflows category (for structured prompts)
const workflows = await prisma.category.upsert({
where: { slug: "workflows" },
update: {},
create: { name: "Workflows", slug: "workflows", description: "Structured AI workflows and pipelines", icon: "⚡", order: 6 },
});
const agentWorkflows = await prisma.category.upsert({
where: { slug: "agent-workflows" },
update: {},
create: { name: "Agent Workflows", slug: "agent-workflows", description: "Multi-step AI agent configurations", parentId: workflows.id, order: 1 },
});
const automations = await prisma.category.upsert({
where: { slug: "automations" },
update: {},
create: { name: "Automations", slug: "automations", description: "Automated task pipelines", parentId: workflows.id, order: 2 },
});
const categories = [coding, writing, business, creative, education, workflows, webDev, mobileDev, devops, dataScience, blogWriting, copywriting, technicalWriting, marketing, sales, hr, imageGen, music, agentWorkflows, automations];
console.log("✅ Created", categories.length, "categories (including nested)");
// Create tags
const tags = await Promise.all([
prisma.tag.upsert({
where: { slug: "gpt-4" },
update: {},
create: { name: "GPT-4", slug: "gpt-4", color: "#10B981" },
}),
prisma.tag.upsert({
where: { slug: "claude" },
update: {},
create: { name: "Claude", slug: "claude", color: "#8B5CF6" },
}),
prisma.tag.upsert({
where: { slug: "midjourney" },
update: {},
create: { name: "Midjourney", slug: "midjourney", color: "#F59E0B" },
}),
prisma.tag.upsert({
where: { slug: "dalle" },
update: {},
create: { name: "DALL-E", slug: "dalle", color: "#EC4899" },
}),
prisma.tag.upsert({
where: { slug: "beginner" },
update: {},
create: { name: "Beginner", slug: "beginner", color: "#06B6D4" },
}),
prisma.tag.upsert({
where: { slug: "advanced" },
update: {},
create: { name: "Advanced", slug: "advanced", color: "#EF4444" },
}),
prisma.tag.upsert({
where: { slug: "chain-of-thought" },
update: {},
create: { name: "Chain of Thought", slug: "chain-of-thought", color: "#3B82F6" },
}),
prisma.tag.upsert({
where: { slug: "system-prompt" },
update: {},
create: { name: "System Prompt", slug: "system-prompt", color: "#6366F1" },
}),
prisma.tag.upsert({
where: { slug: "workflow" },
update: {},
create: { name: "Workflow", slug: "workflow", color: "#F97316" },
}),
prisma.tag.upsert({
where: { slug: "agent" },
update: {},
create: { name: "Agent", slug: "agent", color: "#14B8A6" },
}),
]);
console.log("✅ Created", tags.length, "tags");
// Create sample prompts - distributed among users
const prompts = [
// Admin's prompts
{ title: "Code Review Assistant", description: "A prompt for thorough code reviews", content: `You are an expert code reviewer. Review the following code:\n\n{{code}}\n\nProvide:\n1. Summary\n2. Strengths\n3. Issues\n4. Improvements\n5. Performance suggestions`, type: "TEXT", categorySlug: "web-development", tagSlugs: ["gpt-4", "advanced"], authorId: admin.id },
{ title: "Expert System Prompt", description: "Turn AI into a domain expert", content: `You are an expert {{role}} with {{years}} years of experience in {{domain}}. Be precise, professional, and provide actionable insights.`, type: "TEXT", categorySlug: "coding", tagSlugs: ["system-prompt", "advanced", "gpt-4"], authorId: admin.id },
{ title: "Lesson Plan Creator", description: "Create structured lesson plans", content: `Create a lesson plan for {{subject}} - {{topic}} for {{grade}} level. Include objectives, materials, activities, and assessment.`, type: "TEXT", categorySlug: "education", tagSlugs: ["gpt-4", "beginner"], authorId: admin.id },
{ title: "DALL-E Product Mockup", description: "Professional product mockups", content: `A professional product photo of {{product}} on {{surface}}, soft studio lighting, high-end advertising style, 4k`, type: "IMAGE", categorySlug: "image-generation", tagSlugs: ["dalle", "beginner"], authorId: admin.id },
{ title: "Email Response Generator", description: "Professional email responses", content: `Write a professional email response to: {{original_email}}\n\nTone: {{tone}}\nDesired outcome: {{outcome}}`, type: "TEXT", categorySlug: "business", tagSlugs: ["gpt-4", "beginner"], authorId: admin.id },
// Demo user's prompts
{ title: "Blog Post Generator", description: "Generate engaging blog posts", content: `Write a blog post about {{topic}} for {{audience}}. Include engaging intro, 3-5 sections, practical tips, and CTA. Word count: {{word_count}}`, type: "TEXT", categorySlug: "blog-writing", tagSlugs: ["gpt-4", "beginner"], authorId: demo.id },
{ title: "SWOT Analysis Generator", description: "Comprehensive SWOT analysis", content: `Conduct a SWOT analysis for {{subject}} in {{industry}}. Provide Strengths, Weaknesses, Opportunities, Threats, and Strategic Recommendations.`, type: "TEXT", categorySlug: "business", tagSlugs: ["gpt-4", "chain-of-thought"], authorId: demo.id },
{ title: "Midjourney Fantasy Landscape", description: "Stunning fantasy landscape images", content: `A breathtaking fantasy landscape, {{scene_type}}, ancient ruins, floating islands, dramatic lighting, volumetric fog, 8k --ar 16:9 --v 6`, type: "IMAGE", categorySlug: "image-generation", tagSlugs: ["midjourney", "advanced"], authorId: demo.id },
{ title: "Debug Assistant", description: "Systematic debugging help", content: `Debug this issue:\n\nError: {{error}}\nCode: {{code}}\nTried: {{attempts}}\n\nExplain the error, root cause, fix, and prevention.`, type: "TEXT", categorySlug: "coding", tagSlugs: ["gpt-4", "claude", "chain-of-thought"], authorId: demo.id },
// Alice's prompts
{ title: "React Component Generator", description: "Generate React components with TypeScript", content: `Create a React component for {{component_name}} with TypeScript. Include props interface, hooks if needed, and basic styling.`, type: "TEXT", categorySlug: "web-development", tagSlugs: ["gpt-4", "advanced"], authorId: alice.id },
{ title: "API Documentation Writer", description: "Generate API documentation", content: `Write API documentation for {{endpoint}}:\n\nMethod: {{method}}\nParameters: {{params}}\nResponse: {{response}}\n\nInclude examples and error codes.`, type: "TEXT", categorySlug: "technical-writing", tagSlugs: ["gpt-4", "beginner"], authorId: alice.id },
{ title: "Social Media Content Calendar", description: "Plan social media content", content: `Create a {{duration}} social media content calendar for {{brand}} targeting {{audience}}. Include post ideas, hashtags, and best posting times.`, type: "TEXT", categorySlug: "marketing", tagSlugs: ["claude", "beginner"], authorId: alice.id },
{ title: "UX Research Questions", description: "Generate user research questions", content: `Create user research questions for {{product}} focusing on {{feature}}. Include open-ended, rating, and follow-up questions.`, type: "TEXT", categorySlug: "business", tagSlugs: ["gpt-4", "beginner"], authorId: alice.id },
// Bob's prompts
{ title: "SQL Query Optimizer", description: "Optimize SQL queries", content: `Analyze and optimize this SQL query:\n\n{{query}}\n\nProvide: execution plan analysis, index suggestions, and optimized query.`, type: "TEXT", categorySlug: "data-science", tagSlugs: ["gpt-4", "advanced"], authorId: bob.id },
{ title: "Docker Compose Generator", description: "Generate Docker Compose files", content: `Create a Docker Compose file for {{stack}} with {{services}}. Include environment variables, volumes, and networks.`, type: "TEXT", categorySlug: "devops", tagSlugs: ["gpt-4", "advanced"], authorId: bob.id },
{ title: "Job Description Writer", description: "Write compelling job descriptions", content: `Write a job description for {{position}} at {{company}}. Include responsibilities, requirements, benefits, and company culture.`, type: "TEXT", categorySlug: "hr", tagSlugs: ["claude", "beginner"], authorId: bob.id },
{ title: "Sales Email Sequence", description: "Create sales email sequences", content: `Create a {{length}}-email sequence for {{product}} targeting {{persona}}. Include subject lines, personalization, and CTAs.`, type: "TEXT", categorySlug: "sales", tagSlugs: ["gpt-4", "advanced"], authorId: bob.id },
// Charlie's prompts
{ title: "Mobile App Onboarding Flow", description: "Design onboarding experiences", content: `Design an onboarding flow for {{app_name}} ({{platform}}). Include screens, copy, and user actions for first-time users.`, type: "TEXT", categorySlug: "mobile-development", tagSlugs: ["claude", "beginner"], authorId: charlie.id },
{ title: "Product Copywriter", description: "Compelling product copy", content: `Write product copy for {{product_name}}:\n\nFeatures: {{features}}\nTarget: {{target}}\n\nInclude headline, benefits, and CTA.`, type: "TEXT", categorySlug: "copywriting", tagSlugs: ["gpt-4", "beginner"], authorId: charlie.id },
{ title: "Meeting Notes Summarizer", description: "Summarize meeting notes", content: `Summarize this meeting:\n\n{{transcript}}\n\nProvide: key decisions, action items, owners, and deadlines.`, type: "TEXT", categorySlug: "business", tagSlugs: ["gpt-4", "beginner"], authorId: charlie.id },
{ title: "Music Prompt Generator", description: "Generate music with AI", content: `Create a {{genre}} track with {{mood}} feel. BPM: {{bpm}}, Key: {{key}}. Include intro, verse, chorus structure.`, type: "AUDIO", categorySlug: "music", tagSlugs: ["claude", "advanced"], authorId: charlie.id },
// Structured prompts (workflows)
{
title: "Content Pipeline Workflow",
description: "Multi-step content creation pipeline",
content: JSON.stringify({
name: "Content Creation Pipeline",
version: "1.0",
steps: [
{
id: "research",
name: "Research Topic",
prompt: "Research the topic '{{topic}}' and provide 5 key points with sources",
output: "research_results"
},
{
id: "outline",
name: "Create Outline",
prompt: "Based on {{research_results}}, create a detailed blog post outline",
output: "outline",
depends_on: ["research"]
},
{
id: "draft",
name: "Write Draft",
prompt: "Write a {{word_count}} word blog post following this outline: {{outline}}",
output: "draft",
depends_on: ["outline"]
},
{
id: "review",
name: "Review & Edit",
prompt: "Review and improve this draft for clarity, grammar, and engagement: {{draft}}",
output: "final_content",
depends_on: ["draft"]
}
],
variables: {
topic: { type: "string", required: true },
word_count: { type: "number", default: 1500 }
}
}, null, 2),
type: "STRUCTURED",
structuredFormat: "JSON",
categorySlug: "automations",
tagSlugs: ["workflow", "gpt-4", "advanced"],
authorId: admin.id
},
{
title: "Code Review Agent",
description: "AI agent for comprehensive code reviews",
content: `name: Code Review Agent
version: "1.0"
description: Multi-pass code review agent
agent:
role: Senior Software Engineer
expertise:
- Code quality
- Security
- Performance optimization
- Best practices
workflow:
- step: security_scan
prompt: |
Analyze this code for security vulnerabilities:
\`\`\`{{language}}
{{code}}
\`\`\`
Focus on: injection, XSS, authentication issues
output: security_report
- step: performance_review
prompt: |
Review this code for performance issues:
{{code}}
Consider: time complexity, memory usage, database queries
output: performance_report
depends_on: [security_scan]
- step: best_practices
prompt: |
Check adherence to {{language}} best practices:
{{code}}
output: practices_report
depends_on: [security_scan]
- step: final_summary
prompt: |
Compile a final code review report from:
- Security: {{security_report}}
- Performance: {{performance_report}}
- Best Practices: {{practices_report}}
output: final_review
depends_on: [performance_review, best_practices]
variables:
code:
type: string
required: true
language:
type: string
default: typescript`,
type: "STRUCTURED",
structuredFormat: "YAML",
categorySlug: "agent-workflows",
tagSlugs: ["agent", "workflow", "claude", "advanced"],
authorId: demo.id
},
{
title: "Customer Support Agent",
description: "Intelligent customer support workflow",
content: JSON.stringify({
name: "Customer Support Agent",
version: "1.0",
agent: {
role: "Customer Support Specialist",
tone: "friendly, professional, helpful",
constraints: [
"Never share internal policies",
"Escalate billing issues over $1000",
"Always verify customer identity first"
]
},
workflow: [
{
step: "classify",
prompt: "Classify this customer inquiry: {{inquiry}}\nCategories: billing, technical, general, complaint",
output: "category"
},
{
step: "gather_context",
prompt: "What additional information is needed to resolve this {{category}} issue? List specific questions.",
output: "followup_questions",
depends_on: ["classify"]
},
{
step: "resolve",
prompt: "Provide a helpful response for this {{category}} issue: {{inquiry}}\nContext gathered: {{context}}",
output: "response",
depends_on: ["gather_context"]
}
],
variables: {
inquiry: { type: "string", required: true },
context: { type: "string", default: "" }
}
}, null, 2),
type: "STRUCTURED",
structuredFormat: "JSON",
categorySlug: "agent-workflows",
tagSlugs: ["agent", "workflow", "gpt-4", "beginner"],
authorId: alice.id
},
{
title: "Data Processing Pipeline",
description: "ETL-style data transformation workflow",
content: `name: Data Processing Pipeline
version: "1.0"
description: Transform and analyze data with AI
pipeline:
- stage: extract
name: Data Extraction
prompt: |
Extract structured data from this input:
{{raw_data}}
Output as JSON with fields: {{fields}}
output: extracted_data
- stage: transform
name: Data Transformation
prompt: |
Transform this data according to rules:
Data: {{extracted_data}}
Rules: {{transformation_rules}}
output: transformed_data
depends_on: [extract]
- stage: validate
name: Data Validation
prompt: |
Validate this data against schema:
Data: {{transformed_data}}
Schema: {{validation_schema}}
Report any errors or inconsistencies.
output: validation_report
depends_on: [transform]
- stage: analyze
name: Data Analysis
prompt: |
Analyze this validated data:
{{transformed_data}}
Provide: summary statistics, patterns, anomalies
output: analysis_report
depends_on: [validate]
variables:
raw_data:
type: string
required: true
fields:
type: array
default: [id, name, value, timestamp]
transformation_rules:
type: string
default: "normalize dates, clean text, convert currencies"
validation_schema:
type: string
default: "standard"`,
type: "STRUCTURED",
structuredFormat: "YAML",
categorySlug: "automations",
tagSlugs: ["workflow", "claude", "advanced"],
authorId: bob.id
},
];
for (const promptData of prompts) {
const category = categories.find((c) => c.slug === promptData.categorySlug);
const promptTags = tags.filter((t) => promptData.tagSlugs.includes(t.slug));
const existingPrompt = await prisma.prompt.findFirst({
where: { title: promptData.title, authorId: promptData.authorId },
});
if (!existingPrompt) {
const prompt = await prisma.prompt.create({
data: {
title: promptData.title,
description: promptData.description,
content: promptData.content,
type: promptData.type as "TEXT" | "IMAGE" | "VIDEO" | "AUDIO" | "STRUCTURED",
structuredFormat: (promptData as { structuredFormat?: "JSON" | "YAML" }).structuredFormat,
authorId: promptData.authorId,
categoryId: category?.id,
tags: {
create: promptTags.map((tag) => ({ tagId: tag.id })),
},
},
});
// Create initial version
await prisma.promptVersion.create({
data: {
promptId: prompt.id,
version: 1,
content: promptData.content,
changeNote: "Initial version",
createdBy: promptData.authorId,
},
});
}
}
console.log("✅ Created", prompts.length, "prompts");
// Create comprehensive change requests
const allPrompts = await prisma.prompt.findMany();
const changeRequestsData = [
// Pending requests
{ id: "cr-1", promptTitle: "Code Review Assistant", authorId: demo.id, reason: "Added best practices section", proposedAddition: "\n\n6. **Best Practices**: Suggest industry best practices.", status: "PENDING" as const },
{ id: "cr-2", promptTitle: "Blog Post Generator", authorId: alice.id, reason: "Added SEO tips", proposedAddition: "\n\nInclude meta description and keyword suggestions.", status: "PENDING" as const },
{ id: "cr-3", promptTitle: "React Component Generator", authorId: bob.id, reason: "Add accessibility considerations", proposedAddition: "\n\nEnsure ARIA labels and keyboard navigation support.", status: "PENDING" as const },
{ id: "cr-4", promptTitle: "SQL Query Optimizer", authorId: charlie.id, reason: "Include explain analyze output", proposedAddition: "\n\nShow EXPLAIN ANALYZE output interpretation.", status: "PENDING" as const },
{ id: "cr-5", promptTitle: "Expert System Prompt", authorId: demo.id, reason: "Add error handling guidance", proposedAddition: "\n\nHandle edge cases gracefully and provide fallback responses.", status: "PENDING" as const },
// Approved requests
{ id: "cr-6", promptTitle: "SWOT Analysis Generator", authorId: admin.id, reason: "Added competitive analysis section", proposedAddition: "\n\n## Competitive Position\nCompare against top 3 competitors.", status: "APPROVED" as const, reviewNote: "Great addition! Merged." },
{ id: "cr-7", promptTitle: "Debug Assistant", authorId: alice.id, reason: "Include stack trace analysis", proposedAddition: "\n\n6. Analyze the full stack trace if provided.", status: "APPROVED" as const, reviewNote: "Very helpful improvement." },
{ id: "cr-8", promptTitle: "Docker Compose Generator", authorId: demo.id, reason: "Add health checks", proposedAddition: "\n\nInclude healthcheck configurations for each service.", status: "APPROVED" as const, reviewNote: "Essential for production setups." },
{ id: "cr-9", promptTitle: "API Documentation Writer", authorId: bob.id, reason: "Add rate limiting info", proposedAddition: "\n\nDocument rate limits and throttling policies.", status: "APPROVED" as const, reviewNote: "Good call, this is often missing." },
// Rejected requests
{ id: "cr-10", promptTitle: "Midjourney Fantasy Landscape", authorId: admin.id, reason: "Simplify the prompt", proposedAddition: " (simplified)", status: "REJECTED" as const, reviewNote: "I prefer the detailed version for better results." },
{ id: "cr-11", promptTitle: "Sales Email Sequence", authorId: charlie.id, reason: "Make it more aggressive", proposedAddition: "\n\nBe more pushy and urgent.", status: "REJECTED" as const, reviewNote: "This goes against our brand voice guidelines." },
{ id: "cr-12", promptTitle: "Job Description Writer", authorId: alice.id, reason: "Remove benefits section", proposedAddition: "", status: "REJECTED" as const, reviewNote: "Benefits are important for attracting candidates." },
];
for (const cr of changeRequestsData) {
const prompt = allPrompts.find(p => p.title === cr.promptTitle);
if (prompt) {
await prisma.changeRequest.upsert({
where: { id: cr.id },
update: {},
create: {
id: cr.id,
promptId: prompt.id,
authorId: cr.authorId,
originalContent: prompt.content,
originalTitle: prompt.title,
proposedContent: prompt.content + cr.proposedAddition,
proposedTitle: null,
reason: cr.reason,
status: cr.status,
reviewNote: cr.reviewNote || null,
},
});
}
}
console.log("✅ Created", changeRequestsData.length, "change requests");
console.log("\n🎉 Seeding complete!");
console.log("\n📋 Test credentials (all passwords: password123):");
console.log(" Admin: admin@prompts.chat");
console.log(" Demo: demo@prompts.chat");
console.log(" Alice: alice@example.com");
console.log(" Bob: bob@example.com");
console.log(" Charlie: charlie@example.com");
}
main()
.catch((e) => {
console.error("❌ Seeding failed:", e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});