Files
TK-BOM-Project/backend/app/main.py
Hyungi Ahn 83b90ef05c
Some checks failed
SonarQube Analysis / SonarQube Scan (push) Has been cancelled
feat: 자재 관리 페이지 대규모 개선
- 파이프 수량 계산 로직 수정 (단관 개수가 아닌 실제 길이 기반 계산)
- UI 전면 개편 (DevonThink 스타일의 간결하고 세련된 디자인)
- 자재별 그룹핑 로직 개선:
  * 플랜지: 동일 사양별 그룹핑, WN 스케줄 표시, ORIFICE 풀네임 표시
  * 피팅: 상세 타입 표시 (니플 길이, 엘보 각도/연결, 티 타입, 리듀서 타입 등)
  * 밸브: 동일 사양별 그룹핑, 타입/연결방식/압력 표시
  * 볼트: 크기/재질/길이별 그룹핑 (8SET → 개별 집계)
  * 가스켓: 동일 사양별 그룹핑, 재질/상세내역/두께 분리 표시
  * UNKNOWN: 원본 설명 전체 표시, 동일 항목 그룹핑
- 전체 카테고리 버튼 제거 (표시 복잡도 감소)
- 카테고리별 동적 컬럼 헤더 및 레이아웃 적용
2025-09-09 09:24:45 +09:00

213 lines
6.9 KiB
Python

from fastapi import FastAPI, UploadFile, File, Form
from fastapi.middleware.cors import CORSMiddleware
from sqlalchemy import text
from .database import get_db
from sqlalchemy.orm import Session
from fastapi import Depends
from typing import Optional, List, Dict
import os
import shutil
# 설정 및 로깅 import
from .config import get_settings
from .utils.logger import get_logger
from .utils.error_handlers import setup_error_handlers
# 설정 로드
settings = get_settings()
# 로거 설정
logger = get_logger(__name__)
# FastAPI 앱 생성 (요청 크기 제한 증가)
app = FastAPI(
title=settings.app_name,
description="자재 분류 및 프로젝트 관리 시스템",
version=settings.app_version,
debug=settings.debug
)
# 요청 크기 제한 설정 (100MB로 증가)
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
from starlette.responses import Response
class RequestSizeLimitMiddleware(BaseHTTPMiddleware):
def __init__(self, app, max_request_size: int = 100 * 1024 * 1024): # 100MB
super().__init__(app)
self.max_request_size = max_request_size
async def dispatch(self, request: Request, call_next):
if "content-length" in request.headers:
content_length = int(request.headers["content-length"])
if content_length > self.max_request_size:
return Response("Request Entity Too Large", status_code=413)
return await call_next(request)
# 요청 크기 제한 미들웨어 추가
app.add_middleware(RequestSizeLimitMiddleware, max_request_size=100 * 1024 * 1024)
# 에러 핸들러 설정
setup_error_handlers(app)
# CORS 설정 (환경별 분리)
cors_config = settings.get_cors_config()
app.add_middleware(
CORSMiddleware,
**cors_config
)
logger.info(f"CORS origins configured for {settings.environment}: {settings.security.cors_origins}")
# 라우터들 import 및 등록 - files 라우터를 최우선으로 등록
try:
from .routers import files
app.include_router(files.router, prefix="/files", tags=["files"])
logger.info("FILES 라우터 등록 완료 - 최우선")
except ImportError:
logger.warning("files 라우터를 찾을 수 없습니다")
try:
from .routers import jobs
app.include_router(jobs.router, prefix="/jobs", tags=["jobs"])
except ImportError:
logger.warning("jobs 라우터를 찾을 수 없습니다")
try:
from .routers import purchase
app.include_router(purchase.router, tags=["purchase"])
except ImportError:
logger.warning("purchase 라우터를 찾을 수 없습니다")
try:
from .routers import material_comparison
app.include_router(material_comparison.router, tags=["material-comparison"])
except ImportError:
logger.warning("material_comparison 라우터를 찾을 수 없습니다")
try:
from .routers import dashboard
app.include_router(dashboard.router, tags=["dashboard"])
except ImportError:
logger.warning("dashboard 라우터를 찾을 수 없습니다")
try:
from .routers import tubing
app.include_router(tubing.router, prefix="/tubing", tags=["tubing"])
except ImportError:
logger.warning("tubing 라우터를 찾을 수 없습니다")
# 파일 관리 API 라우터 등록 (비활성화 - files 라우터와 충돌 방지)
# try:
# from .api import file_management
# app.include_router(file_management.router, tags=["file-management"])
# logger.info("파일 관리 API 라우터 등록 완료")
# except ImportError as e:
# logger.warning(f"파일 관리 라우터를 찾을 수 없습니다: {e}")
logger.info("파일 관리 API 라우터 비활성화됨 (files 라우터 사용)")
# 인증 API 라우터 등록
try:
from .auth import auth_router
app.include_router(auth_router, prefix="/auth", tags=["authentication"])
logger.info("인증 API 라우터 등록 완료")
except ImportError as e:
logger.warning(f"인증 라우터를 찾을 수 없습니다: {e}")
# 프로젝트 관리 API (비활성화 - jobs 테이블 사용)
# projects 테이블은 더 이상 사용하지 않음
# ):
# """프로젝트 수정"""
# try:
# update_query = text("""
# UPDATE projects
# SET project_name = :project_name, status = :status
# WHERE id = :project_id
# """)
#
# db.execute(update_query, {
# "project_id": project_id,
# "project_name": project_data["project_name"],
# "status": project_data["status"]
# })
#
# db.commit()
# return {"success": True}
# except Exception as e:
# db.rollback()
# return {"error": f"프로젝트 수정 실패: {str(e)}"}
# @app.delete("/projects/{project_id}")
# async def delete_project(
# project_id: int,
# db: Session = Depends(get_db)
# ):
# """프로젝트 삭제"""
# try:
# delete_query = text("DELETE FROM projects WHERE id = :project_id")
# db.execute(delete_query, {"project_id": project_id})
# db.commit()
# return {"success": True}
# except Exception as e:
# db.rollback()
# return {"error": f"프로젝트 삭제 실패: {str(e)}"}
@app.get("/")
async def root():
return {
"message": "TK-MP BOM Management API",
"version": "1.0.0",
"endpoints": ["/docs", "/jobs", "/files", "/projects"]
}
# Jobs API
# @app.get("/jobs")
# async def get_jobs(db: Session = Depends(get_db)):
# """Jobs 목록 조회"""
# try:
# # jobs 테이블에서 데이터 조회
# query = text("""
# SELECT
# job_no,
# job_name,
# client_name,
# end_user,
# epc_company,
# status,
# created_at
# FROM jobs
# WHERE is_active = true
# ORDER BY created_at DESC
# """)
#
# result = db.execute(query)
# jobs = result.fetchall()
#
# return [
# {
# "job_no": job.job_no,
# "job_name": job.job_name,
# "client_name": job.client_name,
# "end_user": job.end_user,
# "epc_company": job.epc_company,
# "status": job.status or "진행중",
# "created_at": job.created_at
# }
# for job in jobs
# ]
# except Exception as e:
# print(f"Jobs 조회 에러: {str(e)}")
# return {"error": f"Jobs 조회 실패: {str(e)}"}
# 파일 업로드는 /files/upload 엔드포인트를 사용하세요 (routers/files.py)
# parse_file과 classify_material_item 함수는 routers/files.py로 이동되었습니다
@app.get("/health")
async def health_check():
return {"status": "healthy", "timestamp": "2024-07-15"}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000, reload=True)