# 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 주요 테이블 목록 (알파벳순)
전체 테이블 목록 보기 (280개) ``` 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 ```
--- ## 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 ---