같은 답변에 대한 알림이 여러 번 수신됩니다

링크, 인용, 또는 멘션이 추가되지 않은 상태에서 동일한 답글에 대해 두 번째 알림을 처음 목격한 시점은 Topics from some categories do not appear on /latest - #36 by JammyDodger 의 편집 이후였습니다. 이 경우는 아래에 나열한 재현 단계와 약간 다르지만, 근본적인 문제는 동일하다고 생각합니다.

이 문제가 발생한 두 번째 게시글은 Messages section for sidebar - #13 by nathank 입니다. 상황은 비슷했습니다: 편집을 통해 알림을 유발할 수 있는 아무것도 추가되지 않았는데(인용문은 이미 존재했음)에도 불구하고 여전히 두 번째 알림을 받았습니다.

발견한 재현 단계는 다음과 같습니다(대부분의 경우 작동했으며, 때로는 편집에 @멘션을 추가해도 새 알림이 트리거되지 않음)

사용자 3명이 필요합니다: OP(게시자), notifiedUser(알림 수신자), spammer(스패머)

  1. OP가 토픽을 생성합니다.
  2. notifiedUser가 답글을 씁니다.
  3. OP가 notifiedUser의 게시글에 답글을 씁니다.
    notifiedUser가 답글에 대해 알림을 받습니다(예상된 동작)
  4. spammer가 notifiedUser의 게시글에 답글을 씁니다. 답글에는 notifiedUser의 다른 게시글에 대한 링크와 답글을 작성하는 대상 게시글에 대한 인용문이 포함되어 있습니다. (선택 사항: notifiedUser를 @멘션할 수도 있음)
    notifiedUser가 답글에 대해 알림을 받습니다(예상된 동작)
    [@멘션을 추가한 경우, 알림은 @멘션에 대한 것입니다(예상된 동작)]
  5. notifiedUser가 새 답글들을 읽어서 알림을 읽음 처리하고, 알림을 놓치지 않도록 다른 곳으로 이동합니다.
  6. spammer가 답글을 편집하여 오타를 수정합니다(또는 edit1을 추가합니다).
    notifiedUser가 인용된 것에 대해 알림을 받습니다(예상치 못한 동작, 이 답글에 대한 알림을 이미 받았고 인용문은 이미 존재했으므로 다시 알려줄 필요 없음)
  7. spammer가 답글을 다시 편집하여 다른 오타를 수정합니다(또는 edit2를 추가합니다).
    notifiedUser가 링크된 것에 대해 알림을 받습니다(예상치 못한 동작, 이 답글에 대한 알림을 이미 받았고 링크는 이미 존재했으므로 다시 알려줄 필요 없음)

동영상에는 최종 단계인 5~7단계만 표시됩니다. 왼쪽은 spammer, 오른쪽은 notifiedUser입니다.

3개의 좋아요

In post_alerter.rb

Change lines 589-599 from:
 # linked, quoted, mentioned, chat_quoted may be suppressed if you already have a reply notification
 if [
      Notification.types[:quoted],
      Notification.types[:linked],
      Notification.types[:mentioned],
      Notification.types[:chat_quoted],
    ].include?(type)
   if existing_notifications.find { |n| n.notification_type == Notification.types[:replied] }
     return
   end
 end

 To:
 # linked, quoted, mentioned, chat_quoted may be suppressed if you already have any notification about this 
 post
 if [
      Notification.types[:quoted],
      Notification.types[:linked],
      Notification.types[:mentioned],
      Notification.types[:chat_quoted],
    ].include?(type)
   return if existing_notifications.any?
 end

이렇게 하면 동작은 하지만, 여기서 빠져나갈 수 있는 다른 알림들이 있어서 조금 걱정됩니다. (예를 들어 억제하고 싶을 수 있는 플러그인 알림 등)

@lindsey 여기서 제품 관련 질문이 하나 있습니다. 언제 알림을 억제해야 할까요?

아마도 이 작은 수정은 한 걸음 전진인 것 같습니다?

확신이 서지 않습니다. 제 영상에 있는 답글 알림이 아닌가요? 그런데 여전히 그 인용과 링크에 대한 알림이 뒤에 남아 있습니다. 그래서 다른 알림 유형으로 이를 확장해도 여기서는 도움이 되지 않을 수 있습니다. 하지만 다른 엣지 케이스를 커버할 수는 있겠죠.
제 재현 사례에서 문제가 되는 것이 “2개의 답글” 알림인지 궁금합니다. 답글이 수정될 때, 해당 답글에 대한 기존 알림 확인 로직을 깨뜨리는 것일까요?

