diff --git a/casper-user/src/main/kotlin/hs/kr/entrydsm/user/domain/user/adapter/out/persistence/UserPersistenceAdapter.kt b/casper-user/src/main/kotlin/hs/kr/entrydsm/user/domain/user/adapter/out/persistence/UserPersistenceAdapter.kt index 0a5602b..061089c 100644 --- a/casper-user/src/main/kotlin/hs/kr/entrydsm/user/domain/user/adapter/out/persistence/UserPersistenceAdapter.kt +++ b/casper-user/src/main/kotlin/hs/kr/entrydsm/user/domain/user/adapter/out/persistence/UserPersistenceAdapter.kt @@ -36,6 +36,11 @@ class UserPersistenceAdapter( ?.let { userMapper.toModel(it) } } + override fun findByReceiptCode(receiptCode: Long): User? { + return userRepository.findByReceiptCode(receiptCode) + ?.let { userMapper.toModel(it) } + } + /** * 전화번호로 사용자를 조회합니다. * 전화번호를 암호화하여 데이터베이스에서 조회합니다. diff --git a/casper-user/src/main/kotlin/hs/kr/entrydsm/user/domain/user/adapter/out/persistence/repository/UserRepository.kt b/casper-user/src/main/kotlin/hs/kr/entrydsm/user/domain/user/adapter/out/persistence/repository/UserRepository.kt index 6a0f8d3..978cc55 100644 --- a/casper-user/src/main/kotlin/hs/kr/entrydsm/user/domain/user/adapter/out/persistence/repository/UserRepository.kt +++ b/casper-user/src/main/kotlin/hs/kr/entrydsm/user/domain/user/adapter/out/persistence/repository/UserRepository.kt @@ -40,4 +40,6 @@ interface UserRepository : JpaRepository { * @return 삭제 대상 사용자 엔티티 목록 */ fun findAllByActiveFalseAndWithdrawalAtBefore(cutoffDate: LocalDateTime): List + + fun findByReceiptCode(receiptCode: Long): UserJpaEntity? } diff --git a/casper-user/src/main/kotlin/hs/kr/entrydsm/user/domain/user/application/port/in/DeleteReceiptCodeUseCase.kt b/casper-user/src/main/kotlin/hs/kr/entrydsm/user/domain/user/application/port/in/DeleteReceiptCodeUseCase.kt new file mode 100644 index 0000000..d99c07e --- /dev/null +++ b/casper-user/src/main/kotlin/hs/kr/entrydsm/user/domain/user/application/port/in/DeleteReceiptCodeUseCase.kt @@ -0,0 +1,5 @@ +package hs.kr.entrydsm.user.domain.user.application.port.`in` + +interface DeleteReceiptCodeUseCase { + fun deleteReceiptCode(receiptCode: Long) +} \ No newline at end of file diff --git a/casper-user/src/main/kotlin/hs/kr/entrydsm/user/domain/user/application/port/out/QueryUserPort.kt b/casper-user/src/main/kotlin/hs/kr/entrydsm/user/domain/user/application/port/out/QueryUserPort.kt index 04bfc35..68496d9 100644 --- a/casper-user/src/main/kotlin/hs/kr/entrydsm/user/domain/user/application/port/out/QueryUserPort.kt +++ b/casper-user/src/main/kotlin/hs/kr/entrydsm/user/domain/user/application/port/out/QueryUserPort.kt @@ -31,4 +31,6 @@ interface QueryUserPort { * @return 사용자 존재 여부 */ fun existsByPhoneNumber(phoneNumber: String): Boolean + + fun findByReceiptCode(receiptCode: Long): User? } diff --git a/casper-user/src/main/kotlin/hs/kr/entrydsm/user/domain/user/application/service/DeleteReceiptCodeService.kt b/casper-user/src/main/kotlin/hs/kr/entrydsm/user/domain/user/application/service/DeleteReceiptCodeService.kt new file mode 100644 index 0000000..0afa58f --- /dev/null +++ b/casper-user/src/main/kotlin/hs/kr/entrydsm/user/domain/user/application/service/DeleteReceiptCodeService.kt @@ -0,0 +1,62 @@ +package hs.kr.entrydsm.user.domain.user.application.service + +import hs.kr.entrydsm.user.domain.user.application.port.`in`.DeleteReceiptCodeUseCase +import hs.kr.entrydsm.user.domain.user.application.port.out.QueryUserPort +import hs.kr.entrydsm.user.domain.user.application.port.out.SaveUserPort +import hs.kr.entrydsm.user.domain.user.exception.UserNotFoundException +import jakarta.transaction.Transactional +import org.springframework.stereotype.Service + +@Service +class DeleteReceiptCodeService( + private val queryUserPort: QueryUserPort, + private val saveUserPort: SaveUserPort, +) : DeleteReceiptCodeUseCase { + + @Transactional + override fun deleteReceiptCode(receiptCode: Long) { + val user = queryUserPort.findByReceiptCode(receiptCode) + ?: throw UserNotFoundException + + val updatedUser = user.copy(receiptCode = null) + saveUserPort.save(updatedUser) + +// registerAfterCommitCallback(receiptCode) +// try { +// val user = queryUserPort.findByReceiptCode(receiptCode) +// +// if (user == null) { +// userEventProducer.sendReceiptCodeDeleteFailed( +// receiptCode = receiptCode, +// reason = "User not found", +// ) +// throw UserNotFoundException +// } +// +// val updatedUser = user.copy(receiptCode = null) +// saveUserPort.save(updatedUser) +// +// registerAfterCommitCallback(receiptCode) +// } catch (e: Exception) { +// if (e !is UserNotFoundException) { +// userEventProducer.sendReceiptCodeDeleteFailed( +// receiptCode = receiptCode, +// reason = e.message ?: "Unknown error", +// ) +// } +// throw e // 예외 다시 던져서 롤백 발생 +// } + } + +// private fun registerAfterCommitCallback( +// receiptCode: Long +// ) { +// val callback = +// object : TransactionSynchronization { +// override fun afterCommit() { +// userEventProducer.sendReceiptCodeDeleteCompleted(receiptCode) +// } +// } +// TransactionSynchronizationManager.registerSynchronization(callback) +// } +} \ No newline at end of file diff --git a/casper-user/src/main/kotlin/hs/kr/entrydsm/user/infrastructure/kafka/configuration/KafkaTopics.kt b/casper-user/src/main/kotlin/hs/kr/entrydsm/user/infrastructure/kafka/configuration/KafkaTopics.kt index 824217c..bd08676 100644 --- a/casper-user/src/main/kotlin/hs/kr/entrydsm/user/infrastructure/kafka/configuration/KafkaTopics.kt +++ b/casper-user/src/main/kotlin/hs/kr/entrydsm/user/infrastructure/kafka/configuration/KafkaTopics.kt @@ -39,4 +39,6 @@ object KafkaTopics { * 원서 서비스에서 이 이벤트를 수신하면 보상 트랜잭션을 수행함 */ const val USER_RECEIPT_CODE_UPDATE_FAILED = "user-receipt-code-update-failed" + + const val CANCEL_SUBMITTED_APPLICATION = "cancel-submitted-application" } diff --git a/casper-user/src/main/kotlin/hs/kr/entrydsm/user/infrastructure/kafka/consumer/CancelApplicationConsumer.kt b/casper-user/src/main/kotlin/hs/kr/entrydsm/user/infrastructure/kafka/consumer/CancelApplicationConsumer.kt new file mode 100644 index 0000000..9daabb2 --- /dev/null +++ b/casper-user/src/main/kotlin/hs/kr/entrydsm/user/infrastructure/kafka/consumer/CancelApplicationConsumer.kt @@ -0,0 +1,24 @@ +package hs.kr.entrydsm.user.infrastructure.kafka.consumer + +import com.fasterxml.jackson.databind.ObjectMapper +import hs.kr.entrydsm.user.domain.user.application.port.`in`.DeleteReceiptCodeUseCase +import hs.kr.entrydsm.user.infrastructure.kafka.configuration.KafkaTopics +import org.springframework.kafka.annotation.KafkaListener +import org.springframework.stereotype.Component + +@Component +class CancelApplicationConsumer( + private val mapper: ObjectMapper, + private val deleteReceiptCodeUseCase: DeleteReceiptCodeUseCase +) { + + @KafkaListener( + topics = [KafkaTopics.CANCEL_SUBMITTED_APPLICATION], + groupId = "update-user", + containerFactory = "kafkaListenerContainerFactory", + ) + fun execute(message: String) { + val receiptCode = mapper.readValue(message, Long::class.java) + deleteReceiptCodeUseCase.deleteReceiptCode(receiptCode) + } +} \ No newline at end of file