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") }