Skip to content

파싱 완료 알림을 제목=아이템 이름 / 본문=상태 문구 구조로 분리 #913

Description

@sevineleven

파싱 알림의 내용이 전부 title 한 줄에 있고 body 는 빈 문자열이다.

title = "${itemName} 파싱이 완료되었어요"
body  = ""

OS 푸시 제목은 줄바꿈되지 않고 뒤가 잘린다. 그래서 이름이 길면 정작 무슨 일인지를 말하는 부분이 통째로 사라진다.

나이키 에어포스 1 07 화이트 로우탑 스니…   ← "파싱이 완료되었어요" 가 안 보임

지금은 이름을 10글자로 잘라 막고 있는데, 이건 길이를 줄이려는 게 아니라 잘리는 자리를 고르려는 것이다. 그 대가로 실제 상품명 대부분이 일찍 잘린다.

푸시의 body 는 2줄까지 보이고 펼칠 수 있다. 이름을 제목에, 상태를 본문에 두면 제목이 잘려도 잃는 게 없다.

무엇을

알림 title body
성공 (위시 출처) ${itemName} 위시 저장이 성공했어요
성공 (토너먼트 출처) ${itemName} 아이템이 등록됐어요
실패 (현행 유지) (현행 유지)

실패는 손대지 않는다. 파싱이 실패하면 이름이 없다 - markFailed() 는 status 만 바꾸고, ItemSnapshot 주석도 "PROCESSING·FAILED 는 이름·가격이 비어 있다" 고 명시한다. ${itemName} 을 쓰면 모든 실패 알림 제목이 fallback("상품")으로 똑같아져 구분이 안 된다.

출처 분기

ItemParsingRecipientResolver.resolveRouting 이 이미 위시/토너먼트를 가른다(NotificationKind 파생에 쓰는 그 값). 새 조회 없이 그 결과로 body 문구를 고른다.

파싱 알림이 뜨는 시점엔 수신자 성격이 갈리지 않는다:

등록 경로 snapshot 파싱 수신자
위시에 직접 등록 새로 생성 O 위시 주인
토너먼트에 직접 등록 새로 생성 O 올린 사람
위시 -> 토너먼트로 담기 기존 READY 재사용 X (알림 없음)

토너먼트에 직접 등록해도 위시리스트에는 안 들어간다(TournamentItemServiceWish 를 만들지 않는다). 그래서 "위시 저장" 문구가 토너먼트 등록자에게 가는 일이 없다.

body 문구를 변수로 채운다

notification_templates 는 타입당 한 행(PK=type)이라 위시용·토너먼트용 body 를 따로 둘 자리가 없다. 두 문구가 구조도 달라("위시 저장이 성공했어요" vs "아이템이 등록됐어요") 공통 뼈대 + 변수로도 안 쪼개진다.

body_template 을 변수 하나로 두고 핸들러가 문장을 통째로 채운다.

대가: 백오피스(#252)에서 이 body 문구를 편집할 수 없게 된다. title 은 여전히 템플릿이 소유하므로 편집 여지가 완전히 사라지지는 않는다. 템플릿을 type+kind 복합키로 쪼개는 안도 검토했으나, 이 건 하나 때문에 스키마와 백오피스를 바꾸는 비용이 커 접었다.

절단 로직 완화

제목이 이름뿐이면 OS 가 잘라도 의미가 안 사라지므로 10글자 캡이 불필요해진다. displayName 에서 표시 글자 캡을 걷어내고, 엔티티 불변식(require(title.length <= 255))을 지키는 char 안전망만 남긴다.

옆 핸들러의 절단 누락도 함께 고친다

TournamentItemDeletedHandler 가 같은 개념(itemSnapshotRepository.findById(...)?.name ?: "상품")을 갖고 있는데 절단이 없다. 템플릿이 "${actorName}님이 '${itemName}'을(를) 삭제했어요" 라, 이름이 길면 아래 경로로 알림이 조용히 사라진다.

긴 이름 -> title 이 255자 초과 -> Notification 생성자의 require 위반
-> dispatcher 의 수신자별 runCatching 이 삼킴 -> 삭제 알림이 전 수신자에게 누락

ProductSnapshot 이 이름을 512자까지 허용하므로 도달 가능한 경로다. 이 이슈가 어차피 displayName 을 손대니, 그때 두 핸들러가 공유하도록 옮긴다. 중복된 fallback 상수(FALLBACK_NAME / FALLBACK_ITEM_NAME)도 함께 정리된다.

다만 삭제 알림은 제목에 이름이 문장 안에 박혀 있어 파싱 완료 알림과 사정이 다르다. 파싱 쪽은 제목이 이름뿐이라 캡을 걷어내지만, 삭제 쪽은 뒤에 "…을(를) 삭제했어요" 가 붙으므로 표시 글자 캡이 여전히 필요하다. 공유할 때 캡을 인자로 받게 하는 등 두 용도를 모두 만족시켜야 한다.

함께 바뀌어야 하는 것

  • 클라: 알림 카드가 body 도 렌더해야 한다. 지금은 message={notification.title} 로 제목만 그린다(NotificationItem.tsx). 서버만 먼저 나가면 히스토리 카드에 상품명만 뜨고 무슨 일인지 안 보인다. 선행 또는 동시 배포가 필요하다.
  • *Api 문서 표·example 갱신. "body 는 현재 전 타입 빈 문자열" 서술이 더 이상 참이 아니다.

관련

Metadata

Metadata

Assignees

Labels

feat외부 가시적 새 기능

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions