Skip to content

feat(mypage): 회원탈퇴 전 약관 안내 페이지 추가 - #87

Merged
evenif99 merged 3 commits into
devfrom
feature/withdraw-terms-page
Jun 20, 2026
Merged

feat(mypage): 회원탈퇴 전 약관 안내 페이지 추가#87
evenif99 merged 3 commits into
devfrom
feature/withdraw-terms-page

Conversation

@evenif99

@evenif99 evenif99 commented Jun 20, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • 마이페이지에서 '회원탈퇴' 클릭 시 기존 즉시 모달 방식 → 약관 안내 페이지 이동 방식으로 변경
  • 말해부엉 서비스 기준 탈퇴 안내 조항 5개(약 5000자) 페이지 신규 구현
  • 약관 확인 후 하단 '탈퇴하기' 버튼 → ConfirmModal → 실제 탈퇴 처리 흐름 구성
  • DELETE /api/user/me 엔드포인트 추가 (소프트 딜리트 + AuditLog 기록)
  • 탈퇴 계정의 카카오 재로그인 차단 (signIn 콜백)

Changes

  • src/app/(page)/mypage/page.tsxwithdrawOpen state·handleWithdraw 함수·탈퇴 ConfirmModal 제거, 버튼 클릭 시 /mypage/withdraw로 직접 이동
  • src/app/(page)/mypage/withdraw/page.tsx — 말해부엉 서비스 탈퇴 약관 5개 조 렌더링, 하단 '탈퇴하기' 버튼으로 최종 ConfirmModal 오픈, 확인 시 DELETE /api/user/me 호출 후 signOut
  • src/app/(page)/mypage/withdraw/page.module.scss — 프로젝트 내 mixin(text-title-s, text-body-s, respond-to), fn.r(), CSS 변수 활용한 스타일 추가, 하단 버튼 fixed 고정
  • src/app/api/user/me/route.tsDELETE 핸들러 추가: deletedAt / deletionRequestedAt 소프트 딜리트, AuditLog(USER_DELETED) 기록, 이미 탈퇴된 계정 재요청 시 409 반환
  • src/lib/auth/index.tssignIn 콜백에서 deletedAt 설정된 계정의 카카오 로그인 차단 (return false)

Implementation Notes

  • 소프트 딜리트 채택: DisputeRoom.creatorUserId FK에 cascade 없어 hard delete 불가. 스키마의 deletedAt / deletionRequestedAt 필드를 활용
  • 탈퇴 후 재로그인 시 NextAuth signIn 콜백에서 false 반환 → 로그인 페이지로 리다이렉트
  • 멱등성: 이미 탈퇴된 계정에 재요청 시 409 반환

Test plan

  • 마이페이지에서 '회원탈퇴' 클릭 시 모달 없이 /mypage/withdraw 페이지로 이동 확인
  • 회원탈퇴 페이지에서 5개 조항 정상 렌더링 확인
  • 하단 '탈퇴하기' 버튼 클릭 시 ConfirmModal 오픈 확인
  • ConfirmModal '취소' 클릭 시 모달 닫힘 확인
  • ConfirmModal '확인' 클릭 시 API 호출 후 로그인 페이지로 이동 확인
  • DB에서 deleted_at / deletion_requested_at 설정 확인
  • AuditLog에 USER_DELETED 이벤트 기록 확인
  • 탈퇴 후 동일 카카오 계정으로 재로그인 시도 시 차단 확인
  • Header 뒤로가기로 마이페이지 복귀 확인

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features
    • 회원탈퇴 전용 페이지 추가, 제1~5조 약관 표시 및 “탈퇴하기” 확인 흐름 제공
  • Changes
    • 마이페이지 로그아웃 동작을 로그인 화면으로 고정하고, 회원탈퇴는 확인 모달 없이 탈퇴 페이지로 이동하도록 변경
    • 탈퇴 완료 시 자동 로그아웃 후 로그인 화면으로 전환(요청 중 버튼 비활성화)
  • Bug Fixes
    • 소프트 삭제된 계정으로 카카오 로그인 시 접근이 차단됨

마이페이지에서 회원탈퇴 클릭 시 바로 모달이 뜨던 방식을 개선하여,
말해부엉 서비스 기준 탈퇴 안내 조항(5개 조, 약 5000자)을 담은
전용 페이지로 먼저 이동하고, 하단 '탈퇴하기' 버튼으로 최종 확인하는 흐름으로 변경.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
talky-owl Ready Ready Preview, Comment Jun 20, 2026 6:09am

@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: d4ad735b-fc3a-48d7-9aeb-bb10525421e7

📥 Commits

Reviewing files that changed from the base of the PR and between 3716c81 and b3061c5.

📒 Files selected for processing (2)
  • src/app/(page)/mypage/withdraw/page.module.scss
  • src/app/(page)/mypage/withdraw/page.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/app/(page)/mypage/withdraw/page.module.scss
  • src/app/(page)/mypage/withdraw/page.tsx

📝 Walkthrough

Walkthrough

MyPage에서 회원탈퇴 확인 모달과 관련 상태를 제거하고, 탈퇴 버튼 클릭 시 /mypage/withdraw로 직접 이동하도록 변경했다. 신규 탈퇴 페이지에 약관 데이터 상수, DELETE /api/user/me API 호출 핸들러, 확인 모달 UI, 그리고 전용 SCSS 스타일을 추가했다. 동시에 카카오 로그인 인증 로직에서 소프트 삭제 사용자를 차단하는 검사를 추가했다.

Changes

회원탈퇴 전용 페이지 및 소프트 삭제 관리

Layer / File(s) Summary
MyPage 탈퇴 모달 제거 및 라우팅 변경
src/app/(page)/mypage/page.tsx
withdrawOpen 상태와 탈퇴용 ConfirmModal을 제거하고, 탈퇴 버튼 클릭 시 router.push('/mypage/withdraw')로 이동하도록 변경한다. 로그아웃용 ConfirmModal은 유지되며 로그아웃 처리는 signOut({ callbackUrl: '/login' })으로 고정된다.
탈퇴 페이지 약관·핸들러·UI·스타일 구현
src/app/(page)/mypage/withdraw/page.tsx, src/app/(page)/mypage/withdraw/page.module.scss
WITHDRAW_TERMS 배열 상수로 제1조~제5조 약관을 구조화하고, confirmOpen·loading 상태와 함께 DELETE /api/user/me 호출 기반 handleWithdraw 핸들러를 구현한다(실패 시 에러 메시지 알림·성공 시 signOut 리다이렉트·예외 처리 포함). 약관 섹션을 동적으로 렌더링하고 하단 고정 푸터에 탈퇴 버튼과 ConfirmModal을 배치한다. 응답형 레이아웃 SCSS로 main·terms·section·footer 스타일을 정의한다.
DELETE API 엔드포인트 구현
src/app/api/user/me/route.ts
인증 확인 후 미존재 사용자(404)·이미 삭제된 사용자(409, deletedAt 존재) 검사를 수행한다. 정상 요청 시 prisma.$transaction으로 사용자의 deletedAt·deletionRequestedAt 갱신과 USER_DELETED 감사 로그 생성을 원자적으로 처리한다. 성공 시 { success: true }를 반환한다.
카카오 로그인 시 소프트 삭제 사용자 차단
src/lib/auth/index.ts
카카오 로그인 signIn 콜백에서 사용자 조회 시 deletedAt 필드를 함께 조회하고, 존재하면 false를 반환해 로그인을 차단한다.

Sequence Diagram(s)

sequenceDiagram
  participant User as 사용자
  participant WithdrawPage as WithdrawPage
  participant Modal as ConfirmModal
  participant API as DELETE /api/user/me
  participant Auth as signOut

  User->>WithdrawPage: 탈퇴하기 버튼 클릭
  WithdrawPage->>Modal: confirmOpen = true (모달 오픈)
  User->>Modal: 최종 확인 클릭
  Modal->>WithdrawPage: onConfirm → handleWithdraw()
  WithdrawPage->>API: DELETE /api/user/me (loading = true)
  alt 응답 실패
    API-->>WithdrawPage: !res.ok, error.message
    WithdrawPage-->>User: alert(error.message), loading = false
  else 응답 성공
    API-->>WithdrawPage: 200 { success: true }
    WithdrawPage->>Auth: signOut({ callbackUrl: '/login' })
    Auth-->>User: /login 리다이렉트
  else 예외 발생
    WithdrawPage-->>User: 고정 문구 alert, loading = false
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

  • I5-Project/TALKY-OWL#59: src/lib/auth/index.ts의 카카오 callbacks.signIn 흐름을 수정하여 소프트 삭제 사용자를 차단하는 로직이 추가되므로 이전 카카오 로그인 처리 코드와 직접 겹친다.
  • I5-Project/TALKY-OWL#63: mypage/page.tsxConfirmModal 및 로그아웃·탈퇴 처리 흐름을 동일하게 수정하는 코드가 겹친다.
  • I5-Project/TALKY-OWL#74: src/app/(page)/mypage/page.tsx에서 사용자 표시 이름(displayName)을 user.name 우선·없으면 user.nickname으로 계산하는 로직이 겹친다.

Poem

🐰 토끼가 탈퇴 페이지를 새로 팠네,
약관 다섯 조항 나란히 펼쳐지고,
확인 모달 한 번 눌러 DELETE 날아가면,
signOut 부릅 — /login으로 쏜살같이!
이제 MyPage는 가볍게, 새 페이지는 단단히 🎉

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning PR 설명이 변경사항을 상세히 포함하고 있으나, 제시된 템플릿의 필수 섹션(담당 영역 체크, 관련 이슈, 테스트 결과 체크, 보안 확인 체크 등)이 대부분 누락되어 있습니다. 제공된 템플릿 형식을 따라 담당 영역 체크, 관련 이슈/요구사항, 테스트 결과, 보안/DB 변경 여부를 완성해야 합니다.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 주요 변경사항을 명확하게 설명하고 있습니다. 회원탈퇴 전 약관 안내 페이지 추가가 이번 PR의 핵심 내용이며, 제목과 실제 변경사항이 일치합니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/withdraw-terms-page

Comment @coderabbitai help to get the list of available commands and usage tips.

- DELETE /api/user/me: 소프트 딜리트(deletedAt, deletionRequestedAt 설정) 처리
  및 AuditLog(USER_DELETED) 기록, 이미 탈퇴된 계정 재요청 시 409 반환
- signIn 콜백에서 deletedAt이 설정된 계정의 카카오 로그인을 차단(return false)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/app/`(page)/mypage/withdraw/page.module.scss:
- Around line 23-36: Fix the three stylelint errors in the withdraw page module
file. First, add a blank line between the closing brace of the previous selector
block and the &__body selector declaration to comply with spacing rules. Second,
add a blank line between the &__body selector block and the &__paragraph
selector block. Third, replace the legacy word-wrap property on line 36 with the
modern equivalent overflow-wrap property, as word-wrap is a legacy CSS property
that should use overflow-wrap: break-word instead.

In `@src/app/`(page)/mypage/withdraw/page.tsx:
- Around line 73-84: The handleWithdraw function lacks a re-entry guard that
prevents duplicate DELETE requests when users rapidly click the confirmation
button. Add an early return check at the beginning of handleWithdraw that
returns immediately if loading is already true. Additionally, the modal confirm
button (around lines 119-124) should be disabled by binding its disabled
attribute to the loading state so that users cannot trigger multiple requests
while one is already in progress.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 0802f405-f93d-4bad-a63d-80e572e493b9

📥 Commits

Reviewing files that changed from the base of the PR and between 31f4782 and cb4de4e.

📒 Files selected for processing (3)
  • src/app/(page)/mypage/page.tsx
  • src/app/(page)/mypage/withdraw/page.module.scss
  • src/app/(page)/mypage/withdraw/page.tsx

Comment thread src/app/(page)/mypage/withdraw/page.module.scss Outdated
Comment on lines +73 to +84
const handleWithdraw = async () => {
setLoading(true);
try {
const res = await fetch('/api/user/me', { method: 'DELETE' });
if (!res.ok) {
const json = await res.json().catch(() => null);
const message = json?.error?.message ?? '탈퇴 처리 중 오류가 발생했습니다.';
alert(message);
setLoading(false);
return;
}
await signOut({ callbackUrl: '/login' });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

탈퇴 확인 모달에서 중복 DELETE 요청이 발생할 수 있습니다.

Line 73의 handleWithdraw에 재진입 가드가 없고, Line 119-124의 모달 확인 버튼도 loading 중 비활성화되지 않아 연속 클릭 시 DELETE /api/user/me가 중복 호출될 수 있습니다. 계정 삭제 요청은 단일 실행으로 제한하는 게 안전합니다.

중복 호출 방지 제안
 const handleWithdraw = async () => {
+  if (loading) return;
   setLoading(true);
+  setConfirmOpen(false);
   try {
     const res = await fetch('/api/user/me', { method: 'DELETE' });
     if (!res.ok) {
       const json = await res.json().catch(() => null);
       const message = json?.error?.message ?? '탈퇴 처리 중 오류가 발생했습니다.';
       alert(message);
-      setLoading(false);
       return;
     }
     await signOut({ callbackUrl: '/login' });
   } catch {
     alert('탈퇴 처리 중 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.');
-    setLoading(false);
+  } finally {
+    setLoading(false);
   }
 };

Also applies to: 119-124

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/`(page)/mypage/withdraw/page.tsx around lines 73 - 84, The
handleWithdraw function lacks a re-entry guard that prevents duplicate DELETE
requests when users rapidly click the confirmation button. Add an early return
check at the beginning of handleWithdraw that returns immediately if loading is
already true. Additionally, the modal confirm button (around lines 119-124)
should be disabled by binding its disabled attribute to the loading state so
that users cannot trigger multiple requests while one is already in progress.

- page.module.scss: @include 뒤 빈 줄 추가(declaration-empty-line-before) 2건
- page.module.scss: word-wrap → overflow-wrap (property-no-deprecated) 1건
- page.tsx: handleWithdraw 재진입 가드(if loading return) 추가
- page.tsx: setConfirmOpen(false)를 API 호출 전으로 이동
- page.tsx: setLoading(false)를 finally 블록으로 통합

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@evenif99
evenif99 merged commit 0624cd6 into dev Jun 20, 2026
3 checks passed
@evenif99
evenif99 deleted the feature/withdraw-terms-page branch June 20, 2026 06:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant