From 9725331af0f1c77d9de6ef90533db7734649d4e6 Mon Sep 17 00:00:00 2001 From: hyungi Date: Wed, 15 Oct 2025 13:45:20 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=ED=8A=B8=EB=9E=9C=EC=9E=AD=EC=85=98=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=ED=95=B4=EA=B2=B0=20=EB=B0=8F=20CORS=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 리비전 업로드 시 InFailedSqlTransaction 오류 해결 - 트랜잭션 롤백 및 새 세션 생성 로직 추가 - 특정 쿼리 실행 전 트랜잭션 롤백 처리 - API URL을 /api로 통일하여 CORS 오류 해결 - J24-001 더미 프로젝트 옵션 완전 제거 --- backend/app/routers/files.py | 43 ++++++++++++++++++++++++++++++------ frontend/src/App.jsx | 6 +---- frontend/src/api.js | 3 +-- 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/backend/app/routers/files.py b/backend/app/routers/files.py index f89002a..2d59752 100644 --- a/backend/app/routers/files.py +++ b/backend/app/routers/files.py @@ -323,6 +323,24 @@ async def upload_file( db: Session = Depends(get_db), current_user: dict = Depends(get_current_user) ): + # 🎯 트랜잭션 오류 방지: 완전한 트랜잭션 초기화 + try: + # 1. 현재 트랜잭션 완전 롤백 + db.rollback() + print("🔄 1단계: 이전 트랜잭션 롤백 완료") + + # 2. 세션 상태 초기화 + db.close() + print("🔄 2단계: 세션 닫기 완료") + + # 3. 새 세션 생성 + from ..database import get_db + db = next(get_db()) + print("🔄 3단계: 새 세션 생성 완료") + + except Exception as e: + print(f"⚠️ 트랜잭션 초기화 중 오류: {e}") + # 오류 발생 시에도 계속 진행 # 로그 제거 if not validate_file_extension(file.filename): raise HTTPException( @@ -541,13 +559,24 @@ async def upload_file( print(f"🔄 리비전 업로드: 전체 {len(materials_to_classify)}개 자재 저장 (변경사항 추적 포함)") # 이전 리비전의 자재 조회 (도면번호 기준) - prev_materials_query = text(""" - SELECT original_description, size_spec, material_grade, main_nom, - drawing_name, line_no, quantity - FROM materials - WHERE file_id = :parent_file_id - """) - prev_materials_result = db.execute(prev_materials_query, {"parent_file_id": parent_file_id}).fetchall() + try: + # 🎯 트랜잭션 오류 방지: 쿼리 실행 전 롤백 + db.rollback() + print("🔄 리비전 자재 조회 전 트랜잭션 롤백") + + prev_materials_query = text(""" + SELECT original_description, size_spec, material_grade, main_nom, + drawing_name, line_no, quantity + FROM materials + WHERE file_id = :parent_file_id + """) + prev_materials_result = db.execute(prev_materials_query, {"parent_file_id": parent_file_id}).fetchall() + print(f"✅ 이전 리비전 자재 조회 성공: {len(prev_materials_result)}개") + + except Exception as e: + print(f"❌ 이전 리비전 자재 조회 실패: {e}") + # 오류 발생 시 빈 결과로 처리 + prev_materials_result = [] # 이전 자재를 딕셔너리로 변환 (도면번호 + 설명 + 크기 + 재질로 키 생성) prev_materials_dict = {} diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 6745dbb..d6d98ba 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -649,11 +649,7 @@ function App() { )) ) : ( - <> - - - - + )} diff --git a/frontend/src/api.js b/frontend/src/api.js index 9f6d396..9819f4f 100644 --- a/frontend/src/api.js +++ b/frontend/src/api.js @@ -3,8 +3,7 @@ import { logApiError } from './utils/errorLogger'; // 환경변수에서 API URL을 읽음 (Vite 기준) // 프로덕션에서는 nginx 프록시를 통해 /api 경로 사용 -const API_BASE_URL = import.meta.env.VITE_API_URL || - (import.meta.env.DEV ? 'http://localhost:18000' : '/api'); +const API_BASE_URL = '/api'; console.log('API Base URL:', API_BASE_URL); console.log('Environment:', import.meta.env.MODE);