Skip to content

알림 히스토리 삭제 기능 (단건·모두·N일 자동삭제) #747

Description

@sevineleven

알림 히스토리창에 4개 기능이 필요하다 - 모두읽음 · 단건삭제 · 모두삭제 · N일 자동삭제. 이 중 모두읽음은 이미 있고(POST /read {all:true}markAllRead), 나머지 삭제 계열 3개가 미구현이다.

무엇을 (브레인스토밍 확정 설계)

[결정] 하드삭제 / N일 자동삭제는 읽음 무관 전부 삭제 / read API 미러링한 단일 삭제 엔드포인트.

① 모두 읽음 - 작업 없음

기존 POST /read {all:true}markAllRead 그대로 사용.

② 단건·모두 삭제 (하드삭제, 단일 엔드포인트)

  • 엔드포인트: DELETE /api/v1/notifications + body {all XOR ids} (read 계약 미러링). 단건=ids[1개], 다건=ids[N], 모두=all:true.
  • 요청 DTO NotificationDeleteRequest(all, ids): read 의 all XOR ids 검증(@AssertTruetoCommand() 패턴 그대로 복제.
  • 컨트롤러: NotificationHistoryController@DeleteMapping 추가 (같은 /api/v1/notifications).
  • 서비스: 본인(userId) 소유만 삭제. all→전체, ids→지정(타인·없는 id 무영향, 멱등).
  • Repository: deleteByUserIdAndIds(userId, ids): Int 신규 / 모두는 기존 hardDeleteAllByUserId 재사용 가능(동일 쿼리).
  • 뱃지 동기화: 삭제된 것 중 안읽음이 있으면 unread 뱃지 감소 - read flow(readAndSyncBadge)와 대칭으로 삭제 후 뱃지 재계산 + SSE silent sync.
  • 응답: read 미러링이라 카테고리별 unread 뱃지 반환.

③ N일 자동삭제 (하드삭제, 읽음 무관)

  • 스케줄러 NotificationCleanupScheduler(@Scheduled, 1일 1회) - AnnouncementScheduler 패턴 참고.
  • Repository deleteByCreatedAtBefore(cutoff): Int - created_at < now-N일 전부 삭제.
  • N 설정: application.yml (notification.retention-days), 하드코딩 금지. 기본값은 구현 시 협의.
  • 동시성: age delete 는 멱등이라 blue-green 중복 실행 무해.

마이그레이션

  • 하드삭제라 deleted_at 컬럼 불필요.
  • 단, 자동삭제 age 쿼리가 풀스캔 안 하게 created_at 인덱스 확인 / 필요시 idx_notifications_created_at 마이그레이션 추가.

반드시 지킬 CLAUDE.md 규약 (구현자 체크리스트)

1. 도메인 예외 정책 (require/check/error vs 커스텀 예외)

  • 판단 기준 "멀쩡한 클라이언트가 정상 요청으로 여기 닿을 수 있나?" - 닿으면 커스텀 예외(계약), 못 닿으면 require/check/error(불변식).
  • 계약 위반(all·ids 동시 / 둘 다 없음 등)은 Bean Validation(400) 또는 NotificationException 커스텀. 없는 id·타인 id 는 예외 대신 무영향(멱등) 으로 처리 - 설계상 삭제는 본인 소유만 걸러 0건 반환.
  • 커스텀 예외는 NotificationException(도메인 명사)Exception, private 생성자 + companion 정적 팩토리, message·ErrorCategory·HttpStatus 를 한 자리에.

2. 에러 code (#728 code 기반 전환)

3. API 응답 전수 문서화 (절대 규칙)

  • NotificationHistoryApi(DELETE) 에 멀쩡한 클라가 받을 수 있는 모든 응답을 @ApiResponses 로 전수 선언 - 성공 200(+뱃지) · 400(all XOR ids 위반) · 401(미인증).
  • *ApiExamples 에 각 응답 example payload 를 ApiResponseBody.ok/fail 로 등록, fail detail 은 single source(Bean Validation 은 DTO const, 도메인 예외는 OperationExamples.add(exception)).

4. 기타

  • DTO 자체 매핑(toCommand, 별도 Mapper 금지) · @Transactional 서비스 경계(삭제는 쓰기) · FK 제약 금지 · 테스트 컨벤션(DTO 분기 단위 / DELETE 계약 통합 / 자동삭제 cutoff 경계, 내부 모킹·셋업 hook 금지, IntegrationTestSupport 공유).

Metadata

Metadata

Assignees

Labels

feat외부 가시적 새 기능

Fields

No fields configured for Feature.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions