Some checks failed
SonarQube Analysis / SonarQube Scan (push) Has been cancelled
- 사용자 요구사항 저장/로드/엑셀 내보내기 기능 완전 구현 - 백엔드 API 수정: Request Body 방식으로 변경 - 데이터베이스 스키마: material_id 컬럼 추가 - 프론트엔드 상태 관리 개선: 저장 후 자동 리로드 - 입력 필드 연결 문제 해결: 누락된 onChange 핸들러 추가 - NewMaterialsPage에 '전체' 카테고리 버튼 추가 (기본 선택) - Docker 환경 개선: 프론트엔드 볼륨 마운트 및 포트 수정 - UI 개선: 벌레 이모지 제거, 디버그 코드 정리
1570 lines
60 KiB
PL/PgSQL
1570 lines
60 KiB
PL/PgSQL
-- ================================
|
|
-- TK-MP-Project 통합 데이터베이스 스키마
|
|
-- 다른 환경 배포용 완전한 초기화 스크립트
|
|
-- 생성일: 2025.09.09
|
|
-- ================================
|
|
|
|
-- ================================
|
|
-- 1. 기본 스키마 (01_schema.sql 기반)
|
|
-- ================================
|
|
|
|
-- 프로젝트 기본 정보
|
|
CREATE TABLE IF NOT EXISTS projects (
|
|
id SERIAL PRIMARY KEY,
|
|
|
|
-- 회사 공식 정보
|
|
official_project_code VARCHAR(50) UNIQUE, -- PP5-5701-DRYING (정식 코드)
|
|
project_name VARCHAR(200) NOT NULL,
|
|
client_name VARCHAR(100),
|
|
|
|
-- 설계팀 사용 정보
|
|
design_project_code VARCHAR(50), -- 설계팀이 실제 사용한 코드
|
|
design_project_name VARCHAR(200), -- 설계팀이 사용한 프로젝트명
|
|
|
|
-- 매칭 정보
|
|
is_code_matched BOOLEAN DEFAULT false, -- 정식 코드 매칭 완료 여부
|
|
matched_by VARCHAR(100), -- 매칭 작업자
|
|
matched_at TIMESTAMP, -- 매칭 완료 시점
|
|
|
|
-- 기본 정보
|
|
status VARCHAR(20) DEFAULT 'active', -- active/completed/on_hold
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
description TEXT,
|
|
notes TEXT
|
|
);
|
|
|
|
-- 업로드된 자재 목록 파일들
|
|
CREATE TABLE IF NOT EXISTS files (
|
|
id SERIAL PRIMARY KEY,
|
|
project_id INTEGER REFERENCES projects(id) ON DELETE CASCADE,
|
|
filename VARCHAR(255) NOT NULL,
|
|
original_filename VARCHAR(255) NOT NULL,
|
|
file_path VARCHAR(500) NOT NULL,
|
|
revision VARCHAR(20) DEFAULT 'Rev.0', -- Rev.0, Rev.1, Rev.2
|
|
upload_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
uploaded_by VARCHAR(100),
|
|
file_type VARCHAR(10), -- excel/csv/txt
|
|
file_size INTEGER,
|
|
is_active BOOLEAN DEFAULT true,
|
|
|
|
-- 추가 필드 (19_add_user_tracking_fields.sql)
|
|
updated_by VARCHAR(100),
|
|
bom_name VARCHAR(200), -- BOM 이름 필드 추가
|
|
|
|
-- 분류 관련 필드 (05_add_classification_columns.sql)
|
|
classification_stats JSONB,
|
|
classification_completed BOOLEAN DEFAULT FALSE,
|
|
classification_timestamp TIMESTAMP,
|
|
|
|
-- Job 연결 필드 (02_modify_files_table.sql)
|
|
job_no VARCHAR(50),
|
|
|
|
-- 파싱 통계 필드
|
|
parsed_count INTEGER DEFAULT 0
|
|
);
|
|
|
|
-- 개별 자재 상세 정보
|
|
CREATE TABLE IF NOT EXISTS materials (
|
|
id SERIAL PRIMARY KEY,
|
|
file_id INTEGER REFERENCES files(id) ON DELETE CASCADE,
|
|
line_number INTEGER, -- Excel 행 번호
|
|
row_number INTEGER, -- 실제 행 번호
|
|
original_description TEXT NOT NULL, -- 원본 품명
|
|
|
|
-- 분류 정보
|
|
classified_category VARCHAR(50), -- 파이프/피팅/볼트/밸브/계기
|
|
classified_subcategory VARCHAR(100), -- 엘보우/플랜지/벤드 등
|
|
|
|
-- 재질 및 스펙
|
|
material_grade VARCHAR(50), -- A333-6, A105, SS316
|
|
schedule VARCHAR(20), -- SCH40, SCH80, STD
|
|
size_spec VARCHAR(50), -- 6인치, 150A, M16
|
|
main_nom VARCHAR(50), -- 주 호칭 사이즈
|
|
red_nom VARCHAR(50), -- 축소 호칭 사이즈
|
|
|
|
-- 수량 정보
|
|
quantity DECIMAL(10,3) NOT NULL,
|
|
unit VARCHAR(10) NOT NULL, -- EA/mm/SET/kg
|
|
|
|
-- 도면 정보
|
|
drawing_name VARCHAR(100), -- P&ID-001-TANK
|
|
area_code VARCHAR(20), -- #01, #02, #03
|
|
line_no VARCHAR(50), -- LINE-001-A
|
|
|
|
-- 분류 신뢰도 및 검증
|
|
classification_confidence DECIMAL(3,2), -- 0.00-1.00 분류 신뢰도
|
|
classification_details JSONB, -- 분류 상세 정보 (JSON)
|
|
is_verified BOOLEAN DEFAULT false, -- 사용자 검증 여부
|
|
verified_by VARCHAR(100),
|
|
verified_at TIMESTAMP,
|
|
|
|
-- 구매 관련 필드
|
|
purchase_confirmed BOOLEAN DEFAULT false,
|
|
confirmed_quantity DECIMAL(10,3),
|
|
purchase_status VARCHAR(20),
|
|
purchase_confirmed_by VARCHAR(100),
|
|
purchase_confirmed_at TIMESTAMP,
|
|
|
|
-- 길이 정보 (05_add_length_to_materials.sql)
|
|
length NUMERIC(10, 3),
|
|
|
|
-- 사용자 추적 필드 (19_add_user_tracking_fields.sql)
|
|
classified_by VARCHAR(100),
|
|
classified_at TIMESTAMP,
|
|
updated_by VARCHAR(100),
|
|
|
|
-- 분류 상세 필드 (05_add_classification_columns.sql)
|
|
subcategory VARCHAR(100),
|
|
standard VARCHAR(200),
|
|
grade VARCHAR(200),
|
|
|
|
-- 해시 필드 (10_add_material_comparison_system.sql)
|
|
material_hash VARCHAR(64),
|
|
normalized_description TEXT,
|
|
|
|
-- 기타
|
|
drawing_reference VARCHAR(100),
|
|
notes TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- ================================
|
|
-- 2. 자재 상세 정보 테이블들 (create_material_detail_tables.sql)
|
|
-- ================================
|
|
|
|
-- PIPE 상세 테이블
|
|
CREATE TABLE IF NOT EXISTS pipe_details (
|
|
id SERIAL PRIMARY KEY,
|
|
material_id INTEGER REFERENCES materials(id) ON DELETE CASCADE,
|
|
file_id INTEGER REFERENCES files(id) ON DELETE CASCADE,
|
|
|
|
-- 파이프 기본 정보
|
|
outer_diameter VARCHAR(50),
|
|
schedule VARCHAR(50),
|
|
material_spec VARCHAR(100),
|
|
manufacturing_method VARCHAR(50),
|
|
end_preparation VARCHAR(50),
|
|
|
|
-- 길이 정보
|
|
length_mm DECIMAL(10,3),
|
|
|
|
-- 신뢰도
|
|
classification_confidence FLOAT,
|
|
|
|
-- 추가 정보
|
|
additional_info JSONB,
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- FITTING 상세 테이블
|
|
CREATE TABLE IF NOT EXISTS fitting_details (
|
|
id SERIAL PRIMARY KEY,
|
|
material_id INTEGER REFERENCES materials(id) ON DELETE CASCADE,
|
|
file_id INTEGER REFERENCES files(id) ON DELETE CASCADE,
|
|
|
|
-- 피팅 타입 정보
|
|
fitting_type VARCHAR(50),
|
|
fitting_subtype VARCHAR(50),
|
|
|
|
-- 연결 방식
|
|
connection_method VARCHAR(50),
|
|
connection_code VARCHAR(50),
|
|
|
|
-- 압력 등급
|
|
pressure_rating VARCHAR(50),
|
|
max_pressure VARCHAR(50),
|
|
|
|
-- 제작 방법
|
|
manufacturing_method VARCHAR(50),
|
|
|
|
-- 재질 정보
|
|
material_standard VARCHAR(100),
|
|
material_grade VARCHAR(100),
|
|
material_type VARCHAR(50),
|
|
|
|
-- 사이즈 정보
|
|
main_size VARCHAR(50),
|
|
reduced_size VARCHAR(50),
|
|
|
|
-- 길이 정보 (니플용)
|
|
length_mm DECIMAL(10,3),
|
|
schedule VARCHAR(50),
|
|
|
|
-- 신뢰도
|
|
classification_confidence FLOAT,
|
|
|
|
-- 추가 정보
|
|
additional_info JSONB,
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- VALVE 상세 테이블
|
|
CREATE TABLE IF NOT EXISTS valve_details (
|
|
id SERIAL PRIMARY KEY,
|
|
material_id INTEGER REFERENCES materials(id) ON DELETE CASCADE,
|
|
file_id INTEGER REFERENCES files(id) ON DELETE CASCADE,
|
|
|
|
-- 밸브 타입 정보
|
|
valve_type VARCHAR(50),
|
|
valve_subtype VARCHAR(50),
|
|
actuator_type VARCHAR(50),
|
|
|
|
-- 연결 방식
|
|
connection_method VARCHAR(50),
|
|
|
|
-- 압력 등급
|
|
pressure_rating VARCHAR(50),
|
|
pressure_class VARCHAR(50),
|
|
|
|
-- 재질 정보
|
|
body_material VARCHAR(100),
|
|
trim_material VARCHAR(100),
|
|
|
|
-- 사이즈 정보
|
|
size_inches VARCHAR(50),
|
|
|
|
-- 특수 사양
|
|
fire_safe BOOLEAN,
|
|
low_temp_service BOOLEAN,
|
|
special_features JSONB,
|
|
|
|
-- 신뢰도
|
|
classification_confidence FLOAT,
|
|
|
|
-- 추가 정보
|
|
additional_info JSONB,
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- FLANGE 상세 테이블
|
|
CREATE TABLE IF NOT EXISTS flange_details (
|
|
id SERIAL PRIMARY KEY,
|
|
material_id INTEGER REFERENCES materials(id) ON DELETE CASCADE,
|
|
file_id INTEGER REFERENCES files(id) ON DELETE CASCADE,
|
|
|
|
-- 플랜지 타입
|
|
flange_type VARCHAR(50),
|
|
facing_type VARCHAR(50),
|
|
|
|
-- 압력 등급
|
|
pressure_rating VARCHAR(50),
|
|
|
|
-- 재질 정보
|
|
material_standard VARCHAR(100),
|
|
material_grade VARCHAR(100),
|
|
|
|
-- 사이즈 정보
|
|
size_inches VARCHAR(50),
|
|
bolt_hole_count INTEGER,
|
|
bolt_hole_size VARCHAR(50),
|
|
|
|
-- 신뢰도
|
|
classification_confidence FLOAT,
|
|
|
|
-- 추가 정보
|
|
additional_info JSONB,
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- BOLT 상세 테이블
|
|
CREATE TABLE IF NOT EXISTS bolt_details (
|
|
id SERIAL PRIMARY KEY,
|
|
material_id INTEGER REFERENCES materials(id) ON DELETE CASCADE,
|
|
file_id INTEGER REFERENCES files(id) ON DELETE CASCADE,
|
|
|
|
-- 볼트 타입
|
|
bolt_type VARCHAR(50),
|
|
thread_type VARCHAR(50),
|
|
|
|
-- 사양 정보
|
|
diameter VARCHAR(50),
|
|
length VARCHAR(50),
|
|
|
|
-- 재질 정보
|
|
material_standard VARCHAR(100),
|
|
material_grade VARCHAR(100),
|
|
coating_type VARCHAR(100),
|
|
|
|
-- 압력 등급 (06_add_pressure_rating_to_bolt_details.sql)
|
|
pressure_rating VARCHAR(50),
|
|
|
|
-- 너트/와셔 정보
|
|
includes_nut BOOLEAN,
|
|
includes_washer BOOLEAN,
|
|
nut_type VARCHAR(50),
|
|
washer_type VARCHAR(50),
|
|
|
|
-- 신뢰도
|
|
classification_confidence FLOAT,
|
|
|
|
-- 추가 정보
|
|
additional_info JSONB,
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- GASKET 상세 테이블
|
|
CREATE TABLE IF NOT EXISTS gasket_details (
|
|
id SERIAL PRIMARY KEY,
|
|
material_id INTEGER REFERENCES materials(id) ON DELETE CASCADE,
|
|
file_id INTEGER REFERENCES files(id) ON DELETE CASCADE,
|
|
|
|
-- 가스켓 타입
|
|
gasket_type VARCHAR(50),
|
|
gasket_subtype VARCHAR(50),
|
|
|
|
-- 재질 정보
|
|
material_type VARCHAR(100),
|
|
filler_material VARCHAR(100),
|
|
|
|
-- 사이즈 및 등급
|
|
size_inches VARCHAR(50),
|
|
pressure_rating VARCHAR(50),
|
|
thickness VARCHAR(50),
|
|
|
|
-- 특수 사양
|
|
temperature_range VARCHAR(100),
|
|
fire_safe BOOLEAN,
|
|
|
|
-- 신뢰도
|
|
classification_confidence FLOAT,
|
|
|
|
-- 추가 정보
|
|
additional_info JSONB,
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- INSTRUMENT 상세 테이블
|
|
CREATE TABLE IF NOT EXISTS instrument_details (
|
|
id SERIAL PRIMARY KEY,
|
|
material_id INTEGER REFERENCES materials(id) ON DELETE CASCADE,
|
|
file_id INTEGER REFERENCES files(id) ON DELETE CASCADE,
|
|
|
|
-- 계장품 타입
|
|
instrument_type VARCHAR(50),
|
|
instrument_subtype VARCHAR(50),
|
|
|
|
-- 측정 사양
|
|
measurement_type VARCHAR(50),
|
|
measurement_range VARCHAR(100),
|
|
accuracy VARCHAR(50),
|
|
|
|
-- 연결 정보
|
|
connection_type VARCHAR(50),
|
|
connection_size VARCHAR(50),
|
|
|
|
-- 재질 정보
|
|
body_material VARCHAR(100),
|
|
wetted_parts_material VARCHAR(100),
|
|
|
|
-- 전기 사양
|
|
electrical_rating VARCHAR(100),
|
|
output_signal VARCHAR(50),
|
|
|
|
-- 신뢰도
|
|
classification_confidence FLOAT,
|
|
|
|
-- 추가 정보
|
|
additional_info JSONB,
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- ================================
|
|
-- 3. 파이프 끝단 가공 테이블 (20_add_pipe_end_preparation_table.sql)
|
|
-- ================================
|
|
|
|
CREATE TABLE IF NOT EXISTS pipe_end_preparations (
|
|
id SERIAL PRIMARY KEY,
|
|
material_id INTEGER NOT NULL REFERENCES materials(id) ON DELETE CASCADE,
|
|
file_id INTEGER NOT NULL REFERENCES files(id) ON DELETE CASCADE,
|
|
|
|
-- 끝단 가공 정보
|
|
end_preparation_type VARCHAR(50) DEFAULT 'PBE', -- PBE(양쪽무개선), BBE(양쪽개선), POE(한쪽개선), PE(무개선)
|
|
end_preparation_code VARCHAR(20), -- 원본 코드 (BBE, POE, PBE 등)
|
|
machining_required BOOLEAN DEFAULT FALSE, -- 가공 필요 여부
|
|
cutting_note TEXT, -- 가공 메모
|
|
|
|
-- 원본 정보 보존
|
|
original_description TEXT NOT NULL, -- 끝단 가공 포함된 원본 설명
|
|
clean_description TEXT NOT NULL, -- 끝단 가공 제외한 구매용 설명
|
|
|
|
-- 메타데이터
|
|
confidence FLOAT DEFAULT 0.0, -- 분류 신뢰도
|
|
matched_pattern VARCHAR(100), -- 매칭된 패턴
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- ================================
|
|
-- 4. 인증 시스템 테이블들 (18_create_auth_tables.sql)
|
|
-- ================================
|
|
|
|
-- 사용자 테이블
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
user_id SERIAL PRIMARY KEY,
|
|
username VARCHAR(50) UNIQUE NOT NULL,
|
|
password VARCHAR(255) NOT NULL,
|
|
name VARCHAR(100) NOT NULL,
|
|
email VARCHAR(100),
|
|
|
|
-- 권한 관리
|
|
role VARCHAR(20) DEFAULT 'user' CHECK (role IN ('admin', 'system', 'leader', 'support', 'user')),
|
|
access_level VARCHAR(20) DEFAULT 'worker' CHECK (access_level IN ('admin', 'system', 'group_leader', 'support_team', 'worker')),
|
|
|
|
-- 계정 상태 관리
|
|
is_active BOOLEAN DEFAULT true,
|
|
failed_login_attempts INT DEFAULT 0,
|
|
locked_until TIMESTAMP NULL,
|
|
|
|
-- 추가 정보
|
|
department VARCHAR(50),
|
|
position VARCHAR(50),
|
|
phone VARCHAR(20),
|
|
|
|
-- 타임스탬프
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
last_login_at TIMESTAMP NULL
|
|
);
|
|
|
|
-- 로그인 이력 테이블
|
|
CREATE TABLE IF NOT EXISTS login_logs (
|
|
log_id SERIAL PRIMARY KEY,
|
|
user_id INT REFERENCES users(user_id) ON DELETE CASCADE,
|
|
login_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
ip_address VARCHAR(45),
|
|
user_agent TEXT,
|
|
login_status VARCHAR(20) CHECK (login_status IN ('success', 'failed')),
|
|
failure_reason VARCHAR(100),
|
|
session_duration INT, -- 세션 지속 시간 (초)
|
|
|
|
-- 인덱스를 위한 컬럼
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- 사용자 세션 테이블 (JWT Refresh Token 관리)
|
|
CREATE TABLE IF NOT EXISTS user_sessions (
|
|
session_id SERIAL PRIMARY KEY,
|
|
user_id INT REFERENCES users(user_id) ON DELETE CASCADE,
|
|
refresh_token VARCHAR(500) NOT NULL,
|
|
expires_at TIMESTAMP NOT NULL,
|
|
ip_address VARCHAR(45),
|
|
user_agent TEXT,
|
|
is_active BOOLEAN DEFAULT true,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- 권한 테이블
|
|
CREATE TABLE IF NOT EXISTS permissions (
|
|
permission_id SERIAL PRIMARY KEY,
|
|
permission_name VARCHAR(50) UNIQUE NOT NULL,
|
|
description TEXT,
|
|
module VARCHAR(30), -- 모듈별 권한 관리 (bom, project, purchase 등)
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- 역할-권한 매핑 테이블
|
|
CREATE TABLE IF NOT EXISTS role_permissions (
|
|
role_permission_id SERIAL PRIMARY KEY,
|
|
role VARCHAR(20) NOT NULL,
|
|
permission_id INT REFERENCES permissions(permission_id) ON DELETE CASCADE,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE(role, permission_id)
|
|
);
|
|
|
|
-- ================================
|
|
-- 5. 구매 관리 테이블들 (08_create_purchase_tables.sql)
|
|
-- ================================
|
|
|
|
-- 구매 품목 마스터 테이블
|
|
CREATE TABLE IF NOT EXISTS purchase_items (
|
|
id SERIAL PRIMARY KEY,
|
|
|
|
-- 품목 식별
|
|
item_code VARCHAR(100) UNIQUE NOT NULL, -- PI-PIPE-A106-4IN-001
|
|
category VARCHAR(50) NOT NULL, -- PIPE, VALVE, FITTING 등
|
|
specification TEXT NOT NULL, -- 상세 사양
|
|
|
|
-- 기본 정보
|
|
material_spec VARCHAR(200), -- ASTM A106 GR B
|
|
size_spec VARCHAR(100), -- 4", 1-1/2" x 1"
|
|
unit VARCHAR(10) NOT NULL, -- EA, mm, SET
|
|
|
|
-- BOM 수량 정보
|
|
bom_quantity DECIMAL(10,3) NOT NULL, -- BOM상 필요 수량
|
|
|
|
-- 구매 계산 정보
|
|
safety_factor DECIMAL(3,2) DEFAULT 1.10, -- 여유율 (1.1 = 10% 추가)
|
|
minimum_order_qty DECIMAL(10,3) DEFAULT 0, -- 최소 주문 수량
|
|
order_unit_qty DECIMAL(10,3) DEFAULT 1, -- 주문 단위 (박스, 롤 등)
|
|
calculated_qty DECIMAL(10,3), -- 최종 계산된 구매 수량
|
|
|
|
-- PIPE 전용 정보
|
|
cutting_loss DECIMAL(10,3) DEFAULT 0, -- 절단 손실 (mm)
|
|
standard_length DECIMAL(10,3), -- 표준 길이 (PIPE: 6000mm)
|
|
pipes_count INTEGER, -- 필요한 파이프 본수
|
|
waste_length DECIMAL(10,3), -- 여유분 길이
|
|
|
|
-- 상세 스펙 (JSON)
|
|
detailed_spec JSONB, -- 압력등급, 연결방식 등 상세 정보
|
|
|
|
-- 구매 정보
|
|
preferred_supplier VARCHAR(200), -- 선호 공급업체
|
|
last_unit_price DECIMAL(10,2), -- 최근 단가
|
|
currency VARCHAR(10) DEFAULT 'KRW', -- 통화
|
|
lead_time_days INTEGER DEFAULT 30, -- 리드타임
|
|
|
|
-- 연결 정보
|
|
job_no VARCHAR(50) NOT NULL, -- Job 번호
|
|
revision VARCHAR(20) DEFAULT 'Rev.0', -- 리비전
|
|
file_id INTEGER, -- 원본 파일 ID
|
|
|
|
-- 관리 정보
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
created_by VARCHAR(100),
|
|
updated_by VARCHAR(100),
|
|
approved_by VARCHAR(100),
|
|
approved_at TIMESTAMP,
|
|
|
|
-- 외래키
|
|
FOREIGN KEY (file_id) REFERENCES files(id) ON DELETE SET NULL
|
|
);
|
|
|
|
-- 개별 자재와 구매품목 연결 테이블
|
|
CREATE TABLE IF NOT EXISTS material_purchase_mapping (
|
|
id SERIAL PRIMARY KEY,
|
|
material_id INTEGER NOT NULL, -- materials 테이블 ID
|
|
purchase_item_id INTEGER NOT NULL, -- purchase_items 테이블 ID
|
|
quantity_ratio DECIMAL(5,2) DEFAULT 1.0, -- 변환 비율
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
-- 외래키
|
|
FOREIGN KEY (material_id) REFERENCES materials(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (purchase_item_id) REFERENCES purchase_items(id) ON DELETE CASCADE,
|
|
|
|
-- 유니크 제약
|
|
UNIQUE(material_id, purchase_item_id)
|
|
);
|
|
|
|
-- 구매 추적 테이블
|
|
CREATE TABLE IF NOT EXISTS material_purchase_tracking (
|
|
id SERIAL PRIMARY KEY,
|
|
material_hash VARCHAR(64) NOT NULL,
|
|
|
|
-- 기본 정보
|
|
original_description TEXT NOT NULL,
|
|
size_spec VARCHAR(50),
|
|
material_grade VARCHAR(50),
|
|
|
|
-- 수량 정보
|
|
bom_quantity DECIMAL(10,3) NOT NULL,
|
|
confirmed_quantity DECIMAL(10,3),
|
|
purchase_quantity DECIMAL(10,3),
|
|
|
|
-- 상태 관리
|
|
status VARCHAR(20) DEFAULT 'pending',
|
|
confirmed_by VARCHAR(100),
|
|
confirmed_at TIMESTAMP,
|
|
ordered_by VARCHAR(100),
|
|
ordered_at TIMESTAMP,
|
|
approved_by VARCHAR(100),
|
|
approved_at TIMESTAMP,
|
|
|
|
-- 메타데이터
|
|
job_no VARCHAR(50),
|
|
revision VARCHAR(20),
|
|
file_id INTEGER,
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
FOREIGN KEY (file_id) REFERENCES files(id) ON DELETE SET NULL
|
|
);
|
|
|
|
-- ================================
|
|
-- 6. Jobs 테이블 (01_create_jobs_table.sql)
|
|
-- ================================
|
|
|
|
CREATE TABLE IF NOT EXISTS jobs (
|
|
-- 기본 정보
|
|
job_no VARCHAR(50) PRIMARY KEY,
|
|
job_name VARCHAR(200) NOT NULL,
|
|
|
|
-- 계약 관계 (핵심)
|
|
client_name VARCHAR(100) NOT NULL,
|
|
|
|
-- 프로젝트 정보
|
|
end_user VARCHAR(100),
|
|
epc_company VARCHAR(100),
|
|
project_site VARCHAR(200),
|
|
|
|
-- 상업 정보
|
|
contract_date DATE,
|
|
delivery_date DATE,
|
|
delivery_terms VARCHAR(100),
|
|
|
|
-- 상태 관리 (핵심)
|
|
status VARCHAR(20) DEFAULT '진행중',
|
|
delivery_completed_date DATE,
|
|
project_closed_date DATE,
|
|
|
|
-- 관리 정보
|
|
description TEXT,
|
|
created_by VARCHAR(50),
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
is_active BOOLEAN DEFAULT true,
|
|
|
|
-- 사용자 추적 필드 (19_add_user_tracking_fields.sql)
|
|
updated_by VARCHAR(100),
|
|
assigned_to VARCHAR(100),
|
|
|
|
-- 프로젝트 타입 필드 (17_add_project_type_column.sql)
|
|
project_type VARCHAR(50) DEFAULT '냉동기' NOT NULL
|
|
);
|
|
|
|
-- ================================
|
|
-- 7. 자재 규격/재질 기준표 테이블들 (05_create_material_standards_tables.sql)
|
|
-- ================================
|
|
|
|
-- 자재 규격 표준 테이블
|
|
CREATE TABLE IF NOT EXISTS material_standards (
|
|
id SERIAL PRIMARY KEY,
|
|
standard_code VARCHAR(20) UNIQUE NOT NULL,
|
|
standard_name VARCHAR(100) NOT NULL,
|
|
description TEXT,
|
|
country VARCHAR(50),
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- 제조방식별 카테고리 테이블
|
|
CREATE TABLE IF NOT EXISTS material_categories (
|
|
id SERIAL PRIMARY KEY,
|
|
standard_id INTEGER REFERENCES material_standards(id),
|
|
category_code VARCHAR(50) NOT NULL,
|
|
category_name VARCHAR(100) NOT NULL,
|
|
description TEXT,
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- 구체적인 규격 테이블
|
|
CREATE TABLE IF NOT EXISTS material_specifications (
|
|
id SERIAL PRIMARY KEY,
|
|
category_id INTEGER REFERENCES material_categories(id),
|
|
spec_code VARCHAR(20) NOT NULL,
|
|
spec_name VARCHAR(100) NOT NULL,
|
|
description TEXT,
|
|
material_type VARCHAR(50),
|
|
manufacturing VARCHAR(50),
|
|
pressure_rating VARCHAR(100),
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- 등급별 상세 정보 테이블
|
|
CREATE TABLE IF NOT EXISTS material_grades (
|
|
id SERIAL PRIMARY KEY,
|
|
specification_id INTEGER REFERENCES material_specifications(id),
|
|
grade_code VARCHAR(20) NOT NULL,
|
|
grade_name VARCHAR(100),
|
|
composition VARCHAR(200),
|
|
applications VARCHAR(200),
|
|
temp_max VARCHAR(50),
|
|
temp_range VARCHAR(100),
|
|
yield_strength VARCHAR(50),
|
|
tensile_strength VARCHAR(50),
|
|
corrosion_resistance VARCHAR(50),
|
|
stabilizer VARCHAR(50),
|
|
base_grade VARCHAR(20),
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- 정규식 패턴 테이블
|
|
CREATE TABLE IF NOT EXISTS material_patterns (
|
|
id SERIAL PRIMARY KEY,
|
|
specification_id INTEGER REFERENCES material_specifications(id),
|
|
pattern TEXT NOT NULL,
|
|
description VARCHAR(200),
|
|
priority INTEGER DEFAULT 1,
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- 특수 재질 테이블
|
|
CREATE TABLE IF NOT EXISTS special_materials (
|
|
id SERIAL PRIMARY KEY,
|
|
material_type VARCHAR(50) NOT NULL,
|
|
material_name VARCHAR(100) NOT NULL,
|
|
description TEXT,
|
|
composition VARCHAR(200),
|
|
applications TEXT,
|
|
temp_max VARCHAR(50),
|
|
manufacturing VARCHAR(50),
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- 특수 재질 등급 테이블
|
|
CREATE TABLE IF NOT EXISTS special_material_grades (
|
|
id SERIAL PRIMARY KEY,
|
|
material_id INTEGER REFERENCES special_materials(id),
|
|
grade_code VARCHAR(20) NOT NULL,
|
|
composition VARCHAR(200),
|
|
applications VARCHAR(200),
|
|
temp_max VARCHAR(50),
|
|
strength VARCHAR(50),
|
|
purity VARCHAR(100),
|
|
corrosion VARCHAR(50),
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- 특수 재질 정규식 패턴 테이블
|
|
CREATE TABLE IF NOT EXISTS special_material_patterns (
|
|
id SERIAL PRIMARY KEY,
|
|
material_id INTEGER REFERENCES special_materials(id),
|
|
pattern TEXT NOT NULL,
|
|
description VARCHAR(200),
|
|
priority INTEGER DEFAULT 1,
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- ================================
|
|
-- 8. 자재 비교 및 발주 추적 시스템 (10_add_material_comparison_system.sql)
|
|
-- ================================
|
|
|
|
-- 자재 비교 결과 저장 테이블
|
|
CREATE TABLE IF NOT EXISTS material_revisions_comparison (
|
|
id SERIAL PRIMARY KEY,
|
|
|
|
-- 비교 기본 정보
|
|
job_no VARCHAR(50) NOT NULL,
|
|
current_revision VARCHAR(20) NOT NULL,
|
|
previous_revision VARCHAR(20) NOT NULL,
|
|
current_file_id INTEGER NOT NULL,
|
|
previous_file_id INTEGER NOT NULL,
|
|
|
|
-- 비교 결과 요약
|
|
total_current_items INTEGER DEFAULT 0,
|
|
total_previous_items INTEGER DEFAULT 0,
|
|
new_items_count INTEGER DEFAULT 0,
|
|
modified_items_count INTEGER DEFAULT 0,
|
|
removed_items_count INTEGER DEFAULT 0,
|
|
unchanged_items_count INTEGER DEFAULT 0,
|
|
|
|
-- 상세 결과 (JSON)
|
|
comparison_details JSONB,
|
|
|
|
-- 관리 정보
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
created_by VARCHAR(100),
|
|
|
|
-- 외래키
|
|
FOREIGN KEY (current_file_id) REFERENCES files(id),
|
|
FOREIGN KEY (previous_file_id) REFERENCES files(id),
|
|
|
|
-- 유니크 제약 (같은 비교는 한 번만)
|
|
UNIQUE(job_no, current_revision, previous_revision)
|
|
);
|
|
|
|
-- 개별 자재 비교 상세 테이블
|
|
CREATE TABLE IF NOT EXISTS material_comparison_details (
|
|
id SERIAL PRIMARY KEY,
|
|
|
|
comparison_id INTEGER NOT NULL,
|
|
material_hash VARCHAR(32) NOT NULL,
|
|
|
|
-- 비교 타입
|
|
change_type VARCHAR(20) NOT NULL, -- 'NEW', 'MODIFIED', 'REMOVED', 'UNCHANGED'
|
|
|
|
-- 자재 정보
|
|
description TEXT NOT NULL,
|
|
size_spec VARCHAR(100),
|
|
material_grade VARCHAR(100),
|
|
|
|
-- 수량 비교
|
|
previous_quantity DECIMAL(10,3) DEFAULT 0,
|
|
current_quantity DECIMAL(10,3) DEFAULT 0,
|
|
quantity_diff DECIMAL(10,3) DEFAULT 0,
|
|
|
|
-- 추가 구매 필요량 (핵심!)
|
|
additional_purchase_needed DECIMAL(10,3) DEFAULT 0,
|
|
|
|
-- 분류 정보
|
|
classified_category VARCHAR(50),
|
|
classification_confidence DECIMAL(3,2),
|
|
|
|
-- 관리 정보
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
-- 외래키
|
|
FOREIGN KEY (comparison_id) REFERENCES material_revisions_comparison(id) ON DELETE CASCADE
|
|
);
|
|
|
|
-- ================================
|
|
-- 9. Tubing 시스템 테이블들 (15_create_tubing_system.sql)
|
|
-- ================================
|
|
|
|
-- Tubing 카테고리 테이블
|
|
CREATE TABLE IF NOT EXISTS tubing_categories (
|
|
id SERIAL PRIMARY KEY,
|
|
category_code VARCHAR(20) UNIQUE NOT NULL,
|
|
category_name VARCHAR(100) NOT NULL,
|
|
description TEXT,
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Tubing 규격 마스터 테이블
|
|
CREATE TABLE IF NOT EXISTS tubing_specifications (
|
|
id SERIAL PRIMARY KEY,
|
|
category_id INTEGER REFERENCES tubing_categories(id),
|
|
spec_code VARCHAR(50) UNIQUE NOT NULL,
|
|
spec_name VARCHAR(200) NOT NULL,
|
|
|
|
-- 물리적 규격
|
|
outer_diameter_mm DECIMAL(8,3), -- 외경 (mm)
|
|
wall_thickness_mm DECIMAL(6,3), -- 두께 (mm)
|
|
inner_diameter_mm DECIMAL(8,3), -- 내경 (mm, 계산 또는 실측)
|
|
|
|
-- 재질 정보
|
|
material_grade VARCHAR(100), -- SS316, SS316L, Inconel625 등
|
|
material_standard VARCHAR(100), -- ASTM A269, JIS G3463 등
|
|
|
|
-- 압력/온도 등급
|
|
max_pressure_bar DECIMAL(8,2), -- 최대 압력 (bar)
|
|
max_temperature_c DECIMAL(6,2), -- 최대 온도 (°C)
|
|
min_temperature_c DECIMAL(6,2), -- 최소 온도 (°C)
|
|
|
|
-- 표준 규격
|
|
standard_length_m DECIMAL(8,3), -- 표준 길이 (m)
|
|
bend_radius_min_mm DECIMAL(8,2), -- 최소 벤딩 반경 (mm)
|
|
|
|
-- 기타 정보
|
|
surface_finish VARCHAR(100), -- 표면 마감 (BA, #4, 2B 등)
|
|
hardness VARCHAR(50), -- 경도
|
|
notes TEXT,
|
|
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- 제조사 정보 테이블
|
|
CREATE TABLE IF NOT EXISTS tubing_manufacturers (
|
|
id SERIAL PRIMARY KEY,
|
|
manufacturer_code VARCHAR(20) UNIQUE NOT NULL,
|
|
manufacturer_name VARCHAR(200) NOT NULL,
|
|
country VARCHAR(100),
|
|
website VARCHAR(500),
|
|
contact_info JSONB, -- 연락처 정보 (JSON)
|
|
quality_certs JSONB, -- 품질 인증서 정보 (ISO, API 등)
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- 제조사별 제품 테이블
|
|
CREATE TABLE IF NOT EXISTS tubing_products (
|
|
id SERIAL PRIMARY KEY,
|
|
specification_id INTEGER REFERENCES tubing_specifications(id),
|
|
manufacturer_id INTEGER REFERENCES tubing_manufacturers(id),
|
|
|
|
-- 제조사 품목번호 정보
|
|
manufacturer_part_number VARCHAR(200) NOT NULL, -- 제조사 품목번호
|
|
manufacturer_product_name VARCHAR(300), -- 제조사 제품명
|
|
|
|
-- 가격/공급 정보
|
|
list_price DECIMAL(12,2), -- 정가
|
|
currency VARCHAR(10) DEFAULT 'KRW', -- 통화
|
|
lead_time_days INTEGER, -- 리드타임 (일)
|
|
minimum_order_qty DECIMAL(10,3), -- 최소 주문 수량
|
|
standard_packaging_qty DECIMAL(10,3), -- 표준 포장 수량
|
|
|
|
-- 가용성 정보
|
|
availability_status VARCHAR(50), -- 재고 상태
|
|
last_price_update DATE, -- 마지막 가격 업데이트
|
|
|
|
-- 추가 정보
|
|
datasheet_url VARCHAR(500), -- 데이터시트 URL
|
|
catalog_page VARCHAR(100), -- 카탈로그 페이지
|
|
notes TEXT,
|
|
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
-- 유니크 제약 (같은 규격의 같은 제조사 제품은 하나만)
|
|
UNIQUE(specification_id, manufacturer_id, manufacturer_part_number)
|
|
);
|
|
|
|
-- BOM에서 사용되는 Tubing 매핑 테이블
|
|
CREATE TABLE IF NOT EXISTS material_tubing_mapping (
|
|
id SERIAL PRIMARY KEY,
|
|
material_id INTEGER REFERENCES materials(id) ON DELETE CASCADE,
|
|
tubing_product_id INTEGER REFERENCES tubing_products(id),
|
|
|
|
-- 매핑 정보
|
|
confidence_score DECIMAL(3,2), -- 매핑 신뢰도 (0.00-1.00)
|
|
mapping_method VARCHAR(50), -- 매핑 방법 (auto/manual)
|
|
mapped_by VARCHAR(100), -- 매핑한 사용자
|
|
mapped_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
-- 수량 정보
|
|
required_length_m DECIMAL(10,3), -- 필요 길이 (m)
|
|
calculated_quantity DECIMAL(10,3), -- 계산된 주문 수량
|
|
|
|
-- 검증 정보
|
|
is_verified BOOLEAN DEFAULT FALSE,
|
|
verified_by VARCHAR(100),
|
|
verified_at TIMESTAMP,
|
|
|
|
notes TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- ================================
|
|
-- 10. 사용자 요구사항 테이블들 (05_create_pipe_details_and_requirements_postgres.sql)
|
|
-- ================================
|
|
|
|
-- 요구사항 타입 마스터 테이블
|
|
CREATE TABLE IF NOT EXISTS requirement_types (
|
|
id SERIAL PRIMARY KEY,
|
|
type_code VARCHAR(50) UNIQUE NOT NULL, -- 'IMPACT_TEST', 'HEAT_TREATMENT' 등
|
|
type_name VARCHAR(100) NOT NULL, -- '임팩테스트', '열처리' 등
|
|
category VARCHAR(50) NOT NULL, -- 'TEST', 'TREATMENT', 'CERTIFICATION', 'CUSTOM' 등
|
|
description TEXT, -- 타입 설명
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- 사용자 추가 요구사항 테이블
|
|
CREATE TABLE IF NOT EXISTS user_requirements (
|
|
id SERIAL PRIMARY KEY,
|
|
file_id INTEGER NOT NULL,
|
|
material_id INTEGER, -- 자재 ID (개별 자재별 요구사항 연결)
|
|
|
|
-- 요구사항 타입
|
|
requirement_type VARCHAR(50) NOT NULL, -- 'IMPACT_TEST', 'HEAT_TREATMENT', 'CUSTOM_SPEC', 'CERTIFICATION' 등
|
|
|
|
-- 요구사항 내용
|
|
requirement_title VARCHAR(200) NOT NULL, -- '임팩테스트', '열처리', '인증서' 등
|
|
requirement_description TEXT, -- 상세 설명
|
|
requirement_spec TEXT, -- 구체적 스펙 (예: "Charpy V-notch -20°C")
|
|
|
|
-- 상태 관리
|
|
status VARCHAR(20) DEFAULT 'PENDING', -- 'PENDING', 'IN_PROGRESS', 'COMPLETED', 'CANCELLED'
|
|
priority VARCHAR(20) DEFAULT 'NORMAL', -- 'LOW', 'NORMAL', 'HIGH', 'URGENT'
|
|
|
|
-- 담당자 정보
|
|
assigned_to VARCHAR(100), -- 담당자명
|
|
due_date DATE, -- 완료 예정일
|
|
|
|
-- 메타데이터
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
FOREIGN KEY (file_id) REFERENCES files(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (material_id) REFERENCES materials(id) ON DELETE CASCADE
|
|
);
|
|
|
|
-- ================================
|
|
-- 11. 사용자 활동 로그 테이블 (19_add_user_tracking_fields.sql)
|
|
-- ================================
|
|
|
|
CREATE TABLE IF NOT EXISTS user_activity_logs (
|
|
id SERIAL PRIMARY KEY,
|
|
user_id INTEGER, -- users 테이블 참조 (외래키 제약 없음 - 유연성)
|
|
username VARCHAR(100) NOT NULL, -- 사용자명 (필수)
|
|
|
|
-- 활동 정보
|
|
activity_type VARCHAR(50) NOT NULL, -- 'FILE_UPLOAD', 'PROJECT_CREATE', 'PURCHASE_CONFIRM' 등
|
|
activity_description TEXT, -- 상세 활동 내용
|
|
|
|
-- 대상 정보
|
|
target_id INTEGER, -- 대상 ID (파일, 프로젝트 등)
|
|
target_type VARCHAR(50), -- 'FILE', 'PROJECT', 'MATERIAL', 'PURCHASE' 등
|
|
|
|
-- 세션 정보
|
|
ip_address VARCHAR(45), -- IP 주소
|
|
user_agent TEXT, -- 브라우저 정보
|
|
|
|
-- 추가 메타데이터 (JSON)
|
|
metadata JSONB, -- 추가 정보 (파일 크기, 처리 시간 등)
|
|
|
|
-- 시간 정보
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- ================================
|
|
-- 7. 인덱스 생성 (성능 최적화)
|
|
-- ================================
|
|
|
|
-- 프로젝트 관련 인덱스
|
|
CREATE INDEX IF NOT EXISTS idx_projects_official_code ON projects(official_project_code);
|
|
CREATE INDEX IF NOT EXISTS idx_projects_design_code ON projects(design_project_code);
|
|
|
|
-- 파일 관련 인덱스
|
|
CREATE INDEX IF NOT EXISTS idx_files_project ON files(project_id);
|
|
CREATE INDEX IF NOT EXISTS idx_files_active ON files(is_active);
|
|
CREATE INDEX IF NOT EXISTS idx_files_uploaded_by ON files(uploaded_by);
|
|
CREATE INDEX IF NOT EXISTS idx_files_updated_by ON files(updated_by);
|
|
|
|
-- 자재 관련 인덱스
|
|
CREATE INDEX IF NOT EXISTS idx_materials_file ON materials(file_id);
|
|
CREATE INDEX IF NOT EXISTS idx_materials_category ON materials(classified_category, classified_subcategory);
|
|
CREATE INDEX IF NOT EXISTS idx_materials_material_size ON materials(material_grade, size_spec);
|
|
CREATE INDEX IF NOT EXISTS idx_materials_classified_by ON materials(classified_by);
|
|
CREATE INDEX IF NOT EXISTS idx_materials_hash ON materials(material_hash);
|
|
|
|
-- 자재 상세 테이블 인덱스
|
|
CREATE INDEX IF NOT EXISTS idx_pipe_details_material_id ON pipe_details(material_id);
|
|
CREATE INDEX IF NOT EXISTS idx_pipe_details_file_id ON pipe_details(file_id);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_fitting_details_material_id ON fitting_details(material_id);
|
|
CREATE INDEX IF NOT EXISTS idx_fitting_details_file_id ON fitting_details(file_id);
|
|
CREATE INDEX IF NOT EXISTS idx_fitting_details_type ON fitting_details(fitting_type);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_valve_details_material_id ON valve_details(material_id);
|
|
CREATE INDEX IF NOT EXISTS idx_valve_details_file_id ON valve_details(file_id);
|
|
CREATE INDEX IF NOT EXISTS idx_valve_details_type ON valve_details(valve_type);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_flange_details_material_id ON flange_details(material_id);
|
|
CREATE INDEX IF NOT EXISTS idx_flange_details_file_id ON flange_details(file_id);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_bolt_details_material_id ON bolt_details(material_id);
|
|
CREATE INDEX IF NOT EXISTS idx_bolt_details_file_id ON bolt_details(file_id);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_gasket_details_material_id ON gasket_details(material_id);
|
|
CREATE INDEX IF NOT EXISTS idx_gasket_details_file_id ON gasket_details(file_id);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_instrument_details_material_id ON instrument_details(material_id);
|
|
CREATE INDEX IF NOT EXISTS idx_instrument_details_file_id ON instrument_details(file_id);
|
|
|
|
-- 파이프 끝단 가공 테이블 인덱스
|
|
CREATE INDEX IF NOT EXISTS idx_pipe_end_preparations_material_id ON pipe_end_preparations(material_id);
|
|
CREATE INDEX IF NOT EXISTS idx_pipe_end_preparations_file_id ON pipe_end_preparations(file_id);
|
|
CREATE INDEX IF NOT EXISTS idx_pipe_end_preparations_type ON pipe_end_preparations(end_preparation_type);
|
|
|
|
-- 인증 시스템 인덱스
|
|
CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
|
|
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
|
|
CREATE INDEX IF NOT EXISTS idx_users_role ON users(role);
|
|
CREATE INDEX IF NOT EXISTS idx_users_is_active ON users(is_active);
|
|
CREATE INDEX IF NOT EXISTS idx_users_created_at ON users(created_at);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_login_logs_user_id ON login_logs(user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_login_logs_login_time ON login_logs(login_time);
|
|
CREATE INDEX IF NOT EXISTS idx_login_logs_ip_address ON login_logs(ip_address);
|
|
CREATE INDEX IF NOT EXISTS idx_login_logs_status ON login_logs(login_status);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_user_sessions_user_id ON user_sessions(user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_user_sessions_refresh_token ON user_sessions(refresh_token);
|
|
CREATE INDEX IF NOT EXISTS idx_user_sessions_expires_at ON user_sessions(expires_at);
|
|
CREATE INDEX IF NOT EXISTS idx_user_sessions_is_active ON user_sessions(is_active);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_permissions_module ON permissions(module);
|
|
CREATE INDEX IF NOT EXISTS idx_role_permissions_role ON role_permissions(role);
|
|
|
|
-- 구매 관련 인덱스
|
|
CREATE INDEX IF NOT EXISTS idx_purchase_items_job_revision ON purchase_items(job_no, revision);
|
|
CREATE INDEX IF NOT EXISTS idx_purchase_items_category ON purchase_items(category);
|
|
CREATE INDEX IF NOT EXISTS idx_purchase_items_item_code ON purchase_items(item_code);
|
|
CREATE INDEX IF NOT EXISTS idx_purchase_items_active ON purchase_items(is_active);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_material_purchase_mapping_material ON material_purchase_mapping(material_id);
|
|
CREATE INDEX IF NOT EXISTS idx_material_purchase_mapping_purchase ON material_purchase_mapping(purchase_item_id);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_material_purchase_tracking_hash ON material_purchase_tracking(material_hash);
|
|
CREATE INDEX IF NOT EXISTS idx_material_purchase_tracking_job_revision ON material_purchase_tracking(job_no, revision);
|
|
|
|
-- Jobs 테이블 인덱스
|
|
CREATE INDEX IF NOT EXISTS idx_jobs_status ON jobs(status);
|
|
CREATE INDEX IF NOT EXISTS idx_jobs_client ON jobs(client_name);
|
|
CREATE INDEX IF NOT EXISTS idx_jobs_created_at ON jobs(created_at);
|
|
CREATE INDEX IF NOT EXISTS idx_jobs_created_by ON jobs(created_by);
|
|
CREATE INDEX IF NOT EXISTS idx_jobs_assigned_to ON jobs(assigned_to);
|
|
|
|
-- 자재 규격/재질 기준표 인덱스
|
|
CREATE INDEX IF NOT EXISTS idx_material_standards_code ON material_standards(standard_code);
|
|
CREATE INDEX IF NOT EXISTS idx_material_categories_standard ON material_categories(standard_id);
|
|
CREATE INDEX IF NOT EXISTS idx_material_specifications_category ON material_specifications(category_id);
|
|
CREATE INDEX IF NOT EXISTS idx_material_grades_specification ON material_grades(specification_id);
|
|
CREATE INDEX IF NOT EXISTS idx_material_patterns_specification ON material_patterns(specification_id);
|
|
CREATE INDEX IF NOT EXISTS idx_special_materials_type ON special_materials(material_type);
|
|
CREATE INDEX IF NOT EXISTS idx_special_material_grades_material ON special_material_grades(material_id);
|
|
CREATE INDEX IF NOT EXISTS idx_special_material_patterns_material ON special_material_patterns(material_id);
|
|
|
|
-- 활성 상태 인덱스
|
|
CREATE INDEX IF NOT EXISTS idx_material_standards_active ON material_standards(is_active);
|
|
CREATE INDEX IF NOT EXISTS idx_material_categories_active ON material_categories(is_active);
|
|
CREATE INDEX IF NOT EXISTS idx_material_specifications_active ON material_specifications(is_active);
|
|
CREATE INDEX IF NOT EXISTS idx_material_grades_active ON material_grades(is_active);
|
|
CREATE INDEX IF NOT EXISTS idx_material_patterns_active ON material_patterns(is_active);
|
|
CREATE INDEX IF NOT EXISTS idx_special_materials_active ON special_materials(is_active);
|
|
CREATE INDEX IF NOT EXISTS idx_special_material_grades_active ON special_material_grades(is_active);
|
|
CREATE INDEX IF NOT EXISTS idx_special_material_patterns_active ON special_material_patterns(is_active);
|
|
|
|
-- 자재 비교 시스템 인덱스
|
|
CREATE INDEX IF NOT EXISTS idx_material_revisions_job ON material_revisions_comparison(job_no);
|
|
CREATE INDEX IF NOT EXISTS idx_material_revisions_current ON material_revisions_comparison(current_revision);
|
|
CREATE INDEX IF NOT EXISTS idx_material_comparison_hash ON material_comparison_details(material_hash);
|
|
CREATE INDEX IF NOT EXISTS idx_material_comparison_type ON material_comparison_details(change_type);
|
|
|
|
-- Tubing 시스템 인덱스
|
|
CREATE INDEX IF NOT EXISTS idx_tubing_specs_category ON tubing_specifications(category_id);
|
|
CREATE INDEX IF NOT EXISTS idx_tubing_specs_material ON tubing_specifications(material_grade);
|
|
CREATE INDEX IF NOT EXISTS idx_tubing_specs_diameter ON tubing_specifications(outer_diameter_mm, wall_thickness_mm);
|
|
CREATE INDEX IF NOT EXISTS idx_tubing_products_spec ON tubing_products(specification_id);
|
|
CREATE INDEX IF NOT EXISTS idx_tubing_products_manufacturer ON tubing_products(manufacturer_id);
|
|
CREATE INDEX IF NOT EXISTS idx_tubing_products_part_number ON tubing_products(manufacturer_part_number);
|
|
CREATE INDEX IF NOT EXISTS idx_material_tubing_mapping_material ON material_tubing_mapping(material_id);
|
|
CREATE INDEX IF NOT EXISTS idx_material_tubing_mapping_product ON material_tubing_mapping(tubing_product_id);
|
|
|
|
-- 사용자 활동 로그 인덱스
|
|
CREATE INDEX IF NOT EXISTS idx_user_activity_logs_username ON user_activity_logs(username);
|
|
CREATE INDEX IF NOT EXISTS idx_user_activity_logs_activity_type ON user_activity_logs(activity_type);
|
|
CREATE INDEX IF NOT EXISTS idx_user_activity_logs_created_at ON user_activity_logs(created_at);
|
|
CREATE INDEX IF NOT EXISTS idx_user_activity_logs_target ON user_activity_logs(target_type, target_id);
|
|
|
|
-- ================================
|
|
-- 추가 성능 최적화 인덱스 (16_performance_indexes.sql)
|
|
-- ================================
|
|
|
|
-- 복합 인덱스 (자주 함께 사용되는 컬럼들)
|
|
CREATE INDEX IF NOT EXISTS idx_files_job_revision ON files(job_no, revision) WHERE is_active = true;
|
|
CREATE INDEX IF NOT EXISTS idx_files_job_date ON files(job_no, upload_date DESC) WHERE is_active = true;
|
|
CREATE INDEX IF NOT EXISTS idx_materials_file_category ON materials(file_id, classified_category);
|
|
CREATE INDEX IF NOT EXISTS idx_materials_category_grade ON materials(classified_category, material_grade);
|
|
|
|
-- 검색 성능 향상 인덱스
|
|
CREATE INDEX IF NOT EXISTS idx_materials_description_gin ON materials USING gin(to_tsvector('english', original_description));
|
|
|
|
-- 정렬 성능 향상 인덱스
|
|
CREATE INDEX IF NOT EXISTS idx_jobs_status_created ON jobs(status, created_at DESC) WHERE is_active = true;
|
|
CREATE INDEX IF NOT EXISTS idx_materials_quantity_desc ON materials(quantity DESC);
|
|
|
|
-- 조건부 인덱스 (특정 조건에서만 사용)
|
|
CREATE INDEX IF NOT EXISTS idx_materials_unverified ON materials(classified_category, classification_confidence) WHERE is_verified = false;
|
|
CREATE INDEX IF NOT EXISTS idx_materials_low_confidence ON materials(file_id, classified_category) WHERE classification_confidence < 0.8;
|
|
|
|
-- 분류 관련 인덱스 (05_add_classification_columns.sql)
|
|
CREATE INDEX IF NOT EXISTS idx_materials_subcategory ON materials(subcategory);
|
|
CREATE INDEX IF NOT EXISTS idx_materials_standard ON materials(standard);
|
|
CREATE INDEX IF NOT EXISTS idx_materials_grade ON materials(grade);
|
|
|
|
-- Job 연결 인덱스 (02_modify_files_table.sql)
|
|
CREATE INDEX IF NOT EXISTS idx_files_job_no ON files(job_no);
|
|
|
|
-- 프로젝트 타입 인덱스 (17_add_project_type_column.sql)
|
|
CREATE INDEX IF NOT EXISTS idx_jobs_project_type ON jobs(project_type);
|
|
|
|
-- 사용자 요구사항 테이블 인덱스 (05_create_pipe_details_and_requirements_postgres.sql)
|
|
CREATE INDEX IF NOT EXISTS idx_user_requirements_file_id ON user_requirements(file_id);
|
|
CREATE INDEX IF NOT EXISTS idx_user_requirements_material_id ON user_requirements(material_id);
|
|
CREATE INDEX IF NOT EXISTS idx_user_requirements_status ON user_requirements(status);
|
|
CREATE INDEX IF NOT EXISTS idx_user_requirements_type ON user_requirements(requirement_type);
|
|
|
|
-- ================================
|
|
-- 8. 트리거 함수 및 트리거 생성
|
|
-- ================================
|
|
|
|
-- updated_at 자동 업데이트 함수
|
|
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
NEW.updated_at = CURRENT_TIMESTAMP;
|
|
RETURN NEW;
|
|
END;
|
|
$$ language 'plpgsql';
|
|
|
|
-- 파이프 끝단 가공 테이블 트리거
|
|
CREATE OR REPLACE FUNCTION update_pipe_end_preparations_updated_at()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
NEW.updated_at = CURRENT_TIMESTAMP;
|
|
RETURN NEW;
|
|
END;
|
|
$$ language 'plpgsql';
|
|
|
|
-- 구매 관련 트리거 함수들
|
|
CREATE OR REPLACE FUNCTION update_purchase_items_timestamp()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
NEW.updated_at = CURRENT_TIMESTAMP;
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
CREATE OR REPLACE FUNCTION update_files_updated_at()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
NEW.updated_at = CURRENT_TIMESTAMP;
|
|
RETURN NEW;
|
|
END;
|
|
$$ language 'plpgsql';
|
|
|
|
-- 트리거 적용
|
|
CREATE TRIGGER IF NOT EXISTS update_users_updated_at BEFORE UPDATE ON users
|
|
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
|
|
|
CREATE TRIGGER IF NOT EXISTS update_user_sessions_updated_at BEFORE UPDATE ON user_sessions
|
|
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
|
|
|
CREATE TRIGGER IF NOT EXISTS update_pipe_end_preparations_updated_at BEFORE UPDATE ON pipe_end_preparations
|
|
FOR EACH ROW EXECUTE FUNCTION update_pipe_end_preparations_updated_at();
|
|
|
|
CREATE TRIGGER IF NOT EXISTS trigger_update_purchase_items_timestamp BEFORE UPDATE ON purchase_items
|
|
FOR EACH ROW EXECUTE FUNCTION update_purchase_items_timestamp();
|
|
|
|
CREATE TRIGGER IF NOT EXISTS trigger_files_updated_at BEFORE UPDATE ON files
|
|
FOR EACH ROW EXECUTE FUNCTION update_files_updated_at();
|
|
|
|
-- ================================
|
|
-- 해시 생성 함수 및 트리거 (10_add_material_comparison_system.sql)
|
|
-- ================================
|
|
|
|
-- 해시 생성 함수
|
|
CREATE OR REPLACE FUNCTION generate_material_hash(
|
|
description TEXT,
|
|
size_spec TEXT DEFAULT '',
|
|
material_grade TEXT DEFAULT ''
|
|
) RETURNS VARCHAR(32) AS $$
|
|
BEGIN
|
|
-- 정규화: 대소문자 통일, 공백 정리
|
|
description := UPPER(TRIM(REGEXP_REPLACE(description, '\s+', ' ', 'g')));
|
|
size_spec := UPPER(TRIM(COALESCE(size_spec, '')));
|
|
material_grade := UPPER(TRIM(COALESCE(material_grade, '')));
|
|
|
|
-- MD5 해시 생성 (32자리)
|
|
RETURN MD5(description || '|' || size_spec || '|' || material_grade);
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- 자동 해시 생성 트리거 함수
|
|
CREATE OR REPLACE FUNCTION auto_generate_material_hash()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
-- 새로 삽입되거나 업데이트될 때 자동으로 해시 생성
|
|
NEW.material_hash := generate_material_hash(
|
|
NEW.original_description,
|
|
NEW.size_spec,
|
|
NEW.material_grade
|
|
);
|
|
NEW.normalized_description := UPPER(TRIM(REGEXP_REPLACE(NEW.original_description, '\s+', ' ', 'g')));
|
|
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- 자동 해시 생성 트리거 적용
|
|
CREATE TRIGGER IF NOT EXISTS trigger_auto_material_hash
|
|
BEFORE INSERT OR UPDATE ON materials
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION auto_generate_material_hash();
|
|
|
|
-- ================================
|
|
-- 9. 기본 데이터 삽입
|
|
-- ================================
|
|
|
|
-- 기본 권한 데이터 삽입
|
|
INSERT INTO permissions (permission_name, description, module) VALUES
|
|
-- BOM 관리 권한
|
|
('bom.view', 'BOM 조회 권한', 'bom'),
|
|
('bom.create', 'BOM 생성 권한', 'bom'),
|
|
('bom.edit', 'BOM 수정 권한', 'bom'),
|
|
('bom.delete', 'BOM 삭제 권한', 'bom'),
|
|
('bom.approve', 'BOM 승인 권한', 'bom'),
|
|
|
|
-- 프로젝트 관리 권한
|
|
('project.view', '프로젝트 조회 권한', 'project'),
|
|
('project.create', '프로젝트 생성 권한', 'project'),
|
|
('project.edit', '프로젝트 수정 권한', 'project'),
|
|
('project.delete', '프로젝트 삭제 권한', 'project'),
|
|
('project.manage', '프로젝트 관리 권한', 'project'),
|
|
|
|
-- 파일 관리 권한
|
|
('file.upload', '파일 업로드 권한', 'file'),
|
|
('file.download', '파일 다운로드 권한', 'file'),
|
|
('file.delete', '파일 삭제 권한', 'file'),
|
|
|
|
-- 사용자 관리 권한
|
|
('user.view', '사용자 조회 권한', 'user'),
|
|
('user.create', '사용자 생성 권한', 'user'),
|
|
('user.edit', '사용자 수정 권한', 'user'),
|
|
('user.delete', '사용자 삭제 권한', 'user'),
|
|
|
|
-- 시스템 관리 권한
|
|
('system.admin', '시스템 관리 권한', 'system'),
|
|
('system.logs', '로그 조회 권한', 'system'),
|
|
('system.settings', '시스템 설정 권한', 'system')
|
|
|
|
ON CONFLICT (permission_name) DO NOTHING;
|
|
|
|
-- 역할별 기본 권한 할당
|
|
INSERT INTO role_permissions (role, permission_id)
|
|
SELECT 'admin', permission_id FROM permissions
|
|
ON CONFLICT (role, permission_id) DO NOTHING;
|
|
|
|
INSERT INTO role_permissions (role, permission_id)
|
|
SELECT 'system', permission_id FROM permissions
|
|
ON CONFLICT (role, permission_id) DO NOTHING;
|
|
|
|
INSERT INTO role_permissions (role, permission_id)
|
|
SELECT 'leader', permission_id FROM permissions
|
|
WHERE permission_name IN (
|
|
'bom.view', 'bom.create', 'bom.edit', 'bom.approve',
|
|
'project.view', 'project.create', 'project.edit', 'project.manage',
|
|
'file.upload', 'file.download', 'file.delete',
|
|
'user.view'
|
|
)
|
|
ON CONFLICT (role, permission_id) DO NOTHING;
|
|
|
|
INSERT INTO role_permissions (role, permission_id)
|
|
SELECT 'support', permission_id FROM permissions
|
|
WHERE permission_name IN (
|
|
'bom.view', 'bom.create', 'bom.edit',
|
|
'project.view', 'project.create', 'project.edit',
|
|
'file.upload', 'file.download'
|
|
)
|
|
ON CONFLICT (role, permission_id) DO NOTHING;
|
|
|
|
INSERT INTO role_permissions (role, permission_id)
|
|
SELECT 'user', permission_id FROM permissions
|
|
WHERE permission_name IN (
|
|
'bom.view',
|
|
'project.view',
|
|
'file.upload', 'file.download'
|
|
)
|
|
ON CONFLICT (role, permission_id) DO NOTHING;
|
|
|
|
-- 기본 관리자 계정 생성 (비밀번호: admin123)
|
|
-- bcrypt 해시: $2b$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi
|
|
INSERT INTO users (username, password, name, email, role, access_level, department, position) VALUES
|
|
('admin', '$2b$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', '시스템 관리자', 'admin@tkmp.com', 'admin', 'admin', 'IT', '시스템 관리자'),
|
|
('system', '$2b$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', '시스템 계정', 'system@tkmp.com', 'system', 'system', 'IT', '시스템 계정')
|
|
ON CONFLICT (username) DO NOTHING;
|
|
|
|
-- 기본 프로젝트 생성
|
|
INSERT INTO projects (official_project_code, project_name, client_name, status, description) VALUES
|
|
('TK-MP-DEV-001', 'TK-MP 개발 프로젝트', 'TK Engineering', 'active', '개발 및 테스트용 프로젝트'),
|
|
('TK-MP-DEMO-001', 'TK-MP 데모 프로젝트', 'Demo Client', 'active', '데모 및 시연용 프로젝트'),
|
|
('TK-MP-TEST-001', 'TK-MP 테스트 프로젝트', 'Test Client', 'active', '기능 테스트용 프로젝트')
|
|
ON CONFLICT (official_project_code) DO NOTHING;
|
|
|
|
-- Tubing 카테고리 기초 데이터
|
|
INSERT INTO tubing_categories (category_code, category_name, description) VALUES
|
|
('GENERAL', '일반 Tubing', '일반적인 스테인리스 스틸 튜빙'),
|
|
('VCR', 'VCR Tubing', 'VCR (Vacuum Coupling Radiation) 연결용 튜빙'),
|
|
('SANITARY', 'Sanitary Tubing', '위생용 튜빙 (식품, 제약 등)'),
|
|
('HVAC', 'HVAC Tubing', '공조용 튜빙'),
|
|
('HYDRAULIC', 'Hydraulic Tubing', '유압용 튜빙'),
|
|
('PNEUMATIC', 'Pneumatic Tubing', '공압용 튜빙'),
|
|
('PROCESS', 'Process Tubing', '공정용 특수 튜빙'),
|
|
('EXOTIC', 'Exotic Material', '특수 재질 튜빙 (Hastelloy, Inconel 등)')
|
|
ON CONFLICT (category_code) DO NOTHING;
|
|
|
|
-- 주요 제조사 기초 데이터
|
|
INSERT INTO tubing_manufacturers (manufacturer_code, manufacturer_name, country) VALUES
|
|
('SWAGELOK', 'Swagelok Company', 'USA'),
|
|
('PARKER', 'Parker Hannifin', 'USA'),
|
|
('HAM_LET', 'Ham-Let Group', 'Israel'),
|
|
('SUPERLOK', 'Superlok USA', 'USA'),
|
|
('FITOK', 'Fitok Group', 'China'),
|
|
('DK_LOK', 'DK-Lok Corporation', 'South Korea'),
|
|
('GYROLOK', 'Gyrolok (Oliver Valves)', 'UK'),
|
|
('AS_ONE', 'AS ONE Corporation', 'Japan')
|
|
ON CONFLICT (manufacturer_code) DO NOTHING;
|
|
|
|
-- 기본 요구사항 타입 데이터 삽입 (05_create_pipe_details_and_requirements_postgres.sql)
|
|
INSERT INTO requirement_types (type_code, type_name, category, description) VALUES
|
|
('IMPACT_TEST', '임팩테스트', 'TEST', 'Charpy V-notch, Izod 등의 충격 시험'),
|
|
('HEAT_TREATMENT', '열처리', 'TREATMENT', '정규화, 어닐링, 템퍼링 등의 열처리'),
|
|
('CERTIFICATION', '인증서', 'CERTIFICATION', '재질증명서, 시험성적서 등'),
|
|
('CUSTOM_SPEC', '특수사양', 'CUSTOM', '고객 특별 요구사항'),
|
|
('NDT_TEST', '비파괴검사', 'TEST', '초음파, 방사선, 자분탐상 등'),
|
|
('CHEMICAL_ANALYSIS', '화학분석', 'TEST', '화학성분 분석'),
|
|
('MECHANICAL_TEST', '기계적성질', 'TEST', '인장, 압축, 굽힘 시험'),
|
|
('SURFACE_TREATMENT', '표면처리', 'TREATMENT', '도금, 도장, 패시베이션 등'),
|
|
('DIMENSIONAL_CHECK', '치수검사', 'INSPECTION', '치수, 형상 검사'),
|
|
('WELDING_SPEC', '용접사양', 'SPEC', '용접 방법, 용접재 등')
|
|
ON CONFLICT (type_code) DO NOTHING;
|
|
|
|
-- ================================
|
|
-- 10. 뷰 생성
|
|
-- ================================
|
|
|
|
-- 프로젝트 상태 요약 뷰
|
|
CREATE OR REPLACE VIEW project_status_view AS
|
|
SELECT
|
|
p.id,
|
|
COALESCE(p.official_project_code, p.design_project_code) as display_code,
|
|
p.project_name,
|
|
p.status,
|
|
COUNT(f.id) as file_count,
|
|
COUNT(m.id) as material_count,
|
|
p.created_at
|
|
FROM projects p
|
|
LEFT JOIN files f ON p.id = f.project_id AND f.is_active = true
|
|
LEFT JOIN materials m ON f.id = m.file_id
|
|
GROUP BY p.id, p.official_project_code, p.design_project_code,
|
|
p.project_name, p.status, p.created_at
|
|
ORDER BY p.created_at DESC;
|
|
|
|
-- 사용자 정보 조회용 뷰
|
|
CREATE OR REPLACE VIEW user_info_view AS
|
|
SELECT
|
|
u.user_id,
|
|
u.username,
|
|
u.name,
|
|
u.email,
|
|
u.role,
|
|
u.access_level,
|
|
u.department,
|
|
u.position,
|
|
u.is_active,
|
|
u.created_at,
|
|
u.last_login_at,
|
|
COUNT(ll.log_id) as login_count,
|
|
MAX(ll.login_time) as last_successful_login
|
|
FROM users u
|
|
LEFT JOIN login_logs ll ON u.user_id = ll.user_id AND ll.login_status = 'success'
|
|
GROUP BY u.user_id, u.username, u.name, u.email, u.role, u.access_level,
|
|
u.department, u.position, u.is_active, u.created_at, u.last_login_at;
|
|
|
|
-- ================================
|
|
-- 추가 뷰들 (05_add_classification_columns.sql, 10_add_material_comparison_system.sql)
|
|
-- ================================
|
|
|
|
-- 분류 결과 통계 조회용 뷰
|
|
CREATE OR REPLACE VIEW classification_summary AS
|
|
SELECT
|
|
f.job_no,
|
|
f.original_filename,
|
|
f.parsed_count,
|
|
f.classification_completed,
|
|
f.classification_timestamp,
|
|
COUNT(*) as total_materials,
|
|
COUNT(CASE WHEN m.classified_category = 'BOLT' THEN 1 END) as bolt_count,
|
|
COUNT(CASE WHEN m.classified_category = 'FLANGE' THEN 1 END) as flange_count,
|
|
COUNT(CASE WHEN m.classified_category = 'FITTING' THEN 1 END) as fitting_count,
|
|
COUNT(CASE WHEN m.classified_category = 'GASKET' THEN 1 END) as gasket_count,
|
|
COUNT(CASE WHEN m.classified_category = 'INSTRUMENT' THEN 1 END) as instrument_count,
|
|
COUNT(CASE WHEN m.classified_category = 'PIPE' THEN 1 END) as pipe_count,
|
|
COUNT(CASE WHEN m.classified_category = 'VALVE' THEN 1 END) as valve_count,
|
|
COUNT(CASE WHEN m.classified_category = 'MATERIAL' THEN 1 END) as material_count,
|
|
COUNT(CASE WHEN m.classified_category = 'OTHER' THEN 1 END) as other_count,
|
|
AVG(m.classification_confidence) as avg_confidence,
|
|
COUNT(CASE WHEN m.is_verified = TRUE THEN 1 END) as verified_count
|
|
FROM files f
|
|
LEFT JOIN materials m ON f.id = m.file_id
|
|
WHERE f.is_active = TRUE
|
|
GROUP BY f.id, f.job_no, f.original_filename, f.parsed_count, f.classification_completed, f.classification_timestamp;
|
|
|
|
-- 분류 성능 통계 뷰
|
|
CREATE OR REPLACE VIEW classification_performance AS
|
|
SELECT
|
|
classified_category,
|
|
subcategory,
|
|
standard,
|
|
COUNT(*) as total_count,
|
|
AVG(classification_confidence) as avg_confidence,
|
|
COUNT(CASE WHEN is_verified = TRUE THEN 1 END) as verified_count,
|
|
COUNT(CASE WHEN is_verified = FALSE THEN 1 END) as unverified_count,
|
|
ROUND(
|
|
(COUNT(CASE WHEN is_verified = TRUE THEN 1 END)::DECIMAL / COUNT(*) * 100), 2
|
|
) as verification_rate
|
|
FROM materials
|
|
WHERE classified_category IS NOT NULL
|
|
GROUP BY classified_category, subcategory, standard
|
|
ORDER BY total_count DESC;
|
|
|
|
-- 누적 재고 현황 뷰 (10_add_material_comparison_system.sql)
|
|
CREATE OR REPLACE VIEW material_inventory_status AS
|
|
SELECT
|
|
mpt.job_no,
|
|
mpt.material_hash,
|
|
mpt.description,
|
|
mpt.size_spec,
|
|
mpt.unit,
|
|
|
|
-- 누적 수량
|
|
SUM(mpt.confirmed_quantity) as total_confirmed,
|
|
SUM(mpt.ordered_quantity) as total_ordered,
|
|
SUM(mpt.received_quantity) as total_received,
|
|
|
|
-- 현재 가용 재고
|
|
SUM(mpt.received_quantity) as available_stock,
|
|
|
|
-- 최신 리비전 정보
|
|
MAX(mpt.revision) as latest_revision,
|
|
MAX(mpt.updated_at) as last_updated
|
|
|
|
FROM material_purchase_tracking mpt
|
|
WHERE mpt.purchase_status != 'CANCELLED'
|
|
GROUP BY mpt.job_no, mpt.material_hash, mpt.description, mpt.size_spec, mpt.unit;
|
|
|
|
-- ================================
|
|
-- 완료 메시지
|
|
-- ================================
|
|
|
|
DO $$
|
|
BEGIN
|
|
RAISE NOTICE '✅ TK-MP-Project 완전 통합 데이터베이스 스키마가 성공적으로 생성되었습니다!';
|
|
RAISE NOTICE '📋 생성된 주요 테이블:';
|
|
RAISE NOTICE ' - 기본: projects, files, materials, jobs';
|
|
RAISE NOTICE ' - 자재상세: pipe_details, fitting_details, valve_details, flange_details, bolt_details, gasket_details, instrument_details';
|
|
RAISE NOTICE ' - 파이프: pipe_end_preparations';
|
|
RAISE NOTICE ' - 인증: users, login_logs, user_sessions, permissions, role_permissions';
|
|
RAISE NOTICE ' - 구매: purchase_items, material_purchase_mapping, material_purchase_tracking';
|
|
RAISE NOTICE ' - 자재규격: material_standards, material_categories, material_specifications, material_grades, material_patterns';
|
|
RAISE NOTICE ' - 특수재질: special_materials, special_material_grades, special_material_patterns';
|
|
RAISE NOTICE ' - 비교시스템: material_revisions_comparison, material_comparison_details';
|
|
RAISE NOTICE ' - Tubing: tubing_categories, tubing_specifications, tubing_manufacturers, tubing_products, material_tubing_mapping';
|
|
RAISE NOTICE ' - 요구사항: requirement_types, user_requirements';
|
|
RAISE NOTICE ' - 로그: user_activity_logs';
|
|
RAISE NOTICE '👤 기본 계정: admin/admin123, system/admin123';
|
|
RAISE NOTICE '🏗️ 기본 프로젝트: TK-MP-DEV-001, TK-MP-DEMO-001, TK-MP-TEST-001';
|
|
RAISE NOTICE '🏭 기본 Tubing 제조사: SWAGELOK, PARKER, HAM_LET, SUPERLOK, FITOK, DK_LOK, GYROLOK, AS_ONE';
|
|
RAISE NOTICE '🔐 권한 시스템: 5단계 역할 + 모듈별 세분화된 권한';
|
|
RAISE NOTICE '📊 성능 최적화: 복합인덱스, GIN인덱스, 조건부인덱스 포함 107개 인덱스 적용';
|
|
RAISE NOTICE '🔄 자동화: updated_at 트리거, 해시 자동생성, 기본 데이터 자동 생성';
|
|
RAISE NOTICE '📈 통계뷰: classification_summary, classification_performance, material_inventory_status';
|
|
RAISE NOTICE '🔧 함수: generate_material_hash, auto_generate_material_hash';
|
|
RAISE NOTICE '🔬 기본 요구사항 타입: 임팩테스트, 열처리, 인증서, 비파괴검사, 화학분석 등 10종';
|
|
RAISE NOTICE '📝 총 테이블 수: 38개, 인덱스: 107개, 뷰: 5개, 함수: 15개 이상';
|
|
END $$;
|