summaryrefslogtreecommitdiff
path: root/db/schema/menu-v2.ts
blob: 2d0282fa16f7d594c0193d5bba81f9be36dd6ee9 (plain)
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
35
36
37
38
39
40
41
42
43
44
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
81
82
83
84
85
86
87
88
// db/schema/menu-v2.ts
import { pgTable, pgEnum, integer, varchar, text, timestamp, boolean, index, uniqueIndex } from "drizzle-orm/pg-core";
import { relations } from "drizzle-orm";
import { users } from "./users";

export const menuTreeNodeTypeEnum = pgEnum('menu_tree_node_type', [
  'menu_group',  // 메뉴그룹 (1단계) - 헤더에 표시되는 드롭다운 트리거
  'group',       // 그룹 (2단계) - 드롭다운 내 구분 영역
  'menu',        // 메뉴 (3단계) - 드롭다운 내 링크
  'additional'   // 추가 메뉴 - 최상위 단일 링크 (Dashboard, QNA, FAQ 등)
]);

export const menuDomainEnum = pgEnum('menu_domain', [
  'evcp',     // 내부 사용자용
  'partners'  // 협력업체용
]);

export const menuTreeNodes = pgTable("menu_tree_nodes", {
  id: integer("id").primaryKey().generatedAlwaysAsIdentity(),
  
  // 도메인 구분
  domain: menuDomainEnum("domain").notNull(),
  
  // 트리 구조
  parentId: integer("parent_id").references((): any => menuTreeNodes.id, { onDelete: "cascade" }),
  nodeType: menuTreeNodeTypeEnum("node_type").notNull(),
  sortOrder: integer("sort_order").notNull().default(0),
  
  // 다국어 텍스트 (DB 직접 관리)
  titleKo: varchar("title_ko", { length: 255 }).notNull(),
  titleEn: varchar("title_en", { length: 255 }),
  descriptionKo: text("description_ko"),
  descriptionEn: text("description_en"),
  
  // 메뉴 전용 필드 (nodeType === 'menu' 또는 'additional'일 때)
  menuPath: varchar("menu_path", { length: 255 }),  // href 값 (예: /evcp/projects)
  icon: varchar("icon", { length: 100 }),
  
  // 권한 연동
  // evcp: Oracle DB SCR_ID 참조
  // partners: 자체 권한 시스템 (TODO)
  scrId: varchar("scr_id", { length: 100 }),
  
  // 상태
  isActive: boolean("is_active").default(true).notNull(),
  
  // 담당자 (evcp 전용)
  manager1Id: integer("manager1_id").references(() => users.id, { onDelete: "set null" }),
  manager2Id: integer("manager2_id").references(() => users.id, { onDelete: "set null" }),
  
  createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
  updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull(),
}, (table) => ({
  domainIdx: index("menu_tree_domain_idx").on(table.domain),
  parentIdx: index("menu_tree_parent_idx").on(table.parentId),
  sortOrderIdx: index("menu_tree_sort_order_idx").on(table.sortOrder),
  menuPathUnique: uniqueIndex("menu_tree_path_unique_idx").on(table.menuPath),
  scrIdIdx: index("menu_tree_scr_id_idx").on(table.scrId),
}));

// Relations 정의
export const menuTreeNodesRelations = relations(menuTreeNodes, ({ one, many }) => ({
  parent: one(menuTreeNodes, {
    fields: [menuTreeNodes.parentId],
    references: [menuTreeNodes.id],
    relationName: "parentChild",
  }),
  children: many(menuTreeNodes, {
    relationName: "parentChild",
  }),
  manager1: one(users, {
    fields: [menuTreeNodes.manager1Id],
    references: [users.id],
    relationName: "menuManager1",
  }),
  manager2: one(users, {
    fields: [menuTreeNodes.manager2Id],
    references: [users.id],
    relationName: "menuManager2",
  }),
}));

// Type exports
export type MenuTreeNode = typeof menuTreeNodes.$inferSelect;
export type NewMenuTreeNode = typeof menuTreeNodes.$inferInsert;
export type NodeType = (typeof menuTreeNodeTypeEnum.enumValues)[number];
export type MenuDomain = (typeof menuDomainEnum.enumValues)[number];