ERP-node/docs/COLUMN_LABELS_MIGRATION_ANA...

15 KiB

column_labels 테이블 제거 영향 분석

개요

현재 시스템은 컬럼 메타데이터를 두 개의 테이블에서 관리하고 있습니다:

  • column_labels: 레거시 테이블 (회사코드 없음, 공통 데이터)
  • table_type_columns: 새 테이블 (회사코드 있음, 멀티테넌시 지원)

이 문서는 column_labels 테이블을 제거하고 table_type_columns로 통합할 때의 영향을 분석합니다.


1. 두 테이블 스키마 비교

column_labels (레거시)

컬럼 타입 설명
id INTEGER PK
table_name VARCHAR 테이블명
column_name VARCHAR 컬럼명
column_label VARCHAR 한글 라벨
web_type VARCHAR 레거시 (사용 안 함)
input_type VARCHAR 입력 타입
detail_settings TEXT 상세 설정 (JSON)
description TEXT 설명
display_order INTEGER 표시 순서
is_visible BOOLEAN 표시 여부
code_category VARCHAR 코드 카테고리
code_value VARCHAR 코드 값
reference_table VARCHAR 참조 테이블
reference_column VARCHAR 참조 컬럼
display_column VARCHAR 표시 컬럼
created_date TIMESTAMP 생성일
updated_date TIMESTAMP 수정일

특징: company_code 없음 → 멀티테넌시 불가

table_type_columns (신규)

컬럼 타입 설명
id INTEGER PK
table_name VARCHAR 테이블명
column_name VARCHAR 컬럼명
input_type VARCHAR 입력 타입
detail_settings TEXT 상세 설정 (JSON)
is_nullable VARCHAR NULL 허용
display_order INTEGER 표시 순서
company_code VARCHAR 회사 코드
created_date TIMESTAMP 생성일
updated_date TIMESTAMP 수정일

특징: company_code 있음 → 멀티테넌시 지원

누락된 컬럼 (table_type_columns에 추가 필요)

컬럼 용도
column_label 한글 라벨
description 설명
is_visible 표시 여부
code_category 코드 카테고리
code_value 코드 값
reference_table 참조 테이블 (엔티티)
reference_column 참조 컬럼
display_column 표시 컬럼

2. 영향 받는 파일 목록

백엔드 파일 (16개, 87회 참조)

파일 참조 횟수 영향도 용도
tableManagementService.ts 21회 🔴 매우 높음 컬럼 조회/저장/업데이트 핵심 로직
screenGroupController.ts 13회 🟡 중간 화면 그룹/메뉴 동기화 시 라벨 조회
masterDetailExcelService.ts 7회 🟡 중간 엑셀 다운로드 시 엔티티 관계 조회
ddlExecutionService.ts 7회 🟡 중간 테이블 생성/삭제 시 메타데이터 등록
tableManagementController.ts 7회 🟡 중간 API 엔드포인트
screenManagementService.ts 5회 🔴 높음 화면에서 컬럼 라벨 조회
entityJoinService.ts 4회 🔴 높음 엔티티 조인 관계 감지
entityReferenceController.ts 4회 🟡 중간 엔티티 참조 데이터 조회
adminController.ts 3회 🟢 낮음 엑셀 업로드 컬럼 매핑
dataService.ts 3회 🟢 낮음 컬럼 라벨 조회
flowController.ts 3회 🟢 낮음 플로우 컬럼 라벨 조회
categoryTreeService.ts 1회 🟢 낮음 카테고리 라벨 조회
tableManagementRoutes.ts 1회 🟢 낮음 라우트 주석
multiConnectionQueryService.ts 1회 🟢 낮음 멀티 연결 쿼리
migrate-input-type-to-web-type.ts 6회 🟢 낮음 마이그레이션 스크립트
types/ddl.ts 1회 🟢 낮음 타입 정의

프론트엔드 파일 (15개, 20회 참조)

파일 참조 횟수 영향도 용도
UnifiedRepeater.tsx 3회 🟢 낮음 타입 주석
ScreenDesigner.tsx 2회 🟢 낮음 타입 주석
ButtonConfigPanel.tsx 2회 🟢 낮음 타입 주석
ScreenRelationFlow.tsx 2회 🟢 낮음 타입 주석
buttonActions.ts 1회 🟢 낮음 주석
webTypeMapping.ts 1회 🟢 낮음 주석
screenGroup.ts 1회 🟢 낮음 API 타입
tableManagement.ts 1회 🟢 낮음 API 타입
TableSettingModal.tsx 1회 🟢 낮음 주석
tableSchema.ts 1회 🟢 낮음 타입
types/ddl.ts 1회 🟢 낮음 타입 정의
ControlConditionStep.tsx 1회 🟢 낮음 주석
ActionConditionBuilder.tsx 1회 🟢 낮음 주석
WebTypeInput.tsx 1회 🟢 낮음 주석
types/multiConnection.ts 1회 🟢 낮음 타입

3. 주요 사용 패턴 분석

패턴 1: 컬럼 조회 (가장 많음)

-- 현재 방식: column_labels + table_type_columns 조인
SELECT 
  c.column_name,
  COALESCE(cl.column_label, c.column_name) as "displayName",
  COALESCE(ttc.input_type, cl.input_type, 'text') as "inputType",
  COALESCE(ttc.detail_settings, cl.detail_settings) as "detailSettings",
  cl.reference_table as "referenceTable"  -- ❌ 문제: ttc의 detailSettings 무시
FROM information_schema.columns c
LEFT JOIN column_labels cl ON c.table_name = cl.table_name AND c.column_name = cl.column_name
LEFT JOIN table_type_columns ttc ON c.table_name = ttc.table_name 
  AND c.column_name = ttc.column_name 
  AND ttc.company_code = $company_code

문제점: referenceTablecolumn_labels에서만 조회됨 → 회사별 엔티티 설정 무시

패턴 2: 컬럼 저장 (이중 저장)

// 현재: 두 테이블에 모두 저장
await query(`INSERT INTO column_labels (...) VALUES (...) ON CONFLICT ... DO UPDATE ...`);
await this.updateColumnInputType(...); // table_type_columns에도 저장

문제점: 데이터 불일치 가능성, 유지보수 어려움

패턴 3: 엔티티 관계 조회

SELECT column_name, reference_table, reference_column
FROM column_labels
WHERE table_name = $1 AND input_type = 'entity'

문제점: 회사별 엔티티 설정 무시 (column_labels에 company_code 없음)


4. 마이그레이션 계획

Phase 1: 스키마 확장 (table_type_columns)

-- 마이그레이션 파일: 044_extend_table_type_columns.sql

-- 1. 누락된 컬럼 추가
ALTER TABLE table_type_columns ADD COLUMN IF NOT EXISTS column_label VARCHAR(200);
ALTER TABLE table_type_columns ADD COLUMN IF NOT EXISTS description TEXT;
ALTER TABLE table_type_columns ADD COLUMN IF NOT EXISTS is_visible BOOLEAN DEFAULT true;
ALTER TABLE table_type_columns ADD COLUMN IF NOT EXISTS code_category VARCHAR(100);
ALTER TABLE table_type_columns ADD COLUMN IF NOT EXISTS code_value VARCHAR(100);
ALTER TABLE table_type_columns ADD COLUMN IF NOT EXISTS reference_table VARCHAR(100);
ALTER TABLE table_type_columns ADD COLUMN IF NOT EXISTS reference_column VARCHAR(100);
ALTER TABLE table_type_columns ADD COLUMN IF NOT EXISTS display_column VARCHAR(100);

-- 2. 인덱스 추가
CREATE INDEX IF NOT EXISTS idx_ttc_reference_table ON table_type_columns(reference_table);
CREATE INDEX IF NOT EXISTS idx_ttc_input_type ON table_type_columns(input_type);

Phase 2: 데이터 마이그레이션

-- column_labels 데이터를 table_type_columns로 이관 (company_code = '*' 로 공통 데이터)
INSERT INTO table_type_columns (
  table_name, column_name, input_type, detail_settings, 
  column_label, description, is_visible, code_category, code_value,
  reference_table, reference_column, display_column, display_order,
  company_code, created_date, updated_date
)
SELECT 
  table_name, column_name, 
  COALESCE(input_type, 'text'), 
  detail_settings,
  column_label, 
  description, 
  COALESCE(is_visible, true), 
  code_category, 
  code_value,
  reference_table, 
  reference_column, 
  display_column, 
  display_order,
  '*',  -- 공통 데이터 (회사별 설정 없으면 폴백)
  COALESCE(created_date, NOW()), 
  COALESCE(updated_date, NOW())
FROM column_labels
ON CONFLICT (table_name, column_name, company_code) 
DO UPDATE SET
  column_label = COALESCE(EXCLUDED.column_label, table_type_columns.column_label),
  description = COALESCE(EXCLUDED.description, table_type_columns.description),
  reference_table = COALESCE(EXCLUDED.reference_table, table_type_columns.reference_table),
  reference_column = COALESCE(EXCLUDED.reference_column, table_type_columns.reference_column),
  display_column = COALESCE(EXCLUDED.display_column, table_type_columns.display_column),
  updated_date = NOW();

Phase 3: 코드 수정

3.1 조회 쿼리 변경 패턴

-- 변경 전
SELECT ... FROM column_labels WHERE table_name = $1

-- 변경 후 (회사코드 폴백 포함)
SELECT * FROM (
  SELECT *, 
    ROW_NUMBER() OVER (
      PARTITION BY table_name, column_name 
      ORDER BY CASE WHEN company_code = $company_code THEN 0 ELSE 1 END
    ) as rn
  FROM table_type_columns
  WHERE table_name = $1 
    AND company_code IN ($company_code, '*')
) ranked
WHERE rn = 1

3.2 저장 쿼리 변경 패턴

-- 변경 전: 두 테이블에 저장
INSERT INTO column_labels (...) ...;
INSERT INTO table_type_columns (...) ...;

-- 변경 후: 하나의 테이블만
INSERT INTO table_type_columns (
  table_name, column_name, input_type, detail_settings,
  column_label, description, is_visible, code_category, code_value,
  reference_table, reference_column, display_column, display_order,
  company_code, created_date, updated_date
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, NOW(), NOW())
ON CONFLICT (table_name, column_name, company_code) 
DO UPDATE SET ...;

Phase 4: 레거시 코드 정리

  1. column_labels 관련 INSERT/UPDATE 제거
  2. column_labels LEFT JOIN을 table_type_columns로 변경
  3. 프론트엔드 주석/타입 업데이트

Phase 5: 테이블 삭제 (최종)

-- 모든 코드 마이그레이션 완료 후
DROP TABLE IF EXISTS column_labels;

5. 수정해야 할 파일 상세

🔴 우선순위 1: 핵심 서비스 (3개)

tableManagementService.ts (21개 쿼리)

함수 라인 수정 내용
checkCodeTypeColumn 30-36 column_labels → table_type_columns
getColumnList 215-218, 257-258 JOIN 변경 + referenceTable 추출
updateColumnSettings 460-494 column_labels INSERT 제거
getColumnLabels 670-673 table_type_columns로 변경
setColumnInputType 735-740 column_labels INSERT 제거
getFileColumns 1288 table_type_columns로 변경
getColumnMetaInfo 1956 table_type_columns로 변경
findEntityRelation 3579-3590 table_type_columns로 변경
upsertColumnLabel 3723 table_type_columns로 변경
getColumnInputTypes 4129 이미 table_type_columns 사용 중
detectEntityRelation 4810, 4838 table_type_columns로 변경

