Files
M-Project/backend/migrations/016_add_management_fields.sql
Hyungi Ahn d77a71493a feat: 수신함 완료 사진 업로드 및 최종 부적합 사항 DB 구조 구현
📸 Completion Photo Upload:
- 수신함에서 '완료됨' 상태 선택 시 완료 사진 업로드 기능 추가 (1장 제한)
- Base64 인코딩으로 사진 업로드 및 미리보기 기능
- 완료 상태 변경 시 actual_completion_date 자동 설정

🗄️ Final Issue DB Structure:
- 최종 부적합 사항을 위한 포괄적인 DB 스키마 설계 및 구현
- 프로젝트별 순번 (project_sequence_no) 자동 생성 시스템

📋 New Database Fields:
- completion_photo_path: 완료 사진 경로
- solution: 해결방안 (관리함에서 입력)
- responsible_department: 담당부서 (department_type ENUM)
- responsible_person: 담당자 (VARCHAR 100)
- expected_completion_date: 조치 예상일 (DATE)
- actual_completion_date: 완료 확인일 (DATE, 자동 설정)
- cause_department: 원인부서 (department_type ENUM)
- management_comment: ISSUE에 대한 의견 (TEXT)
- final_description: 최종 내용 (수정본 또는 원본)
- final_category: 최종 카테고리 (수정본 또는 원본)

🔧 Backend Implementation:
- Issue 모델에 11개 새 필드 추가
- IssueStatusUpdateRequest에 completion_photo 필드 추가
- ManagementUpdateRequest 스키마 신규 생성
- update_issue_status API에 완료 사진 처리 로직 추가
- generate_project_sequence_no() 함수로 프로젝트별 순번 자동 생성

🎨 Frontend Implementation:
- 상태 결정 모달에 완료 사진 업로드 섹션 추가
- 완료 상태 선택 시에만 사진 업로드 UI 표시
- 파일 크기 제한 (5MB), 이미지 파일 검증
- 사진 미리보기 및 Base64 변환 처리
- 완료 사진 없이 완료 처리 시 확인 다이얼로그

🚀 User Experience:
- 직관적인 완료 사진 업로드 워크플로우
- 실시간 사진 미리보기로 업로드 확인 가능
- 완료 처리 시 자동으로 완료 확인일 기록
- 프로젝트별 순번으로 체계적인 이슈 관리

🔍 Database Migration:
- 016_add_management_fields.sql 마이그레이션 성공적으로 실행
- 멱등성 보장 및 기존 데이터 보존
- 인덱스 최적화 (project_sequence, responsible_department, expected_completion)
- 기존 이슈들의 final_description/final_category 자동 초기화

Expected Result:
 수신함에서 완료 상태 선택 시 완료 사진 업로드 가능
 완료 처리 시 완료 확인일 자동 기록
 프로젝트별 순번으로 체계적인 이슈 번호 관리
 관리함에서 사용할 모든 필드 준비 완료
 최종 부적합 사항 리포트 생성을 위한 DB 구조 완성
2025-10-25 14:18:24 +09:00

