diff --git a/src/main/avro/chat.avsc b/src/main/avro/ChatAvroSchema.avsc similarity index 95% rename from src/main/avro/chat.avsc rename to src/main/avro/ChatAvroSchema.avsc index f9561e3..fe5f46d 100644 --- a/src/main/avro/chat.avsc +++ b/src/main/avro/ChatAvroSchema.avsc @@ -1,7 +1,7 @@ { "type": "record", - "name": "ChatEvent", - "namespace": "com.chatbot.events", + "name": "ChatAvroSchema", + "namespace": "windeath44.server.chatbot.avro", "doc": "챗봇 채팅 이벤트 스키마", "fields": [ { diff --git a/src/main/avro/MemorialBowedAvroSchema.avsc b/src/main/avro/MemorialBowedAvroSchema.avsc new file mode 100644 index 0000000..27bf4fc --- /dev/null +++ b/src/main/avro/MemorialBowedAvroSchema.avsc @@ -0,0 +1,10 @@ +{ + "type": "record", + "name": "MemorialBowedAvroSchema", + "namespace": "windeath44.server.memorial.avro", + "fields": [ + {"name": "memorialId", "type": "long"}, + {"name": "memorialBow", "type": "long"}, + {"name": "writerId", "type": "string"} + ] +} diff --git a/src/main/avro/RemainTokenDecreaseResponse.avsc b/src/main/avro/RemainTokenDecreaseResponse.avsc index 5d2843e..351cf22 100644 --- a/src/main/avro/RemainTokenDecreaseResponse.avsc +++ b/src/main/avro/RemainTokenDecreaseResponse.avsc @@ -1,7 +1,7 @@ { "type": "record", "name": "RemainTokenDecreaseResponse", - "namespace": "com.example.user.avro", + "namespace": "windeath44.server.user.avro", "doc": "토큰 감소 응답 스키마", "fields": [ { diff --git a/src/main/avro/RemainTokenIncreaseResponse.avsc b/src/main/avro/RemainTokenIncreaseResponse.avsc new file mode 100644 index 0000000..536412e --- /dev/null +++ b/src/main/avro/RemainTokenIncreaseResponse.avsc @@ -0,0 +1,30 @@ +{ + "type": "record", + "name": "RemainTokenIncreaseResponse", + "namespace": "windeath44.server.user.avro", + "doc": "토큰 증가 응답 스키마", + "fields": [ + { + "name": "user_id", + "type": "string", + "doc": "사용자 ID" + }, + { + "name": "success", + "type": "boolean", + "doc": "토큰 증가 성공 여부" + }, + { + "name": "remaining_token", + "type": ["null", "long"], + "default": null, + "doc": "남은 토큰 수 (성공 시)" + }, + { + "name": "error_message", + "type": ["null", "string"], + "default": null, + "doc": "에러 발생 시 에러 메시지" + } + ] +} diff --git a/src/main/java/com/example/user/domain/controller/UserController.java b/src/main/java/com/example/user/domain/controller/UserController.java index 5022e6b..4560b59 100644 --- a/src/main/java/com/example/user/domain/controller/UserController.java +++ b/src/main/java/com/example/user/domain/controller/UserController.java @@ -22,7 +22,6 @@ public class UserController { private final UserService userService; - @GetMapping public ResponseEntity>> getUsersByIds(@RequestParam("userIds") List userIds) { List userResponsesList = userService.findAllByIds(userIds); diff --git a/src/main/java/com/example/user/domain/eventlistener/KafkaEventListener.java b/src/main/java/com/example/user/domain/eventlistener/KafkaEventListener.java index cfd35ab..e765fc9 100644 --- a/src/main/java/com/example/user/domain/eventlistener/KafkaEventListener.java +++ b/src/main/java/com/example/user/domain/eventlistener/KafkaEventListener.java @@ -1,25 +1,29 @@ package com.example.user.domain.eventlistener; -import com.chatbot.events.ChatEvent; -import com.example.user.avro.RemainTokenDecreaseResponse; +import windeath44.server.chatbot.avro.ChatAvroSchema; import com.example.user.domain.service.TokenDecreaseService; +import com.example.user.domain.service.TokenIncreaseService; import com.example.user.global.infrastructure.KafkaProducer; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.kafka.annotation.KafkaListener; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; +import windeath44.server.memorial.avro.MemorialBowedAvroSchema; +import windeath44.server.user.avro.RemainTokenDecreaseResponse; +import windeath44.server.user.avro.RemainTokenIncreaseResponse; @Slf4j @Component @RequiredArgsConstructor public class KafkaEventListener { private final TokenDecreaseService tokenDecreaseService; + private final TokenIncreaseService tokenIncreaseService; private final KafkaProducer kafkaProducer; @KafkaListener(topics = "remain-token-decrease-request", groupId = "user") @Transactional - public void handleTokenDecreaseRequest(ChatEvent request) { + public void handleTokenDecreaseRequest(ChatAvroSchema request) { log.info("토큰 감소 요청 수신 - userId: {}, tokenCount: {}", request.getUserId(), request.getTotalTokenCount()); try { @@ -51,5 +55,41 @@ private static RemainTokenDecreaseResponse buildResponse(String userId, boolean .setErrorMessage(errorMessage) .build(); } + + @KafkaListener(topics = "remain-token-increase-request", groupId = "user") + @Transactional + public void handleTokenIncreaseRequest(MemorialBowedAvroSchema memorialBowedAvroSchema) { + String userId = memorialBowedAvroSchema.getWriterId(); + log.info("토큰 증가 요청 수신 - userId: {}, tokenBowCount: {}", userId, memorialBowedAvroSchema.getMemorialBow()); + + try { + Long remainingToken = tokenIncreaseService.increaseToken( + userId, + 1000L + ); + + RemainTokenIncreaseResponse response = buildIncreaseResponse(userId, true, remainingToken, null); + kafkaProducer.send("remain-token-increase-response", response); + + log.info("토큰 증가 성공 - userId: {}, remainingToken: {}", userId, remainingToken); + + } catch (Exception e) { + log.error("토큰 증가 실패 - userId: {}, error: {}", userId, e.getMessage(), e); + + RemainTokenIncreaseResponse response = buildIncreaseResponse(userId, false, null, e.getMessage()); + kafkaProducer.send("remain-token-increase-fail-response", response); + + log.info("토큰 증가 실패 응답 발송 완료 - userId: {}", userId); + } + } + + private static RemainTokenIncreaseResponse buildIncreaseResponse(String userId, boolean success, Long remainingToken, String errorMessage) { + return RemainTokenIncreaseResponse.newBuilder() + .setUserId(userId) + .setSuccess(success) + .setRemainingToken(remainingToken) + .setErrorMessage(errorMessage) + .build(); + } } diff --git a/src/main/java/com/example/user/domain/model/User.java b/src/main/java/com/example/user/domain/model/User.java index bf98d4c..e4bc58d 100644 --- a/src/main/java/com/example/user/domain/model/User.java +++ b/src/main/java/com/example/user/domain/model/User.java @@ -34,7 +34,7 @@ public class User { @PrePersist public void defaultSettings() { - this.remainToken = 0L; + this.remainToken = 3000L; String defaultImage = "https://windeath44.s3.ap-northeast-2.amazonaws.com/seori_profile.png"; this.profile = defaultImage; } diff --git a/src/main/java/com/example/user/domain/service/TokenIncreaseService.java b/src/main/java/com/example/user/domain/service/TokenIncreaseService.java new file mode 100644 index 0000000..657f4e6 --- /dev/null +++ b/src/main/java/com/example/user/domain/service/TokenIncreaseService.java @@ -0,0 +1,29 @@ +package com.example.user.domain.service; + +import com.example.user.domain.exception.NotFoundUserException; +import com.example.user.domain.model.User; +import com.example.user.domain.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@Service +@RequiredArgsConstructor +public class TokenIncreaseService { + private final UserRepository userRepository; + + @Transactional + public Long increaseToken(String userId, Long tokenCount) { + User user = userRepository.findByUserId(userId) + .orElseThrow(NotFoundUserException::getInstance); + + user.increaseToken(tokenCount); + userRepository.save(user); + + log.info("토큰 증가 완료 - userId: {}, 증가량: {}, 남은 토큰: {}", userId, tokenCount, user.getRemainToken()); + + return user.getRemainToken(); + } +}