@allbluecn/database 0.6.0 → 0.9.0

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.
Files changed (103) hide show
  1. package/LICENSE +661 -0
  2. package/dist/get-prisma.d.ts +1 -0
  3. package/dist/get-prisma.js +7 -0
  4. package/generated/browser.ts +85 -0
  5. package/generated/client.ts +85 -0
  6. package/generated/commonInputTypes.ts +106 -46
  7. package/generated/internal/class.ts +174 -4
  8. package/generated/internal/prismaNamespace.ts +1698 -151
  9. package/generated/internal/prismaNamespaceBrowser.ts +279 -7
  10. package/generated/models/AiProviderConfig.ts +100 -1
  11. package/generated/models/AiStreamChunk.ts +1159 -0
  12. package/generated/models/AiUsageLog.ts +91 -31
  13. package/generated/models/Blob.ts +1428 -0
  14. package/generated/models/BusinessAgentBinding.ts +1553 -0
  15. package/generated/models/ChatInterrupt.ts +42 -1
  16. package/generated/models/ChatMessage.ts +58 -29
  17. package/generated/models/ChatPersistenceMeta.ts +1121 -0
  18. package/generated/models/ChatRun.ts +166 -1
  19. package/generated/models/ChatThread.ts +294 -1
  20. package/generated/models/CodeSnippet.ts +1555 -0
  21. package/generated/models/DesktopSetting.ts +1059 -0
  22. package/generated/models/EmailLog.ts +1345 -0
  23. package/generated/models/EmailPreference.ts +1257 -0
  24. package/generated/models/EmailSubscriber.ts +1233 -0
  25. package/generated/models/EmailVerificationToken.ts +1380 -0
  26. package/generated/models/GenerationRun.ts +193 -1
  27. package/generated/models/HarnessPlugin.ts +1677 -0
  28. package/generated/models/HarnessWorkspace.ts +1650 -0
  29. package/generated/models/InvitationCode.ts +65 -9
  30. package/generated/models/NotificationPreference.ts +27 -1
  31. package/generated/models/OAuthProviderConfig.ts +1227 -0
  32. package/generated/models/Plan.ts +115 -1
  33. package/generated/models/SandboxInstance.ts +1277 -0
  34. package/generated/models/SystemPromptTemplate.ts +1583 -0
  35. package/generated/models/SystemPromptVersion.ts +1459 -0
  36. package/generated/models/User.ts +5759 -823
  37. package/generated/models/UserAgent.ts +250 -1
  38. package/generated/models/Workspace.ts +3 -1
  39. package/generated/models/WorkspaceFile.ts +1535 -0
  40. package/generated/models.ts +17 -0
  41. package/generated-sqlite/browser.ts +90 -0
  42. package/generated-sqlite/client.ts +90 -0
  43. package/generated-sqlite/commonInputTypes.ts +192 -78
  44. package/generated-sqlite/internal/class.ts +184 -4
  45. package/generated-sqlite/internal/prismaNamespace.ts +1786 -138
  46. package/generated-sqlite/internal/prismaNamespaceBrowser.ts +291 -7
  47. package/generated-sqlite/models/AiProviderConfig.ts +100 -1
  48. package/generated-sqlite/models/AiStreamChunk.ts +1157 -0
  49. package/generated-sqlite/models/AiUsageLog.ts +91 -31
  50. package/generated-sqlite/models/Blob.ts +1425 -0
  51. package/generated-sqlite/models/BusinessAgentBinding.ts +1549 -0
  52. package/generated-sqlite/models/ChatInterrupt.ts +42 -1
  53. package/generated-sqlite/models/ChatMessage.ts +58 -29
  54. package/generated-sqlite/models/ChatPersistenceMeta.ts +1119 -0
  55. package/generated-sqlite/models/ChatRun.ts +174 -1
  56. package/generated-sqlite/models/ChatThread.ts +293 -1
  57. package/generated-sqlite/models/CodeSnippet.ts +1552 -0
  58. package/generated-sqlite/models/DesktopSetting.ts +1057 -0
  59. package/generated-sqlite/models/EmailLog.ts +1343 -0
  60. package/generated-sqlite/models/EmailPreference.ts +1255 -0
  61. package/generated-sqlite/models/EmailSubscriber.ts +1231 -0
  62. package/generated-sqlite/models/EmailVerificationToken.ts +1377 -0
  63. package/generated-sqlite/models/GenerationRun.ts +193 -1
  64. package/generated-sqlite/models/HarnessPlugin.ts +1674 -0
  65. package/generated-sqlite/models/HarnessWorkspace.ts +1647 -0
  66. package/generated-sqlite/models/InvitationCode.ts +65 -9
  67. package/generated-sqlite/models/NotificationPreference.ts +1313 -0
  68. package/generated-sqlite/models/OAuthProviderConfig.ts +1225 -0
  69. package/generated-sqlite/models/PageVersion.ts +0 -8
  70. package/generated-sqlite/models/Plan.ts +115 -1
  71. package/generated-sqlite/models/SandboxInstance.ts +1283 -0
  72. package/generated-sqlite/models/SystemPromptTemplate.ts +1581 -0
  73. package/generated-sqlite/models/SystemPromptVersion.ts +1456 -0
  74. package/generated-sqlite/models/User.ts +5345 -701
  75. package/generated-sqlite/models/UserAgent.ts +250 -1
  76. package/generated-sqlite/models/Workspace.ts +3 -1
  77. package/generated-sqlite/models/WorkspaceFile.ts +1532 -0
  78. package/generated-sqlite/models.ts +18 -0
  79. package/get-prisma.ts +6 -0
  80. package/index.ts +11 -6
  81. package/migrations/20260911120000_add_pgvector_tables/migration.sql +28 -0
  82. package/migrations/20260911171433_email_auth_invitation/migration.sql +80 -0
  83. package/migrations/20260912032616_email_p4_p8/migration.sql +42 -0
  84. package/migrations/20260914002427_ai_p0_durable_runs_meta/migration.sql +15 -0
  85. package/migrations/20260914041010_ai_p0_interrupt_requested_at/migration.sql +15 -0
  86. package/migrations/20260914041909_ai_p0_message_tool_call_id/migration.sql +2 -0
  87. package/migrations/20260914042448_ai_p0_message_content_json/migration.sql +27 -0
  88. package/migrations/20260914150229_harness_plugin/migration.sql +27 -0
  89. package/migrations/20260914174404_prompt_platform_agents/migration.sql +67 -0
  90. package/migrations/20260915090000_add_memory_facts/migration.sql +22 -0
  91. package/migrations/20260915124417_ai_p3_sandbox_durable/migration.sql +48 -0
  92. package/migrations/20260915150034_sandbox_instance_updatedat_bigint/migration.sql +2 -0
  93. package/migrations/20260915154000_add_code_snippets/migration.sql +31 -0
  94. package/migrations/20260916090000_ai_usage_log_nullable_workspace/migration.sql +10 -0
  95. package/migrations/20260916192752_add_ai_source_mode/migration.sql +13 -0
  96. package/migrations/20260917044512_harness_workspace/migration.sql +47 -0
  97. package/migrations/20260917100000_add_media_plan_limits/migration.sql +3 -0
  98. package/migrations/20260917163433_add_generation_run_linked_target/migration.sql +2 -0
  99. package/migrations/20260920050606_add_blob_table/migration.sql +17 -0
  100. package/migrations/20260920093412_add_byteplus_voice_fields/migration.sql +3 -0
  101. package/package.json +8 -3
  102. package/schema.prisma +413 -99
  103. package/schema.sqlite.prisma +865 -543
