import { NextResponse } from "next/server"; import { PrismaClient } from "@prisma/client"; import { verifyAccessToken, decryptJson } from "@/features/auth/authCrypto"; const prisma = new PrismaClient(); interface AuthUser { id: string; email: string; tokenVersion: number; } // 공통: pb_access 쿠키에서 JWT 토큰을 추출한다. function extractTokenFromCookieHeader(cookieHeader: string | null): string | null { if (!cookieHeader) return null; const parts = cookieHeader.split(";"); for (const part of parts) { const trimmed = part.trim(); if (trimmed.startsWith("pb_access=")) { const value = trimmed.substring("pb_access=".length); return decodeURIComponent(value); } } return null; } // 공통: Request 헤더의 쿠키에서 인증된 유저 정보를 복원한다. async function getAuthUserFromRequest(request: Request): Promise { const cookieHeader = request.headers.get("cookie"); const token = extractTokenFromCookieHeader(cookieHeader); if (!token) return null; const payload = await verifyAccessToken(token); if (!payload) return null; return { id: payload.sub, email: payload.email, tokenVersion: payload.tokenVersion, }; } // GET /api/projects/submissions // - 로그인한 사용자의 모든 프로젝트에 대한 폼 제출 내역을 최신순으로 최대 100건 반환한다. // - FormSubmission.userId 가 현재 사용자와 일치하는 레코드만 포함한다. // - payloadJson 과 sensitiveEnc 복호화 결과를 병합해 payload 로 반환한다. export async function GET(request: Request) { const authUser = await getAuthUserFromRequest(request); if (!authUser) { return NextResponse.json( { message: "폼 제출 내역을 조회하려면 로그인이 필요합니다." }, { status: 401 }, ); } const submissions = await prisma.formSubmission.findMany({ where: { userId: authUser.id }, orderBy: { createdAt: "desc" }, take: 100, include: { project: { select: { title: true, slug: true, }, }, }, }); const items = await Promise.all( submissions.map(async (s: any) => { const basePayload = (s.payloadJson ?? {}) as Record; let sensitive: Record = {}; if (s.sensitiveEnc) { try { sensitive = (await decryptJson>(s.sensitiveEnc)) ?? {}; } catch { sensitive = {}; } } const payload = { ...basePayload, ...sensitive }; return { id: s.id, createdAt: s.createdAt, projectSlug: s.projectSlug, projectTitle: s.project?.title ?? null, payload, }; }), ); return NextResponse.json(items, { status: 200 }); }