diff --git a/application/src/main/kotlin/com/dobby/usecase/experiment/ExtractExperimentPostKeywordsUseCase.kt b/application/src/main/kotlin/com/dobby/usecase/experiment/ExtractExperimentPostKeywordsUseCase.kt index 55ecd569..15b5b042 100644 --- a/application/src/main/kotlin/com/dobby/usecase/experiment/ExtractExperimentPostKeywordsUseCase.kt +++ b/application/src/main/kotlin/com/dobby/usecase/experiment/ExtractExperimentPostKeywordsUseCase.kt @@ -1,17 +1,63 @@ package com.dobby.usecase.experiment -import com.dobby.gateway.experiment.ExperimentKeywordExtractionGateway -import com.dobby.model.experiment.keyword.ExperimentPostKeyword +import com.dobby.exception.ExperimentPostKeywordsDailyLimitExceededException +import com.dobby.gateway.OpenAiGateway +import com.dobby.gateway.experiment.ExperimentPostKeywordsLogGateway +import com.dobby.gateway.member.MemberGateway +import com.dobby.model.experiment.ExperimentPostKeywordsLog +import com.dobby.model.experiment.keyword.ExperimentPostKeywords import com.dobby.usecase.UseCase +import com.dobby.util.IdGenerator +import com.dobby.util.TimeProvider class ExtractExperimentPostKeywordsUseCase( - private val experimentKeywordExtractionGateway: ExperimentKeywordExtractionGateway + private val openAiGateway: OpenAiGateway, + private val experimentPostKeywordsGateway: ExperimentPostKeywordsLogGateway, + private val memberGateway: MemberGateway, + private val idGenerator: IdGenerator ) : UseCase { - data class Input(val text: String) - data class Output(val experimentPostKeyword: ExperimentPostKeyword) + + companion object { + private const val DAILY_USAGE_LIMIT = 2 + } + + data class Input( + val memberId: String, + val text: String + ) + + data class Output( + val experimentPostKeywords: ExperimentPostKeywords + ) override fun execute(input: Input): Output { - val experimentPostKeyword = experimentKeywordExtractionGateway.extractKeywords(input.text) + val member = memberGateway.getById(input.memberId) + validateDailyUsageLimit(input.memberId) + + val experimentPostKeyword = openAiGateway.extractKeywords(input.text) + val log = ExperimentPostKeywordsLog.newExperimentPostKeywordsLog( + id = idGenerator.generateId(), + member = member, + response = experimentPostKeyword + ) + + experimentPostKeywordsGateway.save(log) return Output(experimentPostKeyword) } + + private fun validateDailyUsageLimit(memberId: String) { + val today = TimeProvider.currentDateTime().toLocalDate() + val startOfDay = today.atStartOfDay() + val endOfDay = today.plusDays(1).atStartOfDay() + + val todayUsageCount = experimentPostKeywordsGateway.countByMemberIdAndCreatedAtBetween( + memberId = memberId, + start = startOfDay, + end = endOfDay + ) + + if (todayUsageCount >= DAILY_USAGE_LIMIT) { + throw ExperimentPostKeywordsDailyLimitExceededException + } + } } diff --git a/application/src/test/kotlin/com/dobby/usecase/experiment/ExtractExperimentPostKeywordsUseCaseTest.kt b/application/src/test/kotlin/com/dobby/usecase/experiment/ExtractExperimentPostKeywordsUseCaseTest.kt index 007573ee..095e6076 100644 --- a/application/src/test/kotlin/com/dobby/usecase/experiment/ExtractExperimentPostKeywordsUseCaseTest.kt +++ b/application/src/test/kotlin/com/dobby/usecase/experiment/ExtractExperimentPostKeywordsUseCaseTest.kt @@ -1,32 +1,98 @@ package com.dobby.usecase.experiment -import com.dobby.gateway.experiment.ExperimentKeywordExtractionGateway -import com.dobby.model.experiment.keyword.ExperimentPostKeyword +import com.dobby.exception.ExperimentPostKeywordsDailyLimitExceededException +import com.dobby.gateway.OpenAiGateway +import com.dobby.gateway.experiment.ExperimentPostKeywordsLogGateway +import com.dobby.gateway.member.MemberGateway +import com.dobby.model.experiment.ExperimentPostKeywordsLog +import com.dobby.model.experiment.keyword.ExperimentPostKeywords +import com.dobby.model.member.Member +import com.dobby.util.IdGenerator +import com.dobby.util.TimeProvider +import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.BehaviorSpec import io.kotest.matchers.shouldBe import io.mockk.every import io.mockk.mockk -import io.mockk.verify +import io.mockk.mockkObject +import io.mockk.unmockkAll +import java.time.LocalDateTime class ExtractExperimentPostKeywordsUseCaseTest : BehaviorSpec({ - val experimentKeywordExtractionGateway = mockk() - val extractExperimentPostKeywordsUseCase = ExtractExperimentPostKeywordsUseCase(experimentKeywordExtractionGateway) + val openAiGateway = mockk() + val experimentPostKeywordsLogGateway = mockk() + val memberGateway = mockk() + val idGenerator = mockk() - given("실험 게시글 텍스트에서 키워드를 추출할 때") { + val extractExperimentPostKeywordsUseCase = ExtractExperimentPostKeywordsUseCase( + openAiGateway, + experimentPostKeywordsLogGateway, + memberGateway, + idGenerator + ) + + beforeSpec { + mockkObject(TimeProvider) + } + + afterSpec { + unmockkAll() + } + + given("일일 사용 한도를 초과하지 않은 사용자가") { + val memberId = "test_member_123" val inputText = "남성 20-30대 대상 설문조사 참여자 모집합니다. 시간은 1시간 소요되며 참가비 10,000원 지급합니다." - val input = ExtractExperimentPostKeywordsUseCase.Input(inputText) - val mockExperimentPostKeyword = mockk() + val input = ExtractExperimentPostKeywordsUseCase.Input(memberId, inputText) + + val mockMember = mockk() + val mockExperimentPostKeywords = mockk() + val mockLog = mockk() + val currentDateTime = LocalDateTime.of(2025, 1, 27, 10, 0, 0) - every { experimentKeywordExtractionGateway.extractKeywords(inputText) } returns mockExperimentPostKeyword + every { TimeProvider.currentDateTime() } returns currentDateTime + every { memberGateway.getById(memberId) } returns mockMember + every { idGenerator.generateId() } returns "test_log_id" + every { openAiGateway.extractKeywords(inputText) } returns mockExperimentPostKeywords + every { experimentPostKeywordsLogGateway.save(any()) } returns mockLog + every { + experimentPostKeywordsLogGateway.countByMemberIdAndCreatedAtBetween( + memberId = memberId, + start = currentDateTime.toLocalDate().atStartOfDay(), + end = currentDateTime.toLocalDate().plusDays(1).atStartOfDay() + ) + } returns 1 `when`("키워드 추출을 요청하면") { val result = extractExperimentPostKeywordsUseCase.execute(input) then("추출된 키워드 정보를 반환해야 한다") { - result.experimentPostKeyword shouldBe mockExperimentPostKeyword + result.experimentPostKeywords shouldBe mockExperimentPostKeywords + } + } + } + + given("일일 사용 한도에 도달한 사용자가") { + val memberId = "exceeded_member_456" + val inputText = "실험 참여자 모집" + val input = ExtractExperimentPostKeywordsUseCase.Input(memberId, inputText) - verify(exactly = 1) { - experimentKeywordExtractionGateway.extractKeywords(inputText) + val mockMember = mockk() + val currentDateTime = LocalDateTime.of(2025, 1, 27, 15, 30, 0) + + every { TimeProvider.currentDateTime() } returns currentDateTime + every { memberGateway.getById(memberId) } returns mockMember + every { + experimentPostKeywordsLogGateway.countByMemberIdAndCreatedAtBetween( + memberId = memberId, + start = currentDateTime.toLocalDate().atStartOfDay(), + end = currentDateTime.toLocalDate().plusDays(1).atStartOfDay() + ) + } returns 2 + + `when`("키워드 추출을 요청하면") { + then("DailyLimitExceededException 예외가 발생해야 한다") { + shouldThrow { + extractExperimentPostKeywordsUseCase.execute(input) } } } diff --git a/domain/src/main/kotlin/com/dobby/exception/DobbyException.kt b/domain/src/main/kotlin/com/dobby/exception/DobbyException.kt index b9d6edb3..383b06f9 100644 --- a/domain/src/main/kotlin/com/dobby/exception/DobbyException.kt +++ b/domain/src/main/kotlin/com/dobby/exception/DobbyException.kt @@ -68,6 +68,7 @@ data object ExperimentPostRewardException : ClientException("EP0010", "Reward ca data object ExperimentPostContentException : ClientException("EP0011", "Content cannot be null.") data object ExperimentPostCountException : ClientException("EP0012", "Count could be more than zero.") data object ExperimentPostLeadResearcherException : ClientException("EP0013", "Lead Researcher cannot be null.") +data object ExperimentPostKeywordsDailyLimitExceededException : ClientException("EP0014", "Daily usage limit for experiment post keywords extraction has been exceeded.") /** * ServerException: Exceptions caused by internal server issues diff --git a/domain/src/main/kotlin/com/dobby/gateway/OpenAiGateway.kt b/domain/src/main/kotlin/com/dobby/gateway/OpenAiGateway.kt new file mode 100644 index 00000000..65e4868d --- /dev/null +++ b/domain/src/main/kotlin/com/dobby/gateway/OpenAiGateway.kt @@ -0,0 +1,7 @@ +package com.dobby.gateway + +import com.dobby.model.experiment.keyword.ExperimentPostKeywords + +interface OpenAiGateway { + fun extractKeywords(text: String): ExperimentPostKeywords +} diff --git a/domain/src/main/kotlin/com/dobby/gateway/experiment/ExperimentKeywordExtractionGateway.kt b/domain/src/main/kotlin/com/dobby/gateway/experiment/ExperimentKeywordExtractionGateway.kt deleted file mode 100644 index a189843d..00000000 --- a/domain/src/main/kotlin/com/dobby/gateway/experiment/ExperimentKeywordExtractionGateway.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.dobby.gateway.experiment - -import com.dobby.model.experiment.keyword.ExperimentPostKeyword - -interface ExperimentKeywordExtractionGateway { - fun extractKeywords(text: String): ExperimentPostKeyword -} diff --git a/domain/src/main/kotlin/com/dobby/gateway/experiment/ExperimentPostKeywordsLogGateway.kt b/domain/src/main/kotlin/com/dobby/gateway/experiment/ExperimentPostKeywordsLogGateway.kt new file mode 100644 index 00000000..934484fa --- /dev/null +++ b/domain/src/main/kotlin/com/dobby/gateway/experiment/ExperimentPostKeywordsLogGateway.kt @@ -0,0 +1,9 @@ +package com.dobby.gateway.experiment + +import com.dobby.model.experiment.ExperimentPostKeywordsLog +import java.time.LocalDateTime + +interface ExperimentPostKeywordsLogGateway { + fun save(experimentPostKeywordsLog: ExperimentPostKeywordsLog): ExperimentPostKeywordsLog + fun countByMemberIdAndCreatedAtBetween(memberId: String, start: LocalDateTime, end: LocalDateTime): Int +} diff --git a/domain/src/main/kotlin/com/dobby/model/experiment/ExperimentPostKeywordsLog.kt b/domain/src/main/kotlin/com/dobby/model/experiment/ExperimentPostKeywordsLog.kt new file mode 100644 index 00000000..c0d76df9 --- /dev/null +++ b/domain/src/main/kotlin/com/dobby/model/experiment/ExperimentPostKeywordsLog.kt @@ -0,0 +1,26 @@ +package com.dobby.model.experiment + +import com.dobby.model.experiment.keyword.ExperimentPostKeywords +import com.dobby.model.member.Member +import com.dobby.util.TimeProvider +import java.time.LocalDateTime + +data class ExperimentPostKeywordsLog( + val id: String, + val member: Member, + val response: ExperimentPostKeywords, + val createdAt: LocalDateTime +) { + companion object { + fun newExperimentPostKeywordsLog( + id: String, + member: Member, + response: ExperimentPostKeywords + ) = ExperimentPostKeywordsLog( + id = id, + member = member, + response = response, + createdAt = TimeProvider.currentDateTime() + ) + } +} diff --git a/domain/src/main/kotlin/com/dobby/model/experiment/keyword/ExperimentPostKeyword.kt b/domain/src/main/kotlin/com/dobby/model/experiment/keyword/ExperimentPostKeywords.kt similarity index 90% rename from domain/src/main/kotlin/com/dobby/model/experiment/keyword/ExperimentPostKeyword.kt rename to domain/src/main/kotlin/com/dobby/model/experiment/keyword/ExperimentPostKeywords.kt index cea8f404..e3419956 100644 --- a/domain/src/main/kotlin/com/dobby/model/experiment/keyword/ExperimentPostKeyword.kt +++ b/domain/src/main/kotlin/com/dobby/model/experiment/keyword/ExperimentPostKeywords.kt @@ -3,7 +3,7 @@ package com.dobby.model.experiment.keyword import com.dobby.enums.MatchType import com.dobby.enums.experiment.TimeSlot -data class ExperimentPostKeyword( +data class ExperimentPostKeywords( val targetGroup: TargetGroupKeyword?, val applyMethod: ApplyMethodKeyword?, val matchType: MatchType?, diff --git a/infrastructure/src/main/kotlin/com/dobby/converter/JsonConverter.kt b/infrastructure/src/main/kotlin/com/dobby/converter/JsonConverter.kt new file mode 100644 index 00000000..d3c7f1b3 --- /dev/null +++ b/infrastructure/src/main/kotlin/com/dobby/converter/JsonConverter.kt @@ -0,0 +1,13 @@ +package com.dobby.converter + +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import org.springframework.stereotype.Component + +@Component +class JsonConverter { + private val objectMapper = jacksonObjectMapper() + + fun toJson(obj: T): String = objectMapper.writeValueAsString(obj) + + fun fromJson(json: String, clazz: Class): T = objectMapper.readValue(json, clazz) +} diff --git a/infrastructure/src/main/kotlin/com/dobby/external/gateway/experiment/ExperimentPostKeywordsLogGatewayImpl.kt b/infrastructure/src/main/kotlin/com/dobby/external/gateway/experiment/ExperimentPostKeywordsLogGatewayImpl.kt new file mode 100644 index 00000000..4e46d600 --- /dev/null +++ b/infrastructure/src/main/kotlin/com/dobby/external/gateway/experiment/ExperimentPostKeywordsLogGatewayImpl.kt @@ -0,0 +1,29 @@ +package com.dobby.external.gateway.experiment + +import com.dobby.gateway.experiment.ExperimentPostKeywordsLogGateway +import com.dobby.mapper.ExperimentPostKeywordsLogMapper +import com.dobby.model.experiment.ExperimentPostKeywordsLog +import com.dobby.persistence.repository.ExperimentPostKeywordsLogRepository +import org.springframework.stereotype.Component +import java.time.LocalDateTime + +@Component +class ExperimentPostKeywordsLogGatewayImpl( + private val experimentPostKeywordsLogRepository: ExperimentPostKeywordsLogRepository, + private val mapper: ExperimentPostKeywordsLogMapper +) : ExperimentPostKeywordsLogGateway { + + override fun save(experimentPostKeywordsLog: ExperimentPostKeywordsLog): ExperimentPostKeywordsLog { + val entity = mapper.fromDomain(experimentPostKeywordsLog) + val savedEntity = experimentPostKeywordsLogRepository.save(entity) + return mapper.toDomain(savedEntity) + } + + override fun countByMemberIdAndCreatedAtBetween( + memberId: String, + start: LocalDateTime, + end: LocalDateTime + ): Int { + return experimentPostKeywordsLogRepository.countByMemberIdAndCreatedAtBetween(memberId, start, end) + } +} diff --git a/infrastructure/src/main/kotlin/com/dobby/external/gateway/experiment/ExperimentKeywordExtractionGatewayImpl.kt b/infrastructure/src/main/kotlin/com/dobby/external/openai/OpenAiGatewayImpl.kt similarity index 91% rename from infrastructure/src/main/kotlin/com/dobby/external/gateway/experiment/ExperimentKeywordExtractionGatewayImpl.kt rename to infrastructure/src/main/kotlin/com/dobby/external/openai/OpenAiGatewayImpl.kt index 9ee5c29c..b0cbe9cc 100644 --- a/infrastructure/src/main/kotlin/com/dobby/external/gateway/experiment/ExperimentKeywordExtractionGatewayImpl.kt +++ b/infrastructure/src/main/kotlin/com/dobby/external/openai/OpenAiGatewayImpl.kt @@ -1,4 +1,4 @@ -package com.dobby.external.gateway.experiment +package com.dobby.external.openai import com.dobby.api.dto.request.OpenAiRequest import com.dobby.exception.CustomOpenAiCallException @@ -7,19 +7,19 @@ import com.dobby.external.prompt.ExperimentPostKeywordMapper import com.dobby.external.prompt.PromptTemplate import com.dobby.external.prompt.PromptTemplateLoader import com.dobby.external.prompt.dto.ExperimentPostKeywordDto -import com.dobby.gateway.experiment.ExperimentKeywordExtractionGateway -import com.dobby.model.experiment.keyword.ExperimentPostKeyword +import com.dobby.gateway.OpenAiGateway +import com.dobby.model.experiment.keyword.ExperimentPostKeywords import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.readValue import feign.FeignException import org.springframework.stereotype.Component @Component -class ExperimentKeywordExtractionGatewayImpl( +class OpenAiGatewayImpl( private val openAiFeignClient: OpenAiFeignClient, private val promptTemplateLoader: PromptTemplateLoader, private val mapper: ExperimentPostKeywordMapper -) : ExperimentKeywordExtractionGateway { +) : OpenAiGateway { private val objectMapper = jacksonObjectMapper() @@ -27,7 +27,7 @@ class ExperimentKeywordExtractionGatewayImpl( promptTemplateLoader.loadPrompt("prompts/keyword_extraction_prompt.json") } - override fun extractKeywords(text: String): ExperimentPostKeyword { + override fun extractKeywords(text: String): ExperimentPostKeywords { val promptJson = objectMapper.writeValueAsString(promptTemplate) val prompt = promptJson.replace("{{text}}", escapeJsonString(text)) val messages = listOf( diff --git a/infrastructure/src/main/kotlin/com/dobby/external/prompt/ExperimentPostKeywordMapper.kt b/infrastructure/src/main/kotlin/com/dobby/external/prompt/ExperimentPostKeywordMapper.kt index b1986c76..9d739bed 100644 --- a/infrastructure/src/main/kotlin/com/dobby/external/prompt/ExperimentPostKeywordMapper.kt +++ b/infrastructure/src/main/kotlin/com/dobby/external/prompt/ExperimentPostKeywordMapper.kt @@ -7,15 +7,15 @@ import com.dobby.external.prompt.dto.ApplyMethodDto import com.dobby.external.prompt.dto.ExperimentPostKeywordDto import com.dobby.external.prompt.dto.TargetGroupDto import com.dobby.model.experiment.keyword.ApplyMethodKeyword -import com.dobby.model.experiment.keyword.ExperimentPostKeyword +import com.dobby.model.experiment.keyword.ExperimentPostKeywords import com.dobby.model.experiment.keyword.TargetGroupKeyword import org.springframework.stereotype.Component @Component class ExperimentPostKeywordMapper { - fun toDomain(dto: ExperimentPostKeywordDto): ExperimentPostKeyword { - return ExperimentPostKeyword( + fun toDomain(dto: ExperimentPostKeywordDto): ExperimentPostKeywords { + return ExperimentPostKeywords( targetGroup = dto.targetGroup?.let { targetGroupDto -> TargetGroupKeyword( startAge = targetGroupDto.startAge ?: 0, @@ -59,7 +59,7 @@ class ExperimentPostKeywordMapper { ) } - fun toDto(domain: ExperimentPostKeyword): ExperimentPostKeywordDto { + fun toDto(domain: ExperimentPostKeywords): ExperimentPostKeywordDto { return ExperimentPostKeywordDto( targetGroup = domain.targetGroup?.let { targetGroupDomain -> TargetGroupDto( diff --git a/infrastructure/src/main/kotlin/com/dobby/mapper/ExperimentPostKeywordsLogMapper.kt b/infrastructure/src/main/kotlin/com/dobby/mapper/ExperimentPostKeywordsLogMapper.kt new file mode 100644 index 00000000..2c1eda8a --- /dev/null +++ b/infrastructure/src/main/kotlin/com/dobby/mapper/ExperimentPostKeywordsLogMapper.kt @@ -0,0 +1,32 @@ +package com.dobby.mapper + +import com.dobby.converter.JsonConverter +import com.dobby.model.experiment.ExperimentPostKeywordsLog +import com.dobby.model.experiment.keyword.ExperimentPostKeywords +import com.dobby.persistence.entity.experiment.ExperimentPostKeywordsLogEntity +import com.dobby.persistence.entity.member.MemberEntity +import org.springframework.stereotype.Component + +@Component +class ExperimentPostKeywordsLogMapper( + private val jsonConverter: JsonConverter +) { + + fun toDomain(entity: ExperimentPostKeywordsLogEntity): ExperimentPostKeywordsLog { + return ExperimentPostKeywordsLog( + id = entity.id, + member = entity.member.toDomain(), + response = jsonConverter.fromJson(entity.response, ExperimentPostKeywords::class.java), + createdAt = entity.createdAt + ) + } + + fun fromDomain(domain: ExperimentPostKeywordsLog): ExperimentPostKeywordsLogEntity { + return ExperimentPostKeywordsLogEntity( + id = domain.id, + member = MemberEntity.fromDomain(domain.member), + response = jsonConverter.toJson(domain.response), + createdAt = domain.createdAt + ) + } +} diff --git a/infrastructure/src/main/kotlin/com/dobby/persistence/entity/experiment/ExperimentPostKeywordsLogEntity.kt b/infrastructure/src/main/kotlin/com/dobby/persistence/entity/experiment/ExperimentPostKeywordsLogEntity.kt new file mode 100644 index 00000000..b2559ec7 --- /dev/null +++ b/infrastructure/src/main/kotlin/com/dobby/persistence/entity/experiment/ExperimentPostKeywordsLogEntity.kt @@ -0,0 +1,27 @@ +package com.dobby.persistence.entity.experiment + +import com.dobby.persistence.entity.member.MemberEntity +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.FetchType +import jakarta.persistence.Id +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import java.time.LocalDateTime + +@Entity(name = "experiment_post_keywords_log") +class ExperimentPostKeywordsLogEntity( + @Id + @Column(name = "experiment_post_keywords_log_id", columnDefinition = "CHAR(13)") + val id: String, + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id") + val member: MemberEntity, + + @Column(columnDefinition = "TEXT", nullable = false) + val response: String, + + @Column(name = "created_at", nullable = false) + val createdAt: LocalDateTime +) diff --git a/infrastructure/src/main/kotlin/com/dobby/persistence/repository/ExperimentPostKeywordsLogRepository.kt b/infrastructure/src/main/kotlin/com/dobby/persistence/repository/ExperimentPostKeywordsLogRepository.kt new file mode 100644 index 00000000..506c05c2 --- /dev/null +++ b/infrastructure/src/main/kotlin/com/dobby/persistence/repository/ExperimentPostKeywordsLogRepository.kt @@ -0,0 +1,9 @@ +package com.dobby.persistence.repository + +import com.dobby.persistence.entity.experiment.ExperimentPostKeywordsLogEntity +import org.springframework.data.jpa.repository.JpaRepository +import java.time.LocalDateTime + +interface ExperimentPostKeywordsLogRepository : JpaRepository { + fun countByMemberIdAndCreatedAtBetween(memberId: String, start: LocalDateTime, end: LocalDateTime): Int +} diff --git a/infrastructure/src/main/resources/db/migration/V202507271926__add_experiment_post_keywords_log_table.sql b/infrastructure/src/main/resources/db/migration/V202507271926__add_experiment_post_keywords_log_table.sql new file mode 100644 index 00000000..871b39b0 --- /dev/null +++ b/infrastructure/src/main/resources/db/migration/V202507271926__add_experiment_post_keywords_log_table.sql @@ -0,0 +1,10 @@ +CREATE TABLE experiment_post_keywords_log ( + experiment_post_keywords_log_id CHAR(13) NOT NULL PRIMARY KEY, + member_id CHAR(13) NOT NULL, + response TEXT NOT NULL, + created_at TIMESTAMP NOT NULL, + CONSTRAINT fk_experiment_post_keywords_log_member + FOREIGN KEY (member_id) REFERENCES member (member_id) +) COLLATE = utf8mb4_unicode_ci; + +CREATE INDEX idx_experiment_keywords_log ON experiment_post_keywords_log (member_id, created_at); diff --git a/presentation/src/main/kotlin/com/dobby/api/dto/response/experiment/ExtractKeywordResponse.kt b/presentation/src/main/kotlin/com/dobby/api/dto/response/experiment/ExtractKeywordResponse.kt index 978b49a1..b8154070 100644 --- a/presentation/src/main/kotlin/com/dobby/api/dto/response/experiment/ExtractKeywordResponse.kt +++ b/presentation/src/main/kotlin/com/dobby/api/dto/response/experiment/ExtractKeywordResponse.kt @@ -1,9 +1,9 @@ package com.dobby.api.dto.response.experiment -import com.dobby.model.experiment.keyword.ExperimentPostKeyword +import com.dobby.model.experiment.keyword.ExperimentPostKeywords import io.swagger.v3.oas.annotations.media.Schema data class ExtractKeywordResponse( @Schema(description = "추출된 키워드 정보") - val experimentPostKeyword: ExperimentPostKeyword + val experimentPostKeywords: ExperimentPostKeywords ) diff --git a/presentation/src/main/kotlin/com/dobby/api/mapper/ExperimentPostMapper.kt b/presentation/src/main/kotlin/com/dobby/api/mapper/ExperimentPostMapper.kt index e07ceaf1..5437f42a 100644 --- a/presentation/src/main/kotlin/com/dobby/api/mapper/ExperimentPostMapper.kt +++ b/presentation/src/main/kotlin/com/dobby/api/mapper/ExperimentPostMapper.kt @@ -523,13 +523,14 @@ object ExperimentPostMapper { fun toExtractKeywordUseCaseInput(request: ExtractKeywordRequest): ExtractExperimentPostKeywordsUseCase.Input { return ExtractExperimentPostKeywordsUseCase.Input( + memberId = getCurrentMemberId(), text = request.text ) } fun toExtractKeywordResponse(output: ExtractExperimentPostKeywordsUseCase.Output): ExtractKeywordResponse { return ExtractKeywordResponse( - experimentPostKeyword = output.experimentPostKeyword + experimentPostKeywords = output.experimentPostKeywords ) } }