ERP-node/카테고리_컴포넌트_DB_호환성_분석.md

9.7 KiB

카테고리 컴포넌트 DB 호환성 분석 및 수정

작성일: 2025-11-04
상태: 호환성 문제 발견 및 수정 완료


발견된 호환성 문제

1. 테이블명 불일치

예상 테이블명 실제 테이블명 상태
table_columns table_type_columns 불일치
company_info company_mng 불일치

2. 컬럼명 불일치

table_type_columns 테이블

예상 컬럼명 실제 컬럼명 상태
column_label 존재하지 않음 불일치
web_type input_type 불일치
column_order display_order 불일치
company_code 존재하지 않음 불일치

실제 table_type_columns 구조:

- id (integer, PK)
- table_name (varchar(255), NOT NULL)
- column_name (varchar(255), NOT NULL)
- input_type (varchar(50), NOT NULL, DEFAULT 'text')
- detail_settings (text)
- is_nullable (varchar(10), DEFAULT 'Y')
- display_order (integer, DEFAULT 0)
- created_date (timestamp, DEFAULT now())
- updated_date (timestamp, DEFAULT now())

company_mng 테이블

예상 컬럼명 실제 컬럼명 상태
company_code company_code 일치
company_name company_name 일치

실제 company_mng 구조:

- company_code (varchar(32), PK)
- company_name (varchar(64))
- writer (varchar(32))
- regdate (timestamp)
- status (varchar(32))
- business_registration_number (varchar(20))
- representative_name (varchar(100))
- representative_phone (varchar(20))
- email (varchar(255))
- website (varchar(500))
- address (varchar(500))

적용된 수정사항

1. 마이그레이션 파일 수정

파일: db/migrations/036_create_table_column_category_values.sql

변경사항:

-- 변경 전
CONSTRAINT fk_category_value_company FOREIGN KEY (company_code) 
  REFERENCES company_info(company_code),

-- 변경 후
CONSTRAINT fk_category_value_company FOREIGN KEY (company_code) 
  REFERENCES company_mng(company_code),

2. 백엔드 서비스 수정

파일: backend-node/src/services/tableCategoryValueService.ts

변경사항:

// 변경 전
const query = `
  SELECT 
    tc.table_name AS "tableName",
    tc.column_name AS "columnName",
    tc.column_label AS "columnLabel",
    COUNT(cv.value_id) AS "valueCount"
  FROM table_columns tc
  LEFT JOIN table_column_category_values cv 
    ON tc.table_name = cv.table_name 
    AND tc.column_name = cv.column_name
    AND cv.is_active = true
    AND (cv.company_code = $2 OR cv.company_code = '*')
  WHERE tc.table_name = $1
    AND tc.web_type = 'category'
    AND (tc.company_code = $2 OR tc.company_code = '*')
  GROUP BY tc.table_name, tc.column_name, tc.column_label, tc.column_order
  ORDER BY tc.column_order, tc.column_label
`;

// 변경 후
const query = `
  SELECT 
    tc.table_name AS "tableName",
    tc.column_name AS "columnName",
    tc.column_name AS "columnLabel",  -- column_label이 없으므로 column_name 사용
    COUNT(cv.value_id) AS "valueCount"
  FROM table_type_columns tc  -- table_columns → table_type_columns
  LEFT JOIN table_column_category_values cv 
    ON tc.table_name = cv.table_name 
    AND tc.column_name = cv.column_name
    AND cv.is_active = true
    AND (cv.company_code = $2 OR cv.company_code = '*')
  WHERE tc.table_name = $1
    AND tc.input_type = 'category'  -- web_type → input_type
  GROUP BY tc.table_name, tc.column_name, tc.display_order  -- column_order → display_order
  ORDER BY tc.display_order, tc.column_name
`;

주요 차이점 분석

1. 멀티테넌시 방식

예상: 모든 테이블에 company_code 컬럼 존재 실제: table_type_columns에는 company_code 컬럼이 없음

영향:

  • 카테고리 컬럼 조회 시 회사별 필터링 불가
  • 모든 회사가 동일한 테이블 구조 사용
  • 카테고리 만 회사별로 분리됨 (의도된 설계로 보임)

결론: 정상 - 테이블 구조는 공통, 데이터만 회사별 분리

2. 라벨 관리

예상: table_columns.column_label 컬럼에 라벨 저장 실제: column_label 컬럼 없음

해결책:

  • 현재는 column_name을 그대로 라벨로 사용
  • 필요 시 향후 table_labels 테이블과 JOIN하여 라벨 조회 가능

3. 타입 컬럼명

예상: web_type 실제: input_type

결론: 수정 완료 - input_type 사용으로 변경


테스트 계획

1. 마이그레이션 테스트

-- 1. 마이그레이션 실행
\i db/migrations/036_create_table_column_category_values.sql

-- 2. 테이블 생성 확인
SELECT table_name 
FROM information_schema.tables 
WHERE table_name = 'table_column_category_values';

-- 3. 외래키 제약조건 확인
SELECT
    tc.constraint_name,
    tc.table_name,
    kcu.column_name,
    ccu.table_name AS foreign_table_name,
    ccu.column_name AS foreign_column_name
