- Frontend: 하드코딩된 localhost API URL을 동적 URL 생성으로 변경 - reports-daily.html: 3곳 수정 (프로젝트 로드, 미리보기, 보고서 생성) - issues-archive.html: 프로젝트 로드 함수 수정 - issues-dashboard.html: 2곳 수정 (프로젝트 로드, 진행중 이슈 로드) - issues-inbox.html: 프로젝트 로드 함수 수정 - daily-work.html: 프로젝트 로드 함수 수정 - permissions.js: 2곳 수정 (권한 부여, 사용자 권한 조회) - Backup System: 완전한 백업/복구 시스템 구축 - backup_script.sh: 자동 백업 스크립트 (DB, 볼륨, 설정 파일) - restore_script.sh: 백업 복구 스크립트 - setup_auto_backup.sh: 자동 백업 스케줄 설정 (매일 오후 9시) - 백업 정책: 최신 10개 버전만 유지하여 용량 절약 - Migration: 5장 사진 지원 마이그레이션 파일 업데이트 이제 Cloudflare 환경(m.hyungi.net)에서 HTTPS 프로토콜로 API 호출하여 Mixed Content 오류 없이 모든 기능이 정상 작동합니다.
182 lines
9.4 KiB
PL/PgSQL
182 lines
9.4 KiB
PL/PgSQL
-- 021_add_5_photo_support.sql
|
||
-- 5장 사진 지원을 위한 추가 컬럼들
|
||
-- 작성일: 2025-11-08
|
||
-- 목적: photo_path3, photo_path4, photo_path5 및 completion_photo_path2~5 컬럼 추가
|
||
|
||
BEGIN;
|
||
|
||
DO $$
|
||
DECLARE
|
||
migration_name VARCHAR(255) := '021_add_5_photo_support.sql';
|
||
migration_notes TEXT := '5장 사진 지원: photo_path3~5, completion_photo_path2~5 컬럼 추가';
|
||
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(),
|
||
started_at TIMESTAMP WITH TIME ZONE,
|
||
completed_at TIMESTAMP WITH TIME ZONE
|
||
);
|
||
|
||
SELECT status INTO current_status FROM migration_log WHERE migration_file = migration_name;
|
||
|
||
IF current_status IS NULL THEN
|
||
RAISE NOTICE '--- 마이그레이션 % 시작 ---', migration_name;
|
||
|
||
-- 기본 사진 경로 3~5 추가
|
||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'issues' AND column_name = 'photo_path3') THEN
|
||
ALTER TABLE issues ADD COLUMN photo_path3 VARCHAR(500);
|
||
RAISE NOTICE '✅ issues.photo_path3 컬럼이 추가되었습니다.';
|
||
ELSE
|
||
RAISE NOTICE 'ℹ️ issues.photo_path3 컬럼이 이미 존재합니다.';
|
||
END IF;
|
||
|
||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'issues' AND column_name = 'photo_path4') THEN
|
||
ALTER TABLE issues ADD COLUMN photo_path4 VARCHAR(500);
|
||
RAISE NOTICE '✅ issues.photo_path4 컬럼이 추가되었습니다.';
|
||
ELSE
|
||
RAISE NOTICE 'ℹ️ issues.photo_path4 컬럼이 이미 존재합니다.';
|
||
END IF;
|
||
|
||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'issues' AND column_name = 'photo_path5') THEN
|
||
ALTER TABLE issues ADD COLUMN photo_path5 VARCHAR(500);
|
||
RAISE NOTICE '✅ issues.photo_path5 컬럼이 추가되었습니다.';
|
||
ELSE
|
||
RAISE NOTICE 'ℹ️ issues.photo_path5 컬럼이 이미 존재합니다.';
|
||
END IF;
|
||
|
||
-- 완료 사진 경로 2~5 추가
|
||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'issues' AND column_name = 'completion_photo_path2') THEN
|
||
ALTER TABLE issues ADD COLUMN completion_photo_path2 VARCHAR(500);
|
||
RAISE NOTICE '✅ issues.completion_photo_path2 컬럼이 추가되었습니다.';
|
||
ELSE
|
||
RAISE NOTICE 'ℹ️ issues.completion_photo_path2 컬럼이 이미 존재합니다.';
|
||
END IF;
|
||
|
||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'issues' AND column_name = 'completion_photo_path3') THEN
|
||
ALTER TABLE issues ADD COLUMN completion_photo_path3 VARCHAR(500);
|
||
RAISE NOTICE '✅ issues.completion_photo_path3 컬럼이 추가되었습니다.';
|
||
ELSE
|
||
RAISE NOTICE 'ℹ️ issues.completion_photo_path3 컬럼이 이미 존재합니다.';
|
||
END IF;
|
||
|
||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'issues' AND column_name = 'completion_photo_path4') THEN
|
||
ALTER TABLE issues ADD COLUMN completion_photo_path4 VARCHAR(500);
|
||
RAISE NOTICE '✅ issues.completion_photo_path4 컬럼이 추가되었습니다.';
|
||
ELSE
|
||
RAISE NOTICE 'ℹ️ issues.completion_photo_path4 컬럼이 이미 존재합니다.';
|
||
END IF;
|
||
|
||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'issues' AND column_name = 'completion_photo_path5') THEN
|
||
ALTER TABLE issues ADD COLUMN completion_photo_path5 VARCHAR(500);
|
||
RAISE NOTICE '✅ issues.completion_photo_path5 컬럼이 추가되었습니다.';
|
||
ELSE
|
||
RAISE NOTICE 'ℹ️ issues.completion_photo_path5 컬럼이 이미 존재합니다.';
|
||
END IF;
|
||
|
||
-- 추가 필드들 (최신 버전에서 필요한 것들)
|
||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'issues' AND column_name = 'completion_rejected_at') THEN
|
||
ALTER TABLE issues ADD COLUMN completion_rejected_at TIMESTAMP WITH TIME ZONE;
|
||
RAISE NOTICE '✅ issues.completion_rejected_at 컬럼이 추가되었습니다.';
|
||
ELSE
|
||
RAISE NOTICE 'ℹ️ issues.completion_rejected_at 컬럼이 이미 존재합니다.';
|
||
END IF;
|
||
|
||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'issues' AND column_name = 'completion_rejected_by_id') THEN
|
||
ALTER TABLE issues ADD COLUMN completion_rejected_by_id INTEGER REFERENCES users(id);
|
||
RAISE NOTICE '✅ issues.completion_rejected_by_id 컬럼이 추가되었습니다.';
|
||
ELSE
|
||
RAISE NOTICE 'ℹ️ issues.completion_rejected_by_id 컬럼이 이미 존재합니다.';
|
||
END IF;
|
||
|
||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'issues' AND column_name = 'completion_rejection_reason') THEN
|
||
ALTER TABLE issues ADD COLUMN completion_rejection_reason TEXT;
|
||
RAISE NOTICE '✅ issues.completion_rejection_reason 컬럼이 추가되었습니다.';
|
||
ELSE
|
||
RAISE NOTICE 'ℹ️ issues.completion_rejection_reason 컬럼이 이미 존재합니다.';
|
||
END IF;
|
||
|
||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'issues' AND column_name = 'last_exported_at') THEN
|
||
ALTER TABLE issues ADD COLUMN last_exported_at TIMESTAMP WITH TIME ZONE;
|
||
RAISE NOTICE '✅ issues.last_exported_at 컬럼이 추가되었습니다.';
|
||
ELSE
|
||
RAISE NOTICE 'ℹ️ issues.last_exported_at 컬럼이 이미 존재합니다.';
|
||
END IF;
|
||
|
||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'issues' AND column_name = 'export_count') THEN
|
||
ALTER TABLE issues ADD COLUMN export_count INTEGER DEFAULT 0;
|
||
RAISE NOTICE '✅ issues.export_count 컬럼이 추가되었습니다.';
|
||
ELSE
|
||
RAISE NOTICE 'ℹ️ issues.export_count 컬럼이 이미 존재합니다.';
|
||
END IF;
|
||
|
||
-- 인덱스 추가 (성능 향상)
|
||
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'issues' AND indexname = 'idx_issues_photo_path3') THEN
|
||
CREATE INDEX idx_issues_photo_path3 ON issues (photo_path3) WHERE photo_path3 IS NOT NULL;
|
||
RAISE NOTICE '✅ idx_issues_photo_path3 인덱스가 생성되었습니다.';
|
||
ELSE
|
||
RAISE NOTICE 'ℹ️ idx_issues_photo_path3 인덱스가 이미 존재합니다.';
|
||
END IF;
|
||
|
||
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'issues' AND indexname = 'idx_issues_photo_path4') THEN
|
||
CREATE INDEX idx_issues_photo_path4 ON issues (photo_path4) WHERE photo_path4 IS NOT NULL;
|
||
RAISE NOTICE '✅ idx_issues_photo_path4 인덱스가 생성되었습니다.';
|
||
ELSE
|
||
RAISE NOTICE 'ℹ️ idx_issues_photo_path4 인덱스가 이미 존재합니다.';
|
||
END IF;
|
||
|
||
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'issues' AND indexname = 'idx_issues_photo_path5') THEN
|
||
CREATE INDEX idx_issues_photo_path5 ON issues (photo_path5) WHERE photo_path5 IS NOT NULL;
|
||
RAISE NOTICE '✅ idx_issues_photo_path5 인덱스가 생성되었습니다.';
|
||
ELSE
|
||
RAISE NOTICE 'ℹ️ idx_issues_photo_path5 인덱스가 이미 존재합니다.';
|
||
END IF;
|
||
|
||
-- 마이그레이션 검증
|
||
DECLARE
|
||
col_count INTEGER;
|
||
idx_count INTEGER;
|
||
BEGIN
|
||
SELECT COUNT(*) INTO col_count FROM information_schema.columns
|
||
WHERE table_name = 'issues' AND column_name IN (
|
||
'photo_path3', 'photo_path4', 'photo_path5',
|
||
'completion_photo_path2', 'completion_photo_path3', 'completion_photo_path4', 'completion_photo_path5',
|
||
'completion_rejected_at', 'completion_rejected_by_id', 'completion_rejection_reason',
|
||
'last_exported_at', 'export_count'
|
||
);
|
||
|
||
SELECT COUNT(*) INTO idx_count FROM pg_indexes
|
||
WHERE tablename = 'issues' AND indexname IN (
|
||
'idx_issues_photo_path3', 'idx_issues_photo_path4', 'idx_issues_photo_path5'
|
||
);
|
||
|
||
RAISE NOTICE '=== 마이그레이션 검증 결과 ===';
|
||
RAISE NOTICE '추가된 컬럼: %/11개', col_count;
|
||
RAISE NOTICE '생성된 인덱스: %/3개', idx_count;
|
||
|
||
IF col_count = 11 AND idx_count = 3 THEN
|
||
RAISE NOTICE '✅ 마이그레이션이 성공적으로 완료되었습니다!';
|
||
INSERT INTO migration_log (migration_file, status, notes, completed_at) VALUES (migration_name, 'SUCCESS', migration_notes, NOW());
|
||
ELSE
|
||
RAISE EXCEPTION '❌ 마이그레이션 검증 실패!';
|
||
END IF;
|
||
END;
|
||
|
||
ELSIF current_status = 'SUCCESS' THEN
|
||
RAISE NOTICE 'ℹ️ 마이그레이션 %는 이미 성공적으로 실행되었습니다. 스킵합니다.', migration_name;
|
||
ELSE
|
||
RAISE NOTICE '⚠️ 마이그레이션 %는 이전에 실패했습니다. 수동 확인이 필요합니다.', migration_name;
|
||
END IF;
|
||
END $$;
|
||
|
||
COMMIT;
|
||
|
||
|
||
|
||
|