Files
TK-BOM-Project/backend/app/main.py
Hyungi Ahn 13c375477a Phase 3 완료: 파일 처리 시스템 구축
 주요 완성 기능:
- 프로젝트 생성 API (project_name 필드 포함)
- 엑셀 파일 업로드 및 파싱 시스템
- 자재 DB 저장 (2837개 자재 성공 저장)
- 자재 조회 및 요약 통계 API
- 외래키 관계 정상 동작 (projects -> files -> materials)

📊 테스트 결과:
- MP7 PIPING PROJECT Rev.2 프로젝트 생성
- 00.MP7 PIPING R.2_BOM.XLS 파일 업로드 성공
- NIPPLE, PIPE 등 자재 분류 및 재질 추출
- ASTM A106, SCH 80, 1인치 사이즈 등 정확 파싱

🛠️ 기술 스택:
- FastAPI + PostgreSQL + SQLAlchemy
- pandas를 활용한 엑셀 파싱
- 외래키 제약조건 적용된 정규화 DB 설계
2025-07-14 13:19:24 +09:00

129 lines
4.5 KiB
Python

from fastapi import FastAPI, Depends, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from sqlalchemy.orm import Session
from sqlalchemy import text
from typing import List
from datetime import datetime
from .database import get_db, engine
from .models import Base, Project
from .schemas import ProjectCreate, ProjectResponse
from .api import files
Base.metadata.create_all(bind=engine)
app = FastAPI(
title="TK-MP-Project API",
description="BOM 시스템 개발 프로젝트 - Phase 3: 파일 처리 시스템",
version="1.0.0",
docs_url="/docs",
redoc_url="/redoc"
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.include_router(files.router, prefix="/api/files", tags=["파일 관리"])
@app.get("/")
async def root():
return {
"message": "TK-MP-Project API Server",
"version": "1.0.0 - Phase 3",
"status": "running",
"timestamp": datetime.now().isoformat(),
"new_features": [
"✅ Phase 1: 기반 시스템 구축",
"✅ Phase 2: 데이터베이스 연동",
"🔄 Phase 3: 파일 처리 시스템 개발 중"
]
}
@app.get("/health")
async def health_check(db: Session = Depends(get_db)):
try:
result = db.execute(text("SELECT 1 as test"))
test_value = result.fetchone()[0]
return {
"status": "healthy",
"database": "connected",
"test_query": test_value == 1,
"timestamp": datetime.now().isoformat(),
"phase": "Phase 3 - 파일 처리 시스템"
}
except Exception as e:
raise HTTPException(status_code=500, detail=f"데이터베이스 연결 실패: {str(e)}")
@app.get("/api/projects", response_model=List[ProjectResponse])
async def get_projects(db: Session = Depends(get_db)):
try:
result = db.execute(text("""
SELECT id, official_project_code, project_name, design_project_code,
is_code_matched, status, created_at, updated_at
FROM projects
ORDER BY created_at DESC
"""))
projects = result.fetchall()
return [
ProjectResponse(
id=project.id,
official_project_code=project.official_project_code,
project_name=project.project_name,
design_project_code=project.design_project_code,
is_code_matched=project.is_code_matched,
status=project.status,
created_at=project.created_at,
updated_at=project.updated_at
)
for project in projects
]
except Exception as e:
raise HTTPException(status_code=500, detail=f"프로젝트 조회 실패: {str(e)}")
@app.post("/api/projects", response_model=ProjectResponse)
async def create_project(project: ProjectCreate, db: Session = Depends(get_db)):
try:
insert_query = text("""
INSERT INTO projects (official_project_code, project_name, design_project_code, is_code_matched, status, created_at)
VALUES (:official_code, :project_name, :design_code, :is_matched, :status, :created_at)
RETURNING id, official_project_code, project_name, design_project_code, is_code_matched, status, created_at, updated_at
""")
result = db.execute(insert_query, {
"official_code": project.official_project_code,
"project_name": project.project_name,
"design_code": project.design_project_code,
"is_matched": project.is_code_matched,
"status": project.status,
"created_at": datetime.now()
})
new_project = result.fetchone()
db.commit()
return ProjectResponse(
id=new_project.id,
official_project_code=new_project.official_project_code,
project_name=new_project.project_name,
design_project_code=new_project.design_project_code,
is_code_matched=new_project.is_code_matched,
status=new_project.status,
created_at=new_project.created_at,
updated_at=new_project.updated_at
)
except Exception as e:
db.rollback()
raise HTTPException(status_code=500, detail=f"프로젝트 생성 실패: {str(e)}")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000, reload=True)