From 8c18f1ec823ef7cfc4c7646a6a2873461b7d2996 Mon Sep 17 00:00:00 2001 From: GoGradually Date: Sat, 27 Dec 2025 15:08:30 +0900 Subject: [PATCH 01/13] =?UTF-8?q?build:=20Firebase=20Admin=20SDK=EC=97=90?= =?UTF-8?q?=EC=84=9C=20commons-logging=20=EB=AA=A8=EB=93=88=20=EC=A0=9C?= =?UTF-8?q?=EC=99=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5379312..cc423ad 100644 --- a/build.gradle +++ b/build.gradle @@ -40,7 +40,9 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-actuator' // Firebase Admin SDK - implementation 'com.google.firebase:firebase-admin:9.7.0' + implementation("com.google.firebase:firebase-admin:9.7.0") { + exclude group: "commons-logging", module: "commons-logging" + } // Spring Security implementation 'org.springframework.boot:spring-boot-starter-security' From 55048b4088e2f261145435f668435a1889fc0dfd Mon Sep 17 00:00:00 2001 From: GoGradually Date: Sat, 27 Dec 2025 17:17:33 +0900 Subject: [PATCH 02/13] =?UTF-8?q?chore:=20VAPID=20=EA=B3=B5=EA=B0=9C=20?= =?UTF-8?q?=ED=82=A4=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 13b2f52..5fca049 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -2,7 +2,7 @@ vapid: keys: - public: BA7L1jqFAyxo_KZZZBkUeqC1uY6iSP1NvyNVqV-L_dmqEnHA__5cNs87WJ5QDiH8UC3hgLQu99mbbxlwZZf7J4U + public: BF8QQIULasLr94n0l0xbv43yZeNICudM5lpQN08VYn2g5VjBPU0wM98HypyRmEb-y0ARRsiZ_wcgSMIC-nq-x20 private: ${VAPID_PRIVATE_KEY} From eac16fcc4fd37b08f9433a099a933d0324c3b5c2 Mon Sep 17 00:00:00 2001 From: GoGradually Date: Sat, 27 Dec 2025 17:17:52 +0900 Subject: [PATCH 03/13] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=EA=B8=B0=EA=B8=B0=EB=B3=84=20=ED=91=B8=EC=8B=9C=20=EC=95=8C?= =?UTF-8?q?=EB=A6=BC=20=EA=B5=AC=EB=8F=85=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pinitnotification/application/push/PushService.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/pinitnotification/application/push/PushService.java b/src/main/java/me/pinitnotification/application/push/PushService.java index 18a02b3..284ea16 100644 --- a/src/main/java/me/pinitnotification/application/push/PushService.java +++ b/src/main/java/me/pinitnotification/application/push/PushService.java @@ -4,7 +4,11 @@ public interface PushService { String getVapidPublicKey(); - void subscribe(Long memberId, String token); - void unsubscribe(Long memberId, String token); + + void subscribe(Long memberId, String deviceId, String token); + + void unsubscribe(Long memberId, String deviceId, String token); void sendPushMessage(String token, Notification notification); + + boolean isSubscribed(Long memberId, String deviceId); } From 4e30ff2e0f400e9241cd07827826f0aa3be15d76 Mon Sep 17 00:00:00 2001 From: GoGradually Date: Sat, 27 Dec 2025 17:18:02 +0900 Subject: [PATCH 04/13] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=EA=B8=B0=EA=B8=B0=EB=B3=84=20=ED=91=B8=EC=8B=9C=20=EA=B5=AC?= =?UTF-8?q?=EB=8F=85=20=EA=B4=80=EB=A6=AC=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/push/PushSubscription.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/main/java/me/pinitnotification/domain/push/PushSubscription.java b/src/main/java/me/pinitnotification/domain/push/PushSubscription.java index 4097b17..3864891 100644 --- a/src/main/java/me/pinitnotification/domain/push/PushSubscription.java +++ b/src/main/java/me/pinitnotification/domain/push/PushSubscription.java @@ -2,16 +2,21 @@ import jakarta.persistence.*; import lombok.Getter; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import java.time.Instant; @Entity @Table( uniqueConstraints = { @UniqueConstraint( - name = "uk_token_memberId", - columnNames = {"member_id", "token"} + name = "uk_deviceId_memberId", + columnNames = {"member_id", "device_id"} ) } ) +@EntityListeners(AuditingEntityListener.class) @Getter public class PushSubscription { @Id @@ -20,11 +25,18 @@ public class PushSubscription { @Column(name="token", nullable = false) private String token; + @Column(name = "device_id", nullable = false) + private String deviceId; @Column(name="member_id", nullable = false) private Long memberId; + @LastModifiedDate + @Column(name = "modified_at", nullable = false) + private Instant modifiedAt; protected PushSubscription() {} - public PushSubscription(Long memberId, String token) { + + public PushSubscription(Long memberId, String deviceId, String token) { this.memberId = memberId; + this.deviceId = deviceId; this.token = token; } } From bee13e9121b828fdc783af779da7759ee0e86e48 Mon Sep 17 00:00:00 2001 From: GoGradually Date: Sat, 27 Dec 2025 17:18:44 +0900 Subject: [PATCH 05/13] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=EA=B8=B0=EA=B8=B0=EB=B3=84=20=ED=91=B8=EC=8B=9C=20=EA=B5=AC?= =?UTF-8?q?=EB=8F=85=20=EC=A0=95=EB=B3=B4=EC=97=90=20=EA=B8=B0=EA=B8=B0=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notification/NotificationDispatchSchedulerTest.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/test/java/me/pinitnotification/application/notification/NotificationDispatchSchedulerTest.java b/src/test/java/me/pinitnotification/application/notification/NotificationDispatchSchedulerTest.java index addfac0..278ae35 100644 --- a/src/test/java/me/pinitnotification/application/notification/NotificationDispatchSchedulerTest.java +++ b/src/test/java/me/pinitnotification/application/notification/NotificationDispatchSchedulerTest.java @@ -16,12 +16,7 @@ import java.time.ZoneOffset; import java.util.List; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.anyString; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) class NotificationDispatchSchedulerTest { @@ -49,7 +44,7 @@ void dispatchDueNotifications_sendsAndDeletesPastNotifications() { when(notificationRepository.findAll()).thenReturn(List.of(past, future)); when(pushSubscriptionRepository.findAllByMemberId(1L)) - .thenReturn(List.of(new PushSubscription(1L, "token-1"), new PushSubscription(1L, "token-2"))); + .thenReturn(List.of(new PushSubscription(1L, "device-1", "token-1"), new PushSubscription(1L, "device-2", "token-2"))); scheduler.dispatchDueNotifications(); From e5162d9c155dd386549e80aad7c8b180ab05858b Mon Sep 17 00:00:00 2001 From: GoGradually Date: Sat, 27 Dec 2025 17:18:52 +0900 Subject: [PATCH 06/13] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=EA=B8=B0=EA=B8=B0=EB=B3=84=20=ED=91=B8=EC=8B=9C=20=EA=B5=AC?= =?UTF-8?q?=EB=8F=85=20=EA=B4=80=EB=A6=AC=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/push/PushSubscriptionRepository.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/me/pinitnotification/domain/push/PushSubscriptionRepository.java b/src/main/java/me/pinitnotification/domain/push/PushSubscriptionRepository.java index 9e27446..8ff593c 100644 --- a/src/main/java/me/pinitnotification/domain/push/PushSubscriptionRepository.java +++ b/src/main/java/me/pinitnotification/domain/push/PushSubscriptionRepository.java @@ -3,9 +3,14 @@ import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; +import java.util.Optional; public interface PushSubscriptionRepository extends JpaRepository { + Optional findByMemberIdAndDeviceId(Long memberId, String deviceId); + List findAllByMemberId(Long memberId); void deleteByToken(String token); + + void deleteByMemberIdAndDeviceId(Long memberId, String deviceId); } From 93fa6078799656c7131bcdba2912a8eb7f119519 Mon Sep 17 00:00:00 2001 From: GoGradually Date: Sat, 27 Dec 2025 17:19:03 +0900 Subject: [PATCH 07/13] =?UTF-8?q?feat:=20JPA=20=EA=B0=90=EC=82=AC=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=ED=99=9C=EC=84=B1=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/me/pinitnotification/PinitNotificationApplication.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/me/pinitnotification/PinitNotificationApplication.java b/src/main/java/me/pinitnotification/PinitNotificationApplication.java index e4f9178..24c950b 100644 --- a/src/main/java/me/pinitnotification/PinitNotificationApplication.java +++ b/src/main/java/me/pinitnotification/PinitNotificationApplication.java @@ -2,10 +2,12 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication @EnableScheduling +@EnableJpaAuditing public class PinitNotificationApplication { public static void main(String[] args) { From 759322de4e1757dd15ee9769ab513bae2e224aac Mon Sep 17 00:00:00 2001 From: GoGradually Date: Sat, 27 Dec 2025 17:19:17 +0900 Subject: [PATCH 08/13] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=EA=B8=B0=EA=B8=B0=EB=B3=84=20=ED=91=B8=EC=8B=9C=20=EA=B5=AC?= =?UTF-8?q?=EB=8F=85=20=EA=B8=B0=EB=8A=A5=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infrastructure/fcm/FcmService.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/me/pinitnotification/infrastructure/fcm/FcmService.java b/src/main/java/me/pinitnotification/infrastructure/fcm/FcmService.java index 54d9b9b..9e42265 100644 --- a/src/main/java/me/pinitnotification/infrastructure/fcm/FcmService.java +++ b/src/main/java/me/pinitnotification/infrastructure/fcm/FcmService.java @@ -44,6 +44,11 @@ public void sendPushMessage(String token, Notification notification) { } } + @Override + public boolean isSubscribed(Long memberId, String deviceId) { + return pushSubscriptionRepository.findByMemberIdAndDeviceId(memberId, deviceId).isPresent(); + } + @Override public String getVapidPublicKey() { return vapidPublicKey; @@ -51,13 +56,13 @@ public String getVapidPublicKey() { @Override @Transactional - public void subscribe(Long memberId, String token) { - pushSubscriptionRepository.save(new PushSubscription(memberId, token)); + public void subscribe(Long memberId, String deviceId, String token) { + pushSubscriptionRepository.save(new PushSubscription(memberId, deviceId, token)); } @Override @Transactional - public void unsubscribe(Long memberId, String token) { - pushSubscriptionRepository.delete(new PushSubscription(memberId, token)); + public void unsubscribe(Long memberId, String deviceId, String token) { + pushSubscriptionRepository.deleteByMemberIdAndDeviceId(memberId, deviceId); } } From c5f8d8b8634749652c727444882f55aa8c3a9e62 Mon Sep 17 00:00:00 2001 From: GoGradually Date: Sat, 27 Dec 2025 17:19:21 +0900 Subject: [PATCH 09/13] =?UTF-8?q?feat:=20=ED=91=B8=EC=8B=9C=20=ED=86=A0?= =?UTF-8?q?=ED=81=B0=20=EC=9A=94=EC=B2=AD=EC=97=90=20=EB=94=94=EB=B0=94?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EC=8B=9D=EB=B3=84=EC=9E=90=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../interfaces/notification/dto/PushTokenRequest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/me/pinitnotification/interfaces/notification/dto/PushTokenRequest.java b/src/main/java/me/pinitnotification/interfaces/notification/dto/PushTokenRequest.java index 7ff8f97..082fd83 100644 --- a/src/main/java/me/pinitnotification/interfaces/notification/dto/PushTokenRequest.java +++ b/src/main/java/me/pinitnotification/interfaces/notification/dto/PushTokenRequest.java @@ -4,6 +4,8 @@ @Schema(description = "푸시 토큰 요청 바디") public record PushTokenRequest( + @Schema(description = "사용자의 디바이스 식별자. UUID 형식으로 제공됩니다.", example = "123e4567-e89b-12d3-a456-426614174000") + String deviceId, @Schema(description = "클라이언트에서 발급받은 FCM 푸시 토큰", example = "fcm-token-example") String token ) { From 3ae6c8c2d6c27f16bcc412ecc18e892e5aff0b48 Mon Sep 17 00:00:00 2001 From: GoGradually Date: Sat, 27 Dec 2025 17:19:24 +0900 Subject: [PATCH 10/13] =?UTF-8?q?feat:=20=ED=91=B8=EC=8B=9C=20=EA=B5=AC?= =?UTF-8?q?=EB=8F=85=20=EC=83=81=ED=83=9C=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EA=B5=AC=EB=8F=85?= =?UTF-8?q?=20=EB=93=B1=EB=A1=9D/=ED=95=B4=EC=A0=9C=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PushNotificationController.java | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/main/java/me/pinitnotification/interfaces/notification/PushNotificationController.java b/src/main/java/me/pinitnotification/interfaces/notification/PushNotificationController.java index 7ca8caf..4b4e461 100644 --- a/src/main/java/me/pinitnotification/interfaces/notification/PushNotificationController.java +++ b/src/main/java/me/pinitnotification/interfaces/notification/PushNotificationController.java @@ -1,7 +1,5 @@ package me.pinitnotification.interfaces.notification; -import me.pinitnotification.application.push.PushService; -import me.pinitnotification.domain.member.MemberId; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Content; @@ -9,12 +7,10 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; +import me.pinitnotification.application.push.PushService; +import me.pinitnotification.domain.member.MemberId; import me.pinitnotification.interfaces.notification.dto.PushTokenRequest; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/push") @@ -39,6 +35,21 @@ public String getVapidPublicKey() { return pushService.getVapidPublicKey(); } + @GetMapping("/subscribed") + @Operation( + summary = "푸시 구독 상태 조회", + description = "인증된 회원이 푸시 알림을 구독 중인지 여부를 반환합니다." + ) + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "구독 상태 조회 완료", + content = @Content(mediaType = "text/plain", schema = @Schema(implementation = Boolean.class))) + }) + public boolean isSubscribed( + @MemberId Long memberId, + @RequestParam String deviceId) { + return pushService.isSubscribed(memberId, deviceId); + } + @PostMapping("/subscribe") @Operation( summary = "푸시 토큰 구독 등록", @@ -51,7 +62,7 @@ public String getVapidPublicKey() { public void subscribe( @Parameter(hidden = true) @MemberId Long memberId, @RequestBody PushTokenRequest request) { - pushService.subscribe(memberId, request.token()); + pushService.subscribe(memberId, request.deviceId(), request.token()); } @PostMapping("/unsubscribe") @@ -66,7 +77,7 @@ public void subscribe( public void unsubscribe( @Parameter(hidden = true) @MemberId Long memberId, @RequestBody PushTokenRequest request) { - pushService.unsubscribe(memberId, request.token()); + pushService.unsubscribe(memberId, request.deviceId(), request.token()); } From 269fd8cf291913912c50a6cd6a9171c2e17bb269 Mon Sep 17 00:00:00 2001 From: GoGradually Date: Sat, 27 Dec 2025 17:36:31 +0900 Subject: [PATCH 11/13] =?UTF-8?q?feat:=20PushSubscription=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=EC=9D=98=20=ED=95=84=EB=93=9C=20=EC=88=9C?= =?UTF-8?q?=EC=84=9C=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20=ED=86=A0=ED=81=B0?= =?UTF-8?q?=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/push/PushSubscription.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/java/me/pinitnotification/domain/push/PushSubscription.java b/src/main/java/me/pinitnotification/domain/push/PushSubscription.java index 3864891..3d0353b 100644 --- a/src/main/java/me/pinitnotification/domain/push/PushSubscription.java +++ b/src/main/java/me/pinitnotification/domain/push/PushSubscription.java @@ -23,12 +23,12 @@ public class PushSubscription { @GeneratedValue private Long id; - @Column(name="token", nullable = false) - private String token; + @Column(name = "member_id", nullable = false) + private Long memberId; @Column(name = "device_id", nullable = false) private String deviceId; - @Column(name="member_id", nullable = false) - private Long memberId; + @Column(name = "token", nullable = false) + private String token; @LastModifiedDate @Column(name = "modified_at", nullable = false) private Instant modifiedAt; @@ -39,4 +39,11 @@ public PushSubscription(Long memberId, String deviceId, String token) { this.deviceId = deviceId; this.token = token; } + + public void updateToken(String token) { + if (this.modifiedAt.isAfter(Instant.now())) { + return; + } + this.token = token; + } } From b3b93aa83e3fa6b221a40a2641ce28027054543d Mon Sep 17 00:00:00 2001 From: GoGradually Date: Sat, 27 Dec 2025 17:36:37 +0900 Subject: [PATCH 12/13] =?UTF-8?q?feat:=20isSubscribed=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=EC=9D=98=20memberId=20=ED=8C=8C=EB=9D=BC=EB=AF=B8?= =?UTF-8?q?=ED=84=B0=EC=97=90=20=EC=88=A8=EA=B9=80=20=EC=98=B5=EC=85=98=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../interfaces/notification/PushNotificationController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/pinitnotification/interfaces/notification/PushNotificationController.java b/src/main/java/me/pinitnotification/interfaces/notification/PushNotificationController.java index 4b4e461..a383d4e 100644 --- a/src/main/java/me/pinitnotification/interfaces/notification/PushNotificationController.java +++ b/src/main/java/me/pinitnotification/interfaces/notification/PushNotificationController.java @@ -45,7 +45,7 @@ public String getVapidPublicKey() { content = @Content(mediaType = "text/plain", schema = @Schema(implementation = Boolean.class))) }) public boolean isSubscribed( - @MemberId Long memberId, + @Parameter(hidden = true) @MemberId Long memberId, @RequestParam String deviceId) { return pushService.isSubscribed(memberId, deviceId); } From 9e3726119ec364d3de9d18927be8842f465af6fd Mon Sep 17 00:00:00 2001 From: GoGradually Date: Sat, 27 Dec 2025 17:36:40 +0900 Subject: [PATCH 13/13] =?UTF-8?q?feat:=20=EA=B5=AC=EB=8F=85=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=EC=97=90=EC=84=9C=20=EA=B8=B0=EC=A1=B4=20?= =?UTF-8?q?=EA=B5=AC=EB=8F=85=EC=9D=98=20=ED=86=A0=ED=81=B0=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infrastructure/fcm/FcmService.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/pinitnotification/infrastructure/fcm/FcmService.java b/src/main/java/me/pinitnotification/infrastructure/fcm/FcmService.java index 9e42265..6b2fcab 100644 --- a/src/main/java/me/pinitnotification/infrastructure/fcm/FcmService.java +++ b/src/main/java/me/pinitnotification/infrastructure/fcm/FcmService.java @@ -13,6 +13,8 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.Optional; + @Slf4j @Service public class FcmService implements PushService { @@ -57,7 +59,13 @@ public String getVapidPublicKey() { @Override @Transactional public void subscribe(Long memberId, String deviceId, String token) { - pushSubscriptionRepository.save(new PushSubscription(memberId, deviceId, token)); + Optional byMemberIdAndDeviceId = pushSubscriptionRepository.findByMemberIdAndDeviceId(memberId, deviceId); + if (byMemberIdAndDeviceId.isPresent()) { + PushSubscription existingSubscription = byMemberIdAndDeviceId.get(); + existingSubscription.updateToken(token); + } else { + pushSubscriptionRepository.save(new PushSubscription(memberId, deviceId, token)); + } } @Override