diff --git a/src/app/api/auth/session/route.ts b/src/app/api/auth/session/route.ts index 534fbee..ac07ed9 100644 --- a/src/app/api/auth/session/route.ts +++ b/src/app/api/auth/session/route.ts @@ -61,15 +61,27 @@ export async function POST(req: Request) { }); isAdmin = !!hasAdmin; } + // 추가 안전장치: 사용자 레코드의 authLevel이 ADMIN이면 관리자 취급 + if (!isAdmin && user.authLevel === "ADMIN") { + isAdmin = true; + } const res = NextResponse.json({ ok: true, user: { userId: user.userId, nickname: user.nickname } }); + // HTTPS 요청에서만 Secure 속성 부여 (HTTP 환경에서는 생략하여 로컬 start에서도 동작) + let secureAttr = ""; + try { + const isHttps = new URL(req.url).protocol === "https:"; + secureAttr = isHttps ? "; Secure" : ""; + } catch { + secureAttr = ""; + } res.headers.append( "Set-Cookie", - `uid=${encodeURIComponent(user.userId)}; Path=/; HttpOnly; SameSite=Lax` + `uid=${encodeURIComponent(user.userId)}; Path=/; HttpOnly; SameSite=Lax${secureAttr}` ); res.headers.append( "Set-Cookie", - `isAdmin=${isAdmin ? "1" : "0"}; Path=/; HttpOnly; SameSite=Lax` + `isAdmin=${isAdmin ? "1" : "0"}; Path=/; HttpOnly; SameSite=Lax${secureAttr}` ); return res; } diff --git a/src/app/api/boards/route.ts b/src/app/api/boards/route.ts index 64bfb48..783292b 100644 --- a/src/app/api/boards/route.ts +++ b/src/app/api/boards/route.ts @@ -4,7 +4,7 @@ import prisma from "@/lib/prisma"; export async function GET(req: Request) { const { searchParams } = new URL(req.url); const category = searchParams.get("category"); // slug or id - const where: any = {}; + const where: any = { status: "active" }; if (category) { if (category.length === 25 || category.length === 24) { where.categoryId = category; diff --git a/src/app/boards/[id]/page.tsx b/src/app/boards/[id]/page.tsx index d044ed7..5c1933d 100644 --- a/src/app/boards/[id]/page.tsx +++ b/src/app/boards/[id]/page.tsx @@ -4,6 +4,7 @@ import Link from "next/link"; import { BoardToolbar } from "@/app/components/BoardToolbar"; import { headers } from "next/headers"; import prisma from "@/lib/prisma"; +import { notFound } from "next/navigation"; import { UserAvatar } from "@/app/components/UserAvatar"; import { RankIcon1st } from "@/app/components/RankIcon1st"; import { RankIcon2nd } from "@/app/components/RankIcon2nd"; @@ -33,7 +34,10 @@ export default async function BoardDetail({ params, searchParams }: { params: an const res = await fetch(new URL("/api/boards", base).toString(), { cache: "no-store" }); const { boards } = await res.json(); const board = (boards || []).find((b: any) => b.slug === idOrSlug || b.id === idOrSlug); - const id = board?.id as string; + if (!board) { + return notFound(); + } + const id = board.id as string; const siblingBoards = (boards || []).filter((b: any) => b.category?.id && b.category.id === board?.category?.id); const categoryName = board?.category?.name ?? ""; // 메인배너 표시 설정 diff --git a/src/app/components/BoardPanelClient.tsx b/src/app/components/BoardPanelClient.tsx index 022e18c..9a30340 100644 --- a/src/app/components/BoardPanelClient.tsx +++ b/src/app/components/BoardPanelClient.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import Link from "next/link"; import { RankIcon1st } from "./RankIcon1st"; import { RankIcon2nd } from "./RankIcon2nd"; @@ -52,6 +52,23 @@ export function BoardPanelClient({ }) { const [selectedBoardId, setSelectedBoardId] = useState(initialBoardId); + // 데이터가 비어있을 때 안전 처리 + if (!boardsData || boardsData.length === 0) { + return ( +