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

362 lines
9.7 KiB
Markdown
Raw Normal View History

2025-11-05 15:23:57 +09:00
# 카테고리 컴포넌트 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. 프론트엔드 테스트