@allbluecn/database 0.4.14 → 0.4.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/generated/enums.ts +2 -2
- package/generated/internal/class.ts +1 -1
- package/generated-sqlite/browser.ts +0 -10
- package/generated-sqlite/client.ts +0 -10
- package/generated-sqlite/internal/class.ts +4 -24
- package/generated-sqlite/internal/prismaNamespace.ts +2 -180
- package/generated-sqlite/internal/prismaNamespaceBrowser.ts +1 -29
- package/generated-sqlite/models/User.ts +101 -1067
- package/generated-sqlite/models.ts +0 -2
- package/migrations/20260830000000_story_dependency_plane_align/migration.sql +37 -0
- package/package.json +2 -2
- package/schema.prisma +2 -2
- package/generated-sqlite/models/Notification.ts +0 -1482
- package/generated-sqlite/models/NotificationPreference.ts +0 -1287
package/generated/enums.ts
CHANGED
|
@@ -65,8 +65,8 @@ export type ShareStatus = (typeof ShareStatus)[keyof typeof ShareStatus]
|
|
|
65
65
|
|
|
66
66
|
export const DependencyType = {
|
|
67
67
|
BLOCKS: 'BLOCKS',
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
STARTS_BEFORE: 'STARTS_BEFORE',
|
|
69
|
+
FINISHES_BEFORE: 'FINISHES_BEFORE'
|
|
70
70
|
} as const
|
|
71
71
|
|
|
72
72
|
export type DependencyType = (typeof DependencyType)[keyof typeof DependencyType]
|
|
@@ -20,7 +20,7 @@ const config: runtime.GetPrismaClientConfig = {
|
|
|
20
20
|
"clientVersion": "7.8.0",
|
|
21
21
|
"engineVersion": "3c6e192761c0362d496ed980de936e2f3cebcd3a",
|
|
22
22
|
"activeProvider": "postgresql",
|
|
23
|
-
"inlineSchema": "generator client {\n provider = \"prisma-client\"\n output = \"./generated\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n}\n\n// 系统配置表\nmodel SystemSetting {\n id String @id @default(cuid())\n key String @unique\n value String @db.Text\n category String @default(\"general\") // 配置分类\n desc String? // 说明\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@index([category])\n @@map(\"system_settings\")\n}\n\n// 用户表\nmodel User {\n id String @id @default(cuid())\n email String @unique\n username String @unique\n password String\n emailVerified DateTime?\n image String?\n role Role @default(USER)\n status UserStatus @default(ACTIVE)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n lastLoginAt DateTime?\n\n accounts Account[]\n\n avatarConfig Json?\n bgShape String?\n bgColor String?\n\n aiProvider String? // \"openrouter\" | \"openai\"\n aiApiKey String? // 用户 AI API Key(TODO: 加密存储)\n aiModel String? // 默认 \"openai/gpt-4o-mini\"\n locale String? // 用户语言偏好(zh / en),null 表示未设置\n\n storyDisplayOptions Json? // Story Display Options 个人偏好(URL 无参数时的默认值,跨设备持久化)\n\n sketchApiToken String?\n timezone String? // 用户全局时区,如 \"Asia/Shanghai\"。null = 浏览器时区\n\n /// 用户偏好的计费币种(子项目 3 新增)\n preferredCurrency String @default(\"usd\")\n\n /// 用户默认 workspace ID(B3 精确化:多 workspace 用户权益判定确定性)\n defaultWorkspaceId String?\n\n invitationUses InvitationUse[]\n loginLogs LoginLog[]\n passwordResetTokens PasswordResetToken[]\n prds PRD[]\n tags Tag[]\n knowledgeBases KnowledgeBase[]\n knowledgeDocuments KnowledgeDocument[]\n knowledgeShares KnowledgeShareRecord[]\n legalRegulations LegalRegulation[]\n industryCompliances IndustryCompliance[]\n dictionaryTerms DictionaryTerm[]\n websiteBookmarks WebsiteBookmark[]\n bookmarkCategories BookmarkCategory[]\n articleFavorites ArticleFavorite[]\n anyhubApps AnyHubApp[]\n anyhubMarketApps AnyHubMarketApp[]\n reviewedAnyhubRecommendations AnyHubRecommendation[] @relation(\"reviewedAnyhubRecommendations\")\n anyhubRecommenders AnyHubRecommender[]\n prdVersions PRDVersion[]\n reviewComments ReviewComment[]\n comments Comment[]\n commentIgnores CommentIgnore[]\n reviews Review[] @relation(\"reviewer\")\n designProjects DesignProject[]\n storiesCreated Story[] @relation(\"storyCreator\")\n storiesAssigned Story[] @relation(\"storyAssignee\")\n storiesEdited Story[] @relation(\"storyEditor\")\n labelsCreated Label[] @relation(\"labelCreator\")\n storyActivities StoryActivity[] @relation(\"storyActivityUser\")\n storyComments StoryComment[] @relation(\"storyCommentUser\")\n storyReactions StoryReaction[] @relation(\"storyReactionUser\")\n commentReactions CommentReaction[] @relation(\"commentReactionUser\")\n storyFilterViews StoryFilterView[]\n chatThreads ChatThread[]\n aiProviderConfigs AiProviderConfig[]\n agentConversations AgentConversation[]\n ownedProjects Project[] @relation(\"projectOwner\")\n projectMemberships ProjectMember[]\n projectActivities ProjectActivity[]\n ownedWorkspaces Workspace[] @relation(\"workspaceOwner\")\n workspaceMemberships TeamMembership[] @relation(\"teamOwner\")\n teamJoined TeamMembership? @relation(\"teamMember\")\n sentInvitations TeamInvitation[] @relation(\"invitationOwner\")\n ownedJoinRequests TeamJoinRequest[] @relation(\"joinRequestOwner\")\n applicantJoinRequests TeamJoinRequest[] @relation(\"joinRequestApplicant\")\n aiUsageLogs AiUsageLog[]\n agents UserAgent[]\n skills UserSkill[]\n notifications Notification[]\n notificationPreference NotificationPreference?\n\n issuedLicenses LicenseKey[] @relation(\"LicenseIssuer\")\n ssoMappings SsoMapping[]\n roleAssignments RoleAssignment[]\n subscription Subscription?\n\n @@map(\"users\")\n}\n\n// OAuth 账号关联\nmodel Account {\n id String @id @default(cuid())\n userId String\n type String\n provider String\n providerAccountId String\n refresh_token String? @db.Text\n access_token String? @db.Text\n expires_at Int?\n token_type String?\n scope String?\n id_token String? @db.Text\n session_state String?\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@unique([provider, providerAccountId])\n @@index([userId])\n @@map(\"accounts\")\n}\n\n// 项目\nmodel Project {\n id String @id @default(cuid())\n displayId String? // 用户层项目ID,全大写字母数字,1-10位\n name String\n description String?\n icon String @default(\"folder\")\n timezone String? // 项目时区,null = 跟随用户全局时区\n ownerId String\n owner User @relation(\"projectOwner\", fields: [ownerId], references: [id])\n workspaceId String?\n workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: SetNull)\n members ProjectMember[]\n activities ProjectActivity[]\n stories Story[]\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@unique([ownerId, displayId])\n @@index([ownerId])\n @@index([workspaceId])\n @@map(\"projects\")\n}\n\n// 项目成员\nmodel ProjectMember {\n id String @id @default(cuid())\n projectId String\n project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)\n userId String\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n role String @default(\"member\") // owner | admin | member | viewer\n status String @default(\"active\") // active | invited | suspended\n joinedAt DateTime @default(now())\n\n @@unique([projectId, userId])\n @@index([projectId])\n @@map(\"project_members\")\n}\n\n// 工作空间(项目的上一级容器)\nmodel Workspace {\n id String @id @default(cuid())\n name String\n icon String @default(\"folder\")\n description String?\n ownerId String\n owner User @relation(\"workspaceOwner\", fields: [ownerId], references: [id])\n projects Project[]\n usageRecords UsageRecord[]\n aiUsageLogs AiUsageLog[]\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n ssoProviders SsoProvider[]\n customRoles CustomRole[]\n auditLogs AuditLog[]\n\n @@index([ownerId])\n @@map(\"workspaces\")\n}\n\n// 团队隶属关系\nmodel TeamMembership {\n id String @id @default(cuid())\n ownerId String\n owner User @relation(\"teamOwner\", fields: [ownerId], references: [id], onDelete: Cascade)\n memberId String\n member User @relation(\"teamMember\", fields: [memberId], references: [id], onDelete: Cascade)\n seatType String @default(\"member\")\n joinedAt DateTime @default(now())\n\n @@unique([memberId])\n @@index([ownerId])\n @@map(\"team_memberships\")\n}\n\n// 团队邀请\nmodel TeamInvitation {\n id String @id @default(cuid())\n ownerId String\n owner User @relation(\"invitationOwner\", fields: [ownerId], references: [id], onDelete: Cascade)\n email String?\n seatType String @default(\"member\")\n token String @unique\n channel String @default(\"email\")\n status String @default(\"pending\")\n expiresAt DateTime\n createdAt DateTime @default(now())\n acceptedBy String?\n applicantEmail String?\n message String?\n joinRequests TeamJoinRequest[]\n\n @@unique([ownerId, email])\n @@index([ownerId])\n @@index([email])\n @@map(\"team_invitations\")\n}\n\n// 用户加入团队申请(链接渠道,与 TeamInvitation 分离:一条链接可承载多个申请)\nmodel TeamJoinRequest {\n id String @id @default(cuid())\n invitationId String\n invitation TeamInvitation @relation(fields: [invitationId], references: [id], onDelete: Cascade)\n ownerId String\n owner User @relation(\"joinRequestOwner\", fields: [ownerId], references: [id], onDelete: Cascade)\n userId String?\n applicant User? @relation(\"joinRequestApplicant\", fields: [userId], references: [id], onDelete: SetNull)\n email String\n status String @default(\"pending\")\n seatType String @default(\"member\")\n createdAt DateTime @default(now())\n processedAt DateTime?\n\n @@unique([invitationId, email])\n @@index([ownerId, status])\n @@map(\"team_join_requests\")\n}\n\n// 项目活动记录\nmodel ProjectActivity {\n id String @id @default(cuid())\n projectId String\n project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)\n userId String\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n action String // created | updated | deleted | member_invited | member_joined | member_removed | role_changed | module_viewed\n targetType String? // project | member | requirement | prd | design | testcase | bug | acceptance\n targetId String?\n metadata Json?\n createdAt DateTime @default(now())\n\n @@index([projectId, createdAt])\n @@map(\"project_activities\")\n}\n\n// 对话线程(作为 TanStack AI persistence threadId)\nmodel ChatThread {\n id String @id @default(cuid())\n userId String\n title String?\n isArchived Boolean @default(false)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n messages ChatMessage[]\n runs ChatRun[]\n interrupts ChatInterrupt[]\n generations GenerationRun[]\n agentId String?\n agent UserAgent? @relation(fields: [agentId], references: [id])\n\n @@index([userId, updatedAt])\n @@map(\"chat_threads\")\n}\n\n// 对话消息(TanStack AI messages store)\nmodel ChatMessage {\n id String @id @default(cuid())\n threadId String\n role String // \"user\" | \"assistant\" | \"tool\"\n content String @db.Text\n parts Json?\n thinking String? @db.Text\n citations Json?\n createdAt DateTime @default(now())\n\n thread ChatThread @relation(fields: [threadId], references: [id], onDelete: Cascade)\n\n @@index([threadId, createdAt])\n @@map(\"chat_messages\")\n}\n\n// 运行记录(TanStack AI runs store)\nmodel ChatRun {\n id String @id @default(cuid())\n threadId String\n userId String\n status String // running | completed | failed | aborted | interrupted\n startedAt DateTime @default(now())\n finishedAt DateTime?\n detachedSince DateTime?\n usage Json?\n error String? @db.Text\n\n thread ChatThread @relation(fields: [threadId], references: [id], onDelete: Cascade)\n interrupts ChatInterrupt[]\n\n @@index([threadId, startedAt])\n @@index([userId, status])\n @@map(\"chat_runs\")\n}\n\n// 中断记录(TanStack AI interrupts store)\nmodel ChatInterrupt {\n id String @id @default(cuid())\n runId String\n threadId String\n userId String\n kind String // tool-approval | generic\n toolName String?\n state String // pending | resolved | cancelled\n payload Json?\n resolution Json?\n createdAt DateTime @default(now())\n resolvedAt DateTime?\n\n run ChatRun @relation(fields: [runId], references: [id], onDelete: Cascade)\n thread ChatThread @relation(fields: [threadId], references: [id], onDelete: Cascade)\n\n @@index([runId])\n @@index([threadId, state])\n @@map(\"chat_interrupts\")\n}\n\n// 媒体生成记录(占位,本轮建表不接入业务)\nmodel GenerationRun {\n id String @id @default(cuid())\n threadId String\n userId String\n kind String // image | video | speech | transcription\n status String // running | completed | failed | interrupted\n input Json?\n result Json?\n artifactId String?\n error String? @db.Text\n startedAt DateTime @default(now())\n finishedAt DateTime?\n\n thread ChatThread @relation(fields: [threadId], references: [id], onDelete: Cascade)\n\n @@index([threadId, startedAt])\n @@index([userId, status])\n @@map(\"generation_runs\")\n}\n\n// 登录日志\nmodel LoginLog {\n id String @id @default(cuid())\n userId String\n ip String?\n userAgent String?\n location String? // 地理位置,如 \"北京, 中国\";开发环境为 \"本地\"\n success Boolean @default(true)\n message String? // 失败原因(中文),成功时为 null\n createdAt DateTime @default(now())\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@map(\"login_logs\")\n}\n\n// 邀请码\nmodel InvitationCode {\n id String @id @default(cuid())\n code String @unique\n maxUses Int @default(1)\n usedCount Int @default(0)\n expiresAt DateTime\n createdAt DateTime @default(now())\n\n uses InvitationUse[]\n\n @@map(\"invitation_codes\")\n}\n\n// 邀请码使用记录\nmodel InvitationUse {\n id String @id @default(cuid())\n codeId String\n userId String\n usedAt DateTime @default(now())\n\n code InvitationCode @relation(fields: [codeId], references: [id], onDelete: Cascade)\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@map(\"invitation_uses\")\n}\n\n// 密码重置令牌\nmodel PasswordResetToken {\n id String @id @default(cuid())\n token String @unique\n userId String\n expiresAt DateTime\n usedAt DateTime?\n createdAt DateTime @default(now())\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@map(\"password_reset_tokens\")\n}\n\nenum Role {\n SUPER_ADMIN\n ADMIN\n USER\n GUEST\n}\n\nenum UserStatus {\n ACTIVE\n INACTIVE\n BANNED\n}\n\nenum IconType {\n IMAGE\n ICON\n}\n\nenum MarketplaceAppStatus {\n DRAFT\n PUBLISHED\n UNPUBLISHED\n}\n\nenum ReviewStatus {\n PENDING\n APPROVED\n REJECTED\n}\n\nenum ShareStatus {\n ACTIVE\n EXPIRED\n DISABLED\n}\n\n// 知识库\nmodel KnowledgeBase {\n id String @id @default(cuid())\n name String\n description String? @db.Text\n icon String @default(\"notebook\")\n tags Json @default(\"[]\")\n visibility String @default(\"private\")\n userId String\n isDeleted Boolean @default(false)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n documents KnowledgeDocument[]\n\n @@index([userId])\n @@map(\"knowledge_bases\")\n}\n\nmodel KnowledgeDocument {\n id String @id @default(cuid())\n kbId String\n parentId String?\n title String\n type String @default(\"doc\")\n content Json @default(\"{}\")\n icon String?\n isHomepage Boolean @default(false)\n sortOrder Int @default(0)\n isDeleted Boolean @default(false)\n createdBy String\n tags Json @default(\"[]\")\n properties Json @default(\"{}\")\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n kb KnowledgeBase @relation(fields: [kbId], references: [id], onDelete: Cascade)\n parent KnowledgeDocument? @relation(\"DocumentTree\", fields: [parentId], references: [id], onDelete: SetNull)\n children KnowledgeDocument[] @relation(\"DocumentTree\")\n creator User @relation(fields: [createdBy], references: [id], onDelete: Cascade)\n linkedStories StoryDocLink[] @relation(\"DocStoryLinks\")\n\n @@index([kbId])\n @@index([parentId])\n @@index([kbId, isHomepage])\n @@map(\"knowledge_documents\")\n}\n\n// PRD 文档表\nmodel PRD {\n id String @id @default(cuid())\n icon String @default(\"file\") // 图标名称\n name String // PRD 名称\n description String? // 介绍\n settings Json? // 文档设置(布局、主题等)\n userId String // 所属用户\n isDeleted Boolean @default(false)\n deletedAt DateTime?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n pages PRDPage[]\n versions PRDVersion[]\n reviews Review[]\n comments Comment[]\n shares Share[]\n prdTags PRDTag[]\n agentConversations AgentConversation[]\n linkedStories StoryPrdLink[] @relation(\"PrdStoryLinks\")\n\n @@index([userId])\n @@map(\"prds\")\n}\n\n// Agent 原型生成会话\nmodel AgentConversation {\n id String @id @default(cuid())\n userId String\n prdId String\n title String @default(\"新会话\")\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)\n messages AgentMessage[]\n\n @@index([userId, prdId])\n @@map(\"agent_conversations\")\n}\n\n// Agent 会话消息\nmodel AgentMessage {\n id String @id @default(cuid())\n conversationId String\n role String // \"user\" | \"assistant\"\n content String // 消息文本\n components Json? // AI 生成的组件数据(assistant 消息)\n isError Boolean @default(false)\n createdAt DateTime @default(now())\n\n conversation AgentConversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)\n\n @@index([conversationId])\n @@map(\"agent_messages\")\n}\n\n// 基础组件表(后台维护)\nmodel Component {\n id String @id @default(cuid())\n name String\n description String? // 组件描述\n type String // \"component\" | \"block\" | \"template\"\n category String? // 分类\n subCategory String? // 子分类\n path String? // 树形分组路径(如 \"基础组件/表单/输入框\")\n defaultWidth Int @default(200)\n defaultHeight Int @default(40)\n prototypeKey String? // unique key for registry lookup (e.g. \"text\", \"button\")\n config Json // 属性描述 schema(props定义、slots、events)\n defaultProps Json? // 默认属性值\n defaultStyle Json? // 默认样式\n preview String? // 预览图URL\n version Int @default(1)\n sortOrder Int @default(0) // 排序权重(越大越前)\n source String @default(\"manual\") // \"npm\" | \"file\" | \"manual\"\n sourceId String? // npm 包名 / 文件名\n isHidden Boolean @default(false) // 隐藏/显示\n isDeleted Boolean @default(false)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n blockItems BlockComponent[] @relation(\"componentRef\")\n instances ComponentInstance[] @relation(\"componentRef\")\n componentTags ComponentTag[]\n tags String[] @default([])\n\n @@index([type, category])\n @@index([isDeleted])\n @@index([isHidden])\n @@index([sortOrder])\n @@map(\"components\")\n}\n\n// 区块定义表(后台维护)\nmodel Block {\n id String @id @default(cuid())\n name String\n description String?\n category String?\n isDeleted Boolean @default(false)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n items BlockComponent[]\n instances BlockInstance[] @relation(\"blockRef\")\n templateItems TemplateBlock[] @relation(\"templateBlockRef\")\n\n @@index([isDeleted])\n @@map(\"blocks\")\n}\n\n// 区块内组件布局\nmodel BlockComponent {\n id String @id @default(cuid())\n blockId String\n componentId String\n x Float @default(0)\n y Float @default(0)\n width Float @default(100)\n height Float @default(100)\n zIndex Int @default(0)\n propsOverride Json? // 局部覆写属性\n styleOverride Json? // 局部覆写样式\n\n block Block @relation(fields: [blockId], references: [id], onDelete: Cascade)\n component Component @relation(\"componentRef\", fields: [componentId], references: [id])\n\n @@map(\"block_components\")\n}\n\n// 模板定义表(后台维护)\nmodel Template {\n id String @id @default(cuid())\n name String\n description String?\n category String?\n isDeleted Boolean @default(false)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n items TemplateBlock[]\n\n @@index([isDeleted])\n @@map(\"templates\")\n}\n\n// 模板内区块排布\nmodel TemplateBlock {\n id String @id @default(cuid())\n templateId String\n blockId String\n order Int @default(0) // 排布顺序\n x Float? @default(0)\n y Float? @default(0)\n width Float?\n height Float?\n\n template Template @relation(fields: [templateId], references: [id], onDelete: Cascade)\n block Block @relation(\"templateBlockRef\", fields: [blockId], references: [id])\n\n @@map(\"template_blocks\")\n}\n\n// PRD 页面/目录树节点\nmodel PRDPage {\n id String @id @default(cuid())\n prdId String\n parentId String? // 父节点,构建树形结构(null = 根级)\n name String\n order Int @default(0) // 排序\n type String @default(\"page\") // \"page\" | \"folder\"\n canvas Json? // 原型画板数据\n content Json? // PRD 文档内容\n version Int @default(1) // 页面版本号\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)\n parent PRDPage? @relation(\"PageHierarchy\", fields: [parentId], references: [id], onDelete: Cascade)\n children PRDPage[] @relation(\"PageHierarchy\")\n componentInstances ComponentInstance[]\n blockInstances BlockInstance[]\n pageVersions PageVersion[]\n\n @@index([prdId, order])\n @@map(\"prd_pages\")\n}\n\n// 组件实例(画布上)\nmodel ComponentInstance {\n id String @id @default(cuid())\n pageId String\n componentId String? // null = 已解绑的游离副本\n blockInstanceId String? // 所属区块实例\n name String? // 实例别名\n x Float @default(0)\n y Float @default(0)\n width Float @default(100)\n height Float @default(100)\n zIndex Int @default(0)\n props Json? // 局部覆写属性\n style Json? // 局部覆写样式\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n page PRDPage @relation(fields: [pageId], references: [id], onDelete: Cascade)\n component Component? @relation(\"componentRef\", fields: [componentId], references: [id])\n blockInstance BlockInstance? @relation(fields: [blockInstanceId], references: [id])\n\n @@index([pageId])\n @@map(\"component_instances\")\n}\n\n// 区块实例(画布上)\nmodel BlockInstance {\n id String @id @default(cuid())\n pageId String\n blockId String? // null = 已解绑的游离副本\n name String? // 实例别名\n x Float @default(0)\n y Float @default(0)\n width Float @default(400)\n height Float @default(300)\n zIndex Int @default(0)\n props Json? // 局部覆写属性\n style Json? // 局部覆写样式\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n page PRDPage @relation(fields: [pageId], references: [id], onDelete: Cascade)\n block Block? @relation(\"blockRef\", fields: [blockId], references: [id])\n instances ComponentInstance[]\n\n @@index([pageId])\n @@map(\"block_instances\")\n}\n\n// PRD 版本(手动发布创建)\nmodel PRDVersion {\n id String @id @default(cuid())\n prdId String\n major Int @default(1)\n minor Int @default(0)\n patch Int @default(0)\n versionLabel String // 如 \"v1\", \"v1.1\", \"v1.1.1\"\n parentVersion String? // 上一版本ID(版本链)\n pageVersions Json // [{ pageId, pageName, version, canvas, content }]\n notes String? // 发版说明\n userId String\n createdAt DateTime @default(now())\n updatedAt DateTime?\n\n prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)\n user User @relation(fields: [userId], references: [id])\n reviews Review[]\n shareVersions ShareVersion[]\n\n @@index([prdId, createdAt])\n @@index([userId])\n @@map(\"prd_versions\")\n}\n\n// 页面版本(独立的页面级别版本历史)\nmodel PageVersion {\n id String @id @default(cuid())\n pageId String\n version Int // 整数版本号,自增\n notes String? // 版本说明(用户可编辑)\n canvas Json? // 原型快照\n content Json? // 文档快照\n restoredFromVersion Int? // 从哪个版本号还原而来(null 表示非还原版本)\n fromPRDVersionId String? // 来源:从哪个 PRD 版本创建(可选标记)\n createdAt DateTime @default(now())\n\n page PRDPage @relation(fields: [pageId], references: [id], onDelete: Cascade)\n\n @@index([pageId, createdAt])\n @@index([pageId, version])\n @@map(\"page_versions\")\n}\n\n// 评审工作流\nmodel Review {\n id String @id @default(cuid())\n prdId String\n versionId String\n status ReviewStatus @default(PENDING)\n reviewerId String?\n notes String?\n createdAt DateTime @default(now())\n completedAt DateTime?\n\n prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)\n version PRDVersion @relation(fields: [versionId], references: [id])\n reviewer User? @relation(\"reviewer\", fields: [reviewerId], references: [id])\n comments ReviewComment[]\n\n @@unique([prdId, versionId])\n @@index([prdId])\n @@index([versionId])\n @@index([reviewerId])\n @@map(\"reviews\")\n}\n\n// 评审留言\nmodel ReviewComment {\n id String @id @default(cuid())\n reviewId String\n userId String\n content String @db.Text\n pageId String? // 关联页面\n elementId String? // 关联具体元素\n parentId String? // 回复上级留言\n createdAt DateTime @default(now())\n\n review Review @relation(fields: [reviewId], references: [id], onDelete: Cascade)\n user User @relation(fields: [userId], references: [id])\n parent ReviewComment? @relation(\"ReviewCommentReplies\", fields: [parentId], references: [id])\n replies ReviewComment[] @relation(\"ReviewCommentReplies\")\n\n @@index([reviewId])\n @@index([userId])\n @@index([parentId])\n @@map(\"review_comments\")\n}\n\n// 评论(PRD 级别 / 页面级别 / 元素级别)\nmodel Comment {\n id String @id @default(cuid())\n prdId String\n pageId String? // 可选:针对某页面\n elementId String? // 可选:针对某元素(组件/区块实例ID)\n userId String\n content String @db.Text\n parentId String? // 回复上级评论\n position Json? // 文本选区位置 { from: number, to: number }\n resolved Boolean @default(false)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)\n user User @relation(fields: [userId], references: [id])\n parent Comment? @relation(\"CommentReplies\", fields: [parentId], references: [id])\n replies Comment[] @relation(\"CommentReplies\")\n ignores CommentIgnore[]\n\n @@index([prdId])\n @@index([userId])\n @@index([parentId])\n @@index([pageId])\n @@map(\"comments\")\n}\n\nmodel CommentIgnore {\n id String @id @default(cuid())\n userId String\n commentId String\n createdAt DateTime @default(now())\n\n user User @relation(fields: [userId], references: [id])\n comment Comment @relation(fields: [commentId], references: [id])\n\n @@unique([userId, commentId])\n @@index([userId])\n @@index([commentId])\n @@map(\"comment_ignores\")\n}\n\n// 分享链接\nmodel Share {\n id String @id @default(cuid())\n prdId String\n token String @unique\n type String @default(\"prd\") // \"prd\" | 预留扩展\n status ShareStatus @default(ACTIVE)\n password String? // 加密分享密码(4位,数字+大写+小写字母)\n hasPassword Boolean @default(false)\n expiresAt DateTime?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)\n shareVersions ShareVersion[]\n\n @@index([token])\n @@index([prdId, type, status])\n @@index([status])\n @@index([expiresAt])\n @@map(\"shares\")\n}\n\n// 标签表\nmodel Tag {\n id String @id @default(cuid())\n name String\n color Int @default(0)\n sortOrder Int @default(0)\n isHidden Boolean @default(false)\n userId String\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n prdTags PRDTag[]\n\n @@unique([name, userId])\n @@index([sortOrder])\n @@index([userId])\n @@map(\"tags\")\n}\n\n// PRD-标签多对多\nmodel PRDTag {\n id String @id @default(cuid())\n prdId String\n tagId String\n createdAt DateTime @default(now())\n\n prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)\n tag Tag @relation(fields: [tagId], references: [id], onDelete: Cascade)\n\n @@unique([prdId, tagId])\n @@index([prdId])\n @@index([tagId])\n @@map(\"prd_tags\")\n}\n\n// 组件-标签多对多\n// TODO(ComponentTag 重新调整): Tag 已加 userId,ComponentTag 业务待后续调整。\n// DB 端 FK 已 drop(迁移同步);component_tags 表保留,tagId 列 + 唯一约束 (componentId, tagId) 保留;\n// 移除 Prisma 关系以避免与新 Tag 语义冲突。\nmodel ComponentTag {\n id String @id @default(cuid())\n componentId String\n tagId String\n\n component Component @relation(fields: [componentId], references: [id], onDelete: Cascade)\n\n @@unique([componentId, tagId])\n @@map(\"component_tags\")\n}\n\nmodel Reference {\n id String @id @default(uuid())\n sourceModule String\n sourceEntityId String\n targetModule String\n targetEntityId String\n createdAt DateTime @default(now())\n\n @@index([sourceModule, sourceEntityId])\n @@index([targetModule, targetEntityId])\n @@map(\"references\")\n}\n\nmodel ShareVersion {\n id String @id @default(cuid())\n shareId String\n versionId String\n\n share Share @relation(fields: [shareId], references: [id], onDelete: Cascade)\n version PRDVersion @relation(fields: [versionId], references: [id], onDelete: Cascade)\n\n @@unique([shareId, versionId])\n @@index([shareId])\n @@index([versionId])\n @@map(\"share_versions\")\n}\n\n// ========== AnyHub 模型 ==========\n\nmodel AnyHubApp {\n id String @id @default(cuid())\n name String @unique\n displayName String\n description String? @db.Text\n version String @default(\"0.1.0\")\n source String\n url String?\n localPath String?\n proxyBasePath String?\n iconUrl String?\n pinned Boolean @default(false)\n status String @default(\"installing\")\n userId String\n githubUrl String?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n permissions AnyHubPermission[]\n\n @@index([userId])\n @@index([pinned])\n}\n\nmodel AnyHubPermission {\n id String @id @default(cuid())\n appId String\n capability String\n granted Boolean @default(false)\n userId String\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n app AnyHubApp @relation(fields: [appId], references: [id], onDelete: Cascade)\n\n @@unique([appId, capability, userId])\n @@index([appId])\n}\n\nmodel AnyHubMarketApp {\n id String @id @default(cuid())\n name String\n displayName String\n description String? @db.Text\n entryUrl String\n icon String?\n iconType IconType @default(ICON)\n logo String?\n category String?\n tags String? @db.Text\n downloads Int @default(0)\n capabilities Json\n status MarketplaceAppStatus @default(DRAFT)\n publishedAt DateTime?\n userId String\n recommendationId String? @unique\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id])\n recommendation AnyHubRecommendation? @relation(\"anyhubRecommendation\", fields: [recommendationId], references: [id])\n\n @@index([status])\n @@index([category])\n}\n\nmodel AnyHubRecommendation {\n id String @id @default(cuid())\n githubUrl String @unique\n name String?\n displayName String?\n description String? @db.Text\n status String @default(\"pending\")\n reviewedBy String?\n reviewedAt DateTime?\n marketplaceAppId String?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n marketplaceApp AnyHubMarketApp? @relation(\"anyhubRecommendation\")\n reviewer User? @relation(\"reviewedAnyhubRecommendations\", fields: [reviewedBy], references: [id])\n recommenders AnyHubRecommender[]\n\n @@index([status])\n}\n\nmodel AnyHubRecommender {\n id String @id @default(cuid())\n recommendationId String\n userId String\n reason String?\n createdAt DateTime @default(now())\n\n recommendation AnyHubRecommendation @relation(fields: [recommendationId], references: [id], onDelete: Cascade)\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@unique([recommendationId, userId])\n}\n\n// 设计稿\nmodel DesignProject {\n id String @id @default(cuid())\n name String\n documentId String?\n sketchName String?\n version Int @default(1)\n userId String\n user User @relation(fields: [userId], references: [id])\n artboards Artboard[]\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@index([userId])\n @@map(\"design_projects\")\n}\n\nmodel Artboard {\n id String @id @default(cuid())\n projectId String\n project DesignProject @relation(fields: [projectId], references: [id], onDelete: Cascade)\n name String\n pageName String?\n width Int\n height Int\n pngPath String\n svgPath String?\n annotationJson Json?\n layerCount Int?\n sortOrder Int @default(0)\n createdAt DateTime @default(now())\n exports ArtboardExport[]\n\n @@index([projectId])\n @@map(\"design_artboards\")\n}\n\nmodel ArtboardExport {\n id String @id @default(cuid())\n artboardId String\n artboard Artboard @relation(fields: [artboardId], references: [id], onDelete: Cascade)\n layerName String\n layerId String\n scale Int\n format String @default(\"png\")\n filePath String\n width Int\n height Int\n\n @@unique([artboardId, layerId, scale])\n @@map(\"design_artboard_exports\")\n}\n\n// AI 服务商元数据(admin 维护)\nmodel AiProvider {\n id String @id @default(cuid())\n providerId String @unique // 业务标识 \"openai\" \"anthropic\",用于 adapter 路由与 AiProviderConfig 软关联\n displayName String\n brandName String\n description String @db.Text\n category String @default(\"popular\") // recommended|popular|local\n adapterKind String // openai|anthropic|gemini|groq|grok|openrouter|ollama|openai-compatible\n defaultBaseUrl String?\n keyUrl String?\n docsUrl String?\n keyPlaceholder String?\n iconSlug String?\n brandColor String @default(\"#6467F2\")\n badge String? // 卡片角标文案(如「推荐」「热门」「NEW」),admin 可配\n isLocal Boolean @default(false)\n enabled Boolean @default(true) // 平台级开关:停用后未配置用户看不到,已配置用户继续可用\n models Json // AiModelMeta[](admin 可编辑)\n sortOrder Int @default(0)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@map(\"ai_providers\")\n}\n\n// 用户级 AI 服务商配置\nmodel AiProviderConfig {\n id String @id @default(cuid())\n userId String\n providerId String // 业务 providerId,软关联 AiProvider.providerId(不设外键 cascade,避免 admin 删除丢失用户配置)\n apiKey String? @db.Text // 加密存储 TODO\n baseUrl String?\n enabled Boolean @default(false) // 用户级开关:是否在对话模型选择器中暴露\n models Json? // string[] 用户启用的模型 ID(有序,顺序 = 模型选择器展示顺序)\n customModels Json? // AiModelMeta[] 用户私有的自定义/刷新获取的模型元数据,与 AiProvider.models 取并集按 id 去重\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@unique([userId, providerId])\n @@index([userId])\n @@index([providerId])\n @@map(\"ai_provider_configs\")\n}\n\n// 第三方依赖版本管理(admin 决策是否升级)\n// currentVersion 实时读 monorepo 各 package.json,不存 DB;latestVersion 缓存自 npm registry\nmodel ThirdPartyDependency {\n id String @id @default(cuid())\n name String @unique // npm 包名,如 \"@tiptap/core\" / \"mind-elixir\"\n displayName String? // 展示名(默认取 name)\n description String? @db.Text // 依赖用途说明(admin 可编辑)\n homepage String? // 官网 / 仓库\n category String @default(\"other\") // framework|ui|editor|ai|state|tool|other\n isWatched Boolean @default(true) // 是否置顶「关注列表」\n priority String @default(\"normal\") // high|normal|low\n latestVersion String? // 缓存的 npm registry latest 版本\n latestChangelog String? @db.Text // 最新版本的更新日志(来自 GitHub Releases,markdown)\n lastSyncAt DateTime? // 最后一次成功同步 npm registry 的时间\n notes String? @db.Text // 备注(升级注意事项等)\n sortOrder Int @default(0)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@index([category])\n @@index([isWatched])\n @@map(\"third_party_dependencies\")\n}\n\n// ============ 公共知识库:法律法规 ============\nmodel LegalRegulation {\n id String @id @default(cuid())\n canonicalId String\n title String\n jurisdiction String\n region String?\n country String?\n category String\n issuingAuthority String?\n effectiveDate DateTime?\n summary String? @db.Text\n content String? @db.Text\n sourceUrl String?\n likeCount Int @default(0)\n tags Json @default(\"[]\")\n visibility String @default(\"private\")\n userId String\n isDeleted Boolean @default(false)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@index([canonicalId, visibility])\n @@index([userId, visibility])\n @@index([jurisdiction, category])\n @@map(\"legal_regulations\")\n}\n\nmodel IndustryCompliance {\n id String @id @default(cuid())\n canonicalId String\n title String\n industry String\n regulatoryBody String?\n region String?\n summary String? @db.Text\n content String? @db.Text\n requirements Json @default(\"[]\")\n sourceUrl String?\n likeCount Int @default(0)\n tags Json @default(\"[]\")\n visibility String @default(\"private\")\n userId String\n isDeleted Boolean @default(false)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@index([canonicalId, visibility])\n @@index([userId, visibility])\n @@index([industry])\n @@map(\"industry_compliances\")\n}\n\nmodel DictionaryTerm {\n id String @id @default(cuid())\n canonicalId String\n title String\n industry String\n definition String? @db.Text\n aliases Json @default(\"[]\")\n examples Json @default(\"[]\")\n referenceUrl String?\n tags Json @default(\"[]\")\n visibility String @default(\"private\")\n userId String\n isDeleted Boolean @default(false)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@index([canonicalId, visibility])\n @@index([userId, visibility])\n @@index([title])\n @@map(\"dictionary_terms\")\n}\n\nmodel WebsiteBookmark {\n id String @id @default(cuid())\n canonicalId String\n title String\n url String\n categoryId String?\n summary String? @db.Text\n faviconUrl String?\n faviconSyncedAt DateTime?\n isGithub Boolean @default(false)\n githubOwner String?\n githubRepo String?\n githubStars Int?\n githubLatestVersion String?\n githubVersionDate DateTime?\n githubRepoUpdatedAt DateTime?\n githubSyncedAt DateTime?\n tags Json @default(\"[]\")\n visibility String @default(\"private\")\n userId String\n isDeleted Boolean @default(false)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n category BookmarkCategory? @relation(fields: [categoryId], references: [id], onDelete: SetNull)\n\n @@index([canonicalId, visibility])\n @@index([userId, visibility])\n @@index([categoryId])\n @@index([isGithub])\n @@map(\"website_bookmarks\")\n}\n\nmodel BookmarkCategory {\n id String @id @default(cuid())\n name String\n icon String @default(\"Globe\")\n sortOrder Int @default(0)\n isDefault Boolean @default(false)\n userId String?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User? @relation(fields: [userId], references: [id], onDelete: Cascade)\n bookmarks WebsiteBookmark[]\n\n @@unique([userId, name])\n @@index([userId])\n @@map(\"bookmark_categories\")\n}\n\nmodel KnowledgeShareRecord {\n id String @id @default(cuid())\n entityType String\n canonicalId String\n userId String\n sharedAt DateTime @default(now())\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@unique([entityType, canonicalId, userId])\n @@index([entityType, canonicalId])\n @@map(\"knowledge_share_records\")\n}\n\nmodel ArticleFavorite {\n id String @id @default(cuid())\n entityType String\n entityId String\n userId String\n createdAt DateTime @default(now())\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@unique([entityType, entityId, userId])\n @@index([userId, entityType])\n @@map(\"article_favorites\")\n}\n\n// 需求\nmodel Story {\n id String @id @default(cuid())\n sequenceId Int\n boardOrder Int @default(0)\n identifier String\n projectId String\n project Project @relation(fields: [projectId], references: [id], onDelete: Restrict)\n name String\n description String? @db.Text\n state String @default(\"backlog\")\n priority String @default(\"none\")\n archived Boolean @default(false)\n archivedAt DateTime?\n assigneeId String?\n assignee User? @relation(\"storyAssignee\", fields: [assigneeId], references: [id], onDelete: SetNull)\n startDate DateTime?\n targetDate DateTime?\n createdById String\n createdBy User @relation(\"storyCreator\", fields: [createdById], references: [id])\n updatedById String?\n updatedBy User? @relation(\"storyEditor\", fields: [updatedById], references: [id], onDelete: SetNull)\n labels StoryLabel[]\n activities StoryActivity[]\n comments StoryComment[]\n reactions StoryReaction[]\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n parentId String?\n parent Story? @relation(\"StoryHierarchy\", fields: [parentId], references: [id], onDelete: SetNull)\n children Story[] @relation(\"StoryHierarchy\")\n dependenciesAsSource StoryDependency[] @relation(\"DependencySource\")\n dependenciesAsTarget StoryDependency[] @relation(\"DependencyTarget\")\n links StoryLink[]\n attachments StoryAttachment[]\n linkedPrds StoryPrdLink[] @relation(\"StoryPrdLinks\")\n linkedDocs StoryDocLink[] @relation(\"StoryDocLinks\")\n\n @@unique([identifier])\n @@index([projectId, sequenceId])\n @@index([state])\n @@index([archived])\n @@index([archived, state, createdAt])\n @@index([assigneeId])\n @@index([createdById])\n @@map(\"stories\")\n}\n\n// 全局标签\nmodel Label {\n id String @id @default(cuid())\n name String @unique\n color String @default(\"#6b7280\")\n createdById String\n createdBy User @relation(\"labelCreator\", fields: [createdById], references: [id])\n stories StoryLabel[]\n createdAt DateTime @default(now())\n\n @@map(\"labels\")\n}\n\nmodel StoryLabel {\n storyId String\n labelId String\n story Story @relation(fields: [storyId], references: [id], onDelete: Cascade)\n label Label @relation(fields: [labelId], references: [id], onDelete: Cascade)\n\n @@id([storyId, labelId])\n @@index([labelId])\n @@map(\"story_labels\")\n}\n\nmodel StoryActivity {\n id String @id @default(cuid())\n storyId String\n story Story @relation(fields: [storyId], references: [id], onDelete: Cascade)\n userId String\n user User @relation(\"storyActivityUser\", fields: [userId], references: [id])\n action String\n field String?\n oldValue String? @db.Text\n newValue String? @db.Text\n isAI Boolean @default(false)\n metadata Json?\n createdAt DateTime @default(now())\n\n @@index([storyId, createdAt])\n @@map(\"story_activities\")\n}\n\nmodel SequenceCounter {\n id String @id @default(cuid())\n scope String @unique\n seq Int @default(0)\n\n @@map(\"sequence_counters\")\n}\n\nmodel StoryComment {\n id String @id @default(cuid())\n storyId String\n story Story @relation(fields: [storyId], references: [id], onDelete: Cascade)\n userId String\n user User @relation(\"storyCommentUser\", fields: [userId], references: [id])\n parentId String?\n parent StoryComment? @relation(\"CommentReply\", fields: [parentId], references: [id], onDelete: Cascade)\n replies StoryComment[] @relation(\"CommentReply\")\n content String @db.Text\n reactions CommentReaction[]\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@index([storyId, createdAt])\n @@index([parentId])\n @@map(\"story_comments\")\n}\n\nmodel StoryReaction {\n id String @id @default(cuid())\n storyId String\n story Story @relation(fields: [storyId], references: [id], onDelete: Cascade)\n userId String\n user User @relation(\"storyReactionUser\", fields: [userId], references: [id])\n emoji String\n createdAt DateTime @default(now())\n\n @@unique([storyId, userId, emoji])\n @@index([storyId])\n @@map(\"story_reactions\")\n}\n\nmodel CommentReaction {\n id String @id @default(cuid())\n commentId String\n comment StoryComment @relation(fields: [commentId], references: [id], onDelete: Cascade)\n userId String\n user User @relation(\"commentReactionUser\", fields: [userId], references: [id])\n emoji String\n createdAt DateTime @default(now())\n\n @@unique([commentId, userId, emoji])\n @@index([commentId])\n @@map(\"comment_reactions\")\n}\n\nmodel StoryDependency {\n id String @id @default(cuid())\n sourceId String\n targetId String\n type DependencyType\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n source Story @relation(\"DependencySource\", fields: [sourceId], references: [id], onDelete: Cascade)\n target Story @relation(\"DependencyTarget\", fields: [targetId], references: [id], onDelete: Cascade)\n\n @@unique([sourceId, targetId, type])\n @@index([sourceId])\n @@index([targetId])\n @@map(\"story_dependencies\")\n}\n\nmodel StoryLink {\n id String @id @default(cuid())\n storyId String\n url String\n title String?\n description String?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n story Story @relation(fields: [storyId], references: [id], onDelete: Cascade)\n\n @@index([storyId])\n @@map(\"story_links\")\n}\n\nmodel StoryAttachment {\n id String @id @default(cuid())\n storyId String\n fileName String\n fileSize BigInt\n mimeType String\n storageUrl String\n createdAt DateTime @default(now())\n\n story Story @relation(fields: [storyId], references: [id], onDelete: Cascade)\n\n @@index([storyId])\n @@map(\"story_attachments\")\n}\n\nmodel StoryPrdLink {\n id String @id @default(cuid())\n storyId String\n prdId String\n createdAt DateTime @default(now())\n\n story Story @relation(\"StoryPrdLinks\", fields: [storyId], references: [id], onDelete: Cascade)\n prd PRD @relation(\"PrdStoryLinks\", fields: [prdId], references: [id], onDelete: Cascade)\n\n @@unique([storyId, prdId])\n @@index([storyId])\n @@index([prdId])\n @@map(\"story_prd_links\")\n}\n\nmodel StoryDocLink {\n id String @id @default(cuid())\n storyId String\n docId String\n createdAt DateTime @default(now())\n\n story Story @relation(\"StoryDocLinks\", fields: [storyId], references: [id], onDelete: Cascade)\n doc KnowledgeDocument @relation(\"DocStoryLinks\", fields: [docId], references: [id], onDelete: Cascade)\n\n @@unique([storyId, docId])\n @@index([storyId])\n @@index([docId])\n @@map(\"story_doc_links\")\n}\n\nenum DependencyType {\n BLOCKS\n BLOCKED_BY\n RELATES_TO\n}\n\n// 需求模块保存视图(per-user 私有)\nmodel StoryFilterView {\n id String @id @default(cuid())\n userId String\n name String\n description String?\n icon String @default(\"list\")\n projectId String?\n filters Json\n displayOptions Json\n sortOrder Int @default(0)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@index([userId])\n @@map(\"story_filter_views\")\n}\n\n// ==================== 监控可观测性模块 ====================\n\nmodel MonitoringRequestLog {\n id String @id @default(cuid())\n timestamp DateTime @default(now())\n method String @db.VarChar(10)\n path String @db.VarChar(512)\n status Int\n duration Int\n ip String? @db.VarChar(45)\n userAgent String? @db.Text\n\n @@index([timestamp], map: \"idx_request_log_timestamp\")\n @@index([path, timestamp], map: \"idx_request_log_path_ts\")\n @@map(\"monitoring_request_logs\")\n}\n\nmodel MonitoringErrorReport {\n id String @id @default(cuid())\n timestamp DateTime @default(now())\n errorName String @db.VarChar(128)\n errorMessage String @db.Text\n stackTrace String? @db.Text\n count Int @default(1)\n firstSeen DateTime @default(now())\n lastSeen DateTime @default(now())\n context Json @default(\"{}\")\n\n @@index([errorName], map: \"idx_error_report_name\")\n @@index([lastSeen], map: \"idx_error_report_last_seen\")\n @@map(\"monitoring_error_reports\")\n}\n\nmodel MonitoringMetricsSnapshot {\n id String @id @default(cuid())\n recordedAt DateTime @default(now())\n metricName String @db.VarChar(256)\n count Int\n avg Float\n p50 Float\n p95 Float\n p99 Float\n min Float\n max Float\n\n @@index([metricName, recordedAt], map: \"idx_metrics_name_ts\")\n @@map(\"monitoring_metrics_snapshots\")\n}\n\nmodel MonitoringHealthSnapshot {\n id String @id @default(cuid())\n timestamp DateTime @default(now())\n status String @db.VarChar(16)\n uptimeSeconds Float\n memoryUsage Json\n dbStatus String @db.VarChar(16)\n dbLatencyMs Int?\n\n @@index([timestamp], map: \"idx_health_snapshot_ts\")\n @@map(\"monitoring_health_snapshots\")\n}\n\n// ── 子项目 2:托管 AI 与 BYOK 统一层 ──\n\n/// 订阅计划定义(seed 数据)\nmodel Plan {\n id String @id @default(cuid())\n name String @unique\n displayName String\n description String?\n priceMonthly Int @default(0)\n priceYearly Int?\n currency String @default(\"usd\")\n maxSeats Int?\n maxGuestSeats Int?\n maxWorkspaces Int?\n aiQuotaMonthly Int?\n features Json\n isPublic Boolean @default(true)\n sortOrder Int @default(0)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n /// Provider 产品与价格同步(子项目 3 新增)\n /// ⚠ stripeProductId 已删除:Creem 无独立产品概念,一个价格点 = 一个产品\n providerPriceIdUsd String?\n providerPriceIdCny String?\n providerPriceIdUsdYearly String?\n providerPriceIdCnyYearly String?\n\n /// 席位加购(P2 新增):每席位/月单价(分),null = 不可加购\n seatPriceMonthly Int?\n\n /// 席位加购 Provider Price(P2 新增,per-seat/monthly interval)\n providerSeatPriceIdUsd String?\n providerSeatPriceIdCny String?\n\n agentQuota Int?\n skillQuota Int?\n\n subscriptions Subscription[]\n\n @@map(\"plans\")\n}\n\n/// 订阅记录(User 级,一人一订阅)\nmodel Subscription {\n id String @id @default(cuid())\n userId String @unique\n user User @relation(fields: [userId], references: [id])\n planId String\n plan Plan @relation(fields: [planId], references: [id])\n status SubscriptionStatus @default(ACTIVE)\n\n /// 席位加购数量(账号级)。实际上限 = plan.maxSeats + addonSeats。\n addonSeats Int @default(0)\n\n provider String @default(\"creem\")\n providerCustomerId String?\n providerSubscriptionId String? @unique\n providerPriceId String?\n providerSeatSubscriptionId String?\n\n currentPeriodStart DateTime?\n currentPeriodEnd DateTime?\n cancelAtPeriodEnd Boolean @default(false)\n canceledAt DateTime?\n trialEndsAt DateTime?\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n /// 关联发票(子项目 3 新增)\n invoices Invoice[]\n\n @@map(\"subscriptions\")\n}\n\nenum SubscriptionStatus {\n TRIALING\n ACTIVE\n PAST_DUE\n CANCELED\n EXPIRED\n UNPAID\n}\n\n/// 用量记录(按月聚合,用于额度判断)\nmodel UsageRecord {\n id String @id @default(cuid())\n workspaceId String\n workspace Workspace @relation(fields: [workspaceId], references: [id])\n metric UsageMetric\n period String\n count Int @default(0)\n resetAt DateTime\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@unique([workspaceId, metric, period])\n @@index([workspaceId, metric])\n @@map(\"usage_records\")\n}\n\nenum UsageMetric {\n AI_CALL\n STORAGE_MB\n SEAT\n}\n\n/// AI 用量明细(按次扣减 + 成本审计)\nmodel AiUsageLog {\n id String @id @default(cuid())\n workspaceId String\n workspace Workspace @relation(fields: [workspaceId], references: [id])\n userId String\n user User @relation(fields: [userId], references: [id])\n source String @default(\"byok\")\n provider String\n model String\n inputTokens Int @default(0)\n outputTokens Int @default(0)\n costUsd Decimal? @db.Decimal(10, 6)\n success Boolean @default(true)\n errorMessage String?\n durationMs Int?\n\n createdAt DateTime @default(now())\n\n @@index([workspaceId, createdAt])\n @@index([userId, createdAt])\n @@index([workspaceId, source, createdAt])\n @@index([workspaceId, success, createdAt])\n @@map(\"ai_usage_logs\")\n}\n\n// ── 子项目 3:计费与订阅系统 ──\n\n/// 账单记录(Webhook 同步)\nmodel Invoice {\n id String @id @default(cuid())\n subscriptionId String\n subscription Subscription @relation(fields: [subscriptionId], references: [id])\n providerInvoiceId String @unique\n providerEventId String?\n amountDue Int\n amountPaid Int\n currency String @default(\"usd\")\n status String\n pdfUrl String?\n hostedInvoiceUrl String?\n periodStart DateTime\n periodEnd DateTime\n paidAt DateTime?\n\n createdAt DateTime @default(now())\n\n @@index([subscriptionId, createdAt])\n @@map(\"invoices\")\n}\n\n/// Provider Webhook 事件幂等记录\nmodel ProviderEvent {\n id String @id @default(cuid())\n providerEventId String @unique\n type String\n status String @default(\"processing\")\n payload Json?\n errorMessage String?\n processedAt DateTime? @db.Timestamptz\n\n createdAt DateTime @default(now()) @db.Timestamptz\n\n @@index([type, createdAt])\n @@map(\"provider_events\")\n}\n\n// ==================== 子项目 5:企业治理模型 ====================\n\n// 企业版 License(自部署企业版验证)\nmodel LicenseKey {\n id String @id @default(cuid())\n key String @unique\n signature String\n payload Json\n customerId String\n customerName String\n customerEmail String\n plan String @default(\"enterprise\")\n seats Int\n features Json\n issuedAt DateTime @default(now())\n expiresAt DateTime?\n revokedAt DateTime?\n issuedById String?\n issuedBy User? @relation(\"LicenseIssuer\", fields: [issuedById], references: [id])\n activations LicenseActivation[]\n\n @@map(\"license_keys\")\n}\n\nmodel LicenseActivation {\n id String @id @default(cuid())\n licenseId String\n license LicenseKey @relation(fields: [licenseId], references: [id])\n instanceId String @unique\n fingerprint String\n activatedAt DateTime @default(now())\n lastSeenAt DateTime?\n revokedAt DateTime?\n\n @@map(\"license_activations\")\n}\n\n// 审计日志\nmodel AuditLog {\n id String @id @default(cuid())\n workspaceId String?\n workspace Workspace? @relation(fields: [workspaceId], references: [id])\n userId String?\n action String\n resourceType String\n resourceId String?\n metadata Json\n ip String?\n userAgent String?\n createdAt DateTime @default(now())\n\n @@index([workspaceId, createdAt])\n @@index([userId, createdAt])\n @@index([action])\n @@map(\"audit_logs\")\n}\n\n// SSO Provider 配置\nmodel SsoProvider {\n id String @id @default(cuid())\n workspaceId String\n workspace Workspace @relation(fields: [workspaceId], references: [id])\n type String\n name String\n config Json\n domain String?\n enabled Boolean @default(true)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n mappings SsoMapping[]\n\n @@unique([workspaceId, type, domain])\n @@map(\"sso_providers\")\n}\n\nmodel SsoMapping {\n id String @id @default(cuid())\n providerId String\n provider SsoProvider @relation(fields: [providerId], references: [id])\n externalId String\n userId String\n user User @relation(fields: [userId], references: [id])\n email String?\n createdAt DateTime @default(now())\n\n @@unique([providerId, externalId])\n @@map(\"sso_mappings\")\n}\n\n// 自定义角色\nmodel CustomRole {\n id String @id @default(cuid())\n workspaceId String\n workspace Workspace @relation(fields: [workspaceId], references: [id])\n name String\n permissions Json\n isSystem Boolean @default(false)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n assignments RoleAssignment[]\n\n @@unique([workspaceId, name])\n @@map(\"custom_roles\")\n}\n\nmodel RoleAssignment {\n id String @id @default(cuid())\n roleId String\n role CustomRole @relation(fields: [roleId], references: [id])\n userId String\n user User @relation(fields: [userId], references: [id])\n createdAt DateTime @default(now())\n\n @@unique([roleId, userId])\n @@map(\"role_assignments\")\n}\n\n// 合规导出任务\nmodel ComplianceExport {\n id String @id @default(cuid())\n type String\n scope String\n targetId String\n status String @default(\"pending\")\n downloadUrl String?\n expiresAt DateTime?\n error String?\n content String?\n requestedBy String?\n createdAt DateTime @default(now())\n completedAt DateTime?\n\n @@map(\"compliance_exports\")\n}\n\n// P6 用户自定义 Agent(人设/工具/模型/温度/开场白/建议问题/知识库绑定)\nmodel UserAgent {\n id String @id @default(cuid())\n userId String\n name String\n description String?\n avatarEmoji String?\n systemPrompt String @db.Text\n allowedTools Json @default(\"[]\")\n model String?\n temperature Float?\n greeting String? @db.Text\n suggestedPrompts Json?\n knowledgeBaseIds Json @default(\"[]\")\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n isDeleted Boolean @default(false)\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n threads ChatThread[]\n\n @@index([userId])\n @@map(\"user_agents\")\n}\n\n// P6 用户自定义 Skill(斜杠指令模板)\nmodel UserSkill {\n id String @id @default(cuid())\n userId String\n name String\n title String\n template String @db.Text\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n isDeleted Boolean @default(false)\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@unique([userId, name])\n @@map(\"user_skills\")\n}\n\n// 开发者日志(Changelog 条目,agent 自动生成 + admin 手动管理)\nmodel DeveloperLog {\n id String @id @default(cuid())\n date String // \"Aug 23, 2026\"\n year String // \"2026\"\n title String\n desc String @db.Text\n tags Json @default(\"[]\") // [\"feat\", \"design\"]\n commitSha String?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n isDeleted Boolean @default(false)\n\n @@index([year, date])\n @@map(\"developer_logs\")\n}\n\n// 通知(团队邀请、协作请求、系统消息等)\nmodel Notification {\n id String @id @default(cuid())\n userId String\n category String\n type String\n title String\n body String?\n link String?\n readAt DateTime?\n createdAt DateTime @default(now())\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@index([userId, createdAt(sort: Desc)])\n @@index([userId, readAt])\n @@map(\"notifications\")\n}\n\n// 通知偏好(免打扰时段、分类开关)\nmodel NotificationPreference {\n userId String @id\n categories Json\n dndEnabled Boolean @default(false)\n dndStart String @default(\"22:00\")\n dndEnd String @default(\"08:00\")\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@map(\"notification_preferences\")\n}\n",
|
|
23
|
+
"inlineSchema": "generator client {\n provider = \"prisma-client\"\n output = \"./generated\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n}\n\n// 系统配置表\nmodel SystemSetting {\n id String @id @default(cuid())\n key String @unique\n value String @db.Text\n category String @default(\"general\") // 配置分类\n desc String? // 说明\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@index([category])\n @@map(\"system_settings\")\n}\n\n// 用户表\nmodel User {\n id String @id @default(cuid())\n email String @unique\n username String @unique\n password String\n emailVerified DateTime?\n image String?\n role Role @default(USER)\n status UserStatus @default(ACTIVE)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n lastLoginAt DateTime?\n\n accounts Account[]\n\n avatarConfig Json?\n bgShape String?\n bgColor String?\n\n aiProvider String? // \"openrouter\" | \"openai\"\n aiApiKey String? // 用户 AI API Key(TODO: 加密存储)\n aiModel String? // 默认 \"openai/gpt-4o-mini\"\n locale String? // 用户语言偏好(zh / en),null 表示未设置\n\n storyDisplayOptions Json? // Story Display Options 个人偏好(URL 无参数时的默认值,跨设备持久化)\n\n sketchApiToken String?\n timezone String? // 用户全局时区,如 \"Asia/Shanghai\"。null = 浏览器时区\n\n /// 用户偏好的计费币种(子项目 3 新增)\n preferredCurrency String @default(\"usd\")\n\n /// 用户默认 workspace ID(B3 精确化:多 workspace 用户权益判定确定性)\n defaultWorkspaceId String?\n\n invitationUses InvitationUse[]\n loginLogs LoginLog[]\n passwordResetTokens PasswordResetToken[]\n prds PRD[]\n tags Tag[]\n knowledgeBases KnowledgeBase[]\n knowledgeDocuments KnowledgeDocument[]\n knowledgeShares KnowledgeShareRecord[]\n legalRegulations LegalRegulation[]\n industryCompliances IndustryCompliance[]\n dictionaryTerms DictionaryTerm[]\n websiteBookmarks WebsiteBookmark[]\n bookmarkCategories BookmarkCategory[]\n articleFavorites ArticleFavorite[]\n anyhubApps AnyHubApp[]\n anyhubMarketApps AnyHubMarketApp[]\n reviewedAnyhubRecommendations AnyHubRecommendation[] @relation(\"reviewedAnyhubRecommendations\")\n anyhubRecommenders AnyHubRecommender[]\n prdVersions PRDVersion[]\n reviewComments ReviewComment[]\n comments Comment[]\n commentIgnores CommentIgnore[]\n reviews Review[] @relation(\"reviewer\")\n designProjects DesignProject[]\n storiesCreated Story[] @relation(\"storyCreator\")\n storiesAssigned Story[] @relation(\"storyAssignee\")\n storiesEdited Story[] @relation(\"storyEditor\")\n labelsCreated Label[] @relation(\"labelCreator\")\n storyActivities StoryActivity[] @relation(\"storyActivityUser\")\n storyComments StoryComment[] @relation(\"storyCommentUser\")\n storyReactions StoryReaction[] @relation(\"storyReactionUser\")\n commentReactions CommentReaction[] @relation(\"commentReactionUser\")\n storyFilterViews StoryFilterView[]\n chatThreads ChatThread[]\n aiProviderConfigs AiProviderConfig[]\n agentConversations AgentConversation[]\n ownedProjects Project[] @relation(\"projectOwner\")\n projectMemberships ProjectMember[]\n projectActivities ProjectActivity[]\n ownedWorkspaces Workspace[] @relation(\"workspaceOwner\")\n workspaceMemberships TeamMembership[] @relation(\"teamOwner\")\n teamJoined TeamMembership? @relation(\"teamMember\")\n sentInvitations TeamInvitation[] @relation(\"invitationOwner\")\n ownedJoinRequests TeamJoinRequest[] @relation(\"joinRequestOwner\")\n applicantJoinRequests TeamJoinRequest[] @relation(\"joinRequestApplicant\")\n aiUsageLogs AiUsageLog[]\n agents UserAgent[]\n skills UserSkill[]\n notifications Notification[]\n notificationPreference NotificationPreference?\n\n issuedLicenses LicenseKey[] @relation(\"LicenseIssuer\")\n ssoMappings SsoMapping[]\n roleAssignments RoleAssignment[]\n subscription Subscription?\n\n @@map(\"users\")\n}\n\n// OAuth 账号关联\nmodel Account {\n id String @id @default(cuid())\n userId String\n type String\n provider String\n providerAccountId String\n refresh_token String? @db.Text\n access_token String? @db.Text\n expires_at Int?\n token_type String?\n scope String?\n id_token String? @db.Text\n session_state String?\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@unique([provider, providerAccountId])\n @@index([userId])\n @@map(\"accounts\")\n}\n\n// 项目\nmodel Project {\n id String @id @default(cuid())\n displayId String? // 用户层项目ID,全大写字母数字,1-10位\n name String\n description String?\n icon String @default(\"folder\")\n timezone String? // 项目时区,null = 跟随用户全局时区\n ownerId String\n owner User @relation(\"projectOwner\", fields: [ownerId], references: [id])\n workspaceId String?\n workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: SetNull)\n members ProjectMember[]\n activities ProjectActivity[]\n stories Story[]\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@unique([ownerId, displayId])\n @@index([ownerId])\n @@index([workspaceId])\n @@map(\"projects\")\n}\n\n// 项目成员\nmodel ProjectMember {\n id String @id @default(cuid())\n projectId String\n project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)\n userId String\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n role String @default(\"member\") // owner | admin | member | viewer\n status String @default(\"active\") // active | invited | suspended\n joinedAt DateTime @default(now())\n\n @@unique([projectId, userId])\n @@index([projectId])\n @@map(\"project_members\")\n}\n\n// 工作空间(项目的上一级容器)\nmodel Workspace {\n id String @id @default(cuid())\n name String\n icon String @default(\"folder\")\n description String?\n ownerId String\n owner User @relation(\"workspaceOwner\", fields: [ownerId], references: [id])\n projects Project[]\n usageRecords UsageRecord[]\n aiUsageLogs AiUsageLog[]\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n ssoProviders SsoProvider[]\n customRoles CustomRole[]\n auditLogs AuditLog[]\n\n @@index([ownerId])\n @@map(\"workspaces\")\n}\n\n// 团队隶属关系\nmodel TeamMembership {\n id String @id @default(cuid())\n ownerId String\n owner User @relation(\"teamOwner\", fields: [ownerId], references: [id], onDelete: Cascade)\n memberId String\n member User @relation(\"teamMember\", fields: [memberId], references: [id], onDelete: Cascade)\n seatType String @default(\"member\")\n joinedAt DateTime @default(now())\n\n @@unique([memberId])\n @@index([ownerId])\n @@map(\"team_memberships\")\n}\n\n// 团队邀请\nmodel TeamInvitation {\n id String @id @default(cuid())\n ownerId String\n owner User @relation(\"invitationOwner\", fields: [ownerId], references: [id], onDelete: Cascade)\n email String?\n seatType String @default(\"member\")\n token String @unique\n channel String @default(\"email\")\n status String @default(\"pending\")\n expiresAt DateTime\n createdAt DateTime @default(now())\n acceptedBy String?\n applicantEmail String?\n message String?\n joinRequests TeamJoinRequest[]\n\n @@unique([ownerId, email])\n @@index([ownerId])\n @@index([email])\n @@map(\"team_invitations\")\n}\n\n// 用户加入团队申请(链接渠道,与 TeamInvitation 分离:一条链接可承载多个申请)\nmodel TeamJoinRequest {\n id String @id @default(cuid())\n invitationId String\n invitation TeamInvitation @relation(fields: [invitationId], references: [id], onDelete: Cascade)\n ownerId String\n owner User @relation(\"joinRequestOwner\", fields: [ownerId], references: [id], onDelete: Cascade)\n userId String?\n applicant User? @relation(\"joinRequestApplicant\", fields: [userId], references: [id], onDelete: SetNull)\n email String\n status String @default(\"pending\")\n seatType String @default(\"member\")\n createdAt DateTime @default(now())\n processedAt DateTime?\n\n @@unique([invitationId, email])\n @@index([ownerId, status])\n @@map(\"team_join_requests\")\n}\n\n// 项目活动记录\nmodel ProjectActivity {\n id String @id @default(cuid())\n projectId String\n project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)\n userId String\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n action String // created | updated | deleted | member_invited | member_joined | member_removed | role_changed | module_viewed\n targetType String? // project | member | requirement | prd | design | testcase | bug | acceptance\n targetId String?\n metadata Json?\n createdAt DateTime @default(now())\n\n @@index([projectId, createdAt])\n @@map(\"project_activities\")\n}\n\n// 对话线程(作为 TanStack AI persistence threadId)\nmodel ChatThread {\n id String @id @default(cuid())\n userId String\n title String?\n isArchived Boolean @default(false)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n messages ChatMessage[]\n runs ChatRun[]\n interrupts ChatInterrupt[]\n generations GenerationRun[]\n agentId String?\n agent UserAgent? @relation(fields: [agentId], references: [id])\n\n @@index([userId, updatedAt])\n @@map(\"chat_threads\")\n}\n\n// 对话消息(TanStack AI messages store)\nmodel ChatMessage {\n id String @id @default(cuid())\n threadId String\n role String // \"user\" | \"assistant\" | \"tool\"\n content String @db.Text\n parts Json?\n thinking String? @db.Text\n citations Json?\n createdAt DateTime @default(now())\n\n thread ChatThread @relation(fields: [threadId], references: [id], onDelete: Cascade)\n\n @@index([threadId, createdAt])\n @@map(\"chat_messages\")\n}\n\n// 运行记录(TanStack AI runs store)\nmodel ChatRun {\n id String @id @default(cuid())\n threadId String\n userId String\n status String // running | completed | failed | aborted | interrupted\n startedAt DateTime @default(now())\n finishedAt DateTime?\n detachedSince DateTime?\n usage Json?\n error String? @db.Text\n\n thread ChatThread @relation(fields: [threadId], references: [id], onDelete: Cascade)\n interrupts ChatInterrupt[]\n\n @@index([threadId, startedAt])\n @@index([userId, status])\n @@map(\"chat_runs\")\n}\n\n// 中断记录(TanStack AI interrupts store)\nmodel ChatInterrupt {\n id String @id @default(cuid())\n runId String\n threadId String\n userId String\n kind String // tool-approval | generic\n toolName String?\n state String // pending | resolved | cancelled\n payload Json?\n resolution Json?\n createdAt DateTime @default(now())\n resolvedAt DateTime?\n\n run ChatRun @relation(fields: [runId], references: [id], onDelete: Cascade)\n thread ChatThread @relation(fields: [threadId], references: [id], onDelete: Cascade)\n\n @@index([runId])\n @@index([threadId, state])\n @@map(\"chat_interrupts\")\n}\n\n// 媒体生成记录(占位,本轮建表不接入业务)\nmodel GenerationRun {\n id String @id @default(cuid())\n threadId String\n userId String\n kind String // image | video | speech | transcription\n status String // running | completed | failed | interrupted\n input Json?\n result Json?\n artifactId String?\n error String? @db.Text\n startedAt DateTime @default(now())\n finishedAt DateTime?\n\n thread ChatThread @relation(fields: [threadId], references: [id], onDelete: Cascade)\n\n @@index([threadId, startedAt])\n @@index([userId, status])\n @@map(\"generation_runs\")\n}\n\n// 登录日志\nmodel LoginLog {\n id String @id @default(cuid())\n userId String\n ip String?\n userAgent String?\n location String? // 地理位置,如 \"北京, 中国\";开发环境为 \"本地\"\n success Boolean @default(true)\n message String? // 失败原因(中文),成功时为 null\n createdAt DateTime @default(now())\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@map(\"login_logs\")\n}\n\n// 邀请码\nmodel InvitationCode {\n id String @id @default(cuid())\n code String @unique\n maxUses Int @default(1)\n usedCount Int @default(0)\n expiresAt DateTime\n createdAt DateTime @default(now())\n\n uses InvitationUse[]\n\n @@map(\"invitation_codes\")\n}\n\n// 邀请码使用记录\nmodel InvitationUse {\n id String @id @default(cuid())\n codeId String\n userId String\n usedAt DateTime @default(now())\n\n code InvitationCode @relation(fields: [codeId], references: [id], onDelete: Cascade)\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@map(\"invitation_uses\")\n}\n\n// 密码重置令牌\nmodel PasswordResetToken {\n id String @id @default(cuid())\n token String @unique\n userId String\n expiresAt DateTime\n usedAt DateTime?\n createdAt DateTime @default(now())\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@map(\"password_reset_tokens\")\n}\n\nenum Role {\n SUPER_ADMIN\n ADMIN\n USER\n GUEST\n}\n\nenum UserStatus {\n ACTIVE\n INACTIVE\n BANNED\n}\n\nenum IconType {\n IMAGE\n ICON\n}\n\nenum MarketplaceAppStatus {\n DRAFT\n PUBLISHED\n UNPUBLISHED\n}\n\nenum ReviewStatus {\n PENDING\n APPROVED\n REJECTED\n}\n\nenum ShareStatus {\n ACTIVE\n EXPIRED\n DISABLED\n}\n\n// 知识库\nmodel KnowledgeBase {\n id String @id @default(cuid())\n name String\n description String? @db.Text\n icon String @default(\"notebook\")\n tags Json @default(\"[]\")\n visibility String @default(\"private\")\n userId String\n isDeleted Boolean @default(false)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n documents KnowledgeDocument[]\n\n @@index([userId])\n @@map(\"knowledge_bases\")\n}\n\nmodel KnowledgeDocument {\n id String @id @default(cuid())\n kbId String\n parentId String?\n title String\n type String @default(\"doc\")\n content Json @default(\"{}\")\n icon String?\n isHomepage Boolean @default(false)\n sortOrder Int @default(0)\n isDeleted Boolean @default(false)\n createdBy String\n tags Json @default(\"[]\")\n properties Json @default(\"{}\")\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n kb KnowledgeBase @relation(fields: [kbId], references: [id], onDelete: Cascade)\n parent KnowledgeDocument? @relation(\"DocumentTree\", fields: [parentId], references: [id], onDelete: SetNull)\n children KnowledgeDocument[] @relation(\"DocumentTree\")\n creator User @relation(fields: [createdBy], references: [id], onDelete: Cascade)\n linkedStories StoryDocLink[] @relation(\"DocStoryLinks\")\n\n @@index([kbId])\n @@index([parentId])\n @@index([kbId, isHomepage])\n @@map(\"knowledge_documents\")\n}\n\n// PRD 文档表\nmodel PRD {\n id String @id @default(cuid())\n icon String @default(\"file\") // 图标名称\n name String // PRD 名称\n description String? // 介绍\n settings Json? // 文档设置(布局、主题等)\n userId String // 所属用户\n isDeleted Boolean @default(false)\n deletedAt DateTime?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n pages PRDPage[]\n versions PRDVersion[]\n reviews Review[]\n comments Comment[]\n shares Share[]\n prdTags PRDTag[]\n agentConversations AgentConversation[]\n linkedStories StoryPrdLink[] @relation(\"PrdStoryLinks\")\n\n @@index([userId])\n @@map(\"prds\")\n}\n\n// Agent 原型生成会话\nmodel AgentConversation {\n id String @id @default(cuid())\n userId String\n prdId String\n title String @default(\"新会话\")\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)\n messages AgentMessage[]\n\n @@index([userId, prdId])\n @@map(\"agent_conversations\")\n}\n\n// Agent 会话消息\nmodel AgentMessage {\n id String @id @default(cuid())\n conversationId String\n role String // \"user\" | \"assistant\"\n content String // 消息文本\n components Json? // AI 生成的组件数据(assistant 消息)\n isError Boolean @default(false)\n createdAt DateTime @default(now())\n\n conversation AgentConversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)\n\n @@index([conversationId])\n @@map(\"agent_messages\")\n}\n\n// 基础组件表(后台维护)\nmodel Component {\n id String @id @default(cuid())\n name String\n description String? // 组件描述\n type String // \"component\" | \"block\" | \"template\"\n category String? // 分类\n subCategory String? // 子分类\n path String? // 树形分组路径(如 \"基础组件/表单/输入框\")\n defaultWidth Int @default(200)\n defaultHeight Int @default(40)\n prototypeKey String? // unique key for registry lookup (e.g. \"text\", \"button\")\n config Json // 属性描述 schema(props定义、slots、events)\n defaultProps Json? // 默认属性值\n defaultStyle Json? // 默认样式\n preview String? // 预览图URL\n version Int @default(1)\n sortOrder Int @default(0) // 排序权重(越大越前)\n source String @default(\"manual\") // \"npm\" | \"file\" | \"manual\"\n sourceId String? // npm 包名 / 文件名\n isHidden Boolean @default(false) // 隐藏/显示\n isDeleted Boolean @default(false)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n blockItems BlockComponent[] @relation(\"componentRef\")\n instances ComponentInstance[] @relation(\"componentRef\")\n componentTags ComponentTag[]\n tags String[] @default([])\n\n @@index([type, category])\n @@index([isDeleted])\n @@index([isHidden])\n @@index([sortOrder])\n @@map(\"components\")\n}\n\n// 区块定义表(后台维护)\nmodel Block {\n id String @id @default(cuid())\n name String\n description String?\n category String?\n isDeleted Boolean @default(false)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n items BlockComponent[]\n instances BlockInstance[] @relation(\"blockRef\")\n templateItems TemplateBlock[] @relation(\"templateBlockRef\")\n\n @@index([isDeleted])\n @@map(\"blocks\")\n}\n\n// 区块内组件布局\nmodel BlockComponent {\n id String @id @default(cuid())\n blockId String\n componentId String\n x Float @default(0)\n y Float @default(0)\n width Float @default(100)\n height Float @default(100)\n zIndex Int @default(0)\n propsOverride Json? // 局部覆写属性\n styleOverride Json? // 局部覆写样式\n\n block Block @relation(fields: [blockId], references: [id], onDelete: Cascade)\n component Component @relation(\"componentRef\", fields: [componentId], references: [id])\n\n @@map(\"block_components\")\n}\n\n// 模板定义表(后台维护)\nmodel Template {\n id String @id @default(cuid())\n name String\n description String?\n category String?\n isDeleted Boolean @default(false)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n items TemplateBlock[]\n\n @@index([isDeleted])\n @@map(\"templates\")\n}\n\n// 模板内区块排布\nmodel TemplateBlock {\n id String @id @default(cuid())\n templateId String\n blockId String\n order Int @default(0) // 排布顺序\n x Float? @default(0)\n y Float? @default(0)\n width Float?\n height Float?\n\n template Template @relation(fields: [templateId], references: [id], onDelete: Cascade)\n block Block @relation(\"templateBlockRef\", fields: [blockId], references: [id])\n\n @@map(\"template_blocks\")\n}\n\n// PRD 页面/目录树节点\nmodel PRDPage {\n id String @id @default(cuid())\n prdId String\n parentId String? // 父节点,构建树形结构(null = 根级)\n name String\n order Int @default(0) // 排序\n type String @default(\"page\") // \"page\" | \"folder\"\n canvas Json? // 原型画板数据\n content Json? // PRD 文档内容\n version Int @default(1) // 页面版本号\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)\n parent PRDPage? @relation(\"PageHierarchy\", fields: [parentId], references: [id], onDelete: Cascade)\n children PRDPage[] @relation(\"PageHierarchy\")\n componentInstances ComponentInstance[]\n blockInstances BlockInstance[]\n pageVersions PageVersion[]\n\n @@index([prdId, order])\n @@map(\"prd_pages\")\n}\n\n// 组件实例(画布上)\nmodel ComponentInstance {\n id String @id @default(cuid())\n pageId String\n componentId String? // null = 已解绑的游离副本\n blockInstanceId String? // 所属区块实例\n name String? // 实例别名\n x Float @default(0)\n y Float @default(0)\n width Float @default(100)\n height Float @default(100)\n zIndex Int @default(0)\n props Json? // 局部覆写属性\n style Json? // 局部覆写样式\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n page PRDPage @relation(fields: [pageId], references: [id], onDelete: Cascade)\n component Component? @relation(\"componentRef\", fields: [componentId], references: [id])\n blockInstance BlockInstance? @relation(fields: [blockInstanceId], references: [id])\n\n @@index([pageId])\n @@map(\"component_instances\")\n}\n\n// 区块实例(画布上)\nmodel BlockInstance {\n id String @id @default(cuid())\n pageId String\n blockId String? // null = 已解绑的游离副本\n name String? // 实例别名\n x Float @default(0)\n y Float @default(0)\n width Float @default(400)\n height Float @default(300)\n zIndex Int @default(0)\n props Json? // 局部覆写属性\n style Json? // 局部覆写样式\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n page PRDPage @relation(fields: [pageId], references: [id], onDelete: Cascade)\n block Block? @relation(\"blockRef\", fields: [blockId], references: [id])\n instances ComponentInstance[]\n\n @@index([pageId])\n @@map(\"block_instances\")\n}\n\n// PRD 版本(手动发布创建)\nmodel PRDVersion {\n id String @id @default(cuid())\n prdId String\n major Int @default(1)\n minor Int @default(0)\n patch Int @default(0)\n versionLabel String // 如 \"v1\", \"v1.1\", \"v1.1.1\"\n parentVersion String? // 上一版本ID(版本链)\n pageVersions Json // [{ pageId, pageName, version, canvas, content }]\n notes String? // 发版说明\n userId String\n createdAt DateTime @default(now())\n updatedAt DateTime?\n\n prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)\n user User @relation(fields: [userId], references: [id])\n reviews Review[]\n shareVersions ShareVersion[]\n\n @@index([prdId, createdAt])\n @@index([userId])\n @@map(\"prd_versions\")\n}\n\n// 页面版本(独立的页面级别版本历史)\nmodel PageVersion {\n id String @id @default(cuid())\n pageId String\n version Int // 整数版本号,自增\n notes String? // 版本说明(用户可编辑)\n canvas Json? // 原型快照\n content Json? // 文档快照\n restoredFromVersion Int? // 从哪个版本号还原而来(null 表示非还原版本)\n fromPRDVersionId String? // 来源:从哪个 PRD 版本创建(可选标记)\n createdAt DateTime @default(now())\n\n page PRDPage @relation(fields: [pageId], references: [id], onDelete: Cascade)\n\n @@index([pageId, createdAt])\n @@index([pageId, version])\n @@map(\"page_versions\")\n}\n\n// 评审工作流\nmodel Review {\n id String @id @default(cuid())\n prdId String\n versionId String\n status ReviewStatus @default(PENDING)\n reviewerId String?\n notes String?\n createdAt DateTime @default(now())\n completedAt DateTime?\n\n prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)\n version PRDVersion @relation(fields: [versionId], references: [id])\n reviewer User? @relation(\"reviewer\", fields: [reviewerId], references: [id])\n comments ReviewComment[]\n\n @@unique([prdId, versionId])\n @@index([prdId])\n @@index([versionId])\n @@index([reviewerId])\n @@map(\"reviews\")\n}\n\n// 评审留言\nmodel ReviewComment {\n id String @id @default(cuid())\n reviewId String\n userId String\n content String @db.Text\n pageId String? // 关联页面\n elementId String? // 关联具体元素\n parentId String? // 回复上级留言\n createdAt DateTime @default(now())\n\n review Review @relation(fields: [reviewId], references: [id], onDelete: Cascade)\n user User @relation(fields: [userId], references: [id])\n parent ReviewComment? @relation(\"ReviewCommentReplies\", fields: [parentId], references: [id])\n replies ReviewComment[] @relation(\"ReviewCommentReplies\")\n\n @@index([reviewId])\n @@index([userId])\n @@index([parentId])\n @@map(\"review_comments\")\n}\n\n// 评论(PRD 级别 / 页面级别 / 元素级别)\nmodel Comment {\n id String @id @default(cuid())\n prdId String\n pageId String? // 可选:针对某页面\n elementId String? // 可选:针对某元素(组件/区块实例ID)\n userId String\n content String @db.Text\n parentId String? // 回复上级评论\n position Json? // 文本选区位置 { from: number, to: number }\n resolved Boolean @default(false)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)\n user User @relation(fields: [userId], references: [id])\n parent Comment? @relation(\"CommentReplies\", fields: [parentId], references: [id])\n replies Comment[] @relation(\"CommentReplies\")\n ignores CommentIgnore[]\n\n @@index([prdId])\n @@index([userId])\n @@index([parentId])\n @@index([pageId])\n @@map(\"comments\")\n}\n\nmodel CommentIgnore {\n id String @id @default(cuid())\n userId String\n commentId String\n createdAt DateTime @default(now())\n\n user User @relation(fields: [userId], references: [id])\n comment Comment @relation(fields: [commentId], references: [id])\n\n @@unique([userId, commentId])\n @@index([userId])\n @@index([commentId])\n @@map(\"comment_ignores\")\n}\n\n// 分享链接\nmodel Share {\n id String @id @default(cuid())\n prdId String\n token String @unique\n type String @default(\"prd\") // \"prd\" | 预留扩展\n status ShareStatus @default(ACTIVE)\n password String? // 加密分享密码(4位,数字+大写+小写字母)\n hasPassword Boolean @default(false)\n expiresAt DateTime?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)\n shareVersions ShareVersion[]\n\n @@index([token])\n @@index([prdId, type, status])\n @@index([status])\n @@index([expiresAt])\n @@map(\"shares\")\n}\n\n// 标签表\nmodel Tag {\n id String @id @default(cuid())\n name String\n color Int @default(0)\n sortOrder Int @default(0)\n isHidden Boolean @default(false)\n userId String\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n prdTags PRDTag[]\n\n @@unique([name, userId])\n @@index([sortOrder])\n @@index([userId])\n @@map(\"tags\")\n}\n\n// PRD-标签多对多\nmodel PRDTag {\n id String @id @default(cuid())\n prdId String\n tagId String\n createdAt DateTime @default(now())\n\n prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)\n tag Tag @relation(fields: [tagId], references: [id], onDelete: Cascade)\n\n @@unique([prdId, tagId])\n @@index([prdId])\n @@index([tagId])\n @@map(\"prd_tags\")\n}\n\n// 组件-标签多对多\n// TODO(ComponentTag 重新调整): Tag 已加 userId,ComponentTag 业务待后续调整。\n// DB 端 FK 已 drop(迁移同步);component_tags 表保留,tagId 列 + 唯一约束 (componentId, tagId) 保留;\n// 移除 Prisma 关系以避免与新 Tag 语义冲突。\nmodel ComponentTag {\n id String @id @default(cuid())\n componentId String\n tagId String\n\n component Component @relation(fields: [componentId], references: [id], onDelete: Cascade)\n\n @@unique([componentId, tagId])\n @@map(\"component_tags\")\n}\n\nmodel Reference {\n id String @id @default(uuid())\n sourceModule String\n sourceEntityId String\n targetModule String\n targetEntityId String\n createdAt DateTime @default(now())\n\n @@index([sourceModule, sourceEntityId])\n @@index([targetModule, targetEntityId])\n @@map(\"references\")\n}\n\nmodel ShareVersion {\n id String @id @default(cuid())\n shareId String\n versionId String\n\n share Share @relation(fields: [shareId], references: [id], onDelete: Cascade)\n version PRDVersion @relation(fields: [versionId], references: [id], onDelete: Cascade)\n\n @@unique([shareId, versionId])\n @@index([shareId])\n @@index([versionId])\n @@map(\"share_versions\")\n}\n\n// ========== AnyHub 模型 ==========\n\nmodel AnyHubApp {\n id String @id @default(cuid())\n name String @unique\n displayName String\n description String? @db.Text\n version String @default(\"0.1.0\")\n source String\n url String?\n localPath String?\n proxyBasePath String?\n iconUrl String?\n pinned Boolean @default(false)\n status String @default(\"installing\")\n userId String\n githubUrl String?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n permissions AnyHubPermission[]\n\n @@index([userId])\n @@index([pinned])\n}\n\nmodel AnyHubPermission {\n id String @id @default(cuid())\n appId String\n capability String\n granted Boolean @default(false)\n userId String\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n app AnyHubApp @relation(fields: [appId], references: [id], onDelete: Cascade)\n\n @@unique([appId, capability, userId])\n @@index([appId])\n}\n\nmodel AnyHubMarketApp {\n id String @id @default(cuid())\n name String\n displayName String\n description String? @db.Text\n entryUrl String\n icon String?\n iconType IconType @default(ICON)\n logo String?\n category String?\n tags String? @db.Text\n downloads Int @default(0)\n capabilities Json\n status MarketplaceAppStatus @default(DRAFT)\n publishedAt DateTime?\n userId String\n recommendationId String? @unique\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id])\n recommendation AnyHubRecommendation? @relation(\"anyhubRecommendation\", fields: [recommendationId], references: [id])\n\n @@index([status])\n @@index([category])\n}\n\nmodel AnyHubRecommendation {\n id String @id @default(cuid())\n githubUrl String @unique\n name String?\n displayName String?\n description String? @db.Text\n status String @default(\"pending\")\n reviewedBy String?\n reviewedAt DateTime?\n marketplaceAppId String?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n marketplaceApp AnyHubMarketApp? @relation(\"anyhubRecommendation\")\n reviewer User? @relation(\"reviewedAnyhubRecommendations\", fields: [reviewedBy], references: [id])\n recommenders AnyHubRecommender[]\n\n @@index([status])\n}\n\nmodel AnyHubRecommender {\n id String @id @default(cuid())\n recommendationId String\n userId String\n reason String?\n createdAt DateTime @default(now())\n\n recommendation AnyHubRecommendation @relation(fields: [recommendationId], references: [id], onDelete: Cascade)\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@unique([recommendationId, userId])\n}\n\n// 设计稿\nmodel DesignProject {\n id String @id @default(cuid())\n name String\n documentId String?\n sketchName String?\n version Int @default(1)\n userId String\n user User @relation(fields: [userId], references: [id])\n artboards Artboard[]\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@index([userId])\n @@map(\"design_projects\")\n}\n\nmodel Artboard {\n id String @id @default(cuid())\n projectId String\n project DesignProject @relation(fields: [projectId], references: [id], onDelete: Cascade)\n name String\n pageName String?\n width Int\n height Int\n pngPath String\n svgPath String?\n annotationJson Json?\n layerCount Int?\n sortOrder Int @default(0)\n createdAt DateTime @default(now())\n exports ArtboardExport[]\n\n @@index([projectId])\n @@map(\"design_artboards\")\n}\n\nmodel ArtboardExport {\n id String @id @default(cuid())\n artboardId String\n artboard Artboard @relation(fields: [artboardId], references: [id], onDelete: Cascade)\n layerName String\n layerId String\n scale Int\n format String @default(\"png\")\n filePath String\n width Int\n height Int\n\n @@unique([artboardId, layerId, scale])\n @@map(\"design_artboard_exports\")\n}\n\n// AI 服务商元数据(admin 维护)\nmodel AiProvider {\n id String @id @default(cuid())\n providerId String @unique // 业务标识 \"openai\" \"anthropic\",用于 adapter 路由与 AiProviderConfig 软关联\n displayName String\n brandName String\n description String @db.Text\n category String @default(\"popular\") // recommended|popular|local\n adapterKind String // openai|anthropic|gemini|groq|grok|openrouter|ollama|openai-compatible\n defaultBaseUrl String?\n keyUrl String?\n docsUrl String?\n keyPlaceholder String?\n iconSlug String?\n brandColor String @default(\"#6467F2\")\n badge String? // 卡片角标文案(如「推荐」「热门」「NEW」),admin 可配\n isLocal Boolean @default(false)\n enabled Boolean @default(true) // 平台级开关:停用后未配置用户看不到,已配置用户继续可用\n models Json // AiModelMeta[](admin 可编辑)\n sortOrder Int @default(0)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@map(\"ai_providers\")\n}\n\n// 用户级 AI 服务商配置\nmodel AiProviderConfig {\n id String @id @default(cuid())\n userId String\n providerId String // 业务 providerId,软关联 AiProvider.providerId(不设外键 cascade,避免 admin 删除丢失用户配置)\n apiKey String? @db.Text // 加密存储 TODO\n baseUrl String?\n enabled Boolean @default(false) // 用户级开关:是否在对话模型选择器中暴露\n models Json? // string[] 用户启用的模型 ID(有序,顺序 = 模型选择器展示顺序)\n customModels Json? // AiModelMeta[] 用户私有的自定义/刷新获取的模型元数据,与 AiProvider.models 取并集按 id 去重\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@unique([userId, providerId])\n @@index([userId])\n @@index([providerId])\n @@map(\"ai_provider_configs\")\n}\n\n// 第三方依赖版本管理(admin 决策是否升级)\n// currentVersion 实时读 monorepo 各 package.json,不存 DB;latestVersion 缓存自 npm registry\nmodel ThirdPartyDependency {\n id String @id @default(cuid())\n name String @unique // npm 包名,如 \"@tiptap/core\" / \"mind-elixir\"\n displayName String? // 展示名(默认取 name)\n description String? @db.Text // 依赖用途说明(admin 可编辑)\n homepage String? // 官网 / 仓库\n category String @default(\"other\") // framework|ui|editor|ai|state|tool|other\n isWatched Boolean @default(true) // 是否置顶「关注列表」\n priority String @default(\"normal\") // high|normal|low\n latestVersion String? // 缓存的 npm registry latest 版本\n latestChangelog String? @db.Text // 最新版本的更新日志(来自 GitHub Releases,markdown)\n lastSyncAt DateTime? // 最后一次成功同步 npm registry 的时间\n notes String? @db.Text // 备注(升级注意事项等)\n sortOrder Int @default(0)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@index([category])\n @@index([isWatched])\n @@map(\"third_party_dependencies\")\n}\n\n// ============ 公共知识库:法律法规 ============\nmodel LegalRegulation {\n id String @id @default(cuid())\n canonicalId String\n title String\n jurisdiction String\n region String?\n country String?\n category String\n issuingAuthority String?\n effectiveDate DateTime?\n summary String? @db.Text\n content String? @db.Text\n sourceUrl String?\n likeCount Int @default(0)\n tags Json @default(\"[]\")\n visibility String @default(\"private\")\n userId String\n isDeleted Boolean @default(false)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@index([canonicalId, visibility])\n @@index([userId, visibility])\n @@index([jurisdiction, category])\n @@map(\"legal_regulations\")\n}\n\nmodel IndustryCompliance {\n id String @id @default(cuid())\n canonicalId String\n title String\n industry String\n regulatoryBody String?\n region String?\n summary String? @db.Text\n content String? @db.Text\n requirements Json @default(\"[]\")\n sourceUrl String?\n likeCount Int @default(0)\n tags Json @default(\"[]\")\n visibility String @default(\"private\")\n userId String\n isDeleted Boolean @default(false)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@index([canonicalId, visibility])\n @@index([userId, visibility])\n @@index([industry])\n @@map(\"industry_compliances\")\n}\n\nmodel DictionaryTerm {\n id String @id @default(cuid())\n canonicalId String\n title String\n industry String\n definition String? @db.Text\n aliases Json @default(\"[]\")\n examples Json @default(\"[]\")\n referenceUrl String?\n tags Json @default(\"[]\")\n visibility String @default(\"private\")\n userId String\n isDeleted Boolean @default(false)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@index([canonicalId, visibility])\n @@index([userId, visibility])\n @@index([title])\n @@map(\"dictionary_terms\")\n}\n\nmodel WebsiteBookmark {\n id String @id @default(cuid())\n canonicalId String\n title String\n url String\n categoryId String?\n summary String? @db.Text\n faviconUrl String?\n faviconSyncedAt DateTime?\n isGithub Boolean @default(false)\n githubOwner String?\n githubRepo String?\n githubStars Int?\n githubLatestVersion String?\n githubVersionDate DateTime?\n githubRepoUpdatedAt DateTime?\n githubSyncedAt DateTime?\n tags Json @default(\"[]\")\n visibility String @default(\"private\")\n userId String\n isDeleted Boolean @default(false)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n category BookmarkCategory? @relation(fields: [categoryId], references: [id], onDelete: SetNull)\n\n @@index([canonicalId, visibility])\n @@index([userId, visibility])\n @@index([categoryId])\n @@index([isGithub])\n @@map(\"website_bookmarks\")\n}\n\nmodel BookmarkCategory {\n id String @id @default(cuid())\n name String\n icon String @default(\"Globe\")\n sortOrder Int @default(0)\n isDefault Boolean @default(false)\n userId String?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User? @relation(fields: [userId], references: [id], onDelete: Cascade)\n bookmarks WebsiteBookmark[]\n\n @@unique([userId, name])\n @@index([userId])\n @@map(\"bookmark_categories\")\n}\n\nmodel KnowledgeShareRecord {\n id String @id @default(cuid())\n entityType String\n canonicalId String\n userId String\n sharedAt DateTime @default(now())\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@unique([entityType, canonicalId, userId])\n @@index([entityType, canonicalId])\n @@map(\"knowledge_share_records\")\n}\n\nmodel ArticleFavorite {\n id String @id @default(cuid())\n entityType String\n entityId String\n userId String\n createdAt DateTime @default(now())\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@unique([entityType, entityId, userId])\n @@index([userId, entityType])\n @@map(\"article_favorites\")\n}\n\n// 需求\nmodel Story {\n id String @id @default(cuid())\n sequenceId Int\n boardOrder Int @default(0)\n identifier String\n projectId String\n project Project @relation(fields: [projectId], references: [id], onDelete: Restrict)\n name String\n description String? @db.Text\n state String @default(\"backlog\")\n priority String @default(\"none\")\n archived Boolean @default(false)\n archivedAt DateTime?\n assigneeId String?\n assignee User? @relation(\"storyAssignee\", fields: [assigneeId], references: [id], onDelete: SetNull)\n startDate DateTime?\n targetDate DateTime?\n createdById String\n createdBy User @relation(\"storyCreator\", fields: [createdById], references: [id])\n updatedById String?\n updatedBy User? @relation(\"storyEditor\", fields: [updatedById], references: [id], onDelete: SetNull)\n labels StoryLabel[]\n activities StoryActivity[]\n comments StoryComment[]\n reactions StoryReaction[]\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n parentId String?\n parent Story? @relation(\"StoryHierarchy\", fields: [parentId], references: [id], onDelete: SetNull)\n children Story[] @relation(\"StoryHierarchy\")\n dependenciesAsSource StoryDependency[] @relation(\"DependencySource\")\n dependenciesAsTarget StoryDependency[] @relation(\"DependencyTarget\")\n links StoryLink[]\n attachments StoryAttachment[]\n linkedPrds StoryPrdLink[] @relation(\"StoryPrdLinks\")\n linkedDocs StoryDocLink[] @relation(\"StoryDocLinks\")\n\n @@unique([identifier])\n @@index([projectId, sequenceId])\n @@index([state])\n @@index([archived])\n @@index([archived, state, createdAt])\n @@index([assigneeId])\n @@index([createdById])\n @@map(\"stories\")\n}\n\n// 全局标签\nmodel Label {\n id String @id @default(cuid())\n name String @unique\n color String @default(\"#6b7280\")\n createdById String\n createdBy User @relation(\"labelCreator\", fields: [createdById], references: [id])\n stories StoryLabel[]\n createdAt DateTime @default(now())\n\n @@map(\"labels\")\n}\n\nmodel StoryLabel {\n storyId String\n labelId String\n story Story @relation(fields: [storyId], references: [id], onDelete: Cascade)\n label Label @relation(fields: [labelId], references: [id], onDelete: Cascade)\n\n @@id([storyId, labelId])\n @@index([labelId])\n @@map(\"story_labels\")\n}\n\nmodel StoryActivity {\n id String @id @default(cuid())\n storyId String\n story Story @relation(fields: [storyId], references: [id], onDelete: Cascade)\n userId String\n user User @relation(\"storyActivityUser\", fields: [userId], references: [id])\n action String\n field String?\n oldValue String? @db.Text\n newValue String? @db.Text\n isAI Boolean @default(false)\n metadata Json?\n createdAt DateTime @default(now())\n\n @@index([storyId, createdAt])\n @@map(\"story_activities\")\n}\n\nmodel SequenceCounter {\n id String @id @default(cuid())\n scope String @unique\n seq Int @default(0)\n\n @@map(\"sequence_counters\")\n}\n\nmodel StoryComment {\n id String @id @default(cuid())\n storyId String\n story Story @relation(fields: [storyId], references: [id], onDelete: Cascade)\n userId String\n user User @relation(\"storyCommentUser\", fields: [userId], references: [id])\n parentId String?\n parent StoryComment? @relation(\"CommentReply\", fields: [parentId], references: [id], onDelete: Cascade)\n replies StoryComment[] @relation(\"CommentReply\")\n content String @db.Text\n reactions CommentReaction[]\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@index([storyId, createdAt])\n @@index([parentId])\n @@map(\"story_comments\")\n}\n\nmodel StoryReaction {\n id String @id @default(cuid())\n storyId String\n story Story @relation(fields: [storyId], references: [id], onDelete: Cascade)\n userId String\n user User @relation(\"storyReactionUser\", fields: [userId], references: [id])\n emoji String\n createdAt DateTime @default(now())\n\n @@unique([storyId, userId, emoji])\n @@index([storyId])\n @@map(\"story_reactions\")\n}\n\nmodel CommentReaction {\n id String @id @default(cuid())\n commentId String\n comment StoryComment @relation(fields: [commentId], references: [id], onDelete: Cascade)\n userId String\n user User @relation(\"commentReactionUser\", fields: [userId], references: [id])\n emoji String\n createdAt DateTime @default(now())\n\n @@unique([commentId, userId, emoji])\n @@index([commentId])\n @@map(\"comment_reactions\")\n}\n\nmodel StoryDependency {\n id String @id @default(cuid())\n sourceId String\n targetId String\n type DependencyType\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n source Story @relation(\"DependencySource\", fields: [sourceId], references: [id], onDelete: Cascade)\n target Story @relation(\"DependencyTarget\", fields: [targetId], references: [id], onDelete: Cascade)\n\n @@unique([sourceId, targetId, type])\n @@index([sourceId])\n @@index([targetId])\n @@map(\"story_dependencies\")\n}\n\nmodel StoryLink {\n id String @id @default(cuid())\n storyId String\n url String\n title String?\n description String?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n story Story @relation(fields: [storyId], references: [id], onDelete: Cascade)\n\n @@index([storyId])\n @@map(\"story_links\")\n}\n\nmodel StoryAttachment {\n id String @id @default(cuid())\n storyId String\n fileName String\n fileSize BigInt\n mimeType String\n storageUrl String\n createdAt DateTime @default(now())\n\n story Story @relation(fields: [storyId], references: [id], onDelete: Cascade)\n\n @@index([storyId])\n @@map(\"story_attachments\")\n}\n\nmodel StoryPrdLink {\n id String @id @default(cuid())\n storyId String\n prdId String\n createdAt DateTime @default(now())\n\n story Story @relation(\"StoryPrdLinks\", fields: [storyId], references: [id], onDelete: Cascade)\n prd PRD @relation(\"PrdStoryLinks\", fields: [prdId], references: [id], onDelete: Cascade)\n\n @@unique([storyId, prdId])\n @@index([storyId])\n @@index([prdId])\n @@map(\"story_prd_links\")\n}\n\nmodel StoryDocLink {\n id String @id @default(cuid())\n storyId String\n docId String\n createdAt DateTime @default(now())\n\n story Story @relation(\"StoryDocLinks\", fields: [storyId], references: [id], onDelete: Cascade)\n doc KnowledgeDocument @relation(\"DocStoryLinks\", fields: [docId], references: [id], onDelete: Cascade)\n\n @@unique([storyId, docId])\n @@index([storyId])\n @@index([docId])\n @@map(\"story_doc_links\")\n}\n\nenum DependencyType {\n BLOCKS\n STARTS_BEFORE\n FINISHES_BEFORE\n}\n\n// 需求模块保存视图(per-user 私有)\nmodel StoryFilterView {\n id String @id @default(cuid())\n userId String\n name String\n description String?\n icon String @default(\"list\")\n projectId String?\n filters Json\n displayOptions Json\n sortOrder Int @default(0)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@index([userId])\n @@map(\"story_filter_views\")\n}\n\n// ==================== 监控可观测性模块 ====================\n\nmodel MonitoringRequestLog {\n id String @id @default(cuid())\n timestamp DateTime @default(now())\n method String @db.VarChar(10)\n path String @db.VarChar(512)\n status Int\n duration Int\n ip String? @db.VarChar(45)\n userAgent String? @db.Text\n\n @@index([timestamp], map: \"idx_request_log_timestamp\")\n @@index([path, timestamp], map: \"idx_request_log_path_ts\")\n @@map(\"monitoring_request_logs\")\n}\n\nmodel MonitoringErrorReport {\n id String @id @default(cuid())\n timestamp DateTime @default(now())\n errorName String @db.VarChar(128)\n errorMessage String @db.Text\n stackTrace String? @db.Text\n count Int @default(1)\n firstSeen DateTime @default(now())\n lastSeen DateTime @default(now())\n context Json @default(\"{}\")\n\n @@index([errorName], map: \"idx_error_report_name\")\n @@index([lastSeen], map: \"idx_error_report_last_seen\")\n @@map(\"monitoring_error_reports\")\n}\n\nmodel MonitoringMetricsSnapshot {\n id String @id @default(cuid())\n recordedAt DateTime @default(now())\n metricName String @db.VarChar(256)\n count Int\n avg Float\n p50 Float\n p95 Float\n p99 Float\n min Float\n max Float\n\n @@index([metricName, recordedAt], map: \"idx_metrics_name_ts\")\n @@map(\"monitoring_metrics_snapshots\")\n}\n\nmodel MonitoringHealthSnapshot {\n id String @id @default(cuid())\n timestamp DateTime @default(now())\n status String @db.VarChar(16)\n uptimeSeconds Float\n memoryUsage Json\n dbStatus String @db.VarChar(16)\n dbLatencyMs Int?\n\n @@index([timestamp], map: \"idx_health_snapshot_ts\")\n @@map(\"monitoring_health_snapshots\")\n}\n\n// ── 子项目 2:托管 AI 与 BYOK 统一层 ──\n\n/// 订阅计划定义(seed 数据)\nmodel Plan {\n id String @id @default(cuid())\n name String @unique\n displayName String\n description String?\n priceMonthly Int @default(0)\n priceYearly Int?\n currency String @default(\"usd\")\n maxSeats Int?\n maxGuestSeats Int?\n maxWorkspaces Int?\n aiQuotaMonthly Int?\n features Json\n isPublic Boolean @default(true)\n sortOrder Int @default(0)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n /// Provider 产品与价格同步(子项目 3 新增)\n /// ⚠ stripeProductId 已删除:Creem 无独立产品概念,一个价格点 = 一个产品\n providerPriceIdUsd String?\n providerPriceIdCny String?\n providerPriceIdUsdYearly String?\n providerPriceIdCnyYearly String?\n\n /// 席位加购(P2 新增):每席位/月单价(分),null = 不可加购\n seatPriceMonthly Int?\n\n /// 席位加购 Provider Price(P2 新增,per-seat/monthly interval)\n providerSeatPriceIdUsd String?\n providerSeatPriceIdCny String?\n\n agentQuota Int?\n skillQuota Int?\n\n subscriptions Subscription[]\n\n @@map(\"plans\")\n}\n\n/// 订阅记录(User 级,一人一订阅)\nmodel Subscription {\n id String @id @default(cuid())\n userId String @unique\n user User @relation(fields: [userId], references: [id])\n planId String\n plan Plan @relation(fields: [planId], references: [id])\n status SubscriptionStatus @default(ACTIVE)\n\n /// 席位加购数量(账号级)。实际上限 = plan.maxSeats + addonSeats。\n addonSeats Int @default(0)\n\n provider String @default(\"creem\")\n providerCustomerId String?\n providerSubscriptionId String? @unique\n providerPriceId String?\n providerSeatSubscriptionId String?\n\n currentPeriodStart DateTime?\n currentPeriodEnd DateTime?\n cancelAtPeriodEnd Boolean @default(false)\n canceledAt DateTime?\n trialEndsAt DateTime?\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n /// 关联发票(子项目 3 新增)\n invoices Invoice[]\n\n @@map(\"subscriptions\")\n}\n\nenum SubscriptionStatus {\n TRIALING\n ACTIVE\n PAST_DUE\n CANCELED\n EXPIRED\n UNPAID\n}\n\n/// 用量记录(按月聚合,用于额度判断)\nmodel UsageRecord {\n id String @id @default(cuid())\n workspaceId String\n workspace Workspace @relation(fields: [workspaceId], references: [id])\n metric UsageMetric\n period String\n count Int @default(0)\n resetAt DateTime\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@unique([workspaceId, metric, period])\n @@index([workspaceId, metric])\n @@map(\"usage_records\")\n}\n\nenum UsageMetric {\n AI_CALL\n STORAGE_MB\n SEAT\n}\n\n/// AI 用量明细(按次扣减 + 成本审计)\nmodel AiUsageLog {\n id String @id @default(cuid())\n workspaceId String\n workspace Workspace @relation(fields: [workspaceId], references: [id])\n userId String\n user User @relation(fields: [userId], references: [id])\n source String @default(\"byok\")\n provider String\n model String\n inputTokens Int @default(0)\n outputTokens Int @default(0)\n costUsd Decimal? @db.Decimal(10, 6)\n success Boolean @default(true)\n errorMessage String?\n durationMs Int?\n\n createdAt DateTime @default(now())\n\n @@index([workspaceId, createdAt])\n @@index([userId, createdAt])\n @@index([workspaceId, source, createdAt])\n @@index([workspaceId, success, createdAt])\n @@map(\"ai_usage_logs\")\n}\n\n// ── 子项目 3:计费与订阅系统 ──\n\n/// 账单记录(Webhook 同步)\nmodel Invoice {\n id String @id @default(cuid())\n subscriptionId String\n subscription Subscription @relation(fields: [subscriptionId], references: [id])\n providerInvoiceId String @unique\n providerEventId String?\n amountDue Int\n amountPaid Int\n currency String @default(\"usd\")\n status String\n pdfUrl String?\n hostedInvoiceUrl String?\n periodStart DateTime\n periodEnd DateTime\n paidAt DateTime?\n\n createdAt DateTime @default(now())\n\n @@index([subscriptionId, createdAt])\n @@map(\"invoices\")\n}\n\n/// Provider Webhook 事件幂等记录\nmodel ProviderEvent {\n id String @id @default(cuid())\n providerEventId String @unique\n type String\n status String @default(\"processing\")\n payload Json?\n errorMessage String?\n processedAt DateTime? @db.Timestamptz\n\n createdAt DateTime @default(now()) @db.Timestamptz\n\n @@index([type, createdAt])\n @@map(\"provider_events\")\n}\n\n// ==================== 子项目 5:企业治理模型 ====================\n\n// 企业版 License(自部署企业版验证)\nmodel LicenseKey {\n id String @id @default(cuid())\n key String @unique\n signature String\n payload Json\n customerId String\n customerName String\n customerEmail String\n plan String @default(\"enterprise\")\n seats Int\n features Json\n issuedAt DateTime @default(now())\n expiresAt DateTime?\n revokedAt DateTime?\n issuedById String?\n issuedBy User? @relation(\"LicenseIssuer\", fields: [issuedById], references: [id])\n activations LicenseActivation[]\n\n @@map(\"license_keys\")\n}\n\nmodel LicenseActivation {\n id String @id @default(cuid())\n licenseId String\n license LicenseKey @relation(fields: [licenseId], references: [id])\n instanceId String @unique\n fingerprint String\n activatedAt DateTime @default(now())\n lastSeenAt DateTime?\n revokedAt DateTime?\n\n @@map(\"license_activations\")\n}\n\n// 审计日志\nmodel AuditLog {\n id String @id @default(cuid())\n workspaceId String?\n workspace Workspace? @relation(fields: [workspaceId], references: [id])\n userId String?\n action String\n resourceType String\n resourceId String?\n metadata Json\n ip String?\n userAgent String?\n createdAt DateTime @default(now())\n\n @@index([workspaceId, createdAt])\n @@index([userId, createdAt])\n @@index([action])\n @@map(\"audit_logs\")\n}\n\n// SSO Provider 配置\nmodel SsoProvider {\n id String @id @default(cuid())\n workspaceId String\n workspace Workspace @relation(fields: [workspaceId], references: [id])\n type String\n name String\n config Json\n domain String?\n enabled Boolean @default(true)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n mappings SsoMapping[]\n\n @@unique([workspaceId, type, domain])\n @@map(\"sso_providers\")\n}\n\nmodel SsoMapping {\n id String @id @default(cuid())\n providerId String\n provider SsoProvider @relation(fields: [providerId], references: [id])\n externalId String\n userId String\n user User @relation(fields: [userId], references: [id])\n email String?\n createdAt DateTime @default(now())\n\n @@unique([providerId, externalId])\n @@map(\"sso_mappings\")\n}\n\n// 自定义角色\nmodel CustomRole {\n id String @id @default(cuid())\n workspaceId String\n workspace Workspace @relation(fields: [workspaceId], references: [id])\n name String\n permissions Json\n isSystem Boolean @default(false)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n assignments RoleAssignment[]\n\n @@unique([workspaceId, name])\n @@map(\"custom_roles\")\n}\n\nmodel RoleAssignment {\n id String @id @default(cuid())\n roleId String\n role CustomRole @relation(fields: [roleId], references: [id])\n userId String\n user User @relation(fields: [userId], references: [id])\n createdAt DateTime @default(now())\n\n @@unique([roleId, userId])\n @@map(\"role_assignments\")\n}\n\n// 合规导出任务\nmodel ComplianceExport {\n id String @id @default(cuid())\n type String\n scope String\n targetId String\n status String @default(\"pending\")\n downloadUrl String?\n expiresAt DateTime?\n error String?\n content String?\n requestedBy String?\n createdAt DateTime @default(now())\n completedAt DateTime?\n\n @@map(\"compliance_exports\")\n}\n\n// P6 用户自定义 Agent(人设/工具/模型/温度/开场白/建议问题/知识库绑定)\nmodel UserAgent {\n id String @id @default(cuid())\n userId String\n name String\n description String?\n avatarEmoji String?\n systemPrompt String @db.Text\n allowedTools Json @default(\"[]\")\n model String?\n temperature Float?\n greeting String? @db.Text\n suggestedPrompts Json?\n knowledgeBaseIds Json @default(\"[]\")\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n isDeleted Boolean @default(false)\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n threads ChatThread[]\n\n @@index([userId])\n @@map(\"user_agents\")\n}\n\n// P6 用户自定义 Skill(斜杠指令模板)\nmodel UserSkill {\n id String @id @default(cuid())\n userId String\n name String\n title String\n template String @db.Text\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n isDeleted Boolean @default(false)\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@unique([userId, name])\n @@map(\"user_skills\")\n}\n\n// 开发者日志(Changelog 条目,agent 自动生成 + admin 手动管理)\nmodel DeveloperLog {\n id String @id @default(cuid())\n date String // \"Aug 23, 2026\"\n year String // \"2026\"\n title String\n desc String @db.Text\n tags Json @default(\"[]\") // [\"feat\", \"design\"]\n commitSha String?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n isDeleted Boolean @default(false)\n\n @@index([year, date])\n @@map(\"developer_logs\")\n}\n\n// 通知(团队邀请、协作请求、系统消息等)\nmodel Notification {\n id String @id @default(cuid())\n userId String\n category String\n type String\n title String\n body String?\n link String?\n readAt DateTime?\n createdAt DateTime @default(now())\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@index([userId, createdAt(sort: Desc)])\n @@index([userId, readAt])\n @@map(\"notifications\")\n}\n\n// 通知偏好(免打扰时段、分类开关)\nmodel NotificationPreference {\n userId String @id\n categories Json\n dndEnabled Boolean @default(false)\n dndStart String @default(\"22:00\")\n dndEnd String @default(\"08:00\")\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@map(\"notification_preferences\")\n}\n",
|
|
24
24
|
"runtimeDataModel": {
|
|
25
25
|
"models": {},
|
|
26
26
|
"enums": {},
|
|
@@ -407,13 +407,3 @@ export type UserSkill = Prisma.UserSkillModel
|
|
|
407
407
|
*
|
|
408
408
|
*/
|
|
409
409
|
export type DeveloperLog = Prisma.DeveloperLogModel
|
|
410
|
-
/**
|
|
411
|
-
* Model Notification
|
|
412
|
-
*
|
|
413
|
-
*/
|
|
414
|
-
export type Notification = Prisma.NotificationModel
|
|
415
|
-
/**
|
|
416
|
-
* Model NotificationPreference
|
|
417
|
-
*
|
|
418
|
-
*/
|
|
419
|
-
export type NotificationPreference = Prisma.NotificationPreferenceModel
|
|
@@ -431,13 +431,3 @@ export type UserSkill = Prisma.UserSkillModel
|
|
|
431
431
|
*
|
|
432
432
|
*/
|
|
433
433
|
export type DeveloperLog = Prisma.DeveloperLogModel
|
|
434
|
-
/**
|
|
435
|
-
* Model Notification
|
|
436
|
-
*
|
|
437
|
-
*/
|
|
438
|
-
export type Notification = Prisma.NotificationModel
|
|
439
|
-
/**
|
|
440
|
-
* Model NotificationPreference
|
|
441
|
-
*
|
|
442
|
-
*/
|
|
443
|
-
export type NotificationPreference = Prisma.NotificationPreferenceModel
|