ERP-node/docs/DB_ARCHITECTURE_ANALYSIS.md

2189 lines
59 KiB
Markdown
Raw Permalink Normal View History

# WACE ERP 데이터베이스 아키텍처 분석 보고서
> 📅 작성일: 2026-01-20
> 🎯 목적: WACE ERP 시스템 전체 워크플로우 문서화를 위한 DB 구조 분석
> 📊 DB 엔진: PostgreSQL 16.8
---
## 📋 목차
1. [개요](#1-개요)
2. [전체 테이블 목록](#2-전체-테이블-목록)
3. [멀티테넌시 아키텍처](#3-멀티테넌시-아키텍처)
4. [핵심 시스템 테이블](#4-핵심-시스템-테이블)
5. [메타데이터 관리 시스템](#5-메타데이터-관리-시스템)
6. [화면 관리 시스템](#6-화면-관리-시스템)
7. [비즈니스 도메인별 테이블](#7-비즈니스-도메인별-테이블)
8. [플로우 및 데이터 통합](#8-플로우-및-데이터-통합)
9. [인덱스 전략](#9-인덱스-전략)
10. [동적 테이블 생성 패턴](#10-동적-테이블-생성-패턴)
11. [마이그레이션 히스토리](#11-마이그레이션-히스토리)
---
## 1. 개요
### 1.1 데이터베이스 통계
```
- 총 테이블 수: 약 280개
- 총 함수 수: 약 50개
- 총 트리거 수: 약 30개
- 총 시퀀스 수: 약 100개
- 뷰 수: 약 20개
```
### 1.2 아키텍처 특징
- **멀티테넌시**: 모든 테이블에 `company_code` 컬럼으로 회사별 데이터 격리
- **동적 스키마**: 런타임에 테이블 생성/수정 가능
- **메타데이터 드리븐**: UI 컴포넌트가 메타데이터 테이블을 기반으로 동적 렌더링
- **이력 관리**: 주요 테이블에 `_log` 테이블로 변경 이력 추적
- **외부 연동**: 외부 DB 및 REST API 연결 지원
- **플로우 기반**: 화면 간 데이터 흐름을 정의하고 실행
---
## 2. 전체 테이블 목록
### 2.1 테이블 분류 체계
```
시스템 관리 (약 30개)
├── 사용자/권한 (10개)
├── 메뉴 관리 (5개)
├── 회사 관리 (3개)
└── 공통 코드 (5개)
메타데이터 시스템 (약 20개)
├── 테이블/컬럼 정의 (8개)
├── 화면 정의 (10개)
└── 레이아웃/컴포넌트 (5개)
비즈니스 도메인 (약 200개)
├── 영업/수주 (30개)
├── 구매/발주 (25개)
├── 재고/창고 (20개)
├── 생산/작업 (25개)
├── 품질/검사 (15개)
├── 물류/운송 (20개)
├── PLM/설계 (30개)
├── 회계/원가 (20개)
└── 기타 (15개)
통합/플로우 (약 30개)
├── 데이터플로우 (10개)
├── 배치 작업 (8개)
└── 외부 연동 (12개)
```
### 2.2 주요 테이블 목록 (알파벳순)
<details>
<summary>전체 테이블 목록 보기 (280개)</summary>
```
approval
attach_file_info
auth_tokens
authority_master
authority_master_history
authority_sub_user
batch_configs
batch_execution_logs
batch_job_executions
batch_job_parameters
batch_jobs
batch_mappings
batch_schedules
button_action_standards
carrier_contract_mng
carrier_contract_mng_log
carrier_mng
carrier_mng_log
carrier_vehicle_mng
carrier_vehicle_mng_log
cascading_auto_fill_group
cascading_auto_fill_mapping
cascading_condition
cascading_hierarchy_group
cascading_hierarchy_level
cascading_multi_parent
cascading_multi_parent_source
cascading_mutual_exclusion
cascading_relation
cascading_reverse_lookup
category_column_mapping
category_value_cascading_group
category_value_cascading_mapping
chartmgmt
check_report_mng
code_category
code_info
collection_batch_executions
collection_batch_management
column_labels
comm_code
comm_code_history
comm_exchange_rate
comments
company_code_sequence
company_mng
component_standards
contract_mgmt
contract_mgmt_option
counselingmgmt
customer_item
customer_item_alias
customer_item_mapping
customer_item_price
customer_mng
customer_service_mgmt
customer_service_part
customer_service_workingtime
dashboard_elements
dashboard_shares
dashboard_slider_items
dashboard_sliders
dashboards
data_collection_configs
data_collection_history
data_collection_jobs
data_relationship_bridge
dataflow_diagrams
dataflow_external_calls
ddl_execution_log
defect_standard_mng
defect_standard_mng_log
delivery_destination
delivery_history
delivery_history_defect
delivery_part_price
delivery_route_mng
delivery_route_mng_log
delivery_status
dept_info
dept_info_history
digital_twin_layout
digital_twin_layout_template
digital_twin_location_layout
digital_twin_objects
digital_twin_zone_layout
drivers
dtg_contracts
dtg_maintenance_history
dtg_management
dtg_management_log
dtg_monthly_settlements
dynamic_form_data
equipment_consumable
equipment_consumable_log
equipment_inspection_item
equipment_inspection_item_log
equipment_mng
equipment_mng_log
estimate_mgmt
excel_mapping_template
expense_detail
expense_master
external_call_configs
external_call_logs
external_connection_permission
external_db_connection
external_db_connections
external_rest_api_connections
external_work_review_info
facility_assembly_plan
file_down_log
flow_audit_log
flow_data_mapping
flow_data_status
flow_definition
flow_external_connection_permission
flow_external_db_connection
flow_integration_log
flow_step
flow_step_connection
fund_mgmt
grid_standards
inbound_mng
inboxtask
injection_cost
input_cost_goal
input_resource
inspection_equipment_mng
inspection_equipment_mng_log
inspection_standard
inventory_history
inventory_stock
item_info
item_inspection_info
item_routing_detail
item_routing_version
klbom_tbl
language_master
layout_instances
layout_standards
login_access_log
logistics_cost_mng
logistics_cost_mng_log
mail_log
maintenance_schedules
material_cost
material_detail_mgmt
material_master_mgmt
material_mng
material_release
menu_info
menu_screen_group_items
menu_screen_groups
mold_dev_request_info
multi_lang_category
multi_lang_key_master
multi_lang_text
node_flows
numbering_rule_parts
numbering_rules
oem_factory_mng
oem_milestone_mng
oem_mng
option_mng
option_price_history
order_mgmt
order_mng_master
order_mng_sub
order_plan_mgmt
order_plan_result_error
order_spec_mng
order_spec_mng_history
outbound_mng
part_bom_qty
part_bom_report
part_distribution_list
part_mgmt
part_mng
part_mng_history
planning_issue
pms_invest_cost_mng
pms_pjt_concept_info
pms_pjt_info
pms_pjt_year_goal
pms_rel_pjt_concept_milestone
pms_rel_pjt_concept_prod
pms_rel_pjt_prod
pms_rel_prod_ref_dept
pms_wbs_task
pms_wbs_task_confirm
pms_wbs_task_info
pms_wbs_task_standard
pms_wbs_template
problem_mng
process_equipment
process_mng
procurement_standard
product_group_mng
product_kind_spec
product_kind_spec_main
product_mgmt
product_mgmt_model
product_mgmt_price_history
product_mgmt_upg_detail
product_mgmt_upg_master
product_mng
product_spec
production_issue
production_record
production_task
profit_loss
profit_loss_coefficient
profit_loss_coolingtime
profit_loss_depth
profit_loss_lossrate
profit_loss_machine
profit_loss_pretime
profit_loss_srrate
profit_loss_total
profit_loss_total_addlist
profit_loss_weight
project
project_mgmt
purchase_detail
purchase_order
purchase_order_master
purchase_order_mng
purchase_order_multi
purchase_order_part
ratecal_mgmt
receive_history
receiving
rel_menu_auth
report_layout
report_master
report_menu_mapping
report_query
report_template
safety_budget_execution
safety_incidents
safety_inspections
safety_inspections_log
sales_bom_part_qty
sales_bom_report
sales_bom_report_part
sales_long_delivery
sales_long_delivery_input
sales_long_delivery_predict
sales_order_detail
sales_order_detail_log
sales_order_mng
sales_part_chg
sales_request_master
sales_request_part
sample_supply
screen_data_flows
screen_data_transfer
screen_definitions
screen_embedding
screen_field_joins
screen_group_members
screen_group_screens
screen_groups
screen_layouts
screen_menu_assignments
screen_split_panel
screen_table_relations
screen_templates
screen_widgets
shipment_detail
shipment_header
shipment_instruction
shipment_instruction_item
shipment_pallet
shipment_plan
standard_doc_info
structural_review_proposal
style_templates
supplier_item
supplier_item_alias
supplier_item_mapping
supplier_item_price
supplier_mng
supplier_mng_log
supply_charger_mng
supply_mng
supply_mng_history
table_column_category_values
table_labels
table_log_config
table_relationships
table_type_columns
tax_invoice
tax_invoice_item
time_sheet
transport_logs
transport_statistics
transport_vehicle_locations
used_mng
user_dept
user_dept_sub
user_info
user_info_history
vehicle_location_history
vehicle_locations
vehicle_trip_summary
vehicles
warehouse_info
warehouse_location
web_type_standards
work_instruction
work_instruction_detail
work_instruction_detail_log
work_instruction_log
work_order
work_orders
work_orders_detail
work_request
yard_layout
yard_material_placement
```
</details>
---
## 3. 멀티테넌시 아키텍처
### 3.1 company_code 패턴
**모든 테이블에 필수적으로 포함되는 컬럼:**
```sql
company_code VARCHAR(20) NOT NULL
```
**의미:**
- 하나의 데이터베이스에서 여러 회사의 데이터를 격리
- 모든 쿼리는 반드시 `company_code` 필터 포함 필요
### 3.2 특별한 company_code 값
#### `company_code = "*"` 의미
```sql
-- ❌ 잘못된 이해: 모든 회사가 공유하는 공통 데이터
-- ✅ 올바른 이해: 슈퍼 관리자 전용 데이터
-- 일반 회사는 "*" 데이터를 볼 수 없음
SELECT * FROM table_name
WHERE company_code = 'COMPANY_A'
AND company_code != '*'; -- 필수!
```
**용도:**
- 시스템 관리자용 메타데이터
- 전역 설정 값
- 기본 템플릿
### 3.3 멀티테넌시 쿼리 패턴
```sql
-- ✅ 표준 SELECT 패턴
SELECT * FROM table_name
WHERE company_code = $1
AND company_code != '*'
ORDER BY created_date DESC;
-- ✅ JOIN 패턴 (company_code 매칭 필수!)
SELECT a.*, b.name
FROM table_a a
LEFT JOIN table_b b
ON a.ref_id = b.id
AND a.company_code = b.company_code -- 필수!
WHERE a.company_code = $1;
-- ✅ 서브쿼리 패턴
SELECT *
FROM orders o
WHERE company_code = $1
AND product_id IN (
SELECT id FROM products
WHERE company_code = $1 -- 서브쿼리에도 필수!
);
-- ✅ 집계 패턴
SELECT
product_type,
COUNT(*) as total,
SUM(amount) as total_amount
FROM sales
WHERE company_code = $1
GROUP BY product_type;
```
### 3.4 company_code 인덱스 전략
**모든 테이블에 필수 인덱스:**
```sql
CREATE INDEX idx_{table_name}_company_code
ON {table_name}(company_code);
-- 복합 인덱스 예시
CREATE INDEX idx_sales_company_date
ON sales(company_code, sale_date DESC);
```
---
## 4. 핵심 시스템 테이블
### 4.1 사용자 관리
#### user_info (사용자 정보)
```sql
CREATE TABLE user_info (
sabun VARCHAR(1024), -- 사번
user_id VARCHAR(1024) PRIMARY KEY,-- 사용자 ID
user_password VARCHAR(1024), -- 암호화된 비밀번호
user_name VARCHAR(1024), -- 한글명
user_name_eng VARCHAR(1024), -- 영문명
user_name_cn VARCHAR(1024), -- 중문명
dept_code VARCHAR(1024), -- 부서 코드
dept_name VARCHAR(1024), -- 부서명
position_code VARCHAR(1024), -- 직위 코드
position_name VARCHAR(1024), -- 직위명
email VARCHAR(1024), -- 이메일
tel VARCHAR(1024), -- 전화번호
cell_phone VARCHAR(1024), -- 휴대폰
user_type VARCHAR(1024), -- 사용자 유형 코드
user_type_name VARCHAR(1024), -- 사용자 유형명
company_code VARCHAR(50), -- 회사 코드 (멀티테넌시)
status VARCHAR(32), -- active/inactive
license_number VARCHAR(50), -- 면허번호
vehicle_number VARCHAR(50), -- 차량번호
signup_type VARCHAR(20), -- 가입 유형
branch_name VARCHAR(100), -- 지점명
regdate TIMESTAMP, -- 등록일
end_date TIMESTAMP -- 종료일
);
```
**관련 테이블:**
- `user_info_history`: 사용자 정보 변경 이력
- `user_dept`: 사용자-부서 관계
- `user_dept_sub`: 사용자 하위 부서
#### auth_tokens (인증 토큰)
```sql
CREATE TABLE auth_tokens (
id SERIAL PRIMARY KEY,
user_id VARCHAR(255) NOT NULL,
token VARCHAR(500) NOT NULL,
refresh_token VARCHAR(500),
expires_at TIMESTAMP NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
ip_address VARCHAR(50),
user_agent TEXT
);
```
### 4.2 권한 관리
#### authority_master (권한 그룹)
```sql
CREATE TABLE authority_master (
objid NUMERIC PRIMARY KEY,
auth_code VARCHAR(64), -- 권한 코드
auth_name VARCHAR(64), -- 권한명
company_code VARCHAR(50), -- 회사 코드
status VARCHAR(32), -- 상태
writer VARCHAR(32), -- 작성자
regdate TIMESTAMP -- 등록일
);
```
**관련 테이블:**
- `authority_master_history`: 권한 변경 이력
- `authority_sub_user`: 권한-사용자 매핑
- `rel_menu_auth`: 권한-메뉴 매핑
### 4.3 메뉴 관리
#### menu_info (메뉴 정보)
```sql
CREATE TABLE menu_info (
objid NUMERIC PRIMARY KEY,
menu_type NUMERIC, -- 0=일반, 1=시스템관리, 2=동적생성
parent_obj_id NUMERIC, -- 부모 메뉴 ID
menu_name_kor VARCHAR(64), -- 한글 메뉴명
menu_name_eng VARCHAR(64), -- 영문 메뉴명
menu_code VARCHAR(50), -- 메뉴 코드
menu_url VARCHAR(256), -- 메뉴 URL
seq NUMERIC, -- 순서
screen_code VARCHAR(50), -- 화면 코드 (동적 생성 시)
screen_group_id INTEGER, -- 화면 그룹 ID
company_code VARCHAR(50), -- 회사 코드
status VARCHAR(32), -- active/inactive
lang_key VARCHAR(100), -- 다국어 키
source_menu_objid BIGINT, -- 원본 메뉴 ID (복사 시)
writer VARCHAR(32),
regdate TIMESTAMP
);
```
**특징:**
- `menu_type = 2`: 화면 생성 시 자동으로 생성되는 메뉴
- 트리거: `auto_create_menu_for_screen()` - 화면 생성 시 자동 메뉴 추가
**관련 테이블:**
- `menu_screen_groups`: 메뉴 화면 그룹
- `menu_screen_group_items`: 그룹-화면 연결
### 4.4 회사 관리
#### company_mng (회사 정보)
```sql
CREATE TABLE company_mng (
company_code VARCHAR(32) PRIMARY KEY,
company_name VARCHAR(64),
business_registration_number VARCHAR(20), -- 사업자등록번호
representative_name VARCHAR(100), -- 대표자명
representative_phone VARCHAR(20), -- 대표 연락처
email VARCHAR(255), -- 회사 이메일
website VARCHAR(500), -- 웹사이트
address VARCHAR(500), -- 주소
status VARCHAR(32),
writer VARCHAR(32),
regdate TIMESTAMP
);
```
**관련 테이블:**
- `company_code_sequence`: 회사별 시퀀스 관리
### 4.5 부서 관리
#### dept_info (부서 정보)
```sql
CREATE TABLE dept_info (
dept_code VARCHAR(1024) PRIMARY KEY,
dept_name VARCHAR(1024),
parent_dept_code VARCHAR(1024), -- 상위 부서
company_code VARCHAR(50),
status VARCHAR(32),
writer VARCHAR(32),
regdate TIMESTAMP
);
```
**관련 테이블:**
- `dept_info_history`: 부서 정보 변경 이력
---
## 5. 메타데이터 관리 시스템
WACE ERP의 핵심 특징은 **메타데이터 드리븐 아키텍처**입니다. 화면, 테이블, 컬럼 정보를 메타데이터 테이블에서 관리하고, 프론트엔드가 이를 기반으로 동적 렌더링합니다.
### 5.1 테이블 메타데이터
#### table_labels (테이블 정의)
```sql
CREATE TABLE table_labels (
table_name VARCHAR(100) PRIMARY KEY, -- 테이블명 (물리명)
table_label VARCHAR(200), -- 테이블 한글명
description TEXT, -- 설명
use_log_table VARCHAR(1) DEFAULT 'N', -- 이력 테이블 사용 여부
created_date TIMESTAMP,
updated_date TIMESTAMP
);
```
**역할:**
- 동적으로 생성된 모든 테이블의 메타정보 저장
- 화면 생성 시 테이블 선택 목록 제공
- 데이터 딕셔너리로 활용
#### table_type_columns (컬럼 타입 정의)
```sql
CREATE TABLE table_type_columns (
id SERIAL PRIMARY KEY,
table_name VARCHAR(255) NOT NULL,
column_name VARCHAR(255) NOT NULL,
company_code VARCHAR(20) NOT NULL, -- 회사별 컬럼 설정
input_type VARCHAR(50) DEFAULT 'text',-- 입력 타입
detail_settings TEXT DEFAULT '{}', -- JSON 상세 설정
is_nullable VARCHAR(10) DEFAULT 'Y',
display_order INTEGER DEFAULT 0, -- 표시 순서
created_date TIMESTAMP,
updated_date TIMESTAMP,
UNIQUE(table_name, column_name, company_code)
);
```
**input_type 종류:**
- `text`: 일반 텍스트
- `number`: 숫자
- `date`: 날짜
- `select`: 드롭다운 (options 필요)
- `textarea`: 여러 줄 텍스트
- `entity`: 참조 테이블 (referenceTable, referenceColumn 필요)
- `checkbox`: 체크박스
- `radio`: 라디오 버튼
**detail_settings 예시:**
```json
// select 타입
{
"options": [
{"label": "일반", "value": "normal"},
{"label": "긴급", "value": "urgent"}
]
}
// entity 타입
{
"referenceTable": "customer_mng",
"referenceColumn": "customer_code",
"displayColumn": "customer_name"
}
```
#### column_labels (컬럼 라벨 - 레거시)
```sql
CREATE TABLE column_labels (
table_name VARCHAR(100) NOT NULL,
column_name VARCHAR(100) NOT NULL,
column_label VARCHAR(200), -- 한글 라벨
input_type VARCHAR(50),
detail_settings TEXT,
description TEXT,
display_order INTEGER,
is_visible BOOLEAN DEFAULT true,
created_date TIMESTAMP,
updated_date TIMESTAMP,
PRIMARY KEY (table_name, column_name)
);
```
**참고:**
- 레거시 호환을 위해 유지
- 새로운 컬럼은 `table_type_columns` 사용 권장
- `table_type_columns`는 회사별 설정, `column_labels`는 전역 설정
### 5.2 카테고리 값 관리
#### table_column_category_values (컬럼 카테고리 값)
```sql
CREATE TABLE table_column_category_values (
id SERIAL PRIMARY KEY,
table_name VARCHAR(255) NOT NULL,
column_name VARCHAR(255) NOT NULL,
company_code VARCHAR(20) NOT NULL,
category_value VARCHAR(500) NOT NULL, -- 카테고리 값
display_label VARCHAR(500), -- 표시 라벨
display_order INTEGER DEFAULT 0,
is_active VARCHAR(1) DEFAULT 'Y',
parent_value VARCHAR(500), -- 부모 카테고리 (계층 구조)
created_date TIMESTAMP,
updated_date TIMESTAMP,
UNIQUE(table_name, column_name, company_code, category_value)
);
```
**용도:**
- 동적 드롭다운 값 관리
- 계층형 카테고리 지원 (parent_value)
- 회사별 카테고리 값 커스터마이징
**관련 테이블:**
- `category_column_mapping`: 카테고리-컬럼 매핑
- `category_value_cascading_group`: 카테고리 캐스케이딩 그룹
- `category_value_cascading_mapping`: 캐스케이딩 매핑
### 5.3 테이블 관계 관리
#### table_relationships (테이블 관계)
```sql
CREATE TABLE table_relationships (
id SERIAL PRIMARY KEY,
parent_table VARCHAR(100), -- 부모 테이블
parent_column VARCHAR(100), -- 부모 컬럼
child_table VARCHAR(100), -- 자식 테이블
child_column VARCHAR(100), -- 자식 컬럼
relationship_type VARCHAR(20), -- one-to-many, many-to-one 등
created_date TIMESTAMP
);
```
---
## 6. 화면 관리 시스템
WACE ERP는 코드 작성 없이 화면을 동적으로 생성/수정할 수 있는 **Low-Code 플랫폼** 기능을 제공합니다.
### 6.1 화면 정의
#### screen_definitions (화면 정의)
```sql
CREATE TABLE screen_definitions (
screen_id SERIAL PRIMARY KEY,
screen_name VARCHAR(100) NOT NULL, -- 화면명
screen_code VARCHAR(50) NOT NULL, -- 화면 코드 (URL용)
table_name VARCHAR(100) NOT NULL, -- 메인 테이블
company_code VARCHAR(50) NOT NULL,
description TEXT,
is_active CHAR(1) DEFAULT 'Y', -- Y=활성, N=비활성, D=삭제
layout_metadata JSONB, -- 레이아웃 JSON
-- 외부 데이터 소스 지원
db_source_type VARCHAR(10) DEFAULT 'internal', -- internal/external
db_connection_id INTEGER, -- 외부 DB 연결 ID
data_source_type VARCHAR(20) DEFAULT 'database', -- database/rest_api
rest_api_connection_id INTEGER, -- REST API 연결 ID
rest_api_endpoint VARCHAR(500), -- API 엔드포인트
rest_api_json_path VARCHAR(200) DEFAULT 'data', -- JSON 응답 경로
source_screen_id INTEGER, -- 원본 화면 ID (복사 시)
created_date TIMESTAMP NOT NULL DEFAULT NOW(),
created_by VARCHAR(50),
updated_date TIMESTAMP NOT NULL DEFAULT NOW(),
updated_by VARCHAR(50),
deleted_date TIMESTAMP, -- 휴지통 이동 시점
deleted_by VARCHAR(50),
delete_reason TEXT,
UNIQUE(screen_code, company_code)
);
```
**화면 생성 플로우:**
1. 관리자가 화면 설정 페이지에서 테이블 선택
2. `screen_definitions` 레코드 생성
3. 트리거 `auto_create_menu_for_screen()` 실행 → `menu_info` 자동 생성
4. 프론트엔드가 `/screen/{screen_code}` 경로로 접근 시 동적 렌더링
#### screen_layouts (화면 레이아웃 - 레거시)
```sql
CREATE TABLE screen_layouts (
layout_id SERIAL PRIMARY KEY,
screen_id INTEGER REFERENCES screen_definitions(screen_id),
layout_name VARCHAR(100),
layout_type VARCHAR(50), -- grid, form, split, tab 등
layout_config JSONB, -- 레이아웃 설정
display_order INTEGER,
is_active CHAR(1) DEFAULT 'Y',
company_code VARCHAR(50),
created_date TIMESTAMP,
updated_date TIMESTAMP
);
```
### 6.2 화면 그룹 관리
#### screen_groups (화면 그룹)
```sql
CREATE TABLE screen_groups (
id SERIAL PRIMARY KEY,
group_name VARCHAR(100) NOT NULL, -- 그룹명
group_code VARCHAR(50) NOT NULL, -- 그룹 코드
main_table_name VARCHAR(100), -- 메인 테이블
description TEXT,
icon VARCHAR(100), -- 아이콘
display_order INT DEFAULT 0,
is_active VARCHAR(1) DEFAULT 'Y',
company_code VARCHAR(20) NOT NULL,
-- 계층 구조 지원 (037 마이그레이션에서 추가)
parent_group_id INTEGER REFERENCES screen_groups(id) ON DELETE CASCADE,
group_level INTEGER DEFAULT 0, -- 0=대, 1=중, 2=소
hierarchy_path VARCHAR(500), -- 예: /1/3/5/
created_date TIMESTAMPTZ DEFAULT NOW(),
updated_date TIMESTAMPTZ DEFAULT NOW(),
writer VARCHAR(50),
UNIQUE(company_code, group_code)
);
CREATE INDEX idx_screen_groups_company_code ON screen_groups(company_code);
CREATE INDEX idx_screen_groups_parent_id ON screen_groups(parent_group_id);
CREATE INDEX idx_screen_groups_hierarchy_path ON screen_groups(hierarchy_path);
```
#### screen_group_screens (화면-그룹 연결)
```sql
CREATE TABLE screen_group_screens (
id SERIAL PRIMARY KEY,
group_id INT NOT NULL REFERENCES screen_groups(id) ON DELETE CASCADE,
screen_id INT NOT NULL REFERENCES screen_definitions(screen_id) ON DELETE CASCADE,
screen_role VARCHAR(50) DEFAULT 'main', -- main, register, list, detail 등
display_order INT DEFAULT 0,
is_default VARCHAR(1) DEFAULT 'N', -- 기본 화면 여부
company_code VARCHAR(20) NOT NULL,
created_date TIMESTAMPTZ DEFAULT NOW(),
updated_date TIMESTAMPTZ DEFAULT NOW(),
writer VARCHAR(50),
UNIQUE(group_id, screen_id)
);
```
**용도:**
- 관련 화면들을 그룹으로 묶어 관리
- 예: "영업 관리" 그룹 → 견적 화면, 수주 화면, 출하 화면
### 6.3 화면 필드 조인
#### screen_field_joins (화면 필드 조인 설정)
```sql
CREATE TABLE screen_field_joins (
id SERIAL PRIMARY KEY,
screen_id INT NOT NULL REFERENCES screen_definitions(screen_id) ON DELETE CASCADE,
layout_id INT,
component_id VARCHAR(500),
field_name VARCHAR(100),
-- 저장 테이블 설정
save_table VARCHAR(100) NOT NULL,
save_column VARCHAR(100) NOT NULL,
-- 조인 테이블 설정
join_table VARCHAR(100) NOT NULL,
join_column VARCHAR(100) NOT NULL,
display_column VARCHAR(100) NOT NULL,
-- 조인 옵션
join_type VARCHAR(20) DEFAULT 'LEFT',
filter_condition TEXT,
sort_column VARCHAR(100),
sort_direction VARCHAR(10) DEFAULT 'ASC',
is_active VARCHAR(1) DEFAULT 'Y',
company_code VARCHAR(20) NOT NULL,
created_date TIMESTAMPTZ DEFAULT NOW(),
updated_date TIMESTAMPTZ DEFAULT NOW(),
writer VARCHAR(50)
);
```
**예시:**
```json
{
"save_table": "sales_order",
"save_column": "customer_code",
"join_table": "customer_mng",
"join_column": "customer_code",
"display_column": "customer_name"
}
```
### 6.4 화면 간 데이터 흐름
#### screen_data_flows (화면 간 데이터 흐름)
```sql
CREATE TABLE screen_data_flows (
id SERIAL PRIMARY KEY,
group_id INT REFERENCES screen_groups(id) ON DELETE SET NULL,
-- 소스 화면
source_screen_id INT NOT NULL REFERENCES screen_definitions(screen_id) ON DELETE CASCADE,
source_action VARCHAR(50), -- click, submit, select 등
-- 타겟 화면
target_screen_id INT NOT NULL REFERENCES screen_definitions(screen_id) ON DELETE CASCADE,
target_action VARCHAR(50), -- open, load, refresh 등
-- 데이터 매핑 설정
data_mapping JSONB, -- 필드 매핑 정보
-- 흐름 설정
flow_type VARCHAR(20) DEFAULT 'unidirectional', -- unidirectional/bidirectional
flow_label VARCHAR(100), -- 시각화 라벨
condition_expression TEXT, -- 실행 조건식
is_active VARCHAR(1) DEFAULT 'Y',
company_code VARCHAR(20) NOT NULL,
created_date TIMESTAMPTZ DEFAULT NOW(),
updated_date TIMESTAMPTZ DEFAULT NOW(),
writer VARCHAR(50)
);
```
**data_mapping 예시:**
```json
{
"customer_code": "customer_code",
"customer_name": "customer_name",
"selected_date": "order_date"
}
```
#### screen_table_relations (화면-테이블 관계)
```sql
CREATE TABLE screen_table_relations (
id SERIAL PRIMARY KEY,
group_id INT REFERENCES screen_groups(id) ON DELETE SET NULL,
screen_id INT NOT NULL REFERENCES screen_definitions(screen_id) ON DELETE CASCADE,
table_name VARCHAR(100) NOT NULL,
relation_type VARCHAR(20) DEFAULT 'main', -- main, join, lookup
crud_operations VARCHAR(20) DEFAULT 'CRUD',-- CRUD 조합
description TEXT,
is_active VARCHAR(1) DEFAULT 'Y',
company_code VARCHAR(20) NOT NULL,
created_date TIMESTAMPTZ DEFAULT NOW(),
updated_date TIMESTAMPTZ DEFAULT NOW(),
writer VARCHAR(50)
);
```
### 6.5 컴포넌트 표준
#### component_standards (컴포넌트 표준)
```sql
CREATE TABLE component_standards (
component_code VARCHAR(50) PRIMARY KEY,
component_name VARCHAR(100) NOT NULL,
component_name_eng VARCHAR(100),
description TEXT,
category VARCHAR(50) NOT NULL, -- input, layout, display 등
icon_name VARCHAR(50),
default_size JSON, -- {width, height}
component_config JSON NOT NULL, -- 컴포넌트 설정
preview_image VARCHAR(255),
sort_order INTEGER DEFAULT 0,
is_active CHAR(1) DEFAULT 'Y',
is_public CHAR(1) DEFAULT 'Y',
company_code VARCHAR(50) NOT NULL,
created_date TIMESTAMP,
updated_date TIMESTAMP
);
```
#### layout_standards (레이아웃 표준)
```sql
CREATE TABLE layout_standards (
layout_code VARCHAR(50) PRIMARY KEY,
layout_name VARCHAR(100) NOT NULL,
layout_type VARCHAR(50), -- grid, form, split, tab
default_config JSON,
is_active CHAR(1) DEFAULT 'Y',
company_code VARCHAR(50),
created_date TIMESTAMP,
updated_date TIMESTAMP
);
```
---
## 7. 비즈니스 도메인별 테이블
### 7.1 영업/수주 관리
#### 수주 관리 (Order Management)
```
sales_order_mng -- 수주 마스터
├── sales_order_detail -- 수주 상세
├── sales_order_detail_log -- 수주 상세 이력
├── sales_request_master -- 영업 요청 마스터
├── sales_request_part -- 영업 요청 부품
└── sales_part_chg -- 영업 부품 변경
```
**sales_order_mng:**
- 고객별 수주 정보
- 납기, 금액, 상태 관리
**sales_order_detail:**
- 수주 라인 아이템
- 품목, 수량, 단가 정보
#### 견적 관리
```
estimate_mgmt -- 견적 관리
contract_mgmt -- 계약 관리
├── contract_mgmt_option -- 계약 옵션
```
#### BOM 관리
```
sales_bom_report -- 영업 BOM 리포트
├── sales_bom_report_part -- 영업 BOM 부품
└── sales_bom_part_qty -- 영업 BOM 부품 수량
```
### 7.2 구매/발주 관리
```
purchase_order_master -- 발주 마스터
├── purchase_order -- 발주 상세
├── purchase_order_part -- 발주 부품
├── purchase_order_multi -- 다중 발주
└── purchase_detail -- 구매 상세
supplier_mng -- 공급업체 관리
├── supplier_mng_log -- 공급업체 이력
├── supplier_item -- 공급업체 품목
├── supplier_item_alias -- 공급업체 품목 별칭
├── supplier_item_mapping -- 공급업체 품목 매핑
└── supplier_item_price -- 공급업체 품목 가격
```
### 7.3 재고/창고 관리
```
inventory_stock -- 재고 현황
inventory_history -- 재고 이력
warehouse_info -- 창고 정보
warehouse_location -- 창고 위치
inbound_mng -- 입고 관리
outbound_mng -- 출고 관리
receiving -- 입하
receive_history -- 입하 이력
```
### 7.4 생산/작업 관리
```
work_orders -- 작업지시 (신규)
├── work_orders_detail -- 작업지시 상세
work_order -- 작업지시 (레거시)
work_instruction -- 작업 지시서
├── work_instruction_detail -- 작업 지시서 상세
├── work_instruction_detail_log
└── work_instruction_log
production_record -- 생산 실적
production_task -- 생산 작업
production_issue -- 생산 이슈
work_request -- 작업 요청
```
#### work_orders (작업지시 - 050 마이그레이션)
```sql
CREATE TABLE work_orders (
id VARCHAR(500) PRIMARY KEY DEFAULT gen_random_uuid()::text,
created_date TIMESTAMP DEFAULT NOW(),
updated_date TIMESTAMP DEFAULT NOW(),
writer VARCHAR(500),
company_code VARCHAR(500),
-- 작업지시 정보
wo_number VARCHAR(500), -- WO-20250130-001
product_code VARCHAR(500),
product_name VARCHAR(500),
spec VARCHAR(500),
order_qty VARCHAR(500),
completed_qty VARCHAR(500),
start_date VARCHAR(500),
due_date VARCHAR(500),
status VARCHAR(500), -- normal/urgent
progress_status VARCHAR(500), -- pending/in-progress/completed
equipment VARCHAR(500),
routing VARCHAR(500),
work_team VARCHAR(500), -- DAY/NIGHT
worker VARCHAR(500),
shift VARCHAR(500), -- DAY/NIGHT
remark VARCHAR(500)
);
CREATE INDEX idx_work_orders_company_code ON work_orders(company_code);
CREATE INDEX idx_work_orders_wo_number ON work_orders(wo_number);
```
### 7.5 품질/검사 관리
```
inspection_standard -- 검사 기준
item_inspection_info -- 품목 검사 정보
inspection_equipment_mng -- 검사 설비 관리
├── inspection_equipment_mng_log
defect_standard_mng -- 불량 기준 관리
├── defect_standard_mng_log
check_report_mng -- 검사 성적서 관리
safety_inspections -- 안전 점검
└── safety_inspections_log
```
### 7.6 물류/운송 관리
```
vehicles -- 차량 정보
├── vehicle_locations -- 차량 위치
├── vehicle_location_history -- 차량 위치 이력
├── vehicle_trip_summary -- 차량 운행 요약
drivers -- 운전자 정보
transport_logs -- 운송 로그
transport_statistics -- 운송 통계
transport_vehicle_locations -- 차량 위치
carrier_mng -- 운송사 관리
├── carrier_mng_log
├── carrier_contract_mng -- 운송사 계약
├── carrier_contract_mng_log
├── carrier_vehicle_mng -- 운송사 차량
└── carrier_vehicle_mng_log
delivery_route_mng -- 배송 경로 관리
├── delivery_route_mng_log
delivery_destination -- 배송지
delivery_status -- 배송 상태
delivery_history -- 배송 이력
├── delivery_history_defect -- 배송 불량
delivery_part_price -- 배송 부품 가격
```
#### DTG 관리 (디지털 타코그래프)
```
dtg_management -- DTG 관리
├── dtg_management_log
dtg_contracts -- DTG 계약
dtg_maintenance_history -- DTG 정비 이력
dtg_monthly_settlements -- DTG 월별 정산
```
### 7.7 PLM/설계 관리
```
part_mng -- 부품 관리 (메인)
├── part_mng_history
part_mgmt -- 부품 관리 (서브)
part_bom_qty -- 부품 BOM 수량
part_bom_report -- 부품 BOM 리포트
part_distribution_list -- 부품 배포 목록
item_info -- 품목 정보
item_routing_version -- 품목 라우팅 버전
item_routing_detail -- 품목 라우팅 상세
product_mng -- 제품 관리
product_mgmt -- 제품 관리 (메인)
├── product_mgmt_model -- 제품 모델
├── product_mgmt_price_history -- 제품 가격 이력
├── product_mgmt_upg_master -- 제품 업그레이드 마스터
└── product_mgmt_upg_detail -- 제품 업그레이드 상세
product_kind_spec -- 제품 종류 사양
product_kind_spec_main -- 제품 종류 사양 메인
product_spec -- 제품 사양
product_group_mng -- 제품 그룹 관리
mold_dev_request_info -- 금형 개발 요청
structural_review_proposal -- 구조 검토 제안
```
### 7.8 프로젝트 관리 (PMS)
```
pms_pjt_info -- 프로젝트 정보
├── pms_pjt_concept_info -- 프로젝트 개념 정보
├── pms_pjt_year_goal -- 프로젝트 연도 목표
pms_wbs_task -- WBS 작업
├── pms_wbs_task_info -- WBS 작업 정보
├── pms_wbs_task_confirm -- WBS 작업 확인
├── pms_wbs_task_standard -- WBS 작업 표준
└── pms_wbs_template -- WBS 템플릿
pms_rel_pjt_concept_milestone -- 프로젝트 개념-마일스톤 관계
pms_rel_pjt_concept_prod -- 프로젝트 개념-제품 관계
pms_rel_pjt_prod -- 프로젝트-제품 관계
pms_rel_prod_ref_dept -- 제품-참조부서 관계
pms_invest_cost_mng -- 투자 비용 관리
project_mgmt -- 프로젝트 관리
problem_mng -- 문제 관리
planning_issue -- 계획 이슈
```
### 7.9 회계/원가 관리
```
tax_invoice -- 세금계산서
├── tax_invoice_item -- 세금계산서 항목
fund_mgmt -- 자금 관리
expense_master -- 비용 마스터
├── expense_detail -- 비용 상세
profit_loss -- 손익 계산
├── profit_loss_total -- 손익 합계
├── profit_loss_coefficient -- 손익 계수
├── profit_loss_machine -- 손익 기계
├── profit_loss_weight -- 손익 무게
├── profit_loss_depth -- 손익 깊이
├── profit_loss_pretime -- 손익 사전 시간
├── profit_loss_coolingtime -- 손익 냉각 시간
├── profit_loss_lossrate -- 손익 손실률
└── profit_loss_srrate -- 손익 SR률
material_cost -- 자재 비용
injection_cost -- 사출 비용
logistics_cost_mng -- 물류 비용 관리
└── logistics_cost_mng_log
input_cost_goal -- 투입 비용 목표
input_resource -- 투입 자원
```
### 7.10 고객/협력사 관리
```
customer_mng -- 고객 관리
customer_item -- 고객 품목
├── customer_item_alias -- 고객 품목 별칭
├── customer_item_mapping -- 고객 품목 매핑
└── customer_item_price -- 고객 품목 가격
customer_service_mgmt -- 고객 서비스 관리
├── customer_service_part -- 고객 서비스 부품
└── customer_service_workingtime -- 고객 서비스 작업시간
oem_mng -- OEM 관리
├── oem_factory_mng -- OEM 공장 관리
└── oem_milestone_mng -- OEM 마일스톤 관리
```
### 7.11 설비/장비 관리
```
equipment_mng -- 설비 관리
├── equipment_mng_log
equipment_consumable -- 설비 소모품
├── equipment_consumable_log
equipment_inspection_item -- 설비 검사 항목
└── equipment_inspection_item_log
process_equipment -- 공정 설비
process_mng -- 공정 관리
maintenance_schedules -- 정비 일정
```
### 7.12 기타
```
approval -- 결재
comments -- 댓글
inboxtask -- 수신함 작업
time_sheet -- 작업 시간
attach_file_info -- 첨부 파일
file_down_log -- 파일 다운로드 로그
login_access_log -- 로그인 접근 로그
```
---
## 8. 플로우 및 데이터 통합
### 8.1 플로우 정의
#### flow_definition (플로우 정의)
```sql
CREATE TABLE flow_definition (
flow_id SERIAL PRIMARY KEY,
flow_name VARCHAR(200) NOT NULL,
flow_code VARCHAR(100) NOT NULL,
flow_type VARCHAR(50), -- data_transfer, approval, batch 등
description TEXT,
trigger_type VARCHAR(50), -- manual, schedule, event
trigger_config JSONB,
is_active VARCHAR(1) DEFAULT 'Y',
company_code VARCHAR(20),
created_date TIMESTAMPTZ DEFAULT NOW(),
updated_date TIMESTAMPTZ DEFAULT NOW(),
created_by VARCHAR(50),
updated_by VARCHAR(50),
UNIQUE(flow_code, company_code)
);
```
#### flow_step (플로우 단계)
```sql
CREATE TABLE flow_step (
step_id SERIAL PRIMARY KEY,
flow_id INTEGER REFERENCES flow_definition(flow_id) ON DELETE CASCADE,
step_name VARCHAR(200) NOT NULL,
step_type VARCHAR(50) NOT NULL, -- query, transform, api_call, condition 등
step_order INTEGER NOT NULL,
step_config JSONB NOT NULL,
error_handling_config JSONB,
is_active VARCHAR(1) DEFAULT 'Y',
company_code VARCHAR(20),
created_date TIMESTAMPTZ DEFAULT NOW(),
updated_date TIMESTAMPTZ DEFAULT NOW()
);
```
#### flow_step_connection (플로우 단계 연결)
```sql
CREATE TABLE flow_step_connection (
connection_id SERIAL PRIMARY KEY,
flow_id INTEGER REFERENCES flow_definition(flow_id) ON DELETE CASCADE,
source_step_id INTEGER REFERENCES flow_step(step_id) ON DELETE CASCADE,
target_step_id INTEGER REFERENCES flow_step(step_id) ON DELETE CASCADE,
condition_expression TEXT, -- 조건부 실행
connection_type VARCHAR(20) DEFAULT 'sequential', -- sequential, parallel, conditional
company_code VARCHAR(20),
created_date TIMESTAMPTZ DEFAULT NOW()
);
```
### 8.2 데이터플로우
#### dataflow_diagrams (데이터플로우 다이어그램)
```sql
CREATE TABLE dataflow_diagrams (
diagram_id SERIAL PRIMARY KEY,
diagram_name VARCHAR(200) NOT NULL,
diagram_type VARCHAR(50),
diagram_json JSONB NOT NULL, -- 다이어그램 시각화 정보
description TEXT,
is_active VARCHAR(1) DEFAULT 'Y',
company_code VARCHAR(20),
created_date TIMESTAMPTZ DEFAULT NOW(),
updated_date TIMESTAMPTZ DEFAULT NOW(),
created_by VARCHAR(50),
updated_by VARCHAR(50)
);
```
#### flow_data_mapping (플로우 데이터 매핑)
```sql
CREATE TABLE flow_data_mapping (
mapping_id SERIAL PRIMARY KEY,
flow_id INTEGER REFERENCES flow_definition(flow_id) ON DELETE CASCADE,
source_type VARCHAR(20), -- table, api, flow
source_identifier VARCHAR(200), -- 테이블명 또는 API 엔드포인트
source_field VARCHAR(100),
target_type VARCHAR(20),
target_identifier VARCHAR(200),
target_field VARCHAR(100),
transformation_rule TEXT, -- 변환 규칙 (JavaScript 표현식)
company_code VARCHAR(20),
created_date TIMESTAMPTZ DEFAULT NOW()
);
```
#### flow_data_status (플로우 데이터 상태)
```sql
CREATE TABLE flow_data_status (
status_id SERIAL PRIMARY KEY,
flow_id INTEGER REFERENCES flow_definition(flow_id),
execution_id VARCHAR(100),
source_table VARCHAR(100),
source_record_id VARCHAR(500),
target_table VARCHAR(100),
target_record_id VARCHAR(500),
status VARCHAR(20), -- pending, processing, completed, failed
error_message TEXT,
processed_at TIMESTAMPTZ,
company_code VARCHAR(20),
created_date TIMESTAMPTZ DEFAULT NOW()
);
```
### 8.3 외부 연동
#### external_db_connections (외부 DB 연결)
```sql
CREATE TABLE external_db_connections (
id SERIAL PRIMARY KEY,
connection_name VARCHAR(200) NOT NULL,
connection_code VARCHAR(100) NOT NULL,
db_type VARCHAR(50) NOT NULL, -- postgresql, mysql, mssql, oracle
host VARCHAR(255) NOT NULL,
port INTEGER NOT NULL,
database_name VARCHAR(100) NOT NULL,
username VARCHAR(100),
password_encrypted TEXT,
ssl_enabled BOOLEAN DEFAULT false,
connection_options JSONB,
is_active VARCHAR(1) DEFAULT 'Y',
company_code VARCHAR(20),
created_date TIMESTAMPTZ DEFAULT NOW(),
updated_date TIMESTAMPTZ DEFAULT NOW(),
created_by VARCHAR(50),
UNIQUE(connection_code, company_code)
);
```
#### external_rest_api_connections (외부 REST API 연결)
```sql
CREATE TABLE external_rest_api_connections (
id SERIAL PRIMARY KEY,
connection_name VARCHAR(200) NOT NULL,
connection_code VARCHAR(100) NOT NULL,
base_url VARCHAR(500) NOT NULL,
auth_type VARCHAR(50), -- none, basic, bearer, api_key
auth_config JSONB,
default_headers JSONB,
timeout_seconds INTEGER DEFAULT 30,
retry_count INTEGER DEFAULT 0,
is_active VARCHAR(1) DEFAULT 'Y',
company_code VARCHAR(20),
created_date TIMESTAMPTZ DEFAULT NOW(),
updated_date TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(connection_code, company_code)
);
```
#### external_call_configs (외부 호출 설정)
```sql
CREATE TABLE external_call_configs (
id SERIAL PRIMARY KEY,
config_name VARCHAR(200) NOT NULL,
config_code VARCHAR(100) NOT NULL,
connection_id INTEGER, -- external_rest_api_connections 참조
http_method VARCHAR(10), -- GET, POST, PUT, DELETE
endpoint_path VARCHAR(500),
request_mapping JSONB, -- 요청 데이터 매핑
response_mapping JSONB, -- 응답 데이터 매핑
error_handling JSONB,
is_active VARCHAR(1) DEFAULT 'Y',
company_code VARCHAR(20),
created_date TIMESTAMPTZ DEFAULT NOW(),
updated_date TIMESTAMPTZ DEFAULT NOW()
);
```
### 8.4 배치 작업
#### batch_jobs (배치 작업 정의)
```sql
CREATE TABLE batch_jobs (
job_id SERIAL PRIMARY KEY,
job_name VARCHAR(200) NOT NULL,
job_code VARCHAR(100) NOT NULL,
job_type VARCHAR(50), -- data_collection, aggregation, sync 등
source_type VARCHAR(50), -- database, api, file
source_config JSONB,
target_config JSONB,
schedule_config JSONB,
is_active VARCHAR(1) DEFAULT 'Y',
company_code VARCHAR(20),
created_date TIMESTAMPTZ DEFAULT NOW(),
updated_date TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(job_code, company_code)
);
```
#### batch_execution_logs (배치 실행 로그)
```sql
CREATE TABLE batch_execution_logs (
execution_id SERIAL PRIMARY KEY,
job_id INTEGER REFERENCES batch_jobs(job_id),
execution_status VARCHAR(20), -- running, completed, failed
start_time TIMESTAMPTZ,
end_time TIMESTAMPTZ,
records_processed INTEGER,
records_failed INTEGER,
error_message TEXT,
execution_details JSONB,
company_code VARCHAR(20),
created_date TIMESTAMPTZ DEFAULT NOW()
);
```
---
## 9. 인덱스 전략
### 9.1 필수 인덱스
**모든 테이블에 적용:**
```sql
-- company_code 인덱스 (멀티테넌시 성능)
CREATE INDEX idx_{table_name}_company_code ON {table_name}(company_code);
-- 복합 인덱스 (company_code + 주요 검색 컬럼)
CREATE INDEX idx_{table_name}_company_{column}
ON {table_name}(company_code, {column});
```
### 9.2 화면 관련 인덱스
```sql
-- screen_definitions
CREATE INDEX idx_screen_definitions_company_code ON screen_definitions(company_code);
CREATE INDEX idx_screen_definitions_table_name ON screen_definitions(table_name);
CREATE INDEX idx_screen_definitions_is_active ON screen_definitions(is_active);
CREATE UNIQUE INDEX idx_screen_definitions_code_company
ON screen_definitions(screen_code, company_code);
-- screen_groups
CREATE INDEX idx_screen_groups_company_code ON screen_groups(company_code);
CREATE INDEX idx_screen_groups_parent_id ON screen_groups(parent_group_id);
CREATE INDEX idx_screen_groups_hierarchy_path ON screen_groups(hierarchy_path);
-- screen_field_joins
CREATE INDEX idx_screen_field_joins_screen_id ON screen_field_joins(screen_id);
CREATE INDEX idx_screen_field_joins_save_table ON screen_field_joins(save_table);
CREATE INDEX idx_screen_field_joins_join_table ON screen_field_joins(join_table);
```
### 9.3 메타데이터 인덱스
```sql
-- table_type_columns
CREATE UNIQUE INDEX idx_table_type_columns_unique
ON table_type_columns(table_name, column_name, company_code);
-- column_labels
CREATE INDEX idx_column_labels_table ON column_labels(table_name);
```
### 9.4 비즈니스 테이블 인덱스 예시
```sql
-- sales_order_mng
CREATE INDEX idx_sales_order_company_code ON sales_order_mng(company_code);
CREATE INDEX idx_sales_order_customer ON sales_order_mng(customer_code);
CREATE INDEX idx_sales_order_date ON sales_order_mng(order_date DESC);
CREATE INDEX idx_sales_order_status ON sales_order_mng(order_status);
-- work_orders
CREATE INDEX idx_work_orders_company_code ON work_orders(company_code);
CREATE INDEX idx_work_orders_wo_number ON work_orders(wo_number);
CREATE INDEX idx_work_orders_start_date ON work_orders(start_date);
CREATE INDEX idx_work_orders_product_code ON work_orders(product_code);
```
### 9.5 플로우 관련 인덱스
```sql
-- flow_definition
CREATE UNIQUE INDEX idx_flow_definition_code_company
ON flow_definition(flow_code, company_code);
-- flow_step
CREATE INDEX idx_flow_step_flow_id ON flow_step(flow_id);
CREATE INDEX idx_flow_step_order ON flow_step(flow_id, step_order);
-- flow_data_status
CREATE INDEX idx_flow_data_status_flow_execution
ON flow_data_status(flow_id, execution_id);
CREATE INDEX idx_flow_data_status_source
ON flow_data_status(source_table, source_record_id);
```
---
## 10. 동적 테이블 생성 패턴
WACE ERP의 핵심 기능 중 하나는 **런타임에 테이블을 동적으로 생성**할 수 있다는 것입니다.
### 10.1 표준 컬럼 구조
**모든 동적 생성 테이블의 기본 컬럼:**
```sql
CREATE TABLE {dynamic_table_name} (
-- 시스템 기본 컬럼 (자동 포함)
id VARCHAR(500) PRIMARY KEY DEFAULT gen_random_uuid()::text,
created_date TIMESTAMP DEFAULT NOW(),
updated_date TIMESTAMP DEFAULT NOW(),
writer VARCHAR(500),
company_code VARCHAR(500),
-- 사용자 정의 컬럼 (모두 VARCHAR(500))
{user_column_1} VARCHAR(500),
{user_column_2} VARCHAR(500),
...
);
-- 필수 인덱스
CREATE INDEX idx_{table_name}_company_code ON {table_name}(company_code);
```
### 10.2 메타데이터 등록 프로세스
동적 테이블 생성 시 반드시 수행해야 하는 작업:
#### 1단계: 테이블 생성
```sql
CREATE TABLE {table_name} (
-- 위의 표준 구조 참조
);
```
#### 2단계: table_labels 등록
```sql
INSERT INTO table_labels (table_name, table_label, description, created_date, updated_date)
VALUES ('{table_name}', '{한글명}', '{설명}', NOW(), NOW())
ON CONFLICT (table_name)
DO UPDATE SET
table_label = EXCLUDED.table_label,
description = EXCLUDED.description,
updated_date = NOW();
```
#### 3단계: table_type_columns 등록
```sql
-- 기본 컬럼 등록 (display_order: -5 ~ -1)
INSERT INTO table_type_columns (
table_name, column_name, company_code, input_type, detail_settings,
is_nullable, display_order, created_date, updated_date
) VALUES
('{table_name}', 'id', '{company_code}', 'text', '{}', 'Y', -5, NOW(), NOW()),
('{table_name}', 'created_date', '{company_code}', 'date', '{}', 'Y', -4, NOW(), NOW()),
('{table_name}', 'updated_date', '{company_code}', 'date', '{}', 'Y', -3, NOW(), NOW()),
('{table_name}', 'writer', '{company_code}', 'text', '{}', 'Y', -2, NOW(), NOW()),
('{table_name}', 'company_code', '{company_code}', 'text', '{}', 'Y', -1, NOW(), NOW())
ON CONFLICT (table_name, column_name, company_code)
DO UPDATE SET
input_type = EXCLUDED.input_type,
display_order = EXCLUDED.display_order,
updated_date = NOW();
-- 사용자 정의 컬럼 등록 (display_order: 0부터 시작)
INSERT INTO table_type_columns (
table_name, column_name, company_code, input_type, detail_settings,
is_nullable, display_order, created_date, updated_date
) VALUES
('{table_name}', '{column_1}', '{company_code}', 'text', '{}', 'Y', 0, NOW(), NOW()),
('{table_name}', '{column_2}', '{company_code}', 'number', '{}', 'Y', 1, NOW(), NOW()),
...
```
#### 4단계: column_labels 등록 (레거시 호환용)
```sql
INSERT INTO column_labels (
table_name, column_name, column_label, input_type, detail_settings,
description, display_order, is_visible, created_date, updated_date
) VALUES
('{table_name}', 'id', 'ID', 'text', '{}', '기본키', -5, true, NOW(), NOW()),
...
ON CONFLICT (table_name, column_name)
DO UPDATE SET
column_label = EXCLUDED.column_label,
input_type = EXCLUDED.input_type,
updated_date = NOW();
```
### 10.3 마이그레이션 예시
**050_create_work_orders_table.sql:**
```sql
-- ============================================
-- 1. 테이블 생성
-- ============================================
CREATE TABLE work_orders (
id VARCHAR(500) PRIMARY KEY DEFAULT gen_random_uuid()::text,
created_date TIMESTAMP DEFAULT NOW(),
updated_date TIMESTAMP DEFAULT NOW(),
writer VARCHAR(500),
company_code VARCHAR(500),
wo_number VARCHAR(500),
product_code VARCHAR(500),
product_name VARCHAR(500),
...
);
CREATE INDEX idx_work_orders_company_code ON work_orders(company_code);
CREATE INDEX idx_work_orders_wo_number ON work_orders(wo_number);
-- ============================================
-- 2. table_labels 등록
-- ============================================
INSERT INTO table_labels (table_name, table_label, description, created_date, updated_date)
VALUES ('work_orders', '작업지시', '작업지시 관리 테이블', NOW(), NOW())
ON CONFLICT (table_name) DO UPDATE SET ...;
-- ============================================
-- 3. table_type_columns 등록
-- ============================================
INSERT INTO table_type_columns (...) VALUES (...);
-- ============================================
-- 4. column_labels 등록
-- ============================================
INSERT INTO column_labels (...) VALUES (...);
-- ============================================
-- 5. 코멘트 추가
-- ============================================
COMMENT ON TABLE work_orders IS '작업지시 관리 테이블';
COMMENT ON COLUMN work_orders.wo_number IS '작업지시번호 (WO-YYYYMMDD-XXX)';
```
---
## 11. 마이그레이션 히스토리
### 11.1 마이그레이션 파일 목록
```
db/migrations/
├── 037_add_parent_group_to_screen_groups.sql -- 화면 그룹 계층 구조
├── 050_create_work_orders_table.sql -- 작업지시 테이블
├── 051_insert_work_order_screen_definition.sql -- 작업지시 화면 정의
├── 052_insert_work_order_screen_layout.sql -- 작업지시 화면 레이아웃
├── 054_create_screen_management_enhancement.sql -- 화면 관리 기능 확장
└── plm_schema_20260120.sql -- 전체 스키마 덤프
```
### 11.2 주요 마이그레이션 내용
#### 037: 화면 그룹 계층 구조
- `screen_groups`에 계층 구조 지원 추가
- `parent_group_id`, `group_level`, `hierarchy_path` 컬럼 추가
- 대/중/소 분류 지원
#### 050~052: 작업지시 시스템
- `work_orders` 테이블 생성
- 메타데이터 등록 (table_labels, table_type_columns, column_labels)
- 화면 정의 및 레이아웃 생성
#### 054: 화면 관리 기능 확장
- `screen_groups`: 화면 그룹
- `screen_group_screens`: 화면-그룹 연결
- `screen_field_joins`: 화면 필드 조인 설정
- `screen_data_flows`: 화면 간 데이터 흐름
- `screen_table_relations`: 화면-테이블 관계
### 11.3 마이그레이션 실행 가이드
**마이그레이션 문서:**
- `RUN_027_MIGRATION.md`
- `RUN_043_MIGRATION.md`
- `RUN_044_MIGRATION.md`
- `RUN_046_MIGRATION.md`
- `RUN_063_064_MIGRATION.md`
- `RUN_065_MIGRATION.md`
- `RUN_078_MIGRATION.md`
---
## 12. 데이터베이스 함수 및 트리거
### 12.1 주요 함수
#### 화면 관련
```sql
-- 화면 생성 시 메뉴 자동 생성
CREATE FUNCTION auto_create_menu_for_screen() RETURNS TRIGGER;
-- 화면 삭제 시 메뉴 비활성화
CREATE FUNCTION auto_deactivate_menu_for_screen() RETURNS TRIGGER;
```
#### 통계 집계
```sql
-- 일일 운송 통계 집계
CREATE FUNCTION aggregate_daily_transport_statistics(target_date DATE) RETURNS INTEGER;
```
#### 거리 계산
```sql
-- Haversine 거리 계산
CREATE FUNCTION calculate_distance(lat1 NUMERIC, lng1 NUMERIC, lat2 NUMERIC, lng2 NUMERIC)
RETURNS NUMERIC;
-- 이전 위치로부터 거리 계산
CREATE FUNCTION calculate_distance_from_prev() RETURNS TRIGGER;
```
#### 비즈니스 로직
```sql
-- 수주 잔량 계산
CREATE FUNCTION calculate_order_balance() RETURNS TRIGGER;
-- 세금계산서 합계 계산
CREATE FUNCTION calculate_tax_invoice_total() RETURNS TRIGGER;
-- 영업에서 프로젝트 자동 생성
CREATE FUNCTION auto_create_project_from_sales(p_sales_no VARCHAR) RETURNS VARCHAR;
```
#### 로그 관리
```sql
-- 테이블 변경 로그 트리거 함수
CREATE FUNCTION carrier_contract_mng_log_trigger_func() RETURNS TRIGGER;
CREATE FUNCTION carrier_mng_log_trigger_func() RETURNS TRIGGER;
-- ... 각 테이블별 로그 트리거 함수
```
### 12.2 주요 트리거
```sql
-- 화면 생성 시 메뉴 자동 생성
CREATE TRIGGER trg_auto_create_menu_for_screen
AFTER INSERT ON screen_definitions
FOR EACH ROW
EXECUTE FUNCTION auto_create_menu_for_screen();
-- 화면 삭제 시 메뉴 비활성화
CREATE TRIGGER trg_auto_deactivate_menu_for_screen
AFTER UPDATE ON screen_definitions
FOR EACH ROW
EXECUTE FUNCTION auto_deactivate_menu_for_screen();
-- 차량 위치 이력 거리 계산
CREATE TRIGGER trg_calculate_distance_from_prev
BEFORE INSERT ON vehicle_location_history
FOR EACH ROW
EXECUTE FUNCTION calculate_distance_from_prev();
```
---
## 13. 뷰 (Views)
### 13.1 시스템 뷰
```sql
-- 권한 그룹 요약
CREATE VIEW v_authority_group_summary AS
SELECT
am.objid,
am.auth_name,
am.auth_code,
am.company_code,
(SELECT COUNT(*) FROM authority_sub_user WHERE master_objid = am.objid) AS member_count,
(SELECT COUNT(*) FROM rel_menu_auth WHERE auth_objid = am.objid) AS menu_count
FROM authority_master am;
```
---
## 14. 데이터베이스 보안 및 암호화
### 14.1 암호화 컬럼
```sql
-- external_db_connections
password_encrypted TEXT -- AES 암호화된 비밀번호
-- external_rest_api_connections
auth_config JSONB -- 암호화된 인증 정보
```
### 14.2 접근 제어
- PostgreSQL 롤 기반 접근 제어
- 회사별 데이터 격리 (company_code)
- 사용자별 권한 관리 (authority_master, rel_menu_auth)
---
## 15. 성능 최적화 전략
### 15.1 인덱스 최적화
- **company_code 인덱스**: 모든 테이블에 필수
- **복합 인덱스**: 자주 함께 조회되는 컬럼 조합
- **부분 인덱스**: 특정 조건의 데이터만 인덱싱
### 15.2 쿼리 최적화
- **서브쿼리 최소화**: JOIN으로 대체
- **EXPLAIN ANALYZE** 활용
- **인덱스 힌트** 사용
### 15.3 캐싱 전략
- **참조 데이터 캐싱**: referenceCacheService.ts
- **Redis 캐싱**: 자주 조회되는 메타데이터
### 15.4 파티셔닝
- 대용량 이력 테이블 파티셔닝 고려
- 날짜 기반 파티셔닝 (vehicle_location_history 등)
---
## 16. 백업 및 복구
### 16.1 백업 전략
```bash
# 전체 스키마 백업
pg_dump -h host -U user -d database > plm_schema_YYYYMMDD.sql
# 데이터 포함 백업
pg_dump -h host -U user -d database --data-only > data_YYYYMMDD.sql
# 특정 테이블 백업
pg_dump -h host -U user -d database -t table_name > table_backup.sql
```
### 16.2 마이그레이션 롤백
- DDL 작업 전 백업 필수
- 트랜잭션 기반 마이그레이션
- 롤백 스크립트 준비
---
## 17. 모니터링 및 로깅
### 17.1 시스템 로그 테이블
```
login_access_log -- 로그인 접근 로그
ddl_execution_log -- DDL 실행 로그
batch_execution_logs -- 배치 실행 로그
flow_audit_log -- 플로우 감사 로그
flow_integration_log -- 플로우 통합 로그
external_call_logs -- 외부 호출 로그
mail_log -- 메일 발송 로그
file_down_log -- 파일 다운로드 로그
```
### 17.2 변경 이력 테이블
**패턴:** `{원본테이블}_log` 또는 `{원본테이블}_history`
```
user_info_history
dept_info_history
authority_master_history
comm_code_history
carrier_mng_log
supplier_mng_log
equipment_mng_log
...
```
---
## 18. 결론
### 18.1 핵심 아키텍처 특징
1. **멀티테넌시**: company_code로 완벽한 데이터 격리
2. **메타데이터 드리븐**: 동적 화면/테이블 생성
3. **Low-Code 플랫폼**: 코드 없이 화면 구축
4. **플로우 기반**: 시각적 데이터 흐름 설계
5. **외부 연동**: DB/API 통합 지원
6. **이력 관리**: 완벽한 변경 이력 추적
### 18.2 확장성
- **수평 확장**: 멀티테넌시로 무한한 회사 추가 가능
- **수직 확장**: 동적 테이블/컬럼 추가
- **기능 확장**: 플로우/배치 작업으로 비즈니스 로직 추가
### 18.3 유지보수성
- **표준화된 구조**: 모든 테이블이 동일한 패턴
- **자동화**: 트리거/함수로 반복 작업 자동화
- **문서화**: 메타데이터 테이블 자체가 문서
---
## 부록 A: 백엔드 서비스 매핑
### 주요 서비스와 테이블 매핑
```typescript
// backend-node/src/services/
screenManagementService.ts → screen_definitions, screen_layouts
tableManagementService.ts → table_labels, table_type_columns, column_labels
menuService.ts → menu_info, menu_screen_groups
categoryTreeService.ts → table_column_category_values
flowDefinitionService.ts → flow_definition, flow_step
flowExecutionService.ts → flow_data_status, flow_audit_log
dataflowService.ts → dataflow_diagrams, screen_data_flows
externalDbConnectionService.ts → external_db_connections
externalRestApiConnectionService.ts → external_rest_api_connections
batchService.ts → batch_jobs, batch_execution_logs
authService.ts → user_info, auth_tokens
roleService.ts → authority_master, rel_menu_auth
```
---
## 부록 B: SQL 쿼리 예시
### 멀티테넌시 표준 쿼리
```sql
-- ✅ 단일 테이블 조회
SELECT * FROM sales_order_mng
WHERE company_code = $1
AND company_code != '*'
AND order_date >= $2
ORDER BY order_date DESC
LIMIT 100;
-- ✅ JOIN 쿼리
SELECT
so.order_no,
so.order_date,
c.customer_name,
p.product_name,
so.quantity,
so.unit_price
FROM sales_order_mng so
LEFT JOIN customer_mng c
ON so.customer_code = c.customer_code
AND so.company_code = c.company_code
LEFT JOIN product_mng p
ON so.product_code = p.product_code
AND so.company_code = p.company_code
WHERE so.company_code = $1
AND so.company_code != '*'
AND so.order_date BETWEEN $2 AND $3;
-- ✅ 집계 쿼리
SELECT
customer_code,
COUNT(*) as order_count,
SUM(total_amount) as total_sales
FROM sales_order_mng
WHERE company_code = $1
AND company_code != '*'
AND order_date >= DATE_TRUNC('month', CURRENT_DATE)
GROUP BY customer_code
HAVING COUNT(*) >= 5
ORDER BY total_sales DESC;
```
---
## 부록 C: 참고 문서
```
docs/
├── DDD1542/
│ ├── DB_STRUCTURE_DIAGRAM.md -- DB 구조 다이어그램
│ ├── DB_INEFFICIENCY_ANALYSIS.md -- DB 비효율성 분석
│ ├── COMPONENT_URL_SYSTEM_IMPLEMENTATION.md
│ ├── V2_마이그레이션_학습노트_DDD1542.md
│ └── 본서버_개발서버_마이그레이션_가이드.md
├── backend-architecture-analysis.md -- 백엔드 아키텍처 분석
└── screen-implementation-guide/ -- 화면 구현 가이드
```
---
**문서 작성자**: Cursor AI (DB Specialist Agent)
**문서 버전**: 1.0
**마지막 업데이트**: 2026-01-20
**스키마 버전**: plm_schema_20260120.sql
---