Skip to content

위시 새로고침 파싱 알림을 등록 알림과 타입으로 분리 - #1037

Merged
m-a-king merged 4 commits into
devfrom
feat/1036-wish-refresh-notification
Sep 6, 2026
Merged

위시 새로고침 파싱 알림을 등록 알림과 타입으로 분리#1037
m-a-king merged 4 commits into
devfrom
feat/1036-wish-refresh-notification

Conversation

@m-a-king

@m-a-king m-a-king commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

Situation

  • 위시 새로고침(POST /api/v1/wishlists/{wishId}/refresh)은 등록과 같은 PENDING 버전을 만들어 같은 파싱 이벤트로 끝난다. 그래서 알림도 등록과 완전히 같은 ITEM_PARSING_COMPLETED / ITEM_PARSING_FAILED 로 나갔다.
  • 새로고침한 사람이 "위시 저장이 성공했어요" 를 받고, 실패 시엔 기존 정보가 남아 있는지 알 길이 없었다. 클라는 알림 종류로 등록과 갱신을 구분할 수 없었다.

Task

Action

판정 근거: 위시 생성시각과 버전 생성시각 비교

  • 위시는 늘 이미 있는 버전을 가리키며 태어난다. 등록도 공유 합류도 snapshot 을 먼저 저장하고 wish 를 저장한다. 그래서 위시가 버전보다 먼저 만들어졌다는 것은 곧 생성 후 포인터가 그 버전으로 스왑됐다는 뜻이고, 파싱 대상 버전으로 스왑하는 경로는 새로고침뿐이다.
  • 컬럼을 추가하지 않는다. 기존 위시 주인 조회에 refreshed(w.created_at < s.created_at) 플래그 한 칸을 실어, 수신자 도출·라우팅 해석·등록/새로고침 분할이 같은 한 조회를 나눠 쓴다. created_at 은 DATETIME(6) 이다.
  • 알려진 한계. 정체성 병합으로 옛 버전이 다른 상품으로 옮겨진 뒤 그 진행 중 버전에 새로고침으로 합류하면 위시가 더 늦어 등록으로 보인다. 병합과 진행 중 합류가 겹치는 드문 경합이라 컬럼 없이 감수하고 뷰 주석에 명시했다.
경로 위시 vs 버전 생성 순서 판정
신규 등록 (snapshot 저장 뒤 wish 저장) 위시가 뒤 등록
남의 진행 중 버전에 등록으로 합류 위시가 뒤 등록
새로고침으로 새 PENDING 생성 후 스왑 위시가 앞 새로고침
새로고침이 남의 진행 중 버전에 합류(#826) 위시가 앞 새로고침
토너먼트 출전 새로고침 경로 없음 항상 등록

구현: 같은 이벤트에서 배타적 수신자로 갈라지는 핸들러

  • 실패가 남의 성공으로 해소되면 후속 알림을 보낸다 #1028 해소 통지와 같은 구조다. ItemRefreshCompletedHandlerItemRefreshFailedHandlerItemParsingCompleted / ItemParsingFailed 를 구독하고, 등록 핸들러는 새로고침 수신자를 뺀다.
  • ItemParsingRecipientResolverresolveRegistered(새로고침한 사람을 뺀 등록 수신자)와 resolveRefreshContexts(새로고침한 위시 주인의 wishId 컨텍스트)를 더했고, 두 새로고침 핸들러는 이 하나에 위임한다. 디스패처가 수신자 도출과 컨텍스트 해석을 따로 부르므로 조회는 핸들러당 두 번 돈다(다른 파싱 핸들러와 같은 구조).
  • INCOMPLETE 는 가르지 않는다. 완성 조건이 수기라 "나머지는 직접 채워주세요" 가 새로고침에도 그대로 맞고, 수신자는 그 버전을 가리키는 본인뿐이다. 스펙·히스토리 문서에 이 예외를 적었다.
  • 새로고침 실패 핸들러는 itemName 을 채우지 않는다. 실패한 버전은 이름이 비어 늘 기본값이라 쓸모가 없고, 카탈로그는 dispatch 가 실제로 채우는 변수만 선언한다. 그래서 스냅샷 원본 저장소도 쓰지 않는다.
타입 수신자 title body push
ITEM_REFRESH_COMPLETED 그 버전으로 새로고침한 위시 주인 ${itemName} (새 성공본 이름) 최신 상품 정보로 새로고침했어요 on
ITEM_REFRESH_FAILED 같음 새로고침에 실패했어요 기존 상품 정보는 그대로 남아 있어요 on
  • 실패 문구가 "기존 정보는 남아 있다" 인 이유. 새로고침은 성공(READY) 항목에서만 시작되고, 실패해도 카드는 표시값 파생(카드 표시값을 파생 조회로: 최신 기계 READY 우선 + start 시점 박제 #858)으로 옛 성공본을 그대로 보인다. 등록 실패 문구를 그대로 쓰면 정보가 사라졌다는 오해를 낳는다.
  • NotificationKind.of 에서는 다른 파싱 알림과 같이 라우팅 출처를 따른다. 실질은 항상 WISH 지만 kind 와 payload 셰입이 어긋날 여지를 없애기 위해서다.
  • 템플릿 시드 마이그레이션(JDBC, dollar-brace 회피)과 히스토리 API 문서·SSE 스펙·새로고침 엔드포인트 OpenAPI 설명에 새 타입과 "등록/새로고침은 type 으로 가른다" 안내를 더했다.

검토 후 채택하지 않은 안

이유
타입 분리 없이 body 문구만 분기 클라가 알림 종류로 구분해야 한다는 요구라 타입 분리로 확정
스냅샷에 등록/새로고침 출처 컬럼 추가 생성 순서 불변식으로 충분해 스키마 변경이 불필요
완료만 분리, 실패는 문구만 실패 쪽 오해("정보가 사라졌다")가 더 커서 둘 다 분리

Result

  • 새로고침한 사람에게는 등록 완료 알림이 오지 않는다. end-to-end 테스트가 새로고침 후 알림 목록이 ITEM_REFRESH_COMPLETED 하나임을 고정한다.
  • 수신자 해석 테스트로 고정한 케이스: 등록/새로고침 배타성(완료·실패), 진행 중 합류 양 방향, 토너먼트 등록자는 등록 쪽에 남음, 새로고침 라우팅은 자기 wishId.
  • 클라 후속: 새 타입 2개를 wishId 딥링크로 처리한다. 새로고침 실패 뒤에도 카드 값은 지우지 않는다.
  • 서버 후속 카드 표시값이 새로고침 실패·INCOMPLETE 뒤에 내 수기값을 잃는다 #1039: 실패 문구 "기존 상품 정보는 그대로 남아 있어요" 는 카드 표시 규칙이 내 수기값을 지키고 INCOMPLETE 를 새로고침한 본인에게 보여줄 때 온전히 참이 된다. 지금 표시 파생은 포인터가 옮겨 가면 수기값을 잃고, INCOMPLETE 보다 옛 READY 를 우선한다. 그 수정은 표시 도메인이라 별도 이슈로 뗐다.

연관 이슈

- 새로고침은 등록과 같은 PENDING 버전을 만들어 같은 ItemParsingCompleted/Failed 로 끝나, 새로고침한 사람도 "위시 저장이 성공했어요" 를 받았다. ITEM_REFRESH_COMPLETED / ITEM_REFRESH_FAILED 타입과 핸들러 2개를 신설해 같은 이벤트에서 수신자가 배타적으로 갈리게 했다(#1028 해소 통지와 같은 구조)
- 등록/새로고침을 적는 컬럼은 두지 않았다. 위시는 늘 이미 있는 버전을 가리키며 태어나므로(등록·공유 합류 모두 snapshot 저장 뒤 wish 저장) 위시 created_at 이 버전 created_at 보다 앞서면 곧 새로고침이다. 진행 중 합류(#826) 양 방향에서도 성립함을 테스트로 고정
- 등록 완료·실패 핸들러는 새로고침 수신자를 뺀 resolveRegistered 를 쓰고, 미완 알림은 갈리지 않아 resolve 그대로 둔다
- 실패 문구는 "기존 상품 정보는 그대로 남아 있어요" 로 뒀다. 새로고침은 성공 항목에서만 시작되고 실패해도 카드는 표시값 파생(#858)으로 옛 성공본을 보이므로, 등록 실패 문구를 그대로 쓰면 정보가 사라졌다는 오해를 낳는다
- 새로고침 실패 핸들러는 itemName 을 채우지 않는다. 실패한 버전은 이름이 비어 늘 기본값이고, 카탈로그는 dispatch 가 실제로 채우는 변수만 선언한다
- 히스토리 API 문서·SSE 스펙에 새 타입 행과 "등록/새로고침은 type 으로 가른다" 안내를 더했다

Closes #1036

Claude-Session: https://claude.ai/code/session_01HnKAcdnoziL8hdVr9xinFb
- ITEM_REFRESH_COMPLETED / ITEM_REFRESH_FAILED 행과 "등록과 새로고침은 type 으로 갈린다" 안내, 클라 예시 switch 분기를 추가
- 새로고침은 위시 전용이라 kind 분기 없이 wishId 로 위시 상세에 가고, 실패 뒤에도 카드 값은 지우지 않는다는 계약을 명시

Claude-Session: https://claude.ai/code/session_01HnKAcdnoziL8hdVr9xinFb
@m-a-king m-a-king added the feat 외부 가시적 새 기능 label Sep 5, 2026
@m-a-king m-a-king self-assigned this Sep 5, 2026
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown

Discord 스레드 연동용 메타데이터입니다. discord-pr-bot 워크플로가 자동 생성하며, 수정·삭제하면 PR 과 Discord 알림 연동이 끊깁니다.

@coderabbitai

coderabbitai Bot commented Sep 5, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Team

Run ID: f12063fa-8282-471f-bf43-1e1edbd1bc76


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

- 코드 리뷰 반영. 새로고침 전용 쿼리를 따로 두면 파싱 완료 1건에 같은 위시 행을 세 번 읽는다. 기존 위시 주인 조회에 refreshed(위시가 버전보다 먼저 만들어졌는가) 플래그를 실어 등록/새로고침 분할을 메모리에서 하고, 전용 쿼리와 userId 전용 쿼리를 저장소 3층에서 지웠다
- 두 새로고침 핸들러가 복제하던 수신자·컨텍스트 코드를 resolver 의 resolveRefreshContexts 하나로 접었다. "조회 1회" 주석은 틀렸다 - 디스패처가 수신자 도출과 컨텍스트 해석을 따로 부르므로 두 번 돈다고 바로잡았다
- 시각 비교 판정의 알려진 한계(정체성 병합 뒤 진행 중 합류 시 등록으로 보임)를 뷰 주석에 명시했다. 드문 경합이라 컬럼 없이 감수한다
- 새로고침 엔드포인트 OpenAPI 설명이 "등록과 동일하게 완료·실패 알림" 이라 새 타입과 어긋났던 것을 고쳤다
- INCOMPLETE 는 새로고침이라도 갈리지 않는다는 예외를 스펙·히스토리 문서에 적었다. 완성 조건이 수기라 기존 문구가 그대로 맞고, 카드가 일부만 빈 상태를 보이게 하는 표시 규칙은 #1039 가 맡는다

Claude-Session: https://claude.ai/code/session_01HnKAcdnoziL8hdVr9xinFb
@m-a-king
m-a-king merged commit 7ba80b6 into dev Sep 6, 2026
7 checks passed
@m-a-king
m-a-king deleted the feat/1036-wish-refresh-notification branch September 6, 2026 10:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat 외부 가시적 새 기능

Projects

None yet

Development

Successfully merging this pull request may close these issues.

위시 새로고침 파싱 알림을 등록 알림과 타입으로 분리 (ITEM_REFRESH_COMPLETED / FAILED)

1 participant