Files
conai/backend/app/api/inspections.py
sinmb79 2a4950d8a0 feat: CONAI Phase 1 MVP 초기 구현
소형 건설업체(100억 미만)를 위한 AI 기반 토목공사 통합관리 플랫폼

Backend (FastAPI):
- SQLAlchemy 모델 13개 (users, projects, wbs, tasks, daily_reports, reports, inspections, quality, weather, permits, rag, settings)
- API 라우터 11개 (auth, projects, tasks, daily_reports, reports, inspections, weather, rag, kakao, permits, settings)
- Services: Claude AI 래퍼, CPM Gantt 계산, 기상청 API, RAG(pgvector), 카카오 Skill API
- Alembic 마이그레이션 (pgvector 포함)
- pytest 테스트 (CPM, 날씨 경보)

Frontend (Next.js 15):
- 11개 페이지 (대시보드, 프로젝트, Gantt, 일보, 검측, 품질, 날씨, 인허가, RAG, 설정)
- TanStack Query + Zustand + Tailwind CSS

인프라:
- Docker Compose (PostgreSQL pgvector + backend + frontend)
- 한국어 README 및 설치 가이드

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 20:06:36 +09:00

107 lines
4.5 KiB
Python

import uuid
from fastapi import APIRouter, HTTPException, status
from sqlalchemy import select
from app.deps import CurrentUser, DB
from app.models.inspection import InspectionRequest
from app.models.project import Project, WBSItem
from app.schemas.inspection import InspectionCreate, InspectionUpdate, InspectionGenerateRequest, InspectionResponse
from app.services.inspection_gen import generate_checklist
router = APIRouter(prefix="/projects/{project_id}/inspections", tags=["검측요청서"])
async def _get_project_or_404(project_id: uuid.UUID, db: DB) -> Project:
result = await db.execute(select(Project).where(Project.id == project_id))
p = result.scalar_one_or_none()
if not p:
raise HTTPException(status_code=404, detail="프로젝트를 찾을 수 없습니다")
return p
@router.get("", response_model=list[InspectionResponse])
async def list_inspections(project_id: uuid.UUID, db: DB, current_user: CurrentUser):
result = await db.execute(
select(InspectionRequest)
.where(InspectionRequest.project_id == project_id)
.order_by(InspectionRequest.requested_date.desc())
)
return result.scalars().all()
@router.post("", response_model=InspectionResponse, status_code=status.HTTP_201_CREATED)
async def create_inspection(project_id: uuid.UUID, data: InspectionCreate, db: DB, current_user: CurrentUser):
await _get_project_or_404(project_id, db)
inspection = InspectionRequest(**data.model_dump(), project_id=project_id)
db.add(inspection)
await db.commit()
await db.refresh(inspection)
return inspection
@router.post("/generate", response_model=InspectionResponse, status_code=status.HTTP_201_CREATED)
async def generate_inspection(project_id: uuid.UUID, data: InspectionGenerateRequest, db: DB, current_user: CurrentUser):
"""AI-generate inspection request checklist."""
project = await _get_project_or_404(project_id, db)
# Get WBS item name if provided
wbs_name = None
if data.wbs_item_id:
wbs_result = await db.execute(select(WBSItem).where(WBSItem.id == data.wbs_item_id))
wbs = wbs_result.scalar_one_or_none()
if wbs:
wbs_name = wbs.name
checklist = await generate_checklist(
project_name=project.name,
inspection_type=data.inspection_type,
location_detail=data.location_detail,
requested_date=str(data.requested_date),
wbs_name=wbs_name,
)
inspection = InspectionRequest(
project_id=project_id,
wbs_item_id=data.wbs_item_id,
inspection_type=data.inspection_type,
requested_date=data.requested_date,
location_detail=data.location_detail,
checklist_items=checklist,
ai_generated=True,
)
db.add(inspection)
await db.commit()
await db.refresh(inspection)
return inspection
@router.get("/{inspection_id}", response_model=InspectionResponse)
async def get_inspection(project_id: uuid.UUID, inspection_id: uuid.UUID, db: DB, current_user: CurrentUser):
result = await db.execute(select(InspectionRequest).where(InspectionRequest.id == inspection_id, InspectionRequest.project_id == project_id))
insp = result.scalar_one_or_none()
if not insp:
raise HTTPException(status_code=404, detail="검측요청서를 찾을 수 없습니다")
return insp
@router.put("/{inspection_id}", response_model=InspectionResponse)
async def update_inspection(project_id: uuid.UUID, inspection_id: uuid.UUID, data: InspectionUpdate, db: DB, current_user: CurrentUser):
result = await db.execute(select(InspectionRequest).where(InspectionRequest.id == inspection_id, InspectionRequest.project_id == project_id))
insp = result.scalar_one_or_none()
if not insp:
raise HTTPException(status_code=404, detail="검측요청서를 찾을 수 없습니다")
for field, value in data.model_dump(exclude_none=True).items():
setattr(insp, field, value)
await db.commit()
await db.refresh(insp)
return insp
@router.delete("/{inspection_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_inspection(project_id: uuid.UUID, inspection_id: uuid.UUID, db: DB, current_user: CurrentUser):
result = await db.execute(select(InspectionRequest).where(InspectionRequest.id == inspection_id, InspectionRequest.project_id == project_id))
insp = result.scalar_one_or_none()
if not insp:
raise HTTPException(status_code=404, detail="검측요청서를 찾을 수 없습니다")
await db.delete(insp)
await db.commit()