@allbluecn/database 0.4.15 → 0.4.17

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 (42) hide show
  1. package/generated/browser.ts +20 -0
  2. package/generated/client.ts +20 -0
  3. package/generated/commonInputTypes.ts +34 -0
  4. package/generated/internal/class.ts +44 -4
  5. package/generated/internal/prismaNamespace.ts +378 -3
  6. package/generated/internal/prismaNamespaceBrowser.ts +63 -2
  7. package/generated/models/Iteration.ts +1878 -0
  8. package/generated/models/IterationAutoSchedule.ts +1485 -0
  9. package/generated/models/KnowledgeBase.ts +138 -0
  10. package/generated/models/Project.ts +484 -0
  11. package/generated/models/ProjectKnowledgeBase.ts +1430 -0
  12. package/generated/models/Story.ts +663 -3
  13. package/generated/models/StoryAttachment.ts +110 -1
  14. package/generated/models/StoryExternalLink.ts +1352 -0
  15. package/generated/models/User.ts +618 -0
  16. package/generated/models.ts +4 -0
  17. package/generated-sqlite/browser.ts +20 -0
  18. package/generated-sqlite/client.ts +20 -0
  19. package/generated-sqlite/internal/class.ts +44 -4
  20. package/generated-sqlite/internal/prismaNamespace.ts +374 -2
  21. package/generated-sqlite/internal/prismaNamespaceBrowser.ts +73 -1
  22. package/generated-sqlite/models/Iteration.ts +1874 -0
  23. package/generated-sqlite/models/IterationAutoSchedule.ts +1483 -0
  24. package/generated-sqlite/models/KnowledgeBase.ts +138 -0
  25. package/generated-sqlite/models/Project.ts +634 -0
  26. package/generated-sqlite/models/ProjectKnowledgeBase.ts +1426 -0
  27. package/generated-sqlite/models/Story.ts +3263 -0
  28. package/generated-sqlite/models/User.ts +2103 -107
  29. package/generated-sqlite/models.ts +4 -0
  30. package/index.ts +2 -2
  31. package/migrations/20260831063744_project_knowledge_base/migration.sql +24 -0
  32. package/migrations/20260831123150_story_external_link/migration.sql +19 -0
  33. package/migrations/20260831151740_story_attachment_bytes/migration.sql +2 -0
  34. package/migrations/20260831203925_story_attachment_file_hash/migration.sql +2 -0
  35. package/migrations/20260901010000_story_attachment_description/migration.sql +2 -0
  36. package/migrations/20260901020000_story_attachment_file_hash/migration.sql +2 -0
  37. package/migrations/20260901134601_iterations/migration.sql +52 -0
  38. package/migrations/20260902000000_story_identifier_per_project/migration.sql +37 -0
  39. package/migrations/20260902000100_story_identifier_counter_init/migration.sql +11 -0
  40. package/package.json +12 -5
  41. package/schema.prisma +98 -17
  42. package/schema.sqlite.prisma +112 -9
@@ -27,6 +27,7 @@ export type * from './models/InvitationCode'
27
27
  export type * from './models/InvitationUse'
28
28
  export type * from './models/PasswordResetToken'
29
29
  export type * from './models/KnowledgeBase'
30
+ export type * from './models/ProjectKnowledgeBase'
30
31
  export type * from './models/KnowledgeDocument'
31
32
  export type * from './models/PRD'
32
33
  export type * from './models/AgentConversation'
@@ -86,4 +87,7 @@ export type * from './models/ComplianceExport'
86
87
  export type * from './models/UserAgent'
87
88
  export type * from './models/UserSkill'
88
89
  export type * from './models/DeveloperLog'
90
+ export type * from './models/Story'
91
+ export type * from './models/Iteration'
92
+ export type * from './models/IterationAutoSchedule'
89
93
  export type * from './commonInputTypes'
package/index.ts CHANGED
@@ -18,7 +18,7 @@
18
18
  import { PrismaClient } from "./generated/client";
19
19
  import { PrismaPg } from "@prisma/adapter-pg";
20
20
  import { Prisma } from "./generated/client";
21
- import { registerPrismaSeam } from "@allbluecn/shared/server-seam";
21
+ import { registerPrismaSeam } from "@allbluecn/kernel";
22
22
 
