---
title: "⚖️ 의사결정 — 계정 삭제 설계 (auth-first cascade, 삭제 완전성)"
category: "decision"
parent: "Claude Code 작업보고"
updated: "2026-07-02"
priority: "High"
purpose: "되돌릴 수 없는 계정 삭제 기능의 서버 설계 의사결정. 초기안(앱 데이터 명시삭제 후 auth 삭제)이 Codex 검수에서 '좀비 계정' 위험으로 지적되어 auth-first cascade로 전환한 근거와, 삭제 완전성을 어떻게 증명했는지의 기록."
read_when: ["계정삭제 설계 근거","auth-first cascade","좀비 계정 위험","삭제 완전성 증명","delete-account 의사결정","FK cascade"]
document_type: "의사결정"
source_status: "generated"
knowledge_group: "03_history"
work_timestamp: "20260702_204705"
source_of_truth: "https://dallog-tools.hansbridge.co.kr/knowledge/"
context: "달록본레포CC (D:\\dallog\\dallog_git)."
---

> 관련 작업보고: "설정 표시형식·계정삭제 UX + delete-account Edge Function". 본 문서는 설계 결정·트레이드오프.

## 1. 결정 사항
계정 삭제 서버(delete-account Edge Function)를 **auth-first cascade** 방식으로 확정.
- `admin.auth.admin.deleteUser(uid)` 한 번으로 앱 데이터 전체 + `auth.identities`(OAuth)까지 FK cascade 연쇄 삭제.
- auth 삭제 전 단계는 아바타 storage best-effort 청소뿐.

## 2. 초기안 → 전환 근거
- **초기안**: 앱 데이터(user_id 33테이블 등)를 명시 삭제 후 마지막에 `auth.admin.deleteUser`.
- **Codex 지적(High)**: 마지막 auth 삭제가 실패하면 "앱 데이터는 이미 지워졌는데 계정은 살아있어 로그인 되는 좀비 계정" 발생.
- **DB 실측**: auth.users를 참조하는 앱 FK가 전수 `ON DELETE CASCADE`(pg_constraint 확인). 자식 트리(strength_sets→exercises→logs, post_comments/likes/notifications/reports→posts)도 cascade. `auth.identities`도 cascade.
- **전환**: 명시 삭제 루프(33개)를 제거하고 auth 삭제 하나로 처리. auth 삭제 전 단계가 아바타뿐이라 실패해도 개인 기록 무손실·재시도 완전 회복 → **좀비 계정 위험 소멸**. 코드도 단순화.

## 3. 예외 (의도된 잔여)
`ON DELETE SET NULL` 2개는 개인 식별 불가하게 익명화되어 남음(의도된 설계):
- `coach_onboarding_abuse_log.user_id`(남용방지 로그 익명화)
- `reports.reviewed_by`(관리자 심사 메타)

## 4. 보안 결정
- **본인만 삭제**: 호출자 JWT(`getUser`)로 파생한 uid만 사용. 요청 body의 uid는 신뢰/사용 안 함(타인 삭제 경로 없음). `verify_jwt: true`.
- **클라이언트 auth 직접조작 금지**: 삭제는 서버 service_role만. 클라는 `functions.invoke('delete-account')`만 호출.
- CORS `*`는 verify_jwt 보호로 CSRF 무의미(유효 Bearer JWT 필요) — Codex 반려(문제없음).

## 5. 삭제 완전성 증명
- **DB 실증**(일회용 계정): 13테이블(3계층 자식 + OAuth identity) 시드 → `DELETE FROM auth.users` → 전부 count=0, identities=0.
- **end-to-end 실증**(로그인 가능 실계정): signup→이메일확인→로그인→기록 입력→delete-account HTTP 호출(200 ok)→ 삭제 후 auth 0·identity 0·기록 0·재로그인 400. 테스트 계정 잔여 0.

## 6. 트레이드오프·미래 주의
- cascade에 전적 의존 → **미래에 새 사용자 소유 테이블 추가 시 반드시 `auth.users` FK `ON DELETE CASCADE`를 걸어야** 이 함수가 자동 커버(코드 주석·본 문서에 명시).
- 페이즈1 스탠스: 결제/환불 데이터가 발생 자체 불가 → 코치 지갑/구독/결제 테이블도 cascade로 즉시 삭제. 글로벌 프리셋 행(user_id null)·뷰는 미대상.