FROM information_schema.table_constraints AS tc
JOIN information_schema.key_column_usage AS kcu
    ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage AS ccu
    ON ccu.constraint_name = tc.constraint_name
WHERE tc.table_name = 'table_column_category_values'
    AND tc.constraint_type = 'FOREIGN KEY';

2. 카테고리 타입 컬럼 생성

먼저 테스트용 테이블에 카테고리 타입 컬럼을 추가해야 합니다:

-- 테스트용 projects 테이블이 없으면 생성
CREATE TABLE IF NOT EXISTS projects (
  id SERIAL PRIMARY KEY,
  project_name VARCHAR(200) NOT NULL,
  project_type VARCHAR(50),  -- 카테고리 타입
  project_status VARCHAR(50), -- 카테고리 타입
  priority VARCHAR(50),       -- 카테고리 타입
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- table_type_columns에 카테고리 타입 등록
INSERT INTO table_type_columns (table_name, column_name, input_type, display_order)
VALUES 
  ('projects', 'project_type', 'category', 1),
  ('projects', 'project_status', 'category', 2),
  ('projects', 'priority', 'category', 3)
ON CONFLICT DO NOTHING;

3. API 테스트

# 1. 카테고리 컬럼 목록 조회
curl -X GET http://localhost:8080/api/table-categories/projects/columns \
  -H "Authorization: Bearer YOUR_TOKEN"

# 예상 응답:
# {
#   "success": true,
#   "data": [
#     {
#       "tableName": "projects",
#       "columnName": "project_type",
#       "columnLabel": "project_type",
#       "valueCount": 4
#     },
#     {
#       "tableName": "projects",
#       "columnName": "project_status",
#       "columnLabel": "project_status",
#       "valueCount": 4
#     },
#     {
#       "tableName": "projects",
#       "columnName": "priority",
#       "columnLabel": "priority",
#       "valueCount": 4
#     }
#   ]
# }

# 2. 카테고리 값 목록 조회
curl -X GET http://localhost:8080/api/table-categories/projects/project_type/values \
  -H "Authorization: Bearer YOUR_TOKEN"

# 예상 응답:
# {
#   "success": true,
#   "data": [
#     {
#       "valueId": 1,
#       "valueCode": "DEV",
#       "valueLabel": "개발",
#       "color": "#3b82f6",
#       ...
#     }
#   ]
# }

추가 고려사항

1. 라벨 표시 개선

현재는 columnName을 그대로 라벨로 사용하지만, 더 나은 사용자 경험을 위해 다음 개선 가능:

옵션 A: table_labels 테이블 활용

SELECT 
  tc.table_name AS "tableName",
  tc.column_name AS "columnName",
  COALESCE(tl.table_label, tc.column_name) AS "columnLabel",
  COUNT(cv.value_id) AS "valueCount"
FROM table_type_columns tc
LEFT JOIN table_labels tl 
  ON tc.table_name = tl.table_name
LEFT JOIN table_column_category_values cv 
  ON tc.table_name = cv.table_name 
  AND tc.column_name = cv.column_name
WHERE tc.table_name = $1
  AND tc.input_type = 'category'
GROUP BY tc.table_name, tc.column_name, tl.table_label, tc.display_order
ORDER BY tc.display_order;

옵션 B: detail_settings에서 라벨 추출

SELECT 
  tc.table_name AS "tableName",
  tc.column_name AS "columnName",
  COALESCE(
    (tc.detail_settings::jsonb->>'label')::text,
    tc.column_name
  ) AS "columnLabel"
FROM table_type_columns tc
WHERE tc.table_name = $1
  AND tc.input_type = 'category';

2. input_type = 'category' 추가

현재 input_type'category' 값이 있는지 확인 필요:

-- 현재 사용 중인 input_type 확인
SELECT DISTINCT input_type 
FROM table_type_columns 
ORDER BY input_type;

만약 'category' 타입이 없다면, 기존 시스템에 추가해야 합니다.


호환성 체크리스트

데이터베이스

  • company_mng 테이블 존재 확인
  • table_type_columns 테이블 구조 확인
  • 외래키 참조 수정 (company_infocompany_mng)
  • input_type = 'category' 추가 여부 확인
  • 테스트 데이터 삽입 확인

백엔드

  • 테이블명 수정 (table_columnstable_type_columns)
  • 컬럼명 수정 (web_typeinput_type)
  • 컬럼명 수정 (column_orderdisplay_order)
  • 라벨 처리 수정 (column_labelcolumn_name)
  • 멀티테넌시 로직 확인

프론트엔드

  • API 응답 구조 확인
  • 라벨 표시 테스트
  • UI 테스트

결론

호환성 문제 수정 완료

주요 변경사항:

  1. company_infocompany_mng (외래키)
  2. table_columnstable_type_columns (테이블명)
  3. web_typeinput_type (컬럼명)
  4. column_orderdisplay_order (컬럼명)
  5. column_labelcolumn_name (라벨 처리)

다음 단계:

  1. 마이그레이션 실행
  2. 테스트용 카테고리 컬럼 생성
  3. API 테스트
  4. 프론트엔드 테스트