23
23
  const globalForPrisma = globalThis as unknown as {
24
24
  prisma: PrismaClient | undefined;
@@ -65,7 +65,7 @@ export const prisma: PrismaClient = globalForPrisma.prisma ?? (await createPrism
65
65
  if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
66
66
 
67
67
  // 注册 PrismaSeam,供 shared 包注入式访问 prisma
68
- registerPrismaSeam(prisma as unknown as import("@allbluecn/shared/server-seam").PrismaSeam);
68
+ registerPrismaSeam(prisma as unknown as import("@allbluecn/kernel").PrismaSeam);
69
69
 
70
70
  export { Prisma };
71
71
  export type { PrismaClient } from "./generated/client";
@@ -0,0 +1,24 @@
1
+ -- CreateTable
2
+ CREATE TABLE "project_knowledge_bases" (
3
+ "id" TEXT NOT NULL,
4
+ "projectId" TEXT NOT NULL,
5
+ "kbId" TEXT NOT NULL,
6
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
7
+
8
+ CONSTRAINT "project_knowledge_bases_pkey" PRIMARY KEY ("id")
9
+ );
10
+
11
+ -- CreateIndex
12
+ CREATE INDEX "project_knowledge_bases_projectId_idx" ON "project_knowledge_bases"("projectId");
13
+
14
+ -- CreateIndex
15
+ CREATE INDEX "project_knowledge_bases_kbId_idx" ON "project_knowledge_bases"("kbId");
16
+
17
+ -- CreateIndex
18
+ CREATE UNIQUE INDEX "project_knowledge_bases_projectId_kbId_key" ON "project_knowledge_bases"("projectId", "kbId");
19
+
20
+ -- AddForeignKey
21
+ ALTER TABLE "project_knowledge_bases" ADD CONSTRAINT "project_knowledge_bases_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "projects"("id") ON DELETE CASCADE ON UPDATE CASCADE;
22
+
23
+ -- AddForeignKey
24
+ ALTER TABLE "project_knowledge_bases" ADD CONSTRAINT "project_knowledge_bases_kbId_fkey" FOREIGN KEY ("kbId") REFERENCES "knowledge_bases"("id") ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,19 @@
1
+ -- CreateTable
2
+ CREATE TABLE "story_external_links" (
3
+ "id" TEXT NOT NULL,
4
+ "storyId" TEXT NOT NULL,
5
+ "group" TEXT NOT NULL,
6
+ "externalId" TEXT NOT NULL,
7
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
8
+
9
+ CONSTRAINT "story_external_links_pkey" PRIMARY KEY ("id")
10
+ );
11
+
12
+ -- CreateIndex
13
+ CREATE INDEX "story_external_links_storyId_idx" ON "story_external_links"("storyId");
14
+
15
+ -- CreateIndex
16
+ CREATE UNIQUE INDEX "story_external_links_storyId_group_externalId_key" ON "story_external_links"("storyId", "group", "externalId");
17
+
18
+ -- AddForeignKey
19
+ ALTER TABLE "story_external_links" ADD CONSTRAINT "story_external_links_storyId_fkey" FOREIGN KEY ("storyId") REFERENCES "stories"("id") ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,2 @@
1
+ -- AlterTable
2
+ ALTER TABLE "story_attachments" ADD COLUMN "bytes" BYTEA;
@@ -0,0 +1,2 @@
1
+ -- 恢复丢失的迁移:story_attachments 新增 fileHash 列(内容去重)
2
+ ALTER TABLE "story_attachments" ADD COLUMN IF NOT EXISTS "fileHash" TEXT;
@@ -0,0 +1,2 @@
1
+ -- AlterTable
2
+ ALTER TABLE "story_attachments" ADD COLUMN IF NOT EXISTS "description" TEXT;
@@ -0,0 +1,2 @@
1
+ -- 恢复丢失的迁移:fileHash 索引(幂等,列已存在场景)
2
+ CREATE INDEX IF NOT EXISTS "story_attachments_fileHash_idx" ON "story_attachments"("fileHash");
@@ -0,0 +1,52 @@
1
+ -- AlterTable
2
+ ALTER TABLE "stories" ADD COLUMN "iterationId" TEXT;
3
+
4
+ -- CreateTable
5
+ CREATE TABLE "iterations" (
6
+ "id" TEXT NOT NULL,
7
+ "projectId" TEXT NOT NULL,
8
+ "name" TEXT NOT NULL,
9
+ "description" TEXT,
10
+ "startDate" TIMESTAMP(3) NOT NULL,
11
+ "endDate" TIMESTAMP(3) NOT NULL,
12
+ "archived" BOOLEAN NOT NULL DEFAULT false,
13
+ "archivedAt" TIMESTAMP(3),
14
+ "createdById" TEXT NOT NULL,
15
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
16
+ "updatedAt" TIMESTAMP(3) NOT NULL,
17
+
18
+ CONSTRAINT "iterations_pkey" PRIMARY KEY ("id")
19
+ );
20
+
21
+ -- CreateTable
22
+ CREATE TABLE "iteration_auto_schedules" (
23
+ "projectId" TEXT NOT NULL,
24
+ "enabled" BOOLEAN NOT NULL DEFAULT false,
25
+ "title" TEXT NOT NULL DEFAULT '迭代',
26
+ "durationDays" INTEGER NOT NULL DEFAULT 14,
27
+ "cooldownDays" INTEGER NOT NULL DEFAULT 0,
28
+ "startsOn" TIMESTAMP(3) NOT NULL,
29
+ "futureCount" INTEGER NOT NULL DEFAULT 2,
30
+ "autoRollover" BOOLEAN NOT NULL DEFAULT false,
31
+ "lastSeq" INTEGER NOT NULL DEFAULT 0,
32
+
33
+ CONSTRAINT "iteration_auto_schedules_pkey" PRIMARY KEY ("projectId")
34
+ );
35
+
36
+ -- CreateIndex
37
+ CREATE INDEX "iterations_projectId_startDate_idx" ON "iterations"("projectId", "startDate");
38
+
39
+ -- CreateIndex
40
+ CREATE INDEX "iterations_archived_idx" ON "iterations"("archived");
41
+
42
+ -- AddForeignKey
43
+ ALTER TABLE "stories" ADD CONSTRAINT "stories_iterationId_fkey" FOREIGN KEY ("iterationId") REFERENCES "iterations"("id") ON DELETE SET NULL ON UPDATE CASCADE;
44
+
45
+ -- AddForeignKey
46
+ ALTER TABLE "iterations" ADD CONSTRAINT "iterations_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "projects"("id") ON DELETE CASCADE ON UPDATE CASCADE;
47
+
48
+ -- AddForeignKey
49
+ ALTER TABLE "iterations" ADD CONSTRAINT "iterations_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
50
+
51
+ -- AddForeignKey
52
+ ALTER TABLE "iteration_auto_schedules" ADD CONSTRAINT "iteration_auto_schedules_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "projects"("id") ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,37 @@
1
+ -- Story identifier 改为项目内唯一:独立需求(displayId='STORY')按用户独立计数,从 STORY-1 开始
2
+ -- 1. 删除全局唯一索引(历史上以裸 UNIQUE INDEX 形式创建,非约束)
3
+ DROP INDEX IF EXISTS "stories_identifier_key";
4
+
5
+ -- 2. 重编号独立需求:先把参与行改为临时名,避免批量重写期间瞬时同名冲突
6
+ WITH ranked AS (
7
+ SELECT s.id
8
+ FROM "stories" s
9
+ JOIN "projects" p ON p.id = s."projectId"
10
+ WHERE p."displayId" = 'STORY'
11
+ )
12
+ UPDATE "stories" s
13
+ SET "identifier" = 'TMP-' || s.id
14
+ FROM ranked r
15
+ WHERE s.id = r.id;
16
+
17
+ -- 3. 每个项目(即每个用户)按创建顺序重排为 STORY-1..N
18
+ WITH ranked AS (
19
+ SELECT s.id,
20
+ ROW_NUMBER() OVER (PARTITION BY s."projectId" ORDER BY s."createdAt", s.id) AS rn
21
+ FROM "stories" s
22
+ JOIN "projects" p ON p.id = s."projectId"
23
+ WHERE p."displayId" = 'STORY'
24
+ )
25
+ UPDATE "stories" s
26
+ SET "identifier" = 'STORY-' || r.rn,
27
+ "sequenceId" = r.rn
28
+ FROM ranked r
29
+ WHERE s.id = r.id;
30
+
31
+ -- 4. 重置计数器:清掉全局计数器与独立项目计数器(新逻辑将按 projectId 计数)
32
+ DELETE FROM "sequence_counters" WHERE scope = 'global';
33
+ DELETE FROM "sequence_counters"
34
+ WHERE scope IN (SELECT id FROM "projects" WHERE "displayId" = 'STORY');
35
+
36
+ -- 5. 新复合唯一约束(项目内 identifier 唯一)
37
+ ALTER TABLE "stories" ADD CONSTRAINT "stories_projectId_identifier_key" UNIQUE ("projectId", "identifier");
@@ -0,0 +1,11 @@
1
+ -- 补丁:初始化独立项目计数器为各项目现有 max(sequenceId),避免新需求编号与重编号后的已有需求冲突
2
+ INSERT INTO "sequence_counters" ("id", "scope", "seq")
3
+ SELECT md5(random()::text || s.scope), s.scope, s.seq
4
+ FROM (
5
+ SELECT p.id AS scope, COALESCE(MAX(st."sequenceId"), 0) AS seq
6
+ FROM "projects" p
7
+ LEFT JOIN "stories" st ON st."projectId" = p.id
8
+ WHERE p."displayId" = 'STORY'
9
+ GROUP BY p.id
10
+ ) s
11
+ ON CONFLICT ("scope") DO UPDATE SET "seq" = GREATEST("sequence_counters"."seq", EXCLUDED."seq");
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@allbluecn/database",
3
- "version": "0.4.15",
3
+ "version": "0.4.17",
4
4
  "license": "AGPL-3.0-or-later",
5
5
  "type": "module",
6
- "main": "./index.ts",
7
- "types": "./index.ts",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
8
  "dependencies": {
9
9
  "@prisma/adapter-better-sqlite3": "^7.9.0",
10
10
  "@prisma/adapter-pg": "7.8.0",
@@ -15,7 +15,7 @@
15
15
  "pg": "^8.22.0",
16
16
  "sqlite-vec": "^0.1.9",
17
17
  "bcryptjs": "^3.0.2",
18
- "@allbluecn/shared": "0.4.16"
18
+ "@allbluecn/kernel": "0.5.2"
19
19
  },
20
20
  "devDependencies": {
21
21
  "@types/better-sqlite3": "^7.6.13",
@@ -25,7 +25,10 @@
25
25
  },
26
26
  "exports": {
27
27
  ".": "./index.ts",
28
- "./lib/share-utils": "./src/lib/share-utils.ts"
28
+ "./lib/share-utils": {
29
+ "types": "./dist/lib/share-utils.d.ts",
30
+ "default": "./dist/lib/share-utils.js"
31
+ }
29
32
  },
30
33
  "repository": {
31
34
  "type": "git",
@@ -36,6 +39,7 @@
36
39
  "url": "https://github.com/urmynami/AllBlue/issues"
37
40
  },
38
41
  "files": [
42
+ "dist",
39
43
  "src",
40
44
  "!src/**/*.test.*",
41
45
  "!src/**/__tests__/**",
@@ -49,6 +53,9 @@
49
53
  "desktop-init.d.ts",
50
54
  "index.ts"
51
55
  ],
56
+ "publishConfig": {
57
+ "access": "public"
58
+ },
52
59
  "scripts": {
53
60
  "generate": "prisma generate",
54
61
  "migrate:dev": "prisma migrate dev",
package/schema.prisma CHANGED
@@ -83,7 +83,8 @@ model User {
83
83
  designProjects DesignProject[]
84
84
  storiesCreated Story[] @relation("storyCreator")
85
85
  storiesAssigned Story[] @relation("storyAssignee")
86
- storiesEdited Story[] @relation("storyEditor")
86
+ storiesEdited Story[] @relation("storyEditor")
87
+ iterationsCreated Iteration[] @relation("iterationCreator")
87
88
  labelsCreated Label[] @relation("labelCreator")
88
89
  storyActivities StoryActivity[] @relation("storyActivityUser")
89
90
  storyComments StoryComment[] @relation("storyCommentUser")
@@ -152,8 +153,11 @@ model Project {
152
153
  workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: SetNull)
153
154
  members ProjectMember[]
154
155
  activities ProjectActivity[]
155
- stories Story[]
156
- createdAt DateTime @default(now())
156
+ stories Story[]
157
+ iterations Iteration[]
158
+ iterationAutoSchedule IterationAutoSchedule?
159
+ knowledgeBases ProjectKnowledgeBase[]
160
+ createdAt DateTime @default(now())
157
161
  updatedAt DateTime @updatedAt
158
162
 
159
163
  @@unique([ownerId, displayId])
@@ -479,11 +483,12 @@ model KnowledgeBase {
479
483
  createdAt DateTime @default(now())
480
484
  updatedAt DateTime @updatedAt
481
485
 
482
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
483
- documents KnowledgeDocument[]
486
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
487
+ documents KnowledgeDocument[]
488
+ projectLinks ProjectKnowledgeBase[]
484
489
 
485
- @@index([userId])
486
- @@map("knowledge_bases")
490
+ @@index([userId])
491
+ @@map("knowledge_bases")
487
492
  }
488
493
 
489
494
  model KnowledgeDocument {
@@ -1413,8 +1418,11 @@ model Story {
1413
1418
  attachments StoryAttachment[]
1414
1419
  linkedPrds StoryPrdLink[] @relation("StoryPrdLinks")
1415
1420
  linkedDocs StoryDocLink[] @relation("StoryDocLinks")
1421
+ linkedExternalDocs StoryExternalLink[] @relation("StoryExternalLinks")
1422
+ iterationId String?
1423
+ iteration Iteration? @relation(fields: [iterationId], references: [id], onDelete: SetNull)
1416
1424
 
1417
- @@unique([identifier])
1425
+ @@unique([projectId, identifier])
1418
1426
  @@index([projectId, sequenceId])
1419
1427
  @@index([state])
1420
1428
  @@index([archived])
@@ -1538,6 +1546,22 @@ model StoryDependency {
1538
1546
  @@map("story_dependencies")
1539
1547
  }
1540
1548
 
1549
+ // 项目关联知识库(join 表;关联时仅允许 visibility=team,general 全局可见无需关联,private 跨用户不可读)
1550
+ model ProjectKnowledgeBase {
1551
+ id String @id @default(cuid())
1552
+ projectId String
1553
+ kbId String
1554
+ createdAt DateTime @default(now())
1555
+
1556
+ project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
1557
+ kb KnowledgeBase @relation(fields: [kbId], references: [id], onDelete: Cascade)
1558
+
1559
+ @@unique([projectId, kbId])
1560
+ @@index([projectId])
1561
+ @@index([kbId])
1562
+ @@map("project_knowledge_bases")
1563
+ }
1564
+
1541
1565
  model StoryLink {
1542
1566
  id String @id @default(cuid())
1543
1567
  storyId String
@@ -1554,17 +1578,21 @@ model StoryLink {
1554
1578
  }
1555
1579
 
1556
1580
  model StoryAttachment {
1557
- id String @id @default(cuid())
1558
- storyId String
1559
- fileName String
1560
- fileSize BigInt
1561
- mimeType String
1562
- storageUrl String
1563
- createdAt DateTime @default(now())
1581
+ id String @id @default(cuid())
1582
+ storyId String
1583
+ fileName String
1584
+ fileSize BigInt
1585
+ mimeType String
1586
+ description String?
1587
+ storageUrl String
1588
+ bytes Bytes?
1589
+ fileHash String? @db.Text
1590
+ createdAt DateTime @default(now())
1564
1591
 
1565
1592
  story Story @relation(fields: [storyId], references: [id], onDelete: Cascade)
1566
1593
 
1567
1594
  @@index([storyId])
1595
+ @@index([fileHash])
1568
1596
  @@map("story_attachments")
1569
1597
  }
1570
1598
 
@@ -1598,6 +1626,21 @@ model StoryDocLink {
1598
1626
  @@map("story_doc_links")
1599
1627
  }
1600
1628
 
1629
+ // 通用知识库条目(法律法规/行业合规/词典词条/网站收藏)与需求的关联
1630
+ model StoryExternalLink {
1631
+ id String @id @default(cuid())
1632
+ storyId String
1633
+ group String
1634
+ externalId String
1635
+ createdAt DateTime @default(now())
1636
+
1637
+ story Story @relation("StoryExternalLinks", fields: [storyId], references: [id], onDelete: Cascade)
1638
+
1639
+ @@unique([storyId, group, externalId])
1640
+ @@index([storyId])
1641
+ @@map("story_external_links")
1642
+ }
1643
+
1601
1644
  enum DependencyType {
1602
1645
  BLOCKS
1603
1646
  STARTS_BEFORE
@@ -2081,7 +2124,45 @@ model NotificationPreference {
2081
2124
  dndEnabled Boolean @default(false)
2082
2125
  dndStart String @default("22:00")
2083
2126
  dndEnd String @default("08:00")
2084
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
2127
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
2085
2128
 
2086
- @@map("notification_preferences")
2129
+ @@map("notification_preferences")
2130
+ }
2131
+
2132
+ // 迭代(时间盒冲刺,状态由日期动态推导,不存状态字段)
2133
+ model Iteration {
2134
+ id String @id @default(cuid())
2135
+ projectId String
2136
+ project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
2137
+ name String
2138
+ description String? @db.Text
2139
+ startDate DateTime
2140
+ endDate DateTime
2141
+ archived Boolean @default(false)
2142
+ archivedAt DateTime?
2143
+ createdById String
2144
+ createdBy User @relation("iterationCreator", fields: [createdById], references: [id])
2145
+ createdAt DateTime @default(now())
2146
+ updatedAt DateTime @updatedAt
2147
+ stories Story[]
2148
+
2149
+ @@index([projectId, startDate])
2150
+ @@index([archived])
2151
+ @@map("iterations")
2152
+ }
2153
+
2154
+ // 迭代自动排期配置(一项目一行)
2155
+ model IterationAutoSchedule {
2156
+ projectId String @id
2157
+ project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
2158
+ enabled Boolean @default(false)
2159
+ title String @default("迭代")
2160
+ durationDays Int @default(14)
2161
+ cooldownDays Int @default(0)
2162
+ startsOn DateTime
2163
+ futureCount Int @default(2)
2164
+ autoRollover Boolean @default(false)
2165
+ lastSeq Int @default(0)
2166
+
2167
+ @@map("iteration_auto_schedules")
2087
2168
  }
@@ -86,8 +86,12 @@ model User {
86
86
  aiProviderConfigs AiProviderConfig[]
87
87
  agentConversations AgentConversation[]
88
88
  ownedProjects Project[] @relation("projectOwner")
89
- projectMemberships ProjectMember[]
90
- projectActivities ProjectActivity[]
89
+ projectMemberships ProjectMember[]
90
+ iterationsCreated Iteration[] @relation("iterationCreator")
91
+ storiesCreated Story[] @relation("storyCreator")
92
+ storiesAssigned Story[] @relation("storyAssignee")
93
+ storiesEdited Story[] @relation("storyEditor")
94
+ projectActivities ProjectActivity[]
91
95
  ownedWorkspaces Workspace[] @relation("workspaceOwner")
92
96
  workspaceMemberships TeamMembership[] @relation("teamOwner")
93
97
  teamJoined TeamMembership? @relation("teamMember")
@@ -114,9 +118,13 @@ model Project {
114
118
  owner User @relation("projectOwner", fields: [ownerId], references: [id])
115
119
  workspaceId String?
116
120
  workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: SetNull)
117
- members ProjectMember[]
118
- activities ProjectActivity[]
119
- createdAt DateTime @default(now())
121
+ members ProjectMember[]
122
+ activities ProjectActivity[]
123
+ knowledgeBases ProjectKnowledgeBase[]
124
+ iterations Iteration[]
125
+ iterationAutoSchedule IterationAutoSchedule?
126
+ stories Story[]
127
+ createdAt DateTime @default(now())
120
128
  updatedAt DateTime @updatedAt
121
129
 
122
130
  @@unique([ownerId, displayId])
@@ -398,11 +406,28 @@ model KnowledgeBase {
398
406
  createdAt DateTime @default(now())
399
407
  updatedAt DateTime @updatedAt
400
408
 
401
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
402
- documents KnowledgeDocument[]
409
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
410
+ documents KnowledgeDocument[]
411
+ projectLinks ProjectKnowledgeBase[]
403
412
 
404
- @@index([userId])
405
- @@map("knowledge_bases")
413
+ @@index([userId])
414
+ @@map("knowledge_bases")
415
+ }
416
+
417
+ // 项目关联知识库(join 表;关联时仅允许 visibility=team,general 全局可见无需关联,private 跨用户不可读)
418
+ model ProjectKnowledgeBase {
419
+ id String @id @default(cuid())
420
+ projectId String
421
+ kbId String
422
+ createdAt DateTime @default(now())
423
+
424
+ project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
425
+ kb KnowledgeBase @relation(fields: [kbId], references: [id], onDelete: Cascade)
426
+
427
+ @@unique([projectId, kbId])
428
+ @@index([projectId])
429
+ @@index([kbId])
430
+ @@map("project_knowledge_bases")
406
431
  }
407
432
 
408
433
  model KnowledgeDocument {
@@ -1622,3 +1647,81 @@ model DeveloperLog {
1622
1647
  @@index([year, date])
1623
1648
  @@map("developer_logs")
1624
1649
  }
1650
+
1651
+ // 需求(简化版,与 psql schema 对齐)
1652
+ model Story {
1653
+ id String @id @default(cuid())
1654
+ sequenceId Int
1655
+ boardOrder Int @default(0)
1656
+ identifier String
1657
+ projectId String
1658
+ project Project @relation(fields: [projectId], references: [id], onDelete: Restrict)
1659
+ name String
1660
+ description String?
1661
+ state String @default("backlog")
1662
+ priority String @default("none")
1663
+ archived Boolean @default(false)
1664
+ archivedAt DateTime?
1665
+ assigneeId String?
1666
+ assignee User? @relation("storyAssignee", fields: [assigneeId], references: [id], onDelete: SetNull)
1667
+ startDate DateTime?
1668
+ targetDate DateTime?
1669
+ createdById String
1670
+ createdBy User @relation("storyCreator", fields: [createdById], references: [id])
1671
+ updatedById String?
1672
+ updatedBy User? @relation("storyEditor", fields: [updatedById], references: [id], onDelete: SetNull)
1673
+ parentId String?
1674
+ parent Story? @relation("StoryHierarchy", fields: [parentId], references: [id], onDelete: SetNull)
1675
+ children Story[] @relation("StoryHierarchy")
1676
+ iterationId String?
1677
+ iteration Iteration? @relation(fields: [iterationId], references: [id], onDelete: SetNull)
1678
+ createdAt DateTime @default(now())
1679
+ updatedAt DateTime @updatedAt
1680
+
1681
+ @@unique([projectId, identifier])
1682
+ @@index([projectId, sequenceId])
1683
+ @@index([state])
1684
+ @@index([archived])
1685
+ @@index([archived, state, createdAt])
1686
+ @@index([assigneeId])
1687
+ @@index([createdById])
1688
+ @@map("stories")
1689
+ }
1690
+
1691
+ // 迭代(时间盒冲刺,状态由日期动态推导,不存状态字段)
1692
+ model Iteration {
1693
+ id String @id @default(cuid())
1694
+ projectId String
1695
+ project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
1696
+ name String
1697
+ description String?
1698
+ startDate DateTime
1699
+ endDate DateTime
1700
+ archived Boolean @default(false)
1701
+ archivedAt DateTime?
1702
+ createdById String
1703
+ createdBy User @relation("iterationCreator", fields: [createdById], references: [id])
1704
+ createdAt DateTime @default(now())
1705
+ updatedAt DateTime @updatedAt
1706
+ stories Story[]
1707
+
1708
+ @@index([projectId, startDate])
1709
+ @@index([archived])
1710
+ @@map("iterations")
1711
+ }
1712
+
1713
+ // 迭代自动排期配置(一项目一行)
1714
+ model IterationAutoSchedule {
1715
+ projectId String @id
1716
+ project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
1717
+ enabled Boolean @default(false)
1718
+ title String @default("迭代")
1719
+ durationDays Int @default(14)
1720
+ cooldownDays Int @default(0)
1721
+ startsOn DateTime
1722
+ futureCount Int @default(2)
1723
+ autoRollover Boolean @default(false)
1724
+ lastSeq Int @default(0)
1725
+
1726
+ @@map("iteration_auto_schedules")
1727
+ }