summaryrefslogtreecommitdiff
path: root/app/api/revision-upload/route.ts
diff options
context:
space:
mode:
Diffstat (limited to 'app/api/revision-upload/route.ts')
-rw-r--r--app/api/revision-upload/route.ts213
1 files changed, 213 insertions, 0 deletions
diff --git a/app/api/revision-upload/route.ts b/app/api/revision-upload/route.ts
new file mode 100644
index 00000000..2138d674
--- /dev/null
+++ b/app/api/revision-upload/route.ts
@@ -0,0 +1,213 @@
+// app/api/revision-upload/route.ts
+import { NextRequest, NextResponse } from 'next/server'
+import { writeFile } from 'fs/promises'
+import { join } from 'path'
+import { v4 as uuidv4 } from 'uuid'
+import path from 'path'
+import db from '@/db/db'
+import { documents, issueStages, revisions, documentAttachments } from '@/db/schema/vendorDocu'
+import { and, eq } from 'drizzle-orm'
+
+export async function POST(request: NextRequest) {
+ try {
+ const formData = await request.formData()
+
+ // FormData에서 데이터 추출
+ const stage = formData.get("stage") as string | null
+ const revision = formData.get("revision") as string | null
+ const docIdStr = formData.get("documentId") as string
+ const docId = parseInt(docIdStr, 10)
+ const uploaderName = formData.get("uploaderName") as string | null
+ const comment = formData.get("comment") as string | null
+ const mode = formData.get("mode") as string || "new" // 'new' | 'append'
+
+ // 파일들 추출
+ const attachmentFiles = formData.getAll("attachments") as File[]
+
+ // 유효성 검증
+ if (!docId || Number.isNaN(docId)) {
+ return NextResponse.json(
+ { error: "Invalid or missing documentId" },
+ { status: 400 }
+ )
+ }
+
+ if (!stage || !revision) {
+ return NextResponse.json(
+ { error: "Missing stage or revision" },
+ { status: 400 }
+ )
+ }
+
+ if (attachmentFiles.length === 0) {
+ return NextResponse.json(
+ { error: "No files provided" },
+ { status: 400 }
+ )
+ }
+
+ // 파일 크기 검증 (각 파일 최대 3GB)
+ const maxFileSize = 3 * 1024 * 1024 * 1024 // 3GB
+ for (const file of attachmentFiles) {
+ if (file.size > maxFileSize) {
+ return NextResponse.json(
+ { error: `파일 ${file.name}이 너무 큽니다. 최대 3GB까지 허용됩니다.` },
+ { status: 400 }
+ )
+ }
+ }
+
+ // 트랜잭션 실행
+ const result = await db.transaction(async (tx) => {
+ // (1) issueStageId 찾기 또는 생성
+ let issueStageId: number
+ const stageRecord = await tx
+ .select()
+ .from(issueStages)
+ .where(and(eq(issueStages.stageName, stage), eq(issueStages.documentId, docId)))
+ .limit(1)
+
+ if (!stageRecord.length) {
+ // Stage가 없으면 새로 생성
+ const [newStage] = await tx
+ .insert(issueStages)
+ .values({
+ documentId: docId,
+ stageName: stage,
+ updatedAt: new Date(),
+ })
+ .returning()
+
+ issueStageId = newStage.id
+ } else {
+ issueStageId = stageRecord[0].id
+ }
+
+ // (2) Revision 찾기 또는 생성
+ let revisionId: number
+ const revisionRecord = await tx
+ .select()
+ .from(revisions)
+ .where(and(eq(revisions.issueStageId, issueStageId), eq(revisions.revision, revision)))
+ .limit(1)
+
+ const currentDate = new Date().toISOString().split('T')[0] // YYYY-MM-DD 형식
+
+ if (!revisionRecord.length || mode === 'new') {
+ // 새 리비전 생성
+ const [newRevision] = await tx
+ .insert(revisions)
+ .values({
+ issueStageId,
+ revision,
+ uploaderType: "vendor", // 항상 vendor로 고정
+ uploaderName: uploaderName || undefined,
+ revisionStatus: "SUBMITTED", // 기본 상태
+ submittedDate: currentDate, // 제출일 설정
+ comment: comment || undefined,
+ updatedAt: new Date(),
+ })
+ .returning()
+
+ revisionId = newRevision.id
+ console.log("✅ 새 리비전 생성:", { revisionId, revision })
+ } else {
+ // 기존 리비전에 파일 추가 (append 모드)
+ revisionId = revisionRecord[0].id
+
+ // 기존 리비전 정보 업데이트 (코멘트나 업로더명 변경 가능)
+ await tx
+ .update(revisions)
+ .set({
+ uploaderName: uploaderName || revisionRecord[0].uploaderName,
+ comment: comment || revisionRecord[0].comment,
+ updatedAt: new Date(),
+ })
+ .where(eq(revisions.id, revisionId))
+
+ console.log("✅ 기존 리비전에 파일 추가:", { revisionId, revision })
+ }
+
+ // (3) 파일들 저장 및 DB 기록
+ const uploadedFiles = []
+ const baseDir = join(process.cwd(), "public", "documents")
+
+ for (const file of attachmentFiles) {
+ if (file.size > 0) {
+ const originalName = file.name
+ const ext = path.extname(originalName)
+ const uniqueName = uuidv4() + ext
+ const savePath = join(baseDir, uniqueName)
+
+ // 파일 저장
+ const arrayBuffer = await file.arrayBuffer()
+ const buffer = Buffer.from(arrayBuffer)
+ await writeFile(savePath, buffer)
+
+ // DB에 첨부파일 정보 저장
+ const [attachmentRecord] = await tx
+ .insert(documentAttachments)
+ .values({
+ revisionId,
+ fileName: originalName,
+ filePath: "/documents/" + uniqueName,
+ fileSize: file.size,
+ fileType: ext.replace('.', '').toLowerCase() || undefined,
+ updatedAt: new Date(),
+ })
+ .returning()
+
+ uploadedFiles.push({
+ id: attachmentRecord.id,
+ fileName: originalName,
+ fileSize: file.size,
+ filePath: attachmentRecord.filePath,
+ })
+
+ console.log("✅ 파일 저장 완료:", originalName)
+ }
+ }
+
+ // (4) Documents 테이블의 updatedAt 갱신
+ await tx
+ .update(documents)
+ .set({ updatedAt: new Date() })
+ .where(eq(documents.id, docId))
+
+ return {
+ revisionId,
+ stage,
+ revision,
+ uploaderName,
+ comment,
+ uploadedFiles,
+ mode,
+ }
+ })
+
+ console.log("✅ 리비전 업로드 완료:", {
+ documentId: docId,
+ stage,
+ revision,
+ filesCount: result.uploadedFiles.length,
+ mode
+ })
+
+ return NextResponse.json({
+ success: true,
+ message: `${result.uploadedFiles.length}개 파일이 성공적으로 업로드되었습니다.`,
+ data: result,
+ })
+
+ } catch (error) {
+ console.error('❌ 리비전 업로드 오류:', error)
+
+ return NextResponse.json(
+ {
+ error: 'Failed to upload revision',
+ details: error instanceof Error ? error.message : String(error),
+ },
+ { status: 500 }
+ )
+ }
+} \ No newline at end of file