#!/usr/bin/env python3 """ TK-MP-Project 간단하고 안정적인 DB 마이그레이션 스크립트 macOS Docker와 Synology Container Manager 모두 지원 """ import os import sys import time import psycopg2 from datetime import datetime def get_db_config(): """환경변수에서 DB 설정 가져오기""" return { 'host': os.getenv('DB_HOST', 'postgres'), 'port': int(os.getenv('DB_PORT', 5432)), 'database': os.getenv('DB_NAME', 'tk_mp_bom'), 'user': os.getenv('DB_USER', 'tkmp_user'), 'password': os.getenv('DB_PASSWORD', 'tkmp_password') } def wait_for_database(max_retries=60, retry_interval=2): """데이터베이스 연결 대기 (더 긴 대기시간과 짧은 간격)""" db_config = get_db_config() for attempt in range(1, max_retries + 1): try: conn = psycopg2.connect(**db_config) conn.close() print(f"✅ 데이터베이스 연결 성공 (시도 {attempt}/{max_retries})") return True except Exception as e: print(f"⏳ DB 연결 대기 중... ({attempt}/{max_retries}) - {str(e)[:50]}") time.sleep(retry_interval) print("❌ 데이터베이스 연결 실패") return False def execute_sql(sql_commands): """SQL 명령어 실행""" db_config = get_db_config() try: conn = psycopg2.connect(**db_config) cursor = conn.cursor() for sql in sql_commands: if sql.strip(): cursor.execute(sql) conn.commit() cursor.close() conn.close() return True except Exception as e: print(f"❌ SQL 실행 실패: {str(e)}") return False def get_migration_sql(): """필요한 마이그레이션 SQL 반환""" return [ # materials 테이블 컬럼 추가 "ALTER TABLE materials ADD COLUMN IF NOT EXISTS row_number INTEGER;", "ALTER TABLE materials ADD COLUMN IF NOT EXISTS main_nom VARCHAR(50);", "ALTER TABLE materials ADD COLUMN IF NOT EXISTS red_nom VARCHAR(50);", "ALTER TABLE materials ADD COLUMN IF NOT EXISTS full_material_grade TEXT;", "ALTER TABLE materials ADD COLUMN IF NOT EXISTS length NUMERIC(10,3);", "ALTER TABLE materials ADD COLUMN IF NOT EXISTS purchase_confirmed BOOLEAN DEFAULT FALSE;", "ALTER TABLE materials ADD COLUMN IF NOT EXISTS confirmed_quantity NUMERIC(10,3);", "ALTER TABLE materials ADD COLUMN IF NOT EXISTS purchase_status VARCHAR(20);", "ALTER TABLE materials ADD COLUMN IF NOT EXISTS purchase_confirmed_by VARCHAR(100);", "ALTER TABLE materials ADD COLUMN IF NOT EXISTS purchase_confirmed_at TIMESTAMP;", "ALTER TABLE materials ADD COLUMN IF NOT EXISTS revision_status VARCHAR(20);", "ALTER TABLE materials ADD COLUMN IF NOT EXISTS material_hash VARCHAR(64);", "ALTER TABLE materials ADD COLUMN IF NOT EXISTS normalized_description TEXT;", # users 테이블 status 컬럼 확인 및 추가 "ALTER TABLE users ADD COLUMN IF NOT EXISTS status VARCHAR(20) DEFAULT 'active';", "UPDATE users SET status = 'active' WHERE status IS NULL AND is_active = TRUE;", "UPDATE users SET status = 'inactive' WHERE status IS NULL AND is_active = FALSE;", # 기본 관리자 계정 확인 및 생성 """ INSERT INTO users (username, password, name, email, role, access_level, department, position, status) VALUES ('admin', '$2b$12$ld4LDOW5mxkiRQEkXfMUIep/aIzFleQZ4yoL10ZQkUxGqnkYuhNMW', '시스템 관리자', 'admin@tkmp.com', 'admin', 'admin', 'IT', '시스템 관리자', 'active') ON CONFLICT (username) DO UPDATE SET password = EXCLUDED.password, status = 'active'; """, # 인덱스 생성 "CREATE INDEX IF NOT EXISTS idx_materials_main_nom ON materials(main_nom);", "CREATE INDEX IF NOT EXISTS idx_materials_red_nom ON materials(red_nom);", "CREATE INDEX IF NOT EXISTS idx_materials_revision_status ON materials(revision_status);", "CREATE INDEX IF NOT EXISTS idx_materials_purchase_status ON materials(purchase_status);", "CREATE INDEX IF NOT EXISTS idx_users_status ON users(status);", ] def main(): """메인 실행 함수""" print("🚀 TK-MP-Project 간단 DB 마이그레이션 시작") print(f"⏰ 시작 시간: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") # 1. 데이터베이스 연결 대기 print("🔄 데이터베이스 연결 확인 중...") if not wait_for_database(): print("❌ 데이터베이스 연결 실패. 마이그레이션을 중단합니다.") sys.exit(1) # 2. 마이그레이션 실행 print("🔄 데이터베이스 마이그레이션 실행 중...") migration_sql = get_migration_sql() if execute_sql(migration_sql): print("✅ 데이터베이스 마이그레이션 완료") else: print("❌ 데이터베이스 마이그레이션 실패") sys.exit(1) print("🎉 간단 DB 마이그레이션 완료!") print(f"⏰ 완료 시간: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") print("👤 기본 계정: admin/admin123") if __name__ == "__main__": main()