@allbluecn/database 0.8.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 (88) 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 +60 -0
  5. package/generated/client.ts +60 -0
  6. package/generated/commonInputTypes.ts +106 -46
  7. package/generated/internal/class.ts +124 -4
  8. package/generated/internal/prismaNamespace.ts +1121 -25
  9. package/generated/internal/prismaNamespaceBrowser.ts +202 -6
  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/GenerationRun.ts +193 -1
  23. package/generated/models/HarnessPlugin.ts +1677 -0
  24. package/generated/models/HarnessWorkspace.ts +1650 -0
  25. package/generated/models/InvitationCode.ts +0 -8
  26. package/generated/models/Plan.ts +115 -1
  27. package/generated/models/SandboxInstance.ts +1277 -0
  28. package/generated/models/SystemPromptTemplate.ts +1583 -0
  29. package/generated/models/SystemPromptVersion.ts +1459 -0
  30. package/generated/models/User.ts +4524 -866
  31. package/generated/models/UserAgent.ts +250 -1
  32. package/generated/models/Workspace.ts +3 -1
  33. package/generated/models/WorkspaceFile.ts +1535 -0
  34. package/generated/models.ts +12 -0
  35. package/generated-sqlite/browser.ts +60 -0
  36. package/generated-sqlite/client.ts +60 -0
  37. package/generated-sqlite/commonInputTypes.ts +192 -78
  38. package/generated-sqlite/internal/class.ts +124 -4
  39. package/generated-sqlite/internal/prismaNamespace.ts +1135 -25
  40. package/generated-sqlite/internal/prismaNamespaceBrowser.ts +202 -6
  41. package/generated-sqlite/models/AiProviderConfig.ts +100 -1
  42. package/generated-sqlite/models/AiStreamChunk.ts +1157 -0
  43. package/generated-sqlite/models/AiUsageLog.ts +91 -31
  44. package/generated-sqlite/models/Blob.ts +1425 -0
  45. package/generated-sqlite/models/BusinessAgentBinding.ts +1549 -0
  46. package/generated-sqlite/models/ChatInterrupt.ts +42 -1
  47. package/generated-sqlite/models/ChatMessage.ts +58 -29
  48. package/generated-sqlite/models/ChatPersistenceMeta.ts +1119 -0
  49. package/generated-sqlite/models/ChatRun.ts +174 -1
  50. package/generated-sqlite/models/ChatThread.ts +293 -1
  51. package/generated-sqlite/models/CodeSnippet.ts +1552 -0
  52. package/generated-sqlite/models/DesktopSetting.ts +1057 -0
  53. package/generated-sqlite/models/GenerationRun.ts +193 -1
  54. package/generated-sqlite/models/HarnessPlugin.ts +1674 -0
  55. package/generated-sqlite/models/HarnessWorkspace.ts +1647 -0
  56. package/generated-sqlite/models/InvitationCode.ts +0 -8
  57. package/generated-sqlite/models/PageVersion.ts +0 -8
  58. package/generated-sqlite/models/Plan.ts +115 -1
  59. package/generated-sqlite/models/SandboxInstance.ts +1283 -0
  60. package/generated-sqlite/models/SystemPromptTemplate.ts +1581 -0
  61. package/generated-sqlite/models/SystemPromptVersion.ts +1456 -0
  62. package/generated-sqlite/models/User.ts +3778 -708
  63. package/generated-sqlite/models/UserAgent.ts +250 -1
  64. package/generated-sqlite/models/Workspace.ts +3 -1
  65. package/generated-sqlite/models/WorkspaceFile.ts +1532 -0
  66. package/generated-sqlite/models.ts +12 -0
  67. package/get-prisma.ts +6 -0
  68. package/index.ts +11 -6
  69. package/migrations/20260914002427_ai_p0_durable_runs_meta/migration.sql +15 -0
  70. package/migrations/20260914041010_ai_p0_interrupt_requested_at/migration.sql +15 -0
  71. package/migrations/20260914041909_ai_p0_message_tool_call_id/migration.sql +2 -0
  72. package/migrations/20260914042448_ai_p0_message_content_json/migration.sql +27 -0
  73. package/migrations/20260914150229_harness_plugin/migration.sql +27 -0
  74. package/migrations/20260914174404_prompt_platform_agents/migration.sql +67 -0
  75. package/migrations/20260915090000_add_memory_facts/migration.sql +22 -0
  76. package/migrations/20260915124417_ai_p3_sandbox_durable/migration.sql +48 -0
  77. package/migrations/20260915150034_sandbox_instance_updatedat_bigint/migration.sql +2 -0
  78. package/migrations/20260915154000_add_code_snippets/migration.sql +31 -0
  79. package/migrations/20260916090000_ai_usage_log_nullable_workspace/migration.sql +10 -0
  80. package/migrations/20260916192752_add_ai_source_mode/migration.sql +13 -0
  81. package/migrations/20260917044512_harness_workspace/migration.sql +47 -0
  82. package/migrations/20260917100000_add_media_plan_limits/migration.sql +3 -0
  83. package/migrations/20260917163433_add_generation_run_linked_target/migration.sql +2 -0
  84. package/migrations/20260920050606_add_blob_table/migration.sql +17 -0
  85. package/migrations/20260920093412_add_byteplus_voice_fields/migration.sql +3 -0
  86. package/package.json +8 -3
  87. package/schema.prisma +321 -88
  88. package/schema.sqlite.prisma +779 -546
@@ -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,78 +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
- emailVerificationTokens EmailVerificationToken[]
65
- emailPreference EmailPreference?
66
- notificationPreference NotificationPreference?
67
- prds PRD[]
68
- tags Tag[]
69
- knowledgeBases KnowledgeBase[]
70
- knowledgeDocuments KnowledgeDocument[]
71
- knowledgeShares KnowledgeShareRecord[]
72
- legalRegulations LegalRegulation[]
73
- industryCompliances IndustryCompliance[]
74
- dictionaryTerms DictionaryTerm[]
75
- websiteBookmarks WebsiteBookmark[]
76
- bookmarkCategories BookmarkCategory[]
77
- articleFavorites ArticleFavorite[]
78
- anyhubApps AnyHubApp[]
79
- anyhubMarketApps AnyHubMarketApp[]
80
- reviewedAnyhubRecommendations AnyHubRecommendation[] @relation("reviewedAnyhubRecommendations")
81
- anyhubRecommenders AnyHubRecommender[]
82
- prdVersions PRDVersion[]
83
- reviewComments ReviewComment[]
84
- comments Comment[]
85
- commentIgnores CommentIgnore[]
86
- reviews Review[] @relation("reviewer")
87
- designProjects DesignProject[]
88
- chatThreads ChatThread[]
89
- aiProviderConfigs AiProviderConfig[]
90
- agentConversations AgentConversation[]
91
- ownedProjects Project[] @relation("projectOwner")
92
- projectMemberships ProjectMember[]
93
- iterationsCreated Iteration[] @relation("iterationCreator")
94
- storiesCreated Story[] @relation("storyCreator")
95
- storiesAssigned Story[] @relation("storyAssignee")
96
- storiesEdited Story[] @relation("storyEditor")
97
- projectActivities ProjectActivity[]
98
- ownedWorkspaces Workspace[] @relation("workspaceOwner")
99
- workspaceMemberships TeamMembership[] @relation("teamOwner")
100
- teamJoined TeamMembership? @relation("teamMember")
101
- sentInvitations TeamInvitation[] @relation("invitationOwner")
102
- ownedJoinRequests TeamJoinRequest[] @relation("joinRequestOwner")
103
- applicantJoinRequests TeamJoinRequest[] @relation("joinRequestApplicant")
104
- aiUsageLogs AiUsageLog[]
105
- agents UserAgent[]
106
- skills UserSkill[]
107
- subscription Subscription?
108
- 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[]
109
115
 
110
116
  @@map("users")
111
117
  }
112
118
 
113
119
  // 项目
114
120
  model Project {
115
- id String @id @default(cuid())
116
- displayId String? // 用户层项目ID,全大写字母数字,1-10位
117
- name String
118
- description String?
119
- icon String @default("folder")
120
- timezone String? // 项目时区,null = 跟随用户全局时区
121
- ownerId String
122
- owner User @relation("projectOwner", fields: [ownerId], references: [id])
123
- workspaceId String?
124
- workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: SetNull)
125
- members ProjectMember[]
126
- activities ProjectActivity[]
127
- knowledgeBases ProjectKnowledgeBase[]
128
- iterations Iteration[]
129
- iterationAutoSchedule IterationAutoSchedule?
130
- stories Story[]
131
- createdAt DateTime @default(now())
132
- 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
133
139
 
134
140
  @@unique([ownerId, displayId])
135
141
  @@index([ownerId])
@@ -155,20 +161,20 @@ model ProjectMember {
155
161
 
156
162
  // 工作空间(项目的上一级容器)
157
163
  model Workspace {
158
- id String @id @default(cuid())
159
- name String
160
- icon String @default("folder")
161
- description String?
162
- pinnedToSidebar Boolean @default(false)
163
- ownerId String
164
- owner User @relation("workspaceOwner", fields: [ownerId], references: [id])
165
- projects Project[]
166
- workspaceKbLinks WorkspaceKnowledgeBase[]
167
- quickDocs WorkspaceQuickDoc[]
168
- usageRecords UsageRecord[]
169
- aiUsageLogs AiUsageLog[]
170
- createdAt DateTime @default(now())
171
- 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
172
178
 
173
179
  @@index([ownerId])
174
180
  @@map("workspaces")
@@ -176,13 +182,14 @@ model Workspace {
176
182
 
177
183
  // 团队隶属关系
178
184
  model TeamMembership {
179
- id String @id @default(cuid())
180
- ownerId String
181
- owner User @relation("teamOwner", fields: [ownerId], references: [id], onDelete: Cascade)
182
- memberId String
183
- member User @relation("teamMember", fields: [memberId], references: [id], onDelete: Cascade)
184
- seatType String @default("member")
185
- 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
+
186
193
  @@unique([memberId])
187
194
  @@index([ownerId])
188
195
  @@map("team_memberships")
@@ -190,20 +197,21 @@ model TeamMembership {
190
197
 
191
198
  // 团队邀请
192
199
  model TeamInvitation {
193
- id String @id @default(cuid())
200
+ id String @id @default(cuid())
194
201
  ownerId String
195
- owner User @relation("invitationOwner", fields: [ownerId], references: [id], onDelete: Cascade)
202
+ owner User @relation("invitationOwner", fields: [ownerId], references: [id], onDelete: Cascade)
196
203
  email String?
197
- seatType String @default("member")
198
- token String @unique
199
- channel String @default("email")
200
- status String @default("pending")
204
+ seatType String @default("member")
205
+ token String @unique
206
+ channel String @default("email")
207
+ status String @default("pending")
201
208
  expiresAt DateTime
202
- createdAt DateTime @default(now())
209
+ createdAt DateTime @default(now())
203
210
  acceptedBy String?
204
211
  applicantEmail String?
205
212
  message String?
206
213
  joinRequests TeamJoinRequest[]
214
+
207
215
  @@unique([ownerId, email])
208
216
  @@index([ownerId])
209
217
  @@index([email])
@@ -223,6 +231,7 @@ model TeamJoinRequest {
223
231
  seatType String @default("member")
224
232
  createdAt DateTime @default(now())
225
233
  processedAt DateTime?
234
+
226
235
  @@unique([invitationId, email])
227
236
  @@index([ownerId, status])
228
237
  @@map("team_join_requests")
@@ -235,8 +244,8 @@ model ProjectActivity {
235
244
  project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
236
245
  userId String
237
246
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
238
- action String // created | updated | deleted | member_invited | member_joined | member_removed | role_changed | module_viewed
239
- 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
240
249
  targetId String?
241
250
  metadata Json?
242
251
  createdAt DateTime @default(now())
@@ -246,20 +255,23 @@ model ProjectActivity {
246
255
  }
247
256
 
248
257
  model ChatThread {
249
- id String @id @default(cuid())
250
- userId String
251
- title String?
252
- isArchived Boolean @default(false)
253
- createdAt DateTime @default(now())
254
- 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
255
265
 
256
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
266
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
257
267
  messages ChatMessage[]
258
268
  runs ChatRun[]
259
269
  interrupts ChatInterrupt[]
260
270
  generations GenerationRun[]
261
271
  agentId String?
262
- 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)
263
275
 
264
276
  @@index([userId, updatedAt])
265
277
  @@map("chat_threads")
@@ -269,10 +281,11 @@ model ChatMessage {
269
281
  id String @id @default(cuid())
270
282
  threadId String
271
283
  role String
272
- content String
284
+ content Json?
273
285
  parts Json?
274
286
  thinking String?
275
287
  citations Json?
288
+ toolCallId String?
276
289
  createdAt DateTime @default(now())
277
290
 
278
291
  thread ChatThread @relation(fields: [threadId], references: [id], onDelete: Cascade)
@@ -282,15 +295,18 @@ model ChatMessage {
282
295
  }
283
296
 
284
297
  model ChatRun {
285
- id String @id @default(cuid())
286
- threadId String
287
- userId String
288
- status String
289
- startedAt DateTime @default(now())
290
- finishedAt DateTime?
291
- detachedSince DateTime?
292
- usage Json?
293
- 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?
294
310
 
295
311
  thread ChatThread @relation(fields: [threadId], references: [id], onDelete: Cascade)
296
312
  interrupts ChatInterrupt[]
@@ -301,19 +317,20 @@ model ChatRun {
301
317
  }
302
318
 
303
319
  model ChatInterrupt {
304
- id String @id @default(cuid())
305
- runId String
306
- threadId String
307
- userId String
308
- kind String
309
- toolName String?
310
- state String
311
- payload Json?
312
- resolution Json?
313
- createdAt DateTime @default(now())
314
- 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?
315
332
 
316
- run ChatRun @relation(fields: [runId], references: [id], onDelete: Cascade)
333
+ run ChatRun @relation(fields: [runId], references: [id], onDelete: Cascade)
317
334
  thread ChatThread @relation(fields: [threadId], references: [id], onDelete: Cascade)
318
335
 
319
336
  @@index([runId])
@@ -321,8 +338,100 @@ model ChatInterrupt {
321
338
  @@map("chat_interrupts")
322
339
  }
323
340
 
324
- 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 {
325
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())
326
435
  threadId String
327
436
  userId String
328
437
  kind String
@@ -330,9 +439,15 @@ model GenerationRun {
330
439
  input Json?
331
440
  result Json?
332
441
  artifactId String?
442
+ activity String?
443
+ provider String?
444
+ model String?
445
+ artifacts Json?
446
+ usage Json?
333
447
  error String?
334
- startedAt DateTime @default(now())
448
+ startedAt DateTime @default(now())
335
449
  finishedAt DateTime?
450
+ linkedTarget Json?
336
451
 
337
452
  thread ChatThread @relation(fields: [threadId], references: [id], onDelete: Cascade)
338
453
 
@@ -347,55 +462,55 @@ model LoginLog {
347
462
  userId String
348
463
  ip String?
349
464
  userAgent String?
350
- location String? // 地理位置,如 "北京, 中国";开发环境为 "本地"
465
+ location String? // 地理位置,如 "北京, 中国";开发环境为 "本地"
351
466
  success Boolean @default(true)
352
- message String? // 失败原因(中文),成功时为 null
467
+ message String? // 失败原因(中文),成功时为 null
353
468
  createdAt DateTime @default(now())
354
-
355
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
356
-
469
+
470
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
471
+
357
472
  @@map("login_logs")
358
473
  }
359
474
 
360
475
  // 邀请码
361
476
  model InvitationCode {
362
- id String @id @default(cuid())
363
- code String @unique
364
- maxUses Int @default(1)
365
- usedCount Int @default(0)
366
- expiresAt DateTime
367
- createdAt DateTime @default(now())
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())
368
483
  createdById String?
369
- disabledAt DateTime?
484
+ disabledAt DateTime?
370
485
 
371
- uses InvitationUse[]
486
+ uses InvitationUse[]
372
487
 
373
488
  @@map("invitation_codes")
374
489
  }
375
490
 
376
491
  // 邀请码使用记录
377
492
  model InvitationUse {
378
- id String @id @default(cuid())
379
- codeId String
380
- userId String
381
- usedAt DateTime @default(now())
382
-
383
- code InvitationCode @relation(fields: [codeId], references: [id], onDelete: Cascade)
384
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
385
-
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
+
386
501
  @@map("invitation_uses")
387
502
  }
388
503
 
389
504
  // 密码重置令牌
390
505
  model PasswordResetToken {
391
- id String @id @default(cuid())
392
- token String @unique
506
+ id String @id @default(cuid())
507
+ token String @unique
393
508
  userId String
394
509
  expiresAt DateTime
395
- usedAt DateTime?
396
- createdAt DateTime @default(now())
510
+ usedAt DateTime?
511
+ createdAt DateTime @default(now())
397
512
 
398
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
513
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
399
514
 
400
515
  @@map("password_reset_tokens")
401
516
  }
@@ -408,7 +523,8 @@ model EmailVerificationToken {
408
523
  expiresAt DateTime
409
524
  usedAt DateTime?
410
525
  createdAt DateTime @default(now())
411
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
526
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
527
+
412
528
  @@map("email_verification_tokens")
413
529
  }
414
530
 
@@ -426,6 +542,7 @@ model EmailLog {
426
542
  userId String?
427
543
  createdAt DateTime @default(now())
428
544
  sentAt DateTime?
545
+
429
546
  @@index([to, createdAt])
430
547
  @@index([userId, createdAt])
431
548
  @@index([status])
@@ -438,7 +555,8 @@ model EmailPreference {
438
555
  unsubscribedAll Boolean @default(false)
439
556
  unsubscribedCategories Json @default(dbgenerated("'[]'"))
440
557
  suppressed Boolean @default(false)
441
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
558
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
559
+
442
560
  @@map("email_preferences")
443
561
  }
444
562
 
@@ -447,7 +565,7 @@ model OAuthProviderConfig {
447
565
  id String @id @default(cuid())
448
566
  provider String @unique
449
567
  clientId String
450
- clientSecret String // AES-256-GCM 密文
568
+ clientSecret String // AES-256-GCM 密文
451
569
  enabled Boolean @default(false)
452
570
  extra Json?
453
571
  createdAt DateTime @default(now())
@@ -475,25 +593,25 @@ model EmailSubscriber {
475
593
 
476
594
  // 知识库
477
595
  model KnowledgeBase {
478
- id String @id @default(cuid())
479
- name String
480
- description String?
481
- icon String @default("notebook")
482
- tags Json @default(dbgenerated("'[]'"))
483
- visibility String @default("private")
484
- userId String
485
- pinnedToSidebar Boolean @default(false)
486
- isDeleted Boolean @default(false)
487
- createdAt DateTime @default(now())
488
- 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
489
607
 
490
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
491
- documents KnowledgeDocument[]
492
- projectLinks ProjectKnowledgeBase[]
493
- workspaceLinks WorkspaceKnowledgeBase[]
608
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
609
+ documents KnowledgeDocument[]
610
+ projectLinks ProjectKnowledgeBase[]
611
+ workspaceLinks WorkspaceKnowledgeBase[]
494
612
 
495
- @@index([userId])
496
- @@map("knowledge_bases")
613
+ @@index([userId])
614
+ @@map("knowledge_bases")
497
615
  }
498
616
 
499
617
  // 项目关联知识库(join 表;关联时仅允许 visibility=team,general 全局可见无需关联,private 跨用户不可读)
@@ -570,10 +688,10 @@ model KnowledgeDocument {
570
688
  createdAt DateTime @default(now())
571
689
  updatedAt DateTime @updatedAt
572
690
 
573
- kb KnowledgeBase @relation(fields: [kbId], references: [id], onDelete: Cascade)
574
- parent KnowledgeDocument? @relation("DocumentTree", fields: [parentId], references: [id], onDelete: SetNull)
575
- children KnowledgeDocument[] @relation("DocumentTree")
576
- 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)
577
695
  workspaceQuickDocs WorkspaceQuickDoc[]
578
696
 
579
697
  @@index([kbId])
@@ -584,24 +702,24 @@ model KnowledgeDocument {
584
702
 
585
703
  // PRD 文档表
586
704
  model PRD {
587
- id String @id @default(cuid())
588
- icon String @default("file") // 图标名称
589
- name String // PRD 名称
590
- description String? // 介绍
591
- settings Json? // 文档设置(布局、主题等)
592
- 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 // 所属用户
593
711
  isDeleted Boolean @default(false)
594
712
  deletedAt DateTime?
595
- createdAt DateTime @default(now())
596
- updatedAt DateTime @updatedAt
713
+ createdAt DateTime @default(now())
714
+ updatedAt DateTime @updatedAt
597
715
 
598
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
599
- pages PRDPage[]
600
- versions PRDVersion[]
601
- reviews Review[]
602
- comments Comment[]
603
- shares Share[]
604
- 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[]
605
723
  agentConversations AgentConversation[]
606
724
 
607
725
  @@index([userId])
@@ -617,8 +735,8 @@ model AgentConversation {
617
735
  createdAt DateTime @default(now())
618
736
  updatedAt DateTime @updatedAt
619
737
 
620
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
621
- 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)
622
740
  messages AgentMessage[]
623
741
 
624
742
  @@index([userId, prdId])
@@ -629,9 +747,9 @@ model AgentConversation {
629
747
  model AgentMessage {
630
748
  id String @id @default(cuid())
631
749
  conversationId String
632
- role String // "user" | "assistant"
633
- content String // 消息文本
634
- components Json? // AI 生成的组件数据(assistant 消息)
750
+ role String // "user" | "assistant"
751
+ content String // 消息文本
752
+ components Json? // AI 生成的组件数据(assistant 消息)
635
753
  isError Boolean @default(false)
636
754
  createdAt DateTime @default(now())
637
755
 
@@ -643,33 +761,33 @@ model AgentMessage {
643
761
 
644
762
  // 基础组件表(后台维护)
645
763
  model Component {
646
- id String @id @default(cuid())
647
- name String
648
- description String? // 组件描述
649
- type String // "component" | "block" | "template"
650
- category String? // 分类
651
- subCategory String? // 子分类
652
- 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? // 树形分组路径(如 "基础组件/表单/输入框")
653
771
  defaultWidth Int @default(200)
654
772
  defaultHeight Int @default(40)
655
- prototypeKey String? // unique key for registry lookup (e.g. "text", "button")
656
- config Json // 属性描述 schema(props定义、slots、events)
657
- defaultProps Json? // 默认属性值
658
- defaultStyle Json? // 默认样式
659
- preview String? // 预览图URL
660
- version Int @default(1)
661
- sortOrder Int @default(0) // 排序权重(越大越前)
662
- source String @default("manual") // "npm" | "file" | "manual"
663
- sourceId String? // npm 包名 / 文件名
664
- isHidden Boolean @default(false) // 隐藏/显示
665
- isDeleted Boolean @default(false)
666
- createdAt DateTime @default(now())
667
- 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
668
786
 
669
- blockItems BlockComponent[] @relation("componentRef")
670
- instances ComponentInstance[] @relation("componentRef")
671
- componentTags ComponentTag[]
672
- tags Json @default(dbgenerated("'[]'"))
787
+ blockItems BlockComponent[] @relation("componentRef")
788
+ instances ComponentInstance[] @relation("componentRef")
789
+ componentTags ComponentTag[]
790
+ tags Json @default(dbgenerated("'[]'"))
673
791
 
674
792
  @@index([type, category])
675
793
  @@index([isDeleted])
@@ -688,8 +806,8 @@ model Block {
688
806
  createdAt DateTime @default(now())
689
807
  updatedAt DateTime @updatedAt
690
808
 
691
- items BlockComponent[]
692
- instances BlockInstance[] @relation("blockRef")
809
+ items BlockComponent[]
810
+ instances BlockInstance[] @relation("blockRef")
693
811
  templateItems TemplateBlock[] @relation("templateBlockRef")
694
812
 
695
813
  @@index([isDeleted])
@@ -698,16 +816,16 @@ model Block {
698
816
 
699
817
  // 区块内组件布局
700
818
  model BlockComponent {
701
- id String @id @default(cuid())
819
+ id String @id @default(cuid())
702
820
  blockId String
703
821
  componentId String
704
- x Float @default(0)
705
- y Float @default(0)
706
- width Float @default(100)
707
- height Float @default(100)
708
- zIndex Int @default(0)
709
- propsOverride Json? // 局部覆写属性
710
- 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? // 局部覆写样式
711
829
 
712
830
  block Block @relation(fields: [blockId], references: [id], onDelete: Cascade)
713
831
  component Component @relation("componentRef", fields: [componentId], references: [id])
@@ -733,12 +851,12 @@ model Template {
733
851
 
734
852
  // 模板内区块排布
735
853
  model TemplateBlock {
736
- id String @id @default(cuid())
854
+ id String @id @default(cuid())
737
855
  templateId String
738
856
  blockId String
739
- order Int @default(0) // 排布顺序
740
- x Float? @default(0)
741
- y Float? @default(0)
857
+ order Int @default(0) // 排布顺序
858
+ x Float? @default(0)
859
+ y Float? @default(0)
742
860
  width Float?
743
861
  height Float?
744
862
 
@@ -752,22 +870,22 @@ model TemplateBlock {
752
870
  model PRDPage {
753
871
  id String @id @default(cuid())
754
872
  prdId String
755
- parentId String? // 父节点,构建树形结构(null = 根级)
873
+ parentId String? // 父节点,构建树形结构(null = 根级)
756
874
  name String
757
- order Int @default(0) // 排序
875
+ order Int @default(0) // 排序
758
876
  type String @default("page") // "page" | "folder"
759
- canvas Json? // 原型画板数据
760
- content Json? // PRD 文档内容
877
+ canvas Json? // 原型画板数据
878
+ content Json? // PRD 文档内容
761
879
  version Int @default(1) // 页面版本号
762
880
  createdAt DateTime @default(now())
763
881
  updatedAt DateTime @updatedAt
764
882
 
765
- prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)
766
- parent PRDPage? @relation("PageHierarchy", fields: [parentId], references: [id], onDelete: Cascade)
767
- 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")
768
886
  componentInstances ComponentInstance[]
769
887
  blockInstances BlockInstance[]
770
- pageVersions PageVersion[]
888
+ pageVersions PageVersion[]
771
889
 
772
890
  @@index([prdId, order])
773
891
  @@map("prd_pages")
@@ -775,24 +893,24 @@ model PRDPage {
775
893
 
776
894
  // 组件实例(画布上)
777
895
  model ComponentInstance {
778
- id String @id @default(cuid())
779
- pageId String
780
- componentId String? // null = 已解绑的游离副本
896
+ id String @id @default(cuid())
897
+ pageId String
898
+ componentId String? // null = 已解绑的游离副本
781
899
  blockInstanceId String? // 所属区块实例
782
- name String? // 实例别名
783
- x Float @default(0)
784
- y Float @default(0)
785
- width Float @default(100)
786
- height Float @default(100)
787
- zIndex Int @default(0)
788
- props Json? // 局部覆写属性
789
- style Json? // 局部覆写样式
790
- createdAt DateTime @default(now())
791
- 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
792
910
 
793
- page PRDPage @relation(fields: [pageId], references: [id], onDelete: Cascade)
794
- component Component? @relation("componentRef", fields: [componentId], references: [id])
795
- 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])
796
914
 
797
915
  @@index([pageId])
798
916
  @@map("component_instances")
@@ -800,17 +918,17 @@ model ComponentInstance {
800
918
 
801
919
  // 区块实例(画布上)
802
920
  model BlockInstance {
803
- id String @id @default(cuid())
804
- pageId String
805
- blockId String? // null = 已解绑的游离副本
806
- name String? // 实例别名
807
- x Float @default(0)
808
- y Float @default(0)
809
- width Float @default(400)
810
- height Float @default(300)
811
- zIndex Int @default(0)
812
- props Json? // 局部覆写属性
813
- 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? // 局部覆写样式
814
932
  createdAt DateTime @default(now())
815
933
  updatedAt DateTime @updatedAt
816
934
 
@@ -824,42 +942,42 @@ model BlockInstance {
824
942
 
825
943
  // PRD 版本(手动发布创建)
826
944
  model PRDVersion {
827
- id String @id @default(cuid())
945
+ id String @id @default(cuid())
828
946
  prdId String
829
- major Int @default(1)
830
- minor Int @default(0)
831
- patch Int @default(0)
832
- versionLabel String // 如 "v1", "v1.1", "v1.1.1"
833
- parentVersion String? // 上一版本ID(版本链)
834
- pageVersions Json // [{ pageId, pageName, version, canvas, content }]
835
- 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? // 发版说明
836
954
  userId String
837
- createdAt DateTime @default(now())
955
+ createdAt DateTime @default(now())
838
956
  updatedAt DateTime?
839
957
 
840
- prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)
841
- user User @relation(fields: [userId], references: [id])
842
- reviews Review[]
958
+ prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)
959
+ user User @relation(fields: [userId], references: [id])
960
+ reviews Review[]
843
961
  shareVersions ShareVersion[]
844
962
 
845
- @@index([prdId, createdAt])
846
- @@index([userId])
847
- @@map("prd_versions")
848
- }
963
+ @@index([prdId, createdAt])
964
+ @@index([userId])
965
+ @@map("prd_versions")
966
+ }
849
967
 
850
968
  // 页面版本(独立的页面级别版本历史)
851
969
  model PageVersion {
852
- id String @id @default(cuid())
853
- pageId String
854
- version Int // 整数版本号,自增
855
- notes String? // 版本说明(用户可编辑)
856
- canvas Json? // 原型快照
857
- content Json? // 文档快照
970
+ id String @id @default(cuid())
971
+ pageId String
972
+ version Int // 整数版本号,自增
973
+ notes String? // 版本说明(用户可编辑)
974
+ canvas Json? // 原型快照
975
+ content Json? // 文档快照
858
976
  restoredFromVersion Int? // 从哪个版本号还原而来(null 表示非还原版本)
859
- fromPRDVersionId String? // 来源:从哪个 PRD 版本创建(可选标记)
860
- createdAt DateTime @default(now())
977
+ fromPRDVersionId String? // 来源:从哪个 PRD 版本创建(可选标记)
978
+ createdAt DateTime @default(now())
861
979
 
862
- page PRDPage @relation(fields: [pageId], references: [id], onDelete: Cascade)
980
+ page PRDPage @relation(fields: [pageId], references: [id], onDelete: Cascade)
863
981
 
864
982
  @@index([pageId, createdAt])
865
983
  @@index([pageId, version])
@@ -871,15 +989,15 @@ model Review {
871
989
  id String @id @default(cuid())
872
990
  prdId String
873
991
  versionId String
874
- status String @default("PENDING")
992
+ status String @default("PENDING")
875
993
  reviewerId String?
876
994
  notes String?
877
995
  createdAt DateTime @default(now())
878
996
  completedAt DateTime?
879
997
 
880
- prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)
881
- version PRDVersion @relation(fields: [versionId], references: [id])
882
- 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])
883
1001
  comments ReviewComment[]
884
1002
 
885
1003
  @@unique([prdId, versionId])
@@ -894,15 +1012,15 @@ model ReviewComment {
894
1012
  id String @id @default(cuid())
895
1013
  reviewId String
896
1014
  userId String
897
- content String
898
- pageId String? // 关联页面
899
- elementId String? // 关联具体元素
900
- parentId String? // 回复上级留言
1015
+ content String
1016
+ pageId String? // 关联页面
1017
+ elementId String? // 关联具体元素
1018
+ parentId String? // 回复上级留言
901
1019
  createdAt DateTime @default(now())
902
1020
 
903
- review Review @relation(fields: [reviewId], references: [id], onDelete: Cascade)
904
- user User @relation(fields: [userId], references: [id])
905
- 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])
906
1024
  replies ReviewComment[] @relation("ReviewCommentReplies")
907
1025
 
908
1026
  @@index([reviewId])
@@ -915,21 +1033,21 @@ model ReviewComment {
915
1033
  model Comment {
916
1034
  id String @id @default(cuid())
917
1035
  prdId String
918
- pageId String? // 可选:针对某页面
919
- elementId String? // 可选:针对某元素(组件/区块实例ID)
1036
+ pageId String? // 可选:针对某页面
1037
+ elementId String? // 可选:针对某元素(组件/区块实例ID)
920
1038
  userId String
921
- content String
922
- parentId String? // 回复上级评论
923
- position Json? // 文本选区位置 { from: number, to: number }
1039
+ content String
1040
+ parentId String? // 回复上级评论
1041
+ position Json? // 文本选区位置 { from: number, to: number }
924
1042
  resolved Boolean @default(false)
925
1043
  createdAt DateTime @default(now())
926
1044
  updatedAt DateTime @updatedAt
927
1045
 
928
- prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)
929
- user User @relation(fields: [userId], references: [id])
930
- parent Comment? @relation("CommentReplies", fields: [parentId], references: [id])
931
- replies Comment[] @relation("CommentReplies")
932
- 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[]
933
1051
 
934
1052
  @@index([prdId])
935
1053
  @@index([userId])
@@ -955,18 +1073,18 @@ model CommentIgnore {
955
1073
 
956
1074
  // 分享链接
957
1075
  model Share {
958
- id String @id @default(cuid())
959
- prdId String
960
- token String @unique
961
- type String @default("prd") // "prd" | 预留扩展
962
- status String @default("ACTIVE")
963
- password String? // 加密分享密码(4位,数字+大写+小写字母)
964
- hasPassword Boolean @default(false)
965
- expiresAt DateTime?
966
- createdAt DateTime @default(now())
967
- 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
968
1086
 
969
- prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)
1087
+ prd PRD @relation(fields: [prdId], references: [id], onDelete: Cascade)
970
1088
  shareVersions ShareVersion[]
971
1089
 
972
1090
  @@index([token])
@@ -1028,12 +1146,12 @@ model ComponentTag {
1028
1146
  }
1029
1147
 
1030
1148
  model Reference {
1031
- id String @id @default(uuid())
1032
- sourceModule String
1033
- sourceEntityId String
1034
- targetModule String
1035
- targetEntityId String
1036
- 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())
1037
1155
 
1038
1156
  @@index([sourceModule, sourceEntityId])
1039
1157
  @@index([targetModule, targetEntityId])
@@ -1045,8 +1163,8 @@ model ShareVersion {
1045
1163
  shareId String
1046
1164
  versionId String
1047
1165
 
1048
- share Share @relation(fields: [shareId], references: [id], onDelete: Cascade)
1049
- 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)
1050
1168
 
1051
1169
  @@unique([shareId, versionId])
1052
1170
  @@index([shareId])
@@ -1060,7 +1178,7 @@ model AnyHubApp {
1060
1178
  id String @id @default(cuid())
1061
1179
  name String @unique
1062
1180
  displayName String
1063
- description String?
1181
+ description String?
1064
1182
  version String @default("0.1.0")
1065
1183
  source String
1066
1184
  url String?
@@ -1074,7 +1192,7 @@ model AnyHubApp {
1074
1192
  createdAt DateTime @default(now())
1075
1193
  updatedAt DateTime @updatedAt
1076
1194
 
1077
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1195
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1078
1196
  permissions AnyHubPermission[]
1079
1197
 
1080
1198
  @@index([userId])
@@ -1097,26 +1215,26 @@ model AnyHubPermission {
1097
1215
  }
1098
1216
 
1099
1217
  model AnyHubMarketApp {
1100
- id String @id @default(cuid())
1218
+ id String @id @default(cuid())
1101
1219
  name String
1102
1220
  displayName String
1103
- description String?
1221
+ description String?
1104
1222
  entryUrl String
1105
1223
  icon String?
1106
- iconType String @default("ICON")
1224
+ iconType String @default("ICON")
1107
1225
  logo String?
1108
1226
  category String?
1109
- tags String?
1110
- downloads Int @default(0)
1227
+ tags String?
1228
+ downloads Int @default(0)
1111
1229
  capabilities Json
1112
- status String @default("DRAFT")
1230
+ status String @default("DRAFT")
1113
1231
  publishedAt DateTime?
1114
1232
  userId String
1115
- recommendationId String? @unique
1116
- createdAt DateTime @default(now())
1117
- updatedAt DateTime @updatedAt
1233
+ recommendationId String? @unique
1234
+ createdAt DateTime @default(now())
1235
+ updatedAt DateTime @updatedAt
1118
1236
 
1119
- user User @relation(fields: [userId], references: [id])
1237
+ user User @relation(fields: [userId], references: [id])
1120
1238
  recommendation AnyHubRecommendation? @relation("anyhubRecommendation", fields: [recommendationId], references: [id])
1121
1239
 
1122
1240
  @@index([status])
@@ -1128,7 +1246,7 @@ model AnyHubRecommendation {
1128
1246
  githubUrl String @unique
1129
1247
  name String?
1130
1248
  displayName String?
1131
- description String?
1249
+ description String?
1132
1250
  status String @default("pending")
1133
1251
  reviewedBy String?
1134
1252
  reviewedAt DateTime?
@@ -1136,8 +1254,8 @@ model AnyHubRecommendation {
1136
1254
  createdAt DateTime @default(now())
1137
1255
  updatedAt DateTime @updatedAt
1138
1256
 
1139
- marketplaceApp AnyHubMarketApp? @relation("anyhubRecommendation")
1140
- reviewer User? @relation("reviewedAnyhubRecommendations", fields: [reviewedBy], references: [id])
1257
+ marketplaceApp AnyHubMarketApp? @relation("anyhubRecommendation")
1258
+ reviewer User? @relation("reviewedAnyhubRecommendations", fields: [reviewedBy], references: [id])
1141
1259
  recommenders AnyHubRecommender[]
1142
1260
 
1143
1261
  @@index([status])
@@ -1151,43 +1269,43 @@ model AnyHubRecommender {
1151
1269
  createdAt DateTime @default(now())
1152
1270
 
1153
1271
  recommendation AnyHubRecommendation @relation(fields: [recommendationId], references: [id], onDelete: Cascade)
1154
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1272
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1155
1273
 
1156
1274
  @@unique([recommendationId, userId])
1157
1275
  }
1158
1276
 
1159
1277
  // 设计稿
1160
1278
  model DesignProject {
1161
- id String @id @default(cuid())
1162
- name String
1163
- documentId String?
1164
- sketchName String?
1165
- version Int @default(1)
1166
- userId String
1167
- user User @relation(fields: [userId], references: [id])
1168
- artboards Artboard[]
1169
- createdAt DateTime @default(now())
1170
- 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
1171
1289
 
1172
1290
  @@index([userId])
1173
1291
  @@map("design_projects")
1174
1292
  }
1175
1293
 
1176
1294
  model Artboard {
1177
- id String @id @default(cuid())
1178
- projectId String
1179
- project DesignProject @relation(fields: [projectId], references: [id], onDelete: Cascade)
1180
- name String
1181
- pageName String?
1182
- width Int
1183
- height Int
1184
- pngPath String
1185
- svgPath String?
1186
- annotationJson Json?
1187
- layerCount Int?
1188
- sortOrder Int @default(0)
1189
- createdAt DateTime @default(now())
1190
- 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[]
1191
1309
 
1192
1310
  @@index([projectId])
1193
1311
  @@map("design_artboards")
@@ -1208,25 +1326,26 @@ model ArtboardExport {
1208
1326
  @@unique([artboardId, layerId, scale])
1209
1327
  @@map("design_artboard_exports")
1210
1328
  }
1329
+
1211
1330
  // AI 服务商元数据(admin 维护)
1212
1331
  model AiProvider {
1213
1332
  id String @id @default(cuid())
1214
1333
  providerId String @unique // 业务标识 "openai" "anthropic",用于 adapter 路由与 AiProviderConfig 软关联
1215
1334
  displayName String
1216
1335
  brandName String
1217
- description String
1336
+ description String
1218
1337
  category String @default("popular") // recommended|popular|local
1219
- adapterKind String // openai|anthropic|gemini|groq|grok|openrouter|ollama|openai-compatible
1338
+ adapterKind String // openai|anthropic|gemini|groq|grok|openrouter|ollama|openai-compatible
1220
1339
  defaultBaseUrl String?
1221
1340
  keyUrl String?
1222
1341
  docsUrl String?
1223
1342
  keyPlaceholder String?
1224
1343
  iconSlug String?
1225
1344
  brandColor String @default("#6467F2")
1226
- badge String? // 卡片角标文案(如「推荐」「热门」「NEW」),admin 可配
1345
+ badge String? // 卡片角标文案(如「推荐」「热门」「NEW」),admin 可配
1227
1346
  isLocal Boolean @default(false)
1228
1347
  enabled Boolean @default(true) // 平台级开关:停用后未配置用户看不到,已配置用户继续可用
1229
- models Json // AiModelMeta[](admin 可编辑)
1348
+ models Json // AiModelMeta[](admin 可编辑)
1230
1349
  sortOrder Int @default(0)
1231
1350
  createdAt DateTime @default(now())
1232
1351
  updatedAt DateTime @updatedAt
@@ -1238,12 +1357,15 @@ model AiProvider {
1238
1357
  model AiProviderConfig {
1239
1358
  id String @id @default(cuid())
1240
1359
  userId String
1241
- providerId String // 业务 providerId,软关联 AiProvider.providerId(不设外键 cascade,避免 admin 删除丢失用户配置)
1242
- apiKey String? // 加密存储 TODO
1360
+ providerId String // 业务 providerId,软关联 AiProvider.providerId(不设外键 cascade,避免 admin 删除丢失用户配置)
1361
+ apiKey String? // 加密存储 TODO
1243
1362
  baseUrl String?
1363
+ voiceApiKey String? // BytePlus Voice 独立 API key(speech/transcription 用,与 Ark apiKey 分开)
1364
+ voiceBaseUrl String? // BytePlus Voice Base URL(默认 fallback 到 baseUrl)
1244
1365
  enabled Boolean @default(false) // 用户级开关:是否在对话模型选择器中暴露
1245
- models Json? // string[] 用户启用的模型 ID(有序,顺序 = 模型选择器展示顺序)
1246
- 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 };不存任何密钥
1247
1369
  createdAt DateTime @default(now())
1248
1370
  updatedAt DateTime @updatedAt
1249
1371
 
@@ -1258,21 +1380,21 @@ model AiProviderConfig {
1258
1380
  // 第三方依赖版本管理(admin 决策是否升级)
1259
1381
  // currentVersion 实时读 monorepo 各 package.json,不存 DB;latestVersion 缓存自 npm registry
1260
1382
  model ThirdPartyDependency {
1261
- id String @id @default(cuid())
1262
- name String @unique // npm 包名,如 "@tiptap/core" / "mind-elixir"
1263
- displayName String? // 展示名(默认取 name)
1264
- description String? // 依赖用途说明(admin 可编辑)
1265
- homepage String? // 官网 / 仓库
1266
- category String @default("other") // framework|ui|editor|ai|state|tool|other
1267
- isWatched Boolean @default(true) // 是否置顶「关注列表」
1268
- priority String @default("normal") // high|normal|low
1269
- 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 版本
1270
1392
  latestChangelog String? // 最新版本的更新日志(来自 GitHub Releases,markdown)
1271
- lastSyncAt DateTime? // 最后一次成功同步 npm registry 的时间
1272
- notes String? // 备注(升级注意事项等)
1273
- sortOrder Int @default(0)
1274
- createdAt DateTime @default(now())
1275
- 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
1276
1398
 
1277
1399
  @@index([category])
1278
1400
  @@index([isWatched])
@@ -1290,8 +1412,8 @@ model LegalRegulation {
1290
1412
  category String
1291
1413
  issuingAuthority String?
1292
1414
  effectiveDate DateTime?
1293
- summary String?
1294
- content String?
1415
+ summary String?
1416
+ content String?
1295
1417
  sourceUrl String?
1296
1418
  likeCount Int @default(0)
1297
1419
  tags Json @default(dbgenerated("'[]'"))
@@ -1310,23 +1432,23 @@ model LegalRegulation {
1310
1432
  }
1311
1433
 
1312
1434
  model IndustryCompliance {
1313
- id String @id @default(cuid())
1435
+ id String @id @default(cuid())
1314
1436
  canonicalId String
1315
1437
  title String
1316
1438
  industry String
1317
1439
  regulatoryBody String?
1318
1440
  region String?
1319
- summary String?
1320
- content String?
1321
- requirements Json @default(dbgenerated("'[]'"))
1441
+ summary String?
1442
+ content String?
1443
+ requirements Json @default(dbgenerated("'[]'"))
1322
1444
  sourceUrl String?
1323
- likeCount Int @default(0)
1324
- tags Json @default(dbgenerated("'[]'"))
1325
- visibility String @default("private")
1326
- userId String
1327
- isDeleted Boolean @default(false)
1328
- createdAt DateTime @default(now())
1329
- 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
1330
1452
 
1331
1453
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1332
1454
 
@@ -1337,20 +1459,20 @@ model IndustryCompliance {
1337
1459
  }
1338
1460
 
1339
1461
  model DictionaryTerm {
1340
- id String @id @default(cuid())
1462
+ id String @id @default(cuid())
1341
1463
  canonicalId String
1342
1464
  title String
1343
1465
  industry String
1344
- definition String?
1345
- aliases Json @default(dbgenerated("'[]'"))
1346
- examples Json @default(dbgenerated("'[]'"))
1466
+ definition String?
1467
+ aliases Json @default(dbgenerated("'[]'"))
1468
+ examples Json @default(dbgenerated("'[]'"))
1347
1469
  referenceUrl String?
1348
- tags Json @default(dbgenerated("'[]'"))
1349
- visibility String @default("private")
1470
+ tags Json @default(dbgenerated("'[]'"))
1471
+ visibility String @default("private")
1350
1472
  userId String
1351
- isDeleted Boolean @default(false)
1352
- createdAt DateTime @default(now())
1353
- updatedAt DateTime @updatedAt
1473
+ isDeleted Boolean @default(false)
1474
+ createdAt DateTime @default(now())
1475
+ updatedAt DateTime @updatedAt
1354
1476
 
1355
1477
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1356
1478
 
@@ -1366,7 +1488,7 @@ model WebsiteBookmark {
1366
1488
  title String
1367
1489
  url String
1368
1490
  categoryId String?
1369
- summary String?
1491
+ summary String?
1370
1492
  faviconUrl String?
1371
1493
  faviconSyncedAt DateTime?
1372
1494
  isGithub Boolean @default(false)
@@ -1384,7 +1506,7 @@ model WebsiteBookmark {
1384
1506
  createdAt DateTime @default(now())
1385
1507
  updatedAt DateTime @updatedAt
1386
1508
 
1387
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1509
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1388
1510
  category BookmarkCategory? @relation(fields: [categoryId], references: [id], onDelete: SetNull)
1389
1511
 
1390
1512
  @@index([canonicalId, visibility])
@@ -1467,12 +1589,15 @@ model Plan {
1467
1589
  providerPriceIdUsdYearly String?
1468
1590
  providerPriceIdCnyYearly String?
1469
1591
 
1470
- seatPriceMonthly Int?
1592
+ seatPriceMonthly Int?
1471
1593
  providerSeatPriceIdUsd String?
1472
1594
  providerSeatPriceIdCny String?
1473
1595
 
1474
- agentQuota Int?
1475
- skillQuota Int?
1596
+ agentQuota Int?
1597
+ skillQuota Int?
1598
+ sandboxMinutesMonthly Int?
1599
+ mediaGenerationsMonthly Int?
1600
+ galleryStorageMb Int?
1476
1601
 
1477
1602
  subscriptions Subscription[]
1478
1603
 
@@ -1481,28 +1606,28 @@ model Plan {
1481
1606
 
1482
1607
  /// 订阅记录(User 级,一人一订阅)
1483
1608
  model Subscription {
1484
- id String @id @default(cuid())
1485
- userId String @unique
1486
- user User @relation(fields: [userId], references: [id])
1487
- planId String
1488
- plan Plan @relation(fields: [planId], references: [id])
1489
- status String @default("ACTIVE")
1490
- addonSeats Int @default(0)
1491
-
1492
- provider String @default("creem")
1493
- providerCustomerId String?
1494
- providerSubscriptionId String? @unique
1495
- 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?
1496
1621
  providerSeatSubscriptionId String?
1497
1622
 
1498
- currentPeriodStart DateTime?
1499
- currentPeriodEnd DateTime?
1500
- cancelAtPeriodEnd Boolean @default(false)
1501
- canceledAt DateTime?
1502
- trialEndsAt DateTime?
1623
+ currentPeriodStart DateTime?
1624
+ currentPeriodEnd DateTime?
1625
+ cancelAtPeriodEnd Boolean @default(false)
1626
+ canceledAt DateTime?
1627
+ trialEndsAt DateTime?
1503
1628
 
1504
- createdAt DateTime @default(now())
1505
- updatedAt DateTime @updatedAt
1629
+ createdAt DateTime @default(now())
1630
+ updatedAt DateTime @updatedAt
1506
1631
 
1507
1632
  /// 关联发票(子项目 3 新增)
1508
1633
  invoices Invoice[]
@@ -1512,16 +1637,16 @@ model Subscription {
1512
1637
 
1513
1638
  /// 用量记录(按月聚合,用于额度判断)
1514
1639
  model UsageRecord {
1515
- id String @id @default(cuid())
1640
+ id String @id @default(cuid())
1516
1641
  workspaceId String
1517
1642
  workspace Workspace @relation(fields: [workspaceId], references: [id])
1518
1643
  metric String
1519
1644
  period String
1520
- count Int @default(0)
1645
+ count Int @default(0)
1521
1646
  resetAt DateTime
1522
1647
 
1523
- createdAt DateTime @default(now())
1524
- updatedAt DateTime @updatedAt
1648
+ createdAt DateTime @default(now())
1649
+ updatedAt DateTime @updatedAt
1525
1650
 
1526
1651
  @@unique([workspaceId, metric, period])
1527
1652
  @@index([workspaceId, metric])
@@ -1530,22 +1655,23 @@ model UsageRecord {
1530
1655
 
1531
1656
  /// AI 用量明细(按次扣减 + 成本审计)
1532
1657
  model AiUsageLog {
1533
- id String @id @default(cuid())
1534
- workspaceId String
1535
- 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)
1536
1661
  userId String
1537
- user User @relation(fields: [userId], references: [id])
1538
- source String @default("byok")
1662
+ user User @relation(fields: [userId], references: [id])
1663
+ source String @default("byok")
1664
+ activity String?
1539
1665
  provider String
1540
1666
  model String
1541
- inputTokens Int @default(0)
1542
- outputTokens Int @default(0)
1667
+ inputTokens Int @default(0)
1668
+ outputTokens Int @default(0)
1543
1669
  costUsd String?
1544
- success Boolean @default(true)
1670
+ success Boolean @default(true)
1545
1671
  errorMessage String?
1546
1672
  durationMs Int?
1547
1673
 
1548
- createdAt DateTime @default(now())
1674
+ createdAt DateTime @default(now())
1549
1675
 
1550
1676
  @@index([workspaceId, createdAt])
1551
1677
  @@index([userId, createdAt])
@@ -1558,22 +1684,22 @@ model AiUsageLog {
1558
1684
 
1559
1685
  /// 账单记录(Webhook 同步)
1560
1686
  model Invoice {
1561
- id String @id @default(cuid())
1562
- subscriptionId String
1563
- subscription Subscription @relation(fields: [subscriptionId], references: [id])
1564
- providerInvoiceId String @unique
1565
- providerEventId String?
1566
- amountDue Int
1567
- amountPaid Int
1568
- currency String @default("usd")
1569
- status String
1570
- pdfUrl String?
1571
- hostedInvoiceUrl String?
1572
- periodStart DateTime
1573
- periodEnd DateTime
1574
- paidAt DateTime?
1575
-
1576
- 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())
1577
1703
 
1578
1704
  @@index([subscriptionId, createdAt])
1579
1705
  @@map("invoices")
@@ -1581,15 +1707,15 @@ model Invoice {
1581
1707
 
1582
1708
  /// Provider Webhook 事件幂等记录
1583
1709
  model ProviderEvent {
1584
- id String @id @default(cuid())
1585
- providerEventId String @unique
1710
+ id String @id @default(cuid())
1711
+ providerEventId String @unique
1586
1712
  type String
1587
- status String @default("processing")
1713
+ status String @default("processing")
1588
1714
  payload Json?
1589
1715
  errorMessage String?
1590
1716
  processedAt DateTime?
1591
1717
 
1592
- createdAt DateTime @default(now())
1718
+ createdAt DateTime @default(now())
1593
1719
 
1594
1720
  @@index([type, createdAt])
1595
1721
  @@map("provider_events")
@@ -1598,17 +1724,17 @@ model ProviderEvent {
1598
1724
  // ==================== 子项目 5:企业治理模型(sqlite 降级版)====================
1599
1725
 
1600
1726
  model LicenseKey {
1601
- id String @id @default(cuid())
1602
- key String @unique
1727
+ id String @id @default(cuid())
1728
+ key String @unique
1603
1729
  signature String
1604
- payload String @default(dbgenerated("'{}'"))
1730
+ payload String @default(dbgenerated("'{}'"))
1605
1731
  customerId String
1606
1732
  customerName String
1607
1733
  customerEmail String
1608
- plan String @default("enterprise")
1734
+ plan String @default("enterprise")
1609
1735
  seats Int
1610
- features String @default(dbgenerated("'{}'"))
1611
- issuedAt DateTime @default(now())
1736
+ features String @default(dbgenerated("'{}'"))
1737
+ issuedAt DateTime @default(now())
1612
1738
  expiresAt DateTime?
1613
1739
  revokedAt DateTime?
1614
1740
  issuedById String?
@@ -1617,11 +1743,11 @@ model LicenseKey {
1617
1743
  }
1618
1744
 
1619
1745
  model LicenseActivation {
1620
- id String @id @default(cuid())
1746
+ id String @id @default(cuid())
1621
1747
  licenseId String
1622
- instanceId String @unique
1748
+ instanceId String @unique
1623
1749
  fingerprint String
1624
- activatedAt DateTime @default(now())
1750
+ activatedAt DateTime @default(now())
1625
1751
  lastSeenAt DateTime?
1626
1752
  revokedAt DateTime?
1627
1753
 
@@ -1647,50 +1773,50 @@ model AuditLog {
1647
1773
  }
1648
1774
 
1649
1775
  model SsoProvider {
1650
- id String @id @default(cuid())
1651
- workspaceId String
1652
- type String
1653
- name String
1654
- config String @default(dbgenerated("'{}'"))
1655
- domain String?
1656
- enabled Boolean @default(true)
1657
- createdAt DateTime @default(now())
1658
- 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
1659
1785
 
1660
1786
  @@unique([workspaceId, type, domain])
1661
1787
  @@map("sso_providers")
1662
1788
  }
1663
1789
 
1664
1790
  model SsoMapping {
1665
- id String @id @default(cuid())
1791
+ id String @id @default(cuid())
1666
1792
  providerId String
1667
1793
  externalId String
1668
1794
  userId String
1669
1795
  email String?
1670
- createdAt DateTime @default(now())
1796
+ createdAt DateTime @default(now())
1671
1797
 
1672
1798
  @@unique([providerId, externalId])
1673
1799
  @@map("sso_mappings")
1674
1800
  }
1675
1801
 
1676
1802
  model CustomRole {
1677
- id String @id @default(cuid())
1803
+ id String @id @default(cuid())
1678
1804
  workspaceId String
1679
1805
  name String
1680
- permissions String @default(dbgenerated("'{}'"))
1681
- isSystem Boolean @default(false)
1682
- createdAt DateTime @default(now())
1683
- updatedAt DateTime @updatedAt
1806
+ permissions String @default(dbgenerated("'{}'"))
1807
+ isSystem Boolean @default(false)
1808
+ createdAt DateTime @default(now())
1809
+ updatedAt DateTime @updatedAt
1684
1810
 
1685
1811
  @@unique([workspaceId, name])
1686
1812
  @@map("custom_roles")
1687
1813
  }
1688
1814
 
1689
1815
  model RoleAssignment {
1690
- id String @id @default(cuid())
1816
+ id String @id @default(cuid())
1691
1817
  roleId String
1692
1818
  userId String
1693
- createdAt DateTime @default(now())
1819
+ createdAt DateTime @default(now())
1694
1820
 
1695
1821
  @@unique([roleId, userId])
1696
1822
  @@map("role_assignments")
@@ -1730,9 +1856,12 @@ model UserAgent {
1730
1856
  createdAt DateTime @default(now())
1731
1857
  updatedAt DateTime @updatedAt
1732
1858
  isDeleted Boolean @default(false)
1859
+ isDefault Boolean @default(false)
1860
+ harnessKind String?
1733
1861
 
1734
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1735
- threads ChatThread[]
1862
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1863
+ threads ChatThread[]
1864
+ agentBindings BusinessAgentBinding[]
1736
1865
 
1737
1866
  @@index([userId])
1738
1867
  @@map("user_agents")
@@ -1774,33 +1903,33 @@ model DeveloperLog {
1774
1903
 
1775
1904
  // 需求(简化版,与 psql schema 对齐)
1776
1905
  model Story {
1777
- id String @id @default(cuid())
1906
+ id String @id @default(cuid())
1778
1907
  sequenceId Int
1779
- boardOrder Int @default(0)
1908
+ boardOrder Int @default(0)
1780
1909
  identifier String
1781
1910
  projectId String
1782
- project Project @relation(fields: [projectId], references: [id], onDelete: Restrict)
1911
+ project Project @relation(fields: [projectId], references: [id], onDelete: Restrict)
1783
1912
  name String
1784
1913
  description String?
1785
- state String @default("backlog")
1786
- priority String @default("none")
1787
- archived Boolean @default(false)
1914
+ state String @default("backlog")
1915
+ priority String @default("none")
1916
+ archived Boolean @default(false)
1788
1917
  archivedAt DateTime?
1789
1918
  assigneeId String?
1790
- assignee User? @relation("storyAssignee", fields: [assigneeId], references: [id], onDelete: SetNull)
1919
+ assignee User? @relation("storyAssignee", fields: [assigneeId], references: [id], onDelete: SetNull)
1791
1920
  startDate DateTime?
1792
1921
  targetDate DateTime?
1793
1922
  createdById String
1794
- createdBy User @relation("storyCreator", fields: [createdById], references: [id])
1923
+ createdBy User @relation("storyCreator", fields: [createdById], references: [id])
1795
1924
  updatedById String?
1796
- updatedBy User? @relation("storyEditor", fields: [updatedById], references: [id], onDelete: SetNull)
1925
+ updatedBy User? @relation("storyEditor", fields: [updatedById], references: [id], onDelete: SetNull)
1797
1926
  parentId String?
1798
- parent Story? @relation("StoryHierarchy", fields: [parentId], references: [id], onDelete: SetNull)
1799
- children Story[] @relation("StoryHierarchy")
1927
+ parent Story? @relation("StoryHierarchy", fields: [parentId], references: [id], onDelete: SetNull)
1928
+ children Story[] @relation("StoryHierarchy")
1800
1929
  iterationId String?
1801
1930
  iteration Iteration? @relation(fields: [iterationId], references: [id], onDelete: SetNull)
1802
- createdAt DateTime @default(now())
1803
- updatedAt DateTime @updatedAt
1931
+ createdAt DateTime @default(now())
1932
+ updatedAt DateTime @updatedAt
1804
1933
 
1805
1934
  @@unique([projectId, identifier])
1806
1935
  @@index([projectId, sequenceId])
@@ -1836,16 +1965,16 @@ model Iteration {
1836
1965
 
1837
1966
  // 迭代自动排期配置(一项目一行)
1838
1967
  model IterationAutoSchedule {
1839
- projectId String @id
1840
- project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
1841
- enabled Boolean @default(false)
1842
- title String @default("迭代")
1843
- durationDays Int @default(14)
1844
- 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)
1845
1974
  startsOn DateTime
1846
- futureCount Int @default(2)
1847
- autoRollover Boolean @default(false)
1848
- lastSeq Int @default(0)
1975
+ futureCount Int @default(2)
1976
+ autoRollover Boolean @default(false)
1977
+ lastSeq Int @default(0)
1849
1978
 
1850
1979
  @@map("iteration_auto_schedules")
1851
1980
  }
@@ -1862,3 +1991,107 @@ model NotificationPreference {
1862
1991
 
1863
1992
  @@map("notification_preferences")
1864
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
+ }