@allbluecn/database 0.6.0 → 0.8.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 (34) hide show
  1. package/generated/browser.ts +25 -0
  2. package/generated/client.ts +25 -0
  3. package/generated/internal/class.ts +54 -4
  4. package/generated/internal/prismaNamespace.ts +453 -2
  5. package/generated/internal/prismaNamespaceBrowser.ts +77 -1
  6. package/generated/models/EmailLog.ts +1345 -0
  7. package/generated/models/EmailPreference.ts +1257 -0
  8. package/generated/models/EmailSubscriber.ts +1233 -0
  9. package/generated/models/EmailVerificationToken.ts +1380 -0
  10. package/generated/models/InvitationCode.ts +65 -1
  11. package/generated/models/NotificationPreference.ts +27 -1
  12. package/generated/models/OAuthProviderConfig.ts +1227 -0
  13. package/generated/models/User.ts +1435 -157
  14. package/generated/models.ts +5 -0
  15. package/generated-sqlite/browser.ts +30 -0
  16. package/generated-sqlite/client.ts +30 -0
  17. package/generated-sqlite/internal/class.ts +64 -4
  18. package/generated-sqlite/internal/prismaNamespace.ts +541 -3
  19. package/generated-sqlite/internal/prismaNamespaceBrowser.ts +90 -2
  20. package/generated-sqlite/models/EmailLog.ts +1343 -0
  21. package/generated-sqlite/models/EmailPreference.ts +1255 -0
  22. package/generated-sqlite/models/EmailSubscriber.ts +1231 -0
  23. package/generated-sqlite/models/EmailVerificationToken.ts +1377 -0
  24. package/generated-sqlite/models/InvitationCode.ts +65 -1
  25. package/generated-sqlite/models/NotificationPreference.ts +1313 -0
  26. package/generated-sqlite/models/OAuthProviderConfig.ts +1225 -0
  27. package/generated-sqlite/models/User.ts +1867 -293
  28. package/generated-sqlite/models.ts +6 -0
  29. package/migrations/20260911120000_add_pgvector_tables/migration.sql +28 -0
  30. package/migrations/20260911171433_email_auth_invitation/migration.sql +80 -0
  31. package/migrations/20260912032616_email_p4_p8/migration.sql +42 -0
  32. package/package.json +2 -2
  33. package/schema.prisma +93 -12
  34. package/schema.sqlite.prisma +93 -4
@@ -26,6 +26,11 @@ export type * from './models/LoginLog.ts'
26
26
  export type * from './models/InvitationCode.ts'
27
27
  export type * from './models/InvitationUse.ts'
28
28
  export type * from './models/PasswordResetToken.ts'
29
+ export type * from './models/EmailVerificationToken.ts'
30
+ export type * from './models/EmailLog.ts'
31
+ export type * from './models/EmailPreference.ts'
32
+ export type * from './models/OAuthProviderConfig.ts'
33
+ export type * from './models/EmailSubscriber.ts'
29
34
  export type * from './models/KnowledgeBase.ts'
30
35
  export type * from './models/ProjectKnowledgeBase.ts'
31
36
  export type * from './models/WorkspaceKnowledgeBase.ts'
@@ -92,4 +97,5 @@ export type * from './models/DeveloperLog.ts'
92
97
  export type * from './models/Story.ts'
93
98
  export type * from './models/Iteration.ts'
94
99
  export type * from './models/IterationAutoSchedule.ts'
100
+ export type * from './models/NotificationPreference.ts'
95
101
  export type * from './commonInputTypes.ts'