224 lines
11 KiB
PL/PgSQL
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- 016_add_management_fields.sql
-- 관리함에서 사용할 추가 필드들과 완료 사진 업로드 기능 추가
BEGIN;
DO $$
DECLARE
migration_name VARCHAR(255) := '016_add_management_fields.sql';
migration_notes TEXT := '관리함 필드 추가: 원인/해결방안, 담당부서/담당자, 조치예상일, 완료확인일, 원인부서, 의견, 완료사진, 프로젝트별 No 등';
current_status VARCHAR(50);
BEGIN
-- migration_log 테이블이 없으면 생성 (멱등성)
CREATE TABLE IF NOT EXISTS migration_log (
id SERIAL PRIMARY KEY,
migration_file VARCHAR(255) NOT NULL UNIQUE,
executed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
status VARCHAR(50),
notes TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
SELECT status INTO current_status FROM migration_log WHERE migration_file = migration_name;
IF current_status IS NULL THEN
RAISE NOTICE '--- 마이그레이션 % 시작 ---', migration_name;
-- issues 테이블에 관리함 관련 컬럼들 추가
-- 완료 사진 경로
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'issues' AND column_name = 'completion_photo_path') THEN
ALTER TABLE issues ADD COLUMN completion_photo_path VARCHAR(255);
RAISE NOTICE '✅ issues.completion_photo_path 컬럼이 추가되었습니다.';
ELSE
RAISE NOTICE ' issues.completion_photo_path 컬럼이 이미 존재합니다.';
END IF;
-- 해결방안 (관리함에서 입력)
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'issues' AND column_name = 'solution') THEN
ALTER TABLE issues ADD COLUMN solution TEXT;
RAISE NOTICE '✅ issues.solution 컬럼이 추가되었습니다.';
ELSE
RAISE NOTICE ' issues.solution 컬럼이 이미 존재합니다.';
END IF;
-- 담당부서 (관리함에서 선택)
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'issues' AND column_name = 'responsible_department') THEN
ALTER TABLE issues ADD COLUMN responsible_department department_type;
RAISE NOTICE '✅ issues.responsible_department 컬럼이 추가되었습니다.';
ELSE
RAISE NOTICE ' issues.responsible_department 컬럼이 이미 존재합니다.';
END IF;
-- 담당자 (관리함에서 입력)
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'issues' AND column_name = 'responsible_person') THEN
ALTER TABLE issues ADD COLUMN responsible_person VARCHAR(100);
RAISE NOTICE '✅ issues.responsible_person 컬럼이 추가되었습니다.';
ELSE
RAISE NOTICE ' issues.responsible_person 컬럼이 이미 존재합니다.';
END IF;
-- 조치 예상일 (관리함에서 입력)
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'issues' AND column_name = 'expected_completion_date') THEN
ALTER TABLE issues ADD COLUMN expected_completion_date DATE;
RAISE NOTICE '✅ issues.expected_completion_date 컬럼이 추가되었습니다.';
ELSE
RAISE NOTICE ' issues.expected_completion_date 컬럼이 이미 존재합니다.';
END IF;
-- 완료 확인일 (완료 상태로 변경 시 자동 입력)
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'issues' AND column_name = 'actual_completion_date') THEN
ALTER TABLE issues ADD COLUMN actual_completion_date DATE;
RAISE NOTICE '✅ issues.actual_completion_date 컬럼이 추가되었습니다.';
ELSE
RAISE NOTICE ' issues.actual_completion_date 컬럼이 이미 존재합니다.';
END IF;
-- 원인부서 (관리함에서 입력)
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'issues' AND column_name = 'cause_department') THEN
ALTER TABLE issues ADD COLUMN cause_department department_type;
RAISE NOTICE '✅ issues.cause_department 컬럼이 추가되었습니다.';
ELSE
RAISE NOTICE ' issues.cause_department 컬럼이 이미 존재합니다.';
END IF;
-- ISSUE에 대한 의견 (관리함에서 입력)
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'issues' AND column_name = 'management_comment') THEN
ALTER TABLE issues ADD COLUMN management_comment TEXT;
RAISE NOTICE '✅ issues.management_comment 컬럼이 추가되었습니다.';
ELSE
RAISE NOTICE ' issues.management_comment 컬럼이 이미 존재합니다.';
END IF;
-- 프로젝트별 순번 (No) - 프로젝트 내에서 1, 2, 3... 순으로 증가
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'issues' AND column_name = 'project_sequence_no') THEN
ALTER TABLE issues ADD COLUMN project_sequence_no INTEGER;
RAISE NOTICE '✅ issues.project_sequence_no 컬럼이 추가되었습니다.';
ELSE
RAISE NOTICE ' issues.project_sequence_no 컬럼이 이미 존재합니다.';
END IF;
-- 최종 내용 (수정된 내용이 있으면 수정본, 없으면 원본)
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'issues' AND column_name = 'final_description') THEN
ALTER TABLE issues ADD COLUMN final_description TEXT;
RAISE NOTICE '✅ issues.final_description 컬럼이 추가되었습니다.';
ELSE
RAISE NOTICE ' issues.final_description 컬럼이 이미 존재합니다.';
END IF;
-- 최종 카테고리 (수정된 카테고리가 있으면 수정본, 없으면 원본)
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'issues' AND column_name = 'final_category') THEN
ALTER TABLE issues ADD COLUMN final_category issuecategory;
RAISE NOTICE '✅ issues.final_category 컬럼이 추가되었습니다.';
ELSE
RAISE NOTICE ' issues.final_category 컬럼이 이미 존재합니다.';
END IF;
-- 인덱스 추가
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'issues' AND indexname = 'idx_issues_project_sequence') THEN
CREATE INDEX idx_issues_project_sequence ON issues (project_id, project_sequence_no);
RAISE NOTICE '✅ idx_issues_project_sequence 인덱스가 생성되었습니다.';
ELSE
RAISE NOTICE ' idx_issues_project_sequence 인덱스가 이미 존재합니다.';
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'issues' AND indexname = 'idx_issues_responsible_department') THEN
CREATE INDEX idx_issues_responsible_department ON issues (responsible_department) WHERE responsible_department IS NOT NULL;
RAISE NOTICE '✅ idx_issues_responsible_department 인덱스가 생성되었습니다.';
ELSE
RAISE NOTICE ' idx_issues_responsible_department 인덱스가 이미 존재합니다.';
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'issues' AND indexname = 'idx_issues_expected_completion') THEN
CREATE INDEX idx_issues_expected_completion ON issues (expected_completion_date) WHERE expected_completion_date IS NOT NULL;
RAISE NOTICE '✅ idx_issues_expected_completion 인덱스가 생성되었습니다.';
ELSE
RAISE NOTICE ' idx_issues_expected_completion 인덱스가 이미 존재합니다.';
END IF;
-- 프로젝트별 순번 자동 생성 함수
CREATE OR REPLACE FUNCTION generate_project_sequence_no(p_project_id BIGINT) RETURNS INTEGER AS $func$
DECLARE
next_no INTEGER;
BEGIN
-- 해당 프로젝트의 최대 순번 + 1
SELECT COALESCE(MAX(project_sequence_no), 0) + 1
INTO next_no
FROM issues
WHERE project_id = p_project_id;
RETURN next_no;
END;
$func$ LANGUAGE plpgsql;
RAISE NOTICE '✅ generate_project_sequence_no 함수가 생성되었습니다.';
-- 기존 이슈들에 대해 프로젝트별 순번 설정
DO $update_sequence$
DECLARE
issue_record RECORD;
seq_no INTEGER;
BEGIN
FOR issue_record IN
SELECT id, project_id
FROM issues
WHERE project_sequence_no IS NULL
ORDER BY project_id, report_date
LOOP
SELECT generate_project_sequence_no(issue_record.project_id) INTO seq_no;
UPDATE issues
SET project_sequence_no = seq_no
WHERE id = issue_record.id;
END LOOP;
END $update_sequence$;
RAISE NOTICE '✅ 기존 이슈들의 프로젝트별 순번이 설정되었습니다.';
-- 기존 이슈들의 final_description과 final_category 초기화
UPDATE issues
SET
final_description = description,
final_category = category
WHERE final_description IS NULL OR final_category IS NULL;
RAISE NOTICE '✅ 기존 이슈들의 final_description과 final_category가 초기화되었습니다.';
-- 마이그레이션 검증
DECLARE
col_count INTEGER;
idx_count INTEGER;
func_count INTEGER;
BEGIN
SELECT COUNT(*) INTO col_count FROM information_schema.columns
WHERE table_name = 'issues' AND column_name IN (
'completion_photo_path', 'solution', 'responsible_department', 'responsible_person',
'expected_completion_date', 'actual_completion_date', 'cause_department',
'management_comment', 'project_sequence_no', 'final_description', 'final_category'
);
SELECT COUNT(*) INTO idx_count FROM pg_indexes
WHERE tablename = 'issues' AND indexname IN (
'idx_issues_project_sequence', 'idx_issues_responsible_department', 'idx_issues_expected_completion'
);
SELECT COUNT(*) INTO func_count FROM pg_proc WHERE proname = 'generate_project_sequence_no';
RAISE NOTICE '=== 마이그레이션 검증 결과 ===';
RAISE NOTICE '추가된 컬럼: %/11개', col_count;
RAISE NOTICE '생성된 인덱스: %/3개', idx_count;
RAISE NOTICE '생성된 함수: %/1개', func_count;
IF col_count = 11 AND idx_count = 3 AND func_count = 1 THEN
RAISE NOTICE '✅ 마이그레이션이 성공적으로 완료되었습니다!';
INSERT INTO migration_log (migration_file, status, notes) VALUES (migration_name, 'SUCCESS', migration_notes);
ELSE
RAISE EXCEPTION '❌ 마이그레이션 검증 실패!';
END IF;
END;
ELSIF current_status = 'SUCCESS' THEN
RAISE NOTICE ' 마이그레이션 %는 이미 성공적으로 실행되었습니다. 스킵합니다.', migration_name;
ELSE
RAISE NOTICE '⚠️ 마이그레이션 %는 이전에 실패했습니다. 수동 확인이 필요합니다.', migration_name;
END IF;
END $$;
COMMIT;