Files
page-builder/src/app/api/image/route.ts
T
jaybe 5f541e9524
CI / test (push) Successful in 3m36s
CI / pr_and_merge (push) Successful in 1m17s
회원가입, 로그인
2025-12-01 03:24:38 +09:00

92 lines
3.0 KiB
TypeScript

import { NextResponse } from "next/server";
import { promises as fs } from "fs";
import path from "path";
import { randomUUID } from "crypto";
import { PrismaClient } from "@prisma/client";
// 업로드된 이미지 파일을 저장할 디렉터리 (프로젝트 루트 기준)
const UPLOAD_DIR = path.join(process.cwd(), "uploads");
let prisma: PrismaClient | null = null;
if (process.env.DATABASE_URL && process.env.DATABASE_URL.trim() !== "") {
try {
prisma = new PrismaClient();
} catch (error) {
// DB 가 준비되지 않은 개발/테스트 환경에서도 업로드 자체는 동작할 수 있도록,
// Prisma 초기화 실패는 치명적 오류로 취급하지 않고 로그만 남긴다.
console.error("PrismaClient 초기화 실패 - 파일 시스템 전용 모드로 동작합니다.", error);
prisma = null;
}
}
export async function POST(request: Request) {
const formData = await request.formData();
const file = formData.get("file");
if (!file || typeof (file as any).arrayBuffer !== "function") {
return NextResponse.json({ message: "file 필드는 필수입니다." }, { status: 400 });
}
try {
await fs.mkdir(UPLOAD_DIR, { recursive: true });
} catch (error) {
console.error("업로드 디렉터리 생성 실패", error);
return NextResponse.json({ message: "업로드 디렉터리를 생성할 수 없습니다." }, { status: 500 });
}
try {
const arrayBuffer = await (file as any).arrayBuffer();
const bytes = new Uint8Array(arrayBuffer);
const id = randomUUID();
// 파일 경로는 uploads/<id> 형태로 저장한다.
const relativePath = path.join("uploads", id);
const filePath = path.join(process.cwd(), relativePath);
await fs.writeFile(filePath, bytes);
// 가능하다면 Asset 테이블에도 메타데이터를 남긴다.
if (prisma) {
try {
const project = await prisma.project.upsert({
where: { slug: "assets-global" },
update: {},
create: {
id: randomUUID(),
title: "Assets Global",
slug: "assets-global",
contentJson: [],
},
});
await prisma.asset.create({
data: {
id,
projectId: project.id,
kind: "image",
url: relativePath,
meta: {
sourceType: "uploaded",
originalName: (file as any).name ?? "upload",
mimeType: (file as any).type ?? "application/octet-stream",
},
},
});
} catch (error) {
console.error("이미지 Asset DB 저장 실패 - 파일 시스템만 사용합니다.", error);
}
}
return NextResponse.json(
{
id,
servedUrl: `/api/image/${id}`,
},
{ status: 201 },
);
} catch (error) {
console.error("이미지 업로드 처리 중 오류", error);
return NextResponse.json({ message: "이미지 업로드 중 오류가 발생했습니다." }, { status: 500 });
}
}