@spfn/cms 0.1.0-alpha.8 → 0.1.0-alpha.81

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 (233) hide show
  1. package/README.md +28 -416
  2. package/dist/{helpers/locale.actions.d.ts → actions-BEFWwQsh.d.ts} +70 -7
  3. package/dist/actions.d.ts +2 -9
  4. package/dist/actions.js +99 -10
  5. package/dist/actions.js.map +1 -1
  6. package/dist/api.d.ts +319 -0
  7. package/dist/api.js +467 -0
  8. package/dist/api.js.map +1 -0
  9. package/dist/client.d.ts +135 -127
  10. package/dist/client.js +1318 -59
  11. package/dist/client.js.map +1 -1
  12. package/dist/{types.d.ts → index-Dh5FjWzR.d.ts} +45 -7
  13. package/dist/index.d.ts +112 -16
  14. package/dist/index.js +625 -23
  15. package/dist/index.js.map +1 -1
  16. package/dist/label-sync-generator-B0EmvtWM.d.ts +32 -0
  17. package/dist/lib/contracts/labels.d.ts +244 -0
  18. package/dist/lib/contracts/labels.js +269 -0
  19. package/dist/lib/contracts/labels.js.map +1 -0
  20. package/dist/lib/contracts/published-cache.d.ts +48 -0
  21. package/dist/lib/contracts/published-cache.js +49 -0
  22. package/dist/lib/contracts/published-cache.js.map +1 -0
  23. package/dist/lib/contracts/values.d.ts +71 -0
  24. package/dist/lib/contracts/values.js +104 -0
  25. package/dist/lib/contracts/values.js.map +1 -0
  26. package/dist/locale.constants-BNkSdNP1.d.ts +108 -0
  27. package/dist/{entities → server/entities}/cms-audit-logs.d.ts +15 -70
  28. package/dist/server/entities/cms-audit-logs.js +78 -0
  29. package/dist/server/entities/cms-audit-logs.js.map +1 -0
  30. package/dist/{entities → server/entities}/cms-draft-cache.d.ts +13 -73
  31. package/dist/server/entities/cms-draft-cache.js +38 -0
  32. package/dist/server/entities/cms-draft-cache.js.map +1 -0
  33. package/dist/{entities → server/entities}/cms-label-values.d.ts +16 -67
  34. package/dist/server/entities/cms-label-values.js +81 -0
  35. package/dist/server/entities/cms-label-values.js.map +1 -0
  36. package/dist/{entities → server/entities}/cms-labels.d.ts +17 -14
  37. package/dist/server/entities/cms-labels.js +42 -0
  38. package/dist/server/entities/cms-labels.js.map +1 -0
  39. package/dist/{entities → server/entities}/cms-published-cache.d.ts +14 -69
  40. package/dist/server/entities/cms-published-cache.js +36 -0
  41. package/dist/server/entities/cms-published-cache.js.map +1 -0
  42. package/dist/server/entities/index.d.ts +6 -0
  43. package/dist/server/entities/index.js +185 -0
  44. package/dist/server/entities/index.js.map +1 -0
  45. package/dist/server/generators/index.d.ts +19 -0
  46. package/dist/server/generators/index.js +731 -0
  47. package/dist/server/generators/index.js.map +1 -0
  48. package/dist/server/labels/index.d.ts +1 -0
  49. package/dist/server/labels/index.js +33 -0
  50. package/dist/server/labels/index.js.map +1 -0
  51. package/dist/server/repositories/index.d.ts +212 -0
  52. package/dist/server/repositories/index.js +418 -0
  53. package/dist/server/repositories/index.js.map +1 -0
  54. package/dist/server/routes/labels/[id]/admin/index.js +679 -0
  55. package/dist/server/routes/labels/[id]/admin/index.js.map +1 -0
  56. package/dist/server/routes/labels/[id]/index.js +576 -0
  57. package/dist/server/routes/labels/[id]/index.js.map +1 -0
  58. package/dist/server/routes/labels/[id]/publish/index.js +720 -0
  59. package/dist/server/routes/labels/[id]/publish/index.js.map +1 -0
  60. package/dist/server/routes/labels/[id]/versions/index.js +548 -0
  61. package/dist/server/routes/labels/[id]/versions/index.js.map +1 -0
  62. package/dist/server/routes/labels/_id_/admin/index.d.ts +11 -0
  63. package/dist/{routes/labels/[id] → server/routes/labels/_id_}/index.d.ts +5 -3
  64. package/dist/server/routes/labels/_id_/publish/index.d.ts +11 -0
  65. package/dist/server/routes/labels/_id_/versions/index.d.ts +11 -0
  66. package/dist/server/routes/labels/by-key/[key]/index.js +525 -0
  67. package/dist/server/routes/labels/by-key/[key]/index.js.map +1 -0
  68. package/dist/server/routes/labels/by-key/_key_/index.d.ts +10 -0
  69. package/dist/server/routes/labels/index.d.ts +12 -0
  70. package/dist/server/routes/labels/index.js +684 -0
  71. package/dist/server/routes/labels/index.js.map +1 -0
  72. package/dist/server/routes/published-cache/index.d.ts +11 -0
  73. package/dist/server/routes/published-cache/index.js +337 -0
  74. package/dist/server/routes/published-cache/index.js.map +1 -0
  75. package/dist/server/routes/values/[labelId]/[version]/index.js +457 -0
  76. package/dist/server/routes/values/[labelId]/[version]/index.js.map +1 -0
  77. package/dist/server/routes/values/[labelId]/index.js +452 -0
  78. package/dist/server/routes/values/[labelId]/index.js.map +1 -0
  79. package/dist/server/routes/values/_labelId_/_version_/index.d.ts +10 -0
  80. package/dist/server/routes/values/_labelId_/index.d.ts +10 -0
  81. package/dist/server.d.ts +77 -7
  82. package/dist/server.js +1747 -247
  83. package/dist/server.js.map +1 -1
  84. package/migrations/0000_init.sql +3 -0
  85. package/migrations/0001_far_lady_vermin.sql +86 -0
  86. package/migrations/0002_heavy_the_enforcers.sql +2 -0
  87. package/migrations/0003_rare_runaways.sql +1 -0
  88. package/migrations/meta/0000_snapshot.json +15 -0
  89. package/migrations/meta/0001_snapshot.json +687 -0
  90. package/migrations/meta/0002_snapshot.json +686 -0
  91. package/migrations/meta/0003_snapshot.json +563 -0
  92. package/migrations/meta/_journal.json +34 -0
  93. package/package.json +55 -36
  94. package/dist/actions.d.ts.map +0 -1
  95. package/dist/client.d.ts.map +0 -1
  96. package/dist/cms.config.d.ts +0 -77
  97. package/dist/cms.config.d.ts.map +0 -1
  98. package/dist/cms.config.js +0 -111
  99. package/dist/cms.config.js.map +0 -1
  100. package/dist/entities/cms-audit-logs.d.ts.map +0 -1
  101. package/dist/entities/cms-audit-logs.js +0 -103
  102. package/dist/entities/cms-audit-logs.js.map +0 -1
  103. package/dist/entities/cms-draft-cache.d.ts.map +0 -1
  104. package/dist/entities/cms-draft-cache.js +0 -112
  105. package/dist/entities/cms-draft-cache.js.map +0 -1
  106. package/dist/entities/cms-label-values.d.ts.map +0 -1
  107. package/dist/entities/cms-label-values.js +0 -105
  108. package/dist/entities/cms-label-values.js.map +0 -1
  109. package/dist/entities/cms-label-versions.d.ts +0 -207
  110. package/dist/entities/cms-label-versions.d.ts.map +0 -1
  111. package/dist/entities/cms-label-versions.js +0 -80
  112. package/dist/entities/cms-label-versions.js.map +0 -1
  113. package/dist/entities/cms-labels.d.ts.map +0 -1
  114. package/dist/entities/cms-labels.js +0 -48
  115. package/dist/entities/cms-labels.js.map +0 -1
  116. package/dist/entities/cms-published-cache.d.ts.map +0 -1
  117. package/dist/entities/cms-published-cache.js +0 -103
  118. package/dist/entities/cms-published-cache.js.map +0 -1
  119. package/dist/entities/index.d.ts +0 -10
  120. package/dist/entities/index.d.ts.map +0 -1
  121. package/dist/entities/index.js +0 -10
  122. package/dist/entities/index.js.map +0 -1
  123. package/dist/generators/index.d.ts +0 -19
  124. package/dist/generators/index.d.ts.map +0 -1
  125. package/dist/generators/index.js +0 -19
  126. package/dist/generators/index.js.map +0 -1
  127. package/dist/generators/label-sync-generator.d.ts +0 -33
  128. package/dist/generators/label-sync-generator.d.ts.map +0 -1
  129. package/dist/generators/label-sync-generator.js +0 -86
  130. package/dist/generators/label-sync-generator.js.map +0 -1
  131. package/dist/helpers/locale.actions.d.ts.map +0 -1
  132. package/dist/helpers/locale.actions.js +0 -210
  133. package/dist/helpers/locale.actions.js.map +0 -1
  134. package/dist/helpers/locale.constants.d.ts +0 -10
  135. package/dist/helpers/locale.constants.d.ts.map +0 -1
  136. package/dist/helpers/locale.constants.js +0 -10
  137. package/dist/helpers/locale.constants.js.map +0 -1
  138. package/dist/helpers/locale.d.ts +0 -17
  139. package/dist/helpers/locale.d.ts.map +0 -1
  140. package/dist/helpers/locale.js +0 -20
  141. package/dist/helpers/locale.js.map +0 -1
  142. package/dist/helpers/sync.d.ts +0 -41
  143. package/dist/helpers/sync.d.ts.map +0 -1
  144. package/dist/helpers/sync.js +0 -309
  145. package/dist/helpers/sync.js.map +0 -1
  146. package/dist/index.d.ts.map +0 -1
  147. package/dist/init.d.ts +0 -31
  148. package/dist/init.d.ts.map +0 -1
  149. package/dist/init.js +0 -36
  150. package/dist/init.js.map +0 -1
  151. package/dist/labels/helpers.d.ts +0 -31
  152. package/dist/labels/helpers.d.ts.map +0 -1
  153. package/dist/labels/helpers.js +0 -60
  154. package/dist/labels/helpers.js.map +0 -1
  155. package/dist/labels/index.d.ts +0 -7
  156. package/dist/labels/index.d.ts.map +0 -1
  157. package/dist/labels/index.js +0 -7
  158. package/dist/labels/index.js.map +0 -1
  159. package/dist/repositories/cms-draft-cache.repository.d.ts +0 -62
  160. package/dist/repositories/cms-draft-cache.repository.d.ts.map +0 -1
  161. package/dist/repositories/cms-draft-cache.repository.js +0 -56
  162. package/dist/repositories/cms-draft-cache.repository.js.map +0 -1
  163. package/dist/repositories/cms-label-values.repository.d.ts +0 -32
  164. package/dist/repositories/cms-label-values.repository.d.ts.map +0 -1
  165. package/dist/repositories/cms-label-values.repository.js +0 -72
  166. package/dist/repositories/cms-label-values.repository.js.map +0 -1
  167. package/dist/repositories/cms-labels.repository.d.ts +0 -53
  168. package/dist/repositories/cms-labels.repository.d.ts.map +0 -1
  169. package/dist/repositories/cms-labels.repository.js +0 -77
  170. package/dist/repositories/cms-labels.repository.js.map +0 -1
  171. package/dist/repositories/cms-published-cache.repository.d.ts +0 -53
  172. package/dist/repositories/cms-published-cache.repository.d.ts.map +0 -1
  173. package/dist/repositories/cms-published-cache.repository.js +0 -54
  174. package/dist/repositories/cms-published-cache.repository.js.map +0 -1
  175. package/dist/repositories/index.d.ts +0 -8
  176. package/dist/repositories/index.d.ts.map +0 -1
  177. package/dist/repositories/index.js +0 -9
  178. package/dist/repositories/index.js.map +0 -1
  179. package/dist/routes/labels/[id]/contract.d.ts +0 -68
  180. package/dist/routes/labels/[id]/contract.d.ts.map +0 -1
  181. package/dist/routes/labels/[id]/contract.js +0 -84
  182. package/dist/routes/labels/[id]/contract.js.map +0 -1
  183. package/dist/routes/labels/[id]/index.d.ts.map +0 -1
  184. package/dist/routes/labels/[id]/index.js +0 -96
  185. package/dist/routes/labels/[id]/index.js.map +0 -1
  186. package/dist/routes/labels/by-key/[key]/contract.d.ts +0 -24
  187. package/dist/routes/labels/by-key/[key]/contract.d.ts.map +0 -1
  188. package/dist/routes/labels/by-key/[key]/contract.js +0 -28
  189. package/dist/routes/labels/by-key/[key]/contract.js.map +0 -1
  190. package/dist/routes/labels/by-key/[key]/index.d.ts +0 -8
  191. package/dist/routes/labels/by-key/[key]/index.d.ts.map +0 -1
  192. package/dist/routes/labels/by-key/[key]/index.js +0 -32
  193. package/dist/routes/labels/by-key/[key]/index.js.map +0 -1
  194. package/dist/routes/labels/contract.d.ts +0 -59
  195. package/dist/routes/labels/contract.d.ts.map +0 -1
  196. package/dist/routes/labels/contract.js +0 -75
  197. package/dist/routes/labels/contract.js.map +0 -1
  198. package/dist/routes/labels/index.d.ts +0 -10
  199. package/dist/routes/labels/index.d.ts.map +0 -1
  200. package/dist/routes/labels/index.js +0 -73
  201. package/dist/routes/labels/index.js.map +0 -1
  202. package/dist/routes/published-cache/contract.d.ts +0 -25
  203. package/dist/routes/published-cache/contract.d.ts.map +0 -1
  204. package/dist/routes/published-cache/contract.js +0 -35
  205. package/dist/routes/published-cache/contract.js.map +0 -1
  206. package/dist/routes/published-cache/index.d.ts +0 -8
  207. package/dist/routes/published-cache/index.d.ts.map +0 -1
  208. package/dist/routes/published-cache/index.js +0 -33
  209. package/dist/routes/published-cache/index.js.map +0 -1
  210. package/dist/routes/values/[labelId]/[version]/contract.d.ts +0 -29
  211. package/dist/routes/values/[labelId]/[version]/contract.d.ts.map +0 -1
  212. package/dist/routes/values/[labelId]/[version]/contract.js +0 -33
  213. package/dist/routes/values/[labelId]/[version]/contract.js.map +0 -1
  214. package/dist/routes/values/[labelId]/[version]/index.d.ts +0 -8
  215. package/dist/routes/values/[labelId]/[version]/index.d.ts.map +0 -1
  216. package/dist/routes/values/[labelId]/[version]/index.js +0 -45
  217. package/dist/routes/values/[labelId]/[version]/index.js.map +0 -1
  218. package/dist/routes/values/[labelId]/contract.d.ts +0 -38
  219. package/dist/routes/values/[labelId]/contract.d.ts.map +0 -1
  220. package/dist/routes/values/[labelId]/contract.js +0 -59
  221. package/dist/routes/values/[labelId]/contract.js.map +0 -1
  222. package/dist/routes/values/[labelId]/index.d.ts +0 -8
  223. package/dist/routes/values/[labelId]/index.d.ts.map +0 -1
  224. package/dist/routes/values/[labelId]/index.js +0 -42
  225. package/dist/routes/values/[labelId]/index.js.map +0 -1
  226. package/dist/server.d.ts.map +0 -1
  227. package/dist/store.d.ts +0 -87
  228. package/dist/store.d.ts.map +0 -1
  229. package/dist/store.js +0 -205
  230. package/dist/store.js.map +0 -1
  231. package/dist/types.d.ts.map +0 -1
  232. package/dist/types.js +0 -7
  233. package/dist/types.js.map +0 -1
@@ -0,0 +1,78 @@
1
+ // src/server/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/server/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()
37
+ }, (table) => [
38
+ // 인덱스: 섹션별 조회 최적화
39
+ index("cms_labels_section_idx").on(table.section),
40
+ // 인덱스: key로 조회 최적화 (unique 제약으로 자동 생성되지만 명시)
41
+ index("cms_labels_key_idx").on(table.key)
42
+ ]);
43
+
44
+ // src/server/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
+ };
78
+ //# sourceMappingURL=cms-audit-logs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/server/entities/cms-audit-logs.ts","../../../src/server/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 '@/server/entities/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
- export declare const cmsDraftCache: import("drizzle-orm/pg-core").PgTableWithColumns<{
16
+ declare const cmsDraftCache: drizzle_orm_pg_core.PgTableWithColumns<{
15
17
  name: "draft_cache";
16
18
  schema: string;
17
19
  columns: {
18
- id: import("drizzle-orm/pg-core").PgColumn<{
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: import("drizzle-orm/pg-core").PgColumn<{
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: import("drizzle-orm/pg-core").PgColumn<{
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: import("drizzle-orm/pg-core").PgColumn<{
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: import("drizzle-orm/pg-core").PgColumn<{
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: import("drizzle-orm/pg-core").PgColumn<{
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
- export type CmsDraftCache = typeof cmsDraftCache.$inferSelect;
124
- export type NewCmsDraftCache = typeof cmsDraftCache.$inferInsert;
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 };
@@ -0,0 +1,38 @@
1
+ // src/server/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()
27
+ }, (table) => [
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)
34
+ ]);
35
+ export {
36
+ cmsDraftCache
37
+ };
38
+ //# sourceMappingURL=cms-draft-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/server/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":[]}
@@ -1,3 +1,5 @@
1
+ import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
2
+
1
3
  /**
2
4
  * CMS Label Values Entity
3
5
  *
@@ -7,11 +9,11 @@
7
9
  * - 버전 관리 (version)
8
10
  * - JSONB로 유연한 값 저장
9
11
  */
10
- export declare const cmsLabelValues: import("drizzle-orm/pg-core").PgTableWithColumns<{
12
+ declare const cmsLabelValues: drizzle_orm_pg_core.PgTableWithColumns<{
11
13
  name: "label_values";
12
14
  schema: string;
13
15
  columns: {
14
- id: import("drizzle-orm/pg-core").PgColumn<{
16
+ id: drizzle_orm_pg_core.PgColumn<{
15
17
  name: "id";
16
18
  tableName: "label_values";
17
19
  dataType: "number";
@@ -28,7 +30,7 @@ export declare const cmsLabelValues: import("drizzle-orm/pg-core").PgTableWithCo
28
30
  identity: undefined;
29
31
  generated: undefined;
30
32
  }, {}, {}>;
31
- labelId: import("drizzle-orm/pg-core").PgColumn<{
33
+ labelId: drizzle_orm_pg_core.PgColumn<{
32
34
  name: "label_id";
33
35
  tableName: "label_values";
34
36
  dataType: "number";
@@ -45,15 +47,15 @@ export declare const cmsLabelValues: import("drizzle-orm/pg-core").PgTableWithCo
45
47
  identity: undefined;
46
48
  generated: undefined;
47
49
  }, {}, {}>;
48
- version: import("drizzle-orm/pg-core").PgColumn<{
50
+ version: drizzle_orm_pg_core.PgColumn<{
49
51
  name: "version";
50
52
  tableName: "label_values";
51
53
  dataType: "number";
52
54
  columnType: "PgInteger";
53
55
  data: number;
54
56
  driverParam: string | number;
55
- notNull: true;
56
- hasDefault: true;
57
+ notNull: false;
58
+ hasDefault: false;
57
59
  isPrimaryKey: false;
58
60
  isAutoincrement: false;
59
61
  hasRuntimeDefault: false;
@@ -62,7 +64,7 @@ export declare const cmsLabelValues: import("drizzle-orm/pg-core").PgTableWithCo
62
64
  identity: undefined;
63
65
  generated: undefined;
64
66
  }, {}, {}>;
65
- locale: import("drizzle-orm/pg-core").PgColumn<{
67
+ locale: drizzle_orm_pg_core.PgColumn<{
66
68
  name: "locale";
67
69
  tableName: "label_values";
68
70
  dataType: "string";
@@ -79,7 +81,7 @@ export declare const cmsLabelValues: import("drizzle-orm/pg-core").PgTableWithCo
79
81
  identity: undefined;
80
82
  generated: undefined;
81
83
  }, {}, {}>;
82
- breakpoint: import("drizzle-orm/pg-core").PgColumn<{
84
+ breakpoint: drizzle_orm_pg_core.PgColumn<{
83
85
  name: "breakpoint";
84
86
  tableName: "label_values";
85
87
  dataType: "string";
@@ -96,7 +98,7 @@ export declare const cmsLabelValues: import("drizzle-orm/pg-core").PgTableWithCo
96
98
  identity: undefined;
97
99
  generated: undefined;
98
100
  }, {}, {}>;
99
- value: import("drizzle-orm/pg-core").PgColumn<{
101
+ value: drizzle_orm_pg_core.PgColumn<{
100
102
  name: "value";
101
103
  tableName: "label_values";
102
104
  dataType: "json";
@@ -113,7 +115,7 @@ export declare const cmsLabelValues: import("drizzle-orm/pg-core").PgTableWithCo
113
115
  identity: undefined;
114
116
  generated: undefined;
115
117
  }, {}, {}>;
116
- createdAt: import("drizzle-orm/pg-core").PgColumn<{
118
+ createdAt: drizzle_orm_pg_core.PgColumn<{
117
119
  name: "created_at";
118
120
  tableName: "label_values";
119
121
  dataType: "date";
@@ -133,60 +135,7 @@ export declare const cmsLabelValues: import("drizzle-orm/pg-core").PgTableWithCo
133
135
  };
134
136
  dialect: "pg";
135
137
  }>;
136
- export type CmsLabelValue = typeof cmsLabelValues.$inferSelect;
137
- export type NewCmsLabelValue = typeof cmsLabelValues.$inferInsert;
138
- /**
139
- * 사용 예시:
140
- *
141
- * // 텍스트 값 저장
142
- * await db.insert(cmsLabelValues).values({
143
- * labelId: 1,
144
- * version: 1,
145
- * locale: 'ko',
146
- * breakpoint: null,
147
- * value: {
148
- * type: 'text',
149
- * content: '미래를 만드는 기업'
150
- * }
151
- * });
152
- *
153
- * // 반응형 이미지 저장 (모바일용)
154
- * await db.insert(cmsLabelValues).values({
155
- * labelId: 2,
156
- * version: 1,
157
- * locale: 'ko',
158
- * breakpoint: 'sm',
159
- * value: {
160
- * type: 'image',
161
- * url: '/uploads/hero-mobile.jpg',
162
- * alt: 'Hero Image',
163
- * width: 640,
164
- * height: 480
165
- * }
166
- * });
167
- *
168
- * // 특정 버전의 한국어 값 조회
169
- * const values = await db.select()
170
- * .from(cmsLabelValues)
171
- * .where(and(
172
- * eq(cmsLabelValues.labelId, 1),
173
- * eq(cmsLabelValues.version, 2),
174
- * eq(cmsLabelValues.locale, 'ko')
175
- * ));
176
- *
177
- * // Object 타입 값 저장 (재귀 구조)
178
- * await db.insert(cmsLabelValues).values({
179
- * labelId: 3,
180
- * version: 1,
181
- * locale: 'ko',
182
- * value: {
183
- * type: 'object',
184
- * fields: {
185
- * title: { type: 'text', content: '특징 1' },
186
- * icon: { type: 'image', url: '/icons/feature1.svg', alt: 'Icon' },
187
- * description: { type: 'text', content: '상세 설명...' }
188
- * }
189
- * }
190
- * });
191
- */
192
- //# sourceMappingURL=cms-label-values.d.ts.map
138
+ type CmsLabelValue = typeof cmsLabelValues.$inferSelect;
139
+ type NewCmsLabelValue = typeof cmsLabelValues.$inferInsert;
140
+
141
+ export { type CmsLabelValue, type NewCmsLabelValue, cmsLabelValues };
@@ -0,0 +1,81 @@
1
+ // src/server/entities/cms-label-values.ts
2
+ import { serial as serial2, integer as integer2, text as text2, jsonb, timestamp as timestamp2, index as index2, unique } from "drizzle-orm/pg-core";
3
+ import { createFunctionSchema as createFunctionSchema2 } from "@spfn/core/db";
4
+
5
+ // src/server/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()
37
+ }, (table) => [
38
+ // 인덱스: 섹션별 조회 최적화
39
+ index("cms_labels_section_idx").on(table.section),
40
+ // 인덱스: key로 조회 최적화 (unique 제약으로 자동 생성되지만 명시)
41
+ index("cms_labels_key_idx").on(table.key)
42
+ ]);
43
+
44
+ // src/server/entities/cms-label-values.ts
45
+ var schema2 = createFunctionSchema2("@spfn/cms");
46
+ var cmsLabelValues = schema2.table("label_values", {
47
+ // Primary Key
48
+ id: serial2("id").primaryKey(),
49
+ // Foreign Key: cms_labels
50
+ labelId: integer2("label_id").notNull().references(() => cmsLabels.id, { onDelete: "cascade" }),
51
+ // 버전 번호 (null = draft, number = published version)
52
+ version: integer2("version"),
53
+ // 언어 코드
54
+ locale: text2("locale").notNull().default("ko"),
55
+ // "ko" | "en" | "ja"
56
+ // 반응형 브레이크포인트
57
+ breakpoint: text2("breakpoint"),
58
+ // null = 기본값 (모든 화면 크기)
59
+ // "sm" | "md" | "lg" | "xl" | "2xl"
60
+ // 실제 값 (JSONB)
61
+ value: jsonb("value").notNull(),
62
+ // LabelValue 타입:
63
+ // - TextValue: { type: "text", content: string }
64
+ // - ImageValue: { type: "image", url: string, alt?: string, width?: number, height?: number }
65
+ // - VideoValue: { type: "video", url: string, thumbnail?: string, duration?: number }
66
+ // - FileValue: { type: "file", url: string, filename: string, size?: number }
67
+ // - ObjectValue: { type: "object", fields: Record<string, LabelValue> }
68
+ // 생성 시각
69
+ createdAt: timestamp2("created_at", { withTimezone: true }).notNull().defaultNow()
70
+ }, (table) => [
71
+ // UNIQUE 제약: 같은 버전에서 locale + breakpoint 조합은 유일
72
+ unique("cms_label_values_locale_breakpoint_unique").on(table.labelId, table.version, table.locale, table.breakpoint),
73
+ // 인덱스: labelId + version 복합 조회 최적화
74
+ index2("cms_label_values_label_version_idx").on(table.labelId, table.version),
75
+ // 인덱스: locale 필터링 최적화
76
+ index2("cms_label_values_locale_idx").on(table.locale)
77
+ ]);
78
+ export {
79
+ cmsLabelValues
80
+ };
81
+ //# sourceMappingURL=cms-label-values.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/server/entities/cms-label-values.ts","../../../src/server/entities/cms-labels.ts"],"sourcesContent":["/**\n * CMS Label Values Entity\n *\n * 라벨의 실제 값을 저장합니다.\n * - 다국어 지원 (locale)\n * - 반응형 지원 (breakpoint)\n * - 버전 관리 (version)\n * - JSONB로 유연한 값 저장\n */\n\nimport { serial, integer, text, jsonb, timestamp, index, unique } from 'drizzle-orm/pg-core';\nimport { createFunctionSchema } from '@spfn/core/db';\nimport { cmsLabels } from '@/server/entities/cms-labels';\n\n// Create isolated schema for @spfn/cms\nconst schema = createFunctionSchema('@spfn/cms');\n\nexport const cmsLabelValues = schema.table('label_values', {\n // Primary Key\n id: serial('id').primaryKey(),\n\n // Foreign Key: cms_labels\n labelId: integer('label_id')\n .notNull()\n .references(() => cmsLabels.id, { onDelete: 'cascade' }),\n\n // 버전 번호 (null = draft, number = published version)\n version: integer('version'),\n\n // 언어 코드\n locale: text('locale').notNull().default('ko'),\n // \"ko\" | \"en\" | \"ja\"\n\n // 반응형 브레이크포인트\n breakpoint: text('breakpoint'),\n // null = 기본값 (모든 화면 크기)\n // \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\"\n\n // 실제 값 (JSONB)\n value: jsonb('value').notNull(),\n // LabelValue 타입:\n // - TextValue: { type: \"text\", content: string }\n // - ImageValue: { type: \"image\", url: string, alt?: string, width?: number, height?: number }\n // - VideoValue: { type: \"video\", url: string, thumbnail?: string, duration?: number }\n // - FileValue: { type: \"file\", url: string, filename: string, size?: number }\n // - ObjectValue: { type: \"object\", fields: Record<string, LabelValue> }\n\n // 생성 시각\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n}, (table) => [\n // UNIQUE 제약: 같은 버전에서 locale + breakpoint 조합은 유일\n unique('cms_label_values_locale_breakpoint_unique')\n .on(table.labelId, table.version, table.locale, table.breakpoint),\n\n // 인덱스: labelId + version 복합 조회 최적화\n index('cms_label_values_label_version_idx')\n .on(table.labelId, table.version),\n\n // 인덱스: locale 필터링 최적화\n index('cms_label_values_locale_idx').on(table.locale),\n]);\n\n// 타입 추론\nexport type CmsLabelValue = typeof cmsLabelValues.$inferSelect;\nexport type NewCmsLabelValue = typeof cmsLabelValues.$inferInsert;\n\n/**\n * 사용 예시:\n *\n * // 텍스트 값 저장\n * await db.insert(cmsLabelValues).values({\n * labelId: 1,\n * version: 1,\n * locale: 'ko',\n * breakpoint: null,\n * value: {\n * type: 'text',\n * content: '미래를 만드는 기업'\n * }\n * });\n *\n * // 반응형 이미지 저장 (모바일용)\n * await db.insert(cmsLabelValues).values({\n * labelId: 2,\n * version: 1,\n * locale: 'ko',\n * breakpoint: 'sm',\n * value: {\n * type: 'image',\n * url: '/uploads/hero-mobile.jpg',\n * alt: 'Hero Image',\n * width: 640,\n * height: 480\n * }\n * });\n *\n * // 특정 버전의 한국어 값 조회\n * const values = await db.select()\n * .from(cmsLabelValues)\n * .where(and(\n * eq(cmsLabelValues.labelId, 1),\n * eq(cmsLabelValues.version, 2),\n * eq(cmsLabelValues.locale, 'ko')\n * ));\n *\n * // Object 타입 값 저장 (재귀 구조)\n * await db.insert(cmsLabelValues).values({\n * labelId: 3,\n * version: 1,\n * locale: 'ko',\n * value: {\n * type: 'object',\n * fields: {\n * title: { type: 'text', content: '특징 1' },\n * icon: { type: 'image', url: '/icons/feature1.svg', alt: 'Icon' },\n * description: { type: 'text', content: '상세 설명...' }\n * }\n * }\n * });\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,QAAO,cAAc;AACvE,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,iBAAiBD,QAAO,MAAM,gBAAgB;AAAA;AAAA,EAEvD,IAAIE,QAAO,IAAI,EAAE,WAAW;AAAA;AAAA,EAG5B,SAASC,SAAQ,UAAU,EACtB,QAAQ,EACR,WAAW,MAAM,UAAU,IAAI,EAAE,UAAU,UAAU,CAAC;AAAA;AAAA,EAG3D,SAASA,SAAQ,SAAS;AAAA;AAAA,EAG1B,QAAQC,MAAK,QAAQ,EAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA;AAAA;AAAA,EAI7C,YAAYA,MAAK,YAAY;AAAA;AAAA;AAAA;AAAA,EAK7B,OAAO,MAAM,OAAO,EAAE,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAS9B,WAAWC,WAAU,cAAc,EAAE,cAAc,KAAK,CAAC,EAAE,QAAQ,EAAE,WAAW;AACpF,GAAG,CAAC,UAAU;AAAA;AAAA,EAEV,OAAO,2CAA2C,EAC7C,GAAG,MAAM,SAAS,MAAM,SAAS,MAAM,QAAQ,MAAM,UAAU;AAAA;AAAA,EAGpEC,OAAM,oCAAoC,EACrC,GAAG,MAAM,SAAS,MAAM,OAAO;AAAA;AAAA,EAGpCA,OAAM,6BAA6B,EAAE,GAAG,MAAM,MAAM;AACxD,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 Labels Entity
3
5
  *
@@ -7,11 +9,11 @@
7
9
  * - 타입 정의 (type)
8
10
  * - 발행 상태 (publishedVersion)
9
11
  */
10
- export declare const cmsLabels: import("drizzle-orm/pg-core").PgTableWithColumns<{
12
+ declare const cmsLabels: drizzle_orm_pg_core.PgTableWithColumns<{
11
13
  name: "labels";
12
14
  schema: string;
13
15
  columns: {
14
- id: import("drizzle-orm/pg-core").PgColumn<{
16
+ id: drizzle_orm_pg_core.PgColumn<{
15
17
  name: "id";
16
18
  tableName: "labels";
17
19
  dataType: "number";
@@ -28,7 +30,7 @@ export declare const cmsLabels: import("drizzle-orm/pg-core").PgTableWithColumns
28
30
  identity: undefined;
29
31
  generated: undefined;
30
32
  }, {}, {}>;
31
- key: import("drizzle-orm/pg-core").PgColumn<{
33
+ key: drizzle_orm_pg_core.PgColumn<{
32
34
  name: "key";
33
35
  tableName: "labels";
34
36
  dataType: "string";
@@ -45,7 +47,7 @@ export declare const cmsLabels: import("drizzle-orm/pg-core").PgTableWithColumns
45
47
  identity: undefined;
46
48
  generated: undefined;
47
49
  }, {}, {}>;
48
- section: import("drizzle-orm/pg-core").PgColumn<{
50
+ section: drizzle_orm_pg_core.PgColumn<{
49
51
  name: "section";
50
52
  tableName: "labels";
51
53
  dataType: "string";
@@ -62,7 +64,7 @@ export declare const cmsLabels: import("drizzle-orm/pg-core").PgTableWithColumns
62
64
  identity: undefined;
63
65
  generated: undefined;
64
66
  }, {}, {}>;
65
- type: import("drizzle-orm/pg-core").PgColumn<{
67
+ type: drizzle_orm_pg_core.PgColumn<{
66
68
  name: "type";
67
69
  tableName: "labels";
68
70
  dataType: "string";
@@ -79,7 +81,7 @@ export declare const cmsLabels: import("drizzle-orm/pg-core").PgTableWithColumns
79
81
  identity: undefined;
80
82
  generated: undefined;
81
83
  }, {}, {}>;
82
- defaultValue: import("drizzle-orm/pg-core").PgColumn<{
84
+ defaultValue: drizzle_orm_pg_core.PgColumn<{
83
85
  name: "default_value";
84
86
  tableName: "labels";
85
87
  dataType: "string";
@@ -96,7 +98,7 @@ export declare const cmsLabels: import("drizzle-orm/pg-core").PgTableWithColumns
96
98
  identity: undefined;
97
99
  generated: undefined;
98
100
  }, {}, {}>;
99
- description: import("drizzle-orm/pg-core").PgColumn<{
101
+ description: drizzle_orm_pg_core.PgColumn<{
100
102
  name: "description";
101
103
  tableName: "labels";
102
104
  dataType: "string";
@@ -113,7 +115,7 @@ export declare const cmsLabels: import("drizzle-orm/pg-core").PgTableWithColumns
113
115
  identity: undefined;
114
116
  generated: undefined;
115
117
  }, {}, {}>;
116
- publishedVersion: import("drizzle-orm/pg-core").PgColumn<{
118
+ publishedVersion: drizzle_orm_pg_core.PgColumn<{
117
119
  name: "published_version";
118
120
  tableName: "labels";
119
121
  dataType: "number";
@@ -130,7 +132,7 @@ export declare const cmsLabels: import("drizzle-orm/pg-core").PgTableWithColumns
130
132
  identity: undefined;
131
133
  generated: undefined;
132
134
  }, {}, {}>;
133
- createdBy: import("drizzle-orm/pg-core").PgColumn<{
135
+ createdBy: drizzle_orm_pg_core.PgColumn<{
134
136
  name: "created_by";
135
137
  tableName: "labels";
136
138
  dataType: "string";
@@ -147,7 +149,7 @@ export declare const cmsLabels: import("drizzle-orm/pg-core").PgTableWithColumns
147
149
  identity: undefined;
148
150
  generated: undefined;
149
151
  }, {}, {}>;
150
- createdAt: import("drizzle-orm/pg-core").PgColumn<{
152
+ createdAt: drizzle_orm_pg_core.PgColumn<{
151
153
  name: "created_at";
152
154
  tableName: "labels";
153
155
  dataType: "date";
@@ -164,7 +166,7 @@ export declare const cmsLabels: import("drizzle-orm/pg-core").PgTableWithColumns
164
166
  identity: undefined;
165
167
  generated: undefined;
166
168
  }, {}, {}>;
167
- updatedAt: import("drizzle-orm/pg-core").PgColumn<{
169
+ updatedAt: drizzle_orm_pg_core.PgColumn<{
168
170
  name: "updated_at";
169
171
  tableName: "labels";
170
172
  dataType: "date";
@@ -184,6 +186,7 @@ export declare const cmsLabels: import("drizzle-orm/pg-core").PgTableWithColumns
184
186
  };
185
187
  dialect: "pg";
186
188
  }>;
187
- export type CmsLabel = typeof cmsLabels.$inferSelect;
188
- export type NewCmsLabel = typeof cmsLabels.$inferInsert;
189
- //# sourceMappingURL=cms-labels.d.ts.map
189
+ type CmsLabel = typeof cmsLabels.$inferSelect;
190
+ type NewCmsLabel = typeof cmsLabels.$inferInsert;
191
+
192
+ export { type CmsLabel, type NewCmsLabel, cmsLabels };