import { NextResponse } from "next/server"; import prisma from "@/lib/prisma"; export async function GET(req: Request) { const { searchParams } = new URL(req.url); const boardId = searchParams.get("boardId"); const period = searchParams.get("period") || "daily"; // daily | weekly // 날짜 범위 계산 const now = new Date(); const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0); const endOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 999); const startOfWeek = new Date(now); startOfWeek.setDate(now.getDate() - 7); startOfWeek.setHours(0, 0, 0, 0); const dateFilter = period === "daily" ? { date: { gte: startOfToday, lte: endOfToday, } } : { date: { gte: startOfWeek } }; // 일일 조회수 테이블에서 조회수 합계 계산 const dailyViews = await prisma.dailyPostView.groupBy({ by: ["postId"], where: dateFilter, _sum: { viewCount: true, }, orderBy: { _sum: { viewCount: "desc", }, }, take: 20, // 조회수 상위 20개만 가져와서 게시글 정보 조회 }); if (dailyViews.length === 0) { return NextResponse.json({ items: [], period }); } const postIds = dailyViews.map((dv) => dv.postId); // 게시글 정보 조회 const posts = await prisma.post.findMany({ where: { id: { in: postIds }, status: "published", ...(boardId ? { boardId } : {}), }, select: { id: true, title: true, createdAt: true, boardId: true, board: { select: { id: true, name: true, slug: true } }, isPinned: true, status: true, author: { select: { userId: true, nickname: true } }, stat: { select: { recommendCount: true, views: true, commentsCount: true } }, postTags: { select: { tag: { select: { name: true, slug: true } } } }, }, }); // 조회수와 게시글 매핑 const viewCountMap = new Map( dailyViews.map((dv) => [dv.postId, dv._sum.viewCount ?? 0]) ); // 조회수 순으로 정렬 (조회수가 0보다 큰 것만) const postsWithViews = posts .map((post) => ({ ...post, viewCount: viewCountMap.get(post.id) ?? 0, })) .filter((post) => post.viewCount > 0) // 조회수가 0보다 큰 것만 .sort((a, b) => { // 고정글 우선 if (a.isPinned && !b.isPinned) return -1; if (!a.isPinned && b.isPinned) return 1; // 조회수 순 if (b.viewCount !== a.viewCount) return b.viewCount - a.viewCount; // 최신순 return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(); }) .slice(0, 5); // 상위 5개만 return NextResponse.json({ items: postsWithViews, period }); }