- 화면 복제 기능을 개선하여 DB 구조 개편 후의 효율적인 화면 관리를 지원합니다. - 그룹 복제 시 버튼의 `targetScreenId`가 새 화면으로 매핑되지 않는 버그를 수정하였습니다. - 관련된 서비스 및 쿼리에서 `table_type_columns`를 사용하여 라벨 정보를 조회하도록 변경하였습니다. - 여러 컨트롤러 및 서비스에서 `column_labels` 대신 `table_type_columns`를 참조하도록 업데이트하였습니다.
17 KiB
17 KiB
Vexplor 구조 다이어그램
생성일: 2026-01-22 | 총 테이블: 164개 | 코드 기반 관계 분석 완료
1. 테이블 JOIN 관계도 (핵심)
1-1. 사용자/권한 시스템 JOIN 관계
| CRUD | 테이블 순서 | 설명 |
|---|---|---|
| C | user_info → user_dept → authority_sub_user |
사용자 생성 → 부서 배정 → 권한 부여 |
| R | user_info + company_mng + authority_sub_user + authority_master JOIN |
로그인/조회 시 회사+권한 JOIN |
| U | user_info / user_dept / authority_sub_user 개별 |
각 테이블 독립 수정 |
| D | 각각 독립 삭제 (별도 API) | user_dept, authority_sub_user, user_info 각각 삭제 |
erDiagram
company_mng {
varchar company_code PK "회사코드"
varchar company_name "회사명"
}
user_info {
varchar user_id PK "사용자ID"
varchar company_code "회사코드 (멀티테넌시)"
varchar user_name "사용자명"
varchar user_type "SUPER_ADMIN | COMPANY_ADMIN | USER"
}
dept_info {
varchar dept_code PK "부서코드"
varchar company_code "회사코드"
varchar dept_name "부서명"
}
user_dept {
varchar user_id "사용자ID"
varchar dept_code "부서코드"
varchar company_code "회사코드"
}
authority_master {
int objid PK "권한그룹ID"
varchar company_code "회사코드"
varchar auth_group_name "권한그룹명"
}
authority_sub_user {
int master_objid "권한그룹ID"
varchar user_id "사용자ID"
varchar company_code "회사코드"
}
company_mng ||--o{ user_info : "company_code = company_code"
company_mng ||--o{ dept_info : "company_code = company_code"
user_info ||--o{ user_dept : "user_id = user_id"
dept_info ||--o{ user_dept : "dept_code = dept_code"
authority_master ||--o{ authority_sub_user : "objid = master_objid"
user_info ||--o{ authority_sub_user : "user_id = user_id"
실제 코드 JOIN 예시:
-- 사용자 권한 조회 (authService.ts:158)
SELECT am.auth_group_name, am.objid
FROM authority_sub_user asu
INNER JOIN authority_master am ON asu.master_objid = am.objid
WHERE asu.user_id = $1
1-2. 메뉴/권한 시스템 JOIN 관계
| CRUD | 테이블 순서 | 설명 |
|---|---|---|
| C | menu_info → rel_menu_auth |
메뉴 생성 → 권한그룹에 메뉴 할당 |
| R | authority_master → rel_menu_auth → menu_info |
사용자 권한으로 접근 가능 메뉴 필터링 |
| U | menu_info 단독 / rel_menu_auth 삭제 후 재생성 |
메뉴 수정 or 권한 재할당 |
| D | rel_menu_auth → menu_info |
권한 매핑 먼저 삭제 → 메뉴 삭제 |
erDiagram
menu_info {
int objid PK "메뉴ID"
varchar company_code "회사코드"
varchar menu_name_kor "메뉴명"
varchar menu_url "메뉴URL"
int parent_obj_id "상위메뉴ID"
}
rel_menu_auth {
int menu_objid "메뉴ID"
int auth_objid "권한그룹ID"
varchar company_code "회사코드"
}
authority_master {
int objid PK "권한그룹ID"
varchar company_code "회사코드"
}
menu_info ||--o{ rel_menu_auth : "objid = menu_objid"
authority_master ||--o{ rel_menu_auth : "objid = auth_objid"
실제 코드 JOIN 예시:
-- 사용자 메뉴 조회 (adminService.ts)
SELECT mi.*
FROM menu_info mi
JOIN rel_menu_auth rma ON mi.objid = rma.menu_objid
WHERE rma.auth_objid IN (사용자권한목록)
AND mi.company_code = $companyCode
1-3. 화면 시스템 JOIN 관계
| CRUD | 테이블 순서 | 설명 |
|---|---|---|
| C | screen_definitions → screen_layouts → screen_menu_assignments |
화면 정의 → 레이아웃 → 메뉴 연결 |
| R | menu_info → screen_menu_assignments → screen_definitions + screen_layouts JOIN |
메뉴에서 화면+레이아웃 JOIN |
| U | screen_definitions / screen_layouts 개별 (같은 screen_id) |
정의와 레이아웃 각각 수정 |
| D | screen_layouts → screen_menu_assignments → screen_definitions |
레이아웃 → 메뉴연결 → 정의 순서 |
그룹:
screen_groups→screen_group_screens는 별도 API로 관리 (복사/그룹화 용도)
erDiagram
screen_definitions {
uuid screen_id PK "화면ID"
varchar company_code "회사코드"
varchar screen_name "화면명"
varchar table_name "연결테이블"
}
screen_layouts {
uuid screen_id PK "화면ID"
jsonb layout_metadata "레이아웃JSON"
}
screen_menu_assignments {
uuid screen_id "화면ID"
int menu_objid "메뉴ID"
varchar company_code "회사코드"
}
screen_groups {
int id PK "그룹ID"
varchar company_code "회사코드"
varchar group_name "그룹명"
}
screen_group_screens {
int group_id "그룹ID"
uuid screen_id "화면ID"
varchar company_code "회사코드"
}
screen_definitions ||--|| screen_layouts : "screen_id = screen_id"
screen_definitions ||--o{ screen_menu_assignments : "screen_id = screen_id"
menu_info ||--o{ screen_menu_assignments : "objid = menu_objid"
screen_groups ||--o{ screen_group_screens : "id = group_id"
screen_definitions ||--o{ screen_group_screens : "screen_id = screen_id"
실제 코드 JOIN 예시:
-- 화면 정의 + 레이아웃 조회 (screenGroupController.ts:1272)
SELECT sd.*, sl.layout_metadata
FROM screen_definitions sd
JOIN screen_layouts sl ON sd.screen_id = sl.screen_id
WHERE sd.screen_id = $1
1-4. 테이블 타입/메타데이터 JOIN 관계
| CRUD | 테이블 순서 | 설명 |
|---|---|---|
| C | 각 테이블 독립 생성 | DDL 실행 시 자동 생성, 또는 개별 등록 |
| R | table_type_columns + table_labels + table_relationships LEFT JOIN |
화면 로딩 시 메타데이터 조합 |
| U | 각 테이블 개별 (table_name + column_name + company_code 기준) | 컬럼 정의/라벨/관계 각각 수정 |
| D | 각 테이블 독립 삭제 | 테이블 삭제 시 관련 메타데이터 개별 삭제 |
코드값 조회:
table_column_category_values→code_category→code_info(드롭다운 옵션)
erDiagram
table_type_columns {
varchar table_name PK "테이블명"
varchar column_name PK "컬럼명"
varchar company_code PK "회사코드"
varchar display_name "표시명"
varchar data_type "데이터타입"
varchar reference_table "참조테이블"
varchar reference_column "참조컬럼"
}
table_labels {
varchar table_name PK "테이블명"
varchar company_code PK "회사코드"
varchar display_name "테이블표시명"
}
table_column_category_values {
varchar table_name "테이블명"
varchar column_name "컬럼명"
varchar category_code "카테고리코드"
varchar company_code "회사코드"
}
table_relationships {
varchar table_name "테이블명"
varchar source_column "소스컬럼"
varchar target_table "타겟테이블"
varchar target_column "타겟컬럼"
varchar company_code "회사코드"
}
code_category {
varchar category_code PK "카테고리코드"
varchar company_code PK "회사코드"
varchar category_name "카테고리명"
}
code_info {
varchar category_code "카테고리코드"
varchar code_value PK "코드값"
varchar company_code PK "회사코드"
varchar code_name "코드명"
}
table_type_columns ||--o{ table_labels : "table_name = table_name"
table_type_columns ||--o{ table_column_category_values : "table_name, column_name"
table_type_columns ||--o{ table_relationships : "table_name = table_name"
code_category ||--o{ code_info : "category_code = category_code"
table_column_category_values }o--|| code_category : "category_code = category_code"
실제 코드 JOIN 예시:
-- 테이블 컬럼 정보 조회 (tableManagementService.ts:210)
SELECT ttc.*, cl.display_name as column_label
FROM table_type_columns ttc
LEFT JOIN column_labels cl
ON ttc.table_name = cl.table_name
AND ttc.column_name = cl.column_name
WHERE ttc.table_name = $1
AND ttc.company_code = $2
1-5. 플로우 시스템 JOIN 관계
| CRUD | 테이블 순서 | 설명 |
|---|---|---|
| C | flow_definition → flow_step → flow_step_connection → flow_data_mapping |
플로우 → 스텝 → 연결선 → 매핑 |
| R | flow_definition + flow_step + flow_step_connection JOIN |
플로우 화면 렌더링 |
| U | 각 테이블 개별 (definition_id/step_id 기준) | 정의/스텝/연결 각각 수정 |
| D | 각 테이블 독립 삭제 (DB CASCADE 의존) | step/connection/definition 각각 삭제 API |
데이터 이동:
flow_data_mapping(컬럼 변환) → 소스→타겟 INSERT →flow_audit_log(자동 기록)
erDiagram
flow_definition {
int id PK "플로우ID"
varchar company_code "회사코드"
varchar name "플로우명"
}
flow_step {
int id PK "스텝ID"
int definition_id "플로우ID"
varchar company_code "회사코드"
varchar step_name "스텝명"
varchar table_name "연결테이블"
int step_order "순서"
}
flow_step_connection {
int id PK "연결ID"
int from_step_id "출발스텝ID"
int to_step_id "도착스텝ID"
int definition_id "플로우ID"
}
flow_data_mapping {
int from_step_id "출발스텝ID"
int to_step_id "도착스텝ID"
varchar source_column "소스컬럼"
varchar target_column "타겟컬럼"
}
flow_audit_log {
int id PK "로그ID"
int definition_id "플로우ID"
int from_step_id "출발스텝ID"
int to_step_id "도착스텝ID"
int data_id "데이터ID"
timestamp moved_at "이동시간"
}
flow_definition ||--o{ flow_step : "id = definition_id"
flow_step ||--o{ flow_step_connection : "id = from_step_id"
flow_step ||--o{ flow_step_connection : "id = to_step_id"
flow_step ||--o{ flow_data_mapping : "id = from_step_id"
flow_step ||--o{ flow_audit_log : "id = from_step_id"
실제 코드 JOIN 예시:
-- 플로우 감사로그 조회 (flowDataMoveService.ts:461)
SELECT fal.*,
fs_from.step_name as from_step_name,
fs_to.step_name as to_step_name
FROM flow_audit_log fal
LEFT JOIN flow_step fs_from ON fal.from_step_id = fs_from.id
LEFT JOIN flow_step fs_to ON fal.to_step_id = fs_to.id
WHERE fal.definition_id = $1
1-6. 배치/수집 시스템 JOIN 관계
| CRUD | 테이블 순서 | 설명 |
|---|---|---|
| C | external_db_connections → batch_configs → batch_mappings |
외부DB 연결 → 배치 설정 → 매핑 규칙 |
| R | batch_configs + external_db_connections + batch_mappings JOIN |
배치 실행 시 전체 설정 조회 |
| U | batch_mappings 삭제 후 재생성 / batch_configs 개별 수정 |
매핑은 전체 교체 방식 |
| D | batch_configs 삭제 시 batch_mappings CASCADE 삭제 |
설정만 삭제하면 매핑 자동 삭제 |
실행 시: 크론 → 외부DB 조회 → 내부 테이블 동기화 →
batch_execution_logs(결과 기록)
erDiagram
external_db_connections {
int id PK "연결ID"
varchar company_code "회사코드"
varchar connection_name "연결명"
varchar db_type "postgresql|mysql|mssql"
varchar host "호스트"
int port "포트"
}
batch_configs {
int id PK "배치ID"
varchar company_code "회사코드"
varchar batch_name "배치명"
varchar cron_expression "크론식"
int connection_id "연결ID"
varchar is_active "Y|N"
}
batch_mappings {
int id PK "매핑ID"
int batch_config_id "배치ID"
varchar source_table "소스테이블"
varchar source_column "소스컬럼"
varchar target_table "타겟테이블"
varchar target_column "타겟컬럼"
}
batch_execution_logs {
int id PK "로그ID"
int batch_config_id "배치ID"
timestamp started_at "시작시간"
timestamp finished_at "종료시간"
varchar status "SUCCESS|FAILED"
}
external_db_connections ||--o{ batch_configs : "id = connection_id"
batch_configs ||--o{ batch_mappings : "id = batch_config_id"
batch_configs ||--o{ batch_execution_logs : "id = batch_config_id"
실제 코드 JOIN 예시:
-- 배치 설정 + 매핑 조회 (batchService.ts:143)
SELECT bc.*, bm.*
FROM batch_configs bc
LEFT JOIN batch_mappings bm ON bc.id = bm.batch_config_id
WHERE bc.id = $1
AND bc.company_code = $2
ORDER BY bm.mapping_order
2. 로직 플로우 요약
위 JOIN 관계가 언제 사용되는지 간략 설명
2-1. 로그인 → 화면 접근 순서
| 단계 | 테이블 | JOIN 관계 | 설명 |
|---|---|---|---|
| 1 | user_info |
- | user_id, password 확인 |
| 2 | user_info |
- | company_code 조회 → 멀티테넌시 분기 |
| 3 | company_mng |
user_info.company_code = company_mng.company_code | 회사명 조회 |
| 4 | authority_sub_user → authority_master |
asu.master_objid = am.objid | 사용자 권한 조회 |
| 5 | menu_info → rel_menu_auth |
mi.objid = rma.menu_objid | 권한별 메뉴 필터 |
| 6 | screen_menu_assignments → screen_definitions |
sma.screen_id = sd.screen_id | 메뉴-화면 연결 |
| 7 | screen_definitions → screen_layouts |
sd.screen_id = sl.screen_id | 화면+레이아웃 |
| 8 | table_type_columns |
WHERE table_name = $1 | 컬럼 메타데이터 |
2-2. 데이터 조회 순서
| 단계 | 테이블 | JOIN 관계 | 설명 |
|---|---|---|---|
| 1 | table_type_columns |
- | 컬럼 정의 조회 |
| 2 | table_labels |
ttc.table_name = tl.table_name | 테이블 표시명 |
| 3 | table_column_category_values |
ttc.table_name, column_name | 카테고리 값 |
| 4 | table_relationships |
ttc.table_name = tr.table_name | 참조 관계 |
| 5 | code_category → code_info |
cc.category_code = ci.category_code | 코드값 조회 |
| 6 | 비즈니스 테이블 | LEFT JOIN (table_relationships 기반) | 실제 데이터 |
2-3. 플로우 데이터 이동 순서
| 단계 | 테이블 | JOIN 관계 | 설명 |
|---|---|---|---|
| 1 | flow_definition |
- | 플로우 정의 |
| 2 | flow_step |
fs.definition_id = fd.id | 스텝 목록 |
| 3 | flow_step_connection |
fsc.from_step_id = fs.id | 연결 관계 |
| 4 | flow_data_mapping |
fdm.from_step_id, to_step_id | 컬럼 매핑 |
| 5 | 소스 테이블 | - | 데이터 조회 |
| 6 | 타겟 테이블 | - | 데이터 INSERT |
| 7 | flow_audit_log |
- | 이동 기록 |
2-4. 배치 실행 순서
| 단계 | 테이블 | JOIN 관계 | 설명 |
|---|---|---|---|
| 1 | batch_configs |
- | 활성 배치 조회 |
| 2 | external_db_connections |
bc.connection_id = edc.id | 외부 DB 정보 |
| 3 | batch_mappings |
bm.batch_config_id = bc.id | 매핑 규칙 |
| 4 | 외부 DB | - | 데이터 조회 |
| 5 | 내부 테이블 | - | 데이터 동기화 |
| 6 | batch_execution_logs |
bel.batch_config_id = bc.id | 실행 로그 |
3. 멀티테넌시 (company_code) 적용 요약
| 테이블 | company_code 필터 | 비고 |
|---|---|---|
user_info |
O | 사용자별 회사 구분 |
menu_info |
O | 회사별 메뉴 |
screen_definitions |
O | 회사별 화면 |
table_type_columns |
O | 회사별 컬럼 정의 |
flow_definition |
O | 회사별 플로우 |
batch_configs |
O | 회사별 배치 |
| 모든 비즈니스 테이블 | O | 자동 필터 적용 |
company_mng |
X (PK) | 회사 마스터 |
company_code = '*': 최고관리자, 모든 회사 데이터 접근 가능
4. 비효율성 분석
상세 내용: DB_INEFFICIENCY_ANALYSIS.md
| 심각도 | 항목 | 권장 조치 |
|---|---|---|
| 🔴 | screen_definitions.layout_metadata |
미사용 컬럼 삭제 |
| 🔴 | user_dept 비정규화 |
정규화 리팩토링 |
| 🟡 | 히스토리 테이블 39개 | 통합 감사 테이블 |
| 🟡 | cascading 미사용 3개 | 테이블 삭제 |
| 🟢 | dept_info.company_name |
선택적 정규화 |