Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
Tags
- JavaScript
- react pattern
- react router dom
- 코어자바스크립트
- Next.js
- 프론트엔드
- 토이 프로젝트
- 리액트 라우터 돔
- React Query
- 코테
- TypeScript
- 리덕스
- 동적계획법
- 코딩테스트
- 스택
- 자바스크립트
- 토이프로젝트
- 그리디
- 프로그래머스
- reduxtoolkit
- styled component
- tailwind
- 리액트 패턴
- Form
- Supabase
- React
- revalidatepath
- 타입스크립트
- tanstack query
- 리액트
Archives
- Today
- Total
느려도 한걸음씩
Next.js 토이 프로젝트 (8) - 게시물 삭제 기능 구현 본문
이번 포스트에서는 게시물 삭제 기능을 구현해보겠습니다.
단순히 데이터를 삭제하는 것을 넘어, 본인 소유의 게시물만 삭제할 수 있도록 보안 정책을 적용하고, UI에서도 조건부로 삭제 버튼을 노출하는 흐름까지 함께 살펴볼게요.
✅ Step 1. Supabase RLS 설정
먼저 posts 테이블에서 본인 소유의 게시물만 삭제 가능하도록 Supabase에서 RLS(행 수준 보안, Row-Level Security)를 설정합니다.
CREATE POLICY "Users can delete their own posts"
ON posts
FOR DELETE
USING (auth.uid() = user_id);
- auth.uid()는 현재 로그인한 사용자의 고유 ID입니다.
- user_id는 게시물을 작성한 사용자의 ID입니다.
- 즉, 두 값이 일치할 경우에만 삭제가 허용됩니다.
⚠️ RLS가 비활성화 되어 있다면, 먼저 ENABLE ROW LEVEL SECURITY ON posts; 명령으로 활성화해주세요.
✅ Step 2. 서버 액션 함수 작성
이제 실제 게시물을 삭제하는 서버 함수 deletePost()를 작성합니다.
'use server';
import { createClient } from '@/utils/supabase/server';
import { revalidatePath } from 'next/cache';
import { redirect } from 'next/navigation';
export async function deletePost(formData: FormData) {
const supabase = await createClient();
const post_id = formData.get('post_id')?.toString();
// 1. 로그인된 유저 정보 확인
const {
data: { user },
error: userError,
} = await supabase.auth.getUser();
if (!user || userError) {
console.error("❌ 로그인된 유저가 없습니다:", userError?.message);
return;
}
// 2. 해당 게시물이 현재 유저의 것인지 확인
const { data: post, error: postError } = await supabase
.from("posts")
.select("user_id")
.eq("id", post_id)
.single();
if (postError) {
console.error("❌ 게시글 조회 실패:", postError.message);
return;
}
if (post.user_id !== user.id) {
console.error("❌ 이 게시글을 삭제할 권한이 없습니다.");
return;
}
// 3. 게시물 삭제 요청
const { error: deleteError } = await supabase
.from("posts")
.delete()
.eq("id", post_id);
if (deleteError) {
console.error("❌ 게시글 삭제 실패:", deleteError.message);
return;
}
console.log("✅ 게시글 삭제 성공!");
// 4. 메인 페이지로 리디렉션
revalidatePath("/");
redirect("/");
}
🔒 비록 Supabase에서 RLS로 보안을 걸었더라도, 프론트엔드에서 한번 더 확인해주는 습관은 보안적으로 매우 중요합니다.
✅ Step 3. 클라이언트에서 삭제 버튼 조건부 렌더링
게시물 상세 페이지에서는 현재 로그인한 유저와 게시글 작성자 ID가 일치할 때만 삭제 버튼이 보이도록 합니다.
const supabase = await createClient();
const {
data: { user },
} = await supabase.auth.getUser();
const isAuthor = user?.id === post.user_id;
그 후, 조건부 렌더링을 통해 삭제 버튼을 노출합니다
{isAuthor && (
<form action={deletePost} className='absolute top-4 right-4'>
<input type='hidden' name='post_id' value={params.postId} />
<button
type='submit'
className='text-sm bg-red-500 text-white px-3 py-1 rounded hover:bg-red-600'
>
삭제
</button>
</form>
)}
✅ 정리
- Supabase에서 RLS 정책으로 본인만 게시물 삭제 가능하도록 설정
- 서버 액션에서 유저 검증 → 게시글 검증 → 삭제 → 리디렉션
- UI에서는 작성자일 때만 삭제 버튼 표시
'토이프로젝트 > find side(가제)' 카테고리의 다른 글
Next.js 토이 프로젝트 (10) - 게시물 페이지 네이션 기능 (0) | 2025.05.09 |
---|---|
Next.js 토이 프로젝트 (9) - 게시물 필터링 기능 (0) | 2025.05.09 |
Next.js 토이 프로젝트 (7) - 내 게시물 페이지 구현하기 (0) | 2025.05.08 |
Next.js 토이 프로젝트 (6) - 내 관심글 목록 페이지 구현하기 (0) | 2025.05.08 |
Next.js 토이 프로젝트 (5) - 게시물 북마크 추가 기능(찜하기) 구현 (0) | 2025.05.08 |