일반적으로, 제가 게시물을 읽기 전에 이미 모든 트리거가 게시물에 존재했다면 수정으로 인해 추가 알림이 발생하지 않아야 한다고 생각합니다. 멘션/링크/인용과 무관한 오탈자 수정으로 인해 새로운 알림이 생성되어서는 안 됩니다.
트리거가 교체되는 경우라면, 두 번째 알림을 받는 것보다는 기존에 읽지 않은 알림이 변경(또는 교체)되기를 선호합니다. 노이즈를 피하기 위해 사용자의 게시물에서 @멘션을 제거하는 것이 인용에 대한 두 번째 알림으로 이어져서는 안 됩니다. @멘션에 대한 알림이 사라지기를 기대합니다.
새로운 알림을 원한다고 생각하는 유일한 경우는, 수정이 더 중요한 알림 유형을 추가하는 경우입니다. 즉, 누군가가 제 게시물에 링크를 걸고 나중에 저를 @멘션하는 수정을 추가한다면, 더 이상 제가 쓴 것에 대해 말하는 것이 아니라 저에게 직접 말하는 것으로 보이므로 알려주는 것이 타당합니다. 수정은 더 이상 토픽을 올리지 않으므로, @멘션은 사용자에게 수정 사항을 알리는 데 도움이 될 수 있습니다.

Moin이 사용자 관점에서 이상적인 상황을 잘 설명한 것 같지만, 이 부분을 제대로 구현하기는 어려울 것 같습니다:

앱 내 알림(in-app notifications)의 경우 그렇게 처리할 수 있을지 모르겠지만, 푸시 알림이나 이메일 알림은 이미 발송된 것을 취소할 수 없습니다. (일반적으로 알림 시스템에 복잡성을 더하는 것은 꺼려서, 앱 내 알림과 이메일/푸시 알림의 내용이 달라지는 것을 허용하는 것이 괜찮을 수도 있지만, 저는 이를 포기하는 쪽을 선호합니다.)

다만, 이 의견에는 동의합니다:

  • 게시물이 사용자에게 알림을 보내야 하는 경우(예: 게시물 작성자가 User A를 인용한 경우), 해당 사용자에게 알림을 보냅니다(예: User A가 인용되었음을 알리는 알림을 받음).
  • 해당 게시물에 대한 편집이 알림 대상이나 그 이유를 변경하지 않는 경우(예: 게시물 작성자가 오타를 수정한 경우), 누구에게도 알림을 보내지 않습니다.
  • 해당 게시물에 대한 편집이 알림 대상(예: 게시물 작성자가 User B를 멘션한 경우)이나 이유(예: 게시물 작성자가 User A를 멘션한 경우)를 변경하는 경우, 영향을 받는 사용자에게 알림을 보냅니다(예: User B가 멘션 알림을 받고, User A도 멘션 알림을 받음).

@moin 이 내용 괜찮은가요?

1개의 좋아요

네, 여기서 제 PR을 닫고 이것을 기능 요청으로 처리하겠습니다.

특히 여기에는 다음과 같은 간극이 있습니다:

  • @Moin 님은 … 기존 알림의 업데이트를 원합니다
  • @lindsey 님은 … 게시물에 추가된 새로운 정보에 대한 새 알림을 원합니다

여기서 완전한 정렬을 위해서는 꽤 복잡한 추적 작업이 필요합니다… 변경 사항의 규모를 평가하고 있지만, 솔직히 지금은 아무것도 하지 않는 것이 가장 쉬울 것 같습니다. 변경 사항이 매우 취약해질 것이기 때문입니다.

어떤 멘션이 새로운 것이고 어떤 것이 오래된 것인지 추출하는 것은 파서(그 시점에는 파싱을 수행하지 않음)나 취약한 정규 표현식이 필요합니다.

무엇보다, 게시글에 알림을 유발할 만한 변경 사항이 없다면 다시 알림을 받지 않기를 원합니다. 오타를 수정하는 것만으로는 이미 2개의 알림이 동일한 주제에 대해 병합되었기 때문에 알림을 받은 적이 있는 나에게 다시 알림을 보내서는 안 됩니다. 그리고 12월에 해당 상황이 발생하기 전까지는 몇 년 동안 이런 문제를 전혀 인지하지 못했습니다.

코드를 기반으로 재현 단계를 찾으려 할 때, 이 문제에 대해 ChatGPT가 내게 말한 내용을 요약해 달라고 요청했습니다.

