Files
zhuiguang-ai/prisma/schema.prisma
T

1135 lines
39 KiB
Plaintext

generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql"
}
model Category {
id Int @id @default(autoincrement())
name String @db.VarChar(50)
slug String @unique @db.VarChar(50)
icon String? @db.VarChar(100)
parentId Int? @map("parent_id")
sortOrder Int @default(0) @map("sort_order")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
tools Tool[]
pendingTools PendingTool[]
parent Category? @relation("CategoryToCategory", fields: [parentId], references: [id])
children Category[] @relation("CategoryToCategory")
@@map("categories")
}
model SkillCategory {
id Int @id @default(autoincrement())
name String @db.VarChar(50)
slug String @unique @db.VarChar(50)
icon String? @db.VarChar(100)
parentId Int? @map("parent_id")
sortOrder Int @default(0) @map("sort_order")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
skills Skill[]
pendingSkills PendingSkill[]
parent SkillCategory? @relation("SkillCategoryToSkillCategory", fields: [parentId], references: [id])
children SkillCategory[] @relation("SkillCategoryToSkillCategory")
@@map("skill_categories")
}
model Tool {
id Int @id @default(autoincrement())
name String @db.VarChar(100)
slug String @unique @db.VarChar(100)
categoryId Int @map("category_id")
description String @db.Text
logoUrl String? @map("logo_url") @db.VarChar(255)
websiteUrl String @map("website_url") @db.VarChar(255)
pricingModel PricingModel @default(freemium) @map("pricing_model")
pricingDetail String? @map("pricing_detail") @db.VarChar(200)
features Json?
tags Json?
viewCount Int @default(0) @map("view_count")
commentCount Int @default(0) @map("comment_count")
avgRating Float @default(0) @map("avg_rating")
status Status @default(draft)
lastCheckedAt DateTime? @map("last_checked_at")
websiteOk Boolean @default(true) @map("website_ok")
logoOk Boolean @default(true) @map("logo_ok")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
category Category @relation(fields: [categoryId], references: [id])
favorites Favorite[]
browsingHistory BrowsingHistory[]
reviews Review[]
collectionItems CollectionItem[]
comments Comment[]
@@index([categoryId, status])
@@fulltext([name, description])
@@map("tools")
}
model PendingTool {
id Int @id @default(autoincrement())
name String @db.VarChar(100)
slug String? @db.VarChar(100)
categoryId Int? @map("category_id")
description String? @db.Text
logoUrl String? @map("logo_url") @db.VarChar(255)
websiteUrl String? @map("website_url") @db.VarChar(255)
pricingModel PricingModel? @default(freemium) @map("pricing_model")
pricingDetail String? @map("pricing_detail") @db.VarChar(200)
features Json?
tags Json?
sourceUrl String? @map("source_url") @db.VarChar(255)
status PendingStatus @default(pending)
checkWebsiteOk Boolean? @map("check_website_ok")
checkLogoOk Boolean? @map("check_logo_ok")
checkDescOk Boolean? @map("check_desc_ok")
checkCategoryOk Boolean? @map("check_category_ok")
checkDetail Json? @map("check_detail")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
category Category? @relation(fields: [categoryId], references: [id])
@@map("pending_tools")
}
model Skill {
id Int @id @default(autoincrement())
name String @db.VarChar(100)
slug String @unique @db.VarChar(100)
categoryId Int @map("category_id")
description String @db.Text
logoUrl String? @map("logo_url") @db.VarChar(255)
sourceUrl String @map("source_url") @db.VarChar(255)
sourceType String @default("gitee") @map("source_type") @db.VarChar(20)
rating Float @default(0) @db.Float
features Json?
tags Json?
viewCount Int @default(0) @map("view_count")
status Status @default(draft)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
category SkillCategory @relation(fields: [categoryId], references: [id])
favorites Favorite[]
browsingHistory BrowsingHistory[]
reviews Review[]
collectionItems CollectionItem[]
skillReview SkillReview?
comments Comment[]
lastReviewedAt DateTime? @map("last_reviewed_at")
githubStarsHistory Json? @map("github_stars_history")
githubStars Int @default(0) @map("github_stars")
starsChangeDay Int @default(0) @map("stars_change_day")
starsChangeWeek Int @default(0) @map("stars_change_week")
starsChangeMonth Int @default(0) @map("stars_change_month")
commentCount Int @default(0) @map("comment_count")
avgRating Float @default(0) @map("avg_rating")
@@index([categoryId, status])
@@map("skills")
}
model PendingSkill {
id Int @id @default(autoincrement())
name String @db.VarChar(100)
slug String? @db.VarChar(100)
categoryId Int? @map("category_id")
description String? @db.Text
logoUrl String? @map("logo_url") @db.VarChar(255)
sourceUrl String? @map("source_url") @db.VarChar(255)
sourceType String? @map("source_type") @db.VarChar(20)
rating Float @default(0) @db.Float
features Json?
tags Json?
status PendingStatus @default(pending)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
category SkillCategory? @relation(fields: [categoryId], references: [id])
@@map("pending_skills")
}
enum PricingModel {
free
freemium
paid
subscription
}
enum Status {
draft
published
}
enum PendingStatus {
pending
approved
rejected
}
model SystemConfig {
id Int @id @default(autoincrement())
key String @unique @db.VarChar(50)
value Json
@@map("system_configs")
}
model User {
id Int @id @default(autoincrement())
email String @unique @db.VarChar(255)
passwordHash String? @db.VarChar(255)
name String? @db.VarChar(100)
avatarUrl String?
bio String? @db.Text
oauthProvider String? @db.VarChar(50)
oauthId String? @unique @db.VarChar(255)
role String @default("user") @db.VarChar(20)
roleId Int? @map("role_id")
points Int @default(0)
level UserLevel @default(LV01)
isBot Boolean @default(false) @map("is_bot")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
botConfig BotConfig?
assignedRole Role? @relation(fields: [roleId], references: [id])
favorites Favorite[]
browsingHistory BrowsingHistory[]
reviews Review[]
collections Collection[]
comments Comment[]
commentLikes CommentLike[]
notifications Notification[]
forumTopics ForumTopic[]
forumPosts ForumPost[]
pointsHistory PointsHistory[]
topicLikes ForumTopicLike[]
postLikes ForumPostLike[]
categoryFollows ForumCategoryFollow[]
topicBookmarks ForumTopicBookmark[]
topicDrafts ForumDraft[]
reports ForumReport[]
resolvedReports ForumReport[] @relation("ForumReportResolver")
checkIns ForumCheckIn[]
moderationLogs ForumModerationLog[] @relation("ForumModerationActor")
achievements UserAchievement[]
topicSubscriptions ForumTopicSubscription[]
@@unique([oauthProvider, oauthId])
@@map("users")
}
model PointsHistory {
id Int @id @default(autoincrement())
userId Int @map("user_id")
points Int
reason String @db.VarChar(50)
detail String? @db.VarChar(200)
refType String? @map("ref_type") @db.VarChar(50)
refId Int? @map("ref_id")
createdAt DateTime @default(now()) @map("created_at")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId, createdAt])
@@map("points_history")
}
enum UserLevel {
LV01
LV02
LV03
LV04
LV05
LV06
LV07
LV08
LV09
LV10
LV11
LV12
LV13
LV14
LV15
LV16
LV17
LV18
LV19
LV20
}
model Role {
id Int @id @default(autoincrement())
name String @db.VarChar(50)
slug String @unique @db.VarChar(50)
isSystem Boolean @default(false) @map("is_system")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
permissions RolePermission[]
users User[]
@@map("roles")
}
model Permission {
id Int @id @default(autoincrement())
groupName String @map("group_name") @db.VarChar(50)
name String @db.VarChar(50)
key String @unique @db.VarChar(80)
sortOrder Int @default(0) @map("sort_order")
createdAt DateTime @default(now()) @map("created_at")
rolePermissions RolePermission[]
@@index([groupName, sortOrder])
@@map("permissions")
}
model RolePermission {
roleId Int @map("role_id")
permissionId Int @map("permission_id")
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade)
@@id([roleId, permissionId])
@@map("role_permissions")
}
model Favorite {
id Int @id @default(autoincrement())
userId Int @map("user_id")
toolId Int? @map("tool_id")
skillId Int? @map("skill_id")
createdAt DateTime @default(now()) @map("created_at")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
tool Tool? @relation(fields: [toolId], references: [id], onDelete: Cascade)
skill Skill? @relation(fields: [skillId], references: [id], onDelete: Cascade)
@@unique([userId, toolId])
@@unique([userId, skillId])
@@index([userId])
@@map("favorites")
}
model BrowsingHistory {
id Int @id @default(autoincrement())
userId Int @map("user_id")
toolId Int? @map("tool_id")
skillId Int? @map("skill_id")
viewedAt DateTime @default(now()) @updatedAt @map("viewed_at")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
tool Tool? @relation(fields: [toolId], references: [id], onDelete: Cascade)
skill Skill? @relation(fields: [skillId], references: [id], onDelete: Cascade)
@@unique([userId, toolId])
@@unique([userId, skillId])
@@index([userId, viewedAt])
@@map("browsing_histories")
}
model Review {
id Int @id @default(autoincrement())
userId Int @map("user_id")
toolId Int? @map("tool_id")
skillId Int? @map("skill_id")
rating Int?
comment String @db.Text
createdAt DateTime @default(now()) @map("created_at")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
tool Tool? @relation(fields: [toolId], references: [id], onDelete: Cascade)
skill Skill? @relation(fields: [skillId], references: [id], onDelete: Cascade)
@@unique([userId, toolId])
@@unique([userId, skillId])
@@index([toolId, createdAt])
@@index([skillId, createdAt])
@@map("reviews")
}
model Collection {
id Int @id @default(autoincrement())
userId Int @map("user_id")
name String @db.VarChar(50)
description String? @db.Text
sortOrder Int @default(0) @map("sort_order")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
items CollectionItem[]
@@index([userId])
@@map("collections")
}
model CollectionItem {
id Int @id @default(autoincrement())
collectionId Int @map("collection_id")
toolId Int? @map("tool_id")
skillId Int? @map("skill_id")
addedAt DateTime @default(now()) @map("added_at")
collection Collection @relation(fields: [collectionId], references: [id], onDelete: Cascade)
tool Tool? @relation(fields: [toolId], references: [id], onDelete: Cascade)
skill Skill? @relation(fields: [skillId], references: [id], onDelete: Cascade)
@@unique([collectionId, toolId])
@@unique([collectionId, skillId])
@@index([collectionId])
@@map("collection_items")
}
model DailyReport {
id Int @id @default(autoincrement())
date DateTime @unique @db.Date
title String @db.VarChar(200)
summary String? @db.Text
hotCount Int @default(0) @map("hot_count")
coverUrl String? @map("cover_url") @db.VarChar(255)
status Status @default(draft)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
items DailyReportItem[]
@@index([date])
@@index([status])
@@map("daily_reports")
}
model DailyReportItem {
id Int @id @default(autoincrement())
reportId Int @map("report_id")
sortOrder Int @default(0) @map("sort_order")
category String @default("tech") @db.VarChar(20)
title String @db.VarChar(200)
summary String? @db.Text
detail String? @db.Text
sourceUrl String? @map("source_url") @db.VarChar(500)
imageUrl String? @map("image_url") @db.VarChar(255)
hotScore Int @default(0) @map("hot_score")
createdAt DateTime @default(now()) @map("created_at")
report DailyReport @relation(fields: [reportId], references: [id], onDelete: Cascade)
@@index([reportId, sortOrder])
@@map("daily_report_items")
}
model SkillReview {
id Int @id @default(autoincrement())
skillId Int @unique @map("skill_id")
skill Skill @relation(fields: [skillId], references: [id])
capability Float
devExp Float @map("dev_exp")
costLicense Float @map("cost_license")
community Float
performance Float
overall Float
reviews Json
longArticle String? @map("long_article") @db.Text
videoScript String? @map("video_script") @db.Text
socialCards Json? @map("social_cards")
status ReviewStatus @default(DRAFT)
reviewedAt DateTime @updatedAt @map("reviewed_at")
createdAt DateTime @default(now()) @map("created_at")
@@index([skillId])
@@index([overall])
@@map("skill_reviews")
}
model ReviewGenerationLog {
id Int @id @default(autoincrement())
skillId Int @map("skill_id")
status String @db.VarChar(20)
prompt String @db.Text
response String? @db.Text
error String? @db.Text
createdAt DateTime @default(now()) @map("created_at")
@@index([skillId])
@@map("review_generation_logs")
}
enum ReviewStatus {
DRAFT
PUBLISHED
REJECTED
OUTDATED
}
model TaskLog {
id Int @id @default(autoincrement())
taskKey String @map("task_key") @db.VarChar(50)
taskName String @map("task_name") @db.VarChar(100)
status String @db.VarChar(20)
startedAt DateTime @map("started_at")
finishedAt DateTime? @map("finished_at")
duration Int?
result Json?
error String? @db.Text
triggerBy String @default("cron") @map("trigger_by") @db.VarChar(20)
createdAt DateTime @default(now()) @map("created_at")
@@index([taskKey, startedAt])
@@map("task_logs")
}
model TaskConfig {
id Int @id @default(autoincrement())
taskKey String @unique @map("task_key") @db.VarChar(50)
taskName String @map("task_name") @db.VarChar(100)
description String? @db.VarChar(255)
enabled Boolean @default(true)
cronExpr String? @map("cron_expr") @db.VarChar(50)
config Json?
updatedAt DateTime @updatedAt @map("updated_at")
@@map("task_configs")
}
model Comment {
id Int @id @default(autoincrement())
userId Int @map("user_id")
toolId Int? @map("tool_id")
skillId Int? @map("skill_id")
parentId Int? @map("parent_id")
content String @db.Text
rating Int?
likeCount Int @default(0) @map("like_count")
isPinned Boolean @default(false) @map("is_pinned")
status CommentStatus @default(ACTIVE)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
user User @relation(fields: [userId], references: [id])
tool Tool? @relation(fields: [toolId], references: [id], onDelete: Cascade)
skill Skill? @relation(fields: [skillId], references: [id], onDelete: Cascade)
parent Comment? @relation("CommentReplies", fields: [parentId], references: [id])
replies Comment[] @relation("CommentReplies")
likes CommentLike[]
@@index([toolId, createdAt])
@@index([skillId, createdAt])
@@index([userId])
@@map("comments")
}
enum CommentStatus {
ACTIVE
HIDDEN
DELETED
}
model CommentLike {
id Int @id @default(autoincrement())
commentId Int @map("comment_id")
userId Int @map("user_id")
createdAt DateTime @default(now()) @map("created_at")
comment Comment @relation(fields: [commentId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([commentId, userId])
@@map("comment_likes")
}
model Notification {
id Int @id @default(autoincrement())
userId Int @map("user_id")
type NotifType
title String @db.VarChar(100)
content String? @db.VarChar(255)
link String? @db.VarChar(255)
isRead Boolean @default(false) @map("is_read")
createdAt DateTime @default(now()) @map("created_at")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId, isRead, createdAt])
@@map("notifications")
}
enum NotifType {
COMMENT_REPLY
COMMENT_LIKE
TOPIC_REPLY
MENTION
BEST_ANSWER
POST_LIKE
TOPIC_LIKE
SYSTEM
}
model ForumCategory {
id Int @id @default(autoincrement())
name String @db.VarChar(30)
slug String @unique @db.VarChar(30)
description String? @db.VarChar(100)
icon String? @db.VarChar(30)
parentId Int? @map("parent_id")
sortOrder Int @default(0) @map("sort_order")
topicCount Int @default(0) @map("topic_count")
followerCount Int @default(0) @map("follower_count")
createdAt DateTime @default(now()) @map("created_at")
parent ForumCategory? @relation("CategoryHierarchy", fields: [parentId], references: [id])
children ForumCategory[] @relation("CategoryHierarchy")
topics ForumTopic[]
followers ForumCategoryFollow[]
@@map("forum_categories")
}
model ForumTopic {
id Int @id @default(autoincrement())
categoryId Int @map("category_id")
userId Int @map("user_id")
title String @db.VarChar(100)
slug String @unique @db.VarChar(120)
content String @db.Text
isPinned Boolean @default(false) @map("is_pinned")
isLocked Boolean @default(false) @map("is_locked")
isFeatured Boolean @default(false) @map("is_featured")
isHidden Boolean @default(false) @map("is_hidden")
viewCount Int @default(0) @map("view_count")
replyCount Int @default(0) @map("reply_count")
likeCount Int @default(0) @map("like_count")
lastReplyAt DateTime? @map("last_reply_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
category ForumCategory @relation(fields: [categoryId], references: [id])
user User @relation(fields: [userId], references: [id])
posts ForumPost[]
likes ForumTopicLike[]
tags ForumTopicTag[]
bookmarks ForumTopicBookmark[]
reports ForumReport[]
subscribers ForumTopicSubscription[]
@@index([categoryId, lastReplyAt])
@@index([categoryId, isPinned, createdAt])
@@index([userId])
@@index([isFeatured, lastReplyAt])
@@index([isHidden])
@@fulltext([title])
@@fulltext([title, content])
@@map("forum_topics")
}
model ForumPost {
id Int @id @default(autoincrement())
topicId Int @map("topic_id")
userId Int @map("user_id")
content String @db.Text
isAnswer Boolean @default(false) @map("is_answer")
isHidden Boolean @default(false) @map("is_hidden")
likeCount Int @default(0) @map("like_count")
replyToId Int? @map("reply_to_id")
replyToSnapshot String? @map("reply_to_snapshot") @db.VarChar(300)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
topic ForumTopic @relation(fields: [topicId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id])
likes ForumPostLike[]
replyTo ForumPost? @relation("PostReplies", fields: [replyToId], references: [id], onDelete: SetNull)
replies ForumPost[] @relation("PostReplies")
@@index([topicId, createdAt])
@@index([userId])
@@index([replyToId])
@@index([isHidden])
@@map("forum_posts")
}
model ForumTopicLike {
id Int @id @default(autoincrement())
topicId Int @map("topic_id")
userId Int @map("user_id")
createdAt DateTime @default(now()) @map("created_at")
topic ForumTopic @relation(fields: [topicId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([topicId, userId])
@@index([userId])
@@map("forum_topic_likes")
}
model ForumPostLike {
id Int @id @default(autoincrement())
postId Int @map("post_id")
userId Int @map("user_id")
createdAt DateTime @default(now()) @map("created_at")
post ForumPost @relation(fields: [postId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([postId, userId])
@@index([userId])
@@map("forum_post_likes")
}
model ForumCategoryFollow {
id Int @id @default(autoincrement())
categoryId Int @map("category_id")
userId Int @map("user_id")
createdAt DateTime @default(now()) @map("created_at")
category ForumCategory @relation(fields: [categoryId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([categoryId, userId])
@@index([userId])
@@map("forum_category_follows")
}
model ForumTag {
id Int @id @default(autoincrement())
name String @unique @db.VarChar(20)
slug String @unique @db.VarChar(30)
topicCount Int @default(0) @map("topic_count")
createdAt DateTime @default(now()) @map("created_at")
topics ForumTopicTag[]
@@map("forum_tags")
}
model ForumTopicTag {
id Int @id @default(autoincrement())
topicId Int @map("topic_id")
tagId Int @map("tag_id")
topic ForumTopic @relation(fields: [topicId], references: [id], onDelete: Cascade)
tag ForumTag @relation(fields: [tagId], references: [id], onDelete: Cascade)
@@unique([topicId, tagId])
@@index([tagId])
@@map("forum_topic_tags")
}
model ForumDraft {
id Int @id @default(autoincrement())
userId Int @map("user_id")
categoryId Int? @map("category_id")
title String? @db.VarChar(100)
content String @db.Text
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId, updatedAt])
@@map("forum_drafts")
}
model ForumTopicBookmark {
id Int @id @default(autoincrement())
topicId Int @map("topic_id")
userId Int @map("user_id")
createdAt DateTime @default(now()) @map("created_at")
topic ForumTopic @relation(fields: [topicId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([topicId, userId])
@@index([userId, createdAt])
@@map("forum_topic_bookmarks")
}
model ForumReport {
id Int @id @default(autoincrement())
reporterId Int @map("reporter_id")
topicId Int? @map("topic_id")
postId Int? @map("post_id")
reason String @db.VarChar(50)
detail String? @db.VarChar(500)
status String @default("pending") @db.VarChar(20)
resolution String? @db.VarChar(20)
resolvedBy Int? @map("resolved_by")
resolvedAt DateTime? @map("resolved_at")
createdAt DateTime @default(now()) @map("created_at")
reporter User @relation(fields: [reporterId], references: [id], onDelete: Cascade)
topic ForumTopic? @relation(fields: [topicId], references: [id], onDelete: Cascade)
resolver User? @relation("ForumReportResolver", fields: [resolvedBy], references: [id], onDelete: SetNull)
@@index([status, createdAt])
@@index([reporterId])
@@index([topicId])
@@index([postId])
@@index([resolvedBy])
@@map("forum_reports")
}
model ForumCheckIn {
id Int @id @default(autoincrement())
userId Int @map("user_id")
checkInDate DateTime @map("check_in_date") @db.Date
streak Int @default(1)
pointsEarned Int @default(0) @map("points_earned")
createdAt DateTime @default(now()) @map("created_at")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([userId, checkInDate])
@@index([userId, checkInDate])
@@map("forum_check_ins")
}
model ForumModerationLog {
id Int @id @default(autoincrement())
actorId Int @map("actor_id")
targetType String @map("target_type") @db.VarChar(20)
targetId Int @map("target_id")
action String @db.VarChar(30)
reason String? @db.VarChar(200)
createdAt DateTime @default(now()) @map("created_at")
actor User @relation("ForumModerationActor", fields: [actorId], references: [id], onDelete: Cascade)
@@index([actorId, createdAt])
@@index([targetType, targetId])
@@index([createdAt])
@@map("forum_moderation_logs")
}
model BotConfig {
id Int @id @default(autoincrement())
userId Int @unique @map("user_id")
displayName String @map("display_name") @db.VarChar(50)
personality Json
primaryForums Json @map("primary_forums")
activeHours Json @map("active_hours")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
user User @relation(fields: [userId], references: [id])
memories BotMemory[]
botPersonaVariants BotPersonaVariant[] @relation("BotVariants")
adversarialLearnings BotAdversarialLearning[] @relation("BotAdversarialLearnings")
@@map("bot_configs")
}
model BotMemory {
id Int @id @default(autoincrement())
botId Int @map("bot_id")
memoryType String @map("memory_type") @db.VarChar(20)
layer String @default("LONGTERM") @map("layer") @db.VarChar(20)
content Json
importance Float @default(0.5)
contextTags Json? @map("context_tags")
ttl DateTime? @map("ttl")
createdAt DateTime @default(now()) @map("created_at")
bot BotConfig @relation(fields: [botId], references: [id])
@@index([botId, layer, importance])
@@index([botId, memoryType, createdAt])
@@index([botId, createdAt])
@@map("bot_memories")
}
model BotDailyStat {
id Int @id @default(autoincrement())
botId Int @map("bot_id")
date DateTime @db.Date
topicCreated Int @default(0) @map("topic_created")
replySent Int @default(0) @map("reply_sent")
followUpSent Int @default(0) @map("follow_up_sent")
repliesReceived Int @default(0) @map("replies_received")
likesReceived Int @default(0) @map("likes_received")
humanInteractions Int @default(0) @map("human_interactions")
feedbackProcessed Int @default(0) @map("feedback_processed")
topTopicId Int? @map("top_topic_id")
updatedAt DateTime @updatedAt @map("updated_at")
@@unique([botId, date])
@@index([date])
@@map("bot_daily_stats")
}
model BotSkill {
id Int @id @default(autoincrement())
botId Int @map("bot_id")
name String @db.VarChar(50)
category String @db.VarChar(30)
hookPattern String @map("hook_pattern") @db.Text
bodyTemplate String @map("body_template") @db.Text
applicability String? @db.Text
sourceTopicIds Json @map("source_topic_ids")
successRate Float @default(0) @map("success_rate")
usageCount Int @default(0) @map("usage_count")
avgReplies Float @default(0) @map("avg_replies")
avgLikes Float @default(0) @map("avg_likes")
version Int @default(1)
isActive Boolean @default(true) @map("is_active")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@index([botId, category, isActive])
@@index([botId, successRate])
@@map("bot_skills")
}
model BotWeeklyReview {
id Int @id @default(autoincrement())
botId Int @map("bot_id")
weekStart DateTime @map("week_start") @db.Date
weekEnd DateTime @map("week_end") @db.Date
topicsCreated Int @default(0) @map("topics_created")
repliesSent Int @default(0) @map("replies_sent")
repliesReceived Int @default(0) @map("replies_received")
humanRatio Float @default(0) @map("human_ratio")
likesReceived Int @default(0) @map("likes_received")
engagementScore Float @default(0) @map("engagement_score")
nextWeekQuota String @map("next_week_quota") @db.VarChar(20)
reflection String? @db.Text
createdAt DateTime @default(now()) @map("created_at")
@@unique([botId, weekStart])
@@index([botId, weekStart])
@@map("bot_weekly_reviews")
}
model BotPersona {
botId Int @id @map("bot_id")
avgReplyLength Int @default(0) @map("avg_reply_length")
questionRatio Float @default(0) @map("question_ratio")
exclamationCount Int @default(0) @map("exclamation_count")
avgTopicLength Int @default(0) @map("avg_topic_length")
stanceKeywords Json? @map("stance_keywords")
topHumanUsers Json? @map("top_human_users")
topTopicTypes Json? @map("top_topic_types")
lastTopicTitles Json? @map("last_topic_titles")
postSampleCount Int @default(0) @map("post_sample_count")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("bot_personas")
}
model BotPersonaVariant {
id Int @id @default(autoincrement())
botId Int @map("bot_id")
experimentId Int? @map("experiment_id")
variantKey String @map("variant_key") @db.VarChar(20)
label String @db.VarChar(50)
description String? @db.VarChar(200)
stanceKeywords Json? @map("stance_keywords")
topTopicTypes Json? @map("top_topic_types")
topHumanUsers Json? @map("top_human_users")
styleHints Json? @map("style_hints")
weight Float @default(0.5)
isControl Boolean @default(false) @map("is_control")
isActive Boolean @default(true) @map("is_active")
sampleCount Int @default(0) @map("sample_count")
replyCount Int @default(0) @map("reply_count")
likeCount Int @default(0) @map("like_count")
humanReplyCount Int @default(0) @map("human_reply_count")
engagementScore Float @default(0) @map("engagement_score")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
botConfig BotConfig @relation("BotVariants", fields: [botId], references: [id], onDelete: Cascade)
experiment BotPersonaExperiment? @relation("ExperimentVariants", fields: [experimentId], references: [id], onDelete: SetNull)
assignments BotPersonaAssignment[]
metrics BotPersonaMetric[]
@@unique([botId, variantKey])
@@index([botId, isActive])
@@index([experimentId])
@@map("bot_persona_variants")
}
model BotPersonaExperiment {
id Int @id @default(autoincrement())
botId Int @map("bot_id")
name String @db.VarChar(80)
description String? @db.VarChar(200)
status String @default("active") @db.VarChar(20)
winnerVariantKey String? @map("winner_variant_key") @db.VarChar(20)
minSamplesPerArm Int @default(20) @map("min_samples_per_arm")
significanceLevel Float @default(0.1) @map("significance_level")
primaryMetric String @default("engagement_score") @map("primary_metric") @db.VarChar(30)
config Json?
startedAt DateTime @default(now()) @map("started_at")
endedAt DateTime? @map("ended_at")
lastAnalyzedAt DateTime? @map("last_analyzed_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
variants BotPersonaVariant[] @relation("ExperimentVariants")
@@index([botId, status])
@@index([status])
@@map("bot_persona_experiments")
}
model BotPersonaAssignment {
id Int @id @default(autoincrement())
botId Int @map("bot_id")
variantId Int @map("variant_id")
refType String @map("ref_type") @db.VarChar(20)
refId Int @map("ref_id")
forumSlug String? @map("forum_slug") @db.VarChar(30)
replies Int @default(0)
likes Int @default(0)
humanReplies Int @default(0) @map("human_replies")
impressions Int @default(0)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
variant BotPersonaVariant @relation(fields: [variantId], references: [id], onDelete: Cascade)
@@unique([refType, refId])
@@index([botId, variantId])
@@index([variantId, createdAt])
@@map("bot_persona_assignments")
}
model BotPersonaMetric {
id Int @id @default(autoincrement())
variantId Int @map("variant_id")
date DateTime @db.Date
impressions Int @default(0)
replies Int @default(0)
likes Int @default(0)
humanReplies Int @default(0) @map("human_replies")
contentCount Int @default(0) @map("content_count")
avgReplies Float @default(0) @map("avg_replies")
avgLikes Float @default(0) @map("avg_likes")
computedScore Float @default(0) @map("computed_score")
updatedAt DateTime @updatedAt @map("updated_at")
variant BotPersonaVariant @relation(fields: [variantId], references: [id], onDelete: Cascade)
@@unique([variantId, date])
@@index([date])
@@map("bot_persona_metrics")
}
model BotAdversarialLearning {
id Int @id @default(autoincrement())
botId Int @map("bot_id")
weekKey String @map("week_key") @db.VarChar(20)
sourceRefType String @map("source_ref_type") @db.VarChar(20)
sourceRefId Int @map("source_ref_id")
sourceUserId Int @map("source_user_id")
sourceUserName String? @map("source_user_name") @db.VarChar(50)
forumSlug String? @map("forum_slug") @db.VarChar(30)
sourceTitle String? @map("source_title") @db.VarChar(200)
sourceContent String @map("source_content") @db.Text
sourceMetrics Json @map("source_metrics")
relevanceScore Float @default(0) @map("relevance_score")
learnedInsight String @map("learned_insight") @db.Text
learnCategories Json? @map("learn_categories")
status String @default("active") @db.VarChar(20)
usedCount Int @default(0) @map("used_count")
learnedAt DateTime @default(now()) @map("learned_at")
expiresAt DateTime? @map("expires_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
botConfig BotConfig @relation("BotAdversarialLearnings", fields: [botId], references: [id], onDelete: Cascade)
@@unique([botId, weekKey])
@@index([botId, status])
@@index([weekKey])
@@index([sourceRefType, sourceRefId])
@@map("bot_adversarial_learnings")
}
model BotCrossForumAffinity {
id Int @id @default(autoincrement())
botId Int @map("bot_id")
forumSlug String @map("forum_slug") @db.VarChar(30)
affinity Float @default(0)
sampleCount Int @default(0) @map("sample_count")
reason String? @db.VarChar(100)
updatedAt DateTime @updatedAt @map("updated_at")
@@unique([botId, forumSlug])
@@index([botId, affinity])
@@map("bot_cross_forum_affinities")
}
model Achievement {
key String @id @db.VarChar(50)
name String @db.VarChar(50)
description String @db.VarChar(200)
icon String @db.VarChar(20)
tier String @default("bronze") @db.VarChar(20)
points Int @default(0)
category String @default("general") @db.VarChar(30)
sortOrder Int @default(0) @map("sort_order")
isActive Boolean @default(true) @map("is_active")
createdAt DateTime @default(now()) @map("created_at")
users UserAchievement[]
@@index([category, isActive, sortOrder])
@@map("achievements")
}
model UserAchievement {
id Int @id @default(autoincrement())
userId Int @map("user_id")
achievementKey String @map("achievement_key") @db.VarChar(50)
progress Int @default(0)
unlockedAt DateTime? @map("unlocked_at")
notifiedAt DateTime? @map("notified_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
achievement Achievement @relation(fields: [achievementKey], references: [key])
@@unique([userId, achievementKey])
@@index([userId, unlockedAt])
@@index([achievementKey])
@@map("user_achievements")
}
model ForumTopicSubscription {
id Int @id @default(autoincrement())
topicId Int @map("topic_id")
userId Int @map("user_id")
notifyReply Boolean @default(true) @map("notify_reply")
createdAt DateTime @default(now()) @map("created_at")
topic ForumTopic @relation(fields: [topicId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([topicId, userId])
@@index([userId, createdAt])
@@map("forum_topic_subscriptions")
}