# 카테고리 컴포넌트 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 구조**: ```sql - 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 구조**: ```sql - 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` **변경사항**: ```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` **변경사항**: ```typescript // 변경 전 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. 마이그레이션 테스트 ```sql -- 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. 카테고리 타입 컬럼 생성 먼저 테스트용 테이블에 카테고리 타입 컬럼을 추가해야 합니다: ```sql -- 테스트용 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 테스트 ```bash # 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` 테이블 활용 ```sql 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`에서 라벨 추출 ```sql 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'` 값이 있는지 확인 필요: ```sql -- 현재 사용 중인 input_type 확인 SELECT DISTINCT input_type FROM table_type_columns ORDER BY input_type; ``` 만약 `'category'` 타입이 없다면, 기존 시스템에 추가해야 합니다. --- ## 호환성 체크리스트 ### 데이터베이스 - [x] `company_mng` 테이블 존재 확인 - [x] `table_type_columns` 테이블 구조 확인 - [x] 외래키 참조 수정 (`company_info` → `company_mng`) - [ ] `input_type = 'category'` 추가 여부 확인 - [ ] 테스트 데이터 삽입 확인 ### 백엔드 - [x] 테이블명 수정 (`table_columns` → `table_type_columns`) - [x] 컬럼명 수정 (`web_type` → `input_type`) - [x] 컬럼명 수정 (`column_order` → `display_order`) - [x] 라벨 처리 수정 (`column_label` → `column_name`) - [ ] 멀티테넌시 로직 확인 ### 프론트엔드 - [ ] API 응답 구조 확인 - [ ] 라벨 표시 테스트 - [ ] UI 테스트 --- ## 결론 ✅ **호환성 문제 수정 완료** 주요 변경사항: 1. `company_info` → `company_mng` (외래키) 2. `table_columns` → `table_type_columns` (테이블명) 3. `web_type` → `input_type` (컬럼명) 4. `column_order` → `display_order` (컬럼명) 5. `column_label` → `column_name` (라벨 처리) **다음 단계**: 1. 마이그레이션 실행 2. 테스트용 카테고리 컬럼 생성 3. API 테스트 4. 프론트엔드 테스트