@@ -18,39 +18,40 @@ datasource db {
18
18
  model SystemSetting {
19
19
  id String @id @default(cuid())
20
20
  key String @unique
21
- value String
21
+ value String
22
22
  category String @default("general") // 配置分类
23
- desc String? // 说明
23
+ desc String? // 说明
24
24
  createdAt DateTime @default(now())
25
25
  updatedAt DateTime @updatedAt
26
-
26
+
27
27
  @@index([category])
28
28
  @@map("system_settings")
29
29
  }
30
30
 
31
31
  // 用户表
32
32
  model User {
33
- id String @id @default(cuid())
34
- email String @unique
35
- username String @unique
36
- password String
37
- role String @default("USER")
38
- status String @default("ACTIVE")
39
- createdAt DateTime @default(now())
40
- updatedAt DateTime @updatedAt
33
+ id String @id @default(cuid())
34
+ email String @unique
35
+ username String @unique
36
+ password String
37
+ role String @default("USER")
38
+ status String @default("ACTIVE")
39
+ createdAt DateTime @default(now())
40
+ updatedAt DateTime @updatedAt
41
41
  lastLoginAt DateTime?
42
42
 
43
43
  avatarConfig Json?
44
- bgShape String?
45
- bgColor String?
44
+ bgShape String?
45
+ bgColor String?
46
46
 
47
- aiProvider String? // "openrouter" | "openai"
48
- aiApiKey String? // 用户 AI API Key(TODO: 加密存储)
49
- aiModel String? // 默认 "openai/gpt-4o-mini"
50
- locale String? // 用户语言偏好(zh / en),null 表示未设置
47
+ aiProvider String? // "openrouter" | "openai"
48
+ aiApiKey String? // 用户 AI API Key(TODO: 加密存储)
49
+ aiModel String? // 默认 "openai/gpt-4o-mini"
50
+ aiSourceMode String? // 模型来源模式:hosted | local-agent | byok;null = 未选择(默认 byok 行为)
51
+ locale String? // 用户语言偏好(zh / en),null 表示未设置
51
52
 
52
53
  sketchApiToken String?
53
- timezone String? // 用户全局时区,如 "Asia/Shanghai"。null = 浏览器时区
54
+ timezone String? // 用户全局时区,如 "Asia/Shanghai"。null = 浏览器时区
54
55
 
55
56
  /// 用户偏好的计费币种(子项目 3 新增)
56
57
  preferredCurrency String @default("usd")
@@ -58,75 +59,83 @@ model User {
58
59
  /// 用户默认 workspace ID(B3 精确化)
59
60
  defaultWorkspaceId String?
60
61
 
61
- invitationUses InvitationUse[]
62
- loginLogs LoginLog[]
63
- passwordResetTokens PasswordResetToken[]
64
- prds PRD[]
65
- tags Tag[]
66
- knowledgeBases KnowledgeBase[]
67
- knowledgeDocuments KnowledgeDocument[]
68
- knowledgeShares KnowledgeShareRecord[]
69
- legalRegulations LegalRegulation[]
70
- industryCompliances IndustryCompliance[]
71
- dictionaryTerms DictionaryTerm[]
72
- websiteBookmarks WebsiteBookmark[]
73
- bookmarkCategories BookmarkCategory[]
74
- articleFavorites ArticleFavorite[]
75
- anyhubApps AnyHubApp[]
76
- anyhubMarketApps AnyHubMarketApp[]
77
- reviewedAnyhubRecommendations AnyHubRecommendation[] @relation("reviewedAnyhubRecommendations")
78
- anyhubRecommenders AnyHubRecommender[]
79
- prdVersions PRDVersion[]
80
- reviewComments ReviewComment[]
81
- comments Comment[]
82
- commentIgnores CommentIgnore[]
83
- reviews Review[] @relation("reviewer")
84
- designProjects DesignProject[]
85
- chatThreads ChatThread[]
86
- aiProviderConfigs AiProviderConfig[]
87
- agentConversations AgentConversation[]
88
- ownedProjects Project[] @relation("projectOwner")
89
- projectMemberships ProjectMember[]
90
- iterationsCreated Iteration[] @relation("iterationCreator")
91
- storiesCreated Story[] @relation("storyCreator")
92
- storiesAssigned Story[] @relation("storyAssignee")
93
- storiesEdited Story[] @relation("storyEditor")
94
- projectActivities ProjectActivity[]
95
- ownedWorkspaces Workspace[] @relation("workspaceOwner")
96
- workspaceMemberships TeamMembership[] @relation("teamOwner")
97
- teamJoined TeamMembership? @relation("teamMember")
98
- sentInvitations TeamInvitation[] @relation("invitationOwner")
99
- ownedJoinRequests TeamJoinRequest[] @relation("joinRequestOwner")
100
- applicantJoinRequests TeamJoinRequest[] @relation("joinRequestApplicant")
101
- aiUsageLogs AiUsageLog[]
102
- agents UserAgent[]
103
- skills UserSkill[]
104
- subscription Subscription?
105
- createdQuickDocs WorkspaceQuickDoc[]
62
+ invitationUses InvitationUse[]
63
+ loginLogs LoginLog[]
64
+ passwordResetTokens PasswordResetToken[]
65
+ emailVerificationTokens EmailVerificationToken[]
66
+ emailPreference EmailPreference?
67
+ notificationPreference NotificationPreference?
68
+ prds PRD[]
69
+ tags Tag[]
70
+ knowledgeBases KnowledgeBase[]
71
+ knowledgeDocuments KnowledgeDocument[]
72
+ knowledgeShares KnowledgeShareRecord[]
73
+ legalRegulations LegalRegulation[]
74
+ industryCompliances IndustryCompliance[]
75
+ dictionaryTerms DictionaryTerm[]
76
+ websiteBookmarks WebsiteBookmark[]
77
+ bookmarkCategories BookmarkCategory[]
78
+ articleFavorites ArticleFavorite[]
79
+ anyhubApps AnyHubApp[]
80
+ anyhubMarketApps AnyHubMarketApp[]
81
+ reviewedAnyhubRecommendations AnyHubRecommendation[] @relation("reviewedAnyhubRecommendations")
82
+ anyhubRecommenders AnyHubRecommender[]
83
+ prdVersions PRDVersion[]
84
+ reviewComments ReviewComment[]
85
+ comments Comment[]
86
+ commentIgnores CommentIgnore[]
87
+ reviews Review[] @relation("reviewer")
88
+ designProjects DesignProject[]
89
+ chatThreads ChatThread[]
90
+ aiProviderConfigs AiProviderConfig[]
91
+ agentConversations AgentConversation[]
92
+ ownedProjects Project[] @relation("projectOwner")
93
+ projectMemberships ProjectMember[]
94
+ iterationsCreated Iteration[] @relation("iterationCreator")
95
+ storiesCreated Story[] @relation("storyCreator")
96
+ storiesAssigned Story[] @relation("storyAssignee")
97
+ storiesEdited Story[] @relation("storyEditor")
98
+ projectActivities ProjectActivity[]
99
+ ownedWorkspaces Workspace[] @relation("workspaceOwner")
100
+ workspaceMemberships TeamMembership[] @relation("teamOwner")
101
+ teamJoined TeamMembership? @relation("teamMember")
102
+ sentInvitations TeamInvitation[] @relation("invitationOwner")
103
+ ownedJoinRequests TeamJoinRequest[] @relation("joinRequestOwner")
104
+ applicantJoinRequests TeamJoinRequest[] @relation("joinRequestApplicant")
105
+ aiUsageLogs AiUsageLog[]
106
+ agents UserAgent[]
107
+ skills UserSkill[]
108
+ subscription Subscription?
109
+ createdQuickDocs WorkspaceQuickDoc[]
110
+ plugins HarnessPlugin[]
111
+ harnessWorkspaces HarnessWorkspace[]
112
+ agentBindings BusinessAgentBinding[]
113
+ codeSnippets CodeSnippet[]
114
+ blobs Blob[]
106
115
 
107
116
  @@map("users")
108
117
  }
109
118
 
110
119
  // 项目
111
120
  model Project {
112
- id String @id @default(cuid())
113
- displayId String? // 用户层项目ID,全大写字母数字,1-10位
114
- name String
115
- description String?
116
- icon String @default("folder")
117
- timezone String? // 项目时区,null = 跟随用户全局时区
118
- ownerId String
119
- owner User @relation("projectOwner", fields: [ownerId], references: [id])
120
- workspaceId String?
121
- workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: SetNull)
122
- members ProjectMember[]
123
- activities ProjectActivity[]
124
- knowledgeBases ProjectKnowledgeBase[]
125
- iterations Iteration[]
126
- iterationAutoSchedule IterationAutoSchedule?
127
- stories Story[]
128
- createdAt DateTime @default(now())
129
- updatedAt DateTime @updatedAt
121
+ id String @id @default(cuid())
122
+ displayId String? // 用户层项目ID,全大写字母数字,1-10位
123
+ name String
124
+ description String?
125
+ icon String @default("folder")
126
+ timezone String? // 项目时区,null = 跟随用户全局时区
127
+ ownerId String
128
+ owner User @relation("projectOwner", fields: [ownerId], references: [id])
129
+ workspaceId String?
130
+ workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: SetNull)
131
+ members ProjectMember[]
132
+ activities ProjectActivity[]
133
+ knowledgeBases ProjectKnowledgeBase[]
134
+ iterations Iteration[]
135
+ iterationAutoSchedule IterationAutoSchedule?
136
+ stories Story[]
137
+ createdAt DateTime @default(now())
138
+ updatedAt DateTime @updatedAt
130
139
 
131
140
  @@unique([ownerId, displayId])
132
141
  @@index([ownerId])
@@ -152,20 +161,20 @@ model ProjectMember {
152
161
 
153
162
  // 工作空间(项目的上一级容器)
154
163
  model Workspace {
155
- id String @id @default(cuid())
156
- name String
157
- icon String @default("folder")
158
- description String?
159
- pinnedToSidebar Boolean @default(false)
160
- ownerId String
161
- owner User @relation("workspaceOwner", fields: [ownerId], references: [id])
162
- projects Project[]
163
- workspaceKbLinks WorkspaceKnowledgeBase[]
164
- quickDocs WorkspaceQuickDoc[]
165
- usageRecords UsageRecord[]
166
- aiUsageLogs AiUsageLog[]
167
- createdAt DateTime @default(now())
168
- updatedAt DateTime @updatedAt
164
+ id String @id @default(cuid())
165
+ name String
166
+ icon String @default("folder")
167
+ description String?
168
+ pinnedToSidebar Boolean @default(false)
169
+ ownerId String
170
+ owner User @relation("workspaceOwner", fields: [ownerId], references: [id])
171
+ projects Project[]
172
+ workspaceKbLinks WorkspaceKnowledgeBase[]
173
+ quickDocs WorkspaceQuickDoc[]
174
+ usageRecords UsageRecord[]
175
+ aiUsageLogs AiUsageLog[]
176
+ createdAt DateTime @default(now())
177
+ updatedAt DateTime @updatedAt
169
178
 
170
179
  @@index([ownerId])
171
180
  @@map("workspaces")
@@ -173,13 +182,14 @@ model Workspace {
173
182
 
174
183
  // 团队隶属关系
175
184
  model TeamMembership {
176
- id String @id @default(cuid())
177
- ownerId String
178
- owner User @relation("teamOwner", fields: [ownerId], references: [id], onDelete: Cascade)
179
- memberId String
180
- member User @relation("teamMember", fields: [memberId], references: [id], onDelete: Cascade)
181
- seatType String @default("member")
182
- joinedAt DateTime @default(now())
185
+ id String @id @default(cuid())
186
+ ownerId String
187
+ owner User @relation("teamOwner", fields: [ownerId], references: [id], onDelete: Cascade)
188
+ memberId String
189
+ member User @relation("teamMember", fields: [memberId], references: [id], onDelete: Cascade)
190
+ seatType String @default("member")
191
+ joinedAt DateTime @default(now())
192
+
183
193
  @@unique([memberId])
184
194
  @@index([ownerId])
185
195
  @@map("team_memberships")
@@ -187,20 +197,21 @@ model TeamMembership {
187
197
 
188
198
  // 团队邀请
189
199
  model TeamInvitation {
190
- id String @id @default(cuid())
200
+ id String @id @default(cuid())
191
201
  ownerId String
192
- owner User @relation("invitationOwner", fields: [ownerId], references: [id], onDelete: Cascade)
202
+ owner User @relation("invitationOwner", fields: [ownerId], references: [id], onDelete: Cascade)
193
203
  email String?
194
- seatType String @default("member")
195
- token String @unique
196
- channel String @default("email")
197
- status String @default("pending")
204
+ seatType String @default("member")
205
+ token String @unique
206
+ channel String @default("email")
207
+ status String @default("pending")
198
208
  expiresAt DateTime
199
- createdAt DateTime @default(now())
209
+ createdAt DateTime @default(now())
200
210
  acceptedBy String?
201
211
  applicantEmail String?
202
212
  message String?
203
213
  joinRequests TeamJoinRequest[]
214
+
204
215
  @@unique([ownerId, email])
205
216
  @@index([ownerId])
206
217
  @@index([email])
@@ -220,6 +231,7 @@ model TeamJoinRequest {
220
231
  seatType String @default("member")
221
232
  createdAt DateTime @default(now())
222
233
  processedAt DateTime?
234
+
223
235
  @@unique([invitationId, email])
224
236
  @@index([ownerId, status])
225
237
  @@map("team_join_requests")
@@ -232,8 +244,8 @@ model ProjectActivity {
232
244
  project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
233
245
  userId String
234
246
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
235
- action String // created | updated | deleted | member_invited | member_joined | member_removed | role_changed | module_viewed
236
- targetType String? // project | member | requirement | prd | design | testcase | bug | acceptance
247
+ action String // created | updated | deleted | member_invited | member_joined | member_removed | role_changed | module_viewed
248
+ targetType String? // project | member | requirement | prd | design | testcase | bug | acceptance
237
249
  targetId String?
238
250
  metadata Json?
239
251
  createdAt DateTime @default(now())
@@ -243,20 +255,23 @@ model ProjectActivity {
243
255
  }
244
256
 
245
257
  model ChatThread {
246
- id String @id @default(cuid())
247
- userId String
248
- title String?
249
- isArchived Boolean @default(false)
250
- createdAt DateTime @default(now())
251
- updatedAt DateTime @updatedAt
258
+ id String @id @default(cuid())
259
+ userId String
260
+ title String?
261
+ isArchived Boolean @default(false)
262
+ sandboxPolicy String @default("readonly")
263
+ createdAt DateTime @default(now())
264
+ updatedAt DateTime @updatedAt
252
265
 
253
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
266
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
254
267
  messages ChatMessage[]
255
268
  runs ChatRun[]
256
269
  interrupts ChatInterrupt[]
257
270
  generations GenerationRun[]
258
271
  agentId String?
259
- agent UserAgent? @relation(fields: [agentId], references: [id])
272
+ agent UserAgent? @relation(fields: [agentId], references: [id])
273
+ workspaceId String?
274
+ workspace HarnessWorkspace? @relation(fields: [workspaceId], references: [id], onDelete: SetNull)
260
275
 
261
276
  @@index([userId, updatedAt])
262
277
  @@map("chat_threads")
@@ -266,10 +281,11 @@ model ChatMessage {
266
281
  id String @id @default(cuid())
267
282
  threadId String
268
283
  role String
269
- content String
284
+ content Json?
270
285
  parts Json?
271
286
  thinking String?
272
287
  citations Json?
288
+ toolCallId String?
273
289
  createdAt DateTime @default(now())
274
290
 
275
291
  thread ChatThread @relation(fields: [threadId], references: [id], onDelete: Cascade)
@@ -279,15 +295,18 @@ model ChatMessage {
279
295
  }
280
296
 
281
297
  model ChatRun {
282
- id String @id @default(cuid())
283
- threadId String
284
- userId String
285
- status String
286
- startedAt DateTime @default(now())
287
- finishedAt DateTime?
288
- detachedSince DateTime?
289
- usage Json?
290
- error String?
298
+ id String @id @default(cuid())
299
+ threadId String
300
+ userId String
301
+ status String
302
+ startedAt DateTime @default(now())
303
+ finishedAt DateTime?
304
+ detachedSince DateTime?
305
+ usage Json?
306
+ error String?
307
+ sandboxKey String?
308
+ cancelRequested Boolean?
309
+ driverEpoch Int?
291
310
 
292
311
  thread ChatThread @relation(fields: [threadId], references: [id], onDelete: Cascade)
293
312
  interrupts ChatInterrupt[]
@@ -298,19 +317,20 @@ model ChatRun {
298
317
  }
299
318
 
300
319
  model ChatInterrupt {
301
- id String @id @default(cuid())
302
- runId String
303
- threadId String
304
- userId String
305
- kind String
306
- toolName String?
307
- state String
308
- payload Json?
309
- resolution Json?
310
- createdAt DateTime @default(now())
311
- resolvedAt DateTime?
320
+ id String @id @default(cuid())
321
+ runId String
322
+ threadId String
323
+ userId String
324
+ kind String
325
+ toolName String?
326
+ state String
327
+ payload Json?
328
+ resolution Json?
329
+ requestedAt DateTime @default(now())
330
+ createdAt DateTime @default(now())
331
+ resolvedAt DateTime?
312
332
 
313
- run ChatRun @relation(fields: [runId], references: [id], onDelete: Cascade)
333
+ run ChatRun @relation(fields: [runId], references: [id], onDelete: Cascade)
314
334
  thread ChatThread @relation(fields: [threadId], references: [id], onDelete: Cascade)
315
335
 
316
336
  @@index([runId])
@@ -318,8 +338,100 @@ model ChatInterrupt {
318
338
  @@map("chat_interrupts")
319
339
  }
320
340
 
321
- model GenerationRun {
341
+ model ChatPersistenceMeta {
342
+ namespace String
343
+ key String
344
+ value Json
345
+ updatedAt DateTime @updatedAt
346
+
347
+ @@unique([namespace, key])
348
+ @@map("chat_persistence_meta")
349
+ }
350
+
351
+ // dsh(DeepSeek-Harness)兼容插件(设计 v8 ADR 21:插件定义 DB 持久化,运行态随页面)
352
+ model HarnessPlugin {
322
353
  id String @id @default(cuid())
354
+ userId String
355
+ name String
356
+ purpose String
357
+ codeHost String?
358
+ codeClient String?
359
+ // plugin_define 求值后插件经 harness.defineTool 上报的工具定义(JSON Schema 数组)
360
+ tools Json @default(dbgenerated("'[]'"))
361
+ version Int @default(1)
362
+ // defined | running | stopped | error
363
+ status String @default("defined")
364
+ lastError String?
365
+ createdAt DateTime @default(now())
366
+ updatedAt DateTime @updatedAt
367
+ isDeleted Boolean @default(false)
368
+
369
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
370
+
371
+ @@unique([userId, name])
372
+ @@index([userId])
373
+ @@map("harness_plugins")
374
+ }
375
+
376
+ // P2 提示词平台:系统提示词模板(DB 版本化,服务端唯一来源)
377
+ model SystemPromptTemplate {
378
+ id String @id @default(cuid())
379
+ key String @unique
380
+ name String
381
+ description String?
382
+ sections Json @default(dbgenerated("'[]'"))
383
+ variables Json @default(dbgenerated("'[]'"))
384
+ version Int @default(1)
385
+ isActive Boolean @default(true)
386
+ isProtected Boolean @default(false)
387
+ updatedBy String?
388
+ createdAt DateTime @default(now())
389
+ updatedAt DateTime @updatedAt
390
+ versions SystemPromptVersion[]
391
+
392
+ @@map("system_prompt_templates")
393
+ }
394
+
395
+ // P2 提示词平台:系统提示词模板的历史版本快照。
396
+ // 设计取舍:仅快照 sections(真正发给 LLM 的提示词主体);variables 作为
397
+ // 元数据随模板演进不纳入版本管理——回滚只还原提示词文本,变量声明由模板表当前值兜底。
398
+ model SystemPromptVersion {
399
+ id String @id @default(cuid())
400
+ templateId String
401
+ template SystemPromptTemplate @relation(fields: [templateId], references: [id], onDelete: Cascade)
402
+ version Int
403
+ sections Json
404
+ note String?
405
+ createdBy String?
406
+ createdAt DateTime @default(now())
407
+
408
+ @@unique([templateId, version])
409
+ @@map("system_prompt_versions")
410
+ }
411
+
412
+ // P2 异构多智能体:板块 agent 绑定(三级链第①级:板块绑定 > 用户默认 > 系统默认)。
413
+ // 设计取舍:① 硬删(无独立业务生命周期,upsert/deleteMany 管理)而非 isDeleted 软删;
414
+ // ② workspaceId 为跨工作区绑定的预留字段,当前不建 relation——bizKey 已表达业务作用域,
415
+ // 工作区级绑定待 P3 启用时再补 relation + 索引。
416
+ model BusinessAgentBinding {
417
+ id String @id @default(cuid())
418
+ userId String
419
+ bizKey String
420
+ agentId String
421
+ workspaceId String?
422
+ createdAt DateTime @default(now())
423
+ updatedAt DateTime @updatedAt
424
+
425
+ agent UserAgent @relation(fields: [agentId], references: [id], onDelete: Cascade)
426
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
427
+
428
+ @@unique([userId, bizKey])
429
+ @@index([userId])
430
+ @@map("business_agent_bindings")
431
+ }
432
+
433
+ model GenerationRun {
434
+ id String @id @default(cuid())
323
435
  threadId String
324
436
  userId String
325
437
  kind String
@@ -327,9 +439,15 @@ model GenerationRun {
327
439
  input Json?
328
440
  result Json?
329
441
  artifactId String?
442
+ activity String?
443
+ provider String?
444
+ model String?
445
+ artifacts Json?
446
+ usage Json?
330
447
  error String?
331
- startedAt DateTime @default(now())
448
+ startedAt DateTime @default(now())
332
449
  finishedAt DateTime?
450
+ linkedTarget Json?
333
451
 
334
452
  thread ChatThread @relation(fields: [threadId], references: [id], onDelete: Cascade)
335
453
 
@@ -344,80 +462,156 @@ model LoginLog {
344
462
  userId String
345
463
  ip String?
346
464
  userAgent String?
347
- location String? // 地理位置,如 "北京, 中国";开发环境为 "本地"
465
+ location String? // 地理位置,如 "北京, 中国";开发环境为 "本地"
348
466
  success Boolean @default(true)
349
- message String? // 失败原因(中文),成功时为 null
467
+ message String? // 失败原因(中文),成功时为 null
350
468
  createdAt DateTime @default(now())
351
-
352
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
353
-
469
+
470
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
471
+
354
472
  @@map("login_logs")
355
473
  }
356
474
 
357
475
  // 邀请码
358
476
  model InvitationCode {
359
- id String @id @default(cuid())
360
- code String @unique
361
- maxUses Int @default(1)
362
- usedCount Int @default(0)
363
- expiresAt DateTime
364
- createdAt DateTime @default(now())
365
-
366
- uses InvitationUse[]
367
-
477
+ id String @id @default(cuid())
478
+ code String @unique
479
+ maxUses Int @default(1)
480
+ usedCount Int @default(0)
481
+ expiresAt DateTime
482
+ createdAt DateTime @default(now())
483
+ createdById String?
484
+ disabledAt DateTime?
485
+
486
+ uses InvitationUse[]
487
+
368
488
  @@map("invitation_codes")
369
489
  }
370
490
 
371
491
  // 邀请码使用记录
372
492
  model InvitationUse {
373
- id String @id @default(cuid())
374
- codeId String
375
- userId String
376
- usedAt DateTime @default(now())
377
-
378
- code InvitationCode @relation(fields: [codeId], references: [id], onDelete: Cascade)
379
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
380
-
493
+ id String @id @default(cuid())
494
+ codeId String
495
+ userId String
496
+ usedAt DateTime @default(now())
497
+
498
+ code InvitationCode @relation(fields: [codeId], references: [id], onDelete: Cascade)
499
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
500
+
381
501
  @@map("invitation_uses")
382
502
  }
383
503
 
384
504
  // 密码重置令牌
385
505
  model PasswordResetToken {
386
- id String @id @default(cuid())
387
- token String @unique
506
+ id String @id @default(cuid())
507
+ token String @unique
388
508
  userId String
389
509
  expiresAt DateTime
390
- usedAt DateTime?
391
- createdAt DateTime @default(now())
392
-
393
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
394
-
510
+ usedAt DateTime?
511
+ createdAt DateTime @default(now())
512
+
513
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
514
+
395
515
  @@map("password_reset_tokens")
396
516
  }
397
517
 
518
+ // 邮箱验证令牌
519
+ model EmailVerificationToken {
520
+ id String @id @default(cuid())
521
+ token String @unique
522
+ userId String
523
+ expiresAt DateTime
524
+ usedAt DateTime?
525
+ createdAt DateTime @default(now())
526
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
527
+
528
+ @@map("email_verification_tokens")
529
+ }
530
+
531
+ // 出站邮件日志
532
+ model EmailLog {
533
+ id String @id @default(cuid())
534
+ to String
535
+ templateKey String
536
+ category String
537
+ status String
538
+ provider String
539
+ messageId String?
540
+ dedupeKey String? @unique
541
+ error String?
542
+ userId String?
543
+ createdAt DateTime @default(now())
544
+ sentAt DateTime?
545
+
546
+ @@index([to, createdAt])
547
+ @@index([userId, createdAt])
548
+ @@index([status])
549
+ @@map("email_logs")
550
+ }
551
+
552
+ // 用户邮件偏好
553
+ model EmailPreference {
554
+ userId String @id
555
+ unsubscribedAll Boolean @default(false)
556
+ unsubscribedCategories Json @default(dbgenerated("'[]'"))
557
+ suppressed Boolean @default(false)
558
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
559
+
560
+ @@map("email_preferences")
561
+ }
562
+
563
+ // 第三方登录配置(admin 后台维护)
564
+ model OAuthProviderConfig {
565
+ id String @id @default(cuid())
566
+ provider String @unique
567
+ clientId String
568
+ clientSecret String // AES-256-GCM 密文
569
+ enabled Boolean @default(false)
570
+ extra Json?
571
+ createdAt DateTime @default(now())
572
+ updatedAt DateTime @updatedAt
573
+
574
+ @@map("oauth_provider_configs")
575
+ }
576
+
577
+ // 产品更新订阅者(changelog)
578
+ model EmailSubscriber {
579
+ id String @id @default(cuid())
580
+ email String @unique
581
+ locale String @default("zh")
582
+ confirmToken String @unique
583
+ confirmedAt DateTime?
584
+ unsubscribedAt DateTime?
585
+ source String @default("changelog")
586
+ createdAt DateTime @default(now())
587
+
588
+ @@index([confirmedAt, unsubscribedAt])
589
+ @@map("email_subscribers")
590
+ }
591
+
398
592
  // (enum 已移除:SQLite 无原生 enum,Role/UserStatus/IconType/MarketplaceAppStatus/ReviewStatus/ShareStatus 改为 String 存 TEXT)
399
593
 
400
594
  // 知识库
401
595
  model KnowledgeBase {
402
- id String @id @default(cuid())
403
- name String
404
- description String?
405
- icon String @default("notebook")
406
- tags Json @default(dbgenerated("'[]'"))
407
- visibility String @default("private")
408
- userId String
409
- pinnedToSidebar Boolean @default(false)
410
- isDeleted Boolean @default(false)
411
- createdAt DateTime @default(now())
412
- updatedAt DateTime @updatedAt
596
+ id String @id @default(cuid())
597
+ name String
598
+ description String?
599
+ icon String @default("notebook")
600
+ tags Json @default(dbgenerated("'[]'"))
601
+ visibility String @default("private")
602
+ userId String
603
+ pinnedToSidebar Boolean @default(false)
604
+ isDeleted Boolean @default(false)
605
+ createdAt DateTime @default(now())
606
+ updatedAt DateTime @updatedAt
413
607
 
414
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
415
- documents KnowledgeDocument[]
416
- projectLinks ProjectKnowledgeBase[]
417
- workspaceLinks WorkspaceKnowledgeBase[]
608
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
609
+ documents KnowledgeDocument[]
610
+ projectLinks ProjectKnowledgeBase[]
611
+ workspaceLinks WorkspaceKnowledgeBase[]
418
612
 
419
- @@index([userId])
420
- @@map("knowledge_bases")
613
+ @@index([userId])
614
+ @@map("knowledge_bases")
421
615
  }
422
616
 
423
617
  // 项目关联知识库(join 表;关联时仅允许 visibility=team,general 全局可见无需关联,private 跨用户不可读)
@@ -494,10 +688,10 @@ model KnowledgeDocument {
494
688
  createdAt DateTime @default(now())
495
689
  updatedAt DateTime @updatedAt
496
690
 
497
- kb KnowledgeBase @relation(fields: [kbId], references: [id], onDelete: Cascade)
498
- parent KnowledgeDocument? @relation("DocumentTree", fields: [parentId], references: [id], onDelete: SetNull)
499
- children KnowledgeDocument[] @relation("DocumentTree")
500
- creator User @relation(fields: [createdBy], references: [id], onDelete: Cascade)
691
+ kb KnowledgeBase @relation(fields: [kbId], references: [id], onDelete: Cascade)
692
+ parent KnowledgeDocument? @relation("DocumentTree", fields: [parentId], references: [id], onDelete: SetNull)
693
+ children KnowledgeDocument[] @relation("DocumentTree")
694
+ creator User @relation(fields: [createdBy], references: [id], onDelete: Cascade)
501
695
  workspaceQuickDocs WorkspaceQuickDoc[]
502
696
 
503
697
  @@index([kbId])
@@ -508,24 +702,24 @@ model KnowledgeDocument {
508
702
 
509
703
  // PRD 文档表
510
704
  model PRD {
511
- id String @id @default(cuid())
512
- icon String @default("file") // 图标名称
513
- name String // PRD 名称
514
- description String? // 介绍
515
- settings Json? // 文档设置(布局、主题等)
516
- userId String // 所属用户
705
+ id String @id @default(cuid())
706
+ icon String @default("file") // 图标名称
707
+ name String // PRD 名称
708
+ description String? // 介绍
709
+ settings Json? // 文档设置(布局、主题等)
710
+ userId String // 所属用户
517
711
  isDeleted Boolean @default(false)
518
712
  deletedAt DateTime?
519
- createdAt DateTime @default(now())
520
- updatedAt DateTime @updatedAt
713
+ createdAt DateTime @default(now())
714
+ updatedAt DateTime @updatedAt
521
715
 
522
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
523
- pages PRDPage[]
524
- versions PRDVersion[]
525
- reviews Review[]
526
- comments Comment[]
527
- shares Share[]
528
- prdTags PRDTag[]
716
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
717
+ pages PRDPage[]
718
+ versions PRDVersion[]
719
+ reviews Review[]
720
+ comments Comment[]
721
+ shares Share[]
722
+ prdTags PRDTag[]
529
723
  agentConversations AgentConversation[]
530
724
 
531
725
  @@index([userId])
@@ -541,8 +735,8 @@ model AgentConversation {
541
735
  createdAt DateTime @default(now())
542
736
  updatedAt DateTime @updatedAt
543
737
 
544
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
545
- prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)
738
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
739
+ prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)
546
740
  messages AgentMessage[]
547
741
 
548
742
  @@index([userId, prdId])
@@ -553,9 +747,9 @@ model AgentConversation {
553
747
  model AgentMessage {
554
748
  id String @id @default(cuid())
555
749
  conversationId String
556
- role String // "user" | "assistant"
557
- content String // 消息文本
558
- components Json? // AI 生成的组件数据(assistant 消息)
750
+ role String // "user" | "assistant"
751
+ content String // 消息文本
752
+ components Json? // AI 生成的组件数据(assistant 消息)
559
753
  isError Boolean @default(false)
560
754
  createdAt DateTime @default(now())
561
755
 
@@ -567,33 +761,33 @@ model AgentMessage {
567
761
 
568
762
  // 基础组件表(后台维护)
569
763
  model Component {
570
- id String @id @default(cuid())
571
- name String
572
- description String? // 组件描述
573
- type String // "component" | "block" | "template"
574
- category String? // 分类
575
- subCategory String? // 子分类
576
- path String? // 树形分组路径(如 "基础组件/表单/输入框")
764
+ id String @id @default(cuid())
765
+ name String
766
+ description String? // 组件描述
767
+ type String // "component" | "block" | "template"
768
+ category String? // 分类
769
+ subCategory String? // 子分类
770
+ path String? // 树形分组路径(如 "基础组件/表单/输入框")
577
771
  defaultWidth Int @default(200)
578
772
  defaultHeight Int @default(40)
579
- prototypeKey String? // unique key for registry lookup (e.g. "text", "button")
580
- config Json // 属性描述 schema(props定义、slots、events)
581
- defaultProps Json? // 默认属性值
582
- defaultStyle Json? // 默认样式
583
- preview String? // 预览图URL
584
- version Int @default(1)
585
- sortOrder Int @default(0) // 排序权重(越大越前)
586
- source String @default("manual") // "npm" | "file" | "manual"
587
- sourceId String? // npm 包名 / 文件名
588
- isHidden Boolean @default(false) // 隐藏/显示
589
- isDeleted Boolean @default(false)
590
- createdAt DateTime @default(now())
591
- updatedAt DateTime @updatedAt
773
+ prototypeKey String? // unique key for registry lookup (e.g. "text", "button")
774
+ config Json // 属性描述 schema(props定义、slots、events)
775
+ defaultProps Json? // 默认属性值
776
+ defaultStyle Json? // 默认样式
777
+ preview String? // 预览图URL
778
+ version Int @default(1)
779
+ sortOrder Int @default(0) // 排序权重(越大越前)
780
+ source String @default("manual") // "npm" | "file" | "manual"
781
+ sourceId String? // npm 包名 / 文件名
782
+ isHidden Boolean @default(false) // 隐藏/显示
783
+ isDeleted Boolean @default(false)
784
+ createdAt DateTime @default(now())
785
+ updatedAt DateTime @updatedAt
592
786
 
593
- blockItems BlockComponent[] @relation("componentRef")
594
- instances ComponentInstance[] @relation("componentRef")
595
- componentTags ComponentTag[]
596
- tags Json @default(dbgenerated("'[]'"))
787
+ blockItems BlockComponent[] @relation("componentRef")
788
+ instances ComponentInstance[] @relation("componentRef")
789
+ componentTags ComponentTag[]
790
+ tags Json @default(dbgenerated("'[]'"))
597
791
 
598
792
  @@index([type, category])
599
793
  @@index([isDeleted])
@@ -612,8 +806,8 @@ model Block {
612
806
  createdAt DateTime @default(now())
613
807
  updatedAt DateTime @updatedAt
614
808
 
615
- items BlockComponent[]
616
- instances BlockInstance[] @relation("blockRef")
809
+ items BlockComponent[]
810
+ instances BlockInstance[] @relation("blockRef")
617
811
  templateItems TemplateBlock[] @relation("templateBlockRef")
618
812
 
619
813
  @@index([isDeleted])
@@ -622,16 +816,16 @@ model Block {
622
816
 
623
817
  // 区块内组件布局
624
818
  model BlockComponent {
625
- id String @id @default(cuid())
819
+ id String @id @default(cuid())
626
820
  blockId String
627
821
  componentId String
628
- x Float @default(0)
629
- y Float @default(0)
630
- width Float @default(100)
631
- height Float @default(100)
632
- zIndex Int @default(0)
633
- propsOverride Json? // 局部覆写属性
634
- styleOverride Json? // 局部覆写样式
822
+ x Float @default(0)
823
+ y Float @default(0)
824
+ width Float @default(100)
825
+ height Float @default(100)
826
+ zIndex Int @default(0)
827
+ propsOverride Json? // 局部覆写属性
828
+ styleOverride Json? // 局部覆写样式
635
829
 
636
830
  block Block @relation(fields: [blockId], references: [id], onDelete: Cascade)
637
831
  component Component @relation("componentRef", fields: [componentId], references: [id])
@@ -657,12 +851,12 @@ model Template {
657
851
 
658
852
  // 模板内区块排布
659
853
  model TemplateBlock {
660
- id String @id @default(cuid())
854
+ id String @id @default(cuid())
661
855
  templateId String
662
856
  blockId String
663
- order Int @default(0) // 排布顺序
664
- x Float? @default(0)
665
- y Float? @default(0)
857
+ order Int @default(0) // 排布顺序
858
+ x Float? @default(0)
859
+ y Float? @default(0)
666
860
  width Float?
667
861
  height Float?
668
862
 
@@ -676,22 +870,22 @@ model TemplateBlock {
676
870
  model PRDPage {
677
871
  id String @id @default(cuid())
678
872
  prdId String
679
- parentId String? // 父节点,构建树形结构(null = 根级)
873
+ parentId String? // 父节点,构建树形结构(null = 根级)
680
874
  name String
681
- order Int @default(0) // 排序
875
+ order Int @default(0) // 排序
682
876
  type String @default("page") // "page" | "folder"
683
- canvas Json? // 原型画板数据
684
- content Json? // PRD 文档内容
877
+ canvas Json? // 原型画板数据
878
+ content Json? // PRD 文档内容
685
879
  version Int @default(1) // 页面版本号
686
880
  createdAt DateTime @default(now())
687
881
  updatedAt DateTime @updatedAt
688
882
 
689
- prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)
690
- parent PRDPage? @relation("PageHierarchy", fields: [parentId], references: [id], onDelete: Cascade)
691
- children PRDPage[] @relation("PageHierarchy")
883
+ prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)
884
+ parent PRDPage? @relation("PageHierarchy", fields: [parentId], references: [id], onDelete: Cascade)
885
+ children PRDPage[] @relation("PageHierarchy")
692
886
  componentInstances ComponentInstance[]
693
887
  blockInstances BlockInstance[]
694
- pageVersions PageVersion[]
888
+ pageVersions PageVersion[]
695
889
 
696
890
  @@index([prdId, order])
697
891
  @@map("prd_pages")
@@ -699,24 +893,24 @@ model PRDPage {
699
893
 
700
894
  // 组件实例(画布上)
701
895
  model ComponentInstance {
702
- id String @id @default(cuid())
703
- pageId String
704
- componentId String? // null = 已解绑的游离副本
896
+ id String @id @default(cuid())
897
+ pageId String
898
+ componentId String? // null = 已解绑的游离副本
705
899
  blockInstanceId String? // 所属区块实例
706
- name String? // 实例别名
707
- x Float @default(0)
708
- y Float @default(0)
709
- width Float @default(100)
710
- height Float @default(100)
711
- zIndex Int @default(0)
712
- props Json? // 局部覆写属性
713
- style Json? // 局部覆写样式
714
- createdAt DateTime @default(now())
715
- updatedAt DateTime @updatedAt
900
+ name String? // 实例别名
901
+ x Float @default(0)
902
+ y Float @default(0)
903
+ width Float @default(100)
904
+ height Float @default(100)
905
+ zIndex Int @default(0)
906
+ props Json? // 局部覆写属性
907
+ style Json? // 局部覆写样式
908
+ createdAt DateTime @default(now())
909
+ updatedAt DateTime @updatedAt
716
910
 
717
- page PRDPage @relation(fields: [pageId], references: [id], onDelete: Cascade)
718
- component Component? @relation("componentRef", fields: [componentId], references: [id])
719
- blockInstance BlockInstance? @relation(fields: [blockInstanceId], references: [id])
911
+ page PRDPage @relation(fields: [pageId], references: [id], onDelete: Cascade)
912
+ component Component? @relation("componentRef", fields: [componentId], references: [id])
913
+ blockInstance BlockInstance? @relation(fields: [blockInstanceId], references: [id])
720
914
 
721
915
  @@index([pageId])
722
916
  @@map("component_instances")
@@ -724,17 +918,17 @@ model ComponentInstance {
724
918
 
725
919
  // 区块实例(画布上)
726
920
  model BlockInstance {
727
- id String @id @default(cuid())
728
- pageId String
729
- blockId String? // null = 已解绑的游离副本
730
- name String? // 实例别名
731
- x Float @default(0)
732
- y Float @default(0)
733
- width Float @default(400)
734
- height Float @default(300)
735
- zIndex Int @default(0)
736
- props Json? // 局部覆写属性
737
- style Json? // 局部覆写样式
921
+ id String @id @default(cuid())
922
+ pageId String
923
+ blockId String? // null = 已解绑的游离副本
924
+ name String? // 实例别名
925
+ x Float @default(0)
926
+ y Float @default(0)
927
+ width Float @default(400)
928
+ height Float @default(300)
929
+ zIndex Int @default(0)
930
+ props Json? // 局部覆写属性
931
+ style Json? // 局部覆写样式
738
932
  createdAt DateTime @default(now())
739
933
  updatedAt DateTime @updatedAt
740
934
 
@@ -748,42 +942,42 @@ model BlockInstance {
748
942
 
749
943
  // PRD 版本(手动发布创建)
750
944
  model PRDVersion {
751
- id String @id @default(cuid())
945
+ id String @id @default(cuid())
752
946
  prdId String
753
- major Int @default(1)
754
- minor Int @default(0)
755
- patch Int @default(0)
756
- versionLabel String // 如 "v1", "v1.1", "v1.1.1"
757
- parentVersion String? // 上一版本ID(版本链)
758
- pageVersions Json // [{ pageId, pageName, version, canvas, content }]
759
- notes String? // 发版说明
947
+ major Int @default(1)
948
+ minor Int @default(0)
949
+ patch Int @default(0)
950
+ versionLabel String // 如 "v1", "v1.1", "v1.1.1"
951
+ parentVersion String? // 上一版本ID(版本链)
952
+ pageVersions Json // [{ pageId, pageName, version, canvas, content }]
953
+ notes String? // 发版说明
760
954
  userId String
761
- createdAt DateTime @default(now())
955
+ createdAt DateTime @default(now())
762
956
  updatedAt DateTime?
763
957
 
764
- prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)
765
- user User @relation(fields: [userId], references: [id])
766
- reviews Review[]
958
+ prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)
959
+ user User @relation(fields: [userId], references: [id])
960
+ reviews Review[]
767
961
  shareVersions ShareVersion[]
768
962
 
769
- @@index([prdId, createdAt])
770
- @@index([userId])
771
- @@map("prd_versions")
772
- }
963
+ @@index([prdId, createdAt])
964
+ @@index([userId])
965
+ @@map("prd_versions")
966
+ }
773
967
 
774
968
  // 页面版本(独立的页面级别版本历史)
775
969
  model PageVersion {
776
- id String @id @default(cuid())
777
- pageId String
778
- version Int // 整数版本号,自增
779
- notes String? // 版本说明(用户可编辑)
780
- canvas Json? // 原型快照
781
- content Json? // 文档快照
970
+ id String @id @default(cuid())
971
+ pageId String
972
+ version Int // 整数版本号,自增
973
+ notes String? // 版本说明(用户可编辑)
974
+ canvas Json? // 原型快照
975
+ content Json? // 文档快照
782
976
  restoredFromVersion Int? // 从哪个版本号还原而来(null 表示非还原版本)
783
- fromPRDVersionId String? // 来源:从哪个 PRD 版本创建(可选标记)
784
- createdAt DateTime @default(now())
977
+ fromPRDVersionId String? // 来源:从哪个 PRD 版本创建(可选标记)
978
+ createdAt DateTime @default(now())
785
979
 
786
- page PRDPage @relation(fields: [pageId], references: [id], onDelete: Cascade)
980
+ page PRDPage @relation(fields: [pageId], references: [id], onDelete: Cascade)
787
981
 
788
982
  @@index([pageId, createdAt])
789
983
  @@index([pageId, version])
@@ -795,15 +989,15 @@ model Review {
795
989
  id String @id @default(cuid())
796
990
  prdId String
797
991
  versionId String
798
- status String @default("PENDING")
992
+ status String @default("PENDING")
799
993
  reviewerId String?
800
994
  notes String?
801
995
  createdAt DateTime @default(now())
802
996
  completedAt DateTime?
803
997
 
804
- prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)
805
- version PRDVersion @relation(fields: [versionId], references: [id])
806
- reviewer User? @relation("reviewer", fields: [reviewerId], references: [id])
998
+ prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)
999
+ version PRDVersion @relation(fields: [versionId], references: [id])
1000
+ reviewer User? @relation("reviewer", fields: [reviewerId], references: [id])
807
1001
  comments ReviewComment[]
808
1002
 
809
1003
  @@unique([prdId, versionId])
@@ -818,15 +1012,15 @@ model ReviewComment {
818
1012
  id String @id @default(cuid())
819
1013
  reviewId String
820
1014
  userId String
821
- content String
822
- pageId String? // 关联页面
823
- elementId String? // 关联具体元素
824
- parentId String? // 回复上级留言
1015
+ content String
1016
+ pageId String? // 关联页面
1017
+ elementId String? // 关联具体元素
1018
+ parentId String? // 回复上级留言
825
1019
  createdAt DateTime @default(now())
826
1020
 
827
- review Review @relation(fields: [reviewId], references: [id], onDelete: Cascade)
828
- user User @relation(fields: [userId], references: [id])
829
- parent ReviewComment? @relation("ReviewCommentReplies", fields: [parentId], references: [id])
1021
+ review Review @relation(fields: [reviewId], references: [id], onDelete: Cascade)
1022
+ user User @relation(fields: [userId], references: [id])
1023
+ parent ReviewComment? @relation("ReviewCommentReplies", fields: [parentId], references: [id])
830
1024
  replies ReviewComment[] @relation("ReviewCommentReplies")
831
1025
 
832
1026
  @@index([reviewId])
@@ -839,21 +1033,21 @@ model ReviewComment {
839
1033
  model Comment {
840
1034
  id String @id @default(cuid())
841
1035
  prdId String
842
- pageId String? // 可选:针对某页面
843
- elementId String? // 可选:针对某元素(组件/区块实例ID)
1036
+ pageId String? // 可选:针对某页面
1037
+ elementId String? // 可选:针对某元素(组件/区块实例ID)
844
1038
  userId String
845
- content String
846
- parentId String? // 回复上级评论
847
- position Json? // 文本选区位置 { from: number, to: number }
1039
+ content String
1040
+ parentId String? // 回复上级评论
1041
+ position Json? // 文本选区位置 { from: number, to: number }
848
1042
  resolved Boolean @default(false)
849
1043
  createdAt DateTime @default(now())
850
1044
  updatedAt DateTime @updatedAt
851
1045
 
852
- prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)
853
- user User @relation(fields: [userId], references: [id])
854
- parent Comment? @relation("CommentReplies", fields: [parentId], references: [id])
855
- replies Comment[] @relation("CommentReplies")
856
- ignores CommentIgnore[]
1046
+ prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)
1047
+ user User @relation(fields: [userId], references: [id])
1048
+ parent Comment? @relation("CommentReplies", fields: [parentId], references: [id])
1049
+ replies Comment[] @relation("CommentReplies")
1050
+ ignores CommentIgnore[]
857
1051
 
858
1052
  @@index([prdId])
859
1053
  @@index([userId])
@@ -879,18 +1073,18 @@ model CommentIgnore {
879
1073
 
880
1074
  // 分享链接
881
1075
  model Share {
882
- id String @id @default(cuid())
883
- prdId String
884
- token String @unique
885
- type String @default("prd") // "prd" | 预留扩展
886
- status String @default("ACTIVE")
887
- password String? // 加密分享密码(4位,数字+大写+小写字母)
888
- hasPassword Boolean @default(false)
889
- expiresAt DateTime?
890
- createdAt DateTime @default(now())
891
- updatedAt DateTime @updatedAt
1076
+ id String @id @default(cuid())
1077
+ prdId String
1078
+ token String @unique
1079
+ type String @default("prd") // "prd" | 预留扩展
1080
+ status String @default("ACTIVE")
1081
+ password String? // 加密分享密码(4位,数字+大写+小写字母)
1082
+ hasPassword Boolean @default(false)
1083
+ expiresAt DateTime?
1084
+ createdAt DateTime @default(now())
1085
+ updatedAt DateTime @updatedAt
892
1086
 
893
- prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)
1087
+ prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)
894
1088
  shareVersions ShareVersion[]
895
1089
 
896
1090
  @@index([token])
@@ -952,12 +1146,12 @@ model ComponentTag {
952
1146
  }
953
1147
 
954
1148
  model Reference {
955
- id String @id @default(uuid())
956
- sourceModule String
957
- sourceEntityId String
958
- targetModule String
959
- targetEntityId String
960
- createdAt DateTime @default(now())
1149
+ id String @id @default(uuid())
1150
+ sourceModule String
1151
+ sourceEntityId String
1152
+ targetModule String
1153
+ targetEntityId String
1154
+ createdAt DateTime @default(now())
961
1155
 
962
1156
  @@index([sourceModule, sourceEntityId])
963
1157
  @@index([targetModule, targetEntityId])
@@ -969,8 +1163,8 @@ model ShareVersion {
969
1163
  shareId String
970
1164
  versionId String
971
1165
 
972
- share Share @relation(fields: [shareId], references: [id], onDelete: Cascade)
973
- version PRDVersion @relation(fields: [versionId], references: [id], onDelete: Cascade)
1166
+ share Share @relation(fields: [shareId], references: [id], onDelete: Cascade)
1167
+ version PRDVersion @relation(fields: [versionId], references: [id], onDelete: Cascade)
974
1168
 
975
1169
  @@unique([shareId, versionId])
976
1170
  @@index([shareId])
@@ -984,7 +1178,7 @@ model AnyHubApp {
984
1178
  id String @id @default(cuid())
985
1179
  name String @unique
986
1180
  displayName String
987
- description String?
1181
+ description String?
988
1182
  version String @default("0.1.0")
989
1183
  source String
990
1184
  url String?
@@ -998,7 +1192,7 @@ model AnyHubApp {
998
1192
  createdAt DateTime @default(now())
999
1193
  updatedAt DateTime @updatedAt
1000
1194
 
1001
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1195
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1002
1196
  permissions AnyHubPermission[]
1003
1197
 
1004
1198
  @@index([userId])
@@ -1021,26 +1215,26 @@ model AnyHubPermission {
1021
1215
  }
1022
1216
 
1023
1217
  model AnyHubMarketApp {
1024
- id String @id @default(cuid())
1218
+ id String @id @default(cuid())
1025
1219
  name String
1026
1220
  displayName String
1027
- description String?
1221
+ description String?
1028
1222
  entryUrl String
1029
1223
  icon String?
1030
- iconType String @default("ICON")
1224
+ iconType String @default("ICON")
1031
1225
  logo String?
1032
1226
  category String?
1033
- tags String?
1034
- downloads Int @default(0)
1227
+ tags String?
1228
+ downloads Int @default(0)
1035
1229
  capabilities Json
1036
- status String @default("DRAFT")
1230
+ status String @default("DRAFT")
1037
1231
  publishedAt DateTime?
1038
1232
  userId String
1039
- recommendationId String? @unique
1040
- createdAt DateTime @default(now())
1041
- updatedAt DateTime @updatedAt
1233
+ recommendationId String? @unique
1234
+ createdAt DateTime @default(now())
1235
+ updatedAt DateTime @updatedAt
1042
1236
 
1043
- user User @relation(fields: [userId], references: [id])
1237
+ user User @relation(fields: [userId], references: [id])
1044
1238
  recommendation AnyHubRecommendation? @relation("anyhubRecommendation", fields: [recommendationId], references: [id])
1045
1239
 
1046
1240
  @@index([status])
@@ -1052,7 +1246,7 @@ model AnyHubRecommendation {
1052
1246
  githubUrl String @unique
1053
1247
  name String?
1054
1248
  displayName String?
1055
- description String?
1249
+ description String?
1056
1250
  status String @default("pending")
1057
1251
  reviewedBy String?
1058
1252
  reviewedAt DateTime?
@@ -1060,8 +1254,8 @@ model AnyHubRecommendation {
1060
1254
  createdAt DateTime @default(now())
1061
1255
  updatedAt DateTime @updatedAt
1062
1256
 
1063
- marketplaceApp AnyHubMarketApp? @relation("anyhubRecommendation")
1064
- reviewer User? @relation("reviewedAnyhubRecommendations", fields: [reviewedBy], references: [id])
1257
+ marketplaceApp AnyHubMarketApp? @relation("anyhubRecommendation")
1258
+ reviewer User? @relation("reviewedAnyhubRecommendations", fields: [reviewedBy], references: [id])
1065
1259
  recommenders AnyHubRecommender[]
1066
1260
 
1067
1261
  @@index([status])
@@ -1075,43 +1269,43 @@ model AnyHubRecommender {
1075
1269
  createdAt DateTime @default(now())
1076
1270
 
1077
1271
  recommendation AnyHubRecommendation @relation(fields: [recommendationId], references: [id], onDelete: Cascade)
1078
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1272
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1079
1273
 
1080
1274
  @@unique([recommendationId, userId])
1081
1275
  }
1082
1276
 
1083
1277
  // 设计稿
1084
1278
  model DesignProject {
1085
- id String @id @default(cuid())
1086
- name String
1087
- documentId String?
1088
- sketchName String?
1089
- version Int @default(1)
1090
- userId String
1091
- user User @relation(fields: [userId], references: [id])
1092
- artboards Artboard[]
1093
- createdAt DateTime @default(now())
1094
- updatedAt DateTime @updatedAt
1279
+ id String @id @default(cuid())
1280
+ name String
1281
+ documentId String?
1282
+ sketchName String?
1283
+ version Int @default(1)
1284
+ userId String
1285
+ user User @relation(fields: [userId], references: [id])
1286
+ artboards Artboard[]
1287
+ createdAt DateTime @default(now())
1288
+ updatedAt DateTime @updatedAt
1095
1289
 
1096
1290
  @@index([userId])
1097
1291
  @@map("design_projects")
1098
1292
  }
1099
1293
 
1100
1294
  model Artboard {
1101
- id String @id @default(cuid())
1102
- projectId String
1103
- project DesignProject @relation(fields: [projectId], references: [id], onDelete: Cascade)
1104
- name String
1105
- pageName String?
1106
- width Int
1107
- height Int
1108
- pngPath String
1109
- svgPath String?
1110
- annotationJson Json?
1111
- layerCount Int?
1112
- sortOrder Int @default(0)
1113
- createdAt DateTime @default(now())
1114
- exports ArtboardExport[]
1295
+ id String @id @default(cuid())
1296
+ projectId String
1297
+ project DesignProject @relation(fields: [projectId], references: [id], onDelete: Cascade)
1298
+ name String
1299
+ pageName String?
1300
+ width Int
1301
+ height Int
1302
+ pngPath String
1303
+ svgPath String?
1304
+ annotationJson Json?
1305
+ layerCount Int?
1306
+ sortOrder Int @default(0)
1307
+ createdAt DateTime @default(now())
1308
+ exports ArtboardExport[]
1115
1309
 
1116
1310
  @@index([projectId])
1117
1311
  @@map("design_artboards")
@@ -1132,25 +1326,26 @@ model ArtboardExport {
1132
1326
  @@unique([artboardId, layerId, scale])
1133
1327
  @@map("design_artboard_exports")
1134
1328
  }
1329
+
1135
1330
  // AI 服务商元数据(admin 维护)
1136
1331
  model AiProvider {
1137
1332
  id String @id @default(cuid())
1138
1333
  providerId String @unique // 业务标识 "openai" "anthropic",用于 adapter 路由与 AiProviderConfig 软关联
1139
1334
  displayName String
1140
1335
  brandName String
1141
- description String
1336
+ description String
1142
1337
  category String @default("popular") // recommended|popular|local
1143
- adapterKind String // openai|anthropic|gemini|groq|grok|openrouter|ollama|openai-compatible
1338
+ adapterKind String // openai|anthropic|gemini|groq|grok|openrouter|ollama|openai-compatible
1144
1339
  defaultBaseUrl String?
1145
1340
  keyUrl String?
1146
1341
  docsUrl String?
1147
1342
  keyPlaceholder String?
1148
1343
  iconSlug String?
1149
1344
  brandColor String @default("#6467F2")
1150
- badge String? // 卡片角标文案(如「推荐」「热门」「NEW」),admin 可配
1345
+ badge String? // 卡片角标文案(如「推荐」「热门」「NEW」),admin 可配
1151
1346
  isLocal Boolean @default(false)
1152
1347
  enabled Boolean @default(true) // 平台级开关:停用后未配置用户看不到,已配置用户继续可用
1153
- models Json // AiModelMeta[](admin 可编辑)
1348
+ models Json // AiModelMeta[](admin 可编辑)
1154
1349
  sortOrder Int @default(0)
1155
1350
  createdAt DateTime @default(now())
1156
1351
  updatedAt DateTime @updatedAt
@@ -1162,12 +1357,15 @@ model AiProvider {
1162
1357
  model AiProviderConfig {
1163
1358
  id String @id @default(cuid())
1164
1359
  userId String
1165
- providerId String // 业务 providerId,软关联 AiProvider.providerId(不设外键 cascade,避免 admin 删除丢失用户配置)
1166
- apiKey String? // 加密存储 TODO
1360
+ providerId String // 业务 providerId,软关联 AiProvider.providerId(不设外键 cascade,避免 admin 删除丢失用户配置)
1361
+ apiKey String? // 加密存储 TODO
1167
1362
  baseUrl String?
1363
+ voiceApiKey String? // BytePlus Voice 独立 API key(speech/transcription 用,与 Ark apiKey 分开)
1364
+ voiceBaseUrl String? // BytePlus Voice Base URL(默认 fallback 到 baseUrl)
1168
1365
  enabled Boolean @default(false) // 用户级开关:是否在对话模型选择器中暴露
1169
- models Json? // string[] 用户启用的模型 ID(有序,顺序 = 模型选择器展示顺序)
1170
- customModels Json? // AiModelMeta[] 用户私有的自定义/刷新获取的模型元数据,与 AiProvider.models 取并集按 id 去重
1366
+ models Json? // string[] 用户启用的模型 ID(有序,顺序 = 模型选择器展示顺序)
1367
+ customModels Json? // AiModelMeta[] 用户私有的自定义/刷新获取的模型元数据,与 AiProvider.models 取并集按 id 去重
1368
+ agentMeta Json? // 模式2 本地 Agent 元数据:{ binary, resolvedPath, version, auth, workspaceDir, detectedAt };不存任何密钥
1171
1369
  createdAt DateTime @default(now())
1172
1370
  updatedAt DateTime @updatedAt
1173
1371
 
@@ -1182,21 +1380,21 @@ model AiProviderConfig {
1182
1380
  // 第三方依赖版本管理(admin 决策是否升级)
1183
1381
  // currentVersion 实时读 monorepo 各 package.json,不存 DB;latestVersion 缓存自 npm registry
1184
1382
  model ThirdPartyDependency {
1185
- id String @id @default(cuid())
1186
- name String @unique // npm 包名,如 "@tiptap/core" / "mind-elixir"
1187
- displayName String? // 展示名(默认取 name)
1188
- description String? // 依赖用途说明(admin 可编辑)
1189
- homepage String? // 官网 / 仓库
1190
- category String @default("other") // framework|ui|editor|ai|state|tool|other
1191
- isWatched Boolean @default(true) // 是否置顶「关注列表」
1192
- priority String @default("normal") // high|normal|low
1193
- latestVersion String? // 缓存的 npm registry latest 版本
1383
+ id String @id @default(cuid())
1384
+ name String @unique // npm 包名,如 "@tiptap/core" / "mind-elixir"
1385
+ displayName String? // 展示名(默认取 name)
1386
+ description String? // 依赖用途说明(admin 可编辑)
1387
+ homepage String? // 官网 / 仓库
1388
+ category String @default("other") // framework|ui|editor|ai|state|tool|other
1389
+ isWatched Boolean @default(true) // 是否置顶「关注列表」
1390
+ priority String @default("normal") // high|normal|low
1391
+ latestVersion String? // 缓存的 npm registry latest 版本
1194
1392
  latestChangelog String? // 最新版本的更新日志(来自 GitHub Releases,markdown)
1195
- lastSyncAt DateTime? // 最后一次成功同步 npm registry 的时间
1196
- notes String? // 备注(升级注意事项等)
1197
- sortOrder Int @default(0)
1198
- createdAt DateTime @default(now())
1199
- updatedAt DateTime @updatedAt
1393
+ lastSyncAt DateTime? // 最后一次成功同步 npm registry 的时间
1394
+ notes String? // 备注(升级注意事项等)
1395
+ sortOrder Int @default(0)
1396
+ createdAt DateTime @default(now())
1397
+ updatedAt DateTime @updatedAt
1200
1398
 
1201
1399
  @@index([category])
1202
1400
  @@index([isWatched])
@@ -1214,8 +1412,8 @@ model LegalRegulation {
1214
1412
  category String
1215
1413
  issuingAuthority String?
1216
1414
  effectiveDate DateTime?
1217
- summary String?
1218
- content String?
1415
+ summary String?
1416
+ content String?
1219
1417
  sourceUrl String?
1220
1418
  likeCount Int @default(0)
1221
1419
  tags Json @default(dbgenerated("'[]'"))
@@ -1234,23 +1432,23 @@ model LegalRegulation {
1234
1432
  }
1235
1433
 
1236
1434
  model IndustryCompliance {
1237
- id String @id @default(cuid())
1435
+ id String @id @default(cuid())
1238
1436
  canonicalId String
1239
1437
  title String
1240
1438
  industry String
1241
1439
  regulatoryBody String?
1242
1440
  region String?
1243
- summary String?
1244
- content String?
1245
- requirements Json @default(dbgenerated("'[]'"))
1441
+ summary String?
1442
+ content String?
1443
+ requirements Json @default(dbgenerated("'[]'"))
1246
1444
  sourceUrl String?
1247
- likeCount Int @default(0)
1248
- tags Json @default(dbgenerated("'[]'"))
1249
- visibility String @default("private")
1250
- userId String
1251
- isDeleted Boolean @default(false)
1252
- createdAt DateTime @default(now())
1253
- updatedAt DateTime @updatedAt
1445
+ likeCount Int @default(0)
1446
+ tags Json @default(dbgenerated("'[]'"))
1447
+ visibility String @default("private")
1448
+ userId String
1449
+ isDeleted Boolean @default(false)
1450
+ createdAt DateTime @default(now())
1451
+ updatedAt DateTime @updatedAt
1254
1452
 
1255
1453
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1256
1454
 
@@ -1261,20 +1459,20 @@ model IndustryCompliance {
1261
1459
  }
1262
1460
 
1263
1461
  model DictionaryTerm {
1264
- id String @id @default(cuid())
1462
+ id String @id @default(cuid())
1265
1463
  canonicalId String
1266
1464
  title String
1267
1465
  industry String
1268
- definition String?
1269
- aliases Json @default(dbgenerated("'[]'"))
1270
- examples Json @default(dbgenerated("'[]'"))
1466
+ definition String?
1467
+ aliases Json @default(dbgenerated("'[]'"))
1468
+ examples Json @default(dbgenerated("'[]'"))
1271
1469
  referenceUrl String?
1272
- tags Json @default(dbgenerated("'[]'"))
1273
- visibility String @default("private")
1470
+ tags Json @default(dbgenerated("'[]'"))
1471
+ visibility String @default("private")
1274
1472
  userId String
1275
- isDeleted Boolean @default(false)
1276
- createdAt DateTime @default(now())
1277
- updatedAt DateTime @updatedAt
1473
+ isDeleted Boolean @default(false)
1474
+ createdAt DateTime @default(now())
1475
+ updatedAt DateTime @updatedAt
1278
1476
 
1279
1477
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1280
1478
 
@@ -1290,7 +1488,7 @@ model WebsiteBookmark {
1290
1488
  title String
1291
1489
  url String
1292
1490
  categoryId String?
1293
- summary String?
1491
+ summary String?
1294
1492
  faviconUrl String?
1295
1493
  faviconSyncedAt DateTime?
1296
1494
  isGithub Boolean @default(false)
@@ -1308,7 +1506,7 @@ model WebsiteBookmark {
1308
1506
  createdAt DateTime @default(now())
1309
1507
  updatedAt DateTime @updatedAt
1310
1508
 
1311
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1509
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1312
1510
  category BookmarkCategory? @relation(fields: [categoryId], references: [id], onDelete: SetNull)
1313
1511
 
1314
1512
  @@index([canonicalId, visibility])
@@ -1391,12 +1589,15 @@ model Plan {
1391
1589
  providerPriceIdUsdYearly String?
1392
1590
  providerPriceIdCnyYearly String?
1393
1591
 
1394
- seatPriceMonthly Int?
1592
+ seatPriceMonthly Int?
1395
1593
  providerSeatPriceIdUsd String?
1396
1594
  providerSeatPriceIdCny String?
1397
1595
 
1398
- agentQuota Int?
1399
- skillQuota Int?
1596
+ agentQuota Int?
1597
+ skillQuota Int?
1598
+ sandboxMinutesMonthly Int?
1599
+ mediaGenerationsMonthly Int?
1600
+ galleryStorageMb Int?
1400
1601
 
1401
1602
  subscriptions Subscription[]
1402
1603
 
@@ -1405,28 +1606,28 @@ model Plan {
1405
1606
 
1406
1607
  /// 订阅记录(User 级,一人一订阅)
1407
1608
  model Subscription {
1408
- id String @id @default(cuid())
1409
- userId String @unique
1410
- user User @relation(fields: [userId], references: [id])
1411
- planId String
1412
- plan Plan @relation(fields: [planId], references: [id])
1413
- status String @default("ACTIVE")
1414
- addonSeats Int @default(0)
1415
-
1416
- provider String @default("creem")
1417
- providerCustomerId String?
1418
- providerSubscriptionId String? @unique
1419
- providerPriceId String?
1609
+ id String @id @default(cuid())
1610
+ userId String @unique
1611
+ user User @relation(fields: [userId], references: [id])
1612
+ planId String
1613
+ plan Plan @relation(fields: [planId], references: [id])
1614
+ status String @default("ACTIVE")
1615
+ addonSeats Int @default(0)
1616
+
1617
+ provider String @default("creem")
1618
+ providerCustomerId String?
1619
+ providerSubscriptionId String? @unique
1620
+ providerPriceId String?
1420
1621
  providerSeatSubscriptionId String?
1421
1622
 
1422
- currentPeriodStart DateTime?
1423
- currentPeriodEnd DateTime?
1424
- cancelAtPeriodEnd Boolean @default(false)
1425
- canceledAt DateTime?
1426
- trialEndsAt DateTime?
1623
+ currentPeriodStart DateTime?
1624
+ currentPeriodEnd DateTime?
1625
+ cancelAtPeriodEnd Boolean @default(false)
1626
+ canceledAt DateTime?
1627
+ trialEndsAt DateTime?
1427
1628
 
1428
- createdAt DateTime @default(now())
1429
- updatedAt DateTime @updatedAt
1629
+ createdAt DateTime @default(now())
1630
+ updatedAt DateTime @updatedAt
1430
1631
 
1431
1632
  /// 关联发票(子项目 3 新增)
1432
1633
  invoices Invoice[]
@@ -1436,16 +1637,16 @@ model Subscription {
1436
1637
 
1437
1638
  /// 用量记录(按月聚合,用于额度判断)
1438
1639
  model UsageRecord {
1439
- id String @id @default(cuid())
1640
+ id String @id @default(cuid())
1440
1641
  workspaceId String
1441
1642
  workspace Workspace @relation(fields: [workspaceId], references: [id])
1442
1643
  metric String
1443
1644
  period String
1444
- count Int @default(0)
1645
+ count Int @default(0)
1445
1646
  resetAt DateTime
1446
1647
 
1447
- createdAt DateTime @default(now())
1448
- updatedAt DateTime @updatedAt
1648
+ createdAt DateTime @default(now())
1649
+ updatedAt DateTime @updatedAt
1449
1650
 
1450
1651
  @@unique([workspaceId, metric, period])
1451
1652
  @@index([workspaceId, metric])
@@ -1454,22 +1655,23 @@ model UsageRecord {
1454
1655
 
1455
1656
  /// AI 用量明细(按次扣减 + 成本审计)
1456
1657
  model AiUsageLog {
1457
- id String @id @default(cuid())
1458
- workspaceId String
1459
- workspace Workspace @relation(fields: [workspaceId], references: [id])
1658
+ id String @id @default(cuid())
1659
+ workspaceId String?
1660
+ workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: Restrict)
1460
1661
  userId String
1461
- user User @relation(fields: [userId], references: [id])
1462
- source String @default("byok")
1662
+ user User @relation(fields: [userId], references: [id])
1663
+ source String @default("byok")
1664
+ activity String?
1463
1665
  provider String
1464
1666
  model String
1465
- inputTokens Int @default(0)
1466
- outputTokens Int @default(0)
1667
+ inputTokens Int @default(0)
1668
+ outputTokens Int @default(0)
1467
1669
  costUsd String?
1468
- success Boolean @default(true)
1670
+ success Boolean @default(true)
1469
1671
  errorMessage String?
1470
1672
  durationMs Int?
1471
1673
 
1472
- createdAt DateTime @default(now())
1674
+ createdAt DateTime @default(now())
1473
1675
 
1474
1676
  @@index([workspaceId, createdAt])
1475
1677
  @@index([userId, createdAt])
@@ -1482,22 +1684,22 @@ model AiUsageLog {
1482
1684
 
1483
1685
  /// 账单记录(Webhook 同步)
1484
1686
  model Invoice {
1485
- id String @id @default(cuid())
1486
- subscriptionId String
1487
- subscription Subscription @relation(fields: [subscriptionId], references: [id])
1488
- providerInvoiceId String @unique
1489
- providerEventId String?
1490
- amountDue Int
1491
- amountPaid Int
1492
- currency String @default("usd")
1493
- status String
1494
- pdfUrl String?
1495
- hostedInvoiceUrl String?
1496
- periodStart DateTime
1497
- periodEnd DateTime
1498
- paidAt DateTime?
1499
-
1500
- createdAt DateTime @default(now())
1687
+ id String @id @default(cuid())
1688
+ subscriptionId String
1689
+ subscription Subscription @relation(fields: [subscriptionId], references: [id])
1690
+ providerInvoiceId String @unique
1691
+ providerEventId String?
1692
+ amountDue Int
1693
+ amountPaid Int
1694
+ currency String @default("usd")
1695
+ status String
1696
+ pdfUrl String?
1697
+ hostedInvoiceUrl String?
1698
+ periodStart DateTime
1699
+ periodEnd DateTime
1700
+ paidAt DateTime?
1701
+
1702
+ createdAt DateTime @default(now())
1501
1703
 
1502
1704
  @@index([subscriptionId, createdAt])
1503
1705
  @@map("invoices")
@@ -1505,15 +1707,15 @@ model Invoice {
1505
1707
 
1506
1708
  /// Provider Webhook 事件幂等记录
1507
1709
  model ProviderEvent {
1508
- id String @id @default(cuid())
1509
- providerEventId String @unique
1710
+ id String @id @default(cuid())
1711
+ providerEventId String @unique
1510
1712
  type String
1511
- status String @default("processing")
1713
+ status String @default("processing")
1512
1714
  payload Json?
1513
1715
  errorMessage String?
1514
1716
  processedAt DateTime?
1515
1717
 
1516
- createdAt DateTime @default(now())
1718
+ createdAt DateTime @default(now())
1517
1719
 
1518
1720
  @@index([type, createdAt])
1519
1721
  @@map("provider_events")
@@ -1522,17 +1724,17 @@ model ProviderEvent {
1522
1724
  // ==================== 子项目 5:企业治理模型(sqlite 降级版)====================
1523
1725
 
1524
1726
  model LicenseKey {
1525
- id String @id @default(cuid())
1526
- key String @unique
1727
+ id String @id @default(cuid())
1728
+ key String @unique
1527
1729
  signature String
1528
- payload String @default(dbgenerated("'{}'"))
1730
+ payload String @default(dbgenerated("'{}'"))
1529
1731
  customerId String
1530
1732
  customerName String
1531
1733
  customerEmail String
1532
- plan String @default("enterprise")
1734
+ plan String @default("enterprise")
1533
1735
  seats Int
1534
- features String @default(dbgenerated("'{}'"))
1535
- issuedAt DateTime @default(now())
1736
+ features String @default(dbgenerated("'{}'"))
1737
+ issuedAt DateTime @default(now())
1536
1738
  expiresAt DateTime?
1537
1739
  revokedAt DateTime?
1538
1740
  issuedById String?
@@ -1541,11 +1743,11 @@ model LicenseKey {
1541
1743
  }
1542
1744
 
1543
1745
  model LicenseActivation {
1544
- id String @id @default(cuid())
1746
+ id String @id @default(cuid())
1545
1747
  licenseId String
1546
- instanceId String @unique
1748
+ instanceId String @unique
1547
1749
  fingerprint String
1548
- activatedAt DateTime @default(now())
1750
+ activatedAt DateTime @default(now())
1549
1751
  lastSeenAt DateTime?
1550
1752
  revokedAt DateTime?
1551
1753
 
@@ -1571,50 +1773,50 @@ model AuditLog {
1571
1773
  }
1572
1774
 
1573
1775
  model SsoProvider {
1574
- id String @id @default(cuid())
1575
- workspaceId String
1576
- type String
1577
- name String
1578
- config String @default(dbgenerated("'{}'"))
1579
- domain String?
1580
- enabled Boolean @default(true)
1581
- createdAt DateTime @default(now())
1582
- updatedAt DateTime @updatedAt
1776
+ id String @id @default(cuid())
1777
+ workspaceId String
1778
+ type String
1779
+ name String
1780
+ config String @default(dbgenerated("'{}'"))
1781
+ domain String?
1782
+ enabled Boolean @default(true)
1783
+ createdAt DateTime @default(now())
1784
+ updatedAt DateTime @updatedAt
1583
1785
 
1584
1786
  @@unique([workspaceId, type, domain])
1585
1787
  @@map("sso_providers")
1586
1788
  }
1587
1789
 
1588
1790
  model SsoMapping {
1589
- id String @id @default(cuid())
1791
+ id String @id @default(cuid())
1590
1792
  providerId String
1591
1793
  externalId String
1592
1794
  userId String
1593
1795
  email String?
1594
- createdAt DateTime @default(now())
1796
+ createdAt DateTime @default(now())
1595
1797
 
1596
1798
  @@unique([providerId, externalId])
1597
1799
  @@map("sso_mappings")
1598
1800
  }
1599
1801
 
1600
1802
  model CustomRole {
1601
- id String @id @default(cuid())
1803
+ id String @id @default(cuid())
1602
1804
  workspaceId String
1603
1805
  name String
1604
- permissions String @default(dbgenerated("'{}'"))
1605
- isSystem Boolean @default(false)
1606
- createdAt DateTime @default(now())
1607
- updatedAt DateTime @updatedAt
1806
+ permissions String @default(dbgenerated("'{}'"))
1807
+ isSystem Boolean @default(false)
1808
+ createdAt DateTime @default(now())
1809
+ updatedAt DateTime @updatedAt
1608
1810
 
1609
1811
  @@unique([workspaceId, name])
1610
1812
  @@map("custom_roles")
1611
1813
  }
1612
1814
 
1613
1815
  model RoleAssignment {
1614
- id String @id @default(cuid())
1816
+ id String @id @default(cuid())
1615
1817
  roleId String
1616
1818
  userId String
1617
- createdAt DateTime @default(now())
1819
+ createdAt DateTime @default(now())
1618
1820
 
1619
1821
  @@unique([roleId, userId])
1620
1822
  @@map("role_assignments")
@@ -1654,9 +1856,12 @@ model UserAgent {
1654
1856
  createdAt DateTime @default(now())
1655
1857
  updatedAt DateTime @updatedAt
1656
1858
  isDeleted Boolean @default(false)
1859
+ isDefault Boolean @default(false)
1860
+ harnessKind String?
1657
1861
 
1658
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1659
- threads ChatThread[]
1862
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1863
+ threads ChatThread[]
1864
+ agentBindings BusinessAgentBinding[]
1660
1865
 
1661
1866
  @@index([userId])
1662
1867
  @@map("user_agents")
@@ -1698,33 +1903,33 @@ model DeveloperLog {
1698
1903
 
1699
1904
  // 需求(简化版,与 psql schema 对齐)
1700
1905
  model Story {
1701
- id String @id @default(cuid())
1906
+ id String @id @default(cuid())
1702
1907
  sequenceId Int
1703
- boardOrder Int @default(0)
1908
+ boardOrder Int @default(0)
1704
1909
  identifier String
1705
1910
  projectId String
1706
- project Project @relation(fields: [projectId], references: [id], onDelete: Restrict)
1911
+ project Project @relation(fields: [projectId], references: [id], onDelete: Restrict)
1707
1912
  name String
1708
1913
  description String?
1709
- state String @default("backlog")
1710
- priority String @default("none")
1711
- archived Boolean @default(false)
1914
+ state String @default("backlog")
1915
+ priority String @default("none")
1916
+ archived Boolean @default(false)
1712
1917
  archivedAt DateTime?
1713
1918
  assigneeId String?
1714
- assignee User? @relation("storyAssignee", fields: [assigneeId], references: [id], onDelete: SetNull)
1919
+ assignee User? @relation("storyAssignee", fields: [assigneeId], references: [id], onDelete: SetNull)
1715
1920
  startDate DateTime?
1716
1921
  targetDate DateTime?
1717
1922
  createdById String
1718
- createdBy User @relation("storyCreator", fields: [createdById], references: [id])
1923
+ createdBy User @relation("storyCreator", fields: [createdById], references: [id])
1719
1924
  updatedById String?
1720
- updatedBy User? @relation("storyEditor", fields: [updatedById], references: [id], onDelete: SetNull)
1925
+ updatedBy User? @relation("storyEditor", fields: [updatedById], references: [id], onDelete: SetNull)
1721
1926
  parentId String?
1722
- parent Story? @relation("StoryHierarchy", fields: [parentId], references: [id], onDelete: SetNull)
1723
- children Story[] @relation("StoryHierarchy")
1927
+ parent Story? @relation("StoryHierarchy", fields: [parentId], references: [id], onDelete: SetNull)
1928
+ children Story[] @relation("StoryHierarchy")
1724
1929
  iterationId String?
1725
1930
  iteration Iteration? @relation(fields: [iterationId], references: [id], onDelete: SetNull)
1726
- createdAt DateTime @default(now())
1727
- updatedAt DateTime @updatedAt
1931
+ createdAt DateTime @default(now())
1932
+ updatedAt DateTime @updatedAt
1728
1933
 
1729
1934
  @@unique([projectId, identifier])
1730
1935
  @@index([projectId, sequenceId])
@@ -1760,16 +1965,133 @@ model Iteration {
1760
1965
 
1761
1966
  // 迭代自动排期配置(一项目一行)
1762
1967
  model IterationAutoSchedule {
1763
- projectId String @id
1764
- project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
1765
- enabled Boolean @default(false)
1766
- title String @default("迭代")
1767
- durationDays Int @default(14)
1768
- cooldownDays Int @default(0)
1968
+ projectId String @id
1969
+ project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
1970
+ enabled Boolean @default(false)
1971
+ title String @default("迭代")
1972
+ durationDays Int @default(14)
1973
+ cooldownDays Int @default(0)
1769
1974
  startsOn DateTime
1770
- futureCount Int @default(2)
1771
- autoRollover Boolean @default(false)
1772
- lastSeq Int @default(0)
1975
+ futureCount Int @default(2)
1976
+ autoRollover Boolean @default(false)
1977
+ lastSeq Int @default(0)
1773
1978
 
1774
1979
  @@map("iteration_auto_schedules")
1775
1980
  }
1981
+
1982
+ // 通知偏好(免打扰时段、分类开关)
1983
+ model NotificationPreference {
1984
+ userId String @id
1985
+ categories Json
1986
+ emailCategories Json @default(dbgenerated("'{}'"))
1987
+ dndEnabled Boolean @default(false)
1988
+ dndStart String @default("22:00")
1989
+ dndEnd String @default("08:00")
1990
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1991
+
1992
+ @@map("notification_preferences")
1993
+ }
1994
+
1995
+ // 编排模式可复用片段:用户保存的跨请求编排逻辑。运行时经 getSnippetBindings
1996
+ // 暴露为 snippet_<name> 绑定,片段函数体在嵌套沙箱内执行并可调用 external_* 工具。
1997
+ model CodeSnippet {
1998
+ id String @id @default(cuid())
1999
+ userId String
2000
+ name String
2001
+ title String
2002
+ description String
2003
+ params Json @default(dbgenerated("'{}'"))
2004
+ code String
2005
+ enabled Boolean @default(true)
2006
+ createdAt DateTime @default(now())
2007
+ updatedAt DateTime @updatedAt
2008
+ isDeleted Boolean @default(false)
2009
+
2010
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
2011
+
2012
+ @@unique([userId, name])
2013
+ @@index([userId, enabled, isDeleted])
2014
+ @@map("code_snippets")
2015
+ }
2016
+
2017
+ model SandboxInstance {
2018
+ key String @id
2019
+ provider String
2020
+ providerSandboxId String
2021
+ latestSnapshotId String?
2022
+ threadId String
2023
+ latestRunId String?
2024
+ updatedAt BigInt
2025
+ createdAt DateTime @default(now())
2026
+
2027
+ @@index([threadId])
2028
+ @@map("sandbox_instances")
2029
+ }
2030
+
2031
+ model AiStreamChunk {
2032
+ id BigInt @id @default(autoincrement())
2033
+ runId String
2034
+ chunk Json
2035
+ createdAt DateTime @default(now())
2036
+
2037
+ @@index([runId, id])
2038
+ @@map("ai_stream_chunks")
2039
+ }
2040
+
2041
+ model DesktopSetting {
2042
+ key String @id // "aiSourceMode" | "localAgentConfig"
2043
+ value Json
2044
+
2045
+ @@map("desktop_settings")
2046
+ }
2047
+
2048
+ /// Harness 工作区(云端持久化文件区 + 业务数据视图入口)
2049
+ model HarnessWorkspace {
2050
+ id String @id @default(cuid())
2051
+ name String
2052
+ ownerId String
2053
+ kind String @default("cloud") // "cloud" | "local-meta"(本地挂载只存元数据)
2054
+ createdAt DateTime @default(now())
2055
+ updatedAt DateTime @updatedAt
2056
+
2057
+ owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade)
2058
+ files WorkspaceFile[]
2059
+ threads ChatThread[]
2060
+
2061
+ @@index([ownerId, updatedAt])
2062
+ @@map("harness_workspaces")
2063
+ }
2064
+
2065
+ /// 工作区文件(上传文件 + AI 生成物 + 沙箱产出)
2066
+ model WorkspaceFile {
2067
+ id String @id @default(cuid())
2068
+ workspaceId String
2069
+ path String // 相对路径,如 "src/index.ts"
2070
+ mimeType String @default("application/octet-stream")
2071
+ size Int @default(0)
2072
+ content String? // sqlite 无 @db.Text,降级为普通 String
2073
+ source String @default("upload") // "upload" | "ai-generated" | "sandbox"
2074
+ createdAt DateTime @default(now())
2075
+ updatedAt DateTime @updatedAt
2076
+
2077
+ workspace HarnessWorkspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
2078
+
2079
+ @@unique([workspaceId, path])
2080
+ @@index([workspaceId])
2081
+ @@map("workspace_files")
2082
+ }
2083
+
2084
+ // AI 附件二进制存储(P5 Wave 2)
2085
+ model Blob {
2086
+ id String @id @default(cuid())
2087
+ mimeType String
2088
+ bytes Bytes
2089
+ size Int
2090
+ userId String
2091
+ createdAt DateTime @default(now())
2092
+
2093
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
2094
+
2095
+ @@index([userId])
2096
+ @@map("blobs")
2097
+ }