@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.
- package/generated/browser.ts +25 -0
- package/generated/client.ts +25 -0
- package/generated/internal/class.ts +54 -4
- package/generated/internal/prismaNamespace.ts +453 -2
- package/generated/internal/prismaNamespaceBrowser.ts +77 -1
- package/generated/models/EmailLog.ts +1345 -0
- package/generated/models/EmailPreference.ts +1257 -0
- package/generated/models/EmailSubscriber.ts +1233 -0
- package/generated/models/EmailVerificationToken.ts +1380 -0
- package/generated/models/InvitationCode.ts +65 -1
- package/generated/models/NotificationPreference.ts +27 -1
- package/generated/models/OAuthProviderConfig.ts +1227 -0
- package/generated/models/User.ts +1435 -157
- package/generated/models.ts +5 -0
- package/generated-sqlite/browser.ts +30 -0
- package/generated-sqlite/client.ts +30 -0
- package/generated-sqlite/internal/class.ts +64 -4
- package/generated-sqlite/internal/prismaNamespace.ts +541 -3
- package/generated-sqlite/internal/prismaNamespaceBrowser.ts +90 -2
- package/generated-sqlite/models/EmailLog.ts +1343 -0
- package/generated-sqlite/models/EmailPreference.ts +1255 -0
- package/generated-sqlite/models/EmailSubscriber.ts +1231 -0
- package/generated-sqlite/models/EmailVerificationToken.ts +1377 -0
- package/generated-sqlite/models/InvitationCode.ts +65 -1
- package/generated-sqlite/models/NotificationPreference.ts +1313 -0
- package/generated-sqlite/models/OAuthProviderConfig.ts +1225 -0
- package/generated-sqlite/models/User.ts +1867 -293
- package/generated-sqlite/models.ts +6 -0
- package/migrations/20260911120000_add_pgvector_tables/migration.sql +28 -0
- package/migrations/20260911171433_email_auth_invitation/migration.sql +80 -0
- package/migrations/20260912032616_email_p4_p8/migration.sql +42 -0
- package/package.json +2 -2
- package/schema.prisma +93 -12
- 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.
|
|
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.
|
|
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
|
|
426
|
-
code
|
|
427
|
-
maxUses
|
|
428
|
-
usedCount
|
|
429
|
-
expiresAt
|
|
430
|
-
createdAt
|
|
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
|
|
2197
|
-
categories
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
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
|
}
|
package/schema.sqlite.prisma
CHANGED
|
@@ -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
|
+
}
|