@@ -0,0 +1,28 @@
1
+ -- pgvector 原生向量表(非 Prisma 模型,由 apps/web/src/lib/vector-store/pg-vector-store.ts 以 raw SQL 读写)
2
+ -- 此前仅在开发库手工建表,缺失即报 42P01(relation does not exist)。
3
+ -- 幂等:IF NOT EXISTS,已手工建过表的库安全跳过。
4
+ CREATE EXTENSION IF NOT EXISTS vector;
5
+
6
+ CREATE TABLE IF NOT EXISTS "knowledge_embeddings" (
7
+ "id" TEXT NOT NULL,
8
+ "content" TEXT NOT NULL,
9
+ "kbId" TEXT,
10
+ "documentId" TEXT,
11
+ "prdPageId" TEXT,
12
+ "chunkIndex" INTEGER,
13
+ "embedding" vector(1536) NOT NULL,
14
+ CONSTRAINT "knowledge_embeddings_pkey" PRIMARY KEY ("id")
15
+ );
16
+
17
+ CREATE TABLE IF NOT EXISTS "prd_embeddings" (
18
+ "id" TEXT NOT NULL,
19
+ "content" TEXT NOT NULL,
20
+ "prdPageId" TEXT,
21
+ "chunkIndex" INTEGER,
22
+ "embedding" vector(1536) NOT NULL,
23
+ CONSTRAINT "prd_embeddings_pkey" PRIMARY KEY ("id")
24
+ );
25
+
26
+ CREATE INDEX IF NOT EXISTS "knowledge_embeddings_kbid_idx" ON "knowledge_embeddings"("kbId");
27
+ CREATE INDEX IF NOT EXISTS "knowledge_embeddings_documentid_idx" ON "knowledge_embeddings"("documentId");
28
+ CREATE INDEX IF NOT EXISTS "prd_embeddings_prdpageid_idx" ON "prd_embeddings"("prdPageId");
@@ -0,0 +1,80 @@
1
+ -- AlterTable
2
+ ALTER TABLE "invitation_codes" ADD COLUMN "createdById" TEXT,
3
+ ADD COLUMN "disabledAt" TIMESTAMP(3);
4
+
5
+ -- CreateTable
6
+ CREATE TABLE "email_verification_tokens" (
7
+ "id" TEXT NOT NULL,
8
+ "token" TEXT NOT NULL,
9
+ "userId" TEXT NOT NULL,
10
+ "expiresAt" TIMESTAMP(3) NOT NULL,
11
+ "usedAt" TIMESTAMP(3),
12
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
13
+
14
+ CONSTRAINT "email_verification_tokens_pkey" PRIMARY KEY ("id")
15
+ );
16
+
17
+ -- CreateTable
18
+ CREATE TABLE "email_logs" (
19
+ "id" TEXT NOT NULL,
20
+ "to" TEXT NOT NULL,
21
+ "templateKey" TEXT NOT NULL,
22
+ "category" TEXT NOT NULL,
23
+ "status" TEXT NOT NULL,
24
+ "provider" TEXT NOT NULL,
25
+ "messageId" TEXT,
26
+ "dedupeKey" TEXT,
27
+ "error" TEXT,
28
+ "userId" TEXT,
29
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
30
+ "sentAt" TIMESTAMP(3),
31
+
32
+ CONSTRAINT "email_logs_pkey" PRIMARY KEY ("id")
33
+ );
34
+
35
+ -- CreateTable
36
+ CREATE TABLE "email_preferences" (
37
+ "userId" TEXT NOT NULL,
38
+ "unsubscribedAll" BOOLEAN NOT NULL DEFAULT false,
39
+ "unsubscribedCategories" JSONB NOT NULL DEFAULT '[]',
40
+ "suppressed" BOOLEAN NOT NULL DEFAULT false,
41
+
42
+ CONSTRAINT "email_preferences_pkey" PRIMARY KEY ("userId")
43
+ );
44
+
45
+ -- CreateIndex
46
+ CREATE UNIQUE INDEX "email_verification_tokens_token_key" ON "email_verification_tokens"("token");
47
+
48
+ -- CreateIndex
49
+ CREATE UNIQUE INDEX "email_logs_dedupeKey_key" ON "email_logs"("dedupeKey");
50
+
51
+ -- CreateIndex
52
+ CREATE INDEX "email_logs_to_createdAt_idx" ON "email_logs"("to", "createdAt");
53
+
54
+ -- CreateIndex
55
+ CREATE INDEX "email_logs_userId_createdAt_idx" ON "email_logs"("userId", "createdAt");
56
+
57
+ -- CreateIndex
58
+ CREATE INDEX "email_logs_status_idx" ON "email_logs"("status");
59
+
60
+ -- AddForeignKey
61
+ ALTER TABLE "email_verification_tokens" ADD CONSTRAINT "email_verification_tokens_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
62
+
63
+ -- AddForeignKey
64
+ ALTER TABLE "email_preferences" ADD CONSTRAINT "email_preferences_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
65
+
66
+ -- 存量邮箱小写归一(注册流程从此统一 toLowerCase 写入)。
67
+ -- 零数据丢失策略:只归一,绝不删除任何用户行。
68
+ -- users.email 为 @unique,若线上已存在仅大小写不同的重复邮箱,直接 LOWER 会撞唯一约束
69
+ -- 导致整个迁移事务回滚。此处显式检测并 RAISE EXCEPTION,交人工裁决(手动改邮箱或合并账号)
70
+ -- 后再应用迁移,避免静默改邮箱或删账号造成的不可逆后果。
71
+ DO $$
72
+ DECLARE n integer;
73
+ BEGIN
74
+ SELECT count(*) INTO n
75
+ FROM (SELECT 1 FROM "users" GROUP BY LOWER("email") HAVING count(*) > 1) AS dupes;
76
+ IF n > 0 THEN
77
+ RAISE EXCEPTION '发现 % 组大小写重复邮箱,请先人工处理(改邮箱或合并账号)再应用本迁移', n;
78
+ END IF;
79
+ UPDATE "users" SET "email" = LOWER("email") WHERE "email" != LOWER("email");
80
+ END $$;
@@ -0,0 +1,42 @@
1
+ -- AlterTable
2
+ ALTER TABLE "notification_preferences" ADD COLUMN "emailCategories" JSONB NOT NULL DEFAULT '{}';
3
+
4
+ -- CreateTable
5
+ CREATE TABLE "oauth_provider_configs" (
6
+ "id" TEXT NOT NULL,
7
+ "provider" TEXT NOT NULL,
8
+ "clientId" TEXT NOT NULL,
9
+ "clientSecret" TEXT NOT NULL,
10
+ "enabled" BOOLEAN NOT NULL DEFAULT false,
11
+ "extra" JSONB,
12
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
13
+ "updatedAt" TIMESTAMP(3) NOT NULL,
14
+
15
+ CONSTRAINT "oauth_provider_configs_pkey" PRIMARY KEY ("id")
16
+ );
17
+
18
+ -- CreateTable
19
+ CREATE TABLE "email_subscribers" (
20
+ "id" TEXT NOT NULL,
21
+ "email" TEXT NOT NULL,
22
+ "locale" TEXT NOT NULL DEFAULT 'zh',
23
+ "confirmToken" TEXT NOT NULL,
24
+ "confirmedAt" TIMESTAMP(3),
25
+ "unsubscribedAt" TIMESTAMP(3),
26
+ "source" TEXT NOT NULL DEFAULT 'changelog',
27
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
28
+
29
+ CONSTRAINT "email_subscribers_pkey" PRIMARY KEY ("id")
30
+ );
31
+
32
+ -- CreateIndex
33
+ CREATE UNIQUE INDEX "oauth_provider_configs_provider_key" ON "oauth_provider_configs"("provider");
34
+
35
+ -- CreateIndex
36
+ CREATE UNIQUE INDEX "email_subscribers_email_key" ON "email_subscribers"("email");
37
+
38
+ -- CreateIndex
39
+ CREATE UNIQUE INDEX "email_subscribers_confirmToken_key" ON "email_subscribers"("confirmToken");
40
+
41
+ -- CreateIndex
42
+ CREATE INDEX "email_subscribers_confirmedAt_unsubscribedAt_idx" ON "email_subscribers"("confirmedAt", "unsubscribedAt");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@allbluecn/database",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "license": "AGPL-3.0-or-later",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -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/kernel": "0.6.1"
18
+ "@allbluecn/kernel": "0.8.0"
19
19
  },
