generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") directUrl = env("DIRECT_URL") } model User { id String @id @default(cuid()) email String @unique username String @unique name String? password String? avatar String? bio String? @db.VarChar(250) customLinks Json? // Array of {type: string, url: string, label?: string} role UserRole @default(USER) locale String @default("en") emailVerified DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt verified Boolean @default(false) githubUsername String? apiKey String? @unique mcpPromptsPublicByDefault Boolean @default(false) flagged Boolean @default(false) flaggedAt DateTime? flaggedReason String? dailyGenerationLimit Int @default(3) generationCreditsRemaining Int @default(3) generationCreditsResetAt DateTime? accounts Account[] subscriptions CategorySubscription[] changeRequests ChangeRequest[] pinnedPrompts PinnedPrompt[] reports PromptReport[] promptVersions PromptVersion[] votes PromptVote[] prompts Prompt[] @relation("PromptAuthor") sessions Session[] contributions Prompt[] @relation("PromptContributors") comments Comment[] @relation("CommentAuthor") commentVotes CommentVote[] notifications Notification[] @relation("NotificationRecipient") notificationsActed Notification[] @relation("NotificationActor") collections Collection[] userPromptExamples UserPromptExample[] @@map("users") } model Account { id String @id @default(cuid()) userId String type String provider String providerAccountId String refresh_token String? access_token String? expires_at Int? token_type String? scope String? id_token String? 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") } model Prompt { id String @id @default(cuid()) title String slug String? description String? content String type PromptType @default(TEXT) isPrivate Boolean @default(false) mediaUrl String? viewCount Int @default(0) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt authorId String categoryId String? embedding Json? requiredMediaCount Int? requiredMediaType RequiredMediaType? requiresMediaUpload Boolean @default(false) structuredFormat StructuredFormat? featuredAt DateTime? isFeatured Boolean @default(false) isUnlisted Boolean @default(false) unlistedAt DateTime? delistReason DelistReason? deletedAt DateTime? changeRequests ChangeRequest[] pinnedBy PinnedPrompt[] reports PromptReport[] tags PromptTag[] versions PromptVersion[] votes PromptVote[] comments Comment[] author User @relation("PromptAuthor", fields: [authorId], references: [id], onDelete: Cascade) category Category? @relation(fields: [categoryId], references: [id]) contributors User[] @relation("PromptContributors") outgoingConnections PromptConnection[] @relation("ConnectionSource") incomingConnections PromptConnection[] @relation("ConnectionTarget") collectedBy Collection[] userExamples UserPromptExample[] bestWithModels String[] // Model slugs this prompt works best with (max 3), e.g. ["gpt-4o", "claude-3-5-sonnet"] bestWithMCP Json? // MCP configs array, e.g. [{command: "npx -y @mcp/server", tools: ["tool1"]}] workflowLink String? // URL to test/demo the workflow when prompt has previous/next connections @@index([authorId]) @@index([categoryId]) @@index([type]) @@index([isPrivate]) @@index([isFeatured]) @@index([isUnlisted]) @@map("prompts") } model PromptVersion { id String @id @default(cuid()) version Int content String changeNote String? createdAt DateTime @default(now()) promptId String createdBy String author User @relation(fields: [createdBy], references: [id], onDelete: Cascade) prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade) @@unique([promptId, version]) @@index([promptId]) @@map("prompt_versions") } model ChangeRequest { id String @id @default(cuid()) proposedContent String proposedTitle String? reason String? status ChangeRequestStatus @default(PENDING) reviewNote String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt promptId String authorId String originalContent String originalTitle String author User @relation(fields: [authorId], references: [id], onDelete: Cascade) prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade) @@index([promptId]) @@index([authorId]) @@index([status]) @@map("change_requests") } model Category { id String @id @default(cuid()) name String slug String @unique description String? icon String? order Int @default(0) pinned Boolean @default(false) parentId String? parent Category? @relation("CategoryHierarchy", fields: [parentId], references: [id]) children Category[] @relation("CategoryHierarchy") subscribers CategorySubscription[] prompts Prompt[] @@index([parentId]) @@index([pinned]) @@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") } model CategorySubscription { userId String categoryId String createdAt DateTime @default(now()) category Category @relation(fields: [categoryId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@id([userId, categoryId]) @@index([userId]) @@index([categoryId]) @@map("category_subscriptions") } model PromptVote { userId String promptId String createdAt DateTime @default(now()) prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], 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()) prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@id([userId, promptId]) @@index([userId]) @@map("pinned_prompts") } model Collection { userId String promptId String createdAt DateTime @default(now()) prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@id([userId, promptId]) @@index([userId]) @@index([promptId]) @@map("collections") } model UserPromptExample { id String @id @default(cuid()) mediaUrl String comment String? createdAt DateTime @default(now()) promptId String userId String prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([promptId]) @@index([userId]) @@map("user_prompt_examples") } model PromptReport { id String @id @default(cuid()) reason ReportReason details String? status ReportStatus @default(PENDING) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt promptId String reporterId String prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade) reporter User @relation(fields: [reporterId], references: [id], onDelete: Cascade) @@index([promptId]) @@index([reporterId]) @@index([status]) @@map("prompt_reports") } model WebhookConfig { id String @id @default(cuid()) name String url String method String @default("POST") headers Json? payload String events WebhookEvent[] isEnabled Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@map("webhook_configs") } model Comment { id String @id @default(cuid()) content String score Int @default(0) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt promptId String authorId String parentId String? flagged Boolean @default(false) flaggedAt DateTime? flaggedBy String? deletedAt DateTime? prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade) author User @relation("CommentAuthor", fields: [authorId], references: [id], onDelete: Cascade) parent Comment? @relation("CommentReplies", fields: [parentId], references: [id], onDelete: Cascade) replies Comment[] @relation("CommentReplies") votes CommentVote[] @@index([promptId]) @@index([authorId]) @@index([parentId]) @@map("comments") } model CommentVote { userId String commentId String value Int // 1 for upvote, -1 for downvote createdAt DateTime @default(now()) comment Comment @relation(fields: [commentId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@id([userId, commentId]) @@index([userId]) @@index([commentId]) @@map("comment_votes") } model Notification { id String @id @default(cuid()) type NotificationType read Boolean @default(false) createdAt DateTime @default(now()) userId String actorId String? promptId String? commentId String? user User @relation("NotificationRecipient", fields: [userId], references: [id], onDelete: Cascade) actor User? @relation("NotificationActor", fields: [actorId], references: [id], onDelete: SetNull) @@index([userId]) @@index([userId, read]) @@map("notifications") } model PromptConnection { id String @id @default(cuid()) sourceId String targetId String label String order Int @default(0) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt source Prompt @relation("ConnectionSource", fields: [sourceId], references: [id], onDelete: Cascade) target Prompt @relation("ConnectionTarget", fields: [targetId], references: [id], onDelete: Cascade) @@unique([sourceId, targetId]) @@index([sourceId]) @@index([targetId]) @@map("prompt_connections") } enum NotificationType { COMMENT REPLY } enum UserRole { ADMIN USER } enum PromptType { TEXT IMAGE VIDEO AUDIO STRUCTURED SKILL TASTE } enum StructuredFormat { JSON YAML } enum ChangeRequestStatus { PENDING APPROVED REJECTED } enum RequiredMediaType { IMAGE VIDEO DOCUMENT } enum ReportReason { SPAM INAPPROPRIATE COPYRIGHT MISLEADING RELIST_REQUEST OTHER } enum ReportStatus { PENDING REVIEWED DISMISSED } enum WebhookEvent { PROMPT_CREATED PROMPT_UPDATED PROMPT_DELETED } enum DelistReason { TOO_SHORT NOT_ENGLISH LOW_QUALITY NOT_LLM_INSTRUCTION MANUAL UNUSUAL_ACTIVITY }