diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/comment/AudioContentCommentRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/comment/AudioContentCommentRepository.kt index e581dd1..b49c209 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/comment/AudioContentCommentRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/comment/AudioContentCommentRepository.kt @@ -4,6 +4,7 @@ import com.querydsl.core.types.dsl.Expressions import com.querydsl.jpa.impl.JPAQueryFactory import kr.co.vividnext.sodalive.content.QAudioContent.audioContent import kr.co.vividnext.sodalive.content.comment.QAudioContentComment.audioContentComment +import kr.co.vividnext.sodalive.fcm.QPushToken.pushToken import kr.co.vividnext.sodalive.member.QMember.member import org.springframework.data.jpa.repository.JpaRepository import org.springframework.stereotype.Repository @@ -204,25 +205,27 @@ class AudioContentCommentQueryRepositoryImpl( queryFactory .select( QFindPushTokenByContentIdAndCommentParentIdMyMemberIdResponse( - member.pushToken.coalesce(""), - member.container + pushToken.token, + pushToken.deviceType ) ) .from(audioContentComment) .innerJoin(audioContentComment.audioContent, audioContent) .innerJoin(audioContentComment.member, member) + .innerJoin(pushToken).on(member.id.eq(pushToken.member.id)) .where(where) .fetch() } else { queryFactory .select( QFindPushTokenByContentIdAndCommentParentIdMyMemberIdResponse( - member.pushToken.coalesce(""), - member.container + pushToken.token, + pushToken.deviceType ) ) .from(audioContent) .innerJoin(audioContent.member, member) + .innerJoin(pushToken).on(member.id.eq(pushToken.member.id)) .where(where) .fetch() } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/member/CreatorAdminMemberService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/member/CreatorAdminMemberService.kt index 3e193e9..8ba6b00 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/member/CreatorAdminMemberService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/member/CreatorAdminMemberService.kt @@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.creator.admin.member import kr.co.vividnext.sodalive.common.ApiResponse import kr.co.vividnext.sodalive.common.SodaException +import kr.co.vividnext.sodalive.fcm.PushTokenService import kr.co.vividnext.sodalive.jwt.TokenProvider import kr.co.vividnext.sodalive.member.MemberRepository import kr.co.vividnext.sodalive.member.MemberRole @@ -25,6 +26,8 @@ class CreatorAdminMemberService( private val tokenProvider: TokenProvider, private val authenticationManagerBuilder: AuthenticationManagerBuilder, + private val pushTokenService: PushTokenService, + @Value("\${cloud.aws.cloud-front.host}") private val cloudFrontHost: String ) { @@ -44,6 +47,7 @@ class CreatorAdminMemberService( ?: throw SodaException("로그인 정보를 확인해주세요.") member.pushToken = null + pushTokenService.logout(memberId = memberId) val lock = getOrCreateLock(memberId = memberId) lock.write { diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/fcm/FcmService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/fcm/FcmService.kt index 7a51f63..b1b78fc 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/fcm/FcmService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/fcm/FcmService.kt @@ -14,7 +14,7 @@ import org.springframework.scheduling.annotation.Async import org.springframework.stereotype.Service @Service -class FcmService { +class FcmService(private val pushTokenService: PushTokenService) { private val logger = LoggerFactory.getLogger(this::class.java) @Async @@ -100,7 +100,8 @@ class FcmService { if (exception?.messagingErrorCode == MessagingErrorCode.UNREGISTERED) { logger.error("[FCM] ❌ UNREGISTERED → $token") - // 필요 시 DB에서 삭제 + // DB에서 삭제 + pushTokenService.unregisterInvalidToken(token) } else { logger.error("[FCM] ❌ 실패: $token / ${exception?.messagingErrorCode}") failedTokens.add(token) @@ -148,6 +149,8 @@ class FcmService { // "registration-token-not-registered" 예외 코드 확인 if (e.messagingErrorCode == MessagingErrorCode.UNREGISTERED) { logger.error("[FCM] ❌ 실패: 토큰이 등록되지 않음 (등록 해제됨) → 재시도 안함") + // DB에서 삭제 + pushTokenService.unregisterInvalidToken(token) return } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/fcm/PushToken.kt b/src/main/kotlin/kr/co/vividnext/sodalive/fcm/PushToken.kt new file mode 100644 index 0000000..f442b69 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/fcm/PushToken.kt @@ -0,0 +1,18 @@ +package kr.co.vividnext.sodalive.fcm + +import kr.co.vividnext.sodalive.common.BaseEntity +import kr.co.vividnext.sodalive.member.Member +import javax.persistence.Entity +import javax.persistence.FetchType +import javax.persistence.JoinColumn +import javax.persistence.ManyToOne + +@Entity +data class PushToken( + var token: String, + var deviceType: String +) : BaseEntity() { + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id", nullable = true) + var member: Member? = null +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/fcm/PushTokenRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/fcm/PushTokenRepository.kt new file mode 100644 index 0000000..6047a0f --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/fcm/PushTokenRepository.kt @@ -0,0 +1,30 @@ +package kr.co.vividnext.sodalive.fcm + +import com.querydsl.jpa.impl.JPAQueryFactory +import kr.co.vividnext.sodalive.fcm.QPushToken.pushToken +import org.springframework.data.jpa.repository.JpaRepository + +interface PushTokenRepository : JpaRepository, PushTokenQueryRepository + +interface PushTokenQueryRepository { + fun findByToken(token: String): PushToken? + fun findByMemberId(memberId: Long): List +} + +class PushTokenQueryRepositoryImpl( + private val queryFactory: JPAQueryFactory +) : PushTokenQueryRepository { + override fun findByToken(token: String): PushToken? { + return queryFactory + .selectFrom(pushToken) + .where(pushToken.token.eq(token)) + .fetchFirst() + } + + override fun findByMemberId(memberId: Long): List { + return queryFactory + .selectFrom(pushToken) + .where(pushToken.member.id.eq(memberId)) + .fetch() + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/fcm/PushTokenService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/fcm/PushTokenService.kt new file mode 100644 index 0000000..1de78b9 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/fcm/PushTokenService.kt @@ -0,0 +1,47 @@ +package kr.co.vividnext.sodalive.fcm + +import kr.co.vividnext.sodalive.member.MemberRepository +import org.springframework.data.repository.findByIdOrNull +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional + +@Service +class PushTokenService( + private val repository: PushTokenRepository, + private val memberRepository: MemberRepository +) { + @Transactional + fun registerToken(memberId: Long, token: String, deviceType: String) { + val member = memberRepository.findByIdOrNull(memberId) + + if (member != null) { + val existing = repository.findByToken(token) + if (existing != null) { + existing.member = member + existing.token = token + existing.deviceType = deviceType + } else { + val newToken = PushToken(token, deviceType) + newToken.member = member + repository.save(newToken) + } + } + } + + @Transactional + fun logout(memberId: Long) { + val tokens = repository.findByMemberId(memberId) + + for (token in tokens) { + token.member = null + } + } + + @Transactional + fun unregisterInvalidToken(token: String) { + val existing = repository.findByToken(token) + if (existing != null) { + repository.delete(existing) + } + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/member/MemberRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/member/MemberRepository.kt index c7826ba..62cc950 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/member/MemberRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/member/MemberRepository.kt @@ -3,6 +3,7 @@ package kr.co.vividnext.sodalive.member import com.querydsl.jpa.impl.JPAQueryFactory import kr.co.vividnext.sodalive.fcm.GetMessageRecipientPushTokenResponse import kr.co.vividnext.sodalive.fcm.QGetMessageRecipientPushTokenResponse +import kr.co.vividnext.sodalive.fcm.QPushToken.pushToken import kr.co.vividnext.sodalive.live.reservation.QLiveReservation.liveReservation import kr.co.vividnext.sodalive.live.room.QLiveRoom.liveRoom import kr.co.vividnext.sodalive.member.QMember.member @@ -26,7 +27,6 @@ interface MemberRepository : JpaRepository, MemberQueryRepository } interface MemberQueryRepository { - fun findByPushToken(pushToken: String): List fun findByNicknameAndOtherCondition(nickname: String, member: Member): List fun findCreatorByIdOrNull(memberId: Long): Member? fun getAllRecipientPushTokens(isAuth: Boolean?, container: String): List> @@ -74,13 +74,6 @@ class MemberQueryRepositoryImpl( @Value("\${cloud.aws.cloud-front.host}") private val cloudFrontHost: String ) : MemberQueryRepository { - override fun findByPushToken(pushToken: String): List { - return queryFactory - .selectFrom(member) - .where(member.pushToken.eq(pushToken)) - .fetch() - } - override fun findByNicknameAndOtherCondition(nickname: String, member: Member): List { var where = QMember.member.nickname.containsIgnoreCase(nickname) .and(QMember.member.id.ne(member.id)) @@ -111,8 +104,7 @@ class MemberQueryRepositoryImpl( override fun getAllRecipientPushTokens(isAuth: Boolean?, container: String): List> { var where = member.isActive.isTrue .and(member.email.notIn("admin@sodalive.net")) - .and(member.container.eq(container)) - .and(member.pushToken.isNotNull) + .and(pushToken.deviceType.eq(container)) if (isAuth != null) { where = if (isAuth) { @@ -123,8 +115,9 @@ class MemberQueryRepositoryImpl( } return queryFactory - .select(member.pushToken) + .select(pushToken.token) .from(member) + .innerJoin(pushToken).on(member.id.eq(pushToken.member.id)) .leftJoin(member.auth, auth) .where(where) .fetch() @@ -142,18 +135,18 @@ class MemberQueryRepositoryImpl( val creator = QMember.member var where = creatorFollowing.isActive.isTrue + .and(creatorFollowing.member.isActive.isTrue) .and(creatorFollowing.creator.id.eq(creatorId)) .and(creatorFollowing.member.notification.live.isTrue) - .and(creatorFollowing.member.container.eq(container)) .and(creatorFollowing.member.email.notIn("admin@sodalive.net")) .and( creatorFollowing.member.id.notIn( blockMemberRepository.getBlockedMemberIdList(creatorId) ) ) - .and(creatorFollowing.member.pushToken.isNotNull) .and(creatorFollowing.isNotify.isTrue) - .or(member.id.eq(4).and(member.pushToken.isNotNull)) + .and(pushToken.deviceType.eq(container)) + .or(member.id.eq(4)) if (isAuth) { where = where.and(auth.isNotNull) @@ -164,11 +157,12 @@ class MemberQueryRepositoryImpl( } return queryFactory - .select(creatorFollowing.member.pushToken) + .select(pushToken.token) .from(creatorFollowing) .innerJoin(creatorFollowing.creator, creator) .innerJoin(creatorFollowing.member, member) .innerJoin(creatorFollowing.member.notification, memberNotification) + .innerJoin(pushToken).on(creatorFollowing.member.id.eq(pushToken.member.id)) .leftJoin(creatorFollowing.member.auth, auth) .where(where) .fetch() @@ -187,18 +181,18 @@ class MemberQueryRepositoryImpl( val creator = QMember.member var where = creatorFollowing.isActive.isTrue + .and(creatorFollowing.member.isActive.isTrue) .and(creatorFollowing.creator.id.eq(creatorId)) .and(creatorFollowing.member.notification.live.isTrue) - .and(creatorFollowing.member.container.eq(container)) .and(creatorFollowing.member.email.notIn("admin@sodalive.net")) .and( creatorFollowing.member.id.notIn( blockMemberRepository.getBlockedMemberIdList(creatorId) ) ) - .and(creatorFollowing.member.pushToken.isNotNull) .and(creatorFollowing.isNotify.isTrue) - .or(creatorFollowing.member.id.eq(4).and(member.pushToken.isNotNull)) + .and(pushToken.deviceType.eq(container)) + .or(creatorFollowing.member.id.eq(4)) if (isAuth) { where = where.and(auth.isNotNull) @@ -209,36 +203,37 @@ class MemberQueryRepositoryImpl( } val followingMemberPushToken = queryFactory - .select(creatorFollowing.member.pushToken) + .select(pushToken.token) .from(creatorFollowing) .innerJoin(creatorFollowing.creator, creator) .innerJoin(creatorFollowing.member, member) .innerJoin(creatorFollowing.member.notification, memberNotification) + .innerJoin(pushToken).on(creatorFollowing.member.id.eq(pushToken.member.id)) .leftJoin(creatorFollowing.member.auth, auth) .where(where) .fetch() where = liveReservation.isActive.isTrue .and(liveReservation.member.notification.live.isTrue) - .and(liveReservation.member.container.eq(container)) .and(liveReservation.member.email.notIn("admin@sodalive.net")) - .and(liveReservation.member.pushToken.isNotNull) .and(liveReservation.room.id.eq(roomId)) .and( liveReservation.member.id.notIn( blockMemberRepository.getBlockedMemberIdList(creatorId) ) ) + .and(pushToken.deviceType.eq(container)) if (isAuth) { where = where.and(auth.isNotNull) } val reservationMemberPushToken = queryFactory - .select(liveReservation.member.pushToken) + .select(pushToken.token) .from(liveReservation) .innerJoin(liveReservation.member, member) .innerJoin(liveReservation.member.notification, memberNotification) + .innerJoin(pushToken).on(liveReservation.member.id.eq(pushToken.member.id)) .leftJoin(liveReservation.member.auth, auth) .where(where) .fetch() @@ -259,27 +254,27 @@ class MemberQueryRepositoryImpl( var where = creatorFollowing.isActive.isTrue .and(creatorFollowing.creator.id.eq(creatorId)) .and(creatorFollowing.member.email.notIn("admin@sodalive.net")) - .and(creatorFollowing.member.container.eq(container)) .and(creatorFollowing.member.notification.uploadContent.isTrue) .and( creatorFollowing.member.id.notIn( blockMemberRepository.getBlockedMemberIdList(creatorId) ) ) - .and(creatorFollowing.member.pushToken.isNotNull) .and(creatorFollowing.isNotify.isTrue) - .or(member.id.eq(4).and(member.pushToken.isNotNull)) + .and(pushToken.deviceType.eq(container)) + .or(member.id.eq(4)) if (isAuth) { where = where.and(auth.isNotNull) } return queryFactory - .select(creatorFollowing.member.pushToken) + .select(pushToken.token) .from(creatorFollowing) .innerJoin(creatorFollowing.creator, creator) .innerJoin(creatorFollowing.member, member) .innerJoin(member.notification, memberNotification) + .innerJoin(pushToken).on(creatorFollowing.member.id.eq(pushToken.member.id)) .leftJoin(member.auth, auth) .where(where) .fetch() @@ -291,16 +286,16 @@ class MemberQueryRepositoryImpl( return queryFactory .select( QGetMessageRecipientPushTokenResponse( - member.pushToken, - member.container + pushToken.token, + pushToken.deviceType ) ) .from(message) .innerJoin(message.recipient, member) .innerJoin(member.notification, memberNotification) + .innerJoin(pushToken).on(member.id.eq(pushToken.member.id)) .where( message.id.eq(messageId) - .and(member.pushToken.isNotNull) .and(memberNotification.message.isTrue) ) .fetchFirst() @@ -313,7 +308,6 @@ class MemberQueryRepositoryImpl( var where = member.isActive.isTrue .and(member.email.notIn("admin@sodalive.net")) .and(member.id.`in`(*recipients.toTypedArray())) - .and(member.pushToken.isNotNull) if (isAuth != null) { where = if (isAuth) { @@ -324,19 +318,21 @@ class MemberQueryRepositoryImpl( } val aosPushTokens = queryFactory - .select(member.pushToken) + .select(pushToken.token) .from(member) + .innerJoin(pushToken).on(member.id.eq(pushToken.member.id)) .leftJoin(member.auth, auth) - .where(where.and(member.container.eq("aos"))) + .where(where.and(pushToken.deviceType.eq("aos"))) .fetch() .toSet() .chunked(500) val iosPushTokens = queryFactory - .select(member.pushToken) + .select(pushToken.token) .from(member) + .innerJoin(pushToken).on(member.id.eq(pushToken.member.id)) .leftJoin(member.auth, auth) - .where(where.and(member.container.eq("ios"))) + .where(where.and(pushToken.deviceType.eq("ios"))) .fetch() .toSet() .chunked(500) @@ -373,6 +369,7 @@ class MemberQueryRepositoryImpl( val creator = QMember.member val where = creatorFollowing.isActive.isTrue + .and(creatorFollowing.member.isActive.isTrue) .and(creatorFollowing.creator.id.eq(creatorId)) .and(creatorFollowing.member.email.notIn("admin@sodalive.net")) .and( @@ -380,25 +377,26 @@ class MemberQueryRepositoryImpl( blockMemberRepository.getBlockedMemberIdList(creatorId) ) ) - .and(creatorFollowing.member.pushToken.isNotNull) .and(creatorFollowing.isNotify.isTrue) val aosPushTokens = queryFactory - .select(creatorFollowing.member.pushToken) + .select(pushToken.token) .from(creatorFollowing) .innerJoin(creatorFollowing.creator, creator) .innerJoin(creatorFollowing.member, member) - .where(where.and(member.container.eq("aos"))) + .innerJoin(pushToken).on(creatorFollowing.member.id.eq(pushToken.member.id)) + .where(where.and(pushToken.deviceType.eq("aos"))) .fetch() .toSet() .chunked(500) val iosPushTokens = queryFactory - .select(creatorFollowing.member.pushToken) + .select(pushToken.token) .from(creatorFollowing) .innerJoin(creatorFollowing.creator, creator) .innerJoin(creatorFollowing.member, member) - .where(where.and(member.container.eq("ios"))) + .innerJoin(pushToken).on(creatorFollowing.member.id.eq(pushToken.member.id)) + .where(where.and(pushToken.deviceType.eq("ios"))) .fetch() .toSet() .chunked(500) @@ -411,21 +409,22 @@ class MemberQueryRepositoryImpl( .and(liveReservation.isActive.isTrue) val aosPushTokens = queryFactory - .select(liveReservation.member.pushToken) + .select(pushToken.token) .from(liveReservation) .innerJoin(liveReservation.room, liveRoom) .innerJoin(liveReservation.member, member) - .where(where.and(member.container.eq("aos"))) + .innerJoin(pushToken).on(member.id.eq(pushToken.member.id)) + .where(where.and(pushToken.deviceType.eq("aos"))) .fetch() .toSet() .chunked(500) val iosPushTokens = queryFactory - .select(liveReservation.member.pushToken) + .select(pushToken.token) .from(liveReservation) .innerJoin(liveReservation.room, liveRoom) .innerJoin(liveReservation.member, member) - .where(where.and(member.container.eq("ios"))) + .where(where.and(pushToken.deviceType.eq("aos"))) .fetch() .toSet() .chunked(500) @@ -435,28 +434,29 @@ class MemberQueryRepositoryImpl( override fun getAuditionNoticeRecipientPushTokens(isAuth: Boolean): Map>> { var where = memberNotification.audition.isTrue - .and(member.pushToken.isNotNull) if (isAuth) { where = where.and(auth.isNotNull) } val aosPushTokens = queryFactory - .select(member.pushToken) + .select(pushToken.token) .from(member) + .innerJoin(pushToken).on(member.id.eq(pushToken.member.id)) .leftJoin(member.auth, auth) .leftJoin(memberNotification).on(memberNotification.member.id.eq(member.id)) - .where(where.and(member.container.eq("aos"))) + .where(where.and(pushToken.deviceType.eq("aos"))) .fetch() .toSet() .chunked(500) val iosPushTokens = queryFactory - .select(member.pushToken) + .select(pushToken.token) .from(member) + .innerJoin(pushToken).on(member.id.eq(pushToken.member.id)) .leftJoin(member.auth, auth) .leftJoin(memberNotification).on(memberNotification.member.id.eq(member.id)) - .where(where.and(member.container.eq("ios"))) + .where(where.and(pushToken.deviceType.eq("ios"))) .fetch() .toSet() .chunked(500) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/member/MemberService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/member/MemberService.kt index 5a4f0e3..09c8a21 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/member/MemberService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/member/MemberService.kt @@ -10,6 +10,7 @@ import kr.co.vividnext.sodalive.common.ApiResponse import kr.co.vividnext.sodalive.common.SodaException import kr.co.vividnext.sodalive.content.order.OrderService import kr.co.vividnext.sodalive.email.SendEmailService +import kr.co.vividnext.sodalive.fcm.PushTokenService import kr.co.vividnext.sodalive.jwt.TokenProvider import kr.co.vividnext.sodalive.live.reservation.LiveReservationRepository import kr.co.vividnext.sodalive.live.room.detail.GetRoomDetailUser @@ -82,6 +83,7 @@ class MemberService( private val orderService: OrderService, private val emailService: SendEmailService, + private val pushTokenService: PushTokenService, private val canPaymentService: CanPaymentService, private val nicknameGenerateService: NicknameGenerateService, private val memberNotificationService: MemberNotificationService, @@ -127,7 +129,6 @@ class MemberService( gender = Gender.NONE, container = request.container ) - member.pushToken = request.pushToken if (!request.marketingPid.isNullOrBlank()) { member.activePid = request.marketingPid @@ -137,6 +138,14 @@ class MemberService( repository.save(member) agreeTermsOfServiceAndPrivacyPolicy(member, stipulationTermsOfService, stipulationPrivacyPolicy) + if (request.pushToken != null) { + pushTokenService.registerToken( + memberId = member.id!!, + token = request.pushToken, + deviceType = request.container + ) + } + return SignUpResponse( memberId = member.id!!, marketingPid = request.marketingPid, @@ -235,16 +244,11 @@ class MemberService( @Transactional fun updatePushToken(memberId: Long, pushToken: String, container: String) { - val existsHavePushTokenMemberList = repository.findByPushToken(pushToken = pushToken) - for (existsHavePushTokenMember in existsHavePushTokenMemberList) { - existsHavePushTokenMember.pushToken = null - } - - val member = repository.findByIdOrNull(id = memberId) - ?: throw SodaException("로그인 정보를 확인해주세요.") - - member.pushToken = pushToken - member.container = container + pushTokenService.registerToken( + memberId = memberId, + token = pushToken, + deviceType = container + ) } @Transactional @@ -551,6 +555,7 @@ class MemberService( ?: throw SodaException("로그인 정보를 확인해주세요.") member.pushToken = null + pushTokenService.logout(memberId = memberId) val lock = getOrCreateLock(memberId = memberId) lock.write { @@ -568,6 +573,7 @@ class MemberService( ?: throw SodaException("로그인 정보를 확인해주세요.") member.pushToken = null + pushTokenService.logout(memberId = memberId) val lock = getOrCreateLock(memberId = memberId) lock.write { tokenRepository.deleteById(memberId) } @@ -824,7 +830,14 @@ class MemberService( provider = MemberProvider.GOOGLE, container = container ) - member.pushToken = pushToken + + if (pushToken != null) { + pushTokenService.registerToken( + memberId = member.id!!, + token = pushToken, + deviceType = container + ) + } if (!marketingPid.isNullOrBlank()) { member.activePid = marketingPid @@ -873,7 +886,14 @@ class MemberService( provider = MemberProvider.KAKAO, container = container ) - member.pushToken = pushToken + + if (pushToken != null) { + pushTokenService.registerToken( + memberId = member.id!!, + token = pushToken, + deviceType = container + ) + } if (!marketingPid.isNullOrBlank()) { member.activePid = marketingPid