feat: Job 관리 시스템 및 BOM 연동 완성

 완성된 기능:
- Job 관리 CRUD API 구현 (생성/조회/수정/삭제)
- PostgreSQL jobs 테이블 생성 및 더미 데이터
- files.py project_id → job_no 변경으로 완전 통합
- Job 검증 로직으로 업로드 시 유효성 확인
- Job-Files-Materials 3단계 데이터 연동 완료

📁 추가된 파일:
- scripts/create_jobs.sql: jobs 테이블 스키마
- scripts/insert_dummy_jobs.py: 더미 데이터 생성
- app/routers/jobs.py: Job 관리 API
- app/routers/files.py: BOM 업로드 (job_no 연동)

🚀 다음 단계:
- 자재 분류 시스템 통합 (classification.py)
- 검토 시스템 구현 (행별 분류 확인/수정)
- Job별 자재 통계 및 진행률 API
- 프론트엔드 UI 개발

🎯 테스트 완료:
- J24-001 Job에 BOM 파일 업로드 성공
- Job 검증 및 오류 처리 작동 확인
- PostgreSQL 데이터 저장 및 조회 정상
This commit is contained in:
Hyungi Ahn
2025-07-15 13:26:03 +09:00
parent ffe4f0f969
commit c9e0d90de4
6 changed files with 930 additions and 104 deletions

View File

@@ -1,25 +1,14 @@
from fastapi import FastAPI, Depends, HTTPException
from fastapi import FastAPI
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)
# FastAPI 앱 생성
app = FastAPI(
title="TK-MP-Project API",
description="BOM 시스템 개발 프로젝트 - Phase 3: 파일 처리 시스템",
version="1.0.0",
docs_url="/docs",
redoc_url="/redoc"
title="TK-MP BOM Management API",
description="자재 분류 및 프로젝트 관리 시스템",
version="1.0.0"
)
# CORS 설정
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
@@ -28,100 +17,30 @@ app.add_middleware(
allow_headers=["*"],
)
app.include_router(files.router, prefix="/api/files", tags=["파일 관리"])
# 라우터들 import 및 등록
try:
from .routers import files
app.include_router(files.router, prefix="/files", tags=["files"])
except ImportError:
print("files 라우터를 찾을 수 없습니다")
try:
from .routers import jobs
app.include_router(jobs.router, prefix="/jobs", tags=["jobs"])
except ImportError:
print("jobs 라우터를 찾을 수 없습니다")
@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: 파일 처리 시스템 개발 중"
]
"message": "TK-MP BOM Management API",
"version": "1.0.0",
"endpoints": ["/docs", "/jobs", "/files"]
}
@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)}")
async def health_check():
return {"status": "healthy", "timestamp": "2024-07-15"}
if __name__ == "__main__":
import uvicorn