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];
|