Skip to content

feat: fcm V2추가#80

Merged
wlgusqkr merged 2 commits intodevfrom
feat/#79
Jan 30, 2026
Merged

feat: fcm V2추가#80
wlgusqkr merged 2 commits intodevfrom
feat/#79

Conversation

@wlgusqkr
Copy link
Contributor

@wlgusqkr wlgusqkr commented Jan 30, 2026

Related issue 🛠

어떤 변경사항이 있었나요?

  • 🐛 BugFix Something isn't working
  • 💻 CrossBrowsing Browser compatibility
  • 🌏 Deploy Deploy
  • 🎨 Design Markup & styling
  • 📃 Docs Documentation writing and editing (README.md, Swagger, etc.)
  • ✨ Feature Feature
  • 🔨 Refactor Code refactoring
  • ⚙️ Setting Development environment setup
  • ✅ Test Test related

Work Description ✏️

작업 내용을 작성해주세요.

  • 작업 내용

Uncompleted Tasks 😅

  • Task1

To Reviewers 📢

리뷰어가 알면 좋은 내용을 작성해주세요.

@wlgusqkr wlgusqkr linked an issue Jan 30, 2026 that may be closed by this pull request
@gemini-code-assist
Copy link

Summary of Changes

Hello @wlgusqkr, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 PR은 Firebase Cloud Messaging (FCM) 토큰 관리 시스템을 개선하고 확장합니다. 주요 변경 사항은 디바이스 모델 정보를 포함하는 새로운 FCM 토큰 업데이트 API (V2)를 도입한 것입니다. 또한, FCM 메시징 로직을 FirebaseMessagingClient로 분리하여 서비스의 테스트 용이성을 향상시키고, 알림 발송 실패 시 유효하지 않은 FCM 토큰을 자동으로 처리하는 기능을 강화했습니다. 이로써 푸시 알림 시스템의 안정성과 유지보수성이 증대될 것으로 기대됩니다.

Highlights

  • FCM 토큰 관리 개선: FCM_Token 엔티티의 토큰 업데이트 메서드 이름을 update에서 updateToken으로 변경하고, FCMServiceupdateFcmToken 로직을 개선하여 기존 토큰이 없으면 새로 생성하고, 다르면 업데이트하도록 변경했습니다.
  • FCM 토큰 업데이트 V2 추가: 디바이스 모델 정보를 함께 저장할 수 있는 updateFcmTokenV2 메서드와 이를 위한 새로운 DTO (FCMUpdateRequestV2) 및 REST API 엔드포인트 (PUT /fcm/v2)를 추가했습니다.
  • FirebaseMessaging 클라이언트 분리: FirebaseMessagingClient라는 새로운 컴포넌트를 도입하여 FirebaseMessaging.getInstance().sendEachForMulticast 호출을 캡슐화하고, FCMService에서 이 클라이언트를 주입받아 사용하도록 변경하여 테스트 용이성을 높였습니다.
  • FCM Repository 개선: FCMRepository의 deleteAllByFcmTokenIn 메서드에 @Modifying@Query 어노테이션을 추가하여 JPA의 벌크 삭제 기능을 명시적으로 사용하도록 변경했습니다.
  • FCM 서비스 테스트 추가: FCMServiceTest를 새로 추가하여 알림 발송 시 등록되지 않은(UNREGISTERED) 토큰을 자동으로 삭제하는 로직, 다른 에러 처리, 그리고 updateFcmTokenV2의 토큰 생성 및 업데이트 로직에 대한 포괄적인 단위 테스트를 작성했습니다.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

FCM V2 기능 추가와 관련된 변경 사항을 리뷰했습니다. 전반적으로 좋은 변경이라고 생각합니다.

  • FirebaseMessaging의 정적 호출을 FirebaseMessagingClient 컴포넌트로 분리하여 테스트 용이성을 높였습니다.
  • deleteAllByFcmTokenIn을 JPQL을 사용한 bulk delete로 변경하여 성능을 개선했습니다.
  • 기능 추가와 함께 꼼꼼한 테스트 코드를 작성해주셨습니다.

다만 FCMService의 토큰 업데이트 로직에 몇 가지 개선점을 발견하여 코멘트를 남겼습니다.

  • updateFcmToken 메소드에 토큰 값을 비교하는 로직 버그가 있어 수정이 필요합니다.
  • updateFcmTokenupdateFcmTokenV2 간에 코드 중복이 있어 리팩토링을 권장합니다.
  • 새로 추가된 updateFcmTokenV2 메소드는 사용자가 여러 기기를 사용할 경우를 대비한 설계 개선이 필요해 보입니다.

자세한 내용은 각 파일의 리뷰 코멘트를 참고해주세요.

Comment on lines 142 to 152
List<FCM_Token> FCM_Tokens = fcmRepository.findByUser(user);

fcmToken.update(SFcmToken);
if(FCM_Tokens.isEmpty()){
FCM_Token newToken = FCM_Token.create(user, requestToken, "unknown");
fcmRepository.save(newToken);
} else {
FCM_Token existingToken = FCM_Tokens.get(0);
if (!existingToken.equals(requestToken)) {
existingToken.updateToken(requestToken);
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

updateFcmToken 메소드에 몇 가지 개선점이 있습니다.

  1. [Critical] 149행의 !existingToken.equals(requestToken) 비교 로직에 버그가 있습니다. existingTokenFCM_Token 객체이고 requestTokenString이므로, Object.equals()는 항상 false를 반환합니다. 따라서 토큰이 갱신되어야 할 때 갱신되지 않습니다. existingToken.getFcmToken().equals(requestToken)으로 토큰 문자열 값을 직접 비교해야 합니다.

  2. [Medium] 142행의 FCM_Tokens 변수명은 Java 네이밍 컨벤션(camelCase)에 따라 fcmTokens로 수정하는 것이 좋습니다.

Suggested change
List<FCM_Token> FCM_Tokens = fcmRepository.findByUser(user);
fcmToken.update(SFcmToken);
if(FCM_Tokens.isEmpty()){
FCM_Token newToken = FCM_Token.create(user, requestToken, "unknown");
fcmRepository.save(newToken);
} else {
FCM_Token existingToken = FCM_Tokens.get(0);
if (!existingToken.equals(requestToken)) {
existingToken.updateToken(requestToken);
}
}
List<FCM_Token> fcmTokens = fcmRepository.findByUser(user);
if(fcmTokens.isEmpty()){
FCM_Token newToken = FCM_Token.create(user, requestToken, "unknown");
fcmRepository.save(newToken);
} else {
FCM_Token existingToken = fcmTokens.get(0);
if (!existingToken.getFcmToken().equals(requestToken)) {
existingToken.updateToken(requestToken);
}
}

Comment on lines +161 to +171
List<FCM_Token> fcmTokens = fcmRepository.findByUser(user);

if (fcmTokens.isEmpty()) {
FCM_Token newToken = FCM_Token.create(user, requestToken, model);
fcmRepository.save(newToken);
} else {
FCM_Token existingToken = fcmTokens.get(0);
if (!existingToken.getFcmToken().equals(requestToken)) {
existingToken.updateToken(requestToken);
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

현재 updateFcmTokenV2 메소드는 사용자가 여러 기기를 사용하는 경우를 올바르게 처리하지 못할 수 있습니다.
fcmRepository.findByUser(user)로 모든 토큰을 가져온 후, fcmTokens.get(0)으로 리스트의 첫 번째 토큰만 가져와서 업데이트하고 있습니다. 만약 사용자가 여러 기기(예: 아이폰, 아이패드)를 사용한다면, 이 로직은 임의의 기기 토큰을 갱신하게 되어 다른 기기의 푸시 알림이 끊길 수 있습니다.

또한, 기존 토큰이 존재할 경우 토큰 값만 업데이트하고 model 정보는 업데이트하지 않습니다. 사용자가 기기를 변경했을 때 model 정보가 갱신되지 않는 문제가 있습니다.

이 로직은 사용자가 단 하나의 기기만 사용한다고 가정하는 것으로 보입니다. 여러 기기 지원이 필요하다면 아래와 같은 방식으로 재설계하는 것을 고려해 보세요.

  • (user, model)을 기반으로 토큰을 찾아 업데이트하거나,
  • (user, fcmToken)으로 기존 토큰이 있는지 확인하여 없다면 새로 추가하는 로직

Comment on lines 137 to 172
@Transactional
public void updateFcmToken(String userUuid, String deviceSecret, String SFcmToken) {
public void updateFcmToken(String userUuid, String deviceSecret, String requestToken) {

User user = headerAuthValidator.validateAndGetUser(userUuid, deviceSecret);

FCM_Token fcmToken = fcmRepository.findByUserId(user.getId());
List<FCM_Token> FCM_Tokens = fcmRepository.findByUser(user);

fcmToken.update(SFcmToken);
if(FCM_Tokens.isEmpty()){
FCM_Token newToken = FCM_Token.create(user, requestToken, "unknown");
fcmRepository.save(newToken);
} else {
FCM_Token existingToken = FCM_Tokens.get(0);
if (!existingToken.equals(requestToken)) {
existingToken.updateToken(requestToken);
}
}

}

@Transactional
public void updateFcmTokenV2(String userUuid, String deviceSecret, String requestToken, String model) {

User user = headerAuthValidator.validateAndGetUser(userUuid, deviceSecret);

List<FCM_Token> fcmTokens = fcmRepository.findByUser(user);

if (fcmTokens.isEmpty()) {
FCM_Token newToken = FCM_Token.create(user, requestToken, model);
fcmRepository.save(newToken);
} else {
FCM_Token existingToken = fcmTokens.get(0);
if (!existingToken.getFcmToken().equals(requestToken)) {
existingToken.updateToken(requestToken);
}
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

updateFcmToken 메소드와 updateFcmTokenV2 메소드의 로직이 거의 동일하여 코드 중복이 발생하고 있습니다. model 파라미터를 받는 부분을 제외하면 로직이 같으므로, 하나의 private 메소드로 추출하여 중복을 제거하고 코드 유지보수성을 높이는 것을 권장합니다.

예시:

@Transactional
public void updateFcmToken(String userUuid, String deviceSecret, String requestToken) {
    User user = headerAuthValidator.validateAndGetUser(userUuid, deviceSecret);
    upsertFcmToken(user, requestToken, "unknown");
}

@Transactional
public void updateFcmTokenV2(String userUuid, String deviceSecret, String requestToken, String model) {
    User user = headerAuthValidator.validateAndGetUser(userUuid, deviceSecret);
    upsertFcmToken(user, requestToken, model);
}

private void upsertFcmToken(User user, String requestToken, String model) {
    // 현재 updateFcmTokenV2의 로직을 여기에 구현
    List<FCM_Token> fcmTokens = fcmRepository.findByUser(user);

    if (fcmTokens.isEmpty()) {
        FCM_Token newToken = FCM_Token.create(user, requestToken, model);
        fcmRepository.save(newToken);
    } else {
        FCM_Token existingToken = fcmTokens.get(0);
        if (!existingToken.getFcmToken().equals(requestToken)) {
            existingToken.updateToken(requestToken);
        }
    }
}

@github-actions
Copy link

github-actions bot commented Jan 30, 2026

Test Results

24 tests   24 ✅  3s ⏱️
10 suites   0 💤
10 files     0 ❌

Results for commit 58b2f19.

♻️ This comment has been updated with latest results.

@wlgusqkr wlgusqkr self-assigned this Jan 30, 2026
@wlgusqkr wlgusqkr merged commit f52689d into dev Jan 30, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

✨ [Feat] FCM Update 개선

1 participant