20
20
  "devDependencies": {
21
21
  "@types/better-sqlite3": "^7.6.13",
package/schema.prisma CHANGED
@@ -60,6 +60,8 @@ model User {
60
60
  invitationUses InvitationUse[]
61
61
  loginLogs LoginLog[]
62
62
  passwordResetTokens PasswordResetToken[]
63
+ emailVerificationTokens EmailVerificationToken[]
64
+ emailPreference EmailPreference?
63
65
  prds PRD[]
64
66
  tags Tag[]
65
67
  knowledgeBases KnowledgeBase[]
@@ -422,12 +424,14 @@ model LoginLog {
422
424
 
423
425
  // 邀请码
424
426
  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())
427
+ id String @id @default(cuid())
428
+ code String @unique
429
+ maxUses Int @default(1)
430
+ usedCount Int @default(0)
431
+ expiresAt DateTime
432
+ createdAt DateTime @default(now())
433
+ createdById String?
434
+ disabledAt DateTime?
431
435
 
432
436
  uses InvitationUse[]
433
437
 
@@ -461,6 +465,82 @@ model PasswordResetToken {
461
465
  @@map("password_reset_tokens")
462
466
  }
463
467
 
468
+ // 邮箱验证令牌
469
+ model EmailVerificationToken {
470
+ id String @id @default(cuid())
471
+ token String @unique
472
+ userId String
473
+ expiresAt DateTime
474
+ usedAt DateTime?
475
+ createdAt DateTime @default(now())
476
+
477
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
478
+
479
+ @@map("email_verification_tokens")
480
+ }
481
+
482
+ // 出站邮件日志
483
+ model EmailLog {
484
+ id String @id @default(cuid())
485
+ to String
486
+ templateKey String
487
+ category String
488
+ status String
489
+ provider String
490
+ messageId String?
491
+ dedupeKey String? @unique
492
+ error String?
493
+ userId String?
494
+ createdAt DateTime @default(now())
495
+ sentAt DateTime?
496
+
497
+ @@index([to, createdAt])
498
+ @@index([userId, createdAt])
499
+ @@index([status])
500
+ @@map("email_logs")
501
+ }
502
+
503
+ // 用户邮件偏好
504
+ model EmailPreference {
505
+ userId String @id
506
+ unsubscribedAll Boolean @default(false)
507
+ unsubscribedCategories Json @default("[]")
508
+ suppressed Boolean @default(false)
509
+
510
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
511
+
512
+ @@map("email_preferences")
513
+ }
514
+
515
+ // 第三方登录配置(admin 后台维护)
516
+ model OAuthProviderConfig {
517
+ id String @id @default(cuid())
518
+ provider String @unique
519
+ clientId String
520
+ clientSecret String // AES-256-GCM 密文
521
+ enabled Boolean @default(false)
522
+ extra Json?
523
+ createdAt DateTime @default(now())
524
+ updatedAt DateTime @updatedAt
525
+
526
+ @@map("oauth_provider_configs")
527
+ }
528
+
529
+ // 产品更新订阅者(changelog)
530
+ model EmailSubscriber {
531
+ id String @id @default(cuid())
532
+ email String @unique
533
+ locale String @default("zh")
534
+ confirmToken String @unique
535
+ confirmedAt DateTime?
536
+ unsubscribedAt DateTime?
537
+ source String @default("changelog")
538
+ createdAt DateTime @default(now())
539
+
540
+ @@index([confirmedAt, unsubscribedAt])
541
+ @@map("email_subscribers")
542
+ }
543
+
464
544
  enum Role {
465
545
  SUPER_ADMIN
466
546
  ADMIN
@@ -2193,12 +2273,13 @@ model Notification {
2193
2273
 
2194
2274
  // 通知偏好(免打扰时段、分类开关)
2195
2275
  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)
2276
+ userId String @id
2277
+ categories Json
2278
+ emailCategories Json @default("{}")
2279
+ dndEnabled Boolean @default(false)
2280
+ dndStart String @default("22:00")
2281
+ dndEnd String @default("08:00")
2282
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
2202
2283
 
2203
2284
  @@map("notification_preferences")
2204
2285
  }
@@ -61,6 +61,9 @@ model User {
61
61
  invitationUses InvitationUse[]
62
62
  loginLogs LoginLog[]
63
63
  passwordResetTokens PasswordResetToken[]
64
+ emailVerificationTokens EmailVerificationToken[]
65
+ emailPreference EmailPreference?
66
+ notificationPreference NotificationPreference?
64
67
  prds PRD[]
65
68
  tags Tag[]
66
69
  knowledgeBases KnowledgeBase[]
@@ -362,9 +365,11 @@ model InvitationCode {
362
365
  usedCount Int @default(0)
363
366
  expiresAt DateTime
364
367
  createdAt DateTime @default(now())
365
-
368
+ createdById String?
369
+ disabledAt DateTime?
370
+
366
371
  uses InvitationUse[]
367
-
372
+
368
373
  @@map("invitation_codes")
369
374
  }
370
375
 
@@ -389,12 +394,83 @@ model PasswordResetToken {
389
394
  expiresAt DateTime
390
395
  usedAt DateTime?
391
396
  createdAt DateTime @default(now())
392
-
397
+
393
398
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
394
-
399
+
395
400
  @@map("password_reset_tokens")
396
401
  }
397
402
 
403
+ // 邮箱验证令牌
404
+ model EmailVerificationToken {
405
+ id String @id @default(cuid())
406
+ token String @unique
407
+ userId String
408
+ expiresAt DateTime
409
+ usedAt DateTime?
410
+ createdAt DateTime @default(now())
411
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
412
+ @@map("email_verification_tokens")
413
+ }
414
+
415
+ // 出站邮件日志
416
+ model EmailLog {
417
+ id String @id @default(cuid())
418
+ to String
419
+ templateKey String
420
+ category String
421
+ status String
422
+ provider String
423
+ messageId String?
424
+ dedupeKey String? @unique
425
+ error String?
426
+ userId String?
427
+ createdAt DateTime @default(now())
428
+ sentAt DateTime?
429
+ @@index([to, createdAt])
430
+ @@index([userId, createdAt])
431
+ @@index([status])
432
+ @@map("email_logs")
433
+ }
434
+
435
+ // 用户邮件偏好
436
+ model EmailPreference {
437
+ userId String @id
438
+ unsubscribedAll Boolean @default(false)
439
+ unsubscribedCategories Json @default(dbgenerated("'[]'"))
440
+ suppressed Boolean @default(false)
441
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
442
+ @@map("email_preferences")
443
+ }
444
+
445
+ // 第三方登录配置(admin 后台维护)
446
+ model OAuthProviderConfig {
447
+ id String @id @default(cuid())
448
+ provider String @unique
449
+ clientId String
450
+ clientSecret String // AES-256-GCM 密文
451
+ enabled Boolean @default(false)
452
+ extra Json?
453
+ createdAt DateTime @default(now())
454
+ updatedAt DateTime @updatedAt
455
+
456
+ @@map("oauth_provider_configs")
457
+ }
458
+
459
+ // 产品更新订阅者(changelog)
460
+ model EmailSubscriber {
461
+ id String @id @default(cuid())
462
+ email String @unique
463
+ locale String @default("zh")
464
+ confirmToken String @unique
465
+ confirmedAt DateTime?
466
+ unsubscribedAt DateTime?
467
+ source String @default("changelog")
468
+ createdAt DateTime @default(now())
469
+
470
+ @@index([confirmedAt, unsubscribedAt])
471
+ @@map("email_subscribers")
472
+ }
473
+
398
474
  // (enum 已移除:SQLite 无原生 enum,Role/UserStatus/IconType/MarketplaceAppStatus/ReviewStatus/ShareStatus 改为 String 存 TEXT)
399
475
 
400
476
  // 知识库
@@ -1773,3 +1849,16 @@ model IterationAutoSchedule {
1773
1849
 
1774
1850
  @@map("iteration_auto_schedules")
1775
1851
  }
1852
+
1853
+ // 通知偏好(免打扰时段、分类开关)
1854
+ model NotificationPreference {
1855
+ userId String @id
1856
+ categories Json
1857
+ emailCategories Json @default(dbgenerated("'{}'"))
1858
+ dndEnabled Boolean @default(false)
1859
+ dndStart String @default("22:00")
1860
+ dndEnd String @default("08:00")
1861
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1862
+
1863
+ @@map("notification_preferences")
1864
+ }