-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: FCM을 통해 푸쉬 알림 구현 #605
Conversation
# Conflicts: # backend/.gitignore
|
||
@Slf4j |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 어노테이션은 FcmCondition
에서 사용하나요? 사용하지 않으면 제거 부탁드려요~
@@ -12,13 +12,14 @@ public enum NotificationErrorCode implements ErrorResponse { | |||
|
|||
CANNOT_SEND_ALARM(HttpStatus.INTERNAL_SERVER_ERROR, "FCM 알림 전송에 실패하였습니다."), | |||
CANNOT_FIND_URL(HttpStatus.INTERNAL_SERVER_ERROR, "해당 URL을 찾을 수 없습니다."), | |||
INVALID_COMMENT_ROOM_STATUS(HttpStatus.INTERNAL_SERVER_ERROR, "존재하지 않는 거래 상태입니다."), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
존재하지 않은 거래 상태가 나왔나요??
view 단에서 존재하지 않은 상태를 찾을 때 던지는 예외임을 찾았어요!
|
||
fcm: | ||
secret-key: | ||
path: /fcm/chongdaemarket-fcm-key.json |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
application.yml 파일에 이미 정의되어 있어서, 재정의 안해도 되지 않나요?
import lombok.RequiredArgsConstructor; | ||
|
||
@Getter | ||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
정적팩터리 메서드를 사용하려고 설정하셨을까요? 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
정확합니다!
.subscribeToTopic(List.of(member.getFcmToken()), topic.getValue()); | ||
log.info("구독 성공 개수: {}", response.getSuccessCount()); | ||
log.info("구독 실패 개수: {}", response.getFailureCount()); | ||
return response; | ||
} catch (FirebaseMessagingException e) { | ||
log.error("토픽 구독 실패: {}", e.getMessage()); | ||
e.printStackTrace(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
notification이 제대로 구독되었는지 테스트하기 위해 남긴 로그 같아보여요
실패할 때만 어떤 사용자인지만 로깅하는건 어떨까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FCM 관련 내용은 로그를 통해서만 확인이 가능해요! 저희는 현재 DB에 저장하지 않고 있구요 ㅠㅠ 따라서 로그는 최대한 자세히 남기도록 하였습니당
.unsubscribeFromTopic(List.of(member.getFcmToken()), topic.getValue()); | ||
log.info("구독 취소 성공 개수: {}", response.getSuccessCount()); | ||
log.info("구독 취소 실패 개수: {}", response.getFailureCount()); | ||
return response; | ||
} catch (FirebaseMessagingException e) { | ||
log.error("토픽 구독 실패: {}", e.getMessage()); | ||
e.printStackTrace(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이부분도 마찬가지로 의견드립니다~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
에버 fcm하느라 정말 고생 많았어요..! 👍
코드도 어떤 상황에서 Notification을 보내는지 잘 나뉘어져 있어서 읽기가 너무 편했어요 😄
개인적으로 궁금한 부분들이 있어 코멘트 남깁니다~ 코멘트를 달아주셔도 되고 개인적으로 가볍게 알려줘도 되요~ approve 드려요~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
안녕하세요 에버!
코드 엄청 많이 작성해주셨네요. 짧은 기간동안 잘 구현하시느라 고생 많았어요.
오늘 설명 잘 해주셔서 코드 이해하는데 큰 어려움 없었습니다.
객체도 전반적으로 잘 분리해주셨네요.
그런데 지금 로그가 많이 찍히는 것 같아요. 실패한 상황 위주로만 남겨두면 좋을 것 같습니다.
감사합니다.
@Service | ||
public class FcmMessageCreator { | ||
|
||
private static FcmMessageCreator INSTANCE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
싱글턴 👍
return new AuthInfoDto(authMember, authToken); | ||
} | ||
|
||
private void checkFcmToken(MemberEntity member, String fcmToken) { | ||
if (!memberRepository.existsByIdAndFcmToken(member.getId(), fcmToken)) { | ||
log.info("토큰 갱신 사용자 id: {}", member.getId()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 로그는 빼는게 어떨까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
위에서 포케의 리뷰에 작성해둔 부분 참고해주세요 :-) 감사합니다
} | ||
|
||
public Map<String, String> getData() { | ||
data.forEach((key, value) -> log.info("{} : {}", key, value)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 로그도 빼는 건 어떨까요?
public AuthInfoDto kakaoLogin(KakaoLoginRequest request) { | ||
String loginId = authClient.getKakaoUserInfo(request.accessToken()); | ||
AuthProvider provider = AuthProvider.KAKAO; | ||
MemberEntity member = memberRepository.findByLoginId(loginId) | ||
.orElseGet(() -> signup(provider, loginId, request.fcmToken())); | ||
return login(member); | ||
return login(member, request.fcmToken()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이전 버전 API 를 사용하는 앱에 대응하기 위해서 fcmToken이 null일 때 처리 추가합시다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
위 방식을 통해 현재 DB 내 default 값("invalid" + UUID.randomUUID()
)으로 설정되도록 하였습니다!
public class FcmTopic { | ||
|
||
private static final String TOPIC_FORMAT_MEMBER = "member"; | ||
private static final String TOPIC_FORMAT_OFFERING_MEMBER = "member_of_offering_%d"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 부분도 회의 때 논한대로 participant_of_offering_%d 로 변경합시다!
return INSTANCE; | ||
} | ||
|
||
public Message createMessage(FcmToken token, FcmData data) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
static 메서드로 쓰는 건 어떨까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
협의 후 FcmMessageCreator를 빈으로 등록하도록 하였습니다!
public String participate(OfferingMemberEntity offeringMember) { | ||
Message message = participationMessageManager.messageWhenParticipate(offeringMember); | ||
FcmTopic topic = FcmTopic.offeringMemberTopic(offeringMember.getOffering()); | ||
notificationSubscriber.subscribe(offeringMember.getMember(), topic); | ||
return notificationSender.send(message); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
순서가 아래처럼 되면 더 좋을 거 같습니다!
FcmTopic topic = FcmTopic.offeringMemberTopic(offeringMember.getOffering());
notificationSubscriber.subscribe(offeringMember.getMember(), topic);
Message message = participationMessageManager.messageWhenParticipate(offeringMember);
return notificationSender.send(message);
또한, notificationSender.send(message)의 성공값이 무엇인지 궁금합니다!
FcmNotificationSerivice가 해당 값을 응답해야 하는 이유를 더 듣고 싶습니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
첫번째 의견 반영하도록 하겠습니다!
추가로, notificationSender.send(message)
의 성공값은 fcm서버가 설정한 messageId입니다. 테스트를 통해 알림 전송이 잘 되었는지 확인하고 싶어 응답값을 설정했어요.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
협의 후 Service에서는 messageId를 반환하지 않도록 변경하였습니다!
@@ -61,7 +61,7 @@ void should_sendNotificationsToFcm() { | |||
|
|||
// when | |||
BatchResponse batchResponse = notificationService.saveComment(comment, | |||
List.of(proposerOfferingMember, participant1OfferingMember, participant2OfferingMember)); | |||
List.of(participant1OfferingMember, participant2OfferingMember)); | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 테스트 클래스 이름을 FcmNotificationServiceTest로 하지 않고 FcmNotificationTest로 하신 이유가 따로 있었나요??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
따로 없습니다! 변경하겠습니다 :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
고생하셨어요!!!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
최고존엄 에버
* feat: Member fcmToken 필드 추가 및 로그인 필드 추가 * feat: 공모 참여 시 총대에게 알림 전송 * feat: 공모 참여 취소 시 총대에게 알림 전송 * feat: 댓글방 상태 변경 시 참여자에게 알림 전송 * feat: 댓글 작성 시 작성자 제외 참여자에게 알림 전송 * refactor: FcmMessageManager 메시지 생성 로직 추출 * chore: FCM key 관리 * style: .gitignore EOF * chore: FCM key path 관리 * chore: dev CI/CD script 수정 * chore: dev CI/CD script 트리거 수정 * chore: dev CI/CD script 트리거 수정 * chore: dev CI/CD script 수정 * chore: fcm key 빈 파일 생성 * chore: properties 파일 수정 * chore: yml 파일 수정 * chore: dev CI/CD 파일 수정 * chore: test fcm key 파일 추가 * chore: dev CI/CD 스크립트 수정 * chore: dev CI/CD 스크립트 수정 * chore: dev CI/CD 스크립트 수정 * chore: dev CI/CD 스크립트 수정 * chore: dev CI/CD 스크립트 수정 * chore: dev CI/CD 스크립트 수정 * chore: dev CI/CD 스크립트 수정 * chore: dev CI/CD 스크립트 수정 * feat: notification 방식에서 data 방식으로 변경 * feat: 전달 데이터에 offering_id 추가 * chore: 파일 읽는 방식 변경 * fix: 토픽 이름 변경 * refactor: QA 위한 로그 * refactor: 로그인 시 fcmToken 비교 후 다를 경우 갱신 * refactor: 거래 상태 알림 문구 변경 * feat: 안드로이드 리다이렉트를 위한 필드 추가 * refactor: 필드명 변경 및 패키지 정리 * refactor: FcmTopic 구현 * refactor: 토큰 갱신 여부 로깅 * feat: 공모 작성 시 본인 제외 broadcasting * refactor: 공모 작성 시 본인 제외 broadcasting 주제 구독 방식 * refactor: FcmCondition, FcmTopic 도메인 추출 * refactor: notification 상수 정리 * refactor: 로그인 요청시 fcmToken 필드 비어있는지 검증 * refactor: offering_member 토픽 이름 변경 * feat: 유효하지 않은 토큰을 가진 사용자에 대한 예외 처리 * refactor: 개발 환경과 로컬 환경 분리 * chore: CI/CD 스크립트 정리 * refactor: notificationService에서 repository 의존성 제거 * refactor: MessageManager 계층 도메인에서 서비스로 이동 * chore: dev CI/CD 스크립트 트리거 수정 * fix: 오래된 토큰을 가진 사용자에 대한 알림 전송 무시 * chore: dev CI/CD 트리거 변경 * refactor: yml 중복 필드 제거 * refactor: 불필요한 어노테이션 제거 * refactor: 민감 정보 로깅 제거 * refactor: fcmToken null 처리 * refactor: 방상태 변경 시 토픽 변경 * refactor: FcmMessageCreator 빈 등록 * refactor: FcmNotificationService 코드 순서 변경 * refactor: NotificationService 반환값 변경 * test: 리팩터링 변경 사항 반영 * chore: dev CI/CD 복구
📌 관련 이슈
close #587
✨ 작업 내용
노션 링크 첨부합니다.
https://silent-apparatus-578.notion.site/FCM-7060b9ac40ea47a19dd8d811f2040c7a?pvs=4
📚 기타