Files
zhuiguang-ai/.trae/specs/modules/01-database.md
T

743 lines
33 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 数据库模块
## 技术栈
- Prisma 7.8 + @prisma/adapter-mariadb
- MySQL (阿里云RDS)
- 连接字符串: `mysql://mohe001:***@rm-0jlbgr2rv6dj3t6jngo.mysql.rds.aliyuncs.com:3306/zhuiguang_ai`
- Prisma单例模式防止热重载多实例
## 数据模型
### Category (工具分类)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| name | String @db.VarChar(50) | 分类名称 |
| slug | String @unique @db.VarChar(50) | URL标识 |
| icon | String? @db.VarChar(100) | 图标 |
| parentId | Int? @map("parent_id") | 父分类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/children (自引用层级)
### SkillCategory (技能分类)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| name | String @db.VarChar(50) | 分类名称 |
| slug | String @unique @db.VarChar(50) | URL标识 |
| icon | String? @db.VarChar(100) | 图标 |
| parentId | Int? @map("parent_id") | 父分类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/children (自引用层级)
### Tool (已发布工具)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| name | String @db.VarChar(100) | 工具名称 |
| slug | String @unique @db.VarChar(100) | URL标识 |
| categoryId | Int @map("category_id") | 分类ID |
| description | String @db.Text | 简介 |
| logoUrl | String? @map("logo_url") @db.VarChar(255) | Logo地址 |
| websiteUrl | String @map("website_url") @db.VarChar(255) | 官网地址 |
| pricingModel | PricingModel @default(freemium) | 定价模型 |
| pricingDetail | String? @map("pricing_detail") @db.VarChar(200) | 定价详情 |
| features | Json? | 功能特性(JSON) |
| tags | Json? | 标签数组(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) | 状态(draft/published) |
| lastCheckedAt | DateTime? @map("last_checked_at") | 最后巡检时间 |
| websiteOk | Boolean @default(true) @map("website_ok") | 网站可访问 |
| logoOk | Boolean @default(true) @map("logo_ok") | Logo有效 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: category, favorites, browsingHistory, reviews, collectionItems, comments
### PendingTool (待审核工具)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| name | String @db.VarChar(100) | 工具名称 |
| slug | String? @db.VarChar(100) | URL标识 |
| categoryId | Int? @map("category_id") | 分类ID |
| description | String? @db.Text | 简介 |
| logoUrl | String? @map("logo_url") @db.VarChar(255) | Logo地址 |
| websiteUrl | String? @map("website_url") @db.VarChar(255) | 官网地址 |
| pricingModel | PricingModel? @default(freemium) | 定价模型 |
| pricingDetail | String? @map("pricing_detail") @db.VarChar(200) | 定价详情 |
| features | Json? | 功能特性 |
| tags | Json? | 标签数组 |
| sourceUrl | String? @map("source_url") @db.VarChar(255) | 来源地址 |
| status | PendingStatus @default(pending) | 状态(pending/approved/rejected) |
| checkWebsiteOk | Boolean? @map("check_website_ok") | 网站可访问检查结果 |
| checkLogoOk | Boolean? @map("check_logo_ok") | Logo检查结果 |
| checkDescOk | Boolean? @map("check_desc_ok") | 描述检查结果 |
| checkCategoryOk | Boolean? @map("check_category_ok") | 分类检查结果 |
| checkDetail | Json? @map("check_detail") | 检查详情(JSON) |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: category
### Skill (已发布技能)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| name | String @db.VarChar(100) | 技能名称 |
| slug | String @unique @db.VarChar(100) | URL标识 |
| categoryId | Int @map("category_id") | 分类ID |
| description | String @db.Text | 简介 |
| logoUrl | String? @map("logo_url") @db.VarChar(255) | Logo地址 |
| sourceUrl | String @map("source_url") @db.VarChar(255) | 源码地址(GitHub) |
| sourceType | String @default("gitee") @db.VarChar(20) | 来源类型 |
| rating | Float @default(0) @db.Float | 综合评分 |
| features | Json? | 功能特性(forks/language/license/topics) |
| 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") | 更新时间 |
| lastReviewedAt | DateTime? @map("last_reviewed_at") | 最近评测时间 |
| githubStarsHistory | Json? @map("github_stars_history") | Star历史数据(90天) |
| githubStars | Int @default(0) @map("github_stars") | 当前GitHub Stars |
| starsChangeDay | Int @default(0) @map("stars_change_day") | 日Star变化 |
| starsChangeWeek | Int @default(0) @map("stars_change_week") | 周Star变化 |
| starsChangeMonth | Int @default(0) @map("stars_change_month") | 月Star变化 |
| commentCount | Int @default(0) @map("comment_count") | 评论数 |
| avgRating | Float @default(0) @map("avg_rating") | 平均评分 |
**关系**: category, favorites, browsingHistory, reviews, collectionItems, skillReview, comments
### PendingSkill (待审核技能)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| name | String @db.VarChar(100) | 技能名称 |
| slug | String? @db.VarChar(100) | URL标识 |
| categoryId | Int? @map("category_id") | 分类ID |
| description | String? @db.Text | 简介 |
| logoUrl | String? @map("logo_url") @db.VarChar(255) | Logo地址 |
| 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
### User (用户)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| email | String @unique @db.VarChar(255) | 邮箱 |
| passwordHash | String? @db.VarChar(255) | 密码哈希(bcrypt) |
| name | String? @db.VarChar(100) | 昵称 |
| avatarUrl | String? | 头像地址 |
| oauthProvider | String? @db.VarChar(50) | OAuth提供商(github) |
| oauthId | String? @unique @db.VarChar(255) | OAuth外部ID |
| role | String @default("user") @db.VarChar(20) | 角色字符串(向后兼容) |
| roleId | Int? @map("role_id") | 角色ID(关联Role表) |
| points | Int @default(0) | 积分 |
| level | UserLevel @default(BRONZE) | 用户等级 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: assignedRole, favorites, browsingHistory, reviews, collections, comments, commentLikes, notifications, forumTopics, forumPosts
### 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[])
### 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 (角色-权限关联)
| 字段 | 类型 | 说明 |
|------|------|------|
| roleId | Int @map("role_id") | 角色ID(联合主键) |
| permissionId | Int @map("permission_id") | 权限ID(联合主键) |
**关系**: role, permission (onDelete: Cascade)
### SystemConfig (系统配置)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| key | String @unique @db.VarChar(50) | 配置键 |
| value | Json | 配置值(JSON) |
### SkillReview (技能评测)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| skillId | Int @unique @map("skill_id") | 关联Skill(一对一) |
| capability | Float | 场景与能力评分(1-5) |
| devExp | Float @map("dev_exp") | 开发体验评分(1-5) |
| costLicense | Float @map("cost_license") | 成本与许可评分(1-5) |
| community | Float | 社区健康评分(1-5) |
| performance | Float | 性能稳定评分(1-5) |
| overall | Float | 综合评分(五维均值) |
| reviews | Json | 完整评测数据(含各维度summary/detail) |
| 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") | 创建时间 |
**关系**: skill (一对一)
### ReviewGenerationLog (评测生成日志)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| skillId | Int @map("skill_id") | 关联Skill |
| status | String @db.VarChar(20) | SUCCESS/FAILED |
| prompt | String @db.Text | 生成提示词 |
| response | String? @db.Text | API响应 |
| error | String? @db.Text | 错误信息 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
### 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) | Cron表达式 |
| config | Json? | 任务配置(JSON) |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
### 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) | 执行状态(completed/failed) |
| startedAt | DateTime @map("started_at") | 开始时间 |
| finishedAt | DateTime? @map("finished_at") | 结束时间 |
| duration | Int? | 执行时长(毫秒) |
| result | Json? | 执行结果(JSON) |
| error | String? @db.Text | 错误信息 |
| triggerBy | String @default("cron") @map("trigger_by") @db.VarChar(20) | 触发方式 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
### Favorite (收藏)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| userId | Int @map("user_id") | 用户ID |
| toolId | Int? @map("tool_id") | 工具ID |
| skillId | Int? @map("skill_id") | 技能ID |
| createdAt | DateTime @default(now()) @map("created_at") | 收藏时间 |
**关系**: user, tool, skill
**唯一约束**: [userId, toolId], [userId, skillId]
### BrowsingHistory (浏览历史)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| userId | Int @map("user_id") | 用户ID |
| toolId | Int? @map("tool_id") | 工具ID |
| skillId | Int? @map("skill_id") | 技能ID |
| viewedAt | DateTime @default(now()) @updatedAt @map("viewed_at") | 浏览时间 |
**关系**: user, tool, skill
### Review (评论)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| userId | Int @map("user_id") | 用户ID |
| toolId | Int? @map("tool_id") | 工具ID |
| skillId | Int? @map("skill_id") | 技能ID |
| rating | Int? | 评分(1-5) |
| comment | String @db.Text | 评论内容 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
**关系**: user, tool, skill
### Collection (收藏夹)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| userId | Int @map("user_id") | 用户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, items
### CollectionItem (收藏夹项目)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| collectionId | Int @map("collection_id") | 收藏夹ID |
| toolId | Int? @map("tool_id") | 工具ID |
| skillId | Int? @map("skill_id") | 技能ID |
| addedAt | DateTime @default(now()) @map("added_at") | 添加时间 |
**关系**: collection, tool, skill
### DailyReport (AI日报)
| 字段 | 类型 | 说明 |
|------|------|------|
| 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 (日报条目)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| reportId | Int @map("report_id") | 日报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 (onDelete: Cascade)
### Comment (评论/回复)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| userId | Int @map("user_id") | 用户ID |
| toolId | Int? @map("tool_id") | 工具ID |
| skillId | Int? @map("skill_id") | 技能ID |
| parentId | Int? @map("parent_id") | 父评论ID(回复) |
| content | String @db.Text | 评论内容 |
| rating | Int? | 评分(1-5) |
| 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, tool, skill, parent/replies (自引用), likes
### CommentLike (评论点赞)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| commentId | Int @map("comment_id") | 评论ID |
| userId | Int @map("user_id") | 用户ID |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
**关系**: comment, user (onDelete: Cascade)
**唯一约束**: [commentId, userId]
### Notification (通知)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| userId | Int @map("user_id") | 用户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
### ForumCategory (论坛板块)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| name | String @db.VarChar(30) | 板块名称 |
| slug | String @unique @db.VarChar(30) | URL标识 |
| description | String? @db.VarChar(100) | 描述 |
| icon | String? @db.VarChar(30) | 图标 |
| sortOrder | Int @default(0) @map("sort_order") | 排序 |
| topicCount | Int @default(0) @map("topic_count") | 话题数 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
**关系**: topics
### ForumTopic (论坛话题)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| categoryId | Int @map("category_id") | 板块ID |
| userId | Int @map("user_id") | 作者ID |
| title | String @db.VarChar(100) | 标题 |
| slug | String @unique @db.VarChar(120) | URL标识 |
| content | String @db.Text | 内容 |
| isPinned | Boolean @default(false) @map("is_pinned") | 是否置顶 |
| isLocked | Boolean @default(false) @map("is_locked") | 是否锁定 |
| viewCount | Int @default(0) @map("view_count") | 浏览数 |
| replyCount | Int @default(0) @map("reply_count") | 回复数 |
| lastReplyAt | DateTime? @map("last_reply_at") | 最后回复时间 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: category, user, posts
### ForumPost (论坛回复)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| topicId | Int @map("topic_id") | 话题ID |
| userId | Int @map("user_id") | 作者ID |
| content | String @db.Text | 回复内容 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: topic, user
### BotConfig (Bot配置)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| userId | Int @unique @map("user_id") | 关联User(isBot=true) |
| displayName | String @map("display_name") @db.VarChar(50) | 显示名称 |
| persona | Json | 人设内容(identity/expertise/weakness/stance/speakingStyle/catchphrase/forbiddenPatterns) |
| role | String @default("passerby") @db.VarChar(20) | 角色(expert/passerby) |
| activeHours | Json? @map("active_hours") | 活跃时间段(JSON) |
| primaryForums | Json? @map("primary_forums") | 主要活跃板块(JSON) |
| isActive | Boolean @default(true) @map("is_active") | 是否启用 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: user (一对一), memories, personaVariants, adversarialLearnings, skills, dailyStats, weeklyReviews, crossForumAffinities
### BotMemory (Bot记忆)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| botId | Int @map("bot_id") | 关联BotConfig |
| level | String @db.VarChar(20) | 记忆层级(SESSION/WORKING/LONGTERM) |
| content | String @db.Text | 记忆内容 |
| importance | Float @default(0) | 重要性评分 |
| contextTags | Json? @map("context_tags") | 上下文标签(JSON) |
| ttl | Int? | 存活时间(秒) |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
**关系**: bot
### BotDailyStat (Bot每日统计)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| botId | Int @map("bot_id") | 关联BotConfig |
| date | DateTime @db.Date | 统计日期 |
| topicsCreated | Int @default(0) @map("topics_created") | 创建话题数 |
| postsCreated | Int @default(0) @map("posts_created") | 创建回复数 |
| repliesReceived | Int @default(0) @map("replies_received") | 收到的回复数 |
| likesReceived | Int @default(0) @map("likes_received") | 收到的点赞数 |
| humanInteractions | Int @default(0) @map("human_interactions") | 真人互动数 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
**关系**: bot
**唯一约束**: [botId, date]
### BotSkill (Bot技能结晶)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| botId | Int @map("bot_id") | 关联BotConfig |
| skillName | String @map("skill_name") @db.VarChar(100) | 技能名称 |
| hookTemplate | String @map("hook_template") @db.Text | 钩子模板 |
| bodyTemplate | String @map("body_template") @db.Text | 正文模板 |
| applicabilityNote | String? @map("applicability_note") @db.Text | 适用性说明 |
| sourceTopicId | Int? @map("source_topic_id") | 来源话题ID |
| successRate | Float @default(0) @map("success_rate") | 成功率 |
| usageCount | Int @default(0) @map("usage_count") | 使用次数 |
| isActive | Boolean @default(true) @map("is_active") | 是否启用 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: bot
### BotWeeklyReview (Bot周度复盘)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| botId | Int @map("bot_id") | 关联BotConfig |
| weekKey | String @map("week_key") @db.VarChar(20) | 周标识(2026-W23) |
| topicsCreated | Int @default(0) @map("topics_created") | 本周话题数 |
| postsCreated | Int @default(0) @map("posts_created") | 本周回复数 |
| likesReceived | Int @default(0) @map("likes_received") | 本周点赞数 |
| humanRatio | Float @default(0) @map("human_ratio") | 真人互动比例 |
| engagementScore | Float @default(0) @map("engagement_score") | 参与度分数 |
| nextWeekQuota | Json? @map("next_week_quota") | 下周配额(JSON) |
| reflection | String? @db.Text | LLM反思 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
**关系**: bot
**唯一约束**: [botId, weekKey]
### BotPersona (Bot风格画像)
| 字段 | 类型 | 说明 |
|------|------|------|
| botId | Int @id @map("bot_id") | 关联BotConfig(主键) |
| avgReplyLength | Float @default(0) @map("avg_reply_length") | 平均回复长度 |
| questionRatio | Float @default(0) @map("question_ratio") | 问句比例 |
| exclamationCount | Int @default(0) @map("exclamation_count") | 感叹号数量 |
| stanceKeywords | Json? @map("stance_keywords") | 立场关键词(JSON) |
| topHumanUsers | Json? @map("top_human_users") | 主要互动真人用户(JSON) |
| topTopicTypes | Json? @map("top_topic_types") | 热门话题类型(JSON) |
| lastTopicTitles | Json? @map("last_topic_titles") | 最近话题标题(JSON) |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: bot (一对一)
### BotPersonaVariant (A/B变体)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| botId | Int @map("bot_id") | 关联BotConfig |
| variantKey | String @map("variant_key") @db.VarChar(30) | 变体标识(control/variant_a/variant_b) |
| label | String @db.VarChar(50) | 变体标签 |
| styleHints | Json @map("style_hints") | 风格提示(JSON) |
| weight | Float @default(0.33) | 分流权重 |
| 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") | 综合参与度分 |
**关系**: bot
**唯一约束**: [botId, variantKey]
### BotPersonaExperiment (A/B实验)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| botId | Int @map("bot_id") | 关联BotConfig |
| name | String @db.VarChar(100) | 实验名称 |
| status | String @default("active") @db.VarChar(20) | 状态(active/completed) |
| winnerVariantKey | String? @map("winner_variant_key") @db.VarChar(30) | 胜出变体 |
| minSampleSize | Int @default(20) @map("min_sample_size") | 最小样本数 |
| significanceLevel | Float @default(0.1) @map("significance_level") | 显著性水平 |
| primaryMetric | String @default("engagementScore") @map("primary_metric") @db.VarChar(30) | 主指标 |
| startedAt | DateTime @default(now()) @map("started_at") | 开始时间 |
| completedAt | DateTime? @map("completed_at") | 完成时间 |
**关系**: bot
### BotPersonaAssignment (A/B分配记录)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| variantId | Int @map("variant_id") | 关联变体 |
| refType | String @map("ref_type") @db.VarChar(20) | 引用类型(topic/post) |
| refId | Int @map("ref_id") | 引用ID |
| replyCount | Int @default(0) @map("reply_count") | 收到回复数 |
| likeCount | Int @default(0) @map("like_count") | 收到点赞数 |
| humanReplyCount | Int @default(0) @map("human_reply_count") | 真人回复数 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
**关系**: variant
**唯一约束**: [refType, refId]
### BotPersonaMetric (A/B指标聚合)
| 字段 | 类型 | 说明 |
|------|------|------|
| 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") | 内容数量 |
| score | Float @default(0) | 综合评分 |
**关系**: variant
**唯一约束**: [variantId, date]
### BotAdversarialLearning (对抗学习)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| botId | Int @map("bot_id") | 关联BotConfig |
| weekKey | String @map("week_key") @db.VarChar(20) | 周标识 |
| sourceRefType | String @map("source_ref_type") @db.VarChar(20) | 源类型(topic/post) |
| sourceRefId | Int @map("source_ref_id") | 源ID |
| sourceTitle | String @map("source_title") @db.VarChar(200) | 源标题 |
| sourceContent | String @map("source_content") @db.Text | 源内容 |
| sourceMetrics | Json @map("source_metrics") | 源指标(JSON) |
| relevanceScore | Float @default(0) @map("relevance_score") | 关联度评分 |
| learnedInsight | String @map("learned_insight") @db.Text | LLM提取的洞察 |
| learnCategories | Json? @map("learn_categories") | 学习分类(JSON) |
| status | String @default("active") @db.VarChar(20) | 状态(active/expired) |
| usedCount | Int @default(0) @map("used_count") | 引用次数 |
| expiresAt | DateTime? @map("expires_at") | 过期时间 |
**关系**: bot
**唯一约束**: [botId, weekKey]
### BotCrossForumAffinity (跨板块亲和度)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| botId | Int @map("bot_id") | 关联BotConfig |
| forumSlug | String @map("forum_slug") @db.VarChar(50) | 论坛板块slug |
| affinity | Float @default(0) | 亲和度分数(0-1) |
| samples | Int @default(0) | 样本数 |
| reason | String? @db.VarChar(255) | 原因说明 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: bot
**唯一约束**: [botId, forumSlug]
---
## 枚举
### PricingModel (定价模型)
- `free` — 免费
- `freemium` — 免费增值
- `paid` — 付费
- `subscription` — 订阅制
### Status (状态)
- `draft` — 草稿
- `published` — 已发布
### PendingStatus (待审核状态)
- `pending` — 待审核
- `approved` — 已通过
- `rejected` — 已拒绝
### ReviewStatus (评测状态)
- `DRAFT` — 草稿
- `PUBLISHED` — 已发布
- `REJECTED` — 已拒绝
- `OUTDATED` — 已过期
### UserLevel (用户等级)
- `BRONZE` — 青铜
- `SILVER` — 白银
- `GOLD` — 黄金
- `PLATINUM` — 铂金
### CommentStatus (评论状态)
- `ACTIVE` — 活跃
- `HIDDEN` — 隐藏
- `DELETED` — 已删除
### NotifType (通知类型)
- `COMMENT_REPLY` — 评论回复
- `COMMENT_LIKE` — 评论点赞
- `TOPIC_REPLY` — 话题回复
- `SYSTEM` — 系统通知
## 索引
| 模型 | 索引 | 类型 |
|------|------|------|
| Tool | [categoryId, status] | 联合索引 |
| Tool | [name, description] | 全文索引 |
| Skill | [categoryId, status] | 联合索引 |
| SkillReview | [skillId] | 唯一索引 |
| SkillReview | [overall] | 普通索引 |
| ReviewGenerationLog | [skillId] | 普通索引 |
| TaskLog | [taskKey, startedAt] | 联合索引 |
| TaskConfig | [taskKey] | 唯一索引 |
| Favorite | [userId] | 普通索引 |
| BrowsingHistory | [userId, viewedAt] | 联合索引 |
| Collection | [userId] | 普通索引 |
| DailyReport | [date] | 唯一索引 |
| DailyReport | [status] | 普通索引 |
| DailyReportItem | [reportId, sortOrder] | 联合索引 |
| Comment | [toolId, createdAt] | 联合索引 |
| Comment | [skillId, createdAt] | 联合索引 |
| Comment | [userId] | 普通索引 |
| Notification | [userId, isRead, createdAt] | 联合索引 |
| ForumTopic | [categoryId, lastReplyAt] | 联合索引 |
| ForumTopic | [userId] | 普通索引 |
| ForumTopic | [title] | 全文索引 |
| ForumPost | [topicId, createdAt] | 联合索引 |
| Permission | [groupName, sortOrder] | 联合索引 |
| User | [oauthProvider, oauthId] | 联合唯一 |
| BotConfig | [userId] | 唯一索引 |
| BotDailyStat | [botId, date] | 唯一索引 |
| BotWeeklyReview | [botId, weekKey] | 唯一索引 |
| BotPersona | [botId] | 主键索引 |
| BotPersonaVariant | [botId, variantKey] | 唯一索引 |
| BotPersonaAssignment | [refType, refId] | 唯一索引 |
| BotPersonaMetric | [variantId, date] | 唯一索引 |
| BotAdversarialLearning | [botId, weekKey] | 唯一索引 |
| BotCrossForumAffinity | [botId, forumSlug] | 唯一索引 |
## 迁移历史
| # | 迁移名 | 日期 | 说明 |
|---|--------|------|------|
| 1 | init | 2026-04-28 | 初始化核心表(Category/Tool/PendingTool/SystemConfig/User) |
| 2 | remove_scraped_at | 2026-05-01 | 移除scrapedAt字段 |
| 3 | add_discovery_configs | 2026-05-01 | 添加发现配置 |
| 4 | fix_tag_pool_column | 2026-05-01 | 修复标签池列 |
| 5 | add_discovery_configs_v2 | 2026-05-02 | 发现配置V2 |
| 6 | add_api_providers_and_skills | 2026-05-02 | 添加API提供者和技能(Skill/PendingSkill) |
| 7 | add_skill_categories | 2026-05-02 | 添加技能分类(SkillCategory) |
| 8 | add_pendingtool_category_relation | 2026-05-02 | 添加PendingTool分类关联 |
| 9 | add_hot_score | 2026-05-08 | 添加热度评分(DailyReportItem.hotScore) |
| 10 | add_skill_reviews | 2026-05-20 | 添加技能评测表+Skill扩展字段 |
| 11 | add_task_system | 2026-05-24 | 添加任务调度系统+权限体系+社区功能 |
| 12 | add_bot_system | 2026-06-07 | 添加数字人Bot系统(12张表: BotConfig/BotMemory/BotDailyStat/BotSkill/BotWeeklyReview/BotPersona/BotPersonaVariant/BotPersonaExperiment/BotPersonaAssignment/BotPersonaMetric/BotAdversarialLearning/BotCrossForumAffinity) |
---
## 开发规则引用
> 数据模型变更必须遵守 [开发规则第十六章 - 数据模型与迁移规范](file:///c:/SGP_KF/ZhuiGuangAI/zhuiguang-ai/.trae/rules/project_rules.md):
> - Prisma 命名约定:模型PascalCase→`@@map("snake_case")`,字段camelCase→`@map("snake_case")`
> - 连接单例模式:`globalForPrisma` 防止热重载多实例
> - Schema 变更流程:migrate dev → migrate status → migrate deploy(严禁DROP/TRUNCATE)
> - 数据库隔离:仅操作 `zhuiguang_ai` 库