🎯 UI/UX 개선 및 안정성 강화
Some checks failed
SonarQube Analysis / SonarQube Scan (push) Has been cancelled
Some checks failed
SonarQube Analysis / SonarQube Scan (push) Has been cancelled
✅ 주요 개선사항: - Rev.0일 때 Revisions 카운트 0으로 정확히 표시 - 업로드 후 파일 목록 자동 새로고침 - 대시보드 계정 메뉴 zIndex 문제 해결 - 구매관리 페이지 500 오류 해결 및 대시보드 리다이렉트 - 구매신청 관리 페이지 버튼 텍스트 개선 🔧 기술적 수정: - purchase_requests API SQL 쿼리 테이블 구조에 맞게 수정 - UserMenu 드롭다운 zIndex 1050으로 상향 조정 - 프론트엔드 완전 재빌드로 최신 변경사항 반영 - 완전한 자동 마이그레이션 시스템 구축 (43개 테이블 스키마 동기화) 🚀 다음 단계: 리비전 기능 재도입 준비 완료
This commit is contained in:
@@ -11,6 +11,7 @@ RUN apt-get update && apt-get install -y \
|
||||
libpq-dev \
|
||||
libmagic1 \
|
||||
libmagic-dev \
|
||||
netcat-openbsd \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# requirements.txt 복사 및 의존성 설치
|
||||
@@ -27,4 +28,4 @@ EXPOSE 8000
|
||||
ENV PYTHONPATH=/app
|
||||
|
||||
# 서버 실행
|
||||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
CMD ["bash", "start.sh"]
|
||||
@@ -187,17 +187,14 @@ async def get_purchase_requests(
|
||||
pr.request_no,
|
||||
pr.file_id,
|
||||
pr.job_no,
|
||||
pr.category,
|
||||
pr.material_count,
|
||||
pr.excel_file_path,
|
||||
pr.requested_at,
|
||||
pr.total_items,
|
||||
pr.request_date,
|
||||
pr.status,
|
||||
u.name as requested_by,
|
||||
pr.requested_by_username as requested_by,
|
||||
f.original_filename,
|
||||
j.job_name,
|
||||
COUNT(pri.item_id) as item_count
|
||||
FROM purchase_requests pr
|
||||
LEFT JOIN users u ON pr.requested_by = u.user_id
|
||||
LEFT JOIN files f ON pr.file_id = f.id
|
||||
LEFT JOIN jobs j ON pr.job_no = j.job_no
|
||||
LEFT JOIN purchase_request_items pri ON pr.request_id = pri.request_id
|
||||
@@ -207,9 +204,9 @@ async def get_purchase_requests(
|
||||
AND (:status IS NULL OR pr.status = :status)
|
||||
GROUP BY
|
||||
pr.request_id, pr.request_no, pr.file_id, pr.job_no,
|
||||
pr.category, pr.material_count, pr.excel_file_path,
|
||||
pr.requested_at, pr.status, u.name, f.original_filename, j.job_name
|
||||
ORDER BY pr.requested_at DESC
|
||||
pr.total_items, pr.request_date, pr.status,
|
||||
pr.requested_by_username, f.original_filename, j.job_name
|
||||
ORDER BY pr.request_date DESC
|
||||
""")
|
||||
|
||||
results = db.execute(query, {
|
||||
@@ -226,11 +223,11 @@ async def get_purchase_requests(
|
||||
"file_id": row.file_id,
|
||||
"job_no": row.job_no,
|
||||
"job_name": row.job_name,
|
||||
"category": row.category,
|
||||
"material_count": row.material_count,
|
||||
"category": "ALL", # 기본값
|
||||
"material_count": row.total_items or 0,
|
||||
"item_count": row.item_count,
|
||||
"excel_file_path": row.excel_file_path,
|
||||
"requested_at": row.requested_at.isoformat() if row.requested_at else None,
|
||||
"excel_file_path": None, # 현재 테이블에 없음
|
||||
"requested_at": row.request_date.isoformat() if row.request_date else None,
|
||||
"status": row.status,
|
||||
"requested_by": row.requested_by,
|
||||
"source_file": row.original_filename
|
||||
|
||||
437
backend/scripts/create_missing_tables.py
Normal file
437
backend/scripts/create_missing_tables.py
Normal file
@@ -0,0 +1,437 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
누락된 테이블 생성 스크립트
|
||||
- support_details
|
||||
- special_material_details
|
||||
- purchase_requests
|
||||
- purchase_request_items
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import psycopg2
|
||||
from psycopg2.extras import RealDictCursor
|
||||
import bcrypt
|
||||
|
||||
# 프로젝트 루트를 Python path에 추가
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
def get_db_connection():
|
||||
"""데이터베이스 연결"""
|
||||
try:
|
||||
# Docker 환경에서는 서비스명으로 연결
|
||||
conn = psycopg2.connect(
|
||||
host="tk-mp-postgres",
|
||||
port="5432",
|
||||
database="tk_mp_bom",
|
||||
user="tkmp_user",
|
||||
password="tkmp_password_2025"
|
||||
)
|
||||
return conn
|
||||
except Exception as e:
|
||||
print(f"❌ DB 연결 실패: {e}")
|
||||
return None
|
||||
|
||||
def create_admin_user(cursor):
|
||||
"""기본 admin 계정 생성"""
|
||||
try:
|
||||
# admin 계정이 이미 있는지 확인
|
||||
cursor.execute("SELECT COUNT(*) FROM users WHERE username = 'admin';")
|
||||
if cursor.fetchone()[0] > 0:
|
||||
print("✅ admin 계정이 이미 존재합니다.")
|
||||
return
|
||||
|
||||
# bcrypt로 비밀번호 해시 생성
|
||||
password = "admin123"
|
||||
hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
|
||||
|
||||
# admin 계정 생성
|
||||
cursor.execute("""
|
||||
INSERT INTO users (
|
||||
username, password, name, email, role, access_level,
|
||||
is_active, status, department, position
|
||||
) VALUES (
|
||||
'admin', %s, 'System Administrator', 'admin@example.com',
|
||||
'admin', 'admin', true, 'active', 'IT', 'Administrator'
|
||||
);
|
||||
""", (hashed_password,))
|
||||
|
||||
print("✅ admin 계정 생성 완료 (username: admin, password: admin123)")
|
||||
|
||||
except Exception as e:
|
||||
print(f"⚠️ admin 계정 생성 실패: {e}")
|
||||
|
||||
def add_missing_columns(cursor):
|
||||
"""누락된 컬럼들 추가"""
|
||||
try:
|
||||
print("🔧 누락된 컬럼 확인 및 추가 중...")
|
||||
|
||||
# users 테이블에 status 컬럼 확인 및 추가
|
||||
cursor.execute("""
|
||||
SELECT column_name
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = 'users' AND column_name = 'status';
|
||||
""")
|
||||
|
||||
if not cursor.fetchone():
|
||||
print("➕ users 테이블에 status 컬럼 추가 중...")
|
||||
cursor.execute("""
|
||||
ALTER TABLE users ADD COLUMN status VARCHAR(20) DEFAULT 'active';
|
||||
""")
|
||||
print("✅ users.status 컬럼 추가 완료")
|
||||
else:
|
||||
print("✅ users.status 컬럼이 이미 존재합니다")
|
||||
|
||||
# files 테이블에 누락된 컬럼들 확인 및 추가
|
||||
files_columns = {
|
||||
'job_no': 'VARCHAR(50)',
|
||||
'bom_name': 'VARCHAR(255)',
|
||||
'description': 'TEXT',
|
||||
'parsed_count': 'INTEGER DEFAULT 0',
|
||||
'classification_completed': 'BOOLEAN DEFAULT FALSE'
|
||||
}
|
||||
|
||||
for column_name, column_type in files_columns.items():
|
||||
cursor.execute("""
|
||||
SELECT column_name
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = 'files' AND column_name = %s;
|
||||
""", (column_name,))
|
||||
|
||||
if not cursor.fetchone():
|
||||
print(f"➕ files 테이블에 {column_name} 컬럼 추가 중...")
|
||||
cursor.execute(f"""
|
||||
ALTER TABLE files ADD COLUMN {column_name} {column_type};
|
||||
""")
|
||||
print(f"✅ files.{column_name} 컬럼 추가 완료")
|
||||
else:
|
||||
print(f"✅ files.{column_name} 컬럼이 이미 존재합니다")
|
||||
|
||||
# materials 테이블에 누락된 컬럼들 확인 및 추가
|
||||
materials_columns = {
|
||||
'main_nom': 'VARCHAR(50)',
|
||||
'red_nom': 'VARCHAR(50)',
|
||||
'full_material_grade': 'TEXT',
|
||||
'row_number': 'INTEGER',
|
||||
'length': 'NUMERIC(10,3)',
|
||||
'purchase_confirmed': 'BOOLEAN DEFAULT FALSE',
|
||||
'confirmed_quantity': 'NUMERIC(10,3)',
|
||||
'purchase_status': 'VARCHAR(20)',
|
||||
'purchase_confirmed_by': 'VARCHAR(100)',
|
||||
'purchase_confirmed_at': 'TIMESTAMP',
|
||||
'revision_status': 'VARCHAR(20)',
|
||||
'material_hash': 'VARCHAR(64)',
|
||||
'normalized_description': 'TEXT',
|
||||
'drawing_reference': 'VARCHAR(100)',
|
||||
'notes': 'TEXT',
|
||||
'created_at': 'TIMESTAMP DEFAULT CURRENT_TIMESTAMP',
|
||||
'brand': 'VARCHAR(100)',
|
||||
'user_requirement': 'TEXT',
|
||||
'is_active': 'BOOLEAN DEFAULT TRUE',
|
||||
'total_length': 'NUMERIC(10,3)'
|
||||
}
|
||||
|
||||
for column_name, column_type in materials_columns.items():
|
||||
cursor.execute("""
|
||||
SELECT column_name
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = 'materials' AND column_name = %s;
|
||||
""", (column_name,))
|
||||
|
||||
if not cursor.fetchone():
|
||||
print(f"➕ materials 테이블에 {column_name} 컬럼 추가 중...")
|
||||
cursor.execute(f"""
|
||||
ALTER TABLE materials ADD COLUMN {column_name} {column_type};
|
||||
""")
|
||||
print(f"✅ materials.{column_name} 컬럼 추가 완료")
|
||||
else:
|
||||
print(f"✅ materials.{column_name} 컬럼이 이미 존재합니다")
|
||||
|
||||
# purchase_requests 테이블에 누락된 컬럼들 확인 및 추가
|
||||
purchase_requests_columns = {
|
||||
'file_id': 'INTEGER REFERENCES files(id)'
|
||||
}
|
||||
|
||||
for column_name, column_type in purchase_requests_columns.items():
|
||||
cursor.execute("""
|
||||
SELECT column_name
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = 'purchase_requests' AND column_name = %s;
|
||||
""", (column_name,))
|
||||
|
||||
if not cursor.fetchone():
|
||||
print(f"➕ purchase_requests 테이블에 {column_name} 컬럼 추가 중...")
|
||||
cursor.execute(f"""
|
||||
ALTER TABLE purchase_requests ADD COLUMN {column_name} {column_type};
|
||||
""")
|
||||
print(f"✅ purchase_requests.{column_name} 컬럼 추가 완료")
|
||||
else:
|
||||
print(f"✅ purchase_requests.{column_name} 컬럼이 이미 존재합니다")
|
||||
|
||||
# material_purchase_tracking 테이블에 누락된 컬럼들 확인 및 추가
|
||||
mpt_columns = {
|
||||
'description': 'TEXT',
|
||||
'purchase_status': 'VARCHAR(20) DEFAULT \'pending\''
|
||||
}
|
||||
|
||||
for column_name, column_type in mpt_columns.items():
|
||||
cursor.execute("""
|
||||
SELECT column_name
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = 'material_purchase_tracking' AND column_name = %s;
|
||||
""", (column_name,))
|
||||
|
||||
if not cursor.fetchone():
|
||||
print(f"➕ material_purchase_tracking 테이블에 {column_name} 컬럼 추가 중...")
|
||||
cursor.execute(f"""
|
||||
ALTER TABLE material_purchase_tracking ADD COLUMN {column_name} {column_type};
|
||||
""")
|
||||
print(f"✅ material_purchase_tracking.{column_name} 컬럼 추가 완료")
|
||||
else:
|
||||
print(f"✅ material_purchase_tracking.{column_name} 컬럼이 이미 존재합니다")
|
||||
|
||||
except Exception as e:
|
||||
print(f"⚠️ 컬럼 추가 실패: {e}")
|
||||
|
||||
def create_missing_tables():
|
||||
"""누락된 테이블들 생성 (처음 설치 시에만)"""
|
||||
|
||||
conn = get_db_connection()
|
||||
if not conn:
|
||||
return False
|
||||
|
||||
try:
|
||||
cursor = conn.cursor()
|
||||
|
||||
# 이미 설치되어 있는지 확인 (핵심 테이블들이 모두 존재하는지 체크)
|
||||
print("🔍 기존 설치 상태 확인 중...")
|
||||
cursor.execute("""
|
||||
SELECT COUNT(*) FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name IN ('support_details', 'special_material_details', 'purchase_requests', 'purchase_request_items');
|
||||
""")
|
||||
|
||||
existing_tables = cursor.fetchone()[0]
|
||||
|
||||
if existing_tables == 4:
|
||||
print("✅ 모든 테이블이 이미 존재합니다.")
|
||||
|
||||
# 컬럼 체크는 항상 수행
|
||||
print("🔧 누락된 컬럼 확인 중...")
|
||||
add_missing_columns(cursor)
|
||||
|
||||
# admin 계정 확인
|
||||
cursor.execute("SELECT COUNT(*) FROM users WHERE username = 'admin';")
|
||||
admin_exists = cursor.fetchone()[0]
|
||||
|
||||
if admin_exists == 0:
|
||||
print("👤 admin 계정 생성 중...")
|
||||
create_admin_user(cursor)
|
||||
conn.commit()
|
||||
print("✅ admin 계정 생성 완료")
|
||||
else:
|
||||
print("✅ admin 계정이 이미 존재합니다.")
|
||||
|
||||
conn.commit()
|
||||
return True
|
||||
|
||||
print(f"🔍 누락된 테이블 확인 및 생성 중... ({existing_tables}/4개 존재)")
|
||||
|
||||
# 1. support_details 테이블
|
||||
print("📋 1. support_details 테이블 확인...")
|
||||
cursor.execute("""
|
||||
SELECT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'support_details'
|
||||
);
|
||||
""")
|
||||
|
||||
if not cursor.fetchone()[0]:
|
||||
print("➕ support_details 테이블 생성 중...")
|
||||
cursor.execute("""
|
||||
CREATE TABLE support_details (
|
||||
id SERIAL PRIMARY KEY,
|
||||
material_id INTEGER REFERENCES materials(id) ON DELETE CASCADE,
|
||||
file_id INTEGER REFERENCES files(id) ON DELETE CASCADE,
|
||||
support_type VARCHAR(50),
|
||||
support_subtype VARCHAR(100),
|
||||
load_rating VARCHAR(50),
|
||||
load_capacity VARCHAR(50),
|
||||
material_standard VARCHAR(100),
|
||||
material_grade VARCHAR(50),
|
||||
pipe_size VARCHAR(20),
|
||||
length_mm NUMERIC(10,2),
|
||||
width_mm NUMERIC(10,2),
|
||||
height_mm NUMERIC(10,2),
|
||||
classification_confidence NUMERIC(3,2),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_support_details_material_id ON support_details(material_id);
|
||||
CREATE INDEX idx_support_details_file_id ON support_details(file_id);
|
||||
""")
|
||||
print("✅ support_details 테이블 생성 완료")
|
||||
else:
|
||||
print("✅ support_details 테이블 이미 존재")
|
||||
|
||||
# 2. special_material_details 테이블
|
||||
print("📋 2. special_material_details 테이블 확인...")
|
||||
cursor.execute("""
|
||||
SELECT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'special_material_details'
|
||||
);
|
||||
""")
|
||||
|
||||
if not cursor.fetchone()[0]:
|
||||
print("➕ special_material_details 테이블 생성 중...")
|
||||
cursor.execute("""
|
||||
CREATE TABLE special_material_details (
|
||||
id SERIAL PRIMARY KEY,
|
||||
material_id INTEGER REFERENCES materials(id) ON DELETE CASCADE,
|
||||
file_id INTEGER REFERENCES files(id) ON DELETE CASCADE,
|
||||
special_type VARCHAR(50),
|
||||
special_subtype VARCHAR(100),
|
||||
material_standard VARCHAR(100),
|
||||
material_grade VARCHAR(50),
|
||||
specifications TEXT,
|
||||
dimensions VARCHAR(100),
|
||||
weight_kg NUMERIC(10,3),
|
||||
classification_confidence NUMERIC(3,2),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_special_material_details_material_id ON special_material_details(material_id);
|
||||
CREATE INDEX idx_special_material_details_file_id ON special_material_details(file_id);
|
||||
""")
|
||||
print("✅ special_material_details 테이블 생성 완료")
|
||||
else:
|
||||
print("✅ special_material_details 테이블 이미 존재")
|
||||
|
||||
# 3. purchase_requests 테이블
|
||||
print("📋 3. purchase_requests 테이블 확인...")
|
||||
cursor.execute("""
|
||||
SELECT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'purchase_requests'
|
||||
);
|
||||
""")
|
||||
|
||||
if not cursor.fetchone()[0]:
|
||||
print("➕ purchase_requests 테이블 생성 중...")
|
||||
cursor.execute("""
|
||||
CREATE TABLE purchase_requests (
|
||||
request_id SERIAL PRIMARY KEY,
|
||||
request_no VARCHAR(50) UNIQUE NOT NULL,
|
||||
job_no VARCHAR(50) NOT NULL,
|
||||
project_name VARCHAR(200),
|
||||
requested_by INTEGER REFERENCES users(user_id),
|
||||
requested_by_username VARCHAR(100),
|
||||
request_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
status VARCHAR(20) DEFAULT 'pending',
|
||||
total_items INTEGER DEFAULT 0,
|
||||
notes TEXT,
|
||||
approved_by INTEGER REFERENCES users(user_id),
|
||||
approved_by_username VARCHAR(100),
|
||||
approved_at TIMESTAMP,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_purchase_requests_job_no ON purchase_requests(job_no);
|
||||
CREATE INDEX idx_purchase_requests_status ON purchase_requests(status);
|
||||
CREATE INDEX idx_purchase_requests_requested_by ON purchase_requests(requested_by);
|
||||
""")
|
||||
print("✅ purchase_requests 테이블 생성 완료")
|
||||
else:
|
||||
print("✅ purchase_requests 테이블 이미 존재")
|
||||
|
||||
# 4. purchase_request_items 테이블
|
||||
print("📋 4. purchase_request_items 테이블 확인...")
|
||||
cursor.execute("""
|
||||
SELECT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'purchase_request_items'
|
||||
);
|
||||
""")
|
||||
|
||||
if not cursor.fetchone()[0]:
|
||||
print("➕ purchase_request_items 테이블 생성 중...")
|
||||
cursor.execute("""
|
||||
CREATE TABLE purchase_request_items (
|
||||
item_id SERIAL PRIMARY KEY,
|
||||
request_id INTEGER REFERENCES purchase_requests(request_id) ON DELETE CASCADE,
|
||||
material_id INTEGER REFERENCES materials(id) ON DELETE CASCADE,
|
||||
description TEXT NOT NULL,
|
||||
category VARCHAR(50),
|
||||
subcategory VARCHAR(100),
|
||||
material_grade VARCHAR(50),
|
||||
size_spec VARCHAR(50),
|
||||
quantity NUMERIC(10,3) NOT NULL,
|
||||
unit VARCHAR(10) NOT NULL,
|
||||
drawing_name VARCHAR(100),
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_purchase_request_items_request_id ON purchase_request_items(request_id);
|
||||
CREATE INDEX idx_purchase_request_items_material_id ON purchase_request_items(material_id);
|
||||
CREATE INDEX idx_purchase_request_items_category ON purchase_request_items(category);
|
||||
""")
|
||||
print("✅ purchase_request_items 테이블 생성 완료")
|
||||
else:
|
||||
print("✅ purchase_request_items 테이블 이미 존재")
|
||||
|
||||
# 변경사항 커밋
|
||||
conn.commit()
|
||||
print("\n🎉 누락된 테이블 생성 완료!")
|
||||
|
||||
# 최종 테이블 목록 확인
|
||||
print("\n📋 현재 테이블 목록:")
|
||||
cursor.execute("""
|
||||
SELECT table_name
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
ORDER BY table_name;
|
||||
""")
|
||||
|
||||
tables = cursor.fetchall()
|
||||
for table in tables:
|
||||
print(f" - {table[0]}")
|
||||
|
||||
print(f"\n총 {len(tables)}개 테이블 존재")
|
||||
|
||||
# users 테이블에 status 컬럼 추가 (필요한 경우)
|
||||
add_missing_columns(cursor)
|
||||
|
||||
# admin 계정 생성
|
||||
create_admin_user(cursor)
|
||||
conn.commit()
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 테이블 생성 실패: {e}")
|
||||
conn.rollback()
|
||||
return False
|
||||
|
||||
finally:
|
||||
if conn:
|
||||
conn.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("🚀 누락된 테이블 생성 시작...")
|
||||
success = create_missing_tables()
|
||||
|
||||
if success:
|
||||
print("✅ 모든 작업 완료!")
|
||||
sys.exit(0)
|
||||
else:
|
||||
print("❌ 작업 실패!")
|
||||
sys.exit(1)
|
||||
25
backend/start.sh
Executable file
25
backend/start.sh
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "🚀 TK-MP Backend 시작 중..."
|
||||
|
||||
# 데이터베이스 연결 대기
|
||||
echo "⏳ 데이터베이스 연결 대기 중..."
|
||||
while ! nc -z tk-mp-postgres 5432; do
|
||||
sleep 1
|
||||
done
|
||||
echo "✅ 데이터베이스 연결 확인"
|
||||
|
||||
# 자동 마이그레이션 실행 (처음 설치 시에만)
|
||||
echo "🔧 자동 마이그레이션 실행 중..."
|
||||
python scripts/create_missing_tables.py
|
||||
|
||||
migration_result=$?
|
||||
if [ $migration_result -eq 0 ]; then
|
||||
echo "✅ 마이그레이션 완료"
|
||||
else
|
||||
echo "⚠️ 마이그레이션에 문제가 있었지만 서버를 시작합니다..."
|
||||
fi
|
||||
|
||||
# FastAPI 서버 시작
|
||||
echo "🌟 FastAPI 서버 시작..."
|
||||
exec uvicorn app.main:app --host 0.0.0.0 --port 8000
|
||||
Reference in New Issue
Block a user