요약: 중복 알림이 일반적으로 방지되는 이유와 여기서 실패하는 이유 AI

핵심 문제

중복 방지 메커니즘은 편집된 게시글에 여전히 범위(scope)가 설정된 답변 알림을 찾는 데 의존하지만, 답변 알림은 **병합(collapsed), 삭제(destroyed), 또는 다른 게시글에 재연결(re-attached)**될 수 있습니다.
그 결과, 편집 시점의 억제(suppression) 로직이 사용자가 이미 해당 답변에 대해 알림을 받았다는 사실을 신뢰할 수 있게 감지하지 못합니다.


PostAlerter에서 중복 알림은 다음 방식으로 방지됩니다:

  1. 게시글 생성 시 이미 알림을 받은 사용자 추적
notified = []
  1. 답변 알림이 존재할 경우 2차 트리거 억제
if [:quoted, :linked, :mentioned, :chat_quoted].include?(type)
  return if existing_notifications.find { |n|
    n.notification_type == Notification.types[:replied]
  }
end

이는 동일한 게시글에 대해 사용자에게 두 번 알림을 보내는 것을 방지하기 위한 것입니다.

  1. 답변 알림 병합
    답변 알림(:replied)은 주제(topic)별로 병합됩니다:
destroy_notifications(user, COLLAPSED_NOTIFICATION_TYPES, topic)

남은 알림은 다음에 다시 연결됩니다:

post = first_unread_post(user, topic)

따라서 알림은 원래 트리거가 된 게시글을 더 이상 대표하지 않게 됩니다. 그 결과, post_number 매칭에 의존하는 억제 로직은 편집된 게시글에 대한 이전 알림을 신뢰할 수 있게 감지하지 못합니다.


재현 케이스에서 이 문제가 실패하는 이유

재현 케이스에서는:

  • 사용자가 처음에는 답변에 대해 알림을 받습니다
  • 여러 답변이 존재할 때, 답변 알림은 병합됩니다
  • 병합된 알림은:
    • 편집된 게시글에 대해 더 이상 존재하지 않거나,
    • **다른 post_number**를 가진 채로 존재합니다
  • 편집 시:
    • 답변 로직이 실행되지 않습니다 (new_record == false)
    • 억제 체크는 게시글 스코프의 :replied 알림만 확인합니다
    • 해당 알림이 발견되지 않음 → 억제 실패
  • 인용/링크 감지가 다시 실행되어 새로운 알림이 생성됩니다

사용자의 관점에서는:

“나는 이미 이 답변에 대해 알림을 받았다.”

코드의 관점에서는:

“이 게시글에 대한 기존 알림이 없다.”

양쪽 모두 사실입니다.

공개 카테고리에 테스트 사용자를 멘션한 주제를 만들고 몇 분 후 비공개 카테고리로 이동시키면, @멘션에 대한 이메일이 전송되었음에도 불구하고 알림이 인터페이스에서 제거됩니다.
따라서 이메일은 전송되었지만 삭제된 앱 내 알림은 이미 존재합니다.

mcwumbly가 토픽에 태그를 추가했을 때 내 게시글이 링크되었다는 새로운 알림을 받는 것은 여전히 버그처럼 느껴집니다. 해당 링크는 그가 토픽을 게시했을 때 이미 존재했고, 인용에 대한 알림도 이미 받았습니다. 태그를 제외한 다른 변경 사항은 없습니다. 따라서 편집이 두 번째 알림을 트리거하는 것이 왜 예상되는 일인가요?

첫 번째 게시글의 단계 외에도 다음과 같은 단계에서도 동일한 문제가 발생합니다:

  1. notifiedUser가 토픽을 생성합니다
  2. spammer가 링크된 토픽으로 답글을 남깁니다. 게시글에는 기본적으로 링크가 포함되어 있으므로 @멘션과 인용만 추가하면 됩니다.
    → notifiedUser는 @멘션에 대해 알림을 받습니다(예상됨) 그리고 토픽을 읽습니다
  3. spammer가 토픽에 태그를 추가합니다
    → notifiedUser는 게시글에서 인용되었다는 알림을 받습니다(예상 밖, 이미 알림을 받았고 아무것도 변경되지 않았음)
  4. spammer가 토픽 제목을 편집합니다
    → notifiedUser는 게시글에서 링크되었다는 알림을 받습니다(예상 밖, 이전에 알림을 받았고 게시글도 여전히 변경되지 않았음)

2개의 좋아요