From e56c8c47ff42446eaf2f7b786fce85ce40343ad6 Mon Sep 17 00:00:00 2001 From: mota Date: Mon, 13 Oct 2025 07:01:33 +0900 Subject: [PATCH] =?UTF-8?q?feat(api):=20=EC=B9=B4=ED=85=8C=EA=B3=A0?= =?UTF-8?q?=EB=A6=AC=20=EA=B4=80=EB=A6=AC=EC=9E=90=20API=EC=97=90=20RBAC?= =?UTF-8?q?=20=EA=B6=8C=ED=95=9C=20=EC=B2=B4=ED=81=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit docs(todo): 체크리스트 2.4 완료 표시 --- .cursor/.prompt/게시판 대분류작업.md | 2 +- src/app/api/admin/categories/[id]/route.ts | 8 +++++++- src/app/api/admin/categories/route.ts | 4 ++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.cursor/.prompt/게시판 대분류작업.md b/.cursor/.prompt/게시판 대분류작업.md index 4ccb8df..4e04886 100644 --- a/.cursor/.prompt/게시판 대분류작업.md +++ b/.cursor/.prompt/게시판 대분류작업.md @@ -15,7 +15,7 @@ API - [x] 2.1 Admin: 카테고리 CRUD 엔드포인트 추가(`src/app/api/admin/categories/route.ts`) - [x] 2.2 Admin: 게시판 생성/수정 요청에 `categoryId` 허용(`src/app/api/admin/boards/...`) - [x] 2.3 Public: 게시판 목록 조회에 `category` 포함 및 `?category` 필터 지원(`src/app/api/boards/route.ts`) -- [ ] 2.4 RBAC 검토: `ADMIN` 또는 `BOARD` 권한으로 카테고리 관리 허용 +- [x] 2.4 RBAC 검토: `ADMIN` 또는 `BOARD` 권한으로 카테고리 관리 허용 프론트엔드 - [ ] 3.1 Admin 보드 관리 화면에 카테고리 선택(Select) 추가(`src/app/admin/boards/page.tsx`) diff --git a/src/app/api/admin/categories/[id]/route.ts b/src/app/api/admin/categories/[id]/route.ts index ae35f4b..515ae88 100644 --- a/src/app/api/admin/categories/[id]/route.ts +++ b/src/app/api/admin/categories/[id]/route.ts @@ -1,8 +1,12 @@ import { NextResponse } from "next/server"; import prisma from "@/lib/prisma"; +import { getUserIdFromRequest } from "@/lib/auth"; +import { requirePermission } from "@/lib/rbac"; export async function PATCH(req: Request, context: { params: Promise<{ id: string }> }) { const { id } = await context.params; + const userId = getUserIdFromRequest(req); + await requirePermission({ userId, resource: "ADMIN", action: "MODERATE" }); const body = await req.json().catch(() => ({})); const data: any = {}; for (const k of ["name", "slug", "sortOrder", "status"]) { @@ -12,8 +16,10 @@ export async function PATCH(req: Request, context: { params: Promise<{ id: strin return NextResponse.json({ category }); } -export async function DELETE(_: Request, context: { params: Promise<{ id: string }> }) { +export async function DELETE(req: Request, context: { params: Promise<{ id: string }> }) { const { id } = await context.params; + const userId = getUserIdFromRequest(req); + await requirePermission({ userId, resource: "ADMIN", action: "MODERATE" }); await prisma.boardCategory.delete({ where: { id } }); return NextResponse.json({ ok: true }); } diff --git a/src/app/api/admin/categories/route.ts b/src/app/api/admin/categories/route.ts index f002837..16cbff4 100644 --- a/src/app/api/admin/categories/route.ts +++ b/src/app/api/admin/categories/route.ts @@ -1,6 +1,8 @@ import { NextResponse } from "next/server"; import prisma from "@/lib/prisma"; import { z } from "zod"; +import { getUserIdFromRequest } from "@/lib/auth"; +import { requirePermission } from "@/lib/rbac"; export async function GET() { const categories = await prisma.boardCategory.findMany({ @@ -17,6 +19,8 @@ const createSchema = z.object({ }); export async function POST(req: Request) { + const userId = getUserIdFromRequest(req); + await requirePermission({ userId, resource: "ADMIN", action: "MODERATE" }); const body = await req.json().catch(() => ({})); const parsed = createSchema.safeParse(body); if (!parsed.success) return NextResponse.json({ error: parsed.error.flatten() }, { status: 400 });