@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
package/schema.prisma CHANGED
@@ -44,6 +44,7 @@ model User {
44
44
  aiProvider String? // "openrouter" | "openai"
45
45
  aiApiKey String? // 用户 AI API Key(TODO: 加密存储)
46
46
  aiModel String? // 默认 "openai/gpt-4o-mini"
47
+ aiSourceMode String? // 模型来源模式:hosted | local-agent | byok;null = 未选择(默认 byok 行为)
47
48
  locale String? // 用户语言偏好(zh / en),null 表示未设置
48
49
 
49
50
  storyDisplayOptions Json? // Story Display Options 个人偏好(URL 无参数时的默认值,跨设备持久化)
@@ -60,6 +61,8 @@ model User {
60
61
  invitationUses InvitationUse[]
61
62
  loginLogs LoginLog[]
62
63
  passwordResetTokens PasswordResetToken[]
64
+ emailVerificationTokens EmailVerificationToken[]
65
+ emailPreference EmailPreference?
63
66
  prds PRD[]
64
67
  tags Tag[]
65
68
  knowledgeBases KnowledgeBase[]
@@ -73,48 +76,53 @@ model User {
73
76
  articleFavorites ArticleFavorite[]
74
77
  anyhubApps AnyHubApp[]
75
78
  anyhubMarketApps AnyHubMarketApp[]
76
- reviewedAnyhubRecommendations AnyHubRecommendation[] @relation("reviewedAnyhubRecommendations")
79
+ reviewedAnyhubRecommendations AnyHubRecommendation[] @relation("reviewedAnyhubRecommendations")
77
80
  anyhubRecommenders AnyHubRecommender[]
78
81
  prdVersions PRDVersion[]
79
82
  reviewComments ReviewComment[]
80
83
  comments Comment[]
81
84
  commentIgnores CommentIgnore[]
82
- reviews Review[] @relation("reviewer")
85
+ reviews Review[] @relation("reviewer")
83
86
  designProjects DesignProject[]
84
- storiesCreated Story[] @relation("storyCreator")
85
- storiesAssigned Story[] @relation("storyAssignee")
86
- storiesEdited Story[] @relation("storyEditor")
87
- iterationsCreated Iteration[] @relation("iterationCreator")
88
- labelsCreated Label[] @relation("labelCreator")
89
- storyActivities StoryActivity[] @relation("storyActivityUser")
90
- storyComments StoryComment[] @relation("storyCommentUser")
91
- storyReactions StoryReaction[] @relation("storyReactionUser")
92
- commentReactions CommentReaction[] @relation("commentReactionUser")
87
+ storiesCreated Story[] @relation("storyCreator")
88
+ storiesAssigned Story[] @relation("storyAssignee")
89
+ storiesEdited Story[] @relation("storyEditor")
90
+ iterationsCreated Iteration[] @relation("iterationCreator")
91
+ labelsCreated Label[] @relation("labelCreator")
92
+ storyActivities StoryActivity[] @relation("storyActivityUser")
93
+ storyComments StoryComment[] @relation("storyCommentUser")
94
+ storyReactions StoryReaction[] @relation("storyReactionUser")
95
+ commentReactions CommentReaction[] @relation("commentReactionUser")
93
96
  storyFilterViews StoryFilterView[]
94
97
  chatThreads ChatThread[]
95
98
  aiProviderConfigs AiProviderConfig[]
96
99
  agentConversations AgentConversation[]
97
- ownedProjects Project[] @relation("projectOwner")
100
+ ownedProjects Project[] @relation("projectOwner")
98
101
  projectMemberships ProjectMember[]
99
102
  projectActivities ProjectActivity[]
100
- ownedWorkspaces Workspace[] @relation("workspaceOwner")
101
- workspaceMemberships TeamMembership[] @relation("teamOwner")
102
- teamJoined TeamMembership? @relation("teamMember")
103
+ ownedWorkspaces Workspace[] @relation("workspaceOwner")
104
+ workspaceMemberships TeamMembership[] @relation("teamOwner")
105
+ teamJoined TeamMembership? @relation("teamMember")
103
106
  workspaceMembers WorkspaceMember[]
104
- sentInvitations TeamInvitation[] @relation("invitationOwner")
105
- ownedJoinRequests TeamJoinRequest[] @relation("joinRequestOwner")
106
- applicantJoinRequests TeamJoinRequest[] @relation("joinRequestApplicant")
107
+ sentInvitations TeamInvitation[] @relation("invitationOwner")
108
+ ownedJoinRequests TeamJoinRequest[] @relation("joinRequestOwner")
109
+ applicantJoinRequests TeamJoinRequest[] @relation("joinRequestApplicant")
107
110
  aiUsageLogs AiUsageLog[]
108
111
  agents UserAgent[]
109
112
  skills UserSkill[]
110
113
  notifications Notification[]
111
114
  notificationPreference NotificationPreference?
112
115
 
113
- issuedLicenses LicenseKey[] @relation("LicenseIssuer")
114
- ssoMappings SsoMapping[]
115
- roleAssignments RoleAssignment[]
116
- subscription Subscription?
116
+ issuedLicenses LicenseKey[] @relation("LicenseIssuer")
117
+ ssoMappings SsoMapping[]
118
+ codeSnippets CodeSnippet[]
119
+ roleAssignments RoleAssignment[]
120
+ subscription Subscription?
117
121
  createdQuickDocs WorkspaceQuickDoc[]
122
+ plugins HarnessPlugin[]
123
+ harnessWorkspaces HarnessWorkspace[]
124
+ agentBindings BusinessAgentBinding[]
125
+ blobs Blob[]
118
126
 
119
127
  @@map("users")
120
128
  }
@@ -186,22 +194,22 @@ model ProjectMember {
186
194
 
187
195
  // 工作空间(项目的上一级容器)
188
196
  model Workspace {
189
- id String @id @default(cuid())
190
- name String
191
- icon String @default("folder")
192
- description String?
193
- pinnedToSidebar Boolean @default(false)
194
- ownerId String
195
- owner User @relation("workspaceOwner", fields: [ownerId], references: [id])
196
- projects Project[]
197
- members WorkspaceMember[]
198
- knowledgeBases KnowledgeBase[]
199
- workspaceKbLinks WorkspaceKnowledgeBase[]
200
- quickDocs WorkspaceQuickDoc[]
201
- usageRecords UsageRecord[]
202
- aiUsageLogs AiUsageLog[]
203
- createdAt DateTime @default(now())
204
- updatedAt DateTime @updatedAt
197
+ id String @id @default(cuid())
198
+ name String
199
+ icon String @default("folder")
200
+ description String?
201
+ pinnedToSidebar Boolean @default(false)
202
+ ownerId String
203
+ owner User @relation("workspaceOwner", fields: [ownerId], references: [id])
204
+ projects Project[]
205
+ members WorkspaceMember[]
206
+ knowledgeBases KnowledgeBase[]
207
+ workspaceKbLinks WorkspaceKnowledgeBase[]
208
+ quickDocs WorkspaceQuickDoc[]
209
+ usageRecords UsageRecord[]
210
+ aiUsageLogs AiUsageLog[]
211
+ createdAt DateTime @default(now())
212
+ updatedAt DateTime @updatedAt
205
213
 
206
214
  ssoProviders SsoProvider[]
207
215
  customRoles CustomRole[]
@@ -305,12 +313,13 @@ model ProjectActivity {
305
313
 
306
314
  // 对话线程(作为 TanStack AI persistence threadId)
307
315
  model ChatThread {
308
- id String @id @default(cuid())
309
- userId String
310
- title String?
311
- isArchived Boolean @default(false)
312
- createdAt DateTime @default(now())
313
- updatedAt DateTime @updatedAt
316
+ id String @id @default(cuid())
317
+ userId String
318
+ title String?
319
+ isArchived Boolean @default(false)
320
+ sandboxPolicy String @default("readonly")
321
+ createdAt DateTime @default(now())
322
+ updatedAt DateTime @updatedAt
314
323
 
315
324
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
316
325
  messages ChatMessage[]
@@ -319,6 +328,8 @@ model ChatThread {
319
328
  generations GenerationRun[]
320
329
  agentId String?
321
330
  agent UserAgent? @relation(fields: [agentId], references: [id])
331
+ workspaceId String?
332
+ workspace HarnessWorkspace? @relation(fields: [workspaceId], references: [id], onDelete: SetNull)
322
333
 
323
334
  @@index([userId, updatedAt])
324
335
  @@map("chat_threads")
@@ -326,14 +337,15 @@ model ChatThread {
326
337
 
327
338
  // 对话消息(TanStack AI messages store)
328
339
  model ChatMessage {
329
- id String @id @default(cuid())
330
- threadId String
331
- role String // "user" | "assistant" | "tool"
332
- content String @db.Text
333
- parts Json?
334
- thinking String? @db.Text
335
- citations Json?
336
- createdAt DateTime @default(now())
340
+ id String @id @default(cuid())
341
+ threadId String
342
+ role String // "user" | "assistant" | "tool"
343
+ content Json? // string | ContentPart[] | null — round-trip 无损
344
+ parts Json? // toolCalls(assistant 调用工具时)
345
+ thinking String? @db.Text
346
+ citations Json?
347
+ toolCallId String?
348
+ createdAt DateTime @default(now())
337
349
 
338
350
  thread ChatThread @relation(fields: [threadId], references: [id], onDelete: Cascade)
339
351
 
@@ -343,15 +355,18 @@ model ChatMessage {
343
355
 
344
356
  // 运行记录(TanStack AI runs store)
345
357
  model ChatRun {
346
- id String @id @default(cuid())
347
- threadId String
348
- userId String
349
- status String // running | completed | failed | aborted | interrupted
350
- startedAt DateTime @default(now())
351
- finishedAt DateTime?
352
- detachedSince DateTime?
353
- usage Json?
354
- error String? @db.Text
358
+ id String @id @default(cuid())
359
+ threadId String
360
+ userId String
361
+ status String // running | completed | failed | aborted | interrupted
362
+ startedAt DateTime @default(now())
363
+ finishedAt DateTime?
364
+ detachedSince DateTime?
365
+ usage Json?
366
+ error String? @db.Text
367
+ sandboxKey String?
368
+ cancelRequested Boolean?
369
+ driverEpoch Int?
355
370
 
356
371
  thread ChatThread @relation(fields: [threadId], references: [id], onDelete: Cascade)
357
372
  interrupts ChatInterrupt[]
@@ -363,17 +378,18 @@ model ChatRun {
363
378
 
364
379
  // 中断记录(TanStack AI interrupts store)
365
380
  model ChatInterrupt {
366
- id String @id @default(cuid())
367
- runId String
368
- threadId String
369
- userId String
370
- kind String // tool-approval | generic
371
- toolName String?
372
- state String // pending | resolved | cancelled
373
- payload Json?
374
- resolution Json?
375
- createdAt DateTime @default(now())
376
- resolvedAt DateTime?
381
+ id String @id @default(cuid())
382
+ runId String
383
+ threadId String
384
+ userId String
385
+ kind String // tool-approval | generic
386
+ toolName String?
387
+ state String // pending | resolved | cancelled
388
+ payload Json?
389
+ resolution Json?
390
+ requestedAt DateTime @default(now())
391
+ createdAt DateTime @default(now())
392
+ resolvedAt DateTime?
377
393
 
378
394
  run ChatRun @relation(fields: [runId], references: [id], onDelete: Cascade)
379
395
  thread ChatThread @relation(fields: [threadId], references: [id], onDelete: Cascade)
@@ -383,6 +399,100 @@ model ChatInterrupt {
383
399
  @@map("chat_interrupts")
384
400
  }
385
401
 
402
+ // TanStack AI persistence metadata store(compaction checkpoint / ChatProjection 等)
403
+ // namespace 由消费方(中间件)自带,如 "compaction"、"projection.todos"
404
+ model ChatPersistenceMeta {
405
+ namespace String
406
+ key String
407
+ value Json
408
+ updatedAt DateTime @updatedAt
409
+
410
+ @@unique([namespace, key])
411
+ @@map("chat_persistence_meta")
412
+ }
413
+
414
+ // dsh(DeepSeek-Harness)兼容插件(设计 v8 ADR 21:插件定义 DB 持久化,运行态随页面)
415
+ model HarnessPlugin {
416
+ id String @id @default(cuid())
417
+ userId String
418
+ name String
419
+ purpose String @db.Text
420
+ codeHost String? @db.Text
421
+ codeClient String? @db.Text
422
+ // plugin_define 求值后插件经 harness.defineTool 上报的工具定义(JSON Schema 数组)
423
+ tools Json @default("[]")
424
+ version Int @default(1)
425
+ // defined | running | stopped | error
426
+ status String @default("defined")
427
+ lastError String? @db.Text
428
+ createdAt DateTime @default(now())
429
+ updatedAt DateTime @updatedAt
430
+ isDeleted Boolean @default(false)
431
+
432
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
433
+
434
+ @@unique([userId, name])
435
+ @@index([userId])
436
+ @@map("harness_plugins")
437
+ }
438
+
439
+ // P2 提示词平台:系统提示词模板(DB 版本化,服务端唯一来源)
440
+ model SystemPromptTemplate {
441
+ id String @id @default(cuid())
442
+ key String @unique
443
+ name String
444
+ description String?
445
+ sections Json @default("[]")
446
+ variables Json @default("[]")
447
+ version Int @default(1)
448
+ isActive Boolean @default(true)
449
+ isProtected Boolean @default(false)
450
+ updatedBy String?
451
+ createdAt DateTime @default(now())
452
+ updatedAt DateTime @updatedAt
453
+ versions SystemPromptVersion[]
454
+
455
+ @@map("system_prompt_templates")
456
+ }
457
+
458
+ // P2 提示词平台:系统提示词模板的历史版本快照。
459
+ // 设计取舍:仅快照 sections(真正发给 LLM 的提示词主体);variables 作为
460
+ // 元数据随模板演进不纳入版本管理——回滚只还原提示词文本,变量声明由模板表当前值兜底。
461
+ model SystemPromptVersion {
462
+ id String @id @default(cuid())
463
+ templateId String
464
+ template SystemPromptTemplate @relation(fields: [templateId], references: [id], onDelete: Cascade)
465
+ version Int
466
+ sections Json
467
+ note String?
468
+ createdBy String?
469
+ createdAt DateTime @default(now())
470
+
471
+ @@unique([templateId, version])
472
+ @@map("system_prompt_versions")
473
+ }
474
+
475
+ // P2 异构多智能体:板块 agent 绑定(三级链第①级:板块绑定 > 用户默认 > 系统默认)。
476
+ // 设计取舍:① 硬删(无独立业务生命周期,upsert/deleteMany 管理)而非 isDeleted 软删;
477
+ // ② workspaceId 为跨工作区绑定的预留字段,当前不建 relation——bizKey 已表达业务作用域,
478
+ // 工作区级绑定待 P3 启用时再补 relation + 索引。
479
+ model BusinessAgentBinding {
480
+ id String @id @default(cuid())
481
+ userId String
482
+ bizKey String
483
+ agentId String
484
+ workspaceId String?
485
+ createdAt DateTime @default(now())
486
+ updatedAt DateTime @updatedAt
487
+
488
+ agent UserAgent @relation(fields: [agentId], references: [id], onDelete: Cascade)
489
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
490
+
491
+ @@unique([userId, bizKey])
492
+ @@index([userId])
493
+ @@map("business_agent_bindings")
494
+ }
495
+
386
496
  // 媒体生成记录(占位,本轮建表不接入业务)
387
497
  model GenerationRun {
388
498
  id String @id @default(cuid())
@@ -393,9 +503,15 @@ model GenerationRun {
393
503
  input Json?
394
504
  result Json?
395
505
  artifactId String?
506
+ activity String? // 官方 GenerationRunRecord 视角:chat|image|audio|tts|video|transcription|sandbox
507
+ provider String?
508
+ model String?
509
+ artifacts Json?
510
+ usage Json?
396
511
  error String? @db.Text
397
512
  startedAt DateTime @default(now())
398
513
  finishedAt DateTime?
514
+ linkedTarget Json? // P4d 回流标记 { kind: story|kb|prd, targetId, at },最近一次(覆盖)
399
515
 
400
516
  thread ChatThread @relation(fields: [threadId], references: [id], onDelete: Cascade)
401
517
 
@@ -422,12 +538,14 @@ model LoginLog {
422
538
 
423
539
  // 邀请码
424
540
  model InvitationCode {
425
- id String @id @default(cuid())
426
- code String @unique
427
- maxUses Int @default(1)
428
- usedCount Int @default(0)
429
- expiresAt DateTime
430
- createdAt DateTime @default(now())
541
+ id String @id @default(cuid())
542
+ code String @unique
543
+ maxUses Int @default(1)
544
+ usedCount Int @default(0)
545
+ expiresAt DateTime
546
+ createdAt DateTime @default(now())
547
+ createdById String?
548
+ disabledAt DateTime?
431
549
 
432
550
  uses InvitationUse[]
433
551
 
@@ -461,6 +579,82 @@ model PasswordResetToken {
461
579
  @@map("password_reset_tokens")
462
580
  }
463
581
 
582
+ // 邮箱验证令牌
583
+ model EmailVerificationToken {
584
+ id String @id @default(cuid())
585
+ token String @unique
586
+ userId String
587
+ expiresAt DateTime
588
+ usedAt DateTime?
589
+ createdAt DateTime @default(now())
590
+
591
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
592
+
593
+ @@map("email_verification_tokens")
594
+ }
595
+
596
+ // 出站邮件日志
597
+ model EmailLog {
598
+ id String @id @default(cuid())
599
+ to String
600
+ templateKey String
601
+ category String
602
+ status String
603
+ provider String
604
+ messageId String?
605
+ dedupeKey String? @unique
606
+ error String?
607
+ userId String?
608
+ createdAt DateTime @default(now())
609
+ sentAt DateTime?
610
+
611
+ @@index([to, createdAt])
612
+ @@index([userId, createdAt])
613
+ @@index([status])
614
+ @@map("email_logs")
615
+ }
616
+
617
+ // 用户邮件偏好
618
+ model EmailPreference {
619
+ userId String @id
620
+ unsubscribedAll Boolean @default(false)
621
+ unsubscribedCategories Json @default("[]")
622
+ suppressed Boolean @default(false)
623
+
624
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
625
+
626
+ @@map("email_preferences")
627
+ }
628
+
629
+ // 第三方登录配置(admin 后台维护)
630
+ model OAuthProviderConfig {
631
+ id String @id @default(cuid())
632
+ provider String @unique
633
+ clientId String
634
+ clientSecret String // AES-256-GCM 密文
635
+ enabled Boolean @default(false)
636
+ extra Json?
637
+ createdAt DateTime @default(now())
638
+ updatedAt DateTime @updatedAt
639
+
640
+ @@map("oauth_provider_configs")
641
+ }
642
+
643
+ // 产品更新订阅者(changelog)
644
+ model EmailSubscriber {
645
+ id String @id @default(cuid())
646
+ email String @unique
647
+ locale String @default("zh")
648
+ confirmToken String @unique
649
+ confirmedAt DateTime?
650
+ unsubscribedAt DateTime?
651
+ source String @default("changelog")
652
+ createdAt DateTime @default(now())
653
+
654
+ @@index([confirmedAt, unsubscribedAt])
655
+ @@map("email_subscribers")
656
+ }
657
+
464
658
  enum Role {
465
659
  SUPER_ADMIN
466
660
  ADMIN
@@ -512,10 +706,10 @@ model KnowledgeBase {
512
706
  createdAt DateTime @default(now())
513
707
  updatedAt DateTime @updatedAt
514
708
 
515
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
516
- workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: SetNull)
517
- documents KnowledgeDocument[]
518
- projectLinks ProjectKnowledgeBase[]
709
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
710
+ workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: SetNull)
711
+ documents KnowledgeDocument[]
712
+ projectLinks ProjectKnowledgeBase[]
519
713
  workspaceLinks WorkspaceKnowledgeBase[]
520
714
 
521
715
  @@index([userId])
@@ -540,11 +734,11 @@ model KnowledgeDocument {
540
734
  createdAt DateTime @default(now())
541
735
  updatedAt DateTime @updatedAt
542
736
 
543
- kb KnowledgeBase @relation(fields: [kbId], references: [id], onDelete: Cascade)
544
- parent KnowledgeDocument? @relation("DocumentTree", fields: [parentId], references: [id], onDelete: SetNull)
545
- children KnowledgeDocument[] @relation("DocumentTree")
546
- creator User @relation(fields: [createdBy], references: [id], onDelete: Cascade)
547
- linkedStories StoryDocLink[] @relation("DocStoryLinks")
737
+ kb KnowledgeBase @relation(fields: [kbId], references: [id], onDelete: Cascade)
738
+ parent KnowledgeDocument? @relation("DocumentTree", fields: [parentId], references: [id], onDelete: SetNull)
739
+ children KnowledgeDocument[] @relation("DocumentTree")
740
+ creator User @relation(fields: [createdBy], references: [id], onDelete: Cascade)
741
+ linkedStories StoryDocLink[] @relation("DocStoryLinks")
548
742
  workspaceQuickDocs WorkspaceQuickDoc[]
549
743
 
550
744
  @@index([kbId])
@@ -1214,9 +1408,12 @@ model AiProviderConfig {
1214
1408
  providerId String // 业务 providerId,软关联 AiProvider.providerId(不设外键 cascade,避免 admin 删除丢失用户配置)
1215
1409
  apiKey String? @db.Text // 加密存储 TODO
1216
1410
  baseUrl String?
1411
+ voiceApiKey String? @db.Text // BytePlus Voice 独立 API key(speech/transcription 用,与 Ark apiKey 分开)
1412
+ voiceBaseUrl String? // BytePlus Voice Base URL(默认 fallback 到 baseUrl)
1217
1413
  enabled Boolean @default(false) // 用户级开关:是否在对话模型选择器中暴露
1218
1414
  models Json? // string[] 用户启用的模型 ID(有序,顺序 = 模型选择器展示顺序)
1219
1415
  customModels Json? // AiModelMeta[] 用户私有的自定义/刷新获取的模型元数据,与 AiProvider.models 取并集按 id 去重
1416
+ agentMeta Json? // 模式2 本地 Agent 元数据:{ binary, resolvedPath, version, auth, workspaceDir, detectedAt };不存任何密钥
1220
1417
  createdAt DateTime @default(now())
1221
1418
  updatedAt DateTime @updatedAt
1222
1419
 
@@ -1838,8 +2035,11 @@ model Plan {
1838
2035
  providerSeatPriceIdUsd String?
1839
2036
  providerSeatPriceIdCny String?
1840
2037
 
1841
- agentQuota Int?
1842
- skillQuota Int?
2038
+ agentQuota Int?
2039
+ skillQuota Int?
2040
+ sandboxMinutesMonthly Int?
2041
+ mediaGenerationsMonthly Int?
2042
+ galleryStorageMb Int?
1843
2043
 
1844
2044
  subscriptions Subscription[]
1845
2045
 
@@ -1915,11 +2115,14 @@ enum UsageMetric {
1915
2115
  /// AI 用量明细(按次扣减 + 成本审计)
1916
2116
  model AiUsageLog {
1917
2117
  id String @id @default(cuid())
1918
- workspaceId String
1919
- workspace Workspace @relation(fields: [workspaceId], references: [id])
2118
+ // 可空:配额按 userId 计(见 ResourceRegistry.sandboxMinutesMonthly),工作区只作归属维度。
2119
+ // 不可空会让「尚无工作区的用户」无法落计量行,等于沙箱计费闸可被绕过。
2120
+ workspaceId String?
2121
+ workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: Restrict)
1920
2122
  userId String
1921
2123
  user User @relation(fields: [userId], references: [id])
1922
2124
  source String @default("byok")
2125
+ activity String? // 区分 chat/sandbox/image...(P3 计费维度;null = 既有 byok 语义)
1923
2126
  provider String
1924
2127
  model String
1925
2128
  inputTokens Int @default(0)
@@ -2131,9 +2334,12 @@ model UserAgent {
2131
2334
  createdAt DateTime @default(now())
2132
2335
  updatedAt DateTime @updatedAt
2133
2336
  isDeleted Boolean @default(false)
2337
+ isDefault Boolean @default(false)
2338
+ harnessKind String? // code preset:claude-code | codex | acp | opencode(null = 普通对话 agent)
2134
2339
 
2135
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
2136
- threads ChatThread[]
2340
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
2341
+ threads ChatThread[]
2342
+ agentBindings BusinessAgentBinding[]
2137
2343
 
2138
2344
  @@index([userId])
2139
2345
  @@map("user_agents")
@@ -2193,12 +2399,13 @@ model Notification {
2193
2399
 
2194
2400
  // 通知偏好(免打扰时段、分类开关)
2195
2401
  model NotificationPreference {
2196
- userId String @id
2197
- categories Json
2198
- dndEnabled Boolean @default(false)
2199
- dndStart String @default("22:00")
2200
- dndEnd String @default("08:00")
2201
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
2402
+ userId String @id
2403
+ categories Json
2404
+ emailCategories Json @default("{}")
2405
+ dndEnabled Boolean @default(false)
2406
+ dndStart String @default("22:00")
2407
+ dndEnd String @default("08:00")
2408
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
2202
2409
 
2203
2410
  @@map("notification_preferences")
2204
2411
  }
@@ -2240,3 +2447,110 @@ model IterationAutoSchedule {
2240
2447
 
2241
2448
  @@map("iteration_auto_schedules")
2242
2449
  }
2450
+
2451
+ // 编排模式可复用片段:用户保存的跨请求编排逻辑。运行时经 getSnippetBindings
2452
+ // 暴露为 snippet_<name> 绑定,片段函数体在嵌套沙箱内执行并可调用 external_* 工具。
2453
+ // 片段本身不豁免归属校验,execute 只在服务端执行,不进客户端 bundle。
2454
+ model CodeSnippet {
2455
+ id String @id @default(cuid())
2456
+ userId String
2457
+ name String
2458
+ title String
2459
+ description String
2460
+ params Json @default("{}")
2461
+ code String @db.Text
2462
+ enabled Boolean @default(true)
2463
+ createdAt DateTime @default(now())
2464
+ updatedAt DateTime @updatedAt
2465
+ isDeleted Boolean @default(false)
2466
+
2467
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
2468
+
2469
+ @@unique([userId, name])
2470
+ @@index([userId, enabled, isDeleted])
2471
+ @@map("code_snippets")
2472
+ }
2473
+
2474
+ // P3 durable runs:沙箱实例映射(SandboxInstanceStore 的 Prisma 实现,key = computeSandboxKey 复合键)
2475
+ model SandboxInstance {
2476
+ key String @id
2477
+ provider String
2478
+ providerSandboxId String
2479
+ latestSnapshotId String?
2480
+ threadId String
2481
+ latestRunId String?
2482
+ updatedAt BigInt // epoch ms(契约要求;int4 上限 2.1e9 装不下毫秒,须 int8)
2483
+ createdAt DateTime @default(now())
2484
+
2485
+ @@index([threadId])
2486
+ @@map("sandbox_instances")
2487
+ }
2488
+
2489
+ // P3 durable runs:PG StreamDurability 事件日志(每 chunk 一行,id=offset)
2490
+ model AiStreamChunk {
2491
+ id BigInt @id @default(autoincrement())
2492
+ runId String
2493
+ chunk Json
2494
+ createdAt DateTime @default(now())
2495
+
2496
+ @@index([runId, id])
2497
+ @@map("ai_stream_chunks")
2498
+ }
2499
+
2500
+ model DesktopSetting {
2501
+ key String @id // "aiSourceMode" | "localAgentConfig"
2502
+ value Json
2503
+
2504
+ @@map("desktop_settings")
2505
+ }
2506
+
2507
+ /// Harness 工作区(云端持久化文件区 + 业务数据视图入口)
2508
+ model HarnessWorkspace {
2509
+ id String @id @default(cuid())
2510
+ name String
2511
+ ownerId String
2512
+ kind String @default("cloud") // "cloud" | "local-meta"(本地挂载只存元数据)
2513
+ createdAt DateTime @default(now())
2514
+ updatedAt DateTime @updatedAt
2515
+
2516
+ owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade)
2517
+ files WorkspaceFile[]
2518
+ threads ChatThread[]
2519
+
2520
+ @@index([ownerId, updatedAt])
2521
+ @@map("harness_workspaces")
2522
+ }
2523
+
2524
+ /// 工作区文件(上传文件 + AI 生成物 + 沙箱产出)
2525
+ model WorkspaceFile {
2526
+ id String @id @default(cuid())
2527
+ workspaceId String
2528
+ path String // 相对路径,如 "src/index.ts"
2529
+ mimeType String @default("application/octet-stream")
2530
+ size Int @default(0)
2531
+ content String? @db.Text // 小文件内联(≤256KB);大文件走 blob 存储(P4c)
2532
+ source String @default("upload") // "upload" | "ai-generated" | "sandbox"
2533
+ createdAt DateTime @default(now())
2534
+ updatedAt DateTime @updatedAt
2535
+
2536
+ workspace HarnessWorkspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
2537
+
2538
+ @@unique([workspaceId, path])
2539
+ @@index([workspaceId])
2540
+ @@map("workspace_files")
2541
+ }
2542
+
2543
+ // AI 附件二进制存储(P5 Wave 2)
2544
+ model Blob {
2545
+ id String @id @default(cuid())
2546
+ mimeType String
2547
+ bytes Bytes
2548
+ size Int
2549
+ userId String
2550
+ createdAt DateTime @default(now())
2551
+
2552
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
2553
+
2554
+ @@index([userId])
2555
+ @@map("blobs")
2556
+ }