682 lines
22 KiB
Markdown
682 lines
22 KiB
Markdown
# DB 비효율성 분석 보고서
|
||
|
||
> 분석일: 2026-01-20 | 분석 기준: 코드 사용 빈도 + DB 설계 원칙 + 유지보수성
|
||
|
||
---
|
||
|
||
## 전체 요약
|
||
|
||
```mermaid
|
||
pie title 비효율성 분류
|
||
"🔴 즉시 개선" : 2
|
||
"🟡 검토 후 개선" : 2
|
||
"🟢 선택적 개선" : 2
|
||
```
|
||
|
||
| 심각도 | 개수 | 항목 |
|
||
|--------|------|------|
|
||
| 🔴 즉시 개선 | 2 | layout_metadata 미사용, user_dept 비정규화 |
|
||
| 🟡 검토 후 개선 | 2 | 히스토리 테이블 39개, cascading 미사용 3개 |
|
||
| 🟢 선택적 개선 | 2 | dept_info 중복, screen 테이블 통합 |
|
||
|
||
---
|
||
|
||
## 🔴 1. screen_definitions.layout_metadata (미사용 컬럼)
|
||
|
||
### 현재 구조
|
||
|
||
```mermaid
|
||
erDiagram
|
||
screen_definitions {
|
||
uuid screen_id PK
|
||
varchar screen_name
|
||
varchar table_name
|
||
jsonb layout_metadata "❌ 미사용"
|
||
}
|
||
|
||
screen_layouts {
|
||
int layout_id PK
|
||
uuid screen_id FK
|
||
jsonb properties "✅ 실제 사용"
|
||
jsonb layout_config "✅ 실제 사용"
|
||
jsonb zones_config "✅ 실제 사용"
|
||
}
|
||
|
||
screen_definitions ||--o{ screen_layouts : "screen_id"
|
||
```
|
||
|
||
### 문제점
|
||
|
||
| 항목 | 상세 |
|
||
|------|------|
|
||
| **중복 저장** | `screen_definitions.layout_metadata`와 `screen_layouts.properties`가 유사 데이터 |
|
||
| **코드 증거** | `screenManagementService.ts:534` - "기존 layout_metadata도 확인 (하위 호환성) - **현재는 사용하지 않음**" |
|
||
| **사용 빈도** | 전체 코드에서 6회만 참조 (대부분 복사/마이그레이션용) |
|
||
| **저장 낭비** | JSONB 컬럼이 NULL 또는 빈 객체로 유지 |
|
||
|
||
### 코드 증거
|
||
|
||
```typescript
|
||
// screenManagementService.ts:534-535
|
||
// 기존 layout_metadata도 확인 (하위 호환성) - 현재는 사용하지 않음
|
||
// 실제 데이터는 screen_layouts 테이블에서 개별적으로 조회해야 함
|
||
```
|
||
|
||
### 영향도 분석
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
A[layout_metadata 삭제] --> B{영향 범위}
|
||
B --> C[menuCopyService.ts]
|
||
B --> D[screenManagementService.ts]
|
||
C --> E[복사 시 해당 필드 제외]
|
||
D --> F[조회 시 해당 필드 제외]
|
||
E --> G[✅ 정상 동작]
|
||
F --> G
|
||
```
|
||
|
||
### 개선 방안
|
||
|
||
```sql
|
||
-- Step 1: 데이터 확인 (실행 전)
|
||
SELECT screen_id, screen_name,
|
||
CASE WHEN layout_metadata IS NULL THEN 'NULL'
|
||
WHEN layout_metadata = '{}' THEN 'EMPTY'
|
||
ELSE 'HAS_DATA' END as status
|
||
FROM screen_definitions
|
||
WHERE layout_metadata IS NOT NULL AND layout_metadata != '{}';
|
||
|
||
-- Step 2: 컬럼 삭제
|
||
ALTER TABLE screen_definitions DROP COLUMN layout_metadata;
|
||
```
|
||
|
||
### 예상 효과
|
||
|
||
- ✅ 스키마 단순화
|
||
- ✅ 데이터 정합성 혼란 제거
|
||
- ✅ 저장 공간 절약 (JSONB 오버헤드 제거)
|
||
|
||
---
|
||
|
||
## 🔴 2. user_dept 비정규화 (중복 저장)
|
||
|
||
### 현재 구조 (비효율)
|
||
|
||
```mermaid
|
||
erDiagram
|
||
user_info {
|
||
varchar user_id PK
|
||
varchar user_name "원본"
|
||
varchar dept_code
|
||
}
|
||
|
||
dept_info {
|
||
varchar dept_code PK
|
||
varchar dept_name "원본"
|
||
varchar company_code
|
||
}
|
||
|
||
user_dept {
|
||
varchar user_id FK
|
||
varchar dept_code FK
|
||
varchar dept_name "❌ 중복 (dept_info에서 JOIN)"
|
||
varchar user_name "❌ 중복 (user_info에서 JOIN)"
|
||
varchar position_name "❓ 별도 테이블 필요?"
|
||
boolean is_primary
|
||
}
|
||
|
||
user_info ||--o{ user_dept : "user_id"
|
||
dept_info ||--o{ user_dept : "dept_code"
|
||
```
|
||
|
||
### 문제점
|
||
|
||
| 항목 | 상세 |
|
||
|------|------|
|
||
| **데이터 불일치 위험** | 부서명 변경 시 `dept_info`만 수정하면 `user_dept.dept_name`은 구 데이터 유지 |
|
||
| **수정 비용** | 부서명 변경 시 모든 `user_dept` 레코드 UPDATE 필요 |
|
||
| **저장 낭비** | 동일 부서의 모든 사용자에게 부서명 반복 저장 |
|
||
| **사용 빈도** | 코드에서 `user_dept.dept_name` 직접 조회는 2회뿐 |
|
||
|
||
### 비정규화로 인한 데이터 불일치 시나리오
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant Admin as 관리자
|
||
participant DI as dept_info
|
||
participant UD as user_dept
|
||
|
||
Admin->>DI: UPDATE dept_name = '개발2팀'<br/>WHERE dept_code = 'DEV'
|
||
Note over DI: dept_name = '개발2팀' ✅
|
||
Note over UD: dept_name = '개발1팀' ❌ 구 데이터
|
||
|
||
Admin->>UD: ⚠️ 수동으로 모든 레코드 UPDATE 필요
|
||
Note over UD: dept_name = '개발2팀' ✅
|
||
```
|
||
|
||
### 권장 구조 (정규화)
|
||
|
||
```mermaid
|
||
erDiagram
|
||
user_info {
|
||
varchar user_id PK
|
||
varchar user_name
|
||
varchar position_name "직위 (여기서 관리)"
|
||
}
|
||
|
||
dept_info {
|
||
varchar dept_code PK
|
||
varchar dept_name
|
||
}
|
||
|
||
user_dept {
|
||
varchar user_id FK
|
||
varchar dept_code FK
|
||
boolean is_primary
|
||
}
|
||
|
||
user_info ||--o{ user_dept : "user_id"
|
||
dept_info ||--o{ user_dept : "dept_code"
|
||
```
|
||
|
||
> **참고**: `position_info` 마스터 테이블은 현재 없음. `user_info.position_name`에 직접 저장 중.
|
||
> 직위 표준화 필요 시 별도 마스터 테이블 생성 검토.
|
||
|
||
### 개선 방안
|
||
|
||
```sql
|
||
-- Step 1: 중복 컬럼 삭제 준비 (조회 쿼리 수정 선행)
|
||
-- 기존: SELECT ud.dept_name FROM user_dept ud
|
||
-- 변경: SELECT di.dept_name FROM user_dept ud JOIN dept_info di ON ud.dept_code = di.dept_code
|
||
|
||
-- Step 2: 중복 컬럼 삭제
|
||
ALTER TABLE user_dept DROP COLUMN dept_name;
|
||
ALTER TABLE user_dept DROP COLUMN user_name;
|
||
-- position_name은 user_info에서 조회하도록 변경
|
||
ALTER TABLE user_dept DROP COLUMN position_name;
|
||
```
|
||
|
||
### 예상 효과
|
||
|
||
- ✅ 데이터 정합성 보장 (Single Source of Truth)
|
||
- ✅ 수정 비용 감소 (한 곳만 수정)
|
||
- ✅ 저장 공간 절약
|
||
|
||
---
|
||
|
||
## 🟡 3. 과도한 히스토리/로그 테이블 (39개)
|
||
|
||
### 현재 구조
|
||
|
||
```mermaid
|
||
graph TB
|
||
subgraph HISTORY["히스토리 테이블 (39개)"]
|
||
H1[authority_master_history]
|
||
H2[carrier_contract_mng_log]
|
||
H3[carrier_mng_log]
|
||
H4[carrier_vehicle_mng_log]
|
||
H5[comm_code_history]
|
||
H6[data_collection_history]
|
||
H7[ddl_execution_log]
|
||
H8[defect_standard_mng_log]
|
||
H9[delivery_history]
|
||
H10[...]
|
||
H11[user_info_history]
|
||
H12[vehicle_location_history]
|
||
H13[work_instruction_log]
|
||
end
|
||
|
||
subgraph PROBLEM["문제점"]
|
||
P1["스키마 변경 시<br/>모든 히스토리 테이블 수정"]
|
||
P2["테이블 수 폭증<br/>(원본 + 히스토리)"]
|
||
P3["관리 복잡도 증가"]
|
||
end
|
||
|
||
HISTORY --> PROBLEM
|
||
```
|
||
|
||
### 현재 테이블 목록 (39개)
|
||
|
||
| 카테고리 | 테이블명 | 용도 |
|
||
|----------|----------|------|
|
||
| 시스템 | authority_master_history | 권한 변경 이력 |
|
||
| 시스템 | user_info_history | 사용자 정보 이력 |
|
||
| 시스템 | dept_info_history | 부서 정보 이력 |
|
||
| 시스템 | login_access_log | 로그인 기록 |
|
||
| 시스템 | ddl_execution_log | DDL 실행 기록 |
|
||
| 물류 | carrier_mng_log | 운송사 변경 이력 |
|
||
| 물류 | carrier_contract_mng_log | 운송 계약 이력 |
|
||
| 물류 | carrier_vehicle_mng_log | 운송 차량 이력 |
|
||
| 물류 | delivery_history | 배송 이력 |
|
||
| 물류 | delivery_route_mng_log | 배송 경로 이력 |
|
||
| 물류 | logistics_cost_mng_log | 물류 비용 이력 |
|
||
| 물류 | vehicle_location_history | 차량 위치 이력 |
|
||
| 설비 | equipment_mng_log | 설비 변경 이력 |
|
||
| 설비 | equipment_consumable_log | 설비 소모품 이력 |
|
||
| 설비 | equipment_inspection_item_log | 설비 점검 이력 |
|
||
| 설비 | dtg_maintenance_history | DTG 유지보수 이력 |
|
||
| 설비 | dtg_management_log | DTG 관리 이력 |
|
||
| 생산 | defect_standard_mng_log | 불량 기준 이력 |
|
||
| 생산 | work_instruction_log | 작업 지시 이력 |
|
||
| 생산 | work_instruction_detail_log | 작업 지시 상세 이력 |
|
||
| 생산 | safety_inspections_log | 안전 점검 이력 |
|
||
| 영업 | supplier_mng_log | 공급사 이력 |
|
||
| 영업 | sales_order_detail_log | 판매 주문 이력 |
|
||
| 기타 | flow_audit_log | 플로우 감사 로그 ✅ 필요 |
|
||
| 기타 | flow_integration_log | 플로우 통합 로그 ✅ 필요 |
|
||
| 기타 | mail_log | 메일 발송 로그 ✅ 필요 |
|
||
| ... | ... | ... |
|
||
|
||
### 문제점 상세
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
A[원본 테이블 컬럼 추가] --> B[히스토리 테이블도 수정 필요]
|
||
B --> C{수동 작업}
|
||
C -->|잊음| D[❌ 스키마 불일치]
|
||
C -->|수동 수정| E[⚠️ 추가 작업 비용]
|
||
|
||
F[테이블 39개 × 평균 15컬럼] --> G[약 585개 컬럼 관리]
|
||
```
|
||
|
||
### 권장 구조 (통합 감사 테이블)
|
||
|
||
```mermaid
|
||
erDiagram
|
||
audit_log {
|
||
bigint id PK
|
||
varchar table_name "원본 테이블명"
|
||
varchar record_id "레코드 식별자"
|
||
varchar action "INSERT|UPDATE|DELETE"
|
||
jsonb old_data "변경 전 전체 데이터"
|
||
jsonb new_data "변경 후 전체 데이터"
|
||
jsonb changed_fields "변경된 필드만"
|
||
varchar changed_by "변경자"
|
||
inet ip_address "IP 주소"
|
||
timestamp changed_at "변경 시각"
|
||
varchar company_code "회사 코드"
|
||
}
|
||
```
|
||
|
||
### 개선 방안
|
||
|
||
```sql
|
||
-- 통합 감사 테이블 생성
|
||
CREATE TABLE audit_log (
|
||
id bigserial PRIMARY KEY,
|
||
table_name varchar(100) NOT NULL,
|
||
record_id varchar(100) NOT NULL,
|
||
action varchar(10) NOT NULL CHECK (action IN ('INSERT', 'UPDATE', 'DELETE')),
|
||
old_data jsonb,
|
||
new_data jsonb,
|
||
changed_fields jsonb, -- UPDATE 시 변경된 필드만
|
||
changed_by varchar(50),
|
||
ip_address inet,
|
||
changed_at timestamp DEFAULT now(),
|
||
company_code varchar(20)
|
||
);
|
||
|
||
-- 인덱스
|
||
CREATE INDEX idx_audit_log_table ON audit_log(table_name);
|
||
CREATE INDEX idx_audit_log_record ON audit_log(table_name, record_id);
|
||
CREATE INDEX idx_audit_log_time ON audit_log(changed_at);
|
||
CREATE INDEX idx_audit_log_company ON audit_log(company_code);
|
||
|
||
-- PostgreSQL 트리거 함수 (자동 감사)
|
||
CREATE OR REPLACE FUNCTION audit_trigger_func()
|
||
RETURNS TRIGGER AS $$
|
||
BEGIN
|
||
IF TG_OP = 'INSERT' THEN
|
||
INSERT INTO audit_log (table_name, record_id, action, new_data, changed_by, changed_at)
|
||
VALUES (TG_TABLE_NAME, NEW.id::text, 'INSERT', row_to_json(NEW)::jsonb,
|
||
current_setting('app.current_user', true), now());
|
||
RETURN NEW;
|
||
ELSIF TG_OP = 'UPDATE' THEN
|
||
INSERT INTO audit_log (table_name, record_id, action, old_data, new_data, changed_by, changed_at)
|
||
VALUES (TG_TABLE_NAME, NEW.id::text, 'UPDATE', row_to_json(OLD)::jsonb,
|
||
row_to_json(NEW)::jsonb, current_setting('app.current_user', true), now());
|
||
RETURN NEW;
|
||
ELSIF TG_OP = 'DELETE' THEN
|
||
INSERT INTO audit_log (table_name, record_id, action, old_data, changed_by, changed_at)
|
||
VALUES (TG_TABLE_NAME, OLD.id::text, 'DELETE', row_to_json(OLD)::jsonb,
|
||
current_setting('app.current_user', true), now());
|
||
RETURN OLD;
|
||
END IF;
|
||
END;
|
||
$$ LANGUAGE plpgsql;
|
||
```
|
||
|
||
### 예상 효과
|
||
|
||
- ✅ 테이블 수 39개 → 1개로 감소
|
||
- ✅ 스키마 변경 시 히스토리 수정 불필요 (JSONB 저장)
|
||
- ✅ 통합 조회/분석 용이
|
||
- ⚠️ 주의: 기존 히스토리 데이터 마이그레이션 필요
|
||
|
||
---
|
||
|
||
## 🟡 4. Cascading 미사용 테이블 (3개)
|
||
|
||
### 현재 구조
|
||
|
||
```mermaid
|
||
graph TB
|
||
subgraph USED["✅ 사용 중 (9개)"]
|
||
U1[cascading_hierarchy_group]
|
||
U2[cascading_hierarchy_level]
|
||
U3[cascading_auto_fill_group]
|
||
U4[cascading_auto_fill_mapping]
|
||
U5[cascading_relation]
|
||
U6[cascading_condition]
|
||
U7[cascading_mutual_exclusion]
|
||
U8[category_value_cascading_group]
|
||
U9[category_value_cascading_mapping]
|
||
end
|
||
|
||
subgraph UNUSED["❌ 미사용 (3개)"]
|
||
X1[cascading_multi_parent]
|
||
X2[cascading_multi_parent_source]
|
||
X3[cascading_reverse_lookup]
|
||
end
|
||
|
||
UNUSED --> DELETE[삭제 검토]
|
||
```
|
||
|
||
### 코드 사용 분석
|
||
|
||
| 테이블 | 코드 참조 | 판정 |
|
||
|--------|----------|------|
|
||
| `cascading_hierarchy_group` | 다수 | ✅ 유지 |
|
||
| `cascading_hierarchy_level` | 다수 | ✅ 유지 |
|
||
| `cascading_auto_fill_group` | 다수 | ✅ 유지 |
|
||
| `cascading_auto_fill_mapping` | 다수 | ✅ 유지 |
|
||
| `cascading_relation` | 다수 | ✅ 유지 |
|
||
| `cascading_condition` | 7회 | ⚠️ 검토 |
|
||
| `cascading_mutual_exclusion` | 소수 | ⚠️ 검토 |
|
||
| `cascading_multi_parent` | **0회** | ❌ 삭제 |
|
||
| `cascading_multi_parent_source` | **0회** | ❌ 삭제 |
|
||
| `cascading_reverse_lookup` | **0회** | ❌ 삭제 |
|
||
| `category_value_cascading_group` | 다수 | ✅ 유지 |
|
||
| `category_value_cascading_mapping` | 다수 | ✅ 유지 |
|
||
|
||
### 개선 방안
|
||
|
||
```sql
|
||
-- Step 1: 데이터 확인
|
||
SELECT 'cascading_multi_parent' as tbl, count(*) FROM cascading_multi_parent
|
||
UNION ALL
|
||
SELECT 'cascading_multi_parent_source', count(*) FROM cascading_multi_parent_source
|
||
UNION ALL
|
||
SELECT 'cascading_reverse_lookup', count(*) FROM cascading_reverse_lookup;
|
||
|
||
-- Step 2: 데이터 없으면 삭제
|
||
DROP TABLE IF EXISTS cascading_multi_parent_source; -- 자식 먼저
|
||
DROP TABLE IF EXISTS cascading_multi_parent;
|
||
DROP TABLE IF EXISTS cascading_reverse_lookup;
|
||
```
|
||
|
||
---
|
||
|
||
## 🟢 5. dept_info.company_name 중복
|
||
|
||
### 현재 구조
|
||
|
||
```mermaid
|
||
erDiagram
|
||
company_mng {
|
||
varchar company_code PK
|
||
varchar company_name "원본"
|
||
}
|
||
|
||
dept_info {
|
||
varchar dept_code PK
|
||
varchar company_code FK
|
||
varchar company_name "❌ 중복"
|
||
varchar dept_name
|
||
}
|
||
|
||
company_mng ||--o{ dept_info : "company_code"
|
||
```
|
||
|
||
### 문제점
|
||
|
||
- `dept_info.company_name`은 `company_mng.company_name`과 동일한 값
|
||
- 회사명 변경 시 두 테이블 모두 수정 필요
|
||
|
||
### 개선 방안
|
||
|
||
```sql
|
||
-- 중복 컬럼 삭제
|
||
ALTER TABLE dept_info DROP COLUMN company_name;
|
||
|
||
-- 조회 시 JOIN 사용
|
||
SELECT di.*, cm.company_name
|
||
FROM dept_info di
|
||
JOIN company_mng cm ON di.company_code = cm.company_code;
|
||
```
|
||
|
||
---
|
||
|
||
## 🟢 6. screen 관련 테이블 통합 가능성
|
||
|
||
### 현재 구조
|
||
|
||
```mermaid
|
||
erDiagram
|
||
screen_data_flows {
|
||
int id PK
|
||
uuid source_screen_id
|
||
uuid target_screen_id
|
||
varchar flow_type
|
||
}
|
||
|
||
screen_table_relations {
|
||
int id PK
|
||
uuid screen_id
|
||
varchar table_name
|
||
varchar relation_type
|
||
}
|
||
|
||
screen_field_joins {
|
||
int id PK
|
||
uuid screen_id
|
||
varchar source_field
|
||
varchar target_field
|
||
}
|
||
```
|
||
|
||
### 분석
|
||
|
||
| 테이블 | 용도 | 사용 빈도 |
|
||
|--------|------|----------|
|
||
| `screen_data_flows` | 화면 간 데이터 흐름 | 15회 (screenGroupController) |
|
||
| `screen_table_relations` | 화면-테이블 관계 | 일부 |
|
||
| `screen_field_joins` | 필드 조인 설정 | 일부 |
|
||
|
||
### 통합 가능성
|
||
|
||
- 세 테이블 모두 "화면 간 관계" 정의
|
||
- 하나의 `screen_relations` 테이블로 통합 가능
|
||
- **단, 현재 사용 중이므로 신중한 검토 필요**
|
||
|
||
---
|
||
|
||
## 실행 계획
|
||
|
||
```mermaid
|
||
gantt
|
||
title DB 개선 실행 계획
|
||
dateFormat YYYY-MM-DD
|
||
section 즉시 실행
|
||
layout_metadata 컬럼 삭제 :a1, 2026-01-21, 1d
|
||
미사용 cascading 테이블 삭제 :a2, 2026-01-21, 1d
|
||
section 단기 (1주)
|
||
user_dept 정규화 :b1, 2026-01-22, 5d
|
||
dept_info.company_name 삭제 :b2, 2026-01-22, 2d
|
||
section 장기 (1개월)
|
||
히스토리 테이블 통합 설계 :c1, 2026-01-27, 7d
|
||
히스토리 마이그레이션 :c2, after c1, 14d
|
||
```
|
||
|
||
---
|
||
|
||
## 즉시 실행 가능 SQL 스크립트
|
||
|
||
```sql
|
||
-- ============================================
|
||
-- 🔴 즉시 개선 항목
|
||
-- ============================================
|
||
|
||
-- 1. screen_definitions.layout_metadata 삭제
|
||
BEGIN;
|
||
-- 백업 (선택)
|
||
-- CREATE TABLE screen_definitions_backup AS SELECT * FROM screen_definitions;
|
||
ALTER TABLE screen_definitions DROP COLUMN IF EXISTS layout_metadata;
|
||
COMMIT;
|
||
|
||
-- 2. 미사용 cascading 테이블 삭제
|
||
BEGIN;
|
||
DROP TABLE IF EXISTS cascading_multi_parent_source;
|
||
DROP TABLE IF EXISTS cascading_multi_parent;
|
||
DROP TABLE IF EXISTS cascading_reverse_lookup;
|
||
COMMIT;
|
||
|
||
-- 3. dept_info.company_name 삭제 (선택)
|
||
BEGIN;
|
||
ALTER TABLE dept_info DROP COLUMN IF EXISTS company_name;
|
||
COMMIT;
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 채번-카테고리 시스템 (범용화 완료)
|
||
|
||
### 현황
|
||
|
||
| 테이블 | 건수 | menu_objid | 상태 |
|
||
|--------|------|------------|------|
|
||
| `numbering_rules_test` | 108건 | ❌ 없음 | ✅ 범용화 완료 |
|
||
| `numbering_rule_parts_test` | 267건 | ❌ 없음 | ✅ 범용화 완료 |
|
||
| `category_values_test` | 3건 | ❌ 없음 | ✅ 범용화 완료 |
|
||
| `category_column_mapping_test` | 0건 | ❌ 없음 | 미사용 |
|
||
|
||
### 연결관계도
|
||
|
||
```mermaid
|
||
erDiagram
|
||
numbering_rules_test {
|
||
varchar rule_id PK "규칙 ID"
|
||
varchar rule_name "규칙명"
|
||
varchar table_name "테이블명"
|
||
varchar column_name "컬럼명"
|
||
varchar category_column "카테고리 컬럼"
|
||
int category_value_id FK "카테고리 값 ID"
|
||
varchar separator "구분자"
|
||
varchar reset_period "리셋 주기"
|
||
int current_sequence "현재 시퀀스"
|
||
date last_generated_date "마지막 생성일"
|
||
varchar company_code "회사코드"
|
||
}
|
||
|
||
numbering_rule_parts_test {
|
||
serial id PK "파트 ID"
|
||
varchar rule_id FK "규칙 ID"
|
||
int part_order "순서 (1-6)"
|
||
varchar part_type "유형"
|
||
varchar generation_method "생성방식"
|
||
jsonb auto_config "자동설정"
|
||
jsonb manual_config "수동설정"
|
||
varchar company_code "회사코드"
|
||
}
|
||
|
||
category_values_test {
|
||
serial value_id PK "값 ID"
|
||
varchar table_name "테이블명"
|
||
varchar column_name "컬럼명"
|
||
varchar value_code "코드"
|
||
varchar value_label "라벨"
|
||
int value_order "정렬순서"
|
||
int parent_value_id FK "부모 (계층)"
|
||
int depth "깊이"
|
||
varchar path "경로"
|
||
varchar color "색상"
|
||
varchar icon "아이콘"
|
||
bool is_active "활성"
|
||
bool is_default "기본값"
|
||
varchar company_code "회사코드"
|
||
}
|
||
|
||
numbering_rules_test ||--o{ numbering_rule_parts_test : "1:N"
|
||
numbering_rules_test }o--o| category_values_test : "카테고리 조건"
|
||
category_values_test ||--o{ category_values_test : "계층구조"
|
||
```
|
||
|
||
### 데이터 흐름
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────────────┐
|
||
│ 범용 채번 시스템 (menu_objid 제거 완료) │
|
||
├──────────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ ┌────────────────────┐ ┌─────────────────────────┐ │
|
||
│ │ category_values │ │ numbering_rules_test │ │
|
||
│ │ _test (3건) │◄─────────────│ (108건) │ │
|
||
│ ├────────────────────┤ FK ├─────────────────────────┤ │
|
||
│ │ table + column │ 조인 │ table + column 기준 │ │
|
||
│ │ 기준 카테고리 값 │ │ category_value_id로 │ │
|
||
│ │ │ │ 카테고리별 규칙 구분 │ │
|
||
│ └────────────────────┘ └───────────┬─────────────┘ │
|
||
│ │ │
|
||
│ │ 1:N │
|
||
│ ▼ │
|
||
│ ┌─────────────────────────┐ │
|
||
│ │ numbering_rule_parts │ │
|
||
│ │ _test (267건) │ │
|
||
│ ├─────────────────────────┤ │
|
||
│ │ 파트별 설정 (최대 6개) │ │
|
||
│ │ - prefix, sequence │ │
|
||
│ │ - date, year, month │ │
|
||
│ │ - custom │ │
|
||
│ └─────────────────────────┘ │
|
||
│ │
|
||
└──────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 조회 흐름
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant UI as 사용자 화면
|
||
participant CV as category_values_test
|
||
participant NR as numbering_rules_test
|
||
participant NRP as numbering_rule_parts_test
|
||
|
||
UI->>CV: 1. 카테고리 값 조회<br/>(table_name + column_name)
|
||
CV-->>UI: 카테고리 목록 반환
|
||
|
||
UI->>NR: 2. 채번 규칙 조회<br/>(table + column + category_value_id)
|
||
NR-->>UI: 규칙 반환
|
||
|
||
UI->>NRP: 3. 채번 파트 조회<br/>(rule_id)
|
||
NRP-->>UI: 파트 목록 반환 (1-6개)
|
||
|
||
UI->>UI: 4. 파트 조합하여 채번 생성<br/>"PREFIX-2026-0001"
|
||
```
|
||
|
||
### 범용화 전/후 비교
|
||
|
||
| 항목 | 기존 (menu_objid 의존) | 현재 (범용화) |
|
||
|------|------------------------|---------------|
|
||
| **식별 기준** | menu_objid (메뉴별) | table_name + column_name |
|
||
| **공유 범위** | 메뉴 단위 | 테이블 단위 (여러 메뉴에서 공유) |
|
||
| **중복 규칙** | 같은 테이블도 메뉴마다 별도 | 하나의 규칙을 공유 |
|
||
| **유지보수** | 메뉴 변경 시 규칙도 수정 | 테이블 기준으로 독립 |
|
||
|
||
---
|
||
|
||
## 참고
|
||
|
||
- 분석 대상: `/Users/gbpark/ERP-node/backend-node/src/**/*.ts`
|
||
- 스키마 파일: `/Users/gbpark/ERP-node/db/plm_schema_20260120.sql`
|
||
- 관련 문서: `DB_STRUCTURE_DIAGRAM.md`, `DB_CLEANUP_LOG_20260120.md`
|