@spfn/cms 0.1.0-alpha.6 → 0.1.0-alpha.61
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/dist/actions.d.ts +140 -6
- package/dist/actions.js +97 -10
- package/dist/actions.js.map +1 -1
- package/dist/client.d.ts +43 -9
- package/dist/client.js +406 -56
- package/dist/client.js.map +1 -1
- package/dist/contracts/labels.d.ts +149 -0
- package/dist/contracts/labels.js +166 -0
- package/dist/contracts/labels.js.map +1 -0
- package/dist/contracts/published-cache.d.ts +25 -0
- package/dist/contracts/published-cache.js +32 -0
- package/dist/contracts/published-cache.js.map +1 -0
- package/dist/contracts/values.d.ts +69 -0
- package/dist/contracts/values.js +100 -0
- package/dist/contracts/values.js.map +1 -0
- package/dist/entities/cms-audit-logs.d.ts +15 -70
- package/dist/entities/cms-audit-logs.js +75 -100
- package/dist/entities/cms-audit-logs.js.map +1 -1
- package/dist/entities/cms-draft-cache.d.ts +13 -73
- package/dist/entities/cms-draft-cache.js +35 -109
- package/dist/entities/cms-draft-cache.js.map +1 -1
- package/dist/entities/cms-label-values.d.ts +14 -65
- package/dist/entities/cms-label-values.js +78 -102
- package/dist/entities/cms-label-values.js.map +1 -1
- package/dist/entities/cms-label-versions.d.ts +16 -49
- package/dist/entities/cms-label-versions.js +73 -77
- package/dist/entities/cms-label-versions.js.map +1 -1
- package/dist/entities/cms-labels.d.ts +17 -14
- package/dist/entities/cms-labels.js +39 -45
- package/dist/entities/cms-labels.js.map +1 -1
- package/dist/entities/cms-published-cache.d.ts +14 -69
- package/dist/entities/cms-published-cache.js +33 -100
- package/dist/entities/cms-published-cache.js.map +1 -1
- package/dist/entities/index.d.ts +7 -10
- package/dist/entities/index.js +217 -9
- package/dist/entities/index.js.map +1 -1
- package/dist/generators/index.d.ts +8 -7
- package/dist/generators/index.js +657 -17
- package/dist/generators/index.js.map +1 -1
- package/dist/index.d.ts +134 -20
- package/dist/index.js +1115 -23
- package/dist/index.js.map +1 -1
- package/dist/{generators/label-sync-generator.d.ts → label-sync-generator-lQrcVfja.d.ts} +9 -6
- package/dist/labels/index.d.ts +31 -4
- package/dist/labels/index.js +31 -6
- package/dist/labels/index.js.map +1 -1
- package/dist/repositories/index.d.ts +205 -6
- package/dist/repositories/index.js +435 -8
- package/dist/repositories/index.js.map +1 -1
- package/dist/routes/labels/[id]/index.js +499 -89
- package/dist/routes/labels/[id]/index.js.map +1 -1
- package/dist/routes/labels/{[id] → _id_}/index.d.ts +5 -3
- package/dist/routes/labels/by-key/[key]/index.js +453 -29
- package/dist/routes/labels/by-key/[key]/index.js.map +1 -1
- package/dist/routes/labels/by-key/_key_/index.d.ts +10 -0
- package/dist/routes/labels/index.d.ts +5 -3
- package/dist/routes/labels/index.js +488 -68
- package/dist/routes/labels/index.js.map +1 -1
- package/dist/routes/published-cache/index.d.ts +5 -3
- package/dist/routes/published-cache/index.js +325 -30
- package/dist/routes/published-cache/index.js.map +1 -1
- package/dist/routes/values/[labelId]/[version]/index.js +467 -41
- package/dist/routes/values/[labelId]/[version]/index.js.map +1 -1
- package/dist/routes/values/[labelId]/index.js +463 -39
- package/dist/routes/values/[labelId]/index.js.map +1 -1
- package/dist/routes/values/_labelId_/_version_/index.d.ts +10 -0
- package/dist/routes/values/_labelId_/index.d.ts +10 -0
- package/dist/server.d.ts +17 -7
- package/dist/server.js +263 -252
- package/dist/server.js.map +1 -1
- package/dist/store.d.ts +8 -14
- package/dist/store.js +396 -198
- package/dist/store.js.map +1 -1
- package/dist/types.d.ts +14 -7
- package/dist/types.js +0 -6
- package/dist/types.js.map +1 -1
- package/migrations/0000_condemned_centennial.sql +89 -0
- package/migrations/meta/0000_snapshot.json +687 -0
- package/migrations/meta/_journal.json +13 -0
- package/package.json +33 -16
- package/dist/actions.d.ts.map +0 -1
- package/dist/client.d.ts.map +0 -1
- package/dist/cms.config.d.ts +0 -77
- package/dist/cms.config.d.ts.map +0 -1
- package/dist/cms.config.js +0 -111
- package/dist/cms.config.js.map +0 -1
- package/dist/entities/cms-audit-logs.d.ts.map +0 -1
- package/dist/entities/cms-draft-cache.d.ts.map +0 -1
- package/dist/entities/cms-label-values.d.ts.map +0 -1
- package/dist/entities/cms-label-versions.d.ts.map +0 -1
- package/dist/entities/cms-labels.d.ts.map +0 -1
- package/dist/entities/cms-published-cache.d.ts.map +0 -1
- package/dist/entities/index.d.ts.map +0 -1
- package/dist/generators/index.d.ts.map +0 -1
- package/dist/generators/label-sync-generator.d.ts.map +0 -1
- package/dist/generators/label-sync-generator.js +0 -87
- package/dist/generators/label-sync-generator.js.map +0 -1
- package/dist/helpers/locale.actions.d.ts +0 -132
- package/dist/helpers/locale.actions.d.ts.map +0 -1
- package/dist/helpers/locale.actions.js +0 -210
- package/dist/helpers/locale.actions.js.map +0 -1
- package/dist/helpers/locale.constants.d.ts +0 -10
- package/dist/helpers/locale.constants.d.ts.map +0 -1
- package/dist/helpers/locale.constants.js +0 -10
- package/dist/helpers/locale.constants.js.map +0 -1
- package/dist/helpers/locale.d.ts +0 -17
- package/dist/helpers/locale.d.ts.map +0 -1
- package/dist/helpers/locale.js +0 -20
- package/dist/helpers/locale.js.map +0 -1
- package/dist/helpers/sync.d.ts +0 -41
- package/dist/helpers/sync.d.ts.map +0 -1
- package/dist/helpers/sync.js +0 -309
- package/dist/helpers/sync.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/init.d.ts +0 -31
- package/dist/init.d.ts.map +0 -1
- package/dist/init.js +0 -36
- package/dist/init.js.map +0 -1
- package/dist/labels/helpers.d.ts +0 -31
- package/dist/labels/helpers.d.ts.map +0 -1
- package/dist/labels/helpers.js +0 -60
- package/dist/labels/helpers.js.map +0 -1
- package/dist/labels/index.d.ts.map +0 -1
- package/dist/repositories/cms-draft-cache.repository.d.ts +0 -62
- package/dist/repositories/cms-draft-cache.repository.d.ts.map +0 -1
- package/dist/repositories/cms-draft-cache.repository.js +0 -56
- package/dist/repositories/cms-draft-cache.repository.js.map +0 -1
- package/dist/repositories/cms-label-values.repository.d.ts +0 -32
- package/dist/repositories/cms-label-values.repository.d.ts.map +0 -1
- package/dist/repositories/cms-label-values.repository.js +0 -72
- package/dist/repositories/cms-label-values.repository.js.map +0 -1
- package/dist/repositories/cms-labels.repository.d.ts +0 -53
- package/dist/repositories/cms-labels.repository.d.ts.map +0 -1
- package/dist/repositories/cms-labels.repository.js +0 -77
- package/dist/repositories/cms-labels.repository.js.map +0 -1
- package/dist/repositories/cms-published-cache.repository.d.ts +0 -53
- package/dist/repositories/cms-published-cache.repository.d.ts.map +0 -1
- package/dist/repositories/cms-published-cache.repository.js +0 -54
- package/dist/repositories/cms-published-cache.repository.js.map +0 -1
- package/dist/repositories/index.d.ts.map +0 -1
- package/dist/routes/labels/[id]/contract.d.ts +0 -68
- package/dist/routes/labels/[id]/contract.d.ts.map +0 -1
- package/dist/routes/labels/[id]/contract.js +0 -84
- package/dist/routes/labels/[id]/contract.js.map +0 -1
- package/dist/routes/labels/[id]/index.d.ts.map +0 -1
- package/dist/routes/labels/by-key/[key]/contract.d.ts +0 -24
- package/dist/routes/labels/by-key/[key]/contract.d.ts.map +0 -1
- package/dist/routes/labels/by-key/[key]/contract.js +0 -28
- package/dist/routes/labels/by-key/[key]/contract.js.map +0 -1
- package/dist/routes/labels/by-key/[key]/index.d.ts +0 -8
- package/dist/routes/labels/by-key/[key]/index.d.ts.map +0 -1
- package/dist/routes/labels/contract.d.ts +0 -59
- package/dist/routes/labels/contract.d.ts.map +0 -1
- package/dist/routes/labels/contract.js +0 -75
- package/dist/routes/labels/contract.js.map +0 -1
- package/dist/routes/labels/index.d.ts.map +0 -1
- package/dist/routes/published-cache/contract.d.ts +0 -25
- package/dist/routes/published-cache/contract.d.ts.map +0 -1
- package/dist/routes/published-cache/contract.js +0 -35
- package/dist/routes/published-cache/contract.js.map +0 -1
- package/dist/routes/published-cache/index.d.ts.map +0 -1
- package/dist/routes/values/[labelId]/[version]/contract.d.ts +0 -29
- package/dist/routes/values/[labelId]/[version]/contract.d.ts.map +0 -1
- package/dist/routes/values/[labelId]/[version]/contract.js +0 -33
- package/dist/routes/values/[labelId]/[version]/contract.js.map +0 -1
- package/dist/routes/values/[labelId]/[version]/index.d.ts +0 -8
- package/dist/routes/values/[labelId]/[version]/index.d.ts.map +0 -1
- package/dist/routes/values/[labelId]/contract.d.ts +0 -38
- package/dist/routes/values/[labelId]/contract.d.ts.map +0 -1
- package/dist/routes/values/[labelId]/contract.js +0 -59
- package/dist/routes/values/[labelId]/contract.js.map +0 -1
- package/dist/routes/values/[labelId]/index.d.ts +0 -8
- package/dist/routes/values/[labelId]/index.d.ts.map +0 -1
- package/dist/server.d.ts.map +0 -1
- package/dist/store.d.ts.map +0 -1
- package/dist/types.d.ts.map +0 -1
|
@@ -1,103 +1,78 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
1
|
+
// src/entities/cms-audit-logs.ts
|
|
2
|
+
import { serial as serial2, integer as integer2, text as text2, jsonb, timestamp as timestamp2, index as index2 } from "drizzle-orm/pg-core";
|
|
3
|
+
import { createFunctionSchema as createFunctionSchema2 } from "@spfn/core/db";
|
|
4
|
+
|
|
5
|
+
// src/entities/cms-labels.ts
|
|
6
|
+
import { index, integer, serial, text, timestamp } from "drizzle-orm/pg-core";
|
|
7
|
+
import { createFunctionSchema } from "@spfn/core/db";
|
|
8
|
+
var schema = createFunctionSchema("@spfn/cms");
|
|
9
|
+
var cmsLabels = schema.table("labels", {
|
|
10
|
+
// Primary Key
|
|
11
|
+
id: serial("id").primaryKey(),
|
|
12
|
+
// 라벨 식별자
|
|
13
|
+
key: text("key").notNull().unique(),
|
|
14
|
+
// 예: "home.hero.title", "why-futureplay.hero.subtitle"
|
|
15
|
+
// 구조: {section}.{component}.{property}
|
|
16
|
+
// 섹션 분류 (페이지 단위)
|
|
17
|
+
section: text("section").notNull(),
|
|
18
|
+
// 예: "home", "why-futureplay", "team"
|
|
19
|
+
// 값 타입
|
|
20
|
+
type: text("type").notNull(),
|
|
21
|
+
// "text" | "image" | "video" | "file" | "object"
|
|
22
|
+
// 기본값
|
|
23
|
+
defaultValue: text("default_value"),
|
|
24
|
+
// 라벨의 기본값 (sync 시 설정)
|
|
25
|
+
// 설명
|
|
26
|
+
description: text("description"),
|
|
27
|
+
// 라벨에 대한 설명 (optional)
|
|
28
|
+
// 현재 발행된 버전 번호
|
|
29
|
+
publishedVersion: integer("published_version"),
|
|
30
|
+
// null = 미발행 상태
|
|
31
|
+
// 1, 2, 3... = 발행된 버전 번호
|
|
32
|
+
// 생성자 추적
|
|
33
|
+
createdBy: text("created_by"),
|
|
34
|
+
// 타임스탬프
|
|
35
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
36
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
35
37
|
}, (table) => [
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
// 인덱스: action 필터링 최적화
|
|
41
|
-
index('cms_audit_logs_action_idx').on(table.action),
|
|
42
|
-
// 인덱스: 시간순 조회 최적화
|
|
43
|
-
index('cms_audit_logs_created_at_idx').on(table.createdAt),
|
|
38
|
+
// 인덱스: 섹션별 조회 최적화
|
|
39
|
+
index("cms_labels_section_idx").on(table.section),
|
|
40
|
+
// 인덱스: key로 조회 최적화 (unique 제약으로 자동 생성되지만 명시)
|
|
41
|
+
index("cms_labels_key_idx").on(table.key)
|
|
44
42
|
]);
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
* notes: '신규 브랜딩 적용'
|
|
81
|
-
* }
|
|
82
|
-
* });
|
|
83
|
-
*
|
|
84
|
-
* // 라벨별 이력 조회
|
|
85
|
-
* const logs = await db.select()
|
|
86
|
-
* .from(cmsAuditLogs)
|
|
87
|
-
* .where(eq(cmsAuditLogs.labelId, 1))
|
|
88
|
-
* .orderBy(desc(cmsAuditLogs.createdAt))
|
|
89
|
-
* .limit(20);
|
|
90
|
-
*
|
|
91
|
-
* // 사용자별 활동 조회
|
|
92
|
-
* const userActivity = await db.select()
|
|
93
|
-
* .from(cmsAuditLogs)
|
|
94
|
-
* .where(eq(cmsAuditLogs.userId, 'user123'))
|
|
95
|
-
* .orderBy(desc(cmsAuditLogs.createdAt));
|
|
96
|
-
*
|
|
97
|
-
* // 최근 24시간 변경 이력
|
|
98
|
-
* const recent = await db.select()
|
|
99
|
-
* .from(cmsAuditLogs)
|
|
100
|
-
* .where(gte(cmsAuditLogs.createdAt, new Date(Date.now() - 24 * 60 * 60 * 1000)))
|
|
101
|
-
* .orderBy(desc(cmsAuditLogs.createdAt));
|
|
102
|
-
*/
|
|
43
|
+
|
|
44
|
+
// src/entities/cms-audit-logs.ts
|
|
45
|
+
var schema2 = createFunctionSchema2("@spfn/cms");
|
|
46
|
+
var cmsAuditLogs = schema2.table("audit_logs", {
|
|
47
|
+
// Primary Key
|
|
48
|
+
id: serial2("id").primaryKey(),
|
|
49
|
+
// Foreign Key: cms_labels (nullable - 라벨 삭제 시 로그는 유지)
|
|
50
|
+
labelId: integer2("label_id").references(() => cmsLabels.id, { onDelete: "set null" }),
|
|
51
|
+
// 작업 유형
|
|
52
|
+
action: text2("action").notNull(),
|
|
53
|
+
// "create" | "update" | "publish" | "unpublish" | "archive" | "delete" | "rollback" | "duplicate"
|
|
54
|
+
// 사용자 정보
|
|
55
|
+
userId: text2("user_id").notNull(),
|
|
56
|
+
userName: text2("user_name"),
|
|
57
|
+
// 변경 내용 (before/after)
|
|
58
|
+
changes: jsonb("changes"),
|
|
59
|
+
// { before: {...}, after: {...} }
|
|
60
|
+
// 추가 메타데이터
|
|
61
|
+
metadata: jsonb("metadata"),
|
|
62
|
+
// { version: number, ip: string, userAgent: string, ... }
|
|
63
|
+
// 작업 시각
|
|
64
|
+
createdAt: timestamp2("created_at", { withTimezone: true }).notNull().defaultNow()
|
|
65
|
+
}, (table) => [
|
|
66
|
+
// 인덱스: labelId로 이력 조회 최적화
|
|
67
|
+
index2("cms_audit_logs_label_id_idx").on(table.labelId),
|
|
68
|
+
// 인덱스: userId로 사용자 활동 조회 최적화
|
|
69
|
+
index2("cms_audit_logs_user_id_idx").on(table.userId),
|
|
70
|
+
// 인덱스: action 필터링 최적화
|
|
71
|
+
index2("cms_audit_logs_action_idx").on(table.action),
|
|
72
|
+
// 인덱스: 시간순 조회 최적화
|
|
73
|
+
index2("cms_audit_logs_created_at_idx").on(table.createdAt)
|
|
74
|
+
]);
|
|
75
|
+
export {
|
|
76
|
+
cmsAuditLogs
|
|
77
|
+
};
|
|
103
78
|
//# sourceMappingURL=cms-audit-logs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"sources":["../../src/entities/cms-audit-logs.ts","../../src/entities/cms-labels.ts"],"sourcesContent":["/**\n * CMS Audit Logs Entity\n *\n * CMS의 모든 변경사항을 추적합니다.\n * - 누가 (userId, userName)\n * - 언제 (createdAt)\n * - 무엇을 (action, changes)\n * - 왜 (metadata)\n */\n\nimport { serial, integer, text, jsonb, timestamp, index } from 'drizzle-orm/pg-core';\nimport { createFunctionSchema } from '@spfn/core/db';\nimport { cmsLabels } from './cms-labels';\n\n// Create isolated schema for @spfn/cms\nconst schema = createFunctionSchema('@spfn/cms');\n\nexport const cmsAuditLogs = schema.table('audit_logs', {\n // Primary Key\n id: serial('id').primaryKey(),\n\n // Foreign Key: cms_labels (nullable - 라벨 삭제 시 로그는 유지)\n labelId: integer('label_id')\n .references(() => cmsLabels.id, { onDelete: 'set null' }),\n\n // 작업 유형\n action: text('action').notNull(),\n // \"create\" | \"update\" | \"publish\" | \"unpublish\" | \"archive\" | \"delete\" | \"rollback\" | \"duplicate\"\n\n // 사용자 정보\n userId: text('user_id').notNull(),\n userName: text('user_name'),\n\n // 변경 내용 (before/after)\n changes: jsonb('changes'),\n // { before: {...}, after: {...} }\n\n // 추가 메타데이터\n metadata: jsonb('metadata'),\n // { version: number, ip: string, userAgent: string, ... }\n\n // 작업 시각\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n}, (table) => [\n // 인덱스: labelId로 이력 조회 최적화\n index('cms_audit_logs_label_id_idx').on(table.labelId),\n\n // 인덱스: userId로 사용자 활동 조회 최적화\n index('cms_audit_logs_user_id_idx').on(table.userId),\n\n // 인덱스: action 필터링 최적화\n index('cms_audit_logs_action_idx').on(table.action),\n\n // 인덱스: 시간순 조회 최적화\n index('cms_audit_logs_created_at_idx').on(table.createdAt),\n]);\n\n// 타입 추론\nexport type CmsAuditLog = typeof cmsAuditLogs.$inferSelect;\nexport type NewCmsAuditLog = typeof cmsAuditLogs.$inferInsert;\n\n/**\n * 사용 예시:\n *\n * // 라벨 생성 로그\n * await db.insert(cmsAuditLogs).values({\n * labelId: 1,\n * action: 'create',\n * userId: 'user123',\n * userName: '김철수',\n * changes: {\n * before: null,\n * after: {\n * key: 'home.hero.title',\n * section: 'home',\n * type: 'text'\n * }\n * },\n * metadata: {\n * ip: '192.168.1.1',\n * userAgent: 'Mozilla/5.0...'\n * }\n * });\n *\n * // 발행 로그\n * await db.insert(cmsAuditLogs).values({\n * labelId: 1,\n * action: 'publish',\n * userId: 'admin123',\n * userName: '관리자',\n * changes: {\n * before: { status: 'draft', publishedVersion: null },\n * after: { status: 'published', publishedVersion: 2 }\n * },\n * metadata: {\n * version: 2,\n * notes: '신규 브랜딩 적용'\n * }\n * });\n *\n * // 라벨별 이력 조회\n * const logs = await db.select()\n * .from(cmsAuditLogs)\n * .where(eq(cmsAuditLogs.labelId, 1))\n * .orderBy(desc(cmsAuditLogs.createdAt))\n * .limit(20);\n *\n * // 사용자별 활동 조회\n * const userActivity = await db.select()\n * .from(cmsAuditLogs)\n * .where(eq(cmsAuditLogs.userId, 'user123'))\n * .orderBy(desc(cmsAuditLogs.createdAt));\n *\n * // 최근 24시간 변경 이력\n * const recent = await db.select()\n * .from(cmsAuditLogs)\n * .where(gte(cmsAuditLogs.createdAt, new Date(Date.now() - 24 * 60 * 60 * 1000)))\n * .orderBy(desc(cmsAuditLogs.createdAt));\n */","/**\n * CMS Labels Entity\n *\n * 라벨의 메타데이터와 현재 발행 상태를 관리합니다.\n * - 라벨 식별 (id, key)\n * - 섹션 분류 (section)\n * - 타입 정의 (type)\n * - 발행 상태 (publishedVersion)\n */\n\nimport { index, integer, serial, text, timestamp } from 'drizzle-orm/pg-core';\nimport { createFunctionSchema } from '@spfn/core/db';\n\n// Create isolated schema for @spfn/cms\nconst schema = createFunctionSchema('@spfn/cms');\n\nexport const cmsLabels = schema.table('labels', {\n // Primary Key\n id: serial('id').primaryKey(),\n\n // 라벨 식별자\n key: text('key').notNull().unique(),\n // 예: \"home.hero.title\", \"why-futureplay.hero.subtitle\"\n // 구조: {section}.{component}.{property}\n\n // 섹션 분류 (페이지 단위)\n section: text('section').notNull(),\n // 예: \"home\", \"why-futureplay\", \"team\"\n\n // 값 타입\n type: text('type').notNull(),\n // \"text\" | \"image\" | \"video\" | \"file\" | \"object\"\n\n // 기본값\n defaultValue: text('default_value'),\n // 라벨의 기본값 (sync 시 설정)\n\n // 설명\n description: text('description'),\n // 라벨에 대한 설명 (optional)\n\n // 현재 발행된 버전 번호\n publishedVersion: integer('published_version'),\n // null = 미발행 상태\n // 1, 2, 3... = 발행된 버전 번호\n\n // 생성자 추적\n createdBy: text('created_by'),\n\n // 타임스탬프\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),\n}, (table) => [\n // 인덱스: 섹션별 조회 최적화\n index('cms_labels_section_idx').on(table.section),\n\n // 인덱스: key로 조회 최적화 (unique 제약으로 자동 생성되지만 명시)\n index('cms_labels_key_idx').on(table.key),\n]);\n\n// 타입 추론\nexport type CmsLabel = typeof cmsLabels.$inferSelect;\nexport type NewCmsLabel = typeof cmsLabels.$inferInsert;"],"mappings":";AAUA,SAAS,UAAAA,SAAQ,WAAAC,UAAS,QAAAC,OAAM,OAAO,aAAAC,YAAW,SAAAC,cAAa;AAC/D,SAAS,wBAAAC,6BAA4B;;;ACDrC,SAAS,OAAO,SAAS,QAAQ,MAAM,iBAAiB;AACxD,SAAS,4BAA4B;AAGrC,IAAM,SAAS,qBAAqB,WAAW;AAExC,IAAM,YAAY,OAAO,MAAM,UAAU;AAAA;AAAA,EAE5C,IAAI,OAAO,IAAI,EAAE,WAAW;AAAA;AAAA,EAG5B,KAAK,KAAK,KAAK,EAAE,QAAQ,EAAE,OAAO;AAAA;AAAA;AAAA;AAAA,EAKlC,SAAS,KAAK,SAAS,EAAE,QAAQ;AAAA;AAAA;AAAA,EAIjC,MAAM,KAAK,MAAM,EAAE,QAAQ;AAAA;AAAA;AAAA,EAI3B,cAAc,KAAK,eAAe;AAAA;AAAA;AAAA,EAIlC,aAAa,KAAK,aAAa;AAAA;AAAA;AAAA,EAI/B,kBAAkB,QAAQ,mBAAmB;AAAA;AAAA;AAAA;AAAA,EAK7C,WAAW,KAAK,YAAY;AAAA;AAAA,EAG5B,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,EAAE,QAAQ,EAAE,WAAW;AAAA,EAChF,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,EAAE,QAAQ,EAAE,WAAW;AACpF,GAAG,CAAC,UAAU;AAAA;AAAA,EAEV,MAAM,wBAAwB,EAAE,GAAG,MAAM,OAAO;AAAA;AAAA,EAGhD,MAAM,oBAAoB,EAAE,GAAG,MAAM,GAAG;AAC5C,CAAC;;;AD3CD,IAAMC,UAASC,sBAAqB,WAAW;AAExC,IAAM,eAAeD,QAAO,MAAM,cAAc;AAAA;AAAA,EAEnD,IAAIE,QAAO,IAAI,EAAE,WAAW;AAAA;AAAA,EAG5B,SAASC,SAAQ,UAAU,EAC1B,WAAW,MAAM,UAAU,IAAI,EAAE,UAAU,WAAW,CAAC;AAAA;AAAA,EAGxD,QAAQC,MAAK,QAAQ,EAAE,QAAQ;AAAA;AAAA;AAAA,EAI/B,QAAQA,MAAK,SAAS,EAAE,QAAQ;AAAA,EAChC,UAAUA,MAAK,WAAW;AAAA;AAAA,EAG1B,SAAS,MAAM,SAAS;AAAA;AAAA;AAAA,EAIxB,UAAU,MAAM,UAAU;AAAA;AAAA;AAAA,EAI1B,WAAWC,WAAU,cAAc,EAAE,cAAc,KAAK,CAAC,EAAE,QAAQ,EAAE,WAAW;AACpF,GAAG,CAAC,UAAU;AAAA;AAAA,EAEVC,OAAM,6BAA6B,EAAE,GAAG,MAAM,OAAO;AAAA;AAAA,EAGrDA,OAAM,4BAA4B,EAAE,GAAG,MAAM,MAAM;AAAA;AAAA,EAGnDA,OAAM,2BAA2B,EAAE,GAAG,MAAM,MAAM;AAAA;AAAA,EAGlDA,OAAM,+BAA+B,EAAE,GAAG,MAAM,SAAS;AAC7D,CAAC;","names":["serial","integer","text","timestamp","index","createFunctionSchema","schema","createFunctionSchema","serial","integer","text","timestamp","index"]}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* CMS Draft Cache Entity
|
|
3
5
|
*
|
|
@@ -11,11 +13,11 @@
|
|
|
11
13
|
* - 각자의 변경사항은 자신의 미리보기에만 표시
|
|
12
14
|
* - 충돌 없이 안전하게 작업
|
|
13
15
|
*/
|
|
14
|
-
|
|
16
|
+
declare const cmsDraftCache: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
15
17
|
name: "draft_cache";
|
|
16
18
|
schema: string;
|
|
17
19
|
columns: {
|
|
18
|
-
id:
|
|
20
|
+
id: drizzle_orm_pg_core.PgColumn<{
|
|
19
21
|
name: "id";
|
|
20
22
|
tableName: "draft_cache";
|
|
21
23
|
dataType: "number";
|
|
@@ -32,7 +34,7 @@ export declare const cmsDraftCache: import("drizzle-orm/pg-core").PgTableWithCol
|
|
|
32
34
|
identity: undefined;
|
|
33
35
|
generated: undefined;
|
|
34
36
|
}, {}, {}>;
|
|
35
|
-
section:
|
|
37
|
+
section: drizzle_orm_pg_core.PgColumn<{
|
|
36
38
|
name: "section";
|
|
37
39
|
tableName: "draft_cache";
|
|
38
40
|
dataType: "string";
|
|
@@ -49,7 +51,7 @@ export declare const cmsDraftCache: import("drizzle-orm/pg-core").PgTableWithCol
|
|
|
49
51
|
identity: undefined;
|
|
50
52
|
generated: undefined;
|
|
51
53
|
}, {}, {}>;
|
|
52
|
-
locale:
|
|
54
|
+
locale: drizzle_orm_pg_core.PgColumn<{
|
|
53
55
|
name: "locale";
|
|
54
56
|
tableName: "draft_cache";
|
|
55
57
|
dataType: "string";
|
|
@@ -66,7 +68,7 @@ export declare const cmsDraftCache: import("drizzle-orm/pg-core").PgTableWithCol
|
|
|
66
68
|
identity: undefined;
|
|
67
69
|
generated: undefined;
|
|
68
70
|
}, {}, {}>;
|
|
69
|
-
userId:
|
|
71
|
+
userId: drizzle_orm_pg_core.PgColumn<{
|
|
70
72
|
name: "user_id";
|
|
71
73
|
tableName: "draft_cache";
|
|
72
74
|
dataType: "string";
|
|
@@ -83,7 +85,7 @@ export declare const cmsDraftCache: import("drizzle-orm/pg-core").PgTableWithCol
|
|
|
83
85
|
identity: undefined;
|
|
84
86
|
generated: undefined;
|
|
85
87
|
}, {}, {}>;
|
|
86
|
-
content:
|
|
88
|
+
content: drizzle_orm_pg_core.PgColumn<{
|
|
87
89
|
name: "content";
|
|
88
90
|
tableName: "draft_cache";
|
|
89
91
|
dataType: "json";
|
|
@@ -100,7 +102,7 @@ export declare const cmsDraftCache: import("drizzle-orm/pg-core").PgTableWithCol
|
|
|
100
102
|
identity: undefined;
|
|
101
103
|
generated: undefined;
|
|
102
104
|
}, {}, {}>;
|
|
103
|
-
updatedAt:
|
|
105
|
+
updatedAt: drizzle_orm_pg_core.PgColumn<{
|
|
104
106
|
name: "updated_at";
|
|
105
107
|
tableName: "draft_cache";
|
|
106
108
|
dataType: "date";
|
|
@@ -120,69 +122,7 @@ export declare const cmsDraftCache: import("drizzle-orm/pg-core").PgTableWithCol
|
|
|
120
122
|
};
|
|
121
123
|
dialect: "pg";
|
|
122
124
|
}>;
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
*
|
|
128
|
-
* // Draft 초기화 (편집 시작)
|
|
129
|
-
* await db.insert(cmsDraftCache)
|
|
130
|
-
* .values({
|
|
131
|
-
* section: 'home',
|
|
132
|
-
* locale: 'ko',
|
|
133
|
-
* userId: 'user-a@futureplay.com',
|
|
134
|
-
* content: publishedContent // 발행 버전 복사
|
|
135
|
-
* });
|
|
136
|
-
*
|
|
137
|
-
* // Draft 업데이트 (값 수정 시)
|
|
138
|
-
* const cache = await db.select()
|
|
139
|
-
* .from(cmsDraftCache)
|
|
140
|
-
* .where(and(
|
|
141
|
-
* eq(cmsDraftCache.section, 'home'),
|
|
142
|
-
* eq(cmsDraftCache.locale, 'ko'),
|
|
143
|
-
* eq(cmsDraftCache.userId, userId)
|
|
144
|
-
* ))
|
|
145
|
-
* .limit(1);
|
|
146
|
-
*
|
|
147
|
-
* const updatedContent = {
|
|
148
|
-
* ...cache[0].content,
|
|
149
|
-
* 'home.hero.title': newValue // 부분 업데이트
|
|
150
|
-
* };
|
|
151
|
-
*
|
|
152
|
-
* await db.update(cmsDraftCache)
|
|
153
|
-
* .set({ content: updatedContent, updatedAt: new Date() })
|
|
154
|
-
* .where(eq(cmsDraftCache.id, cache[0].id));
|
|
155
|
-
*
|
|
156
|
-
* // Draft 조회 (미리보기)
|
|
157
|
-
* const draft = await db.select()
|
|
158
|
-
* .from(cmsDraftCache)
|
|
159
|
-
* .where(and(
|
|
160
|
-
* eq(cmsDraftCache.section, 'home'),
|
|
161
|
-
* eq(cmsDraftCache.locale, 'ko'),
|
|
162
|
-
* eq(cmsDraftCache.userId, session.user.id)
|
|
163
|
-
* ))
|
|
164
|
-
* .limit(1);
|
|
165
|
-
*
|
|
166
|
-
* // 사용자의 모든 작업 중인 섹션 조회
|
|
167
|
-
* const userDrafts = await db.select()
|
|
168
|
-
* .from(cmsDraftCache)
|
|
169
|
-
* .where(eq(cmsDraftCache.userId, userId))
|
|
170
|
-
* .orderBy(desc(cmsDraftCache.updatedAt));
|
|
171
|
-
*
|
|
172
|
-
* // 오래된 Draft 정리 (30일 이상)
|
|
173
|
-
* const stale = await db.delete(cmsDraftCache)
|
|
174
|
-
* .where(lt(
|
|
175
|
-
* cmsDraftCache.updatedAt,
|
|
176
|
-
* new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)
|
|
177
|
-
* ))
|
|
178
|
-
* .returning();
|
|
179
|
-
*
|
|
180
|
-
* // Draft 폐기 (변경사항 버리기)
|
|
181
|
-
* await db.delete(cmsDraftCache)
|
|
182
|
-
* .where(and(
|
|
183
|
-
* eq(cmsDraftCache.section, 'home'),
|
|
184
|
-
* eq(cmsDraftCache.locale, 'ko'),
|
|
185
|
-
* eq(cmsDraftCache.userId, userId)
|
|
186
|
-
* ));
|
|
187
|
-
*/
|
|
188
|
-
//# sourceMappingURL=cms-draft-cache.d.ts.map
|
|
125
|
+
type CmsDraftCache = typeof cmsDraftCache.$inferSelect;
|
|
126
|
+
type NewCmsDraftCache = typeof cmsDraftCache.$inferInsert;
|
|
127
|
+
|
|
128
|
+
export { type CmsDraftCache, type NewCmsDraftCache, cmsDraftCache };
|
|
@@ -1,112 +1,38 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
//
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
// 사용자 ID (핵심 필드!)
|
|
28
|
-
userId: text('user_id').notNull(),
|
|
29
|
-
// 각 관리자의 독립적인 작업 공간
|
|
30
|
-
// Draft 콘텐츠 (JSONB)
|
|
31
|
-
content: jsonb('content').notNull(),
|
|
32
|
-
// Record<string, LabelValue>
|
|
33
|
-
// {
|
|
34
|
-
// "home.hero.title": { type: "text", content: "수정 중..." },
|
|
35
|
-
// "home.hero.subtitle": { type: "text", content: "새로운 문구" },
|
|
36
|
-
// ...
|
|
37
|
-
// }
|
|
38
|
-
// 최종 수정 시각
|
|
39
|
-
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
|
|
1
|
+
// src/entities/cms-draft-cache.ts
|
|
2
|
+
import { serial, text, jsonb, timestamp, index, unique } from "drizzle-orm/pg-core";
|
|
3
|
+
import { createFunctionSchema } from "@spfn/core/db";
|
|
4
|
+
var schema = createFunctionSchema("@spfn/cms");
|
|
5
|
+
var cmsDraftCache = schema.table("draft_cache", {
|
|
6
|
+
// Primary Key
|
|
7
|
+
id: serial("id").primaryKey(),
|
|
8
|
+
// 섹션 (페이지 단위)
|
|
9
|
+
section: text("section").notNull(),
|
|
10
|
+
// "home" | "why-futureplay" | "team" | "our-companies" | "apply"
|
|
11
|
+
// 언어
|
|
12
|
+
locale: text("locale").notNull(),
|
|
13
|
+
// "ko" | "en" | "ja"
|
|
14
|
+
// 사용자 ID (핵심 필드!)
|
|
15
|
+
userId: text("user_id").notNull(),
|
|
16
|
+
// 각 관리자의 독립적인 작업 공간
|
|
17
|
+
// Draft 콘텐츠 (JSONB)
|
|
18
|
+
content: jsonb("content").notNull(),
|
|
19
|
+
// Record<string, LabelValue>
|
|
20
|
+
// {
|
|
21
|
+
// "home.hero.title": { type: "text", content: "수정 중..." },
|
|
22
|
+
// "home.hero.subtitle": { type: "text", content: "새로운 문구" },
|
|
23
|
+
// ...
|
|
24
|
+
// }
|
|
25
|
+
// 최종 수정 시각
|
|
26
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
40
27
|
}, (table) => [
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
index('cms_draft_cache_user_idx').on(table.userId),
|
|
28
|
+
// UNIQUE 제약: section + locale + userId 조합은 유일
|
|
29
|
+
unique("cms_draft_cache_unique").on(table.section, table.locale, table.userId),
|
|
30
|
+
// 인덱스: section으로 조회 최적화
|
|
31
|
+
index("cms_draft_cache_section_idx").on(table.section),
|
|
32
|
+
// 인덱스: userId로 사용자의 모든 draft 조회 최적화
|
|
33
|
+
index("cms_draft_cache_user_idx").on(table.userId)
|
|
48
34
|
]);
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
* // Draft 초기화 (편집 시작)
|
|
53
|
-
* await db.insert(cmsDraftCache)
|
|
54
|
-
* .values({
|
|
55
|
-
* section: 'home',
|
|
56
|
-
* locale: 'ko',
|
|
57
|
-
* userId: 'user-a@futureplay.com',
|
|
58
|
-
* content: publishedContent // 발행 버전 복사
|
|
59
|
-
* });
|
|
60
|
-
*
|
|
61
|
-
* // Draft 업데이트 (값 수정 시)
|
|
62
|
-
* const cache = await db.select()
|
|
63
|
-
* .from(cmsDraftCache)
|
|
64
|
-
* .where(and(
|
|
65
|
-
* eq(cmsDraftCache.section, 'home'),
|
|
66
|
-
* eq(cmsDraftCache.locale, 'ko'),
|
|
67
|
-
* eq(cmsDraftCache.userId, userId)
|
|
68
|
-
* ))
|
|
69
|
-
* .limit(1);
|
|
70
|
-
*
|
|
71
|
-
* const updatedContent = {
|
|
72
|
-
* ...cache[0].content,
|
|
73
|
-
* 'home.hero.title': newValue // 부분 업데이트
|
|
74
|
-
* };
|
|
75
|
-
*
|
|
76
|
-
* await db.update(cmsDraftCache)
|
|
77
|
-
* .set({ content: updatedContent, updatedAt: new Date() })
|
|
78
|
-
* .where(eq(cmsDraftCache.id, cache[0].id));
|
|
79
|
-
*
|
|
80
|
-
* // Draft 조회 (미리보기)
|
|
81
|
-
* const draft = await db.select()
|
|
82
|
-
* .from(cmsDraftCache)
|
|
83
|
-
* .where(and(
|
|
84
|
-
* eq(cmsDraftCache.section, 'home'),
|
|
85
|
-
* eq(cmsDraftCache.locale, 'ko'),
|
|
86
|
-
* eq(cmsDraftCache.userId, session.user.id)
|
|
87
|
-
* ))
|
|
88
|
-
* .limit(1);
|
|
89
|
-
*
|
|
90
|
-
* // 사용자의 모든 작업 중인 섹션 조회
|
|
91
|
-
* const userDrafts = await db.select()
|
|
92
|
-
* .from(cmsDraftCache)
|
|
93
|
-
* .where(eq(cmsDraftCache.userId, userId))
|
|
94
|
-
* .orderBy(desc(cmsDraftCache.updatedAt));
|
|
95
|
-
*
|
|
96
|
-
* // 오래된 Draft 정리 (30일 이상)
|
|
97
|
-
* const stale = await db.delete(cmsDraftCache)
|
|
98
|
-
* .where(lt(
|
|
99
|
-
* cmsDraftCache.updatedAt,
|
|
100
|
-
* new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)
|
|
101
|
-
* ))
|
|
102
|
-
* .returning();
|
|
103
|
-
*
|
|
104
|
-
* // Draft 폐기 (변경사항 버리기)
|
|
105
|
-
* await db.delete(cmsDraftCache)
|
|
106
|
-
* .where(and(
|
|
107
|
-
* eq(cmsDraftCache.section, 'home'),
|
|
108
|
-
* eq(cmsDraftCache.locale, 'ko'),
|
|
109
|
-
* eq(cmsDraftCache.userId, userId)
|
|
110
|
-
* ));
|
|
111
|
-
*/
|
|
35
|
+
export {
|
|
36
|
+
cmsDraftCache
|
|
37
|
+
};
|
|
112
38
|
//# sourceMappingURL=cms-draft-cache.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"sources":["../../src/entities/cms-draft-cache.ts"],"sourcesContent":["/**\n * CMS Draft Cache Entity\n *\n * 관리자별 Draft 콘텐츠를 캐싱합니다.\n * - 사용자별 격리 (userId)\n * - 실시간 미리보기 지원\n * - 동시 편집 가능\n *\n * 핵심 기능:\n * - 여러 관리자가 같은 섹션을 동시에 편집\n * - 각자의 변경사항은 자신의 미리보기에만 표시\n * - 충돌 없이 안전하게 작업\n */\n\nimport { serial, text, jsonb, timestamp, index, unique } from 'drizzle-orm/pg-core';\nimport { createFunctionSchema } from '@spfn/core/db';\n\n// Create isolated schema for @spfn/cms\nconst schema = createFunctionSchema('@spfn/cms');\n\nexport const cmsDraftCache = schema.table('draft_cache', {\n // Primary Key\n id: serial('id').primaryKey(),\n\n // 섹션 (페이지 단위)\n section: text('section').notNull(),\n // \"home\" | \"why-futureplay\" | \"team\" | \"our-companies\" | \"apply\"\n\n // 언어\n locale: text('locale').notNull(),\n // \"ko\" | \"en\" | \"ja\"\n\n // 사용자 ID (핵심 필드!)\n userId: text('user_id').notNull(),\n // 각 관리자의 독립적인 작업 공간\n\n // Draft 콘텐츠 (JSONB)\n content: jsonb('content').notNull(),\n // Record<string, LabelValue>\n // {\n // \"home.hero.title\": { type: \"text\", content: \"수정 중...\" },\n // \"home.hero.subtitle\": { type: \"text\", content: \"새로운 문구\" },\n // ...\n // }\n\n // 최종 수정 시각\n updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),\n}, (table) => [\n // UNIQUE 제약: section + locale + userId 조합은 유일\n unique('cms_draft_cache_unique')\n .on(table.section, table.locale, table.userId),\n\n // 인덱스: section으로 조회 최적화\n index('cms_draft_cache_section_idx').on(table.section),\n\n // 인덱스: userId로 사용자의 모든 draft 조회 최적화\n index('cms_draft_cache_user_idx').on(table.userId),\n]);\n\n// 타입 추론\nexport type CmsDraftCache = typeof cmsDraftCache.$inferSelect;\nexport type NewCmsDraftCache = typeof cmsDraftCache.$inferInsert;\n\n/**\n * 사용 예시:\n *\n * // Draft 초기화 (편집 시작)\n * await db.insert(cmsDraftCache)\n * .values({\n * section: 'home',\n * locale: 'ko',\n * userId: 'user-a@futureplay.com',\n * content: publishedContent // 발행 버전 복사\n * });\n *\n * // Draft 업데이트 (값 수정 시)\n * const cache = await db.select()\n * .from(cmsDraftCache)\n * .where(and(\n * eq(cmsDraftCache.section, 'home'),\n * eq(cmsDraftCache.locale, 'ko'),\n * eq(cmsDraftCache.userId, userId)\n * ))\n * .limit(1);\n *\n * const updatedContent = {\n * ...cache[0].content,\n * 'home.hero.title': newValue // 부분 업데이트\n * };\n *\n * await db.update(cmsDraftCache)\n * .set({ content: updatedContent, updatedAt: new Date() })\n * .where(eq(cmsDraftCache.id, cache[0].id));\n *\n * // Draft 조회 (미리보기)\n * const draft = await db.select()\n * .from(cmsDraftCache)\n * .where(and(\n * eq(cmsDraftCache.section, 'home'),\n * eq(cmsDraftCache.locale, 'ko'),\n * eq(cmsDraftCache.userId, session.user.id)\n * ))\n * .limit(1);\n *\n * // 사용자의 모든 작업 중인 섹션 조회\n * const userDrafts = await db.select()\n * .from(cmsDraftCache)\n * .where(eq(cmsDraftCache.userId, userId))\n * .orderBy(desc(cmsDraftCache.updatedAt));\n *\n * // 오래된 Draft 정리 (30일 이상)\n * const stale = await db.delete(cmsDraftCache)\n * .where(lt(\n * cmsDraftCache.updatedAt,\n * new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)\n * ))\n * .returning();\n *\n * // Draft 폐기 (변경사항 버리기)\n * await db.delete(cmsDraftCache)\n * .where(and(\n * eq(cmsDraftCache.section, 'home'),\n * eq(cmsDraftCache.locale, 'ko'),\n * eq(cmsDraftCache.userId, userId)\n * ));\n */"],"mappings":";AAcA,SAAS,QAAQ,MAAM,OAAO,WAAW,OAAO,cAAc;AAC9D,SAAS,4BAA4B;AAGrC,IAAM,SAAS,qBAAqB,WAAW;AAExC,IAAM,gBAAgB,OAAO,MAAM,eAAe;AAAA;AAAA,EAErD,IAAI,OAAO,IAAI,EAAE,WAAW;AAAA;AAAA,EAG5B,SAAS,KAAK,SAAS,EAAE,QAAQ;AAAA;AAAA;AAAA,EAIjC,QAAQ,KAAK,QAAQ,EAAE,QAAQ;AAAA;AAAA;AAAA,EAI/B,QAAQ,KAAK,SAAS,EAAE,QAAQ;AAAA;AAAA;AAAA,EAIhC,SAAS,MAAM,SAAS,EAAE,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASlC,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,EAAE,QAAQ,EAAE,WAAW;AACpF,GAAG,CAAC,UAAU;AAAA;AAAA,EAEV,OAAO,wBAAwB,EAC9B,GAAG,MAAM,SAAS,MAAM,QAAQ,MAAM,MAAM;AAAA;AAAA,EAG7C,MAAM,6BAA6B,EAAE,GAAG,MAAM,OAAO;AAAA;AAAA,EAGrD,MAAM,0BAA0B,EAAE,GAAG,MAAM,MAAM;AACrD,CAAC;","names":[]}
|