screenManagementService.ts (5개 쿼리)

함수 라인 수정 내용
getTableColumns 1279 table_type_columns로 변경
getTableColumns 1334 라벨 추가 로직 수정
getColumnInfo 2083 table_type_columns로 변경
saveColumnSettings 2104 table_type_columns로 변경

entityJoinService.ts (4개 쿼리)

함수 라인 수정 내용
detectEntityColumns 36 table_type_columns로 변경
getTableColumns 755 table_type_columns로 변경

🟡 우선순위 2: 보조 서비스 (5개)

파일 수정 쿼리 수 수정 내용
screenGroupController.ts 13개 라벨 조회, FK 조회 쿼리 변경
masterDetailExcelService.ts 7개 엔티티 관계 조회 변경
ddlExecutionService.ts 7개 테이블 생성 시 메타데이터 등록 변경
entityReferenceController.ts 4개 참조 데이터 조회 변경
adminController.ts 3개 스키마 조회 변경

🟢 우선순위 3: 기타 (8개)

파일 수정 내용
dataService.ts 라벨 조회 변경
flowController.ts 라벨 조회 변경
categoryTreeService.ts JOIN 변경
tableManagementRoutes.ts 주석 수정
multiConnectionQueryService.ts 주석/타입 수정
migrate-input-type-to-web-type.ts 마이그레이션 스크립트 (이미 실행됨, 삭제 가능)
types/ddl.ts 타입 정의 수정
프론트엔드 15개 파일 주석/타입 수정

6. 예상 작업 시간

단계 작업 예상 시간
Phase 1 스키마 확장 (마이그레이션 SQL) 30분
Phase 2 데이터 마이그레이션 (SQL) 30분
Phase 3.1 tableManagementService.ts 수정 2시간
Phase 3.2 screenManagementService.ts 수정 1시간
Phase 3.3 entityJoinService.ts 수정 30분
Phase 3.4 보조 서비스 5개 수정 2시간
Phase 3.5 기타 파일 8개 수정 1시간
Phase 4 테스트 및 검증 2시간
Phase 5 column_labels 삭제 10분
합계 약 10시간

7. 리스크 및 주의사항

높은 리스크

  1. 데이터 불일치: 마이그레이션 중 column_labels와 table_type_columns 데이터 충돌 가능
  2. 회사코드 폴백 로직 복잡성: 모든 조회에 company_code IN ($code, '*') + 우선순위 필요
  3. 기존 운영 데이터 손실: 마이그레이션 실수 시 column_labels 데이터 유실 가능

완화 방안

  1. 단계적 마이그레이션: column_labels는 당분간 유지, 조회만 table_type_columns 우선으로 변경
  2. 폴백 헬퍼 함수: 회사코드 폴백 로직을 공통 함수로 추출
  3. 백업 필수: 마이그레이션 전 column_labels 전체 백업

8. 결론

현재 문제점

  1. 이중 관리: 같은 데이터가 두 테이블에 저장됨
  2. 멀티테넌시 불완전: referenceTable 등이 column_labels에서만 조회되어 회사별 설정 무시
  3. 유지보수 어려움: 변경 시 두 곳 모두 수정 필요

권장 방향

장기적으로 table_type_columns로 통합 권장

하지만 작업량이 상당하므로:

  1. 단기 (즉시): 조회 시 detailSettings에서 referenceTable 우선 추출하도록 수정
  2. 중기 (1-2주): table_type_columns 스키마 확장 + 데이터 마이그레이션
  3. 장기 (한 달): 모든 코드 수정 후 column_labels 제거

참고 자료

  • table_type_columns 관련 마이그레이션: db/migrations/030_create_table_type_columns.sql
  • 테이블 타입 관리 UI: frontend/app/(main)/admin/systemMng/tableMngList/page.tsx
  • 컬럼 조회 핵심 로직: backend-node/src/services/tableManagementService.ts:getColumnList()