본문 바로가기
개발/개발

[스크랩 기능] 스크랩은 HardDelete vs SoftDelete?

by 글쓰는 개발자 2026. 2. 26.

배경

스크랩한 프로필을 삭제하는 기능을 구현하다가 이런 고민이 생겼다.

좋아, scrapId 아이디만 서버로 넘기면 되겠어.

근데 잠깐....? 

스크랩 데이터는 HardDelete(물리 삭제) 해도 될까?
아니면 SoftDelete(논리 삭제)로 남겨야 할까?

 

이에 대한 나의 결론은' HardDelete로 충분하다.'이다
이유는 간단하다.

스크랩은 “보관해야만 하는 기록”이라기보다 사용자 개인 편의 기능에 가깝고,

삭제된 스크랩을 시스템이 계속 들고 있을 비즈니스 가치가 낮기 때문이다.


저는 이렇게 생각합니다

1) Hard Delete / Soft Delete 차이

Hard Delete (물리 삭제)

  • DB에서 행을 완전히 삭제
  • 조회/통계/복구 모두 불가능(백업 없으면)

장점

  • 데이터가 깔끔해지고 테이블이 커지지 않음
  • 쿼리가 단순함 (where deleted_at is null 같은 조건이 없음)
  • “삭제” 의미가 직관적

단점

  • 복구가 어려움
  • 삭제 이력/감사 로그가 필요하면 별도 설계가 필요

Soft Delete (논리 삭제)

  • 실제 삭제 대신 deleted_at, is_deleted 같은 플래그로 “삭제된 것처럼” 처리

장점

  • 복구 가능
  • 감사/분석에 활용 가능

단점

  • 모든 쿼리에 “삭제 제외” 조건이 붙음 (실수로 노출되기 쉬움)
  • 인덱스/유니크 제약/조인 쿼리 설계가 복잡해짐
  • 데이터가 계속 쌓여 테이블이 커짐

2) 스크랩은 왜 Hard Delete가 더 자연스러운가?

스크랩은 대개 이런 특성이 있다.

  • 법적/회계적 보관 의무가 없음 (주문/결제/정산과 다름)
  • 사용자가 삭제하면 “없어지는 것”을 기대하는 기능
  • 운영/CS 측면에서 “삭제한 스크랩을 복구해 달라” 요구가 상대적으로 적음

그래서 내가 생각한 기본값은:

스크랩은 Hard Delete


 

3) “유저 흐름 분석”이 필요하면? → Soft Delete 가 아니라 “이벤트/히스토리”로 분리

HardDelete로 삭제하기로 했는데, 만약

 

  • “스크랩을 많이 당한 프로필”
  • “이 유저가 스크랩한 프로필 순위”
  • “스크랩이 많이 발생한 시간대”

 

라는 기획이 추가된다면 어떻게 해야하지?

근데 유저 흐름?이라는 단어가 맞나?

더보기
더보기

사실 만약 저 위의 기획들을 하나의 단어로 말하려면 뭐라 해야 하지?

'유저의 흐름'인가?

라고 생각했는데, 행동 통계 / 활동 로그 / 이벤트 데이터 분석 쪽이므로

  • 사용자 행동 데이터
  • 활동 로그
  • 이벤트 데이터
  • 사용자 행동 분석
  • 프로필 인기 지표

라고 한다는데, 한마디로 정의한다고 한다면,

👉 사용자 행동 이벤트 데이터 (User Behavior Event Data)

조금 더 짧게 가면:

👉 행동 이벤트 데이터

👉 이벤트 로그 데이터

 

실무에서는 보통 

  • User Activity Log (사용자 활동 로그)
  • Event Log (이벤트 로그)
  • Behavioral Analytics Data (행위분석 데이터)
  • Engagement Metrics (엔게이지먼트 데이터)
  • Interaction Data (인터랙션 로그)

이런 단어로 이야기한다고 한다.

 

이때 로그의 종류는 뭐지라고 생각하게 될 텐데 아래와 같다고 한다.

1. 운영 로그 -> 디버깅, 장애 추적용 (Application)

2. 비즈니스 로그 -> 주문 생성, 상태 변경 (Business)

3. 보안/감사 로그 -> 법적 요구사항 대응 (Compliance/Audit)

 

그래서 이벤트 로그 데이터를 어느 종류로 넣어야 하나? 하면 '비즈니스 로그'로 넣어야 할 것 같다.

왜냐면, 데이터를 가져다가 가공, 분석을 함에 따라 운영 -> 비즈니스 로그로 나눠지기 때문이다

이미 HardDelete 해서 데이터가 없는데? 

“유저 흐름을 알고 싶다면 스크랩 데이터를 계속 들고 있는 게 아니라
스크랩 히스토리(이벤트 로그)만 남기면 되지 않을까?”

 

4) 이벤트 로그 테이블 도입

  • scraps 테이블은 사용자 UI용 “현재 상태”만 관리 (상태 테이터,  삭제한 순간 과거 데이터 - Hard Delete )
  • scrap_events 같은 로그 테이블에 “행위”만 적재 (과거에 무슨 일이 있었는 지를 기록)
scraps
-----------------
id
user_id
profile_id
created_at
scrap_events
---------------------
id
user_id
profile_id
event_type  (SCRAP_CREATED / SCRAP_REMOVED)
created_at

 

이러면 장점이:

  • 스크랩 기능은 단순하게 유지 (조회/삭제/목록이 깔끔)
  • 분석은 이벤트 로그만 보면 됨
  • 개인정보/보관 정책도 이벤트 로그 단위로 통제 가능(보관기간 설정)

여기서 조심해야 할 점은

  • 로그는 접근 통제가 약한 경우가 많으므로 목적에 필요한 최소한만 수집해야 한다
    • 전화번호
    • 생년월일
    • 이메일
    • 실명

가 들어가지 않도록 유의해야 한다.


4) 삭제에 대한 의사결정 기준

Soft Delete가 필요한 경우

  • “복구”가 제품 요구사항에 있음 (휴지통 기능)
  • 삭제가 실수로 자주 발생하고, CS가 복구를 자주 해줘야 함
  • 삭제 이력이 법적/정책적으로 필요함
  • 데이터 감사(audit)가 필수인 도메인 (금융/결제/정산 성격)
  • 이때 생길만한 위험으로는
    • 소프트 딜리트 남발 → 쿼리 복잡도 증가 + 데이터 노출 사고 가능성 증가
    • 목록/조회 쿼리에서 is_deleted=False 조건을 빼먹어 삭제된 데이터가 노출
    • 유니크 제약이 걸린 칼럼에서 소프트 딜리트 때문에 “삭제했는데도 다시 추가가 안 되는” 문제 발생
    • “분석 때문에”라는 이유로 운영 테이블에 계속 데이터를 쌓아 성능/인덱스/비용 문제로 이어짐

Hard Delete가 적합한 경우

  • 삭제는 사용자의 명확한 의사이며 복구 요구가 거의 없음
  • 데이터가 “개인 편의” 성격이고 보관 가치가 낮음
  • 시스템을 단순하고 안정적으로 운영하고 싶음
  • 분석은 이벤트 로그로 분리할 수 있음
  • 이때 생길만한 위험으로는
    • Hard Delete만 하고 로그가 없음 → 사용자 행동 분석/장애 추적이 어려움

결론

나는 스크랩은 Hard Delete가 기본 선택으로 합리적이라고 본다.
대신 “이벤트 로그”가 필요하다면 스크랩 테이블에 Soft Delete를 얹기보다,

행위 이벤트(스크랩 생성/삭제 로그)를 별도 테이블로 분리하는 것이
더 깔끔하고 운영에도 안전하다.

 

물론, “스크랩 많이 당한 프로필” 같은 랭킹을 보여줘야 한다면 통계 테이블을 추가적으로 고려해 봐야겠지만, 일단 이벤트 로그까지만 생각한다면 초기 기능을 설계할 때는 이 정도가 좋지 않을까 한다.

반응형