From c124b8b6dfb13e307ffc9525ea14cec780a71747 Mon Sep 17 00:00:00 2001 From: nurdy-kim Date: Mon, 13 Oct 2025 14:59:06 +0900 Subject: [PATCH 01/16] =?UTF-8?q?feat:=20=ED=80=98=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20LLM=20=EB=A7=88=EC=9D=B4=EA=B7=B8=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GeminiGenerateTextUseCase.java | 9 ++- .../llm/application/GenerateTextCommand.java | 9 ++- .../llm/application/GenerateTextDto.java | 2 +- .../llm/exception/GenerateQuestErrorCode.java | 21 ++++++ .../llm/exception/GenerateQuestException.java | 13 ++++ .../llm/infrastructure/GeminiApiAdapter.java | 62 ++++++++++++++++++ .../llm/infrastructure/GeminiRequest.java | 64 +++++++++++++++++++ .../llm/infrastructure/GeminiResponse.java | 18 ++++++ 8 files changed, 194 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java create mode 100644 src/main/java/com/gomo/app/support/llm/exception/GenerateQuestException.java create mode 100644 src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java create mode 100644 src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java create mode 100644 src/main/java/com/gomo/app/support/llm/infrastructure/GeminiResponse.java diff --git a/src/main/java/com/gomo/app/support/llm/application/GeminiGenerateTextUseCase.java b/src/main/java/com/gomo/app/support/llm/application/GeminiGenerateTextUseCase.java index f9bdc4f5..701f67ea 100644 --- a/src/main/java/com/gomo/app/support/llm/application/GeminiGenerateTextUseCase.java +++ b/src/main/java/com/gomo/app/support/llm/application/GeminiGenerateTextUseCase.java @@ -1,13 +1,18 @@ package com.gomo.app.support.llm.application; import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.support.llm.infrastructure.GeminiApiAdapter; + +import lombok.RequiredArgsConstructor; @ApplicationService +@RequiredArgsConstructor class GeminiGenerateTextUseCase implements GenerateTextPortIn { + private final GeminiApiAdapter geminiApiAdapter; + @Override public GenerateTextDto generate(GenerateTextCommand command) { - // todo nurdy: 기존 py 기반 llm 호출 로직 마이그레이션 필요 - return null; + return geminiApiAdapter.generate(command); } } diff --git a/src/main/java/com/gomo/app/support/llm/application/GenerateTextCommand.java b/src/main/java/com/gomo/app/support/llm/application/GenerateTextCommand.java index 1c5ef221..baff3404 100644 --- a/src/main/java/com/gomo/app/support/llm/application/GenerateTextCommand.java +++ b/src/main/java/com/gomo/app/support/llm/application/GenerateTextCommand.java @@ -1,4 +1,11 @@ package com.gomo.app.support.llm.application; -public record GenerateTextCommand() { +import java.util.Map; + +import com.gomo.app.core.quest.domain.model.quest.QuestType; + +public record GenerateTextCommand(Map interests, QuestType questType, int amount) { + public static GenerateTextCommand of(Map interests, QuestType questType, int amount) { + return new GenerateTextCommand(interests, questType, amount); + } } diff --git a/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java b/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java index 8a275ead..21098463 100644 --- a/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java +++ b/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java @@ -1,4 +1,4 @@ package com.gomo.app.support.llm.application; -public record GenerateTextDto() { +public record GenerateTextDto(String generatedText) { } diff --git a/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java new file mode 100644 index 00000000..9cdf3167 --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java @@ -0,0 +1,21 @@ +package com.gomo.app.support.llm.exception; + +import lombok.Getter; + +@Getter +public enum GenerateQuestErrorCode { + GEMINI_API_ERROR(500, "QUE-GEN-001", "An error occurred while call GeminiAPI"), + EMPTY_RESPONSE(500, "QUE-GEN-002", "Gemini API response blank"), + INVALID_RESPONSE_FORMAT(500, "QUE-GEN-003", "Gemini Response format is invalid") + ; + + private final int httpStatus; + private final String errorCode; + private final String message; + + GenerateQuestErrorCode(int httpStatus, String errorCode, String message) { + this.httpStatus = httpStatus; + this.errorCode = errorCode; + this.message = message; + } +} diff --git a/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestException.java b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestException.java new file mode 100644 index 00000000..9879f9ea --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestException.java @@ -0,0 +1,13 @@ +package com.gomo.app.support.llm.exception; + +import com.gomo.app.common.exception.ApplicationException; + +public class GenerateQuestException extends ApplicationException { + public GenerateQuestException(GenerateQuestErrorCode errorCode){ + super(errorCode.getHttpStatus(), errorCode.name(), errorCode.getMessage()); + } + + public GenerateQuestException(GenerateQuestErrorCode errorCode, Throwable cause){ + super(errorCode.getHttpStatus(), errorCode.name(), errorCode.getMessage(), cause); + } +} diff --git a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java new file mode 100644 index 00000000..f325f9d4 --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java @@ -0,0 +1,62 @@ +package com.gomo.app.support.llm.infrastructure; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; +import org.springframework.web.client.RestClient; + +import com.gomo.app.common.arch.Adapter; +import com.gomo.app.support.llm.application.GenerateTextCommand; +import com.gomo.app.support.llm.application.GenerateTextDto; +import com.gomo.app.support.llm.exception.GenerateQuestException; +import com.gomo.app.support.llm.exception.GenerateQuestErrorCode; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@RequiredArgsConstructor +@Adapter +@Slf4j +public class GeminiApiAdapter { + private final RestClient restClient; + + @Value("${spring.ai.openai.api-key}") + private String apiKey; + + @Value("${spring.ai.openai.chat.options.model}") + private String model; + + private static final String GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions"; + + public GenerateTextDto generate(GenerateTextCommand command){ + try{ + String apiKey = "Bearer " + this.apiKey; + GeminiRequest request = createGeminiRequest(command); + + GeminiResponse response = restClient.post() + .uri(GEMINI_API_URL) + .header("Authorization", apiKey) + .contentType(MediaType.APPLICATION_JSON) + .body(request) + .retrieve() + .body(GeminiResponse.class); + + return convertToGenerateTextDto(response); + } catch (Exception e) { + log.error("Failed to generate text with Gemini API", e); + throw new RuntimeException("Gemini API 호출 중 오류가 발생 했습니다.", e); + } + } + + private GeminiRequest createGeminiRequest(GenerateTextCommand command){ + return GeminiRequest.createPrompt(command.interests(), command.questType(), command.amount()); + } + + private GenerateTextDto convertToGenerateTextDto(GeminiResponse response){ + if (response.choices() == null || response.choices().isEmpty()){ + throw new GenerateQuestException(GenerateQuestErrorCode.EMPTY_RESPONSE); + } + + String generatedText = response.choices().get(0).message().content(); + return new GenerateTextDto(generatedText); + } +} diff --git a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java new file mode 100644 index 00000000..86938e19 --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java @@ -0,0 +1,64 @@ +package com.gomo.app.support.llm.infrastructure; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.gomo.app.core.quest.domain.model.quest.QuestType; + +public record GeminiRequest( + String model, + String reasoning_effort, + List messages +) { + private static Prompt createSystemPrompt(){ + return new Prompt("system", """ + 당신은 개인 맞춤형 도전 과제를 생성하는 전문가 입니다. 아래 가이드라인을 준수하여 도전 과제를 생성하세요. + + **도전 과제 생성 가이드라인** + #1. 아래 주어지는 ‘개인 정보’를 바탕으로 ‘도전 과제’를 생성합니다. + #1-1. ‘개인 정보’의 숙련도와 퀘스트 타입으로 ‘도전 과제’의 ‘소요 시간(분)’을 결정합니다. + #1-1-1. 숙련도는 0 - 100 사이의 정수입니다. + #1-1-2. 퀘스트 타입은 각각 Daily(30 - 90), Weekly(300 - 900), Monthly(1000 - 1500) 사이의 무작위 정수입니다. + #1-1-3. ‘도전 과제’의 ‘소요 시간(분)’은 연산식(숙련도 * 0.1 + 퀘스트 타입) 결과로 0 - 1510 사이의 정수입니다. + #1-2. ‘도전 과제’의 content는 ‘개인 정보’의 관심사와 연관된 목표입니다. + #1-2-1. content는 명확하고 구조적인 행동을 제시합니다. + #1-2-1-1. 문장 형식은 “진행합니다.” 가 아닌 “진행”과 같이 짧게 끝맺음한다. + #1-2-2. content는 실질적으로 ‘소요 시간(분)’ 이내에 달성 가능해야 합니다. + #1-2-2-1. 30 - 100 ex) “알고리즘 1문제 풀이”, “TIL 작성”, “기술 블로그 하나 정독” + #1-2-2-2. 300 - 910 ex) “기술 블로그 하나 작성”, “개인 프로젝트 pr 하나 작업”, “개인 프로젝트 로깅 시스템 점검” + #1-2-2-3. 1000 - 1510 ex) “서킷 브레이커 학습 후, 개인 프로젝트에 적용하기”, “오픈 소스 1회 기여하기”, “멀티 모듈 학습하고 토이 프로젝트 진행하기” + #2. ‘도전 과제’의 응답 형식은 반드시 JSON으로 작성해주세요. + #2-1. 생성된 도전과제는 30자 이내의 동사형으로 제시해주세요. + #2-2. 응답 형식 예시: { + ["관심사명" : [{ “content” : “[생성된 도전 과제]” }, ...],]} + #2-3. 이전 수행 퀘스트를 참고하여, 중복이 발생하지 않도록 제시해주세요. + #2-4. 각 관심사 별 퀘스트 수를 동일한 비율로 생성해 주세요. + """); + } + + private static Prompt createUserPrompt(Map interests, QuestType questType, int amount){ + String interestsText = interests.entrySet().stream() + .map(entry -> entry.getKey() + "(숙련도 : " + entry.getValue() + ")") + .collect(Collectors.joining(", ")); + + String promptText = String.format( + """ + **개인 정보** + - 관심사: %s + - 퀘스트 타입: %s + - 퀘스트 수: %s + """, interestsText, questType.name(), amount + ); + + return new Prompt("user", promptText); + } + + public static GeminiRequest createPrompt(Map interests, QuestType questType, int amount){ + Prompt system = createSystemPrompt(); + Prompt user = createUserPrompt(interests, questType, amount); + return new GeminiRequest("gemini-2.5-flash", "none", List.of(system, user)); + } + + public record Prompt(String role, String content){} +} \ No newline at end of file diff --git a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiResponse.java b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiResponse.java new file mode 100644 index 00000000..587512a9 --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiResponse.java @@ -0,0 +1,18 @@ +package com.gomo.app.support.llm.infrastructure; + +import java.util.List; + +public record GeminiResponse( + List choices, + int created, + String id, + String model, + String object, + GeminiUsage usage +) { + public record Choice(String finish_reason, int index, Message message){} + public record Message(String content, String role){} + public record GeminiUsage(int completion_tokens, int prompt_tokens, int total_tokens){} +} + + From b505f33b3486e6210e1eab8b32f1587fcc544178 Mon Sep 17 00:00:00 2001 From: nurdy-kim Date: Mon, 13 Oct 2025 14:59:06 +0900 Subject: [PATCH 02/16] =?UTF-8?q?feat:=20=ED=80=98=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20LLM=20=EB=A7=88=EC=9D=B4=EA=B7=B8=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GeminiGenerateTextUseCase.java | 9 ++- .../llm/application/GenerateTextCommand.java | 9 ++- .../llm/application/GenerateTextDto.java | 2 +- .../llm/exception/GenerateQuestErrorCode.java | 21 ++++++ .../llm/exception/GenerateQuestException.java | 13 ++++ .../llm/infrastructure/GeminiApiAdapter.java | 62 ++++++++++++++++++ .../llm/infrastructure/GeminiRequest.java | 64 +++++++++++++++++++ .../llm/infrastructure/GeminiResponse.java | 18 ++++++ 8 files changed, 194 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java create mode 100644 src/main/java/com/gomo/app/support/llm/exception/GenerateQuestException.java create mode 100644 src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java create mode 100644 src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java create mode 100644 src/main/java/com/gomo/app/support/llm/infrastructure/GeminiResponse.java diff --git a/src/main/java/com/gomo/app/support/llm/application/GeminiGenerateTextUseCase.java b/src/main/java/com/gomo/app/support/llm/application/GeminiGenerateTextUseCase.java index f9bdc4f5..701f67ea 100644 --- a/src/main/java/com/gomo/app/support/llm/application/GeminiGenerateTextUseCase.java +++ b/src/main/java/com/gomo/app/support/llm/application/GeminiGenerateTextUseCase.java @@ -1,13 +1,18 @@ package com.gomo.app.support.llm.application; import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.support.llm.infrastructure.GeminiApiAdapter; + +import lombok.RequiredArgsConstructor; @ApplicationService +@RequiredArgsConstructor class GeminiGenerateTextUseCase implements GenerateTextPortIn { + private final GeminiApiAdapter geminiApiAdapter; + @Override public GenerateTextDto generate(GenerateTextCommand command) { - // todo nurdy: 기존 py 기반 llm 호출 로직 마이그레이션 필요 - return null; + return geminiApiAdapter.generate(command); } } diff --git a/src/main/java/com/gomo/app/support/llm/application/GenerateTextCommand.java b/src/main/java/com/gomo/app/support/llm/application/GenerateTextCommand.java index 1c5ef221..baff3404 100644 --- a/src/main/java/com/gomo/app/support/llm/application/GenerateTextCommand.java +++ b/src/main/java/com/gomo/app/support/llm/application/GenerateTextCommand.java @@ -1,4 +1,11 @@ package com.gomo.app.support.llm.application; -public record GenerateTextCommand() { +import java.util.Map; + +import com.gomo.app.core.quest.domain.model.quest.QuestType; + +public record GenerateTextCommand(Map interests, QuestType questType, int amount) { + public static GenerateTextCommand of(Map interests, QuestType questType, int amount) { + return new GenerateTextCommand(interests, questType, amount); + } } diff --git a/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java b/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java index 8a275ead..21098463 100644 --- a/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java +++ b/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java @@ -1,4 +1,4 @@ package com.gomo.app.support.llm.application; -public record GenerateTextDto() { +public record GenerateTextDto(String generatedText) { } diff --git a/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java new file mode 100644 index 00000000..9cdf3167 --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java @@ -0,0 +1,21 @@ +package com.gomo.app.support.llm.exception; + +import lombok.Getter; + +@Getter +public enum GenerateQuestErrorCode { + GEMINI_API_ERROR(500, "QUE-GEN-001", "An error occurred while call GeminiAPI"), + EMPTY_RESPONSE(500, "QUE-GEN-002", "Gemini API response blank"), + INVALID_RESPONSE_FORMAT(500, "QUE-GEN-003", "Gemini Response format is invalid") + ; + + private final int httpStatus; + private final String errorCode; + private final String message; + + GenerateQuestErrorCode(int httpStatus, String errorCode, String message) { + this.httpStatus = httpStatus; + this.errorCode = errorCode; + this.message = message; + } +} diff --git a/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestException.java b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestException.java new file mode 100644 index 00000000..9879f9ea --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestException.java @@ -0,0 +1,13 @@ +package com.gomo.app.support.llm.exception; + +import com.gomo.app.common.exception.ApplicationException; + +public class GenerateQuestException extends ApplicationException { + public GenerateQuestException(GenerateQuestErrorCode errorCode){ + super(errorCode.getHttpStatus(), errorCode.name(), errorCode.getMessage()); + } + + public GenerateQuestException(GenerateQuestErrorCode errorCode, Throwable cause){ + super(errorCode.getHttpStatus(), errorCode.name(), errorCode.getMessage(), cause); + } +} diff --git a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java new file mode 100644 index 00000000..f325f9d4 --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java @@ -0,0 +1,62 @@ +package com.gomo.app.support.llm.infrastructure; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; +import org.springframework.web.client.RestClient; + +import com.gomo.app.common.arch.Adapter; +import com.gomo.app.support.llm.application.GenerateTextCommand; +import com.gomo.app.support.llm.application.GenerateTextDto; +import com.gomo.app.support.llm.exception.GenerateQuestException; +import com.gomo.app.support.llm.exception.GenerateQuestErrorCode; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@RequiredArgsConstructor +@Adapter +@Slf4j +public class GeminiApiAdapter { + private final RestClient restClient; + + @Value("${spring.ai.openai.api-key}") + private String apiKey; + + @Value("${spring.ai.openai.chat.options.model}") + private String model; + + private static final String GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions"; + + public GenerateTextDto generate(GenerateTextCommand command){ + try{ + String apiKey = "Bearer " + this.apiKey; + GeminiRequest request = createGeminiRequest(command); + + GeminiResponse response = restClient.post() + .uri(GEMINI_API_URL) + .header("Authorization", apiKey) + .contentType(MediaType.APPLICATION_JSON) + .body(request) + .retrieve() + .body(GeminiResponse.class); + + return convertToGenerateTextDto(response); + } catch (Exception e) { + log.error("Failed to generate text with Gemini API", e); + throw new RuntimeException("Gemini API 호출 중 오류가 발생 했습니다.", e); + } + } + + private GeminiRequest createGeminiRequest(GenerateTextCommand command){ + return GeminiRequest.createPrompt(command.interests(), command.questType(), command.amount()); + } + + private GenerateTextDto convertToGenerateTextDto(GeminiResponse response){ + if (response.choices() == null || response.choices().isEmpty()){ + throw new GenerateQuestException(GenerateQuestErrorCode.EMPTY_RESPONSE); + } + + String generatedText = response.choices().get(0).message().content(); + return new GenerateTextDto(generatedText); + } +} diff --git a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java new file mode 100644 index 00000000..86938e19 --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java @@ -0,0 +1,64 @@ +package com.gomo.app.support.llm.infrastructure; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.gomo.app.core.quest.domain.model.quest.QuestType; + +public record GeminiRequest( + String model, + String reasoning_effort, + List messages +) { + private static Prompt createSystemPrompt(){ + return new Prompt("system", """ + 당신은 개인 맞춤형 도전 과제를 생성하는 전문가 입니다. 아래 가이드라인을 준수하여 도전 과제를 생성하세요. + + **도전 과제 생성 가이드라인** + #1. 아래 주어지는 ‘개인 정보’를 바탕으로 ‘도전 과제’를 생성합니다. + #1-1. ‘개인 정보’의 숙련도와 퀘스트 타입으로 ‘도전 과제’의 ‘소요 시간(분)’을 결정합니다. + #1-1-1. 숙련도는 0 - 100 사이의 정수입니다. + #1-1-2. 퀘스트 타입은 각각 Daily(30 - 90), Weekly(300 - 900), Monthly(1000 - 1500) 사이의 무작위 정수입니다. + #1-1-3. ‘도전 과제’의 ‘소요 시간(분)’은 연산식(숙련도 * 0.1 + 퀘스트 타입) 결과로 0 - 1510 사이의 정수입니다. + #1-2. ‘도전 과제’의 content는 ‘개인 정보’의 관심사와 연관된 목표입니다. + #1-2-1. content는 명확하고 구조적인 행동을 제시합니다. + #1-2-1-1. 문장 형식은 “진행합니다.” 가 아닌 “진행”과 같이 짧게 끝맺음한다. + #1-2-2. content는 실질적으로 ‘소요 시간(분)’ 이내에 달성 가능해야 합니다. + #1-2-2-1. 30 - 100 ex) “알고리즘 1문제 풀이”, “TIL 작성”, “기술 블로그 하나 정독” + #1-2-2-2. 300 - 910 ex) “기술 블로그 하나 작성”, “개인 프로젝트 pr 하나 작업”, “개인 프로젝트 로깅 시스템 점검” + #1-2-2-3. 1000 - 1510 ex) “서킷 브레이커 학습 후, 개인 프로젝트에 적용하기”, “오픈 소스 1회 기여하기”, “멀티 모듈 학습하고 토이 프로젝트 진행하기” + #2. ‘도전 과제’의 응답 형식은 반드시 JSON으로 작성해주세요. + #2-1. 생성된 도전과제는 30자 이내의 동사형으로 제시해주세요. + #2-2. 응답 형식 예시: { + ["관심사명" : [{ “content” : “[생성된 도전 과제]” }, ...],]} + #2-3. 이전 수행 퀘스트를 참고하여, 중복이 발생하지 않도록 제시해주세요. + #2-4. 각 관심사 별 퀘스트 수를 동일한 비율로 생성해 주세요. + """); + } + + private static Prompt createUserPrompt(Map interests, QuestType questType, int amount){ + String interestsText = interests.entrySet().stream() + .map(entry -> entry.getKey() + "(숙련도 : " + entry.getValue() + ")") + .collect(Collectors.joining(", ")); + + String promptText = String.format( + """ + **개인 정보** + - 관심사: %s + - 퀘스트 타입: %s + - 퀘스트 수: %s + """, interestsText, questType.name(), amount + ); + + return new Prompt("user", promptText); + } + + public static GeminiRequest createPrompt(Map interests, QuestType questType, int amount){ + Prompt system = createSystemPrompt(); + Prompt user = createUserPrompt(interests, questType, amount); + return new GeminiRequest("gemini-2.5-flash", "none", List.of(system, user)); + } + + public record Prompt(String role, String content){} +} \ No newline at end of file diff --git a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiResponse.java b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiResponse.java new file mode 100644 index 00000000..587512a9 --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiResponse.java @@ -0,0 +1,18 @@ +package com.gomo.app.support.llm.infrastructure; + +import java.util.List; + +public record GeminiResponse( + List choices, + int created, + String id, + String model, + String object, + GeminiUsage usage +) { + public record Choice(String finish_reason, int index, Message message){} + public record Message(String content, String role){} + public record GeminiUsage(int completion_tokens, int prompt_tokens, int total_tokens){} +} + + From 59a4e37693c5c415c589e1569bad9e14f19f11c6 Mon Sep 17 00:00:00 2001 From: nurdy-kim Date: Sun, 19 Oct 2025 20:27:35 +0900 Subject: [PATCH 03/16] =?UTF-8?q?fix:=20style=20error=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gomo/app/support/llm/exception/GenerateQuestErrorCode.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java index 9cdf3167..ab1aa6a1 100644 --- a/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java +++ b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java @@ -6,8 +6,7 @@ public enum GenerateQuestErrorCode { GEMINI_API_ERROR(500, "QUE-GEN-001", "An error occurred while call GeminiAPI"), EMPTY_RESPONSE(500, "QUE-GEN-002", "Gemini API response blank"), - INVALID_RESPONSE_FORMAT(500, "QUE-GEN-003", "Gemini Response format is invalid") - ; + INVALID_RESPONSE_FORMAT(500, "QUE-GEN-003", "Gemini Response format is invalid"); private final int httpStatus; private final String errorCode; From f83f88ffccd0bd671f4492a2b07263422af638eb Mon Sep 17 00:00:00 2001 From: nurdy-kim Date: Mon, 20 Oct 2025 13:12:20 +0900 Subject: [PATCH 04/16] =?UTF-8?q?feat:=20=EB=A6=AC=EB=B7=B0=20=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EB=B0=98=EC=98=81(prompt=20=EB=B3=84=EB=8F=84=20te?= =?UTF-8?q?xt=20=ED=8C=8C=EC=9D=BC,=20LlmClientPortOut=20interface=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1,=20Style=20=EC=98=A4=EB=A5=98=20=EB=93=B1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gomo/app/common/util/PromptLoader.java | 20 +++++++++ .../llm/application/GenerateTextDto.java | 7 ++- .../llm/application/LlmClientPortOut.java | 14 ++++++ .../llm/exception/GenerateQuestErrorCode.java | 4 +- .../llm/infrastructure/GeminiApiAdapter.java | 43 +++++++++++++++++-- .../llm/infrastructure/GeminiRequest.java | 39 +++-------------- src/main/resources/prompt/system-prompt.txt | 1 + 7 files changed, 90 insertions(+), 38 deletions(-) create mode 100644 src/main/java/com/gomo/app/common/util/PromptLoader.java create mode 100644 src/main/java/com/gomo/app/support/llm/application/LlmClientPortOut.java create mode 100644 src/main/resources/prompt/system-prompt.txt diff --git a/src/main/java/com/gomo/app/common/util/PromptLoader.java b/src/main/java/com/gomo/app/common/util/PromptLoader.java new file mode 100644 index 00000000..1f5c6ca1 --- /dev/null +++ b/src/main/java/com/gomo/app/common/util/PromptLoader.java @@ -0,0 +1,20 @@ +package com.gomo.app.common.util; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Component; + +@Component +public class PromptLoader { + public String loadPrompt(String promptPath) { + try { + ClassPathResource resource = new ClassPathResource("prompts/"+promptPath); + return Files.readString(resource.getFile().toPath(), StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException("Failed to load prompt: "+promptPath, e); + } + } +} diff --git a/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java b/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java index 21098463..ee99b748 100644 --- a/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java +++ b/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java @@ -1,4 +1,7 @@ package com.gomo.app.support.llm.application; -public record GenerateTextDto(String generatedText) { -} +import java.util.List; +import java.util.Map; + +public record GenerateTextDto(Map> generatedText) {} + diff --git a/src/main/java/com/gomo/app/support/llm/application/LlmClientPortOut.java b/src/main/java/com/gomo/app/support/llm/application/LlmClientPortOut.java new file mode 100644 index 00000000..c72d513d --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/application/LlmClientPortOut.java @@ -0,0 +1,14 @@ +package com.gomo.app.support.llm.application; + +import com.gomo.app.core.interest.application.port.dto.RegistrantDto; + +public interface LlmClientPortOut { + + /** + * Retrieves the essential details of a single registrant by id. + * + * @param {@link GenerateTextCommand} The information to generate Quests with LLM. + * @return A {@link GenerateTextDto} containing the GeneratedText data. + */ + GenerateTextDto generate(GenerateTextCommand command); +} diff --git a/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java index ab1aa6a1..9bcc020d 100644 --- a/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java +++ b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java @@ -6,7 +6,9 @@ public enum GenerateQuestErrorCode { GEMINI_API_ERROR(500, "QUE-GEN-001", "An error occurred while call GeminiAPI"), EMPTY_RESPONSE(500, "QUE-GEN-002", "Gemini API response blank"), - INVALID_RESPONSE_FORMAT(500, "QUE-GEN-003", "Gemini Response format is invalid"); + INVALID_RESPONSE_FORMAT(500, "QUE-GEN-003", "Gemini Response format is invalid"), + INVALID_JSON_FORMAT(500, "QUE-GEN-004", "Gemini Response JSON format is invalid"), + PARSING_ERROR(500, "QUE-GEN-005", "An error occurred while parse data String to Map"); private final int httpStatus; private final String errorCode; diff --git a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java index f325f9d4..0dc93c20 100644 --- a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java +++ b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java @@ -1,12 +1,23 @@ package com.gomo.app.support.llm.infrastructure; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.web.client.RestClient; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import com.gomo.app.common.arch.Adapter; +import com.gomo.app.common.util.PromptLoader; import com.gomo.app.support.llm.application.GenerateTextCommand; import com.gomo.app.support.llm.application.GenerateTextDto; +import com.gomo.app.support.llm.application.LlmClientPortOut; import com.gomo.app.support.llm.exception.GenerateQuestException; import com.gomo.app.support.llm.exception.GenerateQuestErrorCode; @@ -16,7 +27,7 @@ @RequiredArgsConstructor @Adapter @Slf4j -public class GeminiApiAdapter { +public class GeminiApiAdapter implements LlmClientPortOut { private final RestClient restClient; @Value("${spring.ai.openai.api-key}") @@ -25,6 +36,8 @@ public class GeminiApiAdapter { @Value("${spring.ai.openai.chat.options.model}") private String model; + private PromptLoader promptLoader; + private static final String GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions"; public GenerateTextDto generate(GenerateTextCommand command){ @@ -48,7 +61,7 @@ public GenerateTextDto generate(GenerateTextCommand command){ } private GeminiRequest createGeminiRequest(GenerateTextCommand command){ - return GeminiRequest.createPrompt(command.interests(), command.questType(), command.amount()); + return GeminiRequest.createPrompt(command.interests(), command.questType(), command.amount(), promptLoader); } private GenerateTextDto convertToGenerateTextDto(GeminiResponse response){ @@ -57,6 +70,30 @@ private GenerateTextDto convertToGenerateTextDto(GeminiResponse response){ } String generatedText = response.choices().get(0).message().content(); - return new GenerateTextDto(generatedText); + return new GenerateTextDto(parseDtofromText(generatedText)); + } + + private Map> parseDtofromText(String text){ + try{ + String cleanText = text.trim(); + + if (cleanText.startsWith("```json")) { + cleanText = cleanText.substring(7); + } + + if (cleanText.endsWith("```")){ + cleanText = cleanText.substring(0, cleanText.length()-3); + } + + cleanText = cleanText.trim(); + ObjectMapper objectMapper = new ObjectMapper(); + TypeReference>> typeRef = new TypeReference>>() {}; + + return objectMapper.readValue(cleanText, typeRef); + } catch (JsonProcessingException e){ + throw new GenerateQuestException(GenerateQuestErrorCode.INVALID_JSON_FORMAT); + } catch (Exception e){ + throw new GenerateQuestException(GenerateQuestErrorCode.PARSING_ERROR); + } } } diff --git a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java index 86938e19..68cfcae5 100644 --- a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java +++ b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java @@ -4,6 +4,7 @@ import java.util.Map; import java.util.stream.Collectors; +import com.gomo.app.common.util.PromptLoader; import com.gomo.app.core.quest.domain.model.quest.QuestType; public record GeminiRequest( @@ -11,30 +12,9 @@ public record GeminiRequest( String reasoning_effort, List messages ) { - private static Prompt createSystemPrompt(){ - return new Prompt("system", """ - 당신은 개인 맞춤형 도전 과제를 생성하는 전문가 입니다. 아래 가이드라인을 준수하여 도전 과제를 생성하세요. - - **도전 과제 생성 가이드라인** - #1. 아래 주어지는 ‘개인 정보’를 바탕으로 ‘도전 과제’를 생성합니다. - #1-1. ‘개인 정보’의 숙련도와 퀘스트 타입으로 ‘도전 과제’의 ‘소요 시간(분)’을 결정합니다. - #1-1-1. 숙련도는 0 - 100 사이의 정수입니다. - #1-1-2. 퀘스트 타입은 각각 Daily(30 - 90), Weekly(300 - 900), Monthly(1000 - 1500) 사이의 무작위 정수입니다. - #1-1-3. ‘도전 과제’의 ‘소요 시간(분)’은 연산식(숙련도 * 0.1 + 퀘스트 타입) 결과로 0 - 1510 사이의 정수입니다. - #1-2. ‘도전 과제’의 content는 ‘개인 정보’의 관심사와 연관된 목표입니다. - #1-2-1. content는 명확하고 구조적인 행동을 제시합니다. - #1-2-1-1. 문장 형식은 “진행합니다.” 가 아닌 “진행”과 같이 짧게 끝맺음한다. - #1-2-2. content는 실질적으로 ‘소요 시간(분)’ 이내에 달성 가능해야 합니다. - #1-2-2-1. 30 - 100 ex) “알고리즘 1문제 풀이”, “TIL 작성”, “기술 블로그 하나 정독” - #1-2-2-2. 300 - 910 ex) “기술 블로그 하나 작성”, “개인 프로젝트 pr 하나 작업”, “개인 프로젝트 로깅 시스템 점검” - #1-2-2-3. 1000 - 1510 ex) “서킷 브레이커 학습 후, 개인 프로젝트에 적용하기”, “오픈 소스 1회 기여하기”, “멀티 모듈 학습하고 토이 프로젝트 진행하기” - #2. ‘도전 과제’의 응답 형식은 반드시 JSON으로 작성해주세요. - #2-1. 생성된 도전과제는 30자 이내의 동사형으로 제시해주세요. - #2-2. 응답 형식 예시: { - ["관심사명" : [{ “content” : “[생성된 도전 과제]” }, ...],]} - #2-3. 이전 수행 퀘스트를 참고하여, 중복이 발생하지 않도록 제시해주세요. - #2-4. 각 관심사 별 퀘스트 수를 동일한 비율로 생성해 주세요. - """); + private static Prompt createSystemPrompt(PromptLoader promptLoader){ + String content = promptLoader.loadPrompt("quest/system-prompt.txt"); + return new Prompt("system", content); } private static Prompt createUserPrompt(Map interests, QuestType questType, int amount){ @@ -43,19 +23,14 @@ private static Prompt createUserPrompt(Map interests, QuestType qu .collect(Collectors.joining(", ")); String promptText = String.format( - """ - **개인 정보** - - 관심사: %s - - 퀘스트 타입: %s - - 퀘스트 수: %s - """, interestsText, questType.name(), amount + "**개인 정보**\n- 관심사: %s \n- 퀘스트 타입: %s \n- 퀘스트 수: %s", interestsText, questType.name(), amount ); return new Prompt("user", promptText); } - public static GeminiRequest createPrompt(Map interests, QuestType questType, int amount){ - Prompt system = createSystemPrompt(); + public static GeminiRequest createPrompt(Map interests, QuestType questType, int amount, PromptLoader promptLoader){ + Prompt system = createSystemPrompt(promptLoader); Prompt user = createUserPrompt(interests, questType, amount); return new GeminiRequest("gemini-2.5-flash", "none", List.of(system, user)); } diff --git a/src/main/resources/prompt/system-prompt.txt b/src/main/resources/prompt/system-prompt.txt new file mode 100644 index 00000000..4841d837 --- /dev/null +++ b/src/main/resources/prompt/system-prompt.txt @@ -0,0 +1 @@ +# 역할: 당신은 개인 맞춤형 도전 과제(퀘스트)를 생성하는 AI 전문가입니다.\n# 목표: 주어진 '개인 정보'와 '요청'을 바탕으로, 아래 명시된 '출력 형식'을 반드시 준수하여 사용자를 위한 도전 과제를 생성합니다.\n\n## 도전 과제 생성 가이드라인\n1. 내용 생성 (Content Generation)\n- 개인화: '개인 정보'의 '관심사'와 '숙련도'를 바탕으로 도전 과제를 생성합니다.\n- 소요 시간: '퀘스트 타입'과 '숙련도'를 고려하여, 현실적으로 달성 가능한 분량의 과제를 제안합니다.\n-- Daily (30-90분): e.g., \"알고리즘 1문제 풀이\", \"TIL 작성\", \"기술 블로그 1개 정독\"\n-- Weekly (300-900분): e.g., \"기술 블로그 1개 작성\", \"개인 프로젝트 PR 1개 작업\", \"개인 프로젝트 로깅 시스템 점검\"\n-- Monthly (1000-1500분): e.g., \"서킷 브레이커 학습 후 개인 프로젝트에 적용\", \"오픈 소스 1회 기여\", \"멀티 모듈 학습 및 토이 프로젝트 진행\"\n- 문체: 내용은 30자 이내의 간결한 명사형 또는 동사형으로 끝맺습니다. (e.g., \"알고리즘 문제 풀이\", \"기술 블로그 작성\")\n\n2. 생성 규칙 (Generation Rules)\n- 고유성: '이전 수행 퀘스트' 목록을 참고하여, 중복된 과제를 생성하지 않습니다.\n- 균형: 요청된 각 '관심사'에 대해 동일한 개수의 과제를 생성해야 합니다.\n\n## 출력 형식 (Output Format)\n- [중요] 반드시 아래 명시된 JSON 형식으로만 응답해야 합니다.\n- JSON 구조:\n-- Key: '관심사' 이름 (String)\n-- Value: 해당 관심사에 대한 도전 과제 목록 (Array)\n- JSON 출력 예시:\n```json\n{\n\"알고리즘\": [\n\"백준 골드 IV 문제 풀이\",\n\"해시 테이블 개념 정리 및 블로깅\"\n],\n\"백엔드\": [\n\"Spring Security 적용하여 JWT 인증 구현\",\n\"JPA N+1 문제 원인 분석 및 해결\"\n]\n}\n``` \ No newline at end of file From d53c9e925a660a599da3f0490f8c982436d0be6d Mon Sep 17 00:00:00 2001 From: nurdy-kim Date: Mon, 13 Oct 2025 14:59:06 +0900 Subject: [PATCH 05/16] =?UTF-8?q?feat:=20=ED=80=98=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20LLM=20=EB=A7=88=EC=9D=B4=EA=B7=B8=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GeminiGenerateTextUseCase.java | 9 ++- .../llm/application/GenerateTextCommand.java | 9 ++- .../llm/application/GenerateTextDto.java | 2 +- .../llm/exception/GenerateQuestErrorCode.java | 21 ++++++ .../llm/exception/GenerateQuestException.java | 13 ++++ .../llm/infrastructure/GeminiApiAdapter.java | 62 ++++++++++++++++++ .../llm/infrastructure/GeminiRequest.java | 64 +++++++++++++++++++ .../llm/infrastructure/GeminiResponse.java | 18 ++++++ 8 files changed, 194 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java create mode 100644 src/main/java/com/gomo/app/support/llm/exception/GenerateQuestException.java create mode 100644 src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java create mode 100644 src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java create mode 100644 src/main/java/com/gomo/app/support/llm/infrastructure/GeminiResponse.java diff --git a/src/main/java/com/gomo/app/support/llm/application/GeminiGenerateTextUseCase.java b/src/main/java/com/gomo/app/support/llm/application/GeminiGenerateTextUseCase.java index f9bdc4f5..701f67ea 100644 --- a/src/main/java/com/gomo/app/support/llm/application/GeminiGenerateTextUseCase.java +++ b/src/main/java/com/gomo/app/support/llm/application/GeminiGenerateTextUseCase.java @@ -1,13 +1,18 @@ package com.gomo.app.support.llm.application; import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.support.llm.infrastructure.GeminiApiAdapter; + +import lombok.RequiredArgsConstructor; @ApplicationService +@RequiredArgsConstructor class GeminiGenerateTextUseCase implements GenerateTextPortIn { + private final GeminiApiAdapter geminiApiAdapter; + @Override public GenerateTextDto generate(GenerateTextCommand command) { - // todo nurdy: 기존 py 기반 llm 호출 로직 마이그레이션 필요 - return null; + return geminiApiAdapter.generate(command); } } diff --git a/src/main/java/com/gomo/app/support/llm/application/GenerateTextCommand.java b/src/main/java/com/gomo/app/support/llm/application/GenerateTextCommand.java index 1c5ef221..baff3404 100644 --- a/src/main/java/com/gomo/app/support/llm/application/GenerateTextCommand.java +++ b/src/main/java/com/gomo/app/support/llm/application/GenerateTextCommand.java @@ -1,4 +1,11 @@ package com.gomo.app.support.llm.application; -public record GenerateTextCommand() { +import java.util.Map; + +import com.gomo.app.core.quest.domain.model.quest.QuestType; + +public record GenerateTextCommand(Map interests, QuestType questType, int amount) { + public static GenerateTextCommand of(Map interests, QuestType questType, int amount) { + return new GenerateTextCommand(interests, questType, amount); + } } diff --git a/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java b/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java index 8a275ead..21098463 100644 --- a/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java +++ b/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java @@ -1,4 +1,4 @@ package com.gomo.app.support.llm.application; -public record GenerateTextDto() { +public record GenerateTextDto(String generatedText) { } diff --git a/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java new file mode 100644 index 00000000..9cdf3167 --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java @@ -0,0 +1,21 @@ +package com.gomo.app.support.llm.exception; + +import lombok.Getter; + +@Getter +public enum GenerateQuestErrorCode { + GEMINI_API_ERROR(500, "QUE-GEN-001", "An error occurred while call GeminiAPI"), + EMPTY_RESPONSE(500, "QUE-GEN-002", "Gemini API response blank"), + INVALID_RESPONSE_FORMAT(500, "QUE-GEN-003", "Gemini Response format is invalid") + ; + + private final int httpStatus; + private final String errorCode; + private final String message; + + GenerateQuestErrorCode(int httpStatus, String errorCode, String message) { + this.httpStatus = httpStatus; + this.errorCode = errorCode; + this.message = message; + } +} diff --git a/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestException.java b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestException.java new file mode 100644 index 00000000..9879f9ea --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestException.java @@ -0,0 +1,13 @@ +package com.gomo.app.support.llm.exception; + +import com.gomo.app.common.exception.ApplicationException; + +public class GenerateQuestException extends ApplicationException { + public GenerateQuestException(GenerateQuestErrorCode errorCode){ + super(errorCode.getHttpStatus(), errorCode.name(), errorCode.getMessage()); + } + + public GenerateQuestException(GenerateQuestErrorCode errorCode, Throwable cause){ + super(errorCode.getHttpStatus(), errorCode.name(), errorCode.getMessage(), cause); + } +} diff --git a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java new file mode 100644 index 00000000..f325f9d4 --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java @@ -0,0 +1,62 @@ +package com.gomo.app.support.llm.infrastructure; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; +import org.springframework.web.client.RestClient; + +import com.gomo.app.common.arch.Adapter; +import com.gomo.app.support.llm.application.GenerateTextCommand; +import com.gomo.app.support.llm.application.GenerateTextDto; +import com.gomo.app.support.llm.exception.GenerateQuestException; +import com.gomo.app.support.llm.exception.GenerateQuestErrorCode; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@RequiredArgsConstructor +@Adapter +@Slf4j +public class GeminiApiAdapter { + private final RestClient restClient; + + @Value("${spring.ai.openai.api-key}") + private String apiKey; + + @Value("${spring.ai.openai.chat.options.model}") + private String model; + + private static final String GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions"; + + public GenerateTextDto generate(GenerateTextCommand command){ + try{ + String apiKey = "Bearer " + this.apiKey; + GeminiRequest request = createGeminiRequest(command); + + GeminiResponse response = restClient.post() + .uri(GEMINI_API_URL) + .header("Authorization", apiKey) + .contentType(MediaType.APPLICATION_JSON) + .body(request) + .retrieve() + .body(GeminiResponse.class); + + return convertToGenerateTextDto(response); + } catch (Exception e) { + log.error("Failed to generate text with Gemini API", e); + throw new RuntimeException("Gemini API 호출 중 오류가 발생 했습니다.", e); + } + } + + private GeminiRequest createGeminiRequest(GenerateTextCommand command){ + return GeminiRequest.createPrompt(command.interests(), command.questType(), command.amount()); + } + + private GenerateTextDto convertToGenerateTextDto(GeminiResponse response){ + if (response.choices() == null || response.choices().isEmpty()){ + throw new GenerateQuestException(GenerateQuestErrorCode.EMPTY_RESPONSE); + } + + String generatedText = response.choices().get(0).message().content(); + return new GenerateTextDto(generatedText); + } +} diff --git a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java new file mode 100644 index 00000000..86938e19 --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java @@ -0,0 +1,64 @@ +package com.gomo.app.support.llm.infrastructure; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.gomo.app.core.quest.domain.model.quest.QuestType; + +public record GeminiRequest( + String model, + String reasoning_effort, + List messages +) { + private static Prompt createSystemPrompt(){ + return new Prompt("system", """ + 당신은 개인 맞춤형 도전 과제를 생성하는 전문가 입니다. 아래 가이드라인을 준수하여 도전 과제를 생성하세요. + + **도전 과제 생성 가이드라인** + #1. 아래 주어지는 ‘개인 정보’를 바탕으로 ‘도전 과제’를 생성합니다. + #1-1. ‘개인 정보’의 숙련도와 퀘스트 타입으로 ‘도전 과제’의 ‘소요 시간(분)’을 결정합니다. + #1-1-1. 숙련도는 0 - 100 사이의 정수입니다. + #1-1-2. 퀘스트 타입은 각각 Daily(30 - 90), Weekly(300 - 900), Monthly(1000 - 1500) 사이의 무작위 정수입니다. + #1-1-3. ‘도전 과제’의 ‘소요 시간(분)’은 연산식(숙련도 * 0.1 + 퀘스트 타입) 결과로 0 - 1510 사이의 정수입니다. + #1-2. ‘도전 과제’의 content는 ‘개인 정보’의 관심사와 연관된 목표입니다. + #1-2-1. content는 명확하고 구조적인 행동을 제시합니다. + #1-2-1-1. 문장 형식은 “진행합니다.” 가 아닌 “진행”과 같이 짧게 끝맺음한다. + #1-2-2. content는 실질적으로 ‘소요 시간(분)’ 이내에 달성 가능해야 합니다. + #1-2-2-1. 30 - 100 ex) “알고리즘 1문제 풀이”, “TIL 작성”, “기술 블로그 하나 정독” + #1-2-2-2. 300 - 910 ex) “기술 블로그 하나 작성”, “개인 프로젝트 pr 하나 작업”, “개인 프로젝트 로깅 시스템 점검” + #1-2-2-3. 1000 - 1510 ex) “서킷 브레이커 학습 후, 개인 프로젝트에 적용하기”, “오픈 소스 1회 기여하기”, “멀티 모듈 학습하고 토이 프로젝트 진행하기” + #2. ‘도전 과제’의 응답 형식은 반드시 JSON으로 작성해주세요. + #2-1. 생성된 도전과제는 30자 이내의 동사형으로 제시해주세요. + #2-2. 응답 형식 예시: { + ["관심사명" : [{ “content” : “[생성된 도전 과제]” }, ...],]} + #2-3. 이전 수행 퀘스트를 참고하여, 중복이 발생하지 않도록 제시해주세요. + #2-4. 각 관심사 별 퀘스트 수를 동일한 비율로 생성해 주세요. + """); + } + + private static Prompt createUserPrompt(Map interests, QuestType questType, int amount){ + String interestsText = interests.entrySet().stream() + .map(entry -> entry.getKey() + "(숙련도 : " + entry.getValue() + ")") + .collect(Collectors.joining(", ")); + + String promptText = String.format( + """ + **개인 정보** + - 관심사: %s + - 퀘스트 타입: %s + - 퀘스트 수: %s + """, interestsText, questType.name(), amount + ); + + return new Prompt("user", promptText); + } + + public static GeminiRequest createPrompt(Map interests, QuestType questType, int amount){ + Prompt system = createSystemPrompt(); + Prompt user = createUserPrompt(interests, questType, amount); + return new GeminiRequest("gemini-2.5-flash", "none", List.of(system, user)); + } + + public record Prompt(String role, String content){} +} \ No newline at end of file diff --git a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiResponse.java b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiResponse.java new file mode 100644 index 00000000..587512a9 --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiResponse.java @@ -0,0 +1,18 @@ +package com.gomo.app.support.llm.infrastructure; + +import java.util.List; + +public record GeminiResponse( + List choices, + int created, + String id, + String model, + String object, + GeminiUsage usage +) { + public record Choice(String finish_reason, int index, Message message){} + public record Message(String content, String role){} + public record GeminiUsage(int completion_tokens, int prompt_tokens, int total_tokens){} +} + + From db1bd167cd41cc06fe2e34bd519dd597c9b78731 Mon Sep 17 00:00:00 2001 From: nurdy-kim Date: Sun, 19 Oct 2025 20:27:35 +0900 Subject: [PATCH 06/16] =?UTF-8?q?fix:=20style=20error=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gomo/app/support/llm/exception/GenerateQuestErrorCode.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java index 9cdf3167..ab1aa6a1 100644 --- a/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java +++ b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java @@ -6,8 +6,7 @@ public enum GenerateQuestErrorCode { GEMINI_API_ERROR(500, "QUE-GEN-001", "An error occurred while call GeminiAPI"), EMPTY_RESPONSE(500, "QUE-GEN-002", "Gemini API response blank"), - INVALID_RESPONSE_FORMAT(500, "QUE-GEN-003", "Gemini Response format is invalid") - ; + INVALID_RESPONSE_FORMAT(500, "QUE-GEN-003", "Gemini Response format is invalid"); private final int httpStatus; private final String errorCode; From 826c1b13c6910ed574fcfad88a8924ef4157f1bb Mon Sep 17 00:00:00 2001 From: nurdy-kim Date: Mon, 20 Oct 2025 13:12:20 +0900 Subject: [PATCH 07/16] =?UTF-8?q?feat:=20=EB=A6=AC=EB=B7=B0=20=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EB=B0=98=EC=98=81(prompt=20=EB=B3=84=EB=8F=84=20te?= =?UTF-8?q?xt=20=ED=8C=8C=EC=9D=BC,=20LlmClientPortOut=20interface=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1,=20Style=20=EC=98=A4=EB=A5=98=20=EB=93=B1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gomo/app/common/util/PromptLoader.java | 20 +++++++++ .../llm/application/GenerateTextDto.java | 7 ++- .../llm/application/LlmClientPortOut.java | 14 ++++++ .../llm/exception/GenerateQuestErrorCode.java | 4 +- .../llm/infrastructure/GeminiApiAdapter.java | 43 +++++++++++++++++-- .../llm/infrastructure/GeminiRequest.java | 39 +++-------------- src/main/resources/prompt/system-prompt.txt | 1 + 7 files changed, 90 insertions(+), 38 deletions(-) create mode 100644 src/main/java/com/gomo/app/common/util/PromptLoader.java create mode 100644 src/main/java/com/gomo/app/support/llm/application/LlmClientPortOut.java create mode 100644 src/main/resources/prompt/system-prompt.txt diff --git a/src/main/java/com/gomo/app/common/util/PromptLoader.java b/src/main/java/com/gomo/app/common/util/PromptLoader.java new file mode 100644 index 00000000..1f5c6ca1 --- /dev/null +++ b/src/main/java/com/gomo/app/common/util/PromptLoader.java @@ -0,0 +1,20 @@ +package com.gomo.app.common.util; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Component; + +@Component +public class PromptLoader { + public String loadPrompt(String promptPath) { + try { + ClassPathResource resource = new ClassPathResource("prompts/"+promptPath); + return Files.readString(resource.getFile().toPath(), StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException("Failed to load prompt: "+promptPath, e); + } + } +} diff --git a/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java b/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java index 21098463..ee99b748 100644 --- a/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java +++ b/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java @@ -1,4 +1,7 @@ package com.gomo.app.support.llm.application; -public record GenerateTextDto(String generatedText) { -} +import java.util.List; +import java.util.Map; + +public record GenerateTextDto(Map> generatedText) {} + diff --git a/src/main/java/com/gomo/app/support/llm/application/LlmClientPortOut.java b/src/main/java/com/gomo/app/support/llm/application/LlmClientPortOut.java new file mode 100644 index 00000000..c72d513d --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/application/LlmClientPortOut.java @@ -0,0 +1,14 @@ +package com.gomo.app.support.llm.application; + +import com.gomo.app.core.interest.application.port.dto.RegistrantDto; + +public interface LlmClientPortOut { + + /** + * Retrieves the essential details of a single registrant by id. + * + * @param {@link GenerateTextCommand} The information to generate Quests with LLM. + * @return A {@link GenerateTextDto} containing the GeneratedText data. + */ + GenerateTextDto generate(GenerateTextCommand command); +} diff --git a/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java index ab1aa6a1..9bcc020d 100644 --- a/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java +++ b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java @@ -6,7 +6,9 @@ public enum GenerateQuestErrorCode { GEMINI_API_ERROR(500, "QUE-GEN-001", "An error occurred while call GeminiAPI"), EMPTY_RESPONSE(500, "QUE-GEN-002", "Gemini API response blank"), - INVALID_RESPONSE_FORMAT(500, "QUE-GEN-003", "Gemini Response format is invalid"); + INVALID_RESPONSE_FORMAT(500, "QUE-GEN-003", "Gemini Response format is invalid"), + INVALID_JSON_FORMAT(500, "QUE-GEN-004", "Gemini Response JSON format is invalid"), + PARSING_ERROR(500, "QUE-GEN-005", "An error occurred while parse data String to Map"); private final int httpStatus; private final String errorCode; diff --git a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java index f325f9d4..0dc93c20 100644 --- a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java +++ b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java @@ -1,12 +1,23 @@ package com.gomo.app.support.llm.infrastructure; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.web.client.RestClient; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import com.gomo.app.common.arch.Adapter; +import com.gomo.app.common.util.PromptLoader; import com.gomo.app.support.llm.application.GenerateTextCommand; import com.gomo.app.support.llm.application.GenerateTextDto; +import com.gomo.app.support.llm.application.LlmClientPortOut; import com.gomo.app.support.llm.exception.GenerateQuestException; import com.gomo.app.support.llm.exception.GenerateQuestErrorCode; @@ -16,7 +27,7 @@ @RequiredArgsConstructor @Adapter @Slf4j -public class GeminiApiAdapter { +public class GeminiApiAdapter implements LlmClientPortOut { private final RestClient restClient; @Value("${spring.ai.openai.api-key}") @@ -25,6 +36,8 @@ public class GeminiApiAdapter { @Value("${spring.ai.openai.chat.options.model}") private String model; + private PromptLoader promptLoader; + private static final String GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions"; public GenerateTextDto generate(GenerateTextCommand command){ @@ -48,7 +61,7 @@ public GenerateTextDto generate(GenerateTextCommand command){ } private GeminiRequest createGeminiRequest(GenerateTextCommand command){ - return GeminiRequest.createPrompt(command.interests(), command.questType(), command.amount()); + return GeminiRequest.createPrompt(command.interests(), command.questType(), command.amount(), promptLoader); } private GenerateTextDto convertToGenerateTextDto(GeminiResponse response){ @@ -57,6 +70,30 @@ private GenerateTextDto convertToGenerateTextDto(GeminiResponse response){ } String generatedText = response.choices().get(0).message().content(); - return new GenerateTextDto(generatedText); + return new GenerateTextDto(parseDtofromText(generatedText)); + } + + private Map> parseDtofromText(String text){ + try{ + String cleanText = text.trim(); + + if (cleanText.startsWith("```json")) { + cleanText = cleanText.substring(7); + } + + if (cleanText.endsWith("```")){ + cleanText = cleanText.substring(0, cleanText.length()-3); + } + + cleanText = cleanText.trim(); + ObjectMapper objectMapper = new ObjectMapper(); + TypeReference>> typeRef = new TypeReference>>() {}; + + return objectMapper.readValue(cleanText, typeRef); + } catch (JsonProcessingException e){ + throw new GenerateQuestException(GenerateQuestErrorCode.INVALID_JSON_FORMAT); + } catch (Exception e){ + throw new GenerateQuestException(GenerateQuestErrorCode.PARSING_ERROR); + } } } diff --git a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java index 86938e19..68cfcae5 100644 --- a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java +++ b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java @@ -4,6 +4,7 @@ import java.util.Map; import java.util.stream.Collectors; +import com.gomo.app.common.util.PromptLoader; import com.gomo.app.core.quest.domain.model.quest.QuestType; public record GeminiRequest( @@ -11,30 +12,9 @@ public record GeminiRequest( String reasoning_effort, List messages ) { - private static Prompt createSystemPrompt(){ - return new Prompt("system", """ - 당신은 개인 맞춤형 도전 과제를 생성하는 전문가 입니다. 아래 가이드라인을 준수하여 도전 과제를 생성하세요. - - **도전 과제 생성 가이드라인** - #1. 아래 주어지는 ‘개인 정보’를 바탕으로 ‘도전 과제’를 생성합니다. - #1-1. ‘개인 정보’의 숙련도와 퀘스트 타입으로 ‘도전 과제’의 ‘소요 시간(분)’을 결정합니다. - #1-1-1. 숙련도는 0 - 100 사이의 정수입니다. - #1-1-2. 퀘스트 타입은 각각 Daily(30 - 90), Weekly(300 - 900), Monthly(1000 - 1500) 사이의 무작위 정수입니다. - #1-1-3. ‘도전 과제’의 ‘소요 시간(분)’은 연산식(숙련도 * 0.1 + 퀘스트 타입) 결과로 0 - 1510 사이의 정수입니다. - #1-2. ‘도전 과제’의 content는 ‘개인 정보’의 관심사와 연관된 목표입니다. - #1-2-1. content는 명확하고 구조적인 행동을 제시합니다. - #1-2-1-1. 문장 형식은 “진행합니다.” 가 아닌 “진행”과 같이 짧게 끝맺음한다. - #1-2-2. content는 실질적으로 ‘소요 시간(분)’ 이내에 달성 가능해야 합니다. - #1-2-2-1. 30 - 100 ex) “알고리즘 1문제 풀이”, “TIL 작성”, “기술 블로그 하나 정독” - #1-2-2-2. 300 - 910 ex) “기술 블로그 하나 작성”, “개인 프로젝트 pr 하나 작업”, “개인 프로젝트 로깅 시스템 점검” - #1-2-2-3. 1000 - 1510 ex) “서킷 브레이커 학습 후, 개인 프로젝트에 적용하기”, “오픈 소스 1회 기여하기”, “멀티 모듈 학습하고 토이 프로젝트 진행하기” - #2. ‘도전 과제’의 응답 형식은 반드시 JSON으로 작성해주세요. - #2-1. 생성된 도전과제는 30자 이내의 동사형으로 제시해주세요. - #2-2. 응답 형식 예시: { - ["관심사명" : [{ “content” : “[생성된 도전 과제]” }, ...],]} - #2-3. 이전 수행 퀘스트를 참고하여, 중복이 발생하지 않도록 제시해주세요. - #2-4. 각 관심사 별 퀘스트 수를 동일한 비율로 생성해 주세요. - """); + private static Prompt createSystemPrompt(PromptLoader promptLoader){ + String content = promptLoader.loadPrompt("quest/system-prompt.txt"); + return new Prompt("system", content); } private static Prompt createUserPrompt(Map interests, QuestType questType, int amount){ @@ -43,19 +23,14 @@ private static Prompt createUserPrompt(Map interests, QuestType qu .collect(Collectors.joining(", ")); String promptText = String.format( - """ - **개인 정보** - - 관심사: %s - - 퀘스트 타입: %s - - 퀘스트 수: %s - """, interestsText, questType.name(), amount + "**개인 정보**\n- 관심사: %s \n- 퀘스트 타입: %s \n- 퀘스트 수: %s", interestsText, questType.name(), amount ); return new Prompt("user", promptText); } - public static GeminiRequest createPrompt(Map interests, QuestType questType, int amount){ - Prompt system = createSystemPrompt(); + public static GeminiRequest createPrompt(Map interests, QuestType questType, int amount, PromptLoader promptLoader){ + Prompt system = createSystemPrompt(promptLoader); Prompt user = createUserPrompt(interests, questType, amount); return new GeminiRequest("gemini-2.5-flash", "none", List.of(system, user)); } diff --git a/src/main/resources/prompt/system-prompt.txt b/src/main/resources/prompt/system-prompt.txt new file mode 100644 index 00000000..4841d837 --- /dev/null +++ b/src/main/resources/prompt/system-prompt.txt @@ -0,0 +1 @@ +# 역할: 당신은 개인 맞춤형 도전 과제(퀘스트)를 생성하는 AI 전문가입니다.\n# 목표: 주어진 '개인 정보'와 '요청'을 바탕으로, 아래 명시된 '출력 형식'을 반드시 준수하여 사용자를 위한 도전 과제를 생성합니다.\n\n## 도전 과제 생성 가이드라인\n1. 내용 생성 (Content Generation)\n- 개인화: '개인 정보'의 '관심사'와 '숙련도'를 바탕으로 도전 과제를 생성합니다.\n- 소요 시간: '퀘스트 타입'과 '숙련도'를 고려하여, 현실적으로 달성 가능한 분량의 과제를 제안합니다.\n-- Daily (30-90분): e.g., \"알고리즘 1문제 풀이\", \"TIL 작성\", \"기술 블로그 1개 정독\"\n-- Weekly (300-900분): e.g., \"기술 블로그 1개 작성\", \"개인 프로젝트 PR 1개 작업\", \"개인 프로젝트 로깅 시스템 점검\"\n-- Monthly (1000-1500분): e.g., \"서킷 브레이커 학습 후 개인 프로젝트에 적용\", \"오픈 소스 1회 기여\", \"멀티 모듈 학습 및 토이 프로젝트 진행\"\n- 문체: 내용은 30자 이내의 간결한 명사형 또는 동사형으로 끝맺습니다. (e.g., \"알고리즘 문제 풀이\", \"기술 블로그 작성\")\n\n2. 생성 규칙 (Generation Rules)\n- 고유성: '이전 수행 퀘스트' 목록을 참고하여, 중복된 과제를 생성하지 않습니다.\n- 균형: 요청된 각 '관심사'에 대해 동일한 개수의 과제를 생성해야 합니다.\n\n## 출력 형식 (Output Format)\n- [중요] 반드시 아래 명시된 JSON 형식으로만 응답해야 합니다.\n- JSON 구조:\n-- Key: '관심사' 이름 (String)\n-- Value: 해당 관심사에 대한 도전 과제 목록 (Array)\n- JSON 출력 예시:\n```json\n{\n\"알고리즘\": [\n\"백준 골드 IV 문제 풀이\",\n\"해시 테이블 개념 정리 및 블로깅\"\n],\n\"백엔드\": [\n\"Spring Security 적용하여 JWT 인증 구현\",\n\"JPA N+1 문제 원인 분석 및 해결\"\n]\n}\n``` \ No newline at end of file From 3c496adf08cb384811c92dd906ab43cecb4f1fd5 Mon Sep 17 00:00:00 2001 From: Kang-Jin Kim Date: Mon, 3 Nov 2025 14:30:57 +0900 Subject: [PATCH 08/16] =?UTF-8?q?feat:=20=EB=A6=AC=EB=B7=B0=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=EC=82=AC=ED=95=AD=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GeminiGenerateTextUseCase.java | 5 +-- .../llm/exception/GenerateQuestErrorCode.java | 22 ---------- .../support/llm/exception/LlmErrorCode.java | 22 ++++++++++ ...eQuestException.java => LlmException.java} | 6 +-- .../llm/infrastructure/GeminiApiAdapter.java | 44 +++++++++---------- .../llm/infrastructure/GeminiRequest.java | 2 +- .../llm/infrastructure/GeminiResponse.java | 37 ++++++++++++++-- .../llm}/util/PromptLoader.java | 6 +-- 8 files changed, 86 insertions(+), 58 deletions(-) delete mode 100644 src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java create mode 100644 src/main/java/com/gomo/app/support/llm/exception/LlmErrorCode.java rename src/main/java/com/gomo/app/support/llm/exception/{GenerateQuestException.java => LlmException.java} (56%) rename src/main/java/com/gomo/app/{common => support/llm}/util/PromptLoader.java (78%) diff --git a/src/main/java/com/gomo/app/support/llm/application/GeminiGenerateTextUseCase.java b/src/main/java/com/gomo/app/support/llm/application/GeminiGenerateTextUseCase.java index 701f67ea..9f711d31 100644 --- a/src/main/java/com/gomo/app/support/llm/application/GeminiGenerateTextUseCase.java +++ b/src/main/java/com/gomo/app/support/llm/application/GeminiGenerateTextUseCase.java @@ -1,7 +1,6 @@ package com.gomo.app.support.llm.application; import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.support.llm.infrastructure.GeminiApiAdapter; import lombok.RequiredArgsConstructor; @@ -9,10 +8,10 @@ @RequiredArgsConstructor class GeminiGenerateTextUseCase implements GenerateTextPortIn { - private final GeminiApiAdapter geminiApiAdapter; + private final LlmClientPortOut llmClientPortOut; @Override public GenerateTextDto generate(GenerateTextCommand command) { - return geminiApiAdapter.generate(command); + return llmClientPortOut.generate(command); } } diff --git a/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java deleted file mode 100644 index 9bcc020d..00000000 --- a/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.gomo.app.support.llm.exception; - -import lombok.Getter; - -@Getter -public enum GenerateQuestErrorCode { - GEMINI_API_ERROR(500, "QUE-GEN-001", "An error occurred while call GeminiAPI"), - EMPTY_RESPONSE(500, "QUE-GEN-002", "Gemini API response blank"), - INVALID_RESPONSE_FORMAT(500, "QUE-GEN-003", "Gemini Response format is invalid"), - INVALID_JSON_FORMAT(500, "QUE-GEN-004", "Gemini Response JSON format is invalid"), - PARSING_ERROR(500, "QUE-GEN-005", "An error occurred while parse data String to Map"); - - private final int httpStatus; - private final String errorCode; - private final String message; - - GenerateQuestErrorCode(int httpStatus, String errorCode, String message) { - this.httpStatus = httpStatus; - this.errorCode = errorCode; - this.message = message; - } -} diff --git a/src/main/java/com/gomo/app/support/llm/exception/LlmErrorCode.java b/src/main/java/com/gomo/app/support/llm/exception/LlmErrorCode.java new file mode 100644 index 00000000..4d8e9036 --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/exception/LlmErrorCode.java @@ -0,0 +1,22 @@ +package com.gomo.app.support.llm.exception; + +import lombok.Getter; + +@Getter +public enum LlmErrorCode { + GEMINI_API_ERROR(500, "LLM-GEN-001", "An error occurred while call GeminiAPI"), + EMPTY_RESPONSE(500, "LLM-GEN-002", "Gemini API response blank"), + INVALID_RESPONSE_FORMAT(500, "LLM-GEN-003", "Gemini Response format is invalid"), + INVALID_JSON_FORMAT(500, "LLM-GEN-004", "Gemini Response JSON format is invalid"), + PARSING_ERROR(500, "LLM-GEN-005", "An error occurred while parse data String to Map"); + + private final int httpStatus; + private final String errorCode; + private final String message; + + LlmErrorCode(int httpStatus, String errorCode, String message) { + this.httpStatus = httpStatus; + this.errorCode = errorCode; + this.message = message; + } +} diff --git a/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestException.java b/src/main/java/com/gomo/app/support/llm/exception/LlmException.java similarity index 56% rename from src/main/java/com/gomo/app/support/llm/exception/GenerateQuestException.java rename to src/main/java/com/gomo/app/support/llm/exception/LlmException.java index 9879f9ea..a47efd1e 100644 --- a/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestException.java +++ b/src/main/java/com/gomo/app/support/llm/exception/LlmException.java @@ -2,12 +2,12 @@ import com.gomo.app.common.exception.ApplicationException; -public class GenerateQuestException extends ApplicationException { - public GenerateQuestException(GenerateQuestErrorCode errorCode){ +public class LlmException extends ApplicationException { + public LlmException(LlmErrorCode errorCode) { super(errorCode.getHttpStatus(), errorCode.name(), errorCode.getMessage()); } - public GenerateQuestException(GenerateQuestErrorCode errorCode, Throwable cause){ + public LlmException(LlmErrorCode errorCode, Throwable cause) { super(errorCode.getHttpStatus(), errorCode.name(), errorCode.getMessage(), cause); } } diff --git a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java index 0dc93c20..86440dca 100644 --- a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java +++ b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java @@ -1,10 +1,7 @@ package com.gomo.app.support.llm.infrastructure; -import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; @@ -14,20 +11,20 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.gomo.app.common.arch.Adapter; -import com.gomo.app.common.util.PromptLoader; import com.gomo.app.support.llm.application.GenerateTextCommand; import com.gomo.app.support.llm.application.GenerateTextDto; import com.gomo.app.support.llm.application.LlmClientPortOut; -import com.gomo.app.support.llm.exception.GenerateQuestException; -import com.gomo.app.support.llm.exception.GenerateQuestErrorCode; +import com.gomo.app.support.llm.exception.LlmErrorCode; +import com.gomo.app.support.llm.exception.LlmException; +import com.gomo.app.support.llm.util.PromptLoader; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @RequiredArgsConstructor -@Adapter @Slf4j -public class GeminiApiAdapter implements LlmClientPortOut { +@Adapter +class GeminiApiAdapter implements LlmClientPortOut { private final RestClient restClient; @Value("${spring.ai.openai.api-key}") @@ -40,8 +37,8 @@ public class GeminiApiAdapter implements LlmClientPortOut { private static final String GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions"; - public GenerateTextDto generate(GenerateTextCommand command){ - try{ + public GenerateTextDto generate(GenerateTextCommand command) { + try { String apiKey = "Bearer " + this.apiKey; GeminiRequest request = createGeminiRequest(command); @@ -60,40 +57,41 @@ public GenerateTextDto generate(GenerateTextCommand command){ } } - private GeminiRequest createGeminiRequest(GenerateTextCommand command){ + private GeminiRequest createGeminiRequest(GenerateTextCommand command) { return GeminiRequest.createPrompt(command.interests(), command.questType(), command.amount(), promptLoader); } - private GenerateTextDto convertToGenerateTextDto(GeminiResponse response){ - if (response.choices() == null || response.choices().isEmpty()){ - throw new GenerateQuestException(GenerateQuestErrorCode.EMPTY_RESPONSE); + private GenerateTextDto convertToGenerateTextDto(GeminiResponse response) { + if (response.choices() == null || response.choices().isEmpty()) { + throw new LlmException(LlmErrorCode.EMPTY_RESPONSE); } String generatedText = response.choices().get(0).message().content(); return new GenerateTextDto(parseDtofromText(generatedText)); } - private Map> parseDtofromText(String text){ - try{ + private Map> parseDtofromText(String text) { + try { String cleanText = text.trim(); if (cleanText.startsWith("```json")) { cleanText = cleanText.substring(7); } - if (cleanText.endsWith("```")){ - cleanText = cleanText.substring(0, cleanText.length()-3); + if (cleanText.endsWith("```")) { + cleanText = cleanText.substring(0, cleanText.length() - 3); } cleanText = cleanText.trim(); ObjectMapper objectMapper = new ObjectMapper(); - TypeReference>> typeRef = new TypeReference>>() {}; + TypeReference>> typeRef = new TypeReference>>() { + }; return objectMapper.readValue(cleanText, typeRef); - } catch (JsonProcessingException e){ - throw new GenerateQuestException(GenerateQuestErrorCode.INVALID_JSON_FORMAT); - } catch (Exception e){ - throw new GenerateQuestException(GenerateQuestErrorCode.PARSING_ERROR); + } catch (JsonProcessingException e) { + throw new LlmException(LlmErrorCode.INVALID_JSON_FORMAT); + } catch (Exception e) { + throw new LlmException(LlmErrorCode.PARSING_ERROR); } } } diff --git a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java index 68cfcae5..30a17b24 100644 --- a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java +++ b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java @@ -4,7 +4,7 @@ import java.util.Map; import java.util.stream.Collectors; -import com.gomo.app.common.util.PromptLoader; +import com.gomo.app.support.llm.util.PromptLoader; import com.gomo.app.core.quest.domain.model.quest.QuestType; public record GeminiRequest( diff --git a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiResponse.java b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiResponse.java index 587512a9..4c6da3db 100644 --- a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiResponse.java +++ b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiResponse.java @@ -2,6 +2,15 @@ import java.util.List; +/** + * + * @param choices: a list of generated contents. normally returns 1 content. + * @param created: response created time. (Unix timestamp, unit: s) + * @param id: Unique ID. + * @param model: Gemini Model name who create response( normally: gemini-2.5-flash ) + * @param object: API response object specification string( normally: "chat.completion") + * @param usage: Total Usage. + */ public record GeminiResponse( List choices, int created, @@ -10,9 +19,31 @@ public record GeminiResponse( String object, GeminiUsage usage ) { - public record Choice(String finish_reason, int index, Message message){} - public record Message(String content, String role){} - public record GeminiUsage(int completion_tokens, int prompt_tokens, int total_tokens){} + /** + * + * @param finish_reason: reason which stopped model( ex: "stop", "length") + * @param index: index of Choice array. + * @param message: information of generated model (response and role) + */ + public record Choice(String finish_reason, int index, Message message) { + } + + /** + * + * @param content: generated text contents(in this project. generated quest) + * @param role: role ("user", "assistant") + */ + public record Message(String content, String role) { + } + + /** + * + * @param completion_tokens : Total usage to Response Token. + * @param prompt_tokens : Total usage to Prompt Token. + * @param total_tokens : Total usage of Token. + */ + public record GeminiUsage(int completion_tokens, int prompt_tokens, int total_tokens) { + } } diff --git a/src/main/java/com/gomo/app/common/util/PromptLoader.java b/src/main/java/com/gomo/app/support/llm/util/PromptLoader.java similarity index 78% rename from src/main/java/com/gomo/app/common/util/PromptLoader.java rename to src/main/java/com/gomo/app/support/llm/util/PromptLoader.java index 1f5c6ca1..9fd32f0e 100644 --- a/src/main/java/com/gomo/app/common/util/PromptLoader.java +++ b/src/main/java/com/gomo/app/support/llm/util/PromptLoader.java @@ -1,4 +1,4 @@ -package com.gomo.app.common.util; +package com.gomo.app.support.llm.util; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -11,10 +11,10 @@ public class PromptLoader { public String loadPrompt(String promptPath) { try { - ClassPathResource resource = new ClassPathResource("prompts/"+promptPath); + ClassPathResource resource = new ClassPathResource("prompts/" + promptPath); return Files.readString(resource.getFile().toPath(), StandardCharsets.UTF_8); } catch (IOException e) { - throw new RuntimeException("Failed to load prompt: "+promptPath, e); + throw new RuntimeException("Failed to load prompt: " + promptPath, e); } } } From 979f4683418b2077ea52369348966d56686b324b Mon Sep 17 00:00:00 2001 From: Junhyeok Lee Date: Mon, 27 Oct 2025 22:11:03 +0900 Subject: [PATCH 09/16] =?UTF-8?q?[GOMO-234]=20api=20=EB=AC=B8=EC=84=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#98)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: api 문서 수정 * fix: final 키워드 추가 * refactor: 테스트 이름 수정 * fix: http method 수정 --- src/docs/asciidoc/apis/auth-api.adoc | 66 ---------------- src/docs/asciidoc/apis/member-api.adoc | 78 +++++++++++++++++-- .../member/presentation/EmailCodeApi.java | 6 +- .../request/ResetPasswordRequest.java | 6 +- .../VerifyEmailAuthCodeDocumentationTest.java | 11 ++- .../snippet/VerifyEmailAuthCodeSnippet.java | 11 ++- .../adapter/RabbitMQClientTest.java | 2 +- 7 files changed, 88 insertions(+), 92 deletions(-) diff --git a/src/docs/asciidoc/apis/auth-api.adoc b/src/docs/asciidoc/apis/auth-api.adoc index 0c37c6de..fc5e482f 100644 --- a/src/docs/asciidoc/apis/auth-api.adoc +++ b/src/docs/asciidoc/apis/auth-api.adoc @@ -65,69 +65,3 @@ operation::auth-update-refresh-token[snippets='http-response,response-fields'] // operation::auth-update-refresh-token-error[snippets='http-response,response-fields'] ''' - -=== 이메일 인증 코드 발송 (회원 가입) - -`POST /members/emails/codes/signup` - -회원가입에 사용할 이메일 인증 코드를 요청한 이메일 주소로 발송합니다. - -==== 요청 헤더 - -operation::member-email-auth-code-create[snippets='request-headers'] - -==== 요청 본문 (JSON) - -operation::member-email-auth-code-create[snippets='http-request,request-fields'] - -==== 성공 응답 - -성공 시 `201 Created` 상태 코드와 함께 빈 응답 본문을 반환합니다. - -==== 에러 응답 (이미 가입된 이메일) - -operation::member-email-auth-code-create-error[snippets='http-response,response-fields'] - -''' - -=== 이메일 인증 코드 발송 (비밀번호 변경 시) - -`POST /members/passwords/reset` - -비밀번호 찾기에 사용할 이메일 인증 코드를 요청한 이메일 주소로 발송합니다. - -==== 요청 헤더 - -operation::member-password-auth-code-create[snippets='request-headers'] - -==== 요청 본문 (JSON) - -operation::member-password-auth-code-create[snippets='http-request,request-fields'] - -==== 성공 응답 - -성공 시 `201 Created` 상태 코드와 함께 빈 응답 본문을 반환합니다. - -==== 에러 응답 (이미 가입된 이메일) - -operation::member-password-auth-code-create-error[snippets='http-response,response-fields'] - -''' - -=== 이메일 인증 코드 검증 - -`GET /members/emails/codes/verify` - -이메일로 발송된 인증 코드가 올바른지 검증합니다. - -==== 쿼리 파라미터 - -operation::member-email-auth-code-verify[snippets='query-parameters'] - -==== 성공 응답 - -인증 성공 시, `200 OK` 상태 코드와 함께 빈 응답 본문을 반환합니다. - -==== 에러 응답 (잘못된 인증 코드) - -operation::member-email-auth-code-verify-error[snippets='http-response,response-fields'] diff --git a/src/docs/asciidoc/apis/member-api.adoc b/src/docs/asciidoc/apis/member-api.adoc index 77c6b3c4..6fe67a39 100644 --- a/src/docs/asciidoc/apis/member-api.adoc +++ b/src/docs/asciidoc/apis/member-api.adoc @@ -183,9 +183,9 @@ operation::member-quest-property-read[snippets='request-headers'] operation::member-quest-property-read[snippets='http-response,response-fields'] -==== 에러 응답 - -operation::member-quest-property-read-error[snippets='http-response,response-fields'] +// ==== 에러 응답 +// +// operation::member-quest-property-read-error[snippets='http-response,response-fields'] ''' @@ -207,9 +207,9 @@ operation::member-password-reset[snippets='http-request,request-fields'] 성공 시 `204 No Content` 상태 코드와 함께 빈 응답 본문을 반환합니다. -==== 에러 응답 - -operation::member-password-reset-error[snippets='http-response,response-fields'] +// ==== 에러 응답 +// +// operation::member-password-reset-error[snippets='http-response,response-fields'] ''' @@ -328,3 +328,69 @@ operation::member-widget-update[snippets='http-request,request-fields'] // ==== 에러 응답 // // operation::member-quest-property-update-error[snippets='http-response,response-fields'] + +=== 이메일 인증 코드 발송 (회원 가입) + +`POST /members/emails/codes/signup` + +회원가입에 사용할 이메일 인증 코드를 요청한 이메일 주소로 발송합니다. + +==== 요청 헤더 + +operation::member-email-auth-code-create[snippets='request-headers'] + +==== 요청 본문 (JSON) + +operation::member-email-auth-code-create[snippets='http-request,request-fields'] + +==== 성공 응답 + +성공 시 `201 Created` 상태 코드와 함께 빈 응답 본문을 반환합니다. + +==== 에러 응답 (이미 가입된 이메일) + +operation::member-email-auth-code-create-error[snippets='http-response,response-fields'] + +''' + +=== 이메일 인증 코드 발송 (비밀번호 변경 시) + +`POST /members/emails/codes/passwords/reset` + +비밀번호 찾기에 사용할 이메일 인증 코드를 요청한 이메일 주소로 발송합니다. + +==== 요청 헤더 + +operation::member-password-auth-code-create[snippets='request-headers'] + +==== 요청 본문 (JSON) + +operation::member-password-auth-code-create[snippets='http-request,request-fields'] + +==== 성공 응답 + +성공 시 `201 Created` 상태 코드와 함께 빈 응답 본문을 반환합니다. + +==== 에러 응답 (이미 가입된 이메일) + +operation::member-password-auth-code-create-error[snippets='http-response,response-fields'] + +''' + +=== 이메일 인증 코드 검증 + +`GET /members/emails/codes/verify` + +이메일로 발송된 인증 코드가 올바른지 검증합니다. + +==== 쿼리 파라미터 + +operation::member-email-auth-code-verify[snippets='query-parameters'] + +==== 성공 응답 + +operation::member-email-auth-code-verify[snippets='http-response,response-fields'] + +==== 에러 응답 (잘못된 인증 코드) + +operation::member-email-auth-code-verify-error[snippets='http-response,response-fields'] diff --git a/src/main/java/com/gomo/app/core/member/presentation/EmailCodeApi.java b/src/main/java/com/gomo/app/core/member/presentation/EmailCodeApi.java index a2339140..859ff50f 100644 --- a/src/main/java/com/gomo/app/core/member/presentation/EmailCodeApi.java +++ b/src/main/java/com/gomo/app/core/member/presentation/EmailCodeApi.java @@ -2,8 +2,6 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -38,8 +36,8 @@ public ResponseEntity createForPassword(@RequestBody Cr return ResponseEntity.status(HttpStatus.CREATED).body(CreateEmailCodeResponse.of(emailCode)); } - @GetMapping("/verify") - public ResponseEntity verify(@ModelAttribute VerifyEmailCodeRequest request) { + @PostMapping("/verify") + public ResponseEntity verify(@RequestBody VerifyEmailCodeRequest request) { String temporaryToken = verifyEmailCodeUseCase.verify(request.getEmail(), request.getCode()); return ResponseEntity.status(HttpStatus.OK).body(VerifyEmailCodeResponse.of(temporaryToken)); } diff --git a/src/main/java/com/gomo/app/core/member/presentation/request/ResetPasswordRequest.java b/src/main/java/com/gomo/app/core/member/presentation/request/ResetPasswordRequest.java index c565638f..7b8a069f 100644 --- a/src/main/java/com/gomo/app/core/member/presentation/request/ResetPasswordRequest.java +++ b/src/main/java/com/gomo/app/core/member/presentation/request/ResetPasswordRequest.java @@ -5,9 +5,9 @@ @Getter public class ResetPasswordRequest { - private String email; - private String newPassword; - private String temporaryToken; + private final String email; + private final String newPassword; + private final String temporaryToken; private ResetPasswordRequest(String email, String newPassword, String temporaryToken) { this.email = email; diff --git a/src/test/java/com/gomo/app/core/member/documentation/VerifyEmailAuthCodeDocumentationTest.java b/src/test/java/com/gomo/app/core/member/documentation/VerifyEmailAuthCodeDocumentationTest.java index 697aaf69..63b9d056 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/VerifyEmailAuthCodeDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/member/documentation/VerifyEmailAuthCodeDocumentationTest.java @@ -13,6 +13,7 @@ import org.springframework.restdocs.restassured.RestDocumentationFilter; import com.gomo.app.core.member.documentation.snippet.VerifyEmailAuthCodeSnippet; +import com.gomo.app.core.member.presentation.request.VerifyEmailCodeRequest; import com.gomo.app.support.auth.application.port.CreateAuthCodePortIn; import com.gomo.app.support.auth.domain.repository.AuthCodeRepository; import com.gomo.app.support.auth.exception.AuthErrorCode; @@ -44,10 +45,9 @@ void verify_email_auth_code_with_correct_code() { String authCode = authCodeRepository.findByEmail(sessionEmail).get(); given(this.specification).filter(filter) .header(CONTENT_TYPE, APPLICATION_JSON_VALUE) - .param("email", sessionEmail) - .param("code", authCode) + .body(VerifyEmailCodeRequest.of(sessionEmail, authCode)) .when() - .get(URL) + .post(URL) .then() .statusCode(OK.value()); } @@ -57,10 +57,9 @@ void verify_email_auth_code_with_correct_code() { void verify_email_auth_code_with_incorrect_code() { given(this.specification).filter(errorFilter) .header(CONTENT_TYPE, APPLICATION_JSON_VALUE) - .param("email", sessionEmail) - .param("code", "00000") + .body(VerifyEmailCodeRequest.of(sessionEmail, "000000")) .when() - .get(URL) + .post(URL) .then() .statusCode(AuthErrorCode.INVALID_AUTH_CODE.getHttpStatus()) .body("timestamp", instanceOf(String.class)) diff --git a/src/test/java/com/gomo/app/core/member/documentation/snippet/VerifyEmailAuthCodeSnippet.java b/src/test/java/com/gomo/app/core/member/documentation/snippet/VerifyEmailAuthCodeSnippet.java index 543cb9d9..40f25e77 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/snippet/VerifyEmailAuthCodeSnippet.java +++ b/src/test/java/com/gomo/app/core/member/documentation/snippet/VerifyEmailAuthCodeSnippet.java @@ -2,7 +2,6 @@ import static org.springframework.restdocs.operation.preprocess.Preprocessors.*; import static org.springframework.restdocs.payload.PayloadDocumentation.*; -import static org.springframework.restdocs.request.RequestDocumentation.*; import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.*; import org.springframework.restdocs.payload.JsonFieldType; @@ -14,9 +13,9 @@ public class VerifyEmailAuthCodeSnippet { private static final String IDENTIFIER = "member-email-auth-code-verify"; - private static final Snippet QUERY_PARAMETERS = queryParameters( - parameterWithName("email").description("인증 코드를 받은 이메일 주소"), - parameterWithName("code").description("이메일로 발송된 인증 코드") + private static final Snippet REQUEST_FIELDS = requestFields( + fieldWithPath("email").description("인증 코드를 받은 이메일 주소"), + fieldWithPath("code").description("이메일로 발송된 인증 코드") ); private static final Snippet RESPONSE_FIELDS = responseFields( @@ -28,7 +27,7 @@ public static RestDocumentationFilter create() { IDENTIFIER, preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), - QUERY_PARAMETERS, + REQUEST_FIELDS, RESPONSE_FIELDS ); } @@ -38,7 +37,7 @@ public static RestDocumentationFilter createError() { IDENTIFIER + "-error", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), - QUERY_PARAMETERS, + REQUEST_FIELDS, ErrorResponseFields.RESPONSE_FIELDS ); } diff --git a/src/test/java/com/gomo/app/support/messagebroker/infrastructure/adapter/RabbitMQClientTest.java b/src/test/java/com/gomo/app/support/messagebroker/infrastructure/adapter/RabbitMQClientTest.java index 73d5377d..ba3f97c7 100644 --- a/src/test/java/com/gomo/app/support/messagebroker/infrastructure/adapter/RabbitMQClientTest.java +++ b/src/test/java/com/gomo/app/support/messagebroker/infrastructure/adapter/RabbitMQClientTest.java @@ -13,7 +13,7 @@ import com.gomo.app.test.WithRabbitMQ; import com.rabbitmq.client.ShutdownSignalException; -@DisplayName("[Infrastructure Integration]: RabbitMQ 접근 테스트") +@DisplayName("[Infrastructure Integration]: RabbitMQ 접근 테스트 (Flaky Test)") @IntegrationTest @WithRabbitMQ class RabbitMQClientTest { From 6670d714caac42f45b9b4d2904a566df2d3178ad Mon Sep 17 00:00:00 2001 From: Junhyeok Lee Date: Mon, 27 Oct 2025 22:17:46 +0900 Subject: [PATCH 10/16] =?UTF-8?q?[GOMO-235]=20=EC=9C=84=EC=A0=AF=20?= =?UTF-8?q?=EC=8A=A4=EB=83=85=EC=83=B7=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(#100)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix: 회원 조회 시, 위젯도 함께 조회하도록 수정 --- .../app/core/member/application/port/dto/MemberDto.java | 5 +++-- .../member/presentation/response/ReadMemberResponse.java | 7 +++++-- .../member/documentation/ReadMemberDocumentationTest.java | 3 ++- .../member/documentation/snippet/ReadMemberSnippet.java | 3 ++- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/gomo/app/core/member/application/port/dto/MemberDto.java b/src/main/java/com/gomo/app/core/member/application/port/dto/MemberDto.java index cf9a0414..abeeaf9c 100644 --- a/src/main/java/com/gomo/app/core/member/application/port/dto/MemberDto.java +++ b/src/main/java/com/gomo/app/core/member/application/port/dto/MemberDto.java @@ -7,7 +7,7 @@ public record MemberDto(UUID id, String email, String handle, String name, String motto, String profileImageUrl, String profileBannerUrl, String loginProvider, String roleType, String subscriptionPlan, String activateStatus, QuestPropertyDto questProperty, int availablePoints, - LocalDateTime signUpDateTime, LocalDateTime lastLoginDateTime, LocalDateTime deletedAt) { + LocalDateTime signUpDateTime, LocalDateTime lastLoginDateTime, LocalDateTime deletedAt, String widgetSnapshot) { public static MemberDto from(Member member, int availablePoints) { return new MemberDto( @@ -26,7 +26,8 @@ public static MemberDto from(Member member, int availablePoints) { availablePoints, member.getSignUpDateTime(), member.getLastLoginDateTime(), - member.getDeletedAt() + member.getDeletedAt(), + member.getWidget().getSnapshot() ); } } diff --git a/src/main/java/com/gomo/app/core/member/presentation/response/ReadMemberResponse.java b/src/main/java/com/gomo/app/core/member/presentation/response/ReadMemberResponse.java index 4253f2bc..75642d08 100644 --- a/src/main/java/com/gomo/app/core/member/presentation/response/ReadMemberResponse.java +++ b/src/main/java/com/gomo/app/core/member/presentation/response/ReadMemberResponse.java @@ -23,9 +23,10 @@ public class ReadMemberResponse { private final String subscriptionPlan; private final String activateStatus; private final LocalDateTime signUpDateTime; + private final String widgetSnapshot; private ReadMemberResponse(UUID id, String email, String handle, String name, String motto, int availablePoints, String profileImageUrl, String profileBannerUrl, - String loginProvider, String roleType, String subscriptionPlan, String activateStatus, LocalDateTime signUpDateTime) { + String loginProvider, String roleType, String subscriptionPlan, String activateStatus, LocalDateTime signUpDateTime, String widgetSnapshot) { this.id = id; this.email = email; this.handle = handle; @@ -39,6 +40,7 @@ private ReadMemberResponse(UUID id, String email, String handle, String name, St this.subscriptionPlan = subscriptionPlan; this.activateStatus = activateStatus; this.signUpDateTime = signUpDateTime; + this.widgetSnapshot = widgetSnapshot; } public static ReadMemberResponse of(MemberDto dto) { @@ -55,7 +57,8 @@ public static ReadMemberResponse of(MemberDto dto) { dto.roleType(), dto.subscriptionPlan(), dto.activateStatus(), - dto.signUpDateTime() + dto.signUpDateTime(), + dto.widgetSnapshot() ); } } diff --git a/src/test/java/com/gomo/app/core/member/documentation/ReadMemberDocumentationTest.java b/src/test/java/com/gomo/app/core/member/documentation/ReadMemberDocumentationTest.java index 6eb962a6..1bf730de 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/ReadMemberDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/member/documentation/ReadMemberDocumentationTest.java @@ -42,6 +42,7 @@ void read_profile() { .body("roleType", equalTo("ROLE_MEMBER")) .body("subscriptionPlan", equalTo("FREE")) .body("activateStatus", equalTo("ACTIVE")) - .body("signUpDateTime", notNullValue()); + .body("signUpDateTime", notNullValue()) + .body("widgetSnapshot", notNullValue()); } } diff --git a/src/test/java/com/gomo/app/core/member/documentation/snippet/ReadMemberSnippet.java b/src/test/java/com/gomo/app/core/member/documentation/snippet/ReadMemberSnippet.java index 7e42b0a6..b0363e42 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/snippet/ReadMemberSnippet.java +++ b/src/test/java/com/gomo/app/core/member/documentation/snippet/ReadMemberSnippet.java @@ -30,7 +30,8 @@ public class ReadMemberSnippet { fieldWithPath("roleType").type(JsonFieldType.STRING).description("사용자 권한"), fieldWithPath("subscriptionPlan").type(JsonFieldType.STRING).description("유료 플랜 등급"), fieldWithPath("activateStatus").type(JsonFieldType.STRING).description("계정 활성화 상태"), - fieldWithPath("signUpDateTime").type(JsonFieldType.STRING).description("가입 날짜") + fieldWithPath("signUpDateTime").type(JsonFieldType.STRING).description("가입 날짜"), + fieldWithPath("widgetSnapshot").type(JsonFieldType.STRING).description("사용자 위젯 구성도") ); public static RestDocumentationFilter create() { From 90628e0d895117f774bc9952cfc0439ef661fff1 Mon Sep 17 00:00:00 2001 From: Junhyeok Lee Date: Tue, 4 Nov 2025 00:29:51 +0900 Subject: [PATCH 11/16] =?UTF-8?q?[GOMO-236]=20=ED=97=A5=EC=82=AC=EA=B3=A0?= =?UTF-8?q?=EB=82=A0=20=EC=95=84=ED=82=A4=ED=85=8D=EC=B2=98=20=EC=A0=84?= =?UTF-8?q?=ED=99=98=20(#101)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 전체 모듈 헥사고날 아키텍처로 전환 * refactor: 관심사 도메인 서비스 리팩터링 * refacter: 인증 코드, 인증 토큰 검증 기능 인증 모듈로 이동 * fix: 인증 코드 검증 api http method GET -> POST 수정 * refactor: 인증 모듈을 core 하위로 이동 * fix: OAuth 가입 시, 인증 토큰을 검증하지 않도록 수정 --- README.md | 63 +-- src/docs/asciidoc/apis/auth-api.adoc | 96 ++++- src/docs/asciidoc/apis/member-api.adoc | 130 +------ src/docs/asciidoc/index.adoc | 21 +- .../gomo/app/batch/ImageCleanupScheduler.java | 25 +- .../app/batch/MemberCleanupScheduler.java | 8 +- .../batch/quest/CreateAssignQuestConfig.java | 10 +- .../app/batch/quest/FillQuestPoolConfig.java | 10 +- .../{support => common}/logging/AuditLog.java | 2 +- .../application/PasswordEncodeUseCase.java | 26 -- .../port/EncodePasswordPortIn.java | 12 - .../port/VerifyPasswordPortIn.java | 13 - .../application/port/GenerateJwtPortIn.java | 19 - .../jwt/application/port/VerifyJwtPortIn.java | 10 - .../com/gomo/app/common/web/PageRequest.java | 12 +- .../FilterRegistrationConfiguration.java | 2 +- .../com/gomo/app/config/WebConfiguration.java | 2 +- .../auth/adapter/in}/api/AuthApi.java | 44 ++- .../auth/adapter/in/api/EmailCodeApi.java | 43 ++ .../auth/adapter/in}/api/OAuthApi.java | 10 +- .../api}/request/CreateEmailCodeRequest.java | 4 +- .../api/request/CreatePrincipalRequest.java | 35 ++ .../adapter/in/api}/request/LoginRequest.java | 2 +- .../api}/request/VerifyEmailCodeRequest.java | 3 +- .../in/api}/response/AccessTokenResponse.java | 2 +- .../api/response/CreatePrincipalResponse.java | 21 + .../api}/response/OAuthPrincipalResponse.java | 2 +- .../in/api}/response/OAuthResponse.java | 4 +- .../response/VerifyEmailCodeResponse.java | 2 +- .../auth/adapter/in}/security/Auth.java | 2 +- .../in}/security/AuthArgumentResolver.java | 2 +- .../auth/adapter/in/security/AuthInfo.java | 19 + .../in}/security/AuthenticationFilter.java | 8 +- .../auth/adapter/out/client/MailClient.java} | 9 +- .../auth/adapter/out/client/MemberClient.java | 47 +++ .../out/client/OAuthGoogleClient.java} | 11 +- .../adapter/out/client/OAuthKakaoClient.java} | 9 +- .../adapter/out/client/OAuthNaverClient.java} | 9 +- .../out/factory/OAuthProviderFactory.java | 24 ++ .../auth/adapter/out/lib/JwtClient.java} | 23 +- .../out}/persistence/AuditorAwareImpl.java | 12 +- .../persistence/RedisAuthCodeRepository.java | 4 +- .../persistence/RedisAuthTokenRepository.java | 8 +- .../port/command/CreatePrincipalCommand.java | 14 + .../application/port/dto/AuthTokenDto.java | 2 +- .../application/port/dto/OAuthTokenDto.java | 2 +- .../application/port/in/AuthCodeIssuer.java | 25 ++ .../application/port/in/AuthTokenIssuer.java | 14 + .../application/port/in/LoginProcessor.java | 8 + .../port/in/OAuthLoginProcessor.java | 10 + .../port/in/RefreshTokenDeleter.java} | 6 +- .../port/in/RefreshTokenUpdater.java | 8 + .../application/port/in/SignupProcessor.java | 10 + .../application/port/out/AuthCodeSender.java} | 6 +- .../auth/application/port/out/JwtCreator.java | 19 + .../application/port/out/JwtVerifier.java | 10 + .../application/port/out/OAuthProvider.java | 8 + .../port/out/OAuthProviderReader.java | 6 + .../port/out/PrincipalCreator.java | 10 + .../port/out/PrincipalEmailChecker.java | 6 + .../port/out/PrincipalLoginProcessor.java | 8 + .../out/PrincipalOAuthLoginProcessor.java | 9 + .../application/service/AuthCodeService.java | 54 +++ .../auth/application/service/AuthService.java | 49 +++ .../application/service/AuthTokenService.java | 69 ++++ .../application/service/OAuthService.java | 55 +++ .../AuthCodeCreateFailException.java | 14 + .../auth/domain}/exception/AuthErrorCode.java | 7 +- .../AuthenticationFailException.java | 2 +- .../exception/InvalidAuthCodeException.java | 2 +- .../auth/domain/model/AuthCode.java | 2 +- .../auth/domain/model/AuthToken.java | 2 +- .../auth/domain/model/OAuthPrincipal.java | 2 +- .../domain/repository/AuthCodeRepository.java | 2 +- .../repository/AuthTokenRepository.java | 12 + .../in}/api/InterestApi.java | 42 +- .../in}/api/InterestLogoApi.java | 8 +- .../in}/api/InterestNetworkApi.java | 30 +- .../in}/api/MajorInterestApi.java | 28 +- .../in}/api/OrderUpdateMajorInterestApi.java | 14 +- .../CreateInterestRelationRequest.java | 2 +- .../api/request/CreateInterestRequest.java | 2 +- .../OrderUpdateMajorInterestRequest.java | 2 +- .../api/request/UpdateInterestRequest.java | 2 +- .../CreateInterestRelationResponse.java | 2 +- .../api/response/CreateInterestResponse.java | 2 +- .../response/CreateMajorInterestResponse.java | 2 +- .../api/response/InterestNetworkResponse.java | 2 +- .../api/response/ListInterestResponse.java | 2 +- .../response/ListMajorInterestResponse.java | 2 +- .../ReadInterestRelationResponse.java | 2 +- .../api/response/ReadInterestResponse.java | 2 +- .../response/ReadMajorInterestResponse.java | 2 +- .../CompleteQuestEventScoreConsumer.java | 10 +- .../adapter/out/client/LogoClient.java | 31 ++ .../out/client/RegistrantClient.java} | 12 +- .../JDBCLevelThresholdPolicyRepository.java} | 4 +- .../application/port/in/InterestCreator.java | 19 + .../application/port/in/InterestDeleter.java | 20 + .../port/in/InterestNetworkReader.java | 18 + .../InterestReader.java} | 12 +- .../port/in/InterestRelationCreator.java | 19 + .../port/in/InterestRelationDeleter.java | 21 + .../application/port/in/InterestUpdater.java | 18 + .../application/port/in/LogoUpdater.java | 20 + .../port/in/MajorInterestCreator.java | 22 ++ .../port/in/MajorInterestDeleter.java | 19 + .../port/in/MajorInterestOrderUpdater.java | 14 + .../port/in/MajorInterestReader.java | 18 + .../ProficiencyPropagator.java} | 8 +- .../application/port/out/LogoDeleter.java | 6 + .../application/port/out/LogoUploader.java | 10 + .../RegistrantReader.java} | 4 +- .../InterestCreateService.java} | 19 +- .../service/InterestDeleteService.java | 59 +++ .../service/InterestNetworkService.java | 28 ++ .../service/InterestRelationService.java | 82 ++++ .../InterestService.java} | 43 +- .../LogoService.java} | 22 +- .../service/MajorInterestService.java | 95 +++++ .../service/ProficiencyService.java | 66 ++++ .../usecase/AdjustProficiencyUseCase.java | 28 -- .../CreateInterestRelationUseCase.java | 31 -- .../usecase/CreateMajorInterestUseCase.java | 31 -- .../DeleteInterestRelationUseCase.java | 32 -- .../usecase/DeleteInterestUseCase.java | 70 ---- .../usecase/DeleteMajorInterestUseCase.java | 29 -- .../OrderUpdateMajorInterestUseCase.java | 36 -- .../usecase/ReadInterestNetworkUseCase.java | 55 --- .../usecase/ReadMajorInterestUseCase.java | 35 -- .../usecase/UpdateInterestUseCase.java | 28 -- .../InterestAccessDeniedException.java | 4 +- .../InterestConstraintViolationException.java | 4 +- ...erestNameConstraintViolationException.java | 4 +- .../exception/InterestNotFoundException.java | 4 +- ...InterestRelationAccessDeniedException.java | 4 +- .../InterestRelationCycleException.java | 4 +- .../InterestRelationDuplicatedException.java | 4 +- .../InterestRelationNotFoundException.java | 4 +- .../LevelConstraintViolationException.java | 4 +- .../MajorInterestAccessDeniedException.java | 4 +- .../MajorInterestDuplicatedException.java | 4 +- .../MajorInterestNotFoundException.java | 4 +- .../ProficiencyAdjustFailureException.java | 4 +- .../ScoreConstraintViolationException.java | 4 +- .../exception/code/InterestErrorCode.java | 2 +- .../exception/code/InterestNameErrorCode.java | 2 +- .../code/InterestRelationErrorCode.java | 4 +- .../exception/code/LevelErrorCode.java | 2 +- .../code/MajorInterestErrorCode.java | 2 +- .../exception/code/ProficiencyErrorCode.java | 2 +- .../exception/code/ScoreErrorCode.java | 2 +- .../core/interest/domain/model/Interest.java | 5 +- .../interest/domain/model/InterestName.java | 13 +- .../domain/model/InterestRelation.java | 4 +- .../app/core/interest/domain/model/Level.java | 4 +- .../interest/domain/model/MajorInterest.java | 9 +- .../interest/domain/model/Proficiency.java | 1 + .../interest/domain/model/Registrant.java | 4 +- .../app/core/interest/domain/model/Score.java | 4 +- .../domain/repository/InterestRepository.java | 8 - .../service/InterestNetworkBuilder.java | 109 ++++++ .../service/InterestRelationService.java | 137 ------- .../domain/service/InterestService.java | 23 -- .../interest/domain/service/LogoService.java | 20 - .../domain/service/MajorInterestService.java | 53 --- .../ProficiencyCalculator.java | 30 +- .../domain/service/ProficiencyService.java | 105 ----- .../in/api}/HandleApi.java | 20 +- .../core/member/adapter/in/api/MemberApi.java | 48 +++ .../member/adapter/in/api/PasswordApi.java | 37 ++ .../in/api}/ProfileBannerApi.java | 20 +- .../in/api}/ProfileImageApi.java | 20 +- .../in/api}/QuestPropertyApi.java | 22 +- .../in/api}/WidgetApi.java | 14 +- .../in/api}/request/ResetPasswordRequest.java | 2 +- .../in/api}/request/UpdateHandleRequest.java | 2 +- .../in/api}/request/UpdateMemberRequest.java | 2 +- .../api}/request/UpdatePasswordRequest.java | 2 +- .../request/UpdateProfileBannerRequest.java | 2 +- .../request/UpdateProfileImageRequest.java | 2 +- .../request/UpdateQuestPropertyRequest.java | 2 +- .../in/api}/request/UpdateWidgetRequest.java | 2 +- .../in/api}/response/ReadMemberResponse.java | 2 +- .../response/ReadQuestPropertyResponse.java | 2 +- .../adapter/out/MemberEventPublisher.java | 25 ++ .../member/adapter/out/client/AuthClient.java | 21 + .../adapter/out/client/EmailTokenClient.java | 24 ++ .../out/client/PointBalanceClient.java | 21 + .../out/client/ProfileAssetClient.java | 21 + .../member/adapter/out/lib/BcryptEncoder.java | 25 ++ .../application/port/LoginMemberPortIn.java | 18 - .../port/ReadActiveMemberPortIn.java | 19 - .../port/command/CreateMemberCommand.java | 6 +- .../port/dto/UpdateProfileBannerDto.java | 8 - .../port/dto/UpdateProfileImageDto.java | 8 - .../application/port/in/EmailChecker.java | 16 + .../application/port/in/HandleUpdater.java | 20 + .../application/port/in/HandleValidator.java | 14 + .../application/port/in/MemberCreator.java | 20 + .../application/port/in/MemberDeleter.java | 16 + .../port/in/MemberLoginProcessor.java | 18 + .../MemberOAuthLoginProcessor.java} | 8 +- .../MemberReader.java} | 8 +- .../application/port/in/MemberUpdater.java | 18 + .../application/port/in/PasswordResetter.java | 17 + .../application/port/in/PasswordUpdater.java | 20 + .../port/in/ProfileBannerDeleter.java | 16 + .../port/in/ProfileBannerUpdater.java | 19 + .../port/in/ProfileImageDeleter.java | 16 + .../port/in/ProfileImageUpdater.java | 19 + .../port/in/QuestPropertyReader.java | 18 + .../port/in/QuestPropertyUpdater.java | 15 + .../application/port/in/WidgetUpdater.java | 18 + .../port/out/EmailTokenVerifier.java | 14 + .../port/out/MemberCreateEventPublisher.java | 9 + .../port/out/MemberLogoutProcessor.java | 13 + .../port/out/PasswordEncodeManager.java | 21 + .../port/out/PointBalanceReader.java | 14 + .../port/out/ProfileAssetUploader.java | 14 + .../application/service/EmailService.java | 29 ++ .../application/service/HandleService.java | 42 ++ .../service/MemberCreateService.java | 59 +++ .../service/MemberLoginService.java | 32 ++ .../MemberOAuthLoginService.java} | 16 +- .../application/service/MemberService.java | 62 +++ .../application/service/PasswordService.java | 59 +++ .../service/ProfileBannerService.java | 39 ++ .../service/ProfileImageService.java | 39 ++ .../service/QuestPropertyService.java | 40 ++ .../WidgetService.java} | 13 +- .../usecase/CheckHandleUseCase.java | 18 - .../usecase/CreateEmailCodeUseCase.java | 30 -- .../usecase/CreateMemberUseCase.java | 73 ---- .../usecase/DeleteMemberUseCase.java | 29 -- .../usecase/DeleteProfileBannerUseCase.java | 25 -- .../usecase/DeleteProfileImageUseCase.java | 25 -- .../usecase/LoginMemberUseCase.java | 45 --- .../usecase/ReadMemberUseCase.java | 27 -- .../usecase/ReadQuestPropertyUseCase.java | 24 -- .../usecase/ResetPasswordUseCase.java | 32 -- .../usecase/UpdateHandleUseCase.java | 27 -- .../usecase/UpdateMemberUseCase.java | 26 -- .../usecase/UpdatePasswordUseCase.java | 41 -- .../usecase/UpdateProfileBannerUseCase.java | 32 -- .../usecase/UpdateProfileImageUseCase.java | 33 -- .../usecase/UpdateQuestPropertyUseCase.java | 27 -- .../usecase/VerifyEmailCodeUseCase.java | 22 -- .../exception/ActivateStatusException.java | 4 +- .../EmailConstraintViolationException.java | 4 +- .../exception/EmailDuplicatedException.java | 4 +- .../HandleConstraintViolationException.java | 4 +- .../exception/HandleDuplicatedException.java | 4 +- .../MemberAuthenticationFailedException.java | 15 + .../exception/MemberDuplicatedException.java | 15 + ...emberNameConstraintViolationException.java | 4 +- .../exception/MemberNotFoundException.java | 4 +- .../MottoConstraintViolationException.java | 4 +- .../PasswordConstraintViolationException.java | 4 +- .../exception/PasswordMismatchException.java | 4 +- ...tPropertyConstraintViolationException.java | 4 +- .../code/ActivateStatusErrorCode.java | 2 +- .../exception/code/EmailErrorCode.java | 2 +- .../exception/code/HandleErrorCode.java | 2 +- .../exception/code/MemberErrorCode.java | 2 +- .../exception/code/MemberNameErrorCode.java | 2 +- .../exception/code/MottoErrorCode.java | 2 +- .../exception/code/PasswordErrorCode.java | 2 +- .../code/QuestPropertyErrorCode.java | 2 +- .../app/core/member/domain/model/Email.java | 4 +- .../app/core/member/domain/model/Handle.java | 4 +- .../app/core/member/domain/model/Member.java | 8 +- .../core/member/domain/model/MemberName.java | 84 ++-- .../app/core/member/domain/model/Motto.java | 64 +-- .../core/member/domain/model/Password.java | 4 +- .../member/domain/model/QuestProperty.java | 4 +- .../member/domain/service/MemberService.java | 46 --- .../domain/service/ProfileImageService.java | 20 - .../MemberAuthenticationFailedException.java | 15 - .../exception/MemberDuplicatedException.java | 15 - .../member/presentation/EmailCodeApi.java | 44 --- .../core/member/presentation/MemberApi.java | 62 --- .../core/member/presentation/PasswordApi.java | 37 -- .../request/CreateMemberRequest.java | 35 -- .../response/CreateEmailCodeResponse.java | 19 - .../response/CreateMemberResponse.java | 21 - .../in}/api/PointApi.java | 22 +- .../in}/api/response/ListPointResponse.java | 2 +- .../in}/api/response/ReadBalanceResponse.java | 2 +- .../in}/api/response/ReadPointResponse.java | 2 +- .../CompleteQuestEventPointConsumer.java | 10 +- .../BalanceReader.java} | 8 +- .../PointCreator.java} | 4 +- .../application/port/in/PointReader.java | 19 + .../PointWalletCreator.java} | 6 +- .../application/service/BalanceService.java | 22 ++ .../application/service/PointService.java | 73 ++++ .../service/PointWalletService.java | 56 +++ .../usecase/CreatePointUseCase.java | 26 -- .../usecase/CreatePointWalletUseCase.java | 31 -- .../usecase/ReadBalanceUseCase.java | 23 -- .../application/usecase/ReadPointUseCase.java | 41 -- .../InsufficientBalanceException.java | 4 +- .../PointConstraintViolationException.java | 4 +- .../PointWalletNotFoundException.java | 4 +- .../exception/code/BalanceErrorCode.java | 2 +- .../exception/code/PointErrorCode.java | 2 +- .../exception/code/PointWalletErrorCode.java | 2 +- .../app/core/point/domain/model/Balance.java | 6 +- .../app/core/point/domain/model/Point.java | 4 +- .../domain/repository/PointRepository.java | 10 +- .../repository/PointWalletRepository.java | 2 + .../point/domain/service/PointService.java | 40 -- .../domain/service/PointWalletService.java | 38 -- .../quest/adapter/in/api/AssignQuestApi.java | 64 +++ .../in/api/CalendarAssignQuestApi.java | 36 ++ .../in}/api/CompleteAssignQuestApi.java | 14 +- .../in}/api/ConfirmAssignQuestApi.java | 12 +- .../in}/api/OrderUpdateAssignQuestApi.java | 14 +- .../in}/api/OrderUpdateRepeatQuestApi.java | 14 +- .../adapter/in/api/ReRollAssignQuestApi.java | 32 ++ .../in}/api/RepeatQuestApi.java | 38 +- .../request/CompleteAssignQuestRequest.java | 2 +- .../api/request/CreateAssignQuestRequest.java | 2 +- .../api/request/CreateRepeatQuestRequest.java | 2 +- .../OrderUpdateAssignQuestRequest.java | 2 +- .../OrderUpdateRepeatQuestRequest.java | 2 +- .../api/request/ReRollAssignQuestRequest.java | 2 +- .../api/request/UpdateAssignQuestRequest.java | 2 +- .../api/request/UpdateRepeatQuestRequest.java | 2 +- .../response/CreateAssignQuestResponse.java | 2 +- .../response/CreateRepeatQuestResponse.java | 2 +- .../ListAssignQuestDetailResponse.java | 33 ++ .../api/response/ListAssignQuestResponse.java | 19 + .../api/response/ListRepeatQuestResponse.java | 2 +- .../ReadAssignQuestDetailResponse.java} | 12 +- .../response/ReadAssignQuestResponse.java} | 12 +- .../api/response/ReadRepeatQuestResponse.java | 2 +- .../consumer/FillQuestPoolEventConsumer.java | 12 +- .../out/client/LlmQuestContentClient.java} | 6 +- .../out/client/ParticipantClient.java} | 14 +- .../adapter/out/client/SubjectClient.java | 41 ++ .../InMemoryQuestRewardPolicyRepository.java | 2 +- .../JdbcBulkAssignQuestRepository.java | 2 +- .../command/CalendarAssignQuestCommand.java | 11 - .../port/command/ListAssignQuestCommand.java | 11 + .../port/dto/ActiveParticipantDto.java | 10 - .../port/dto/AssignQuestDetailDto.java | 27 ++ .../application/port/dto/AssignQuestDto.java | 17 +- .../port/dto/CalendarAssignQuestDto.java | 23 -- .../port/dto/ListAssignQuestDetailDto.java | 10 + .../port/dto/ListAssignQuestDto.java | 10 - .../application/port/dto/RepeatQuestDto.java | 3 +- .../port/in/AssignQuestCompleter.java | 8 + .../port/in/AssignQuestConfirmer.java | 8 + .../port/in/AssignQuestCreator.java | 10 + .../port/in/AssignQuestDeleter.java | 8 + .../port/in/AssignQuestDetailReader.java | 10 + .../port/in/AssignQuestOrderUpdater.java | 8 + .../port/in/AssignQuestReRoller.java | 10 + .../port/in/AssignQuestReader.java | 11 + .../AssignQuestRoutineCreator.java} | 4 +- .../port/in/AssignQuestUpdater.java | 8 + .../QuestPoolCreator.java} | 4 +- .../QuestPoolEventPublisher.java} | 4 +- .../port/in/RepeatQuestCreator.java | 10 + .../port/in/RepeatQuestDeleter.java | 8 + .../port/in/RepeatQuestOrderUpdater.java | 8 + .../port/in/RepeatQuestReader.java | 10 + .../port/in/RepeatQuestUpdater.java | 8 + .../ParticipantReader.java} | 8 +- .../QuestContentCreator.java} | 4 +- .../SubjectReader.java} | 8 +- .../AssignQuestCompleteService.java} | 23 +- .../AssignQuestCreateService.java} | 64 ++- .../AssignQuestReRollService.java} | 31 +- .../AssignQuestRoutineService.java} | 16 +- .../service/AssignQuestService.java | 151 ++++++++ .../QuestPoolCreateService.java} | 18 +- .../QuestPoolEventService.java} | 26 +- .../RepeatQuestCreateService.java} | 42 +- .../service/RepeatQuestService.java | 109 ++++++ .../usecase/CalendarAssignQuestUseCase.java | 38 -- .../usecase/ConfirmAssignQuestUseCase.java | 27 -- .../usecase/DeleteAssignQuestUseCase.java | 31 -- .../usecase/DeleteRepeatQuestUseCase.java | 29 -- .../OrderUpdateAssignQuestUseCase.java | 44 --- .../OrderUpdateRepeatQuestUseCase.java | 38 -- .../usecase/ReadAssignQuestUseCase.java | 43 -- .../usecase/ReadRepeatQuestUseCase.java | 37 -- .../usecase/UpdateAssignQuestUseCase.java | 40 -- .../usecase/UpdateRepeatQuestUseCase.java | 45 --- .../event/CompleteQuestEvent.java | 2 +- .../event/CreateQuestPoolEvent.java | 2 +- .../AssignQuestAccessDeniedException.java | 4 +- ...signQuestConstraintViolationException.java | 4 +- .../AssignQuestNotFoundException.java | 4 +- ...tionProofConstraintViolationException.java | 4 +- .../exception/InvalidPeriodTypeException.java | 4 +- .../exception/QuestAccessDeniedException.java | 4 +- .../QuestConstraintViolationException.java | 4 +- ...stContentConstraintViolationException.java | 4 +- .../exception/QuestPoolNotFoundException.java | 4 +- ...QuestTypeConstraintViolationException.java | 4 +- .../RepeatQuestAccessDeniedException.java | 4 +- .../RepeatQuestNotFoundException.java | 4 +- ...RepeatQuestThresholdExceededException.java | 4 +- .../exception/code/AssignQuestErrorCode.java | 2 +- .../code/CompletionProofErrorCode.java | 2 +- .../exception/code/QuestContentErrorCode.java | 2 +- .../exception/code/QuestErrorCode.java | 2 +- .../exception/code/QuestPoolErrorCode.java | 2 +- .../exception/code/QuestTypeErrorCode.java | 2 +- .../exception/code/RepeatQuestErrorCode.java | 2 +- .../domain/model/assign/AssignQuest.java | 10 +- .../domain/model/assign/CompletionProof.java | 4 +- .../domain/model/participant/Participant.java | 4 +- .../quest/domain/model/pool/QuestPool.java | 4 +- .../domain/model/quest/QuestContent.java | 4 +- .../domain/model/repeat/RepeatQuest.java | 4 +- .../domain/service/AssignQuestService.java | 61 --- ...dService.java => QuestRewardProvider.java} | 4 +- .../domain/service/RepeatQuestService.java | 38 -- .../adapter/ReadSubjectAdapter.java | 41 -- .../presentation/api/AssignQuestApi.java | 64 --- .../api/CalendarAssignQuestApi.java | 36 -- .../api/ReRollAssignQuestApi.java | 32 -- .../api/response/ListAssignQuestResponse.java | 33 -- .../ListCalendarAssignQuestResponse.java | 19 - .../in}/api/AchieverApi.java | 14 +- .../in}/api/StreakApi.java | 14 +- .../in}/api/response/ListStreakResponse.java | 2 +- .../api/response/ReadAchieverResponse.java | 2 +- .../in}/api/response/ReadStreakResponse.java | 2 +- .../CompleteQuestEventStreakConsumer.java | 10 +- .../AchieverCreator.java} | 6 +- .../application/port/in/AchieverReader.java | 18 + .../StreakCreator.java} | 4 +- .../application/port/in/StreakReader.java | 21 + .../application/service/AchieverService.java | 49 +++ .../application/service/StreakService.java | 70 ++++ .../usecase/CreateAchieverUseCase.java | 29 -- .../usecase/CreateStreakUseCase.java | 29 -- .../usecase/ReadAchieverUseCase.java | 20 - .../usecase/ReadStreakUseCase.java | 36 -- .../exception/AchieverErrorCode.java | 2 +- .../exception/AchieverNotFoundException.java | 2 +- .../domain/service/AchieverService.java | 22 -- .../streak/domain/service/StreakService.java | 50 --- .../in/api}/SurveyApi.java | 24 +- .../request/CreateSurveyResultRequest.java | 4 +- .../request/SelectedSurveyItemRequest.java | 4 +- .../response/ListSurveyQuestionResponse.java | 4 +- .../api}/response/ReadSurveyItemResponse.java | 4 +- .../response/ReadSurveyQuestionResponse.java | 4 +- .../SurveyResultRepositoryImpl.java | 2 +- .../CreateSurveyResultCommand.java | 4 +- .../application/{ => dto}/SurveyItemDto.java | 2 +- .../{ => dto}/SurveyQuestionDto.java | 2 +- .../SurveyQuestionService.java} | 6 +- .../SurveyResultService.java} | 8 +- ...veyResultConstraintViolationException.java | 2 +- .../exception/SurveyResultErrorCode.java | 2 +- .../survey/domain/model/SurveyResult.java | 4 +- .../port/CreateAuthCodePortIn.java | 13 - .../port/VerifyAuthCodePortIn.java | 18 - .../usecase/AuthenticateUseCase.java | 29 -- .../usecase/CreateAuthCodeUseCase.java | 31 -- .../CreateAuthTokenInternalService.java | 29 -- .../usecase/DeleteRefreshTokenUseCase.java | 23 -- .../application/usecase/OAuthUseCase.java | 54 --- .../usecase/UpdateRefreshTokenUseCase.java | 40 -- .../usecase/VerifyAuthCodeUseCase.java | 24 -- .../repository/AuthTokenRepository.java | 12 - .../oauth/OAuthProviderFactory.java | 24 -- .../oauth/provider/OAuthProvider.java | 8 - .../auth/presentation/security/AuthInfo.java | 19 - .../usecase/ForwardEventEntryUseCase.java | 6 +- .../out/client/MinioImageClient.java} | 6 +- .../ImageDeleter.java} | 4 +- .../ImageReader.java} | 4 +- .../ImageUploader.java} | 4 +- .../ImageStore.java} | 4 +- .../application/service/ImageService.java | 40 ++ .../usecase/DeleteImageUseCase.java | 19 - .../application/usecase/ReadImageUseCase.java | 21 - .../usecase/UploadImageUseCase.java | 27 -- .../support/logging/AuditLoggingAspect.java | 4 +- .../app/support/logging/LoggingFilter.java | 1 + .../out/client}/RabbitMQClient.java | 6 +- .../JdbcProcessedDirectEventRepository.java | 2 +- .../application/PublishMessageUseCase.java | 21 - .../IdempotentDirectEventConsumer.java | 2 +- .../MessagePublisher.java} | 4 +- .../MessageBrokerManager.java} | 4 +- .../IdempotentDirectEventConsumerAspect.java | 4 +- .../service/MessagePublishService.java | 21 + .../web/ApplicationExceptionAdviceTest.java | 2 +- ...odeForPasswordResetDocumentationTest.java} | 22 +- ...teAuthCodeForSignupDocumentationTest.java} | 22 +- .../in/api/LoginDocumentationTest.java} | 8 +- .../in/api/LogoutDocumentationTest.java} | 6 +- .../api}/RefreshTokenDocumentationTest.java | 4 +- .../in/api/SignupDocumentationTest.java} | 34 +- .../VerifyEmailCodeDocumentationTest.java} | 22 +- .../snippet/CreateEmailAuthCodeSnippet.java | 4 +- .../CreatePasswordAuthCodeSnippet.java | 4 +- .../in/api}/snippet/LoginMemberSnippet.java | 2 +- .../in/api}/snippet/LogoutMemberSnippet.java | 2 +- .../in/api}/snippet/RefreshTokenSnippet.java | 2 +- .../in/api/snippet/SignupSnippet.java} | 6 +- .../snippet/VerifyEmailAuthCodeSnippet.java | 6 +- .../adapter/out/client/MemberClientTest.java | 73 ++++ .../auth/adapter/out/lib/JwtClientTest.java} | 26 +- .../RedisAuthCodeRepositoryTest.java | 4 +- .../RedisAuthTokenRepositoryTest.java | 10 +- .../service/AuthCodeServiceTest.java | 105 +++++ .../application/service/AuthServiceTest.java | 98 +++++ .../service/AuthTokenServiceTest.java | 147 +++++++ .../auth/domain/model/AuthCodeTest.java | 2 +- .../api}/CreateInterestDocumentationTest.java | 6 +- ...eateInterestRelationDocumentationTest.java | 9 +- .../CreateMajorInterestDocumentationTest.java | 10 +- .../api}/DeleteInterestDocumentationTest.java | 7 +- ...leteInterestRelationDocumentationTest.java | 10 +- .../DeleteMajorInterestDocumentationTest.java | 8 +- .../InterestNetworkDocumentationTest.java | 10 +- .../api}/ListInterestDocumentationTest.java | 7 +- .../ListMajorInterestDocumentationTest.java | 8 +- ...rUpdateMajorInterestDocumentationTest.java | 10 +- .../api}/ReadInterestDocumentationTest.java | 7 +- .../api}/UpdateInterestDocumentationTest.java | 11 +- .../UpdateInterestLogoDocumentationTest.java | 7 +- .../CreateInterestRelationSnippet.java | 2 +- .../api}/snippet/CreateInterestSnippet.java | 2 +- .../snippet/CreateMajorInterestSnippet.java | 2 +- .../DeleteInterestRelationSnippet.java | 2 +- .../api}/snippet/DeleteInterestSnippet.java | 2 +- .../snippet/DeleteMajorInterestSnippet.java | 2 +- .../api}/snippet/InterestNetworkSnippet.java | 2 +- .../in/api}/snippet/ListInterestSnippet.java | 2 +- .../snippet/ListMajorInterestSnippet.java | 2 +- .../OrderUpdateMajorInterestSnippet.java | 2 +- .../in/api}/snippet/ReadInterestSnippet.java | 2 +- .../snippet/UpdateInterestLogoSnippet.java | 2 +- .../api}/snippet/UpdateInterestSnippet.java | 2 +- .../CompleteQuestEventScoreConsumerTest.java | 12 +- .../adapter/out/client/LogoClientTest.java | 51 +++ .../out/client/RegistrantClientTest.java} | 12 +- ...BCLevelThresholdPolicyRepositoryTest.java} | 6 +- .../InterestCreateServiceTest.java} | 18 +- .../InterestDeleteServiceTest.java} | 48 ++- .../service/InterestNetworkServiceTest.java | 55 +++ .../service/InterestRelationServiceTest.java | 171 ++++++++ .../InterestServiceTest.java} | 71 +++- .../LogoServiceTest.java} | 31 +- .../service/MajorInterestServiceTest.java | 171 ++++++++ .../service/ProficiencyServiceTest.java | 67 ++++ .../usecase/AdjustProficiencyUseCaseTest.java | 41 -- .../CreateInterestRelationUseCaseTest.java | 49 --- .../CreateMajorInterestUseCaseTest.java | 57 --- .../DeleteInterestRelationUseCaseTest.java | 60 --- .../DeleteMajorInterestUseCaseTest.java | 55 --- .../OrderUpdateMajorInterestUseCaseTest.java | 62 --- .../ReadInterestNetworkUseCaseTest.java | 87 ----- .../usecase/ReadMajorInterestUseCaseTest.java | 63 --- .../usecase/UpdateInterestUseCaseTest.java | 51 --- .../domain/model/InterestNameTest.java | 4 +- .../domain/model/InterestRelationTest.java | 2 +- .../interest/domain/model/InterestTest.java | 3 +- .../core/interest/domain/model/LevelTest.java | 4 +- .../domain/model/MajorInterestTest.java | 11 +- .../domain/model/ProficiencyTest.java | 2 + .../interest/domain/model/RegistrantTest.java | 4 +- .../core/interest/domain/model/ScoreTest.java | 4 +- .../InterestRelationRepositoryTest.java | 4 +- .../MajorInterestRepositoryTest.java | 4 +- .../service/InterestNetworkBuilderTest.java | 179 +++++++++ .../service/InterestRelationServiceTest.java | 151 -------- .../domain/service/InterestServiceTest.java | 52 --- .../domain/service/LogoServiceTest.java | 37 -- .../service/MajorInterestServiceTest.java | 64 --- .../ProficiencyCalculatorTest.java | 44 ++- .../service/ProficiencyServiceTest.java | 91 ----- ...CheckHandleDuplicateDocumentationTest.java | 6 +- .../api}/DeleteMemberDocumentationTest.java | 4 +- .../DeleteProfileBannerDocumentationTest.java | 4 +- .../DeleteProfileImageDocumentationTest.java | 4 +- .../in/api}/ReadMemberDocumentationTest.java | 4 +- .../ReadQuestPropertyDocumentationTest.java | 4 +- .../api}/ResetPasswordDocumentationTest.java | 8 +- .../api}/UpdateHandleDocumentationTest.java | 8 +- .../api}/UpdateMemberDocumentationTest.java | 6 +- .../api}/UpdatePasswordDocumentationTest.java | 6 +- .../UpdateProfileBannerDocumentationTest.java | 4 +- .../UpdateProfileImageDocumentationTest.java | 4 +- .../UpdateQuestPropertyDocumentationTest.java | 6 +- .../api}/UpdateWidgetDocumentationTest.java | 6 +- .../snippet/CheckHandleDuplicateSnippet.java | 2 +- .../in/api}/snippet/DeleteMemberSnippet.java | 2 +- .../snippet/DeleteProfileBannerSnippet.java | 2 +- .../snippet/DeleteProfileImageSnippet.java | 2 +- .../in/api}/snippet/ReadMemberSnippet.java | 2 +- .../snippet/ReadQuestPropertySnippet.java | 2 +- .../in/api}/snippet/ResetPasswordSnippet.java | 2 +- .../in/api}/snippet/UpdateHandleSnippet.java | 2 +- .../in/api}/snippet/UpdateMemberSnippet.java | 2 +- .../api}/snippet/UpdatePasswordSnippet.java | 2 +- .../snippet/UpdateProfileBannerSnippet.java | 2 +- .../snippet/UpdateProfileImageSnippet.java | 2 +- .../snippet/UpdateQuestPropertySnippet.java | 2 +- .../in/api}/snippet/UpdateWidgetSnippet.java | 2 +- .../adapter/out/client/AuthClientTest.java | 28 ++ .../out/client/PointBalanceClientTest.java | 33 ++ .../out/client/ProfileAssetClientTest.java | 49 +++ .../out/client/TemporaryTokenClientTest.java | 43 ++ .../adapter/out/lib/BcryptEncoderTest.java} | 14 +- .../application/service/EmailServiceTest.java | 69 ++++ .../service/HandleServiceTest.java | 66 ++++ .../service/MemberCreateServiceTest.java | 58 +++ .../MemberLoginServiceTest.java} | 16 +- .../MemberOAuthLoginServiceTest.java} | 10 +- .../service/MemberServiceTest.java | 121 ++++++ .../service/PasswordServiceTest.java | 111 ++++++ .../ProfileBannerServiceTest.java} | 36 +- .../QuestPropertyServiceTest.java} | 24 +- .../TempProfileImageServiceTest.java} | 35 +- .../WidgetServiceTest.java} | 9 +- .../usecase/CheckHandleUseCaseTest.java | 36 -- .../usecase/CreateEmailCodeUseCaseTest.java | 56 --- .../usecase/CreateMemberUseCaseTest.java | 79 ---- .../usecase/DeleteMemberUseCaseTest.java | 44 --- .../DeleteProfileBannerUseCaseTest.java | 37 -- .../DeleteProfileImageUseCaseTest.java | 35 -- .../usecase/ReadMemberUseCaseTest.java | 48 --- .../usecase/ReadQuestPropertyUseCaseTest.java | 39 -- .../usecase/ResetPasswordUseCaseTest.java | 58 --- .../usecase/UpdateHandleUseCaseTest.java | 37 -- .../usecase/UpdateMemberUseCaseTest.java | 63 --- .../usecase/UpdatePasswordUseCaseTest.java | 63 --- .../usecase/VerifyEmailCodeUseCaseTest.java | 59 --- .../domain/model/DailyThresholdTest.java | 4 +- .../core/member/domain/model/EmailTest.java | 4 +- .../core/member/domain/model/HandleTest.java | 4 +- .../member/domain/model/MemberNameTest.java | 4 +- .../core/member/domain/model/MemberTest.java | 4 +- .../domain/model/MonthlyThresholdTest.java | 4 +- .../core/member/domain/model/MottoTest.java | 4 +- .../member/domain/model/PasswordTest.java | 4 +- .../domain/model/WeeklyThresholdTest.java | 4 +- .../repository/MemberRepositoryTest.java | 2 +- .../domain/service/MemberServiceTest.java | 115 ------ .../service/ProfileImageServiceTest.java | 37 -- .../in/api}/ListPointDocumentationTest.java | 28 +- .../in/api}/ReadBalanceDocumentationTest.java | 4 +- .../in/api}/snippet/ListPointSnippet.java | 2 +- .../in/api}/snippet/ReadBalanceSnippet.java | 2 +- .../CompleteQuestEventPointConsumerTest.java | 12 +- .../BalanceServiceTest.java} | 74 ++-- .../PointServiceTest.java} | 115 +++--- .../service/PointWalletServiceTest.java | 153 ++++---- .../usecase/CreatePointUseCaseTest.java | 34 -- .../usecase/CreatePointWalletUseCaseTest.java | 40 -- .../core/point/domain/model/BalanceTest.java | 2 +- .../core/point/domain/model/PointTest.java | 2 +- .../repository/PointRepositoryTest.java | 125 ++++++ .../domain/service/PointServiceTest.java | 40 -- .../app/core/point/fixture/PointFixture.java | 12 + .../infrastructure/PointRepositoryTest.java | 114 ------ .../CalendarAssignQuestDocumentationTest.java | 4 +- .../CompleteAssignQuestDocumentationTest.java | 6 +- .../ConfirmAssignQuestDocumentationTest.java | 4 +- .../CreateAssignQuestDocumentationTest.java | 14 +- .../CreateRepeatQuestDocumentationTest.java | 18 +- .../DeleteAssignQuestDocumentationTest.java | 4 +- .../DeleteRepeatQuestDocumentationTest.java | 7 +- .../ListAssignQuestDocumentationTest.java | 4 +- .../ListRepeatQuestDocumentationTest.java | 7 +- ...derUpdateAssignQuestDocumentationTest.java | 6 +- ...derUpdateRepeatQuestDocumentationTest.java | 6 +- .../ReRollAssignQuestDocumentationTest.java | 6 +- .../UpdateAssignQuestDocumentationTest.java | 8 +- .../UpdateRepeatQuestDocumentationTest.java | 11 +- .../snippet/CalendarAssignQuestSnippet.java | 2 +- .../snippet/CompleteAssignQuestSnippet.java | 2 +- .../snippet/ConfirmAssignQuestSnippet.java | 2 +- .../snippet/CreateAssignQuestSnippet.java | 2 +- .../snippet/CreateRepeatQuestSnippet.java | 2 +- .../snippet/DeleteAssignQuestSnippet.java | 2 +- .../snippet/DeleteRepeatQuestSnippet.java | 2 +- .../api}/snippet/ListAssignQuestSnippet.java | 2 +- .../api}/snippet/ListRepeatQuestSnippet.java | 2 +- .../OrderUpdateAssignQuestSnippet.java | 2 +- .../OrderUpdateRepeatQuestSnippet.java | 2 +- .../snippet/ReRollAssignQuestSnippet.java | 2 +- .../snippet/UpdateAssignQuestSnippet.java | 2 +- .../snippet/UpdateRepeatQuestSnippet.java | 2 +- .../LlmCreateQuestContentAdapterTest.java | 2 +- .../out/client/ParticipantClientTest.java} | 14 +- .../out/client/SubjectClientTest.java} | 26 +- .../AssignQuestRepositoryTest.java | 2 +- .../JdbcBulkAssignQuestRepositoryTest.java | 2 +- .../RepeatQuestRepositoryTest.java | 2 +- .../AssignQuestCompleteServiceTest.java} | 23 +- .../AssignQuestCreateServiceTest.java} | 43 +- .../AssignQuestReRollServiceTest.java} | 23 +- .../AssignQuestRoutineServiceTest.java} | 6 +- .../service/AssignQuestServiceTest.java | 366 ++++++++++++++++++ .../QuestPoolCreateServiceTest.java} | 14 +- .../service/RepeatQuestCreateServiceTest.java | 84 ++++ .../service/RepeatQuestServiceTest.java | 198 ++++++++++ .../CalendarAssignQuestUseCaseTest.java | 105 ----- .../ConfirmAssignQuestUseCaseTest.java | 54 --- .../usecase/CreateRepeatQuestUseCaseTest.java | 63 --- .../usecase/DeleteAssignQuestUseCaseTest.java | 83 ---- .../usecase/DeleteRepeatQuestUseCaseTest.java | 57 --- .../OrderUpdateAssignQuestUseCaseTest.java | 65 ---- .../OrderUpdateRepeatQuestUseCaseTest.java | 65 ---- .../usecase/ReadAssignQuestUseCaseTest.java | 59 --- .../usecase/ReadRepeatQuestUseCaseTest.java | 59 --- .../usecase/UpdateAssignQuestUseCaseTest.java | 94 ----- .../usecase/UpdateRepeatQuestUseCaseTest.java | 68 ---- .../domain/model/assign/AssignQuestTest.java | 10 +- .../model/assign/CompletionProofTest.java | 4 +- .../model/participant/ParticipantTest.java | 4 +- .../domain/model/pool/QuestPoolTest.java | 2 +- .../domain/model/quest/QuestContentTest.java | 4 +- .../domain/model/repeat/RepeatQuestTest.java | 2 +- .../service/AssignQuestServiceTest.java | 78 ---- ...Test.java => QuestRewardProviderTest.java} | 8 +- .../service/RepeatQuestServiceTest.java | 53 --- .../in/api}/ListStreakDocumentationTest.java | 4 +- .../api}/ReadAchieverDocumentationTest.java | 4 +- .../in/api}/snippet/ListStreakSnippet.java | 2 +- .../in/api}/snippet/ReadAchieverSnippet.java | 2 +- .../CompleteQuestEventStreakConsumerTest.java | 12 +- .../service/AchieverServiceTest.java | 74 ++++ .../service/StreakServiceTest.java | 114 ++++++ .../usecase/CreateAchieverUseCaseTest.java | 36 -- .../usecase/CreateStreakUseCaseTest.java | 36 -- .../usecase/ReadAchieverUseCaseTest.java | 39 -- .../usecase/ReadStreakUseCaseTest.java | 50 --- .../domain/service/AchieverServiceTest.java | 40 -- .../domain/service/StreakServiceTest.java | 86 ---- .../CreateSurveyAnswerDocumentationTest.java | 8 +- .../in/api}/ListSurveyDocumentationTest.java | 4 +- .../snippet/CreateSurveyAnswerSnippet.java | 2 +- .../in/api}/snippet/ListSurveySnippet.java | 2 +- .../SurveyResultRepositoryTest.java | 2 +- .../service}/ReadSurveyResultUseCaseTest.java | 7 +- .../service/SurveyResultServiceTest.java} | 11 +- .../{unit => }/domain/SurveyResultTest.java | 6 +- .../usecase/AuthenticateUseCaseTest.java | 52 --- .../usecase/CreateAuthCodeUseCaseTest.java | 39 -- .../CreateAuthTokenInternalServiceTest.java | 46 --- .../UpdateRefreshTokenUseCaseTest.java | 78 ---- .../out/client/MinioImageClientTest.java} | 14 +- .../ImageServiceTest.java} | 33 +- .../usecase/DeleteImageUseCaseTest.java | 31 -- .../usecase/ReadImageUseCaseTest.java | 36 -- .../out/client}/RabbitMQClientTest.java | 2 +- ...dbcProcessedDirectEventRepositoryTest.java | 2 +- ...empotentDirectEventConsumerAspectTest.java | 4 +- .../MessagePublishServiceTest.java} | 12 +- .../gomo/app/test/DocumentationTestBase.java | 22 +- 765 files changed, 8130 insertions(+), 8596 deletions(-) rename src/main/java/com/gomo/app/{support => common}/logging/AuditLog.java (88%) delete mode 100644 src/main/java/com/gomo/app/common/security/encoder/application/PasswordEncodeUseCase.java delete mode 100644 src/main/java/com/gomo/app/common/security/encoder/application/port/EncodePasswordPortIn.java delete mode 100644 src/main/java/com/gomo/app/common/security/encoder/application/port/VerifyPasswordPortIn.java delete mode 100644 src/main/java/com/gomo/app/common/security/jwt/application/port/GenerateJwtPortIn.java delete mode 100644 src/main/java/com/gomo/app/common/security/jwt/application/port/VerifyJwtPortIn.java rename src/main/java/com/gomo/app/{support/auth/presentation => core/auth/adapter/in}/api/AuthApi.java (56%) create mode 100644 src/main/java/com/gomo/app/core/auth/adapter/in/api/EmailCodeApi.java rename src/main/java/com/gomo/app/{support/auth/presentation => core/auth/adapter/in}/api/OAuthApi.java (80%) rename src/main/java/com/gomo/app/core/{member/presentation => auth/adapter/in/api}/request/CreateEmailCodeRequest.java (83%) create mode 100644 src/main/java/com/gomo/app/core/auth/adapter/in/api/request/CreatePrincipalRequest.java rename src/main/java/com/gomo/app/{support/auth/presentation => core/auth/adapter/in/api}/request/LoginRequest.java (86%) rename src/main/java/com/gomo/app/core/{member/presentation => auth/adapter/in/api}/request/VerifyEmailCodeRequest.java (86%) rename src/main/java/com/gomo/app/{support/auth/presentation => core/auth/adapter/in/api}/response/AccessTokenResponse.java (88%) create mode 100644 src/main/java/com/gomo/app/core/auth/adapter/in/api/response/CreatePrincipalResponse.java rename src/main/java/com/gomo/app/{support/auth/presentation => core/auth/adapter/in/api}/response/OAuthPrincipalResponse.java (89%) rename src/main/java/com/gomo/app/{support/auth/presentation => core/auth/adapter/in/api}/response/OAuthResponse.java (86%) rename src/main/java/com/gomo/app/core/{member/presentation => auth/adapter/in/api}/response/VerifyEmailCodeResponse.java (85%) rename src/main/java/com/gomo/app/{support/auth/presentation => core/auth/adapter/in}/security/Auth.java (81%) rename src/main/java/com/gomo/app/{support/auth/presentation => core/auth/adapter/in}/security/AuthArgumentResolver.java (94%) create mode 100644 src/main/java/com/gomo/app/core/auth/adapter/in/security/AuthInfo.java rename src/main/java/com/gomo/app/{support/auth/presentation => core/auth/adapter/in}/security/AuthenticationFilter.java (86%) rename src/main/java/com/gomo/app/{support/auth/infrastructure/adapter/SendAuthCodeAdapter.java => core/auth/adapter/out/client/MailClient.java} (76%) create mode 100644 src/main/java/com/gomo/app/core/auth/adapter/out/client/MemberClient.java rename src/main/java/com/gomo/app/{support/auth/infrastructure/oauth/provider/GoogleOAuthProvider.java => core/auth/adapter/out/client/OAuthGoogleClient.java} (87%) rename src/main/java/com/gomo/app/{support/auth/infrastructure/oauth/provider/KakaoOAuthProvider.java => core/auth/adapter/out/client/OAuthKakaoClient.java} (90%) rename src/main/java/com/gomo/app/{support/auth/infrastructure/oauth/provider/NaverOAuthProvider.java => core/auth/adapter/out/client/OAuthNaverClient.java} (88%) create mode 100644 src/main/java/com/gomo/app/core/auth/adapter/out/factory/OAuthProviderFactory.java rename src/main/java/com/gomo/app/{common/security/jwt/application/ManageJwtUseCase.java => core/auth/adapter/out/lib/JwtClient.java} (78%) rename src/main/java/com/gomo/app/{support/auth/infrastructure => core/auth/adapter/out}/persistence/AuditorAwareImpl.java (75%) rename src/main/java/com/gomo/app/{support/auth/infrastructure => core/auth/adapter/out}/persistence/RedisAuthCodeRepository.java (87%) rename src/main/java/com/gomo/app/{support/auth/infrastructure => core/auth/adapter/out}/persistence/RedisAuthTokenRepository.java (78%) create mode 100644 src/main/java/com/gomo/app/core/auth/application/port/command/CreatePrincipalCommand.java rename src/main/java/com/gomo/app/{support => core}/auth/application/port/dto/AuthTokenDto.java (85%) rename src/main/java/com/gomo/app/{support => core}/auth/application/port/dto/OAuthTokenDto.java (91%) create mode 100644 src/main/java/com/gomo/app/core/auth/application/port/in/AuthCodeIssuer.java create mode 100644 src/main/java/com/gomo/app/core/auth/application/port/in/AuthTokenIssuer.java create mode 100644 src/main/java/com/gomo/app/core/auth/application/port/in/LoginProcessor.java create mode 100644 src/main/java/com/gomo/app/core/auth/application/port/in/OAuthLoginProcessor.java rename src/main/java/com/gomo/app/{support/auth/application/port/DeleteAuthTokenPortIn.java => core/auth/application/port/in/RefreshTokenDeleter.java} (58%) create mode 100644 src/main/java/com/gomo/app/core/auth/application/port/in/RefreshTokenUpdater.java create mode 100644 src/main/java/com/gomo/app/core/auth/application/port/in/SignupProcessor.java rename src/main/java/com/gomo/app/{support/auth/application/port/SendAuthCodePortOut.java => core/auth/application/port/out/AuthCodeSender.java} (65%) create mode 100644 src/main/java/com/gomo/app/core/auth/application/port/out/JwtCreator.java create mode 100644 src/main/java/com/gomo/app/core/auth/application/port/out/JwtVerifier.java create mode 100644 src/main/java/com/gomo/app/core/auth/application/port/out/OAuthProvider.java create mode 100644 src/main/java/com/gomo/app/core/auth/application/port/out/OAuthProviderReader.java create mode 100644 src/main/java/com/gomo/app/core/auth/application/port/out/PrincipalCreator.java create mode 100644 src/main/java/com/gomo/app/core/auth/application/port/out/PrincipalEmailChecker.java create mode 100644 src/main/java/com/gomo/app/core/auth/application/port/out/PrincipalLoginProcessor.java create mode 100644 src/main/java/com/gomo/app/core/auth/application/port/out/PrincipalOAuthLoginProcessor.java create mode 100644 src/main/java/com/gomo/app/core/auth/application/service/AuthCodeService.java create mode 100644 src/main/java/com/gomo/app/core/auth/application/service/AuthService.java create mode 100644 src/main/java/com/gomo/app/core/auth/application/service/AuthTokenService.java create mode 100644 src/main/java/com/gomo/app/core/auth/application/service/OAuthService.java create mode 100644 src/main/java/com/gomo/app/core/auth/domain/exception/AuthCodeCreateFailException.java rename src/main/java/com/gomo/app/{support/auth => core/auth/domain}/exception/AuthErrorCode.java (64%) rename src/main/java/com/gomo/app/{support/auth => core/auth/domain}/exception/AuthenticationFailException.java (88%) rename src/main/java/com/gomo/app/{support/auth => core/auth/domain}/exception/InvalidAuthCodeException.java (87%) rename src/main/java/com/gomo/app/{support => core}/auth/domain/model/AuthCode.java (93%) rename src/main/java/com/gomo/app/{support => core}/auth/domain/model/AuthToken.java (90%) rename src/main/java/com/gomo/app/{support => core}/auth/domain/model/OAuthPrincipal.java (92%) rename src/main/java/com/gomo/app/{support => core}/auth/domain/repository/AuthCodeRepository.java (78%) create mode 100644 src/main/java/com/gomo/app/core/auth/domain/repository/AuthTokenRepository.java rename src/main/java/com/gomo/app/core/interest/{presentation => adapter/in}/api/InterestApi.java (55%) rename src/main/java/com/gomo/app/core/interest/{presentation => adapter/in}/api/InterestLogoApi.java (74%) rename src/main/java/com/gomo/app/core/interest/{presentation => adapter/in}/api/InterestNetworkApi.java (52%) rename src/main/java/com/gomo/app/core/interest/{presentation => adapter/in}/api/MajorInterestApi.java (55%) rename src/main/java/com/gomo/app/core/interest/{presentation => adapter/in}/api/OrderUpdateMajorInterestApi.java (52%) rename src/main/java/com/gomo/app/core/interest/{presentation => adapter/in}/api/request/CreateInterestRelationRequest.java (85%) rename src/main/java/com/gomo/app/core/interest/{presentation => adapter/in}/api/request/CreateInterestRequest.java (89%) rename src/main/java/com/gomo/app/core/interest/{presentation => adapter/in}/api/request/OrderUpdateMajorInterestRequest.java (89%) rename src/main/java/com/gomo/app/core/interest/{presentation => adapter/in}/api/request/UpdateInterestRequest.java (87%) rename src/main/java/com/gomo/app/core/interest/{presentation => adapter/in}/api/response/CreateInterestRelationResponse.java (79%) rename src/main/java/com/gomo/app/core/interest/{presentation => adapter/in}/api/response/CreateInterestResponse.java (77%) rename src/main/java/com/gomo/app/core/interest/{presentation => adapter/in}/api/response/CreateMajorInterestResponse.java (79%) rename src/main/java/com/gomo/app/core/interest/{presentation => adapter/in}/api/response/InterestNetworkResponse.java (91%) rename src/main/java/com/gomo/app/core/interest/{presentation => adapter/in}/api/response/ListInterestResponse.java (82%) rename src/main/java/com/gomo/app/core/interest/{presentation => adapter/in}/api/response/ListMajorInterestResponse.java (87%) rename src/main/java/com/gomo/app/core/interest/{presentation => adapter/in}/api/response/ReadInterestRelationResponse.java (89%) rename src/main/java/com/gomo/app/core/interest/{presentation => adapter/in}/api/response/ReadInterestResponse.java (91%) rename src/main/java/com/gomo/app/core/interest/{presentation => adapter/in}/api/response/ReadMajorInterestResponse.java (90%) rename src/main/java/com/gomo/app/core/interest/{presentation => adapter/in}/consumer/CompleteQuestEventScoreConsumer.java (67%) create mode 100644 src/main/java/com/gomo/app/core/interest/adapter/out/client/LogoClient.java rename src/main/java/com/gomo/app/core/interest/{infrastructure/adapter/ReadRegistrantAdapter.java => adapter/out/client/RegistrantClient.java} (52%) rename src/main/java/com/gomo/app/core/interest/{infrastructure/repository/LevelThresholdPolicyRepositoryImpl.java => adapter/out/persistence/JDBCLevelThresholdPolicyRepository.java} (81%) create mode 100644 src/main/java/com/gomo/app/core/interest/application/port/in/InterestCreator.java create mode 100644 src/main/java/com/gomo/app/core/interest/application/port/in/InterestDeleter.java create mode 100644 src/main/java/com/gomo/app/core/interest/application/port/in/InterestNetworkReader.java rename src/main/java/com/gomo/app/core/interest/application/port/{ReadInterestPortIn.java => in/InterestReader.java} (78%) create mode 100644 src/main/java/com/gomo/app/core/interest/application/port/in/InterestRelationCreator.java create mode 100644 src/main/java/com/gomo/app/core/interest/application/port/in/InterestRelationDeleter.java create mode 100644 src/main/java/com/gomo/app/core/interest/application/port/in/InterestUpdater.java create mode 100644 src/main/java/com/gomo/app/core/interest/application/port/in/LogoUpdater.java create mode 100644 src/main/java/com/gomo/app/core/interest/application/port/in/MajorInterestCreator.java create mode 100644 src/main/java/com/gomo/app/core/interest/application/port/in/MajorInterestDeleter.java create mode 100644 src/main/java/com/gomo/app/core/interest/application/port/in/MajorInterestOrderUpdater.java create mode 100644 src/main/java/com/gomo/app/core/interest/application/port/in/MajorInterestReader.java rename src/main/java/com/gomo/app/core/interest/application/port/{AdjustProficiencyPortIn.java => in/ProficiencyPropagator.java} (52%) create mode 100644 src/main/java/com/gomo/app/core/interest/application/port/out/LogoDeleter.java create mode 100644 src/main/java/com/gomo/app/core/interest/application/port/out/LogoUploader.java rename src/main/java/com/gomo/app/core/interest/application/port/{ReadRegistrantPortOut.java => out/RegistrantReader.java} (78%) rename src/main/java/com/gomo/app/core/interest/application/{usecase/CreateInterestUseCase.java => service/InterestCreateService.java} (69%) create mode 100644 src/main/java/com/gomo/app/core/interest/application/service/InterestDeleteService.java create mode 100644 src/main/java/com/gomo/app/core/interest/application/service/InterestNetworkService.java create mode 100644 src/main/java/com/gomo/app/core/interest/application/service/InterestRelationService.java rename src/main/java/com/gomo/app/core/interest/application/{usecase/ReadInterestUseCase.java => service/InterestService.java} (56%) rename src/main/java/com/gomo/app/core/interest/application/{usecase/UpdateLogoUseCase.java => service/LogoService.java} (52%) create mode 100644 src/main/java/com/gomo/app/core/interest/application/service/MajorInterestService.java create mode 100644 src/main/java/com/gomo/app/core/interest/application/service/ProficiencyService.java delete mode 100644 src/main/java/com/gomo/app/core/interest/application/usecase/AdjustProficiencyUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/interest/application/usecase/CreateInterestRelationUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/interest/application/usecase/CreateMajorInterestUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/interest/application/usecase/DeleteInterestRelationUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/interest/application/usecase/DeleteInterestUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/interest/application/usecase/DeleteMajorInterestUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/interest/application/usecase/OrderUpdateMajorInterestUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/interest/application/usecase/ReadInterestNetworkUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/interest/application/usecase/ReadMajorInterestUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/interest/application/usecase/UpdateInterestUseCase.java rename src/main/java/com/gomo/app/core/interest/{ => domain}/exception/InterestAccessDeniedException.java (77%) rename src/main/java/com/gomo/app/core/interest/{ => domain}/exception/InterestConstraintViolationException.java (77%) rename src/main/java/com/gomo/app/core/interest/{ => domain}/exception/InterestNameConstraintViolationException.java (77%) rename src/main/java/com/gomo/app/core/interest/{ => domain}/exception/InterestNotFoundException.java (76%) rename src/main/java/com/gomo/app/core/interest/{ => domain}/exception/InterestRelationAccessDeniedException.java (77%) rename src/main/java/com/gomo/app/core/interest/{ => domain}/exception/InterestRelationCycleException.java (76%) rename src/main/java/com/gomo/app/core/interest/{ => domain}/exception/InterestRelationDuplicatedException.java (77%) rename src/main/java/com/gomo/app/core/interest/{ => domain}/exception/InterestRelationNotFoundException.java (77%) rename src/main/java/com/gomo/app/core/interest/{ => domain}/exception/LevelConstraintViolationException.java (77%) rename src/main/java/com/gomo/app/core/interest/{ => domain}/exception/MajorInterestAccessDeniedException.java (77%) rename src/main/java/com/gomo/app/core/interest/{ => domain}/exception/MajorInterestDuplicatedException.java (77%) rename src/main/java/com/gomo/app/core/interest/{ => domain}/exception/MajorInterestNotFoundException.java (76%) rename src/main/java/com/gomo/app/core/interest/{ => domain}/exception/ProficiencyAdjustFailureException.java (77%) rename src/main/java/com/gomo/app/core/interest/{ => domain}/exception/ScoreConstraintViolationException.java (77%) rename src/main/java/com/gomo/app/core/interest/{ => domain}/exception/code/InterestErrorCode.java (87%) rename src/main/java/com/gomo/app/core/interest/{ => domain}/exception/code/InterestNameErrorCode.java (87%) rename src/main/java/com/gomo/app/core/interest/{ => domain}/exception/code/InterestRelationErrorCode.java (81%) rename src/main/java/com/gomo/app/core/interest/{ => domain}/exception/code/LevelErrorCode.java (88%) rename src/main/java/com/gomo/app/core/interest/{ => domain}/exception/code/MajorInterestErrorCode.java (87%) rename src/main/java/com/gomo/app/core/interest/{ => domain}/exception/code/ProficiencyErrorCode.java (86%) rename src/main/java/com/gomo/app/core/interest/{ => domain}/exception/code/ScoreErrorCode.java (83%) create mode 100644 src/main/java/com/gomo/app/core/interest/domain/service/InterestNetworkBuilder.java delete mode 100644 src/main/java/com/gomo/app/core/interest/domain/service/InterestRelationService.java delete mode 100644 src/main/java/com/gomo/app/core/interest/domain/service/InterestService.java delete mode 100644 src/main/java/com/gomo/app/core/interest/domain/service/LogoService.java delete mode 100644 src/main/java/com/gomo/app/core/interest/domain/service/MajorInterestService.java rename src/main/java/com/gomo/app/core/interest/domain/{model => service}/ProficiencyCalculator.java (76%) delete mode 100644 src/main/java/com/gomo/app/core/interest/domain/service/ProficiencyService.java rename src/main/java/com/gomo/app/core/member/{presentation => adapter/in/api}/HandleApi.java (56%) create mode 100644 src/main/java/com/gomo/app/core/member/adapter/in/api/MemberApi.java create mode 100644 src/main/java/com/gomo/app/core/member/adapter/in/api/PasswordApi.java rename src/main/java/com/gomo/app/core/member/{presentation => adapter/in/api}/ProfileBannerApi.java (55%) rename src/main/java/com/gomo/app/core/member/{presentation => adapter/in/api}/ProfileImageApi.java (54%) rename src/main/java/com/gomo/app/core/member/{presentation => adapter/in/api}/QuestPropertyApi.java (51%) rename src/main/java/com/gomo/app/core/member/{presentation => adapter/in/api}/WidgetApi.java (54%) rename src/main/java/com/gomo/app/core/member/{presentation => adapter/in/api}/request/ResetPasswordRequest.java (90%) rename src/main/java/com/gomo/app/core/member/{presentation => adapter/in/api}/request/UpdateHandleRequest.java (78%) rename src/main/java/com/gomo/app/core/member/{presentation => adapter/in/api}/request/UpdateMemberRequest.java (82%) rename src/main/java/com/gomo/app/core/member/{presentation => adapter/in/api}/request/UpdatePasswordRequest.java (85%) rename src/main/java/com/gomo/app/core/member/{presentation => adapter/in/api}/request/UpdateProfileBannerRequest.java (84%) rename src/main/java/com/gomo/app/core/member/{presentation => adapter/in/api}/request/UpdateProfileImageRequest.java (84%) rename src/main/java/com/gomo/app/core/member/{presentation => adapter/in/api}/request/UpdateQuestPropertyRequest.java (91%) rename src/main/java/com/gomo/app/core/member/{presentation => adapter/in/api}/request/UpdateWidgetRequest.java (79%) rename src/main/java/com/gomo/app/core/member/{presentation => adapter/in/api}/response/ReadMemberResponse.java (93%) rename src/main/java/com/gomo/app/core/member/{presentation => adapter/in/api}/response/ReadQuestPropertyResponse.java (89%) create mode 100644 src/main/java/com/gomo/app/core/member/adapter/out/MemberEventPublisher.java create mode 100644 src/main/java/com/gomo/app/core/member/adapter/out/client/AuthClient.java create mode 100644 src/main/java/com/gomo/app/core/member/adapter/out/client/EmailTokenClient.java create mode 100644 src/main/java/com/gomo/app/core/member/adapter/out/client/PointBalanceClient.java create mode 100644 src/main/java/com/gomo/app/core/member/adapter/out/client/ProfileAssetClient.java create mode 100644 src/main/java/com/gomo/app/core/member/adapter/out/lib/BcryptEncoder.java delete mode 100644 src/main/java/com/gomo/app/core/member/application/port/LoginMemberPortIn.java delete mode 100644 src/main/java/com/gomo/app/core/member/application/port/ReadActiveMemberPortIn.java delete mode 100644 src/main/java/com/gomo/app/core/member/application/port/dto/UpdateProfileBannerDto.java delete mode 100644 src/main/java/com/gomo/app/core/member/application/port/dto/UpdateProfileImageDto.java create mode 100644 src/main/java/com/gomo/app/core/member/application/port/in/EmailChecker.java create mode 100644 src/main/java/com/gomo/app/core/member/application/port/in/HandleUpdater.java create mode 100644 src/main/java/com/gomo/app/core/member/application/port/in/HandleValidator.java create mode 100644 src/main/java/com/gomo/app/core/member/application/port/in/MemberCreator.java create mode 100644 src/main/java/com/gomo/app/core/member/application/port/in/MemberDeleter.java create mode 100644 src/main/java/com/gomo/app/core/member/application/port/in/MemberLoginProcessor.java rename src/main/java/com/gomo/app/core/member/application/port/{OAuthLoginMemberPortIn.java => in/MemberOAuthLoginProcessor.java} (60%) rename src/main/java/com/gomo/app/core/member/application/port/{ReadMemberPortIn.java => in/MemberReader.java} (65%) create mode 100644 src/main/java/com/gomo/app/core/member/application/port/in/MemberUpdater.java create mode 100644 src/main/java/com/gomo/app/core/member/application/port/in/PasswordResetter.java create mode 100644 src/main/java/com/gomo/app/core/member/application/port/in/PasswordUpdater.java create mode 100644 src/main/java/com/gomo/app/core/member/application/port/in/ProfileBannerDeleter.java create mode 100644 src/main/java/com/gomo/app/core/member/application/port/in/ProfileBannerUpdater.java create mode 100644 src/main/java/com/gomo/app/core/member/application/port/in/ProfileImageDeleter.java create mode 100644 src/main/java/com/gomo/app/core/member/application/port/in/ProfileImageUpdater.java create mode 100644 src/main/java/com/gomo/app/core/member/application/port/in/QuestPropertyReader.java create mode 100644 src/main/java/com/gomo/app/core/member/application/port/in/QuestPropertyUpdater.java create mode 100644 src/main/java/com/gomo/app/core/member/application/port/in/WidgetUpdater.java create mode 100644 src/main/java/com/gomo/app/core/member/application/port/out/EmailTokenVerifier.java create mode 100644 src/main/java/com/gomo/app/core/member/application/port/out/MemberCreateEventPublisher.java create mode 100644 src/main/java/com/gomo/app/core/member/application/port/out/MemberLogoutProcessor.java create mode 100644 src/main/java/com/gomo/app/core/member/application/port/out/PasswordEncodeManager.java create mode 100644 src/main/java/com/gomo/app/core/member/application/port/out/PointBalanceReader.java create mode 100644 src/main/java/com/gomo/app/core/member/application/port/out/ProfileAssetUploader.java create mode 100644 src/main/java/com/gomo/app/core/member/application/service/EmailService.java create mode 100644 src/main/java/com/gomo/app/core/member/application/service/HandleService.java create mode 100644 src/main/java/com/gomo/app/core/member/application/service/MemberCreateService.java create mode 100644 src/main/java/com/gomo/app/core/member/application/service/MemberLoginService.java rename src/main/java/com/gomo/app/core/member/application/{usecase/OAuthLoginMemberUseCase.java => service/MemberOAuthLoginService.java} (67%) create mode 100644 src/main/java/com/gomo/app/core/member/application/service/MemberService.java create mode 100644 src/main/java/com/gomo/app/core/member/application/service/PasswordService.java create mode 100644 src/main/java/com/gomo/app/core/member/application/service/ProfileBannerService.java create mode 100644 src/main/java/com/gomo/app/core/member/application/service/ProfileImageService.java create mode 100644 src/main/java/com/gomo/app/core/member/application/service/QuestPropertyService.java rename src/main/java/com/gomo/app/core/member/application/{usecase/UpdateWidgetUseCase.java => service/WidgetService.java} (56%) delete mode 100644 src/main/java/com/gomo/app/core/member/application/usecase/CheckHandleUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/member/application/usecase/CreateEmailCodeUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/member/application/usecase/CreateMemberUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/member/application/usecase/DeleteMemberUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/member/application/usecase/DeleteProfileBannerUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/member/application/usecase/DeleteProfileImageUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/member/application/usecase/LoginMemberUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/member/application/usecase/ReadMemberUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/member/application/usecase/ReadQuestPropertyUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/member/application/usecase/ResetPasswordUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/member/application/usecase/UpdateHandleUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/member/application/usecase/UpdateMemberUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/member/application/usecase/UpdatePasswordUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/member/application/usecase/UpdateProfileBannerUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/member/application/usecase/UpdateProfileImageUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/member/application/usecase/UpdateQuestPropertyUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/member/application/usecase/VerifyEmailCodeUseCase.java rename src/main/java/com/gomo/app/core/member/{ => domain}/exception/ActivateStatusException.java (76%) rename src/main/java/com/gomo/app/core/member/{ => domain}/exception/EmailConstraintViolationException.java (78%) rename src/main/java/com/gomo/app/core/member/{ => domain}/exception/EmailDuplicatedException.java (77%) rename src/main/java/com/gomo/app/core/member/{ => domain}/exception/HandleConstraintViolationException.java (78%) rename src/main/java/com/gomo/app/core/member/{ => domain}/exception/HandleDuplicatedException.java (77%) create mode 100644 src/main/java/com/gomo/app/core/member/domain/exception/MemberAuthenticationFailedException.java create mode 100644 src/main/java/com/gomo/app/core/member/domain/exception/MemberDuplicatedException.java rename src/main/java/com/gomo/app/core/member/{ => domain}/exception/MemberNameConstraintViolationException.java (78%) rename src/main/java/com/gomo/app/core/member/{ => domain}/exception/MemberNotFoundException.java (76%) rename src/main/java/com/gomo/app/core/member/{ => domain}/exception/MottoConstraintViolationException.java (78%) rename src/main/java/com/gomo/app/core/member/{ => domain}/exception/PasswordConstraintViolationException.java (78%) rename src/main/java/com/gomo/app/core/member/{ => domain}/exception/PasswordMismatchException.java (77%) rename src/main/java/com/gomo/app/core/member/{ => domain}/exception/QuestPropertyConstraintViolationException.java (78%) rename src/main/java/com/gomo/app/core/member/{ => domain}/exception/code/ActivateStatusErrorCode.java (86%) rename src/main/java/com/gomo/app/core/member/{ => domain}/exception/code/EmailErrorCode.java (89%) rename src/main/java/com/gomo/app/core/member/{ => domain}/exception/code/HandleErrorCode.java (89%) rename src/main/java/com/gomo/app/core/member/{ => domain}/exception/code/MemberErrorCode.java (87%) rename src/main/java/com/gomo/app/core/member/{ => domain}/exception/code/MemberNameErrorCode.java (88%) rename src/main/java/com/gomo/app/core/member/{ => domain}/exception/code/MottoErrorCode.java (86%) rename src/main/java/com/gomo/app/core/member/{ => domain}/exception/code/PasswordErrorCode.java (92%) rename src/main/java/com/gomo/app/core/member/{ => domain}/exception/code/QuestPropertyErrorCode.java (87%) delete mode 100644 src/main/java/com/gomo/app/core/member/domain/service/MemberService.java delete mode 100644 src/main/java/com/gomo/app/core/member/domain/service/ProfileImageService.java delete mode 100644 src/main/java/com/gomo/app/core/member/exception/MemberAuthenticationFailedException.java delete mode 100644 src/main/java/com/gomo/app/core/member/exception/MemberDuplicatedException.java delete mode 100644 src/main/java/com/gomo/app/core/member/presentation/EmailCodeApi.java delete mode 100644 src/main/java/com/gomo/app/core/member/presentation/MemberApi.java delete mode 100644 src/main/java/com/gomo/app/core/member/presentation/PasswordApi.java delete mode 100644 src/main/java/com/gomo/app/core/member/presentation/request/CreateMemberRequest.java delete mode 100644 src/main/java/com/gomo/app/core/member/presentation/response/CreateEmailCodeResponse.java delete mode 100644 src/main/java/com/gomo/app/core/member/presentation/response/CreateMemberResponse.java rename src/main/java/com/gomo/app/core/point/{presentation => adapter/in}/api/PointApi.java (53%) rename src/main/java/com/gomo/app/core/point/{presentation => adapter/in}/api/response/ListPointResponse.java (87%) rename src/main/java/com/gomo/app/core/point/{presentation => adapter/in}/api/response/ReadBalanceResponse.java (77%) rename src/main/java/com/gomo/app/core/point/{presentation => adapter/in}/api/response/ReadPointResponse.java (91%) rename src/main/java/com/gomo/app/core/point/{presentation => adapter/in}/consumer/CompleteQuestEventPointConsumer.java (66%) rename src/main/java/com/gomo/app/core/point/application/port/{ReadBalancePortIn.java => in/BalanceReader.java} (63%) rename src/main/java/com/gomo/app/core/point/application/port/{CreatePointPortIn.java => in/PointCreator.java} (90%) create mode 100644 src/main/java/com/gomo/app/core/point/application/port/in/PointReader.java rename src/main/java/com/gomo/app/core/point/application/port/{CreatePointWalletPortIn.java => in/PointWalletCreator.java} (60%) create mode 100644 src/main/java/com/gomo/app/core/point/application/service/BalanceService.java create mode 100644 src/main/java/com/gomo/app/core/point/application/service/PointService.java create mode 100644 src/main/java/com/gomo/app/core/point/application/service/PointWalletService.java delete mode 100644 src/main/java/com/gomo/app/core/point/application/usecase/CreatePointUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/point/application/usecase/CreatePointWalletUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/point/application/usecase/ReadBalanceUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/point/application/usecase/ReadPointUseCase.java rename src/main/java/com/gomo/app/core/point/{ => domain}/exception/InsufficientBalanceException.java (77%) rename src/main/java/com/gomo/app/core/point/{ => domain}/exception/PointConstraintViolationException.java (78%) rename src/main/java/com/gomo/app/core/point/{ => domain}/exception/PointWalletNotFoundException.java (77%) rename src/main/java/com/gomo/app/core/point/{ => domain}/exception/code/BalanceErrorCode.java (84%) rename src/main/java/com/gomo/app/core/point/{ => domain}/exception/code/PointErrorCode.java (87%) rename src/main/java/com/gomo/app/core/point/{ => domain}/exception/code/PointWalletErrorCode.java (86%) delete mode 100644 src/main/java/com/gomo/app/core/point/domain/service/PointService.java delete mode 100644 src/main/java/com/gomo/app/core/point/domain/service/PointWalletService.java create mode 100644 src/main/java/com/gomo/app/core/quest/adapter/in/api/AssignQuestApi.java create mode 100644 src/main/java/com/gomo/app/core/quest/adapter/in/api/CalendarAssignQuestApi.java rename src/main/java/com/gomo/app/core/quest/{presentation => adapter/in}/api/CompleteAssignQuestApi.java (57%) rename src/main/java/com/gomo/app/core/quest/{presentation => adapter/in}/api/ConfirmAssignQuestApi.java (59%) rename src/main/java/com/gomo/app/core/quest/{presentation => adapter/in}/api/OrderUpdateAssignQuestApi.java (53%) rename src/main/java/com/gomo/app/core/quest/{presentation => adapter/in}/api/OrderUpdateRepeatQuestApi.java (53%) create mode 100644 src/main/java/com/gomo/app/core/quest/adapter/in/api/ReRollAssignQuestApi.java rename src/main/java/com/gomo/app/core/quest/{presentation => adapter/in}/api/RepeatQuestApi.java (52%) rename src/main/java/com/gomo/app/core/quest/{presentation => adapter/in}/api/request/CompleteAssignQuestRequest.java (88%) rename src/main/java/com/gomo/app/core/quest/{presentation => adapter/in}/api/request/CreateAssignQuestRequest.java (90%) rename src/main/java/com/gomo/app/core/quest/{presentation => adapter/in}/api/request/CreateRepeatQuestRequest.java (90%) rename src/main/java/com/gomo/app/core/quest/{presentation => adapter/in}/api/request/OrderUpdateAssignQuestRequest.java (90%) rename src/main/java/com/gomo/app/core/quest/{presentation => adapter/in}/api/request/OrderUpdateRepeatQuestRequest.java (90%) rename src/main/java/com/gomo/app/core/quest/{presentation => adapter/in}/api/request/ReRollAssignQuestRequest.java (81%) rename src/main/java/com/gomo/app/core/quest/{presentation => adapter/in}/api/request/UpdateAssignQuestRequest.java (91%) rename src/main/java/com/gomo/app/core/quest/{presentation => adapter/in}/api/request/UpdateRepeatQuestRequest.java (91%) rename src/main/java/com/gomo/app/core/quest/{presentation => adapter/in}/api/response/CreateAssignQuestResponse.java (78%) rename src/main/java/com/gomo/app/core/quest/{presentation => adapter/in}/api/response/CreateRepeatQuestResponse.java (78%) create mode 100644 src/main/java/com/gomo/app/core/quest/adapter/in/api/response/ListAssignQuestDetailResponse.java create mode 100644 src/main/java/com/gomo/app/core/quest/adapter/in/api/response/ListAssignQuestResponse.java rename src/main/java/com/gomo/app/core/quest/{presentation => adapter/in}/api/response/ListRepeatQuestResponse.java (91%) rename src/main/java/com/gomo/app/core/quest/{presentation/api/response/ReadAssignQuestResponse.java => adapter/in/api/response/ReadAssignQuestDetailResponse.java} (78%) rename src/main/java/com/gomo/app/core/quest/{presentation/api/response/CalendarAssignQuestResponse.java => adapter/in/api/response/ReadAssignQuestResponse.java} (68%) rename src/main/java/com/gomo/app/core/quest/{presentation => adapter/in}/api/response/ReadRepeatQuestResponse.java (90%) rename src/main/java/com/gomo/app/core/quest/{presentation => adapter/in}/consumer/FillQuestPoolEventConsumer.java (69%) rename src/main/java/com/gomo/app/core/quest/{infrastructure/adapter/LlmCreateQuestContentAdapter.java => adapter/out/client/LlmQuestContentClient.java} (85%) rename src/main/java/com/gomo/app/core/quest/{infrastructure/adapter/ReadParticipantAdapter.java => adapter/out/client/ParticipantClient.java} (53%) create mode 100644 src/main/java/com/gomo/app/core/quest/adapter/out/client/SubjectClient.java rename src/main/java/com/gomo/app/core/quest/{infrastructure/repository => adapter/out/persistence}/InMemoryQuestRewardPolicyRepository.java (91%) rename src/main/java/com/gomo/app/core/quest/{infrastructure/repository => adapter/out/persistence}/JdbcBulkAssignQuestRepository.java (97%) delete mode 100644 src/main/java/com/gomo/app/core/quest/application/port/command/CalendarAssignQuestCommand.java create mode 100644 src/main/java/com/gomo/app/core/quest/application/port/command/ListAssignQuestCommand.java delete mode 100644 src/main/java/com/gomo/app/core/quest/application/port/dto/ActiveParticipantDto.java create mode 100644 src/main/java/com/gomo/app/core/quest/application/port/dto/AssignQuestDetailDto.java delete mode 100644 src/main/java/com/gomo/app/core/quest/application/port/dto/CalendarAssignQuestDto.java create mode 100644 src/main/java/com/gomo/app/core/quest/application/port/dto/ListAssignQuestDetailDto.java delete mode 100644 src/main/java/com/gomo/app/core/quest/application/port/dto/ListAssignQuestDto.java create mode 100644 src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestCompleter.java create mode 100644 src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestConfirmer.java create mode 100644 src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestCreator.java create mode 100644 src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestDeleter.java create mode 100644 src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestDetailReader.java create mode 100644 src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestOrderUpdater.java create mode 100644 src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestReRoller.java create mode 100644 src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestReader.java rename src/main/java/com/gomo/app/core/quest/application/port/{AutoCreateAssignQuestPortIn.java => in/AssignQuestRoutineCreator.java} (84%) create mode 100644 src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestUpdater.java rename src/main/java/com/gomo/app/core/quest/application/port/{CreateQuestPoolPortIn.java => in/QuestPoolCreator.java} (81%) rename src/main/java/com/gomo/app/core/quest/application/port/{PublishCreateQuestPoolPortIn.java => in/QuestPoolEventPublisher.java} (59%) create mode 100644 src/main/java/com/gomo/app/core/quest/application/port/in/RepeatQuestCreator.java create mode 100644 src/main/java/com/gomo/app/core/quest/application/port/in/RepeatQuestDeleter.java create mode 100644 src/main/java/com/gomo/app/core/quest/application/port/in/RepeatQuestOrderUpdater.java create mode 100644 src/main/java/com/gomo/app/core/quest/application/port/in/RepeatQuestReader.java create mode 100644 src/main/java/com/gomo/app/core/quest/application/port/in/RepeatQuestUpdater.java rename src/main/java/com/gomo/app/core/quest/application/port/{ReadParticipantPortOut.java => out/ParticipantReader.java} (57%) rename src/main/java/com/gomo/app/core/quest/application/port/{CreateQuestContentPortOut.java => out/QuestContentCreator.java} (84%) rename src/main/java/com/gomo/app/core/quest/application/port/{ReadSubjectPortOut.java => out/SubjectReader.java} (79%) rename src/main/java/com/gomo/app/core/quest/application/{usecase/CompleteAssignQuestUseCase.java => service/AssignQuestCompleteService.java} (69%) rename src/main/java/com/gomo/app/core/quest/application/{usecase/CreateAssignQuestUseCase.java => service/AssignQuestCreateService.java} (58%) rename src/main/java/com/gomo/app/core/quest/application/{usecase/ReRollAssignQuestUseCase.java => service/AssignQuestReRollService.java} (56%) rename src/main/java/com/gomo/app/core/quest/application/{usecase/AutoCreateAssignQuestUseCase.java => service/AssignQuestRoutineService.java} (90%) create mode 100644 src/main/java/com/gomo/app/core/quest/application/service/AssignQuestService.java rename src/main/java/com/gomo/app/core/quest/application/{usecase/CreateQuestPoolUseCase.java => service/QuestPoolCreateService.java} (76%) rename src/main/java/com/gomo/app/core/quest/application/{usecase/PublishCreateQuestPoolUseCase.java => service/QuestPoolEventService.java} (68%) rename src/main/java/com/gomo/app/core/quest/application/{usecase/CreateRepeatQuestUseCase.java => service/RepeatQuestCreateService.java} (61%) create mode 100644 src/main/java/com/gomo/app/core/quest/application/service/RepeatQuestService.java delete mode 100644 src/main/java/com/gomo/app/core/quest/application/usecase/CalendarAssignQuestUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/quest/application/usecase/ConfirmAssignQuestUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/quest/application/usecase/DeleteAssignQuestUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/quest/application/usecase/DeleteRepeatQuestUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/quest/application/usecase/OrderUpdateAssignQuestUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/quest/application/usecase/OrderUpdateRepeatQuestUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/quest/application/usecase/ReadAssignQuestUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/quest/application/usecase/ReadRepeatQuestUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/quest/application/usecase/UpdateAssignQuestUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/quest/application/usecase/UpdateRepeatQuestUseCase.java rename src/main/java/com/gomo/app/core/quest/{ => domain}/event/CompleteQuestEvent.java (94%) rename src/main/java/com/gomo/app/core/quest/{ => domain}/event/CreateQuestPoolEvent.java (94%) rename src/main/java/com/gomo/app/core/quest/{ => domain}/exception/AssignQuestAccessDeniedException.java (77%) rename src/main/java/com/gomo/app/core/quest/{ => domain}/exception/AssignQuestConstraintViolationException.java (78%) rename src/main/java/com/gomo/app/core/quest/{ => domain}/exception/AssignQuestNotFoundException.java (77%) rename src/main/java/com/gomo/app/core/quest/{ => domain}/exception/CompletionProofConstraintViolationException.java (78%) rename src/main/java/com/gomo/app/core/quest/{ => domain}/exception/InvalidPeriodTypeException.java (77%) rename src/main/java/com/gomo/app/core/quest/{ => domain}/exception/QuestAccessDeniedException.java (77%) rename src/main/java/com/gomo/app/core/quest/{ => domain}/exception/QuestConstraintViolationException.java (78%) rename src/main/java/com/gomo/app/core/quest/{ => domain}/exception/QuestContentConstraintViolationException.java (78%) rename src/main/java/com/gomo/app/core/quest/{ => domain}/exception/QuestPoolNotFoundException.java (77%) rename src/main/java/com/gomo/app/core/quest/{ => domain}/exception/QuestTypeConstraintViolationException.java (78%) rename src/main/java/com/gomo/app/core/quest/{ => domain}/exception/RepeatQuestAccessDeniedException.java (77%) rename src/main/java/com/gomo/app/core/quest/{ => domain}/exception/RepeatQuestNotFoundException.java (77%) rename src/main/java/com/gomo/app/core/quest/{ => domain}/exception/RepeatQuestThresholdExceededException.java (78%) rename src/main/java/com/gomo/app/core/quest/{ => domain}/exception/code/AssignQuestErrorCode.java (91%) rename src/main/java/com/gomo/app/core/quest/{ => domain}/exception/code/CompletionProofErrorCode.java (86%) rename src/main/java/com/gomo/app/core/quest/{ => domain}/exception/code/QuestContentErrorCode.java (89%) rename src/main/java/com/gomo/app/core/quest/{ => domain}/exception/code/QuestErrorCode.java (85%) rename src/main/java/com/gomo/app/core/quest/{ => domain}/exception/code/QuestPoolErrorCode.java (83%) rename src/main/java/com/gomo/app/core/quest/{ => domain}/exception/code/QuestTypeErrorCode.java (86%) rename src/main/java/com/gomo/app/core/quest/{ => domain}/exception/code/RepeatQuestErrorCode.java (86%) delete mode 100644 src/main/java/com/gomo/app/core/quest/domain/service/AssignQuestService.java rename src/main/java/com/gomo/app/core/quest/domain/service/{QuestRewardService.java => QuestRewardProvider.java} (89%) delete mode 100644 src/main/java/com/gomo/app/core/quest/domain/service/RepeatQuestService.java delete mode 100644 src/main/java/com/gomo/app/core/quest/infrastructure/adapter/ReadSubjectAdapter.java delete mode 100644 src/main/java/com/gomo/app/core/quest/presentation/api/AssignQuestApi.java delete mode 100644 src/main/java/com/gomo/app/core/quest/presentation/api/CalendarAssignQuestApi.java delete mode 100644 src/main/java/com/gomo/app/core/quest/presentation/api/ReRollAssignQuestApi.java delete mode 100644 src/main/java/com/gomo/app/core/quest/presentation/api/response/ListAssignQuestResponse.java delete mode 100644 src/main/java/com/gomo/app/core/quest/presentation/api/response/ListCalendarAssignQuestResponse.java rename src/main/java/com/gomo/app/core/streak/{presentation => adapter/in}/api/AchieverApi.java (53%) rename src/main/java/com/gomo/app/core/streak/{presentation => adapter/in}/api/StreakApi.java (59%) rename src/main/java/com/gomo/app/core/streak/{presentation => adapter/in}/api/response/ListStreakResponse.java (91%) rename src/main/java/com/gomo/app/core/streak/{presentation => adapter/in}/api/response/ReadAchieverResponse.java (87%) rename src/main/java/com/gomo/app/core/streak/{presentation => adapter/in}/api/response/ReadStreakResponse.java (89%) rename src/main/java/com/gomo/app/core/streak/{presentation => adapter/in}/consumer/CompleteQuestEventStreakConsumer.java (64%) rename src/main/java/com/gomo/app/core/streak/application/port/{CreateAchieverPortIn.java => in/AchieverCreator.java} (61%) create mode 100644 src/main/java/com/gomo/app/core/streak/application/port/in/AchieverReader.java rename src/main/java/com/gomo/app/core/streak/application/port/{CreateStreakPortIn.java => in/StreakCreator.java} (85%) create mode 100644 src/main/java/com/gomo/app/core/streak/application/port/in/StreakReader.java create mode 100644 src/main/java/com/gomo/app/core/streak/application/service/AchieverService.java create mode 100644 src/main/java/com/gomo/app/core/streak/application/service/StreakService.java delete mode 100644 src/main/java/com/gomo/app/core/streak/application/usecase/CreateAchieverUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/streak/application/usecase/CreateStreakUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/streak/application/usecase/ReadAchieverUseCase.java delete mode 100644 src/main/java/com/gomo/app/core/streak/application/usecase/ReadStreakUseCase.java rename src/main/java/com/gomo/app/core/streak/{ => domain}/exception/AchieverErrorCode.java (86%) rename src/main/java/com/gomo/app/core/streak/{ => domain}/exception/AchieverNotFoundException.java (87%) delete mode 100644 src/main/java/com/gomo/app/core/streak/domain/service/AchieverService.java delete mode 100644 src/main/java/com/gomo/app/core/streak/domain/service/StreakService.java rename src/main/java/com/gomo/app/core/survey/{presentation => adapter/in/api}/SurveyApi.java (51%) rename src/main/java/com/gomo/app/core/survey/{presentation => adapter/in/api}/request/CreateSurveyResultRequest.java (80%) rename src/main/java/com/gomo/app/core/survey/{presentation => adapter/in/api}/request/SelectedSurveyItemRequest.java (85%) rename src/main/java/com/gomo/app/core/survey/{presentation => adapter/in/api}/response/ListSurveyQuestionResponse.java (77%) rename src/main/java/com/gomo/app/core/survey/{presentation => adapter/in/api}/response/ReadSurveyItemResponse.java (76%) rename src/main/java/com/gomo/app/core/survey/{presentation => adapter/in/api}/response/ReadSurveyQuestionResponse.java (84%) rename src/main/java/com/gomo/app/core/survey/{infrastructure => adapter/out/persistence}/SurveyResultRepositoryImpl.java (94%) rename src/main/java/com/gomo/app/core/survey/application/{ => command}/CreateSurveyResultCommand.java (73%) rename src/main/java/com/gomo/app/core/survey/application/{ => dto}/SurveyItemDto.java (92%) rename src/main/java/com/gomo/app/core/survey/application/{ => dto}/SurveyQuestionDto.java (93%) rename src/main/java/com/gomo/app/core/survey/application/{ReadSurveyQuestionUseCase.java => service/SurveyQuestionService.java} (76%) rename src/main/java/com/gomo/app/core/survey/application/{CreateSurveyResultUseCase.java => service/SurveyResultService.java} (78%) rename src/main/java/com/gomo/app/core/survey/{ => domain}/exception/SurveyResultConstraintViolationException.java (88%) rename src/main/java/com/gomo/app/core/survey/{ => domain}/exception/SurveyResultErrorCode.java (90%) delete mode 100644 src/main/java/com/gomo/app/support/auth/application/port/CreateAuthCodePortIn.java delete mode 100644 src/main/java/com/gomo/app/support/auth/application/port/VerifyAuthCodePortIn.java delete mode 100644 src/main/java/com/gomo/app/support/auth/application/usecase/AuthenticateUseCase.java delete mode 100644 src/main/java/com/gomo/app/support/auth/application/usecase/CreateAuthCodeUseCase.java delete mode 100644 src/main/java/com/gomo/app/support/auth/application/usecase/CreateAuthTokenInternalService.java delete mode 100644 src/main/java/com/gomo/app/support/auth/application/usecase/DeleteRefreshTokenUseCase.java delete mode 100644 src/main/java/com/gomo/app/support/auth/application/usecase/OAuthUseCase.java delete mode 100644 src/main/java/com/gomo/app/support/auth/application/usecase/UpdateRefreshTokenUseCase.java delete mode 100644 src/main/java/com/gomo/app/support/auth/application/usecase/VerifyAuthCodeUseCase.java delete mode 100644 src/main/java/com/gomo/app/support/auth/domain/repository/AuthTokenRepository.java delete mode 100644 src/main/java/com/gomo/app/support/auth/infrastructure/oauth/OAuthProviderFactory.java delete mode 100644 src/main/java/com/gomo/app/support/auth/infrastructure/oauth/provider/OAuthProvider.java delete mode 100644 src/main/java/com/gomo/app/support/auth/presentation/security/AuthInfo.java rename src/main/java/com/gomo/app/support/image/{infrastructure/MinioImageAdapter.java => adapter/out/client/MinioImageClient.java} (94%) rename src/main/java/com/gomo/app/support/image/application/port/{DeleteImagePortIn.java => in/ImageDeleter.java} (63%) rename src/main/java/com/gomo/app/support/image/application/port/{ReadImagePortIn.java => in/ImageReader.java} (68%) rename src/main/java/com/gomo/app/support/image/application/port/{UploadImagePortIn.java => in/ImageUploader.java} (80%) rename src/main/java/com/gomo/app/support/image/application/port/{ManageImagePortOut.java => out/ImageStore.java} (91%) create mode 100644 src/main/java/com/gomo/app/support/image/application/service/ImageService.java delete mode 100644 src/main/java/com/gomo/app/support/image/application/usecase/DeleteImageUseCase.java delete mode 100644 src/main/java/com/gomo/app/support/image/application/usecase/ReadImageUseCase.java delete mode 100644 src/main/java/com/gomo/app/support/image/application/usecase/UploadImageUseCase.java rename src/main/java/com/gomo/app/support/messagebroker/{infrastructure/adapter => adapter/out/client}/RabbitMQClient.java (79%) rename src/main/java/com/gomo/app/support/messagebroker/{infrastructure/adapter => adapter/out/repository}/JdbcProcessedDirectEventRepository.java (93%) delete mode 100644 src/main/java/com/gomo/app/support/messagebroker/application/PublishMessageUseCase.java rename src/main/java/com/gomo/app/support/messagebroker/application/port/{ => in}/IdempotentDirectEventConsumer.java (95%) rename src/main/java/com/gomo/app/support/messagebroker/application/port/{PublishMessagePortIn.java => in/MessagePublisher.java} (86%) rename src/main/java/com/gomo/app/support/messagebroker/application/port/{MessageBrokerClientPortOut.java => out/MessageBrokerManager.java} (84%) rename src/main/java/com/gomo/app/support/messagebroker/{infrastructure/aspect => application/service}/IdempotentDirectEventConsumerAspect.java (96%) create mode 100644 src/main/java/com/gomo/app/support/messagebroker/application/service/MessagePublishService.java rename src/test/java/com/gomo/app/core/{member/documentation/CreatePasswordAuthCodeDocumentationTest.java => auth/adapter/in/api/CreateAuthCodeForPasswordResetDocumentationTest.java} (62%) rename src/test/java/com/gomo/app/core/{member/documentation/CreateEmailAuthCodeDocumentationTest.java => auth/adapter/in/api/CreateAuthCodeForSignupDocumentationTest.java} (63%) rename src/test/java/com/gomo/app/{support/auth/documentation/LoginMemberDocumentationTest.java => core/auth/adapter/in/api/LoginDocumentationTest.java} (78%) rename src/test/java/com/gomo/app/{support/auth/documentation/LogoutMemberDocumentationTest.java => core/auth/adapter/in/api/LogoutDocumentationTest.java} (83%) rename src/test/java/com/gomo/app/{support/auth/documentation => core/auth/adapter/in/api}/RefreshTokenDocumentationTest.java (89%) rename src/test/java/com/gomo/app/core/{member/documentation/CreateMemberDocumentationTest.java => auth/adapter/in/api/SignupDocumentationTest.java} (53%) rename src/test/java/com/gomo/app/core/{member/documentation/VerifyEmailAuthCodeDocumentationTest.java => auth/adapter/in/api/VerifyEmailCodeDocumentationTest.java} (74%) rename src/test/java/com/gomo/app/core/{member/documentation => auth/adapter/in/api}/snippet/CreateEmailAuthCodeSnippet.java (91%) rename src/test/java/com/gomo/app/core/{member/documentation => auth/adapter/in/api}/snippet/CreatePasswordAuthCodeSnippet.java (91%) rename src/test/java/com/gomo/app/{support/auth/documentation => core/auth/adapter/in/api}/snippet/LoginMemberSnippet.java (96%) rename src/test/java/com/gomo/app/{support/auth/documentation => core/auth/adapter/in/api}/snippet/LogoutMemberSnippet.java (95%) rename src/test/java/com/gomo/app/{support/auth/documentation => core/auth/adapter/in/api}/snippet/RefreshTokenSnippet.java (97%) rename src/test/java/com/gomo/app/core/{member/documentation/snippet/CreateMemberSnippet.java => auth/adapter/in/api/snippet/SignupSnippet.java} (93%) rename src/test/java/com/gomo/app/core/{member/documentation => auth/adapter/in/api}/snippet/VerifyEmailAuthCodeSnippet.java (86%) create mode 100644 src/test/java/com/gomo/app/core/auth/adapter/out/client/MemberClientTest.java rename src/test/java/com/gomo/app/{common/security/jwt/application/ManageJwtUseCaseTest.java => core/auth/adapter/out/lib/JwtClientTest.java} (60%) rename src/test/java/com/gomo/app/{support/auth/infrastructure => core/auth/adapter/out}/persistence/RedisAuthCodeRepositoryTest.java (87%) rename src/test/java/com/gomo/app/{support/auth/infrastructure => core/auth/adapter/out}/persistence/RedisAuthTokenRepositoryTest.java (72%) create mode 100644 src/test/java/com/gomo/app/core/auth/application/service/AuthCodeServiceTest.java create mode 100644 src/test/java/com/gomo/app/core/auth/application/service/AuthServiceTest.java create mode 100644 src/test/java/com/gomo/app/core/auth/application/service/AuthTokenServiceTest.java rename src/test/java/com/gomo/app/{support => core}/auth/domain/model/AuthCodeTest.java (97%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/CreateInterestDocumentationTest.java (91%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/CreateInterestRelationDocumentationTest.java (81%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/CreateMajorInterestDocumentationTest.java (84%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/DeleteInterestDocumentationTest.java (82%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/DeleteInterestRelationDocumentationTest.java (81%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/DeleteMajorInterestDocumentationTest.java (82%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/InterestNetworkDocumentationTest.java (81%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/ListInterestDocumentationTest.java (82%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/ListMajorInterestDocumentationTest.java (83%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/OrderUpdateMajorInterestDocumentationTest.java (82%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/ReadInterestDocumentationTest.java (82%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/UpdateInterestDocumentationTest.java (83%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/UpdateInterestLogoDocumentationTest.java (88%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/snippet/CreateInterestRelationSnippet.java (93%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/snippet/CreateInterestSnippet.java (93%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/snippet/CreateMajorInterestSnippet.java (93%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/snippet/DeleteInterestRelationSnippet.java (92%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/snippet/DeleteInterestSnippet.java (92%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/snippet/DeleteMajorInterestSnippet.java (92%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/snippet/InterestNetworkSnippet.java (95%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/snippet/ListInterestSnippet.java (95%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/snippet/ListMajorInterestSnippet.java (94%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/snippet/OrderUpdateMajorInterestSnippet.java (93%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/snippet/ReadInterestSnippet.java (95%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/snippet/UpdateInterestLogoSnippet.java (93%) rename src/test/java/com/gomo/app/core/interest/{presentation/documentation => adapter/in/api}/snippet/UpdateInterestSnippet.java (93%) rename src/test/java/com/gomo/app/core/interest/{presentation => adapter/in}/consumer/CompleteQuestEventScoreConsumerTest.java (83%) create mode 100644 src/test/java/com/gomo/app/core/interest/adapter/out/client/LogoClientTest.java rename src/test/java/com/gomo/app/core/interest/{infrastructure/adapter/ReadRegistrantAdapterTest.java => adapter/out/client/RegistrantClientTest.java} (78%) rename src/test/java/com/gomo/app/core/interest/{infrastructure/repository/LevelThresholdPolicyRepositoryImplTest.java => adapter/out/persistence/JDBCLevelThresholdPolicyRepositoryTest.java} (80%) rename src/test/java/com/gomo/app/core/interest/application/{usecase/CreateInterestUseCaseTest.java => service/InterestCreateServiceTest.java} (74%) rename src/test/java/com/gomo/app/core/interest/application/{usecase/DeleteInterestUseCaseTest.java => service/InterestDeleteServiceTest.java} (70%) create mode 100644 src/test/java/com/gomo/app/core/interest/application/service/InterestNetworkServiceTest.java create mode 100644 src/test/java/com/gomo/app/core/interest/application/service/InterestRelationServiceTest.java rename src/test/java/com/gomo/app/core/interest/application/{usecase/ReadInterestUseCaseTest.java => service/InterestServiceTest.java} (60%) rename src/test/java/com/gomo/app/core/interest/application/{usecase/UpdateLogoUseCaseTest.java => service/LogoServiceTest.java} (54%) create mode 100644 src/test/java/com/gomo/app/core/interest/application/service/MajorInterestServiceTest.java create mode 100644 src/test/java/com/gomo/app/core/interest/application/service/ProficiencyServiceTest.java delete mode 100644 src/test/java/com/gomo/app/core/interest/application/usecase/AdjustProficiencyUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/interest/application/usecase/CreateInterestRelationUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/interest/application/usecase/CreateMajorInterestUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/interest/application/usecase/DeleteInterestRelationUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/interest/application/usecase/DeleteMajorInterestUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/interest/application/usecase/OrderUpdateMajorInterestUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/interest/application/usecase/ReadInterestNetworkUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/interest/application/usecase/ReadMajorInterestUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/interest/application/usecase/UpdateInterestUseCaseTest.java rename src/test/java/com/gomo/app/core/interest/{infrastructure => domain}/repository/InterestRelationRepositoryTest.java (91%) rename src/test/java/com/gomo/app/core/interest/{infrastructure => domain}/repository/MajorInterestRepositoryTest.java (89%) create mode 100644 src/test/java/com/gomo/app/core/interest/domain/service/InterestNetworkBuilderTest.java delete mode 100644 src/test/java/com/gomo/app/core/interest/domain/service/InterestRelationServiceTest.java delete mode 100644 src/test/java/com/gomo/app/core/interest/domain/service/InterestServiceTest.java delete mode 100644 src/test/java/com/gomo/app/core/interest/domain/service/LogoServiceTest.java delete mode 100644 src/test/java/com/gomo/app/core/interest/domain/service/MajorInterestServiceTest.java rename src/test/java/com/gomo/app/core/interest/domain/{model => service}/ProficiencyCalculatorTest.java (66%) delete mode 100644 src/test/java/com/gomo/app/core/interest/domain/service/ProficiencyServiceTest.java rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/CheckHandleDuplicateDocumentationTest.java (90%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/DeleteMemberDocumentationTest.java (92%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/DeleteProfileBannerDocumentationTest.java (89%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/DeleteProfileImageDocumentationTest.java (89%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/ReadMemberDocumentationTest.java (93%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/ReadQuestPropertyDocumentationTest.java (90%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/ResetPasswordDocumentationTest.java (84%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/UpdateHandleDocumentationTest.java (87%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/UpdateMemberDocumentationTest.java (85%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/UpdatePasswordDocumentationTest.java (85%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/UpdateProfileBannerDocumentationTest.java (91%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/UpdateProfileImageDocumentationTest.java (91%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/UpdateQuestPropertyDocumentationTest.java (84%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/UpdateWidgetDocumentationTest.java (85%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/snippet/CheckHandleDuplicateSnippet.java (95%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/snippet/DeleteMemberSnippet.java (95%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/snippet/DeleteProfileBannerSnippet.java (95%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/snippet/DeleteProfileImageSnippet.java (95%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/snippet/ReadMemberSnippet.java (97%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/snippet/ReadQuestPropertySnippet.java (96%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/snippet/ResetPasswordSnippet.java (96%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/snippet/UpdateHandleSnippet.java (96%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/snippet/UpdateMemberSnippet.java (96%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/snippet/UpdatePasswordSnippet.java (96%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/snippet/UpdateProfileBannerSnippet.java (96%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/snippet/UpdateProfileImageSnippet.java (96%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/snippet/UpdateQuestPropertySnippet.java (96%) rename src/test/java/com/gomo/app/core/member/{documentation => adapter/in/api}/snippet/UpdateWidgetSnippet.java (96%) create mode 100644 src/test/java/com/gomo/app/core/member/adapter/out/client/AuthClientTest.java create mode 100644 src/test/java/com/gomo/app/core/member/adapter/out/client/PointBalanceClientTest.java create mode 100644 src/test/java/com/gomo/app/core/member/adapter/out/client/ProfileAssetClientTest.java create mode 100644 src/test/java/com/gomo/app/core/member/adapter/out/client/TemporaryTokenClientTest.java rename src/test/java/com/gomo/app/{common/security/encoder/application/PasswordEncodeUseCaseTest.java => core/member/adapter/out/lib/BcryptEncoderTest.java} (80%) create mode 100644 src/test/java/com/gomo/app/core/member/application/service/EmailServiceTest.java create mode 100644 src/test/java/com/gomo/app/core/member/application/service/HandleServiceTest.java create mode 100644 src/test/java/com/gomo/app/core/member/application/service/MemberCreateServiceTest.java rename src/test/java/com/gomo/app/core/member/application/{usecase/LoginMemberUseCaseTest.java => service/MemberLoginServiceTest.java} (67%) rename src/test/java/com/gomo/app/core/member/application/{usecase/OAuthLoginMemberUseCaseTest.java => service/MemberOAuthLoginServiceTest.java} (82%) create mode 100644 src/test/java/com/gomo/app/core/member/application/service/MemberServiceTest.java create mode 100644 src/test/java/com/gomo/app/core/member/application/service/PasswordServiceTest.java rename src/test/java/com/gomo/app/core/member/application/{usecase/UpdateProfileBannerUseCaseTest.java => service/ProfileBannerServiceTest.java} (50%) rename src/test/java/com/gomo/app/core/member/application/{usecase/UpdateQuestPropertyUseCaseTest.java => service/QuestPropertyServiceTest.java} (58%) rename src/test/java/com/gomo/app/core/member/application/{usecase/UpdateProfileImageUseCaseTest.java => service/TempProfileImageServiceTest.java} (50%) rename src/test/java/com/gomo/app/core/member/application/{usecase/UpdateWidgetUseCaseTest.java => service/WidgetServiceTest.java} (79%) delete mode 100644 src/test/java/com/gomo/app/core/member/application/usecase/CheckHandleUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/member/application/usecase/CreateEmailCodeUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/member/application/usecase/CreateMemberUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/member/application/usecase/DeleteMemberUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/member/application/usecase/DeleteProfileBannerUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/member/application/usecase/DeleteProfileImageUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/member/application/usecase/ReadMemberUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/member/application/usecase/ReadQuestPropertyUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/member/application/usecase/ResetPasswordUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/member/application/usecase/UpdateHandleUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/member/application/usecase/UpdateMemberUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/member/application/usecase/UpdatePasswordUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/member/application/usecase/VerifyEmailCodeUseCaseTest.java rename src/test/java/com/gomo/app/core/member/{infrastructure => domain}/repository/MemberRepositoryTest.java (97%) delete mode 100644 src/test/java/com/gomo/app/core/member/domain/service/MemberServiceTest.java delete mode 100644 src/test/java/com/gomo/app/core/member/domain/service/ProfileImageServiceTest.java rename src/test/java/com/gomo/app/core/point/{presentation/documentation => adapter/in/api}/ListPointDocumentationTest.java (64%) rename src/test/java/com/gomo/app/core/point/{presentation/documentation => adapter/in/api}/ReadBalanceDocumentationTest.java (85%) rename src/test/java/com/gomo/app/core/point/{presentation/documentation => adapter/in/api}/snippet/ListPointSnippet.java (95%) rename src/test/java/com/gomo/app/core/point/{presentation/documentation => adapter/in/api}/snippet/ReadBalanceSnippet.java (92%) rename src/test/java/com/gomo/app/core/point/{presentation => adapter/in}/consumer/CompleteQuestEventPointConsumerTest.java (84%) rename src/test/java/com/gomo/app/core/point/application/{usecase/ReadBalanceUseCaseTest.java => service/BalanceServiceTest.java} (62%) rename src/test/java/com/gomo/app/core/point/application/{usecase/ReadPointUseCaseTest.java => service/PointServiceTest.java} (54%) rename src/test/java/com/gomo/app/core/point/{domain => application}/service/PointWalletServiceTest.java (69%) delete mode 100644 src/test/java/com/gomo/app/core/point/application/usecase/CreatePointUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/point/application/usecase/CreatePointWalletUseCaseTest.java create mode 100644 src/test/java/com/gomo/app/core/point/domain/repository/PointRepositoryTest.java delete mode 100644 src/test/java/com/gomo/app/core/point/domain/service/PointServiceTest.java delete mode 100644 src/test/java/com/gomo/app/core/point/infrastructure/PointRepositoryTest.java rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/CalendarAssignQuestDocumentationTest.java (93%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/CompleteAssignQuestDocumentationTest.java (85%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/ConfirmAssignQuestDocumentationTest.java (89%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/CreateAssignQuestDocumentationTest.java (85%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/CreateRepeatQuestDocumentationTest.java (83%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/DeleteAssignQuestDocumentationTest.java (89%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/DeleteRepeatQuestDocumentationTest.java (84%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/ListAssignQuestDocumentationTest.java (91%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/ListRepeatQuestDocumentationTest.java (86%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/OrderUpdateAssignQuestDocumentationTest.java (88%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/OrderUpdateRepeatQuestDocumentationTest.java (87%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/ReRollAssignQuestDocumentationTest.java (89%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/UpdateAssignQuestDocumentationTest.java (88%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/UpdateRepeatQuestDocumentationTest.java (85%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/snippet/CalendarAssignQuestSnippet.java (95%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/snippet/CompleteAssignQuestSnippet.java (93%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/snippet/ConfirmAssignQuestSnippet.java (92%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/snippet/CreateAssignQuestSnippet.java (94%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/snippet/CreateRepeatQuestSnippet.java (94%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/snippet/DeleteAssignQuestSnippet.java (92%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/snippet/DeleteRepeatQuestSnippet.java (92%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/snippet/ListAssignQuestSnippet.java (96%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/snippet/ListRepeatQuestSnippet.java (95%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/snippet/OrderUpdateAssignQuestSnippet.java (94%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/snippet/OrderUpdateRepeatQuestSnippet.java (94%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/snippet/ReRollAssignQuestSnippet.java (95%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/snippet/UpdateAssignQuestSnippet.java (94%) rename src/test/java/com/gomo/app/core/quest/{presentation/documentation => adapter/in/api}/snippet/UpdateRepeatQuestSnippet.java (94%) rename src/test/java/com/gomo/app/core/quest/{infrastructure/adapter => adapter/out/client}/LlmCreateQuestContentAdapterTest.java (85%) rename src/test/java/com/gomo/app/core/quest/{infrastructure/adapter/ReadParticipantAdapterTest.java => adapter/out/client/ParticipantClientTest.java} (75%) rename src/test/java/com/gomo/app/core/quest/{infrastructure/adapter/ReadSubjectAdapterTest.java => adapter/out/client/SubjectClientTest.java} (73%) rename src/test/java/com/gomo/app/core/quest/{infrastructure/repository => adapter/out/persistence}/AssignQuestRepositoryTest.java (96%) rename src/test/java/com/gomo/app/core/quest/{infrastructure/repository => adapter/out/persistence}/JdbcBulkAssignQuestRepositoryTest.java (98%) rename src/test/java/com/gomo/app/core/quest/{infrastructure/repository => adapter/out/persistence}/RepeatQuestRepositoryTest.java (94%) rename src/test/java/com/gomo/app/core/quest/application/{usecase/CompleteAssignQuestUseCaseTest.java => service/AssignQuestCompleteServiceTest.java} (77%) rename src/test/java/com/gomo/app/core/quest/application/{usecase/CreateAssignQuestUseCaseTest.java => service/AssignQuestCreateServiceTest.java} (52%) rename src/test/java/com/gomo/app/core/quest/application/{usecase/ReRollAssignQuestUseCaseTest.java => service/AssignQuestReRollServiceTest.java} (78%) rename src/test/java/com/gomo/app/core/quest/application/{usecase/AutoCreateAssignQuestUseCaseTest.java => service/AssignQuestRoutineServiceTest.java} (91%) create mode 100644 src/test/java/com/gomo/app/core/quest/application/service/AssignQuestServiceTest.java rename src/test/java/com/gomo/app/core/quest/application/{usecase/CreateQuestPoolUseCaseTest.java => service/QuestPoolCreateServiceTest.java} (89%) create mode 100644 src/test/java/com/gomo/app/core/quest/application/service/RepeatQuestCreateServiceTest.java create mode 100644 src/test/java/com/gomo/app/core/quest/application/service/RepeatQuestServiceTest.java delete mode 100644 src/test/java/com/gomo/app/core/quest/application/usecase/CalendarAssignQuestUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/quest/application/usecase/ConfirmAssignQuestUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/quest/application/usecase/CreateRepeatQuestUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/quest/application/usecase/DeleteAssignQuestUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/quest/application/usecase/DeleteRepeatQuestUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/quest/application/usecase/OrderUpdateAssignQuestUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/quest/application/usecase/OrderUpdateRepeatQuestUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/quest/application/usecase/ReadAssignQuestUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/quest/application/usecase/ReadRepeatQuestUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/quest/application/usecase/UpdateAssignQuestUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/quest/application/usecase/UpdateRepeatQuestUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/quest/domain/service/AssignQuestServiceTest.java rename src/test/java/com/gomo/app/core/quest/domain/service/{QuestRewardServiceTest.java => QuestRewardProviderTest.java} (87%) delete mode 100644 src/test/java/com/gomo/app/core/quest/domain/service/RepeatQuestServiceTest.java rename src/test/java/com/gomo/app/core/streak/{presentation/documentation => adapter/in/api}/ListStreakDocumentationTest.java (91%) rename src/test/java/com/gomo/app/core/streak/{presentation/documentation => adapter/in/api}/ReadAchieverDocumentationTest.java (89%) rename src/test/java/com/gomo/app/core/streak/{presentation/documentation => adapter/in/api}/snippet/ListStreakSnippet.java (95%) rename src/test/java/com/gomo/app/core/streak/{presentation/documentation => adapter/in/api}/snippet/ReadAchieverSnippet.java (93%) rename src/test/java/com/gomo/app/core/streak/{presentation => adapter/in}/consumer/CompleteQuestEventStreakConsumerTest.java (84%) create mode 100644 src/test/java/com/gomo/app/core/streak/application/service/AchieverServiceTest.java create mode 100644 src/test/java/com/gomo/app/core/streak/application/service/StreakServiceTest.java delete mode 100644 src/test/java/com/gomo/app/core/streak/application/usecase/CreateAchieverUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/streak/application/usecase/CreateStreakUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/streak/application/usecase/ReadAchieverUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/streak/application/usecase/ReadStreakUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/core/streak/domain/service/AchieverServiceTest.java delete mode 100644 src/test/java/com/gomo/app/core/streak/domain/service/StreakServiceTest.java rename src/test/java/com/gomo/app/core/survey/{documentation => adapter/in/api}/CreateSurveyAnswerDocumentationTest.java (87%) rename src/test/java/com/gomo/app/core/survey/{documentation => adapter/in/api}/ListSurveyDocumentationTest.java (92%) rename src/test/java/com/gomo/app/core/survey/{documentation => adapter/in/api}/snippet/CreateSurveyAnswerSnippet.java (95%) rename src/test/java/com/gomo/app/core/survey/{documentation => adapter/in/api}/snippet/ListSurveySnippet.java (95%) rename src/test/java/com/gomo/app/core/survey/{integration => adapter/out/persistence}/SurveyResultRepositoryTest.java (94%) rename src/test/java/com/gomo/app/core/survey/{unit/usecase => application/service}/ReadSurveyResultUseCaseTest.java (83%) rename src/test/java/com/gomo/app/core/survey/{unit/usecase/CreateSurveyResultUseCaseTest.java => application/service/SurveyResultServiceTest.java} (75%) rename src/test/java/com/gomo/app/core/survey/{unit => }/domain/SurveyResultTest.java (92%) delete mode 100644 src/test/java/com/gomo/app/support/auth/application/usecase/AuthenticateUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/support/auth/application/usecase/CreateAuthCodeUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/support/auth/application/usecase/CreateAuthTokenInternalServiceTest.java delete mode 100644 src/test/java/com/gomo/app/support/auth/application/usecase/UpdateRefreshTokenUseCaseTest.java rename src/test/java/com/gomo/app/support/image/{infrastructure/MinioImageAdapterTest.java => adapter/out/client/MinioImageClientTest.java} (81%) rename src/test/java/com/gomo/app/support/image/application/{usecase/UploadImageUseCaseTest.java => service/ImageServiceTest.java} (56%) delete mode 100644 src/test/java/com/gomo/app/support/image/application/usecase/DeleteImageUseCaseTest.java delete mode 100644 src/test/java/com/gomo/app/support/image/application/usecase/ReadImageUseCaseTest.java rename src/test/java/com/gomo/app/support/messagebroker/{infrastructure/adapter => adapter/out/client}/RabbitMQClientTest.java (95%) rename src/test/java/com/gomo/app/support/messagebroker/{infrastructure/adapter => adapter/out/repository}/JdbcProcessedDirectEventRepositoryTest.java (94%) rename src/test/java/com/gomo/app/support/messagebroker/{infrastructure/aspect => application/service}/IdempotentDirectEventConsumerAspectTest.java (96%) rename src/test/java/com/gomo/app/support/messagebroker/application/{PublishMessageUseCaseTest.java => service/MessagePublishServiceTest.java} (60%) diff --git a/README.md b/README.md index 3b7253d4..aa8202fd 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,12 @@ dependencies { #4-3.  단, 메서드 파라미터가 많아 Hard wrap 160을 넘긴다면 **한 라인에 하나**만 작성한다.
#5.  루트 엔티티에서 값 객체 내부 필드에 바로 접근하는 메서드는 `get`으로 시작하지 않는다.
-#5-1.   ex) `member.getId().getId()` == `member.id()` +#5-1.   ex) `member.getId().getId()` == `member.id()`
+ +#6.  check vs validate vs verify
+#6-1.   check: 로직 흐름에서 조건 분기를 확인. 가능성을 검토하며 true / false 반환 +#6-2.   validate: 규칙을 준수하는지 확인. 유효성을 검증하며 규칙 위반 시 예외 발생 +#6-3.   verify: 진위 여부 확인. 데이터 진위를 판별하며, 검증 실패 시 예외 발생

@@ -92,7 +97,7 @@ dependencies { | 이름 | Member name | 사용자의 이름 | | 한 줄 다짐 | Motto | 사용자가 지정한 좌우명 혹은 다짐 | | 프로필 이미지 | Profile image | 사용자의 프로필 이미지 | -| 퀘스트 설정 | Quest property | 사용자가 관리하는 퀘스트 설정 값 | +| 퀘스트 설정 | Quest property | 사용자가 관리하는 퀘스트 설정 값 | | 일일 퀘스트 제한 | DailyThreshold | 사용자가 생성할 수 있는 일일 퀘스트 임계치 | | 주간 퀘스트 제한 | WeeklyThreshold | 사용자가 생성할 수 있는 주간 퀘스트 임계치 | | 월간 퀘스트 제한 | MonthlyThreshold | 사용자가 생성할 수 있는 월간 퀘스트 임계치 | @@ -102,23 +107,23 @@ dependencies { ### 관심사 -| 한글명 | 영문명 | 설명 | -|------------|-------------------|-------------------------------| -| 관심사 | Interest | 사용자가 등록한 관심 분야 | -| 등록자 | Registrant | 관심사를 등록한 사용자 | -| 이름 | Interest name | 관심사의 이름 | -| 로고 | Logo | 관심사의 로고 이미지 | -| 숙련도 | Proficiency | 관심사에 대한 역량 | -| 레벨 | Level | 숙련도의 등급 | -| 점수 | Score | 현재 보유중인 점수 | -| 총 점수 | Total score | 이제까지 획득한 모든 점수의 합계 | -| 점수 임계치 | Score threshold | 다음 레벨을 위한 임계 점수 | -| 주요 관심사 | Major interest | 등록한 관심사 중, 사용자가 특별하게 생각하는 관심사 | -| 관심사 그래프 | Interest network | 여러 가지 관심사가 계층 구조를 이룬 자료 구조 | -| 관심사 연결선 | Interest relation | 관심사 그래프에서 두 관심사의 간선 | -| 상위 관심사 | Parent interest | 관심사 그래프에서 상위 계층에 속하는 관심사 | -| 하위 관심사 | Child interest | 관심사 그래프에서 하위 계층에 속하는 관심사 | -| 관심사 할당량 | Interest quota | 사용자 구독 플랜에 따른 관심사 생성 가능 개수 | +| 한글명 | 영문명 | 설명 | +|---------|-------------------|-------------------------------| +| 관심사 | Interest | 사용자가 등록한 관심 분야 | +| 등록자 | Registrant | 관심사를 등록한 사용자 | +| 이름 | Interest name | 관심사의 이름 | +| 로고 | Logo | 관심사의 로고 이미지 | +| 숙련도 | Proficiency | 관심사에 대한 역량 | +| 레벨 | Level | 숙련도의 등급 | +| 점수 | Score | 현재 보유중인 점수 | +| 총 점수 | Total score | 이제까지 획득한 모든 점수의 합계 | +| 점수 임계치 | Score threshold | 다음 레벨을 위한 임계 점수 | +| 주요 관심사 | Major interest | 등록한 관심사 중, 사용자가 특별하게 생각하는 관심사 | +| 관심사 그래프 | Interest network | 여러 가지 관심사가 계층 구조를 이룬 자료 구조 | +| 관심사 연결선 | Interest relation | 관심사 그래프에서 두 관심사의 간선 | +| 상위 관심사 | Parent interest | 관심사 그래프에서 상위 계층에 속하는 관심사 | +| 하위 관심사 | Child interest | 관심사 그래프에서 하위 계층에 속하는 관심사 | +| 관심사 할당량 | Interest quota | 사용자 구독 플랜에 따른 관심사 생성 가능 개수 |
@@ -145,11 +150,11 @@ dependencies { ### 스트릭 -| 한글명 | 영문명 | 설명 | -|-----------|---------------------|-------------------------------| -| 스트릭 | Streak | 기간 별 퀘스트를 완료한 개수 만큼 쌓이는 점수 | -| 성취자 | Achiever | 퀘스트를 등록하고 수행하는 사용자 | -| 스트릭 타입 | Streak type | 일간, 주간, 월간 등의 스트릭 유형 | +| 한글명 | 영문명 | 설명 | +|--------|-------------|----------------------------| +| 스트릭 | Streak | 기간 별 퀘스트를 완료한 개수 만큼 쌓이는 점수 | +| 성취자 | Achiever | 퀘스트를 등록하고 수행하는 사용자 | +| 스트릭 타입 | Streak type | 일간, 주간, 월간 등의 스트릭 유형 |
@@ -158,17 +163,17 @@ dependencies { | 한글명 | 영문명 | 설명 | |--------|-------------|----------------------| | 포인트 | Point | 서비스 내의 재화 | -| 거래자 | Transactor | 포인트를 획득하고 사용하는 사용자 | +| 거래자 | Transactor | 포인트를 획득하고 사용하는 사용자 | | 스트릭 타입 | Streak type | 일간, 주간, 월간 등의 스트릭 유형 |
### 설문 -| 한글명 | 영문명 | 설명 | -|--------|----------------|-----------------| -| 설문 | Survey | 사용자 정보를 수집하는 설문 | +| 한글명 | 영문명 | 설명 | +|--------|-----------------|-----------------| +| 설문 | Survey | 사용자 정보를 수집하는 설문 | | 설문 응답자 | Respondent | 설문을 작성한 사용자 | | 설문 문항 | Survey question | 설문에 포함되는 질문 | | 항목 | Survey item | 문항에 포함되는 항목 | -| 답변 | Survey result | 사용자가 수행한 설문 기록 | \ No newline at end of file +| 답변 | Survey result | 사용자가 수행한 설문 기록 | diff --git a/src/docs/asciidoc/apis/auth-api.adoc b/src/docs/asciidoc/apis/auth-api.adoc index fc5e482f..ba4fe7aa 100644 --- a/src/docs/asciidoc/apis/auth-api.adoc +++ b/src/docs/asciidoc/apis/auth-api.adoc @@ -1,3 +1,23 @@ +=== 회원 가입 + +`POST /auth/signup` + +새로운 회원을 생성합니다. + +==== 요청 헤더 + +operation::auth-signup[snippets='request-headers'] + +==== 요청 본문 (JSON) + +operation::auth-signup[snippets='http-request,request-fields'] + +==== 성공 응답 + +operation::auth-signup[snippets='http-response,response-fields'] + +''' + === 로그인 `POST /auth/login` @@ -16,10 +36,6 @@ operation::auth-login[snippets='http-request,request-fields'] operation::auth-login[snippets='http-response,response-fields'] -// ==== 에러 응답 -// -// operation::auth-login-error[snippets='http-response,response-fields'] - ''' === 로그아웃 @@ -36,10 +52,6 @@ operation::auth-logout[snippets='request-headers'] 성공 시 `204 No Content` 상태 코드와 함께 빈 응답 본문을 반환합니다. -// ==== 에러 응답 -// -// operation::member-logout-error[snippets='http-response,response-fields'] - ''' === Refresh Token 재발급 @@ -60,8 +72,70 @@ operation::auth-update-refresh-token[snippets='request-cookies'] operation::auth-update-refresh-token[snippets='http-response,response-fields'] -// ==== 에러 응답 -// -// operation::auth-update-refresh-token-error[snippets='http-response,response-fields'] +''' + +=== 이메일 인증 코드 발송 (회원 가입) + +`POST /auth/codes/emails/signup` + +회원가입에 사용할 이메일 인증 코드를 요청한 이메일 주소로 발송합니다. + +==== 요청 헤더 + +operation::auth-code-for-sign-up-create[snippets='request-headers'] + +==== 요청 본문 (JSON) + +operation::auth-code-for-sign-up-create[snippets='http-request,request-fields'] + +==== 성공 응답 + +성공 시 `201 Created` 상태 코드와 함께 빈 응답 본문을 반환합니다. + +==== 에러 응답 (이미 가입된 이메일) + +operation::auth-code-for-sign-up-create-error[snippets='http-response,response-fields'] + +''' + +=== 이메일 인증 코드 발송 (비밀번호 변경 시) + +`POST /auth/codes/emails/passwords/reset` + +비밀번호 찾기에 사용할 이메일 인증 코드를 요청한 이메일 주소로 발송합니다. + +==== 요청 헤더 + +operation::auth-code-for-password-reset-create[snippets='request-headers'] + +==== 요청 본문 (JSON) + +operation::auth-code-for-password-reset-create[snippets='http-request,request-fields'] + +==== 성공 응답 + +성공 시 `201 Created` 상태 코드와 함께 빈 응답 본문을 반환합니다. + +==== 에러 응답 (이미 가입된 이메일) + +operation::auth-code-for-password-reset-create-error[snippets='http-response,response-fields'] ''' + +=== 이메일 인증 코드 검증 + +`GET /auth/codes/emails/verify` + +이메일로 발송된 인증 코드가 올바른지 검증합니다. + +==== 쿼리 파라미터 + +operation::auth-code-verify[snippets='query-parameters'] + +==== 성공 응답 + +인증 성공 시, `200 OK` 상태 코드와 함께 빈 응답 본문을 반환합니다. + +==== 에러 응답 (잘못된 인증 코드) + +operation::auth-code-verify-error[snippets='http-response,response-fields'] diff --git a/src/docs/asciidoc/apis/member-api.adoc b/src/docs/asciidoc/apis/member-api.adoc index 6fe67a39..0fb6cb74 100644 --- a/src/docs/asciidoc/apis/member-api.adoc +++ b/src/docs/asciidoc/apis/member-api.adoc @@ -20,30 +20,6 @@ operation::member-handle-check-duplicate-error[snippets='http-response,response- ''' -=== 회원 가입 - -`POST /members` - -새로운 회원을 생성합니다. - -==== 요청 헤더 - -operation::member-create[snippets='request-headers'] - -==== 요청 본문 (JSON) - -operation::member-create[snippets='http-request,request-fields'] - -==== 성공 응답 - -operation::member-create[snippets='http-response,response-fields'] - -// ==== 에러 응답 -// -// operation::member-create-error[snippets='http-response,response-fields'] - -''' - === 회원 탈퇴 `DELETE /members` @@ -83,10 +59,6 @@ operation::member-profile-banner-update[snippets='request-parts'] 성공 시 `204 No Content` 상태 코드와 함께 빈 응답 본문을 반환합니다. -// ==== 에러 응답 -// -// operation::member-profile-banner-update-error[snippets='http-response,response-fields'] - ''' === 프로필 이미지 수정 @@ -107,10 +79,6 @@ operation::member-profile-image-update[snippets='request-parts'] 성공 시 `204 No Content` 상태 코드와 함께 빈 응답 본문을 반환합니다. -// ==== 에러 응답 -// -// operation::member-profile-image-update-error[snippets='http-response,response-fields'] - ''' === 프로필 배너 이미지 삭제 @@ -127,10 +95,6 @@ operation::member-profile-banner-delete[snippets='request-headers'] 성공 시 `200 OK` 상태 코드와 함께 빈 응답 본문을 반환합니다. -// ==== 에러 응답 -// -// operation::member-profile-banner-delete-error[snippets='http-response,response-fields'] - ''' === 프로필 이미지 삭제 @@ -183,9 +147,9 @@ operation::member-quest-property-read[snippets='request-headers'] operation::member-quest-property-read[snippets='http-response,response-fields'] -// ==== 에러 응답 -// -// operation::member-quest-property-read-error[snippets='http-response,response-fields'] +==== 에러 응답 + +operation::member-quest-property-read-error[snippets='http-response,response-fields'] ''' @@ -207,9 +171,9 @@ operation::member-password-reset[snippets='http-request,request-fields'] 성공 시 `204 No Content` 상태 코드와 함께 빈 응답 본문을 반환합니다. -// ==== 에러 응답 -// -// operation::member-password-reset-error[snippets='http-response,response-fields'] +==== 에러 응답 + +operation::member-password-reset-error[snippets='http-response,response-fields'] ''' @@ -255,10 +219,6 @@ operation::member-info-update[snippets='http-request,request-fields'] 성공 시 `204 No Content` 상태 코드와 함께 빈 응답 본문을 반환합니다. -// ==== 에러 응답 -// -// operation::member-info-update-error[snippets='http-response,response-fields'] - ''' === 비밀번호 변경 @@ -279,10 +239,6 @@ operation::member-password-update[snippets='http-request,request-fields'] 성공 시 `204 No Content` 상태 코드와 함께 빈 응답 본문을 반환합니다. -// ==== 에러 응답 -// -// operation::member-password-update-error[snippets='http-response,response-fields'] - ''' === 퀘스트 설정값 수정 @@ -303,10 +259,6 @@ operation::member-quest-property-update[snippets='http-request,request-fields'] 성공 시 `204 No Content` 상태 코드와 함께 빈 응답 본문을 반환합니다. -// ==== 에러 응답 -// -// operation::member-quest-property-update-error[snippets='http-response,response-fields'] - === 위젯 스냅샷 수정 `PUT /members/widgets` @@ -324,73 +276,3 @@ operation::member-widget-update[snippets='http-request,request-fields'] ==== 성공 응답 성공 시 `204 No Content` 상태 코드와 함께 빈 응답 본문을 반환합니다. - -// ==== 에러 응답 -// -// operation::member-quest-property-update-error[snippets='http-response,response-fields'] - -=== 이메일 인증 코드 발송 (회원 가입) - -`POST /members/emails/codes/signup` - -회원가입에 사용할 이메일 인증 코드를 요청한 이메일 주소로 발송합니다. - -==== 요청 헤더 - -operation::member-email-auth-code-create[snippets='request-headers'] - -==== 요청 본문 (JSON) - -operation::member-email-auth-code-create[snippets='http-request,request-fields'] - -==== 성공 응답 - -성공 시 `201 Created` 상태 코드와 함께 빈 응답 본문을 반환합니다. - -==== 에러 응답 (이미 가입된 이메일) - -operation::member-email-auth-code-create-error[snippets='http-response,response-fields'] - -''' - -=== 이메일 인증 코드 발송 (비밀번호 변경 시) - -`POST /members/emails/codes/passwords/reset` - -비밀번호 찾기에 사용할 이메일 인증 코드를 요청한 이메일 주소로 발송합니다. - -==== 요청 헤더 - -operation::member-password-auth-code-create[snippets='request-headers'] - -==== 요청 본문 (JSON) - -operation::member-password-auth-code-create[snippets='http-request,request-fields'] - -==== 성공 응답 - -성공 시 `201 Created` 상태 코드와 함께 빈 응답 본문을 반환합니다. - -==== 에러 응답 (이미 가입된 이메일) - -operation::member-password-auth-code-create-error[snippets='http-response,response-fields'] - -''' - -=== 이메일 인증 코드 검증 - -`GET /members/emails/codes/verify` - -이메일로 발송된 인증 코드가 올바른지 검증합니다. - -==== 쿼리 파라미터 - -operation::member-email-auth-code-verify[snippets='query-parameters'] - -==== 성공 응답 - -operation::member-email-auth-code-verify[snippets='http-response,response-fields'] - -==== 에러 응답 (잘못된 인증 코드) - -operation::member-email-auth-code-verify-error[snippets='http-response,response-fields'] diff --git a/src/docs/asciidoc/index.adoc b/src/docs/asciidoc/index.adoc index b5486973..0c6e1d1f 100644 --- a/src/docs/asciidoc/index.adoc +++ b/src/docs/asciidoc/index.adoc @@ -5,10 +5,24 @@ :toclevels: 2 :seclinks: +[[auth-api]] +== 인증 (Auth) API + +include::apis/auth-api.adoc[] + +==== 에러 코드 + +`AUT-ROO-001`: Auth code is incorrect + +`AUT-ROO-002`: Refresh token not found + +`AUT-ROO-003`: Refresh token is incorrect + +`AUT-ROO-004`: OAuth member cannot login with password + +`AUT-ROO-005`: Principal already exists + +`AUT-ROO-006`: Principal not found + +`AUT-ROO-007`: Verified email token is incorrect + + [[member-api]] == 회원 (Member) API -include::apis/auth-api.adoc[] include::apis/member-api.adoc[] ==== 에러 코드 @@ -53,11 +67,6 @@ include::apis/member-api.adoc[] `MEM-QUE-002`: Threshold must meet the maximum value + `MEM-QUE-003`: Unexpected quest type + -`AUT-ROO-001`: Auth code is incorrect + -`AUT-ROO-002`: Refresh token not found + -`AUT-ROO-003`: Refresh token is incorrect + -`AUT-ROO-004`: OAuth member cannot login with password + - [[interest-api]] == 관심사 (Interest) API diff --git a/src/main/java/com/gomo/app/batch/ImageCleanupScheduler.java b/src/main/java/com/gomo/app/batch/ImageCleanupScheduler.java index 871a282b..489f4f08 100644 --- a/src/main/java/com/gomo/app/batch/ImageCleanupScheduler.java +++ b/src/main/java/com/gomo/app/batch/ImageCleanupScheduler.java @@ -1,37 +1,14 @@ package com.gomo.app.batch; -import java.util.Set; - -import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; -import com.gomo.app.core.interest.domain.service.LogoService; -import com.gomo.app.core.member.domain.service.ProfileImageService; -import com.gomo.app.support.image.application.port.DeleteImagePortIn; -import com.gomo.app.support.image.application.port.ReadImagePortIn; - import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @Component public class ImageCleanupScheduler { - private final ReadImagePortIn readImagePortIn; - private final DeleteImagePortIn deleteImagePortIn; - private final LogoService logoService; - private final ProfileImageService profileImageService; - @Scheduled(cron = "0 0 2 ? * SUN") public void cleanUnusedImages() { - Set allImages = readImagePortIn.readAllImages(); - - Set profileImages = profileImageService.getAllProfileImageUrl(); - allImages.removeAll(profileImages); - - Set logoImages = logoService.findAllUrls(); - allImages.removeAll(logoImages); - - for (String unusedImage : allImages) { - deleteImagePortIn.delete(unusedImage); - } + // TODO [2025-10-30] jhl221123 : batch 프로그램을 구현해야합니다. } } diff --git a/src/main/java/com/gomo/app/batch/MemberCleanupScheduler.java b/src/main/java/com/gomo/app/batch/MemberCleanupScheduler.java index 212d6c3d..df267ac4 100644 --- a/src/main/java/com/gomo/app/batch/MemberCleanupScheduler.java +++ b/src/main/java/com/gomo/app/batch/MemberCleanupScheduler.java @@ -20,7 +20,7 @@ import com.gomo.app.core.quest.domain.repository.RepeatQuestRepository; import com.gomo.app.core.streak.domain.repository.AchieverRepository; import com.gomo.app.core.streak.domain.repository.StreakRepository; -import com.gomo.app.support.image.application.port.DeleteImagePortIn; +import com.gomo.app.support.image.application.port.in.ImageDeleter; import lombok.RequiredArgsConstructor; @@ -28,7 +28,7 @@ @RequiredArgsConstructor public class MemberCleanupScheduler { - private final DeleteImagePortIn deleteImagePortIn; + private final ImageDeleter imageDeleter; private final PointRepository pointRepository; private final PointWalletRepository pointWalletRepository; private final AssignQuestRepository assignQuestRepository; @@ -81,8 +81,8 @@ private void deleteMemberAndRelatedData(Member member) { achieverRepository.deleteByAchieverId(member.getId()); // 이미지 파일 삭제 - deleteImagePortIn.delete(member.profileImageUrl()); - deleteImagePortIn.delete(member.profileBannerUrl()); + imageDeleter.delete(member.profileImageUrl()); + imageDeleter.delete(member.profileBannerUrl()); // member 최종 삭제 memberRepository.deleteById(member.getId()); diff --git a/src/main/java/com/gomo/app/batch/quest/CreateAssignQuestConfig.java b/src/main/java/com/gomo/app/batch/quest/CreateAssignQuestConfig.java index 307304ec..1baec681 100644 --- a/src/main/java/com/gomo/app/batch/quest/CreateAssignQuestConfig.java +++ b/src/main/java/com/gomo/app/batch/quest/CreateAssignQuestConfig.java @@ -25,8 +25,8 @@ import com.gomo.app.core.member.domain.model.ActivateStatus; import com.gomo.app.core.member.domain.model.Member; import com.gomo.app.core.member.domain.repository.MemberRepository; -import com.gomo.app.core.quest.application.port.AutoCreateAssignQuestPortIn; import com.gomo.app.core.quest.application.port.dto.ParticipantDto; +import com.gomo.app.core.quest.application.port.in.AssignQuestRoutineCreator; @Configuration public class CreateAssignQuestConfig { @@ -36,14 +36,14 @@ public class CreateAssignQuestConfig { private final JobRepository jobRepository; private final PlatformTransactionManager transactionManager; private final MemberRepository memberRepository; - private final AutoCreateAssignQuestPortIn autoCreateAssignQuestPortIn; + private final AssignQuestRoutineCreator assignQuestRoutineCreator; public CreateAssignQuestConfig(JobRepository jobRepository, @Qualifier("metaTransactionManager") PlatformTransactionManager metaTransactionManager, - MemberRepository memberRepository, AutoCreateAssignQuestPortIn autoCreateAssignQuestPortIn) { + MemberRepository memberRepository, AssignQuestRoutineCreator assignQuestRoutineCreator) { this.jobRepository = jobRepository; this.transactionManager = metaTransactionManager; this.memberRepository = memberRepository; - this.autoCreateAssignQuestPortIn = autoCreateAssignQuestPortIn; + this.assignQuestRoutineCreator = assignQuestRoutineCreator; } @Bean @@ -91,7 +91,7 @@ public ItemProcessor createAssignQuestProcessor() { public ItemWriter createAssignQuestWriter(@Value("#{jobParameters['questType']}") String questType) { return chunk -> { List participantDtos = new ArrayList<>(chunk.getItems()); - autoCreateAssignQuestPortIn.execute(participantDtos, questType); + assignQuestRoutineCreator.execute(participantDtos, questType); }; } diff --git a/src/main/java/com/gomo/app/batch/quest/FillQuestPoolConfig.java b/src/main/java/com/gomo/app/batch/quest/FillQuestPoolConfig.java index 5e1c3579..28acab76 100644 --- a/src/main/java/com/gomo/app/batch/quest/FillQuestPoolConfig.java +++ b/src/main/java/com/gomo/app/batch/quest/FillQuestPoolConfig.java @@ -25,8 +25,8 @@ import com.gomo.app.core.member.domain.model.ActivateStatus; import com.gomo.app.core.member.domain.model.Member; import com.gomo.app.core.member.domain.repository.MemberRepository; -import com.gomo.app.core.quest.application.port.PublishCreateQuestPoolPortIn; import com.gomo.app.core.quest.application.port.command.PublishCreateQuestPoolCommand; +import com.gomo.app.core.quest.application.port.in.QuestPoolEventPublisher; import com.gomo.app.core.quest.domain.model.participant.Participant; import com.gomo.app.core.quest.domain.model.participant.QuestQuota; @@ -38,14 +38,14 @@ public class FillQuestPoolConfig { private final JobRepository jobRepository; private final PlatformTransactionManager transactionManager; private final MemberRepository memberRepository; - private final PublishCreateQuestPoolPortIn publishCreateQuestPoolPortIn; + private final QuestPoolEventPublisher questPoolEventPublisher; public FillQuestPoolConfig(JobRepository jobRepository, @Qualifier("metaTransactionManager") PlatformTransactionManager metaTransactionManager, - MemberRepository memberRepository, PublishCreateQuestPoolPortIn publishCreateQuestPoolPortIn) { + MemberRepository memberRepository, QuestPoolEventPublisher questPoolEventPublisher) { this.jobRepository = jobRepository; this.transactionManager = metaTransactionManager; this.memberRepository = memberRepository; - this.publishCreateQuestPoolPortIn = publishCreateQuestPoolPortIn; + this.questPoolEventPublisher = questPoolEventPublisher; } @Bean @@ -85,7 +85,7 @@ public ItemWriter fillQuestPoolEventWriter( ) { return chunk -> { PublishCreateQuestPoolCommand command = PublishCreateQuestPoolCommand.of(createParticipants(chunk), questType, limitPerMember); - publishCreateQuestPoolPortIn.publish(command); + questPoolEventPublisher.publish(command); }; } diff --git a/src/main/java/com/gomo/app/support/logging/AuditLog.java b/src/main/java/com/gomo/app/common/logging/AuditLog.java similarity index 88% rename from src/main/java/com/gomo/app/support/logging/AuditLog.java rename to src/main/java/com/gomo/app/common/logging/AuditLog.java index 32f78b46..58249642 100644 --- a/src/main/java/com/gomo/app/support/logging/AuditLog.java +++ b/src/main/java/com/gomo/app/common/logging/AuditLog.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.logging; +package com.gomo.app.common.logging; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/com/gomo/app/common/security/encoder/application/PasswordEncodeUseCase.java b/src/main/java/com/gomo/app/common/security/encoder/application/PasswordEncodeUseCase.java deleted file mode 100644 index 762f2405..00000000 --- a/src/main/java/com/gomo/app/common/security/encoder/application/PasswordEncodeUseCase.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.gomo.app.common.security.encoder.application; - -import org.springframework.security.crypto.password.PasswordEncoder; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.common.security.encoder.application.port.EncodePasswordPortIn; -import com.gomo.app.common.security.encoder.application.port.VerifyPasswordPortIn; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -class PasswordEncodeUseCase implements EncodePasswordPortIn, VerifyPasswordPortIn { - - private final PasswordEncoder passwordEncoder; - - @Override - public String encode(String rawPassword) { - return passwordEncoder.encode(rawPassword); - } - - @Override - public boolean matches(String rawPassword, String encodedPassword) { - return passwordEncoder.matches(rawPassword, encodedPassword); - } -} diff --git a/src/main/java/com/gomo/app/common/security/encoder/application/port/EncodePasswordPortIn.java b/src/main/java/com/gomo/app/common/security/encoder/application/port/EncodePasswordPortIn.java deleted file mode 100644 index 0a2363d9..00000000 --- a/src/main/java/com/gomo/app/common/security/encoder/application/port/EncodePasswordPortIn.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.gomo.app.common.security.encoder.application.port; - -public interface EncodePasswordPortIn { - - /** - * Encodes a given plain-text password. - * - * @param rawPassword The plain-text password to be encoded. - * @return The resulting encoded (hashed and salted) password as a string. - */ - String encode(String rawPassword); -} diff --git a/src/main/java/com/gomo/app/common/security/encoder/application/port/VerifyPasswordPortIn.java b/src/main/java/com/gomo/app/common/security/encoder/application/port/VerifyPasswordPortIn.java deleted file mode 100644 index f624e8f7..00000000 --- a/src/main/java/com/gomo/app/common/security/encoder/application/port/VerifyPasswordPortIn.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.gomo.app.common.security.encoder.application.port; - -public interface VerifyPasswordPortIn { - - /** - * Verifies if a raw password matches a stored, encoded password. - * - * @param rawPassword The plain-text password submitted for verification. - * @param encodedPassword The stored, encoded password from the database to compare against. - * @return {@code true} if the raw password matches the encoded password, {@code false} otherwise. - */ - boolean matches(String rawPassword, String encodedPassword); -} diff --git a/src/main/java/com/gomo/app/common/security/jwt/application/port/GenerateJwtPortIn.java b/src/main/java/com/gomo/app/common/security/jwt/application/port/GenerateJwtPortIn.java deleted file mode 100644 index ef8f1ca0..00000000 --- a/src/main/java/com/gomo/app/common/security/jwt/application/port/GenerateJwtPortIn.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.gomo.app.common.security.jwt.application.port; - -import java.util.UUID; - -public interface GenerateJwtPortIn { - - String generateAccessToken(UUID subject); - - String generateRefreshToken(UUID subject); - - /** - * Generates a temporary token. - * - * @param subject token subject - * @param expiration time in seconds - * @return temporary token - */ - String generateTemporaryToken(String subject, long expiration); -} diff --git a/src/main/java/com/gomo/app/common/security/jwt/application/port/VerifyJwtPortIn.java b/src/main/java/com/gomo/app/common/security/jwt/application/port/VerifyJwtPortIn.java deleted file mode 100644 index 606099c4..00000000 --- a/src/main/java/com/gomo/app/common/security/jwt/application/port/VerifyJwtPortIn.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.gomo.app.common.security.jwt.application.port; - -public interface VerifyJwtPortIn { - - boolean validateToken(String token); - - String extractSubject(String token); - - long extractExpirationTime(String token); -} diff --git a/src/main/java/com/gomo/app/common/web/PageRequest.java b/src/main/java/com/gomo/app/common/web/PageRequest.java index 69ec1eb6..c46a2f91 100644 --- a/src/main/java/com/gomo/app/common/web/PageRequest.java +++ b/src/main/java/com/gomo/app/common/web/PageRequest.java @@ -1,6 +1,6 @@ package com.gomo.app.common.web; -import java.util.UUID; +import java.time.LocalDateTime; import lombok.Getter; @@ -8,14 +8,16 @@ public class PageRequest { private int size; - private UUID lastElementId; + private String lastElementId; + private LocalDateTime lastElementTime; - private PageRequest(int size, UUID lastElementId) { + private PageRequest(int size, String lastElementId, LocalDateTime lastElementTime) { this.size = size; this.lastElementId = lastElementId; + this.lastElementTime = lastElementTime; } - public static PageRequest of(int size, UUID lastElementId) { - return new PageRequest(size, lastElementId); + public static PageRequest of(int size, String lastElementId, LocalDateTime lastElementTime) { + return new PageRequest(size, lastElementId, lastElementTime); } } diff --git a/src/main/java/com/gomo/app/config/FilterRegistrationConfiguration.java b/src/main/java/com/gomo/app/config/FilterRegistrationConfiguration.java index c0775457..faec657b 100644 --- a/src/main/java/com/gomo/app/config/FilterRegistrationConfiguration.java +++ b/src/main/java/com/gomo/app/config/FilterRegistrationConfiguration.java @@ -10,7 +10,7 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; -import com.gomo.app.support.auth.presentation.security.AuthenticationFilter; +import com.gomo.app.core.auth.adapter.in.security.AuthenticationFilter; import com.gomo.app.support.logging.LoggingFilter; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/com/gomo/app/config/WebConfiguration.java b/src/main/java/com/gomo/app/config/WebConfiguration.java index 61229c50..b02bb4fc 100644 --- a/src/main/java/com/gomo/app/config/WebConfiguration.java +++ b/src/main/java/com/gomo/app/config/WebConfiguration.java @@ -8,7 +8,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import com.gomo.app.common.web.OctetStreamReadMsgConverter; -import com.gomo.app.support.auth.presentation.security.AuthArgumentResolver; +import com.gomo.app.core.auth.adapter.in.security.AuthArgumentResolver; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/com/gomo/app/support/auth/presentation/api/AuthApi.java b/src/main/java/com/gomo/app/core/auth/adapter/in/api/AuthApi.java similarity index 56% rename from src/main/java/com/gomo/app/support/auth/presentation/api/AuthApi.java rename to src/main/java/com/gomo/app/core/auth/adapter/in/api/AuthApi.java index 51a6b31c..17fec369 100644 --- a/src/main/java/com/gomo/app/support/auth/presentation/api/AuthApi.java +++ b/src/main/java/com/gomo/app/core/auth/adapter/in/api/AuthApi.java @@ -1,10 +1,12 @@ -package com.gomo.app.support.auth.presentation.api; +package com.gomo.app.core.auth.adapter.in.api; import static org.springframework.http.HttpStatus.*; import java.time.Duration; +import java.util.UUID; import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.CookieValue; @@ -14,31 +16,39 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; -import com.gomo.app.support.auth.application.port.DeleteAuthTokenPortIn; -import com.gomo.app.support.auth.application.port.dto.AuthTokenDto; -import com.gomo.app.support.auth.application.usecase.AuthenticateUseCase; -import com.gomo.app.support.auth.application.usecase.UpdateRefreshTokenUseCase; -import com.gomo.app.support.auth.presentation.request.LoginRequest; -import com.gomo.app.support.auth.presentation.response.AccessTokenResponse; -import com.gomo.app.support.auth.presentation.security.Auth; -import com.gomo.app.support.auth.presentation.security.AuthInfo; +import com.gomo.app.core.auth.adapter.in.api.request.CreatePrincipalRequest; +import com.gomo.app.core.auth.adapter.in.api.request.LoginRequest; +import com.gomo.app.core.auth.adapter.in.api.response.AccessTokenResponse; +import com.gomo.app.core.auth.adapter.in.api.response.CreatePrincipalResponse; +import com.gomo.app.core.auth.adapter.in.security.Auth; +import com.gomo.app.core.auth.adapter.in.security.AuthInfo; +import com.gomo.app.core.auth.application.port.dto.AuthTokenDto; +import com.gomo.app.core.auth.application.port.in.LoginProcessor; +import com.gomo.app.core.auth.application.port.in.RefreshTokenDeleter; +import com.gomo.app.core.auth.application.port.in.RefreshTokenUpdater; +import com.gomo.app.core.auth.application.port.in.SignupProcessor; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -@Slf4j @RequiredArgsConstructor @RequestMapping("/auth") @CoreApi public class AuthApi { - private final AuthenticateUseCase authenticateUseCase; - private final UpdateRefreshTokenUseCase updateRefreshTokenUseCase; - private final DeleteAuthTokenPortIn deleteAuthTokenPortIn; + private final SignupProcessor signupProcessor; + private final LoginProcessor loginProcessor; + private final RefreshTokenUpdater refreshTokenUpdater; + private final RefreshTokenDeleter refreshTokenDeleter; + + @PostMapping("/signup") + public ResponseEntity signup(@RequestBody CreatePrincipalRequest request) { + UUID principalId = signupProcessor.signup(request.toCommand()); + return ResponseEntity.status(HttpStatus.CREATED).body(CreatePrincipalResponse.of(principalId)); + } @PostMapping("/login") public ResponseEntity login(@RequestBody LoginRequest request) { - AuthTokenDto authTokenDto = authenticateUseCase.authenticate(request.getEmail(), request.getPassword()); + AuthTokenDto authTokenDto = loginProcessor.login(request.getEmail(), request.getPassword()); ResponseCookie cookie = createResponseCookie(authTokenDto.refreshToken(), authTokenDto.expiresIn()); AccessTokenResponse body = AccessTokenResponse.of(authTokenDto.principalId(), authTokenDto.accessToken()); return ResponseEntity.status(OK).header(HttpHeaders.SET_COOKIE, cookie.toString()).body(body); @@ -46,7 +56,7 @@ public ResponseEntity login(@RequestBody LoginRequest reque @PostMapping("/refresh") public ResponseEntity refresh(@CookieValue(name = "refreshToken", required = false) String refreshToken) { - AuthTokenDto authTokenDto = updateRefreshTokenUseCase.update(refreshToken); + AuthTokenDto authTokenDto = refreshTokenUpdater.update(refreshToken); ResponseCookie cookie = createResponseCookie(authTokenDto.refreshToken(), authTokenDto.expiresIn()); return ResponseEntity.ok().header(HttpHeaders.SET_COOKIE, cookie.toString()) .body(AccessTokenResponse.of(authTokenDto.principalId(), authTokenDto.accessToken())); @@ -54,7 +64,7 @@ public ResponseEntity refresh(@CookieValue(name = "refreshT @GetMapping("/logout") public ResponseEntity logout(@Auth AuthInfo authInfo) { - deleteAuthTokenPortIn.deleteRefreshToken(authInfo.getMemberId()); + refreshTokenDeleter.delete(authInfo.getPrincipalId()); ResponseCookie cookie = createResponseCookie("", 0); return ResponseEntity.ok().header(HttpHeaders.SET_COOKIE, cookie.toString()).build(); } diff --git a/src/main/java/com/gomo/app/core/auth/adapter/in/api/EmailCodeApi.java b/src/main/java/com/gomo/app/core/auth/adapter/in/api/EmailCodeApi.java new file mode 100644 index 00000000..52e7a092 --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/adapter/in/api/EmailCodeApi.java @@ -0,0 +1,43 @@ +package com.gomo.app.core.auth.adapter.in.api; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; + +import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.core.auth.adapter.in.api.request.CreateEmailCodeRequest; +import com.gomo.app.core.auth.adapter.in.api.request.VerifyEmailCodeRequest; +import com.gomo.app.core.auth.adapter.in.api.response.VerifyEmailCodeResponse; +import com.gomo.app.core.auth.application.port.in.AuthCodeIssuer; +import com.gomo.app.core.auth.application.port.in.AuthTokenIssuer; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@RequestMapping("/auth/codes/emails") +@CoreApi +public class EmailCodeApi { + + private final AuthCodeIssuer authCodeIssuer; + private final AuthTokenIssuer authTokenIssuer; + + @PostMapping("/signup") + public ResponseEntity create(@RequestBody CreateEmailCodeRequest request) { + authCodeIssuer.issueForSignUp(request.getEmail()); + return ResponseEntity.status(HttpStatus.CREATED).build(); + } + + @PostMapping("/passwords/reset") + public ResponseEntity createForPassword(@RequestBody CreateEmailCodeRequest request) { + authCodeIssuer.issueForPasswordReset(request.getEmail()); + return ResponseEntity.status(HttpStatus.CREATED).build(); + } + + @PostMapping("/verify") + public ResponseEntity verify(@RequestBody VerifyEmailCodeRequest request) { + String temporaryToken = authTokenIssuer.issue(request.getEmail(), request.getCode()); + return ResponseEntity.status(HttpStatus.OK).body(VerifyEmailCodeResponse.of(temporaryToken)); + } +} diff --git a/src/main/java/com/gomo/app/support/auth/presentation/api/OAuthApi.java b/src/main/java/com/gomo/app/core/auth/adapter/in/api/OAuthApi.java similarity index 80% rename from src/main/java/com/gomo/app/support/auth/presentation/api/OAuthApi.java rename to src/main/java/com/gomo/app/core/auth/adapter/in/api/OAuthApi.java index e7715b60..1705b7f6 100644 --- a/src/main/java/com/gomo/app/support/auth/presentation/api/OAuthApi.java +++ b/src/main/java/com/gomo/app/core/auth/adapter/in/api/OAuthApi.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.presentation.api; +package com.gomo.app.core.auth.adapter.in.api; import java.time.Duration; @@ -11,8 +11,8 @@ import org.springframework.web.bind.annotation.RequestParam; import com.gomo.app.common.arch.CoreApi; -import com.gomo.app.support.auth.application.usecase.OAuthUseCase; -import com.gomo.app.support.auth.presentation.response.OAuthResponse; +import com.gomo.app.core.auth.adapter.in.api.response.OAuthResponse; +import com.gomo.app.core.auth.application.port.in.OAuthLoginProcessor; import lombok.RequiredArgsConstructor; @@ -21,11 +21,11 @@ @CoreApi public class OAuthApi { - private final OAuthUseCase oauthUseCase; + private final OAuthLoginProcessor oAuthLoginProcessor; @GetMapping("/{provider}") public ResponseEntity getUserInformation(@PathVariable String provider, @RequestParam String code) { - return oauthUseCase.findPrincipal(provider, code).map(oAuthTokenDto -> { + return oAuthLoginProcessor.login(provider, code).map(oAuthTokenDto -> { ResponseCookie cookie = createResponseCookie(oAuthTokenDto.refreshToken(), oAuthTokenDto.expiresIn()); return ResponseEntity.ok().header(HttpHeaders.SET_COOKIE, cookie.toString()).body(OAuthResponse.from(oAuthTokenDto)); }).orElseGet(() -> ResponseEntity.ok().body(OAuthResponse.none())); diff --git a/src/main/java/com/gomo/app/core/member/presentation/request/CreateEmailCodeRequest.java b/src/main/java/com/gomo/app/core/auth/adapter/in/api/request/CreateEmailCodeRequest.java similarity index 83% rename from src/main/java/com/gomo/app/core/member/presentation/request/CreateEmailCodeRequest.java rename to src/main/java/com/gomo/app/core/auth/adapter/in/api/request/CreateEmailCodeRequest.java index b8733d87..04fc4c50 100644 --- a/src/main/java/com/gomo/app/core/member/presentation/request/CreateEmailCodeRequest.java +++ b/src/main/java/com/gomo/app/core/auth/adapter/in/api/request/CreateEmailCodeRequest.java @@ -1,10 +1,10 @@ -package com.gomo.app.core.member.presentation.request; +package com.gomo.app.core.auth.adapter.in.api.request; import lombok.Getter; @Getter public class CreateEmailCodeRequest { - + private final String email; private CreateEmailCodeRequest(String email) { diff --git a/src/main/java/com/gomo/app/core/auth/adapter/in/api/request/CreatePrincipalRequest.java b/src/main/java/com/gomo/app/core/auth/adapter/in/api/request/CreatePrincipalRequest.java new file mode 100644 index 00000000..87f11d45 --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/adapter/in/api/request/CreatePrincipalRequest.java @@ -0,0 +1,35 @@ +package com.gomo.app.core.auth.adapter.in.api.request; + +import com.gomo.app.core.auth.application.port.command.CreatePrincipalCommand; + +import lombok.Getter; + +@Getter +public class CreatePrincipalRequest { + + private final String email; + private final String password; + private final String handle; + private final String name; + private final String motto; + private final String loginProvider; + private final String temporaryToken; + + private CreatePrincipalRequest(String email, String password, String handle, String name, String motto, String loginProvider, String temporaryToken) { + this.email = email; + this.password = password; + this.handle = handle; + this.name = name; + this.motto = motto; + this.loginProvider = loginProvider; + this.temporaryToken = temporaryToken; + } + + public static CreatePrincipalRequest of(String email, String password, String handle, String name, String motto, String loginProvider, String temporaryToken) { + return new CreatePrincipalRequest(email, password, handle, name, motto, loginProvider, temporaryToken); + } + + public CreatePrincipalCommand toCommand() { + return CreatePrincipalCommand.of(email, password, handle, name, motto, loginProvider, temporaryToken); + } +} diff --git a/src/main/java/com/gomo/app/support/auth/presentation/request/LoginRequest.java b/src/main/java/com/gomo/app/core/auth/adapter/in/api/request/LoginRequest.java similarity index 86% rename from src/main/java/com/gomo/app/support/auth/presentation/request/LoginRequest.java rename to src/main/java/com/gomo/app/core/auth/adapter/in/api/request/LoginRequest.java index cdeda3f5..a11a2537 100644 --- a/src/main/java/com/gomo/app/support/auth/presentation/request/LoginRequest.java +++ b/src/main/java/com/gomo/app/core/auth/adapter/in/api/request/LoginRequest.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.presentation.request; +package com.gomo.app.core.auth.adapter.in.api.request; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/member/presentation/request/VerifyEmailCodeRequest.java b/src/main/java/com/gomo/app/core/auth/adapter/in/api/request/VerifyEmailCodeRequest.java similarity index 86% rename from src/main/java/com/gomo/app/core/member/presentation/request/VerifyEmailCodeRequest.java rename to src/main/java/com/gomo/app/core/auth/adapter/in/api/request/VerifyEmailCodeRequest.java index b05b9985..93e6f0dc 100644 --- a/src/main/java/com/gomo/app/core/member/presentation/request/VerifyEmailCodeRequest.java +++ b/src/main/java/com/gomo/app/core/auth/adapter/in/api/request/VerifyEmailCodeRequest.java @@ -1,9 +1,10 @@ -package com.gomo.app.core.member.presentation.request; +package com.gomo.app.core.auth.adapter.in.api.request; import lombok.Getter; @Getter public class VerifyEmailCodeRequest { + private final String email; private final String code; diff --git a/src/main/java/com/gomo/app/support/auth/presentation/response/AccessTokenResponse.java b/src/main/java/com/gomo/app/core/auth/adapter/in/api/response/AccessTokenResponse.java similarity index 88% rename from src/main/java/com/gomo/app/support/auth/presentation/response/AccessTokenResponse.java rename to src/main/java/com/gomo/app/core/auth/adapter/in/api/response/AccessTokenResponse.java index a44e732e..384d19fc 100644 --- a/src/main/java/com/gomo/app/support/auth/presentation/response/AccessTokenResponse.java +++ b/src/main/java/com/gomo/app/core/auth/adapter/in/api/response/AccessTokenResponse.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.presentation.response; +package com.gomo.app.core.auth.adapter.in.api.response; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/auth/adapter/in/api/response/CreatePrincipalResponse.java b/src/main/java/com/gomo/app/core/auth/adapter/in/api/response/CreatePrincipalResponse.java new file mode 100644 index 00000000..3f7cde92 --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/adapter/in/api/response/CreatePrincipalResponse.java @@ -0,0 +1,21 @@ +package com.gomo.app.core.auth.adapter.in.api.response; + +import java.util.UUID; + +import lombok.Getter; +import lombok.ToString; + +@Getter +@ToString +public class CreatePrincipalResponse { + + private final UUID id; + + private CreatePrincipalResponse(UUID id) { + this.id = id; + } + + public static CreatePrincipalResponse of(UUID id) { + return new CreatePrincipalResponse(id); + } +} diff --git a/src/main/java/com/gomo/app/support/auth/presentation/response/OAuthPrincipalResponse.java b/src/main/java/com/gomo/app/core/auth/adapter/in/api/response/OAuthPrincipalResponse.java similarity index 89% rename from src/main/java/com/gomo/app/support/auth/presentation/response/OAuthPrincipalResponse.java rename to src/main/java/com/gomo/app/core/auth/adapter/in/api/response/OAuthPrincipalResponse.java index a7e96c13..b2ff07bc 100644 --- a/src/main/java/com/gomo/app/support/auth/presentation/response/OAuthPrincipalResponse.java +++ b/src/main/java/com/gomo/app/core/auth/adapter/in/api/response/OAuthPrincipalResponse.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.presentation.response; +package com.gomo.app.core.auth.adapter.in.api.response; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/support/auth/presentation/response/OAuthResponse.java b/src/main/java/com/gomo/app/core/auth/adapter/in/api/response/OAuthResponse.java similarity index 86% rename from src/main/java/com/gomo/app/support/auth/presentation/response/OAuthResponse.java rename to src/main/java/com/gomo/app/core/auth/adapter/in/api/response/OAuthResponse.java index 9d854aca..7a9b0d2a 100644 --- a/src/main/java/com/gomo/app/support/auth/presentation/response/OAuthResponse.java +++ b/src/main/java/com/gomo/app/core/auth/adapter/in/api/response/OAuthResponse.java @@ -1,6 +1,6 @@ -package com.gomo.app.support.auth.presentation.response; +package com.gomo.app.core.auth.adapter.in.api.response; -import com.gomo.app.support.auth.application.port.dto.OAuthTokenDto; +import com.gomo.app.core.auth.application.port.dto.OAuthTokenDto; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/member/presentation/response/VerifyEmailCodeResponse.java b/src/main/java/com/gomo/app/core/auth/adapter/in/api/response/VerifyEmailCodeResponse.java similarity index 85% rename from src/main/java/com/gomo/app/core/member/presentation/response/VerifyEmailCodeResponse.java rename to src/main/java/com/gomo/app/core/auth/adapter/in/api/response/VerifyEmailCodeResponse.java index c30d154b..283d7caf 100644 --- a/src/main/java/com/gomo/app/core/member/presentation/response/VerifyEmailCodeResponse.java +++ b/src/main/java/com/gomo/app/core/auth/adapter/in/api/response/VerifyEmailCodeResponse.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.presentation.response; +package com.gomo.app.core.auth.adapter.in.api.response; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/support/auth/presentation/security/Auth.java b/src/main/java/com/gomo/app/core/auth/adapter/in/security/Auth.java similarity index 81% rename from src/main/java/com/gomo/app/support/auth/presentation/security/Auth.java rename to src/main/java/com/gomo/app/core/auth/adapter/in/security/Auth.java index 02b3ae6d..40055c24 100644 --- a/src/main/java/com/gomo/app/support/auth/presentation/security/Auth.java +++ b/src/main/java/com/gomo/app/core/auth/adapter/in/security/Auth.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.presentation.security; +package com.gomo.app.core.auth.adapter.in.security; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/com/gomo/app/support/auth/presentation/security/AuthArgumentResolver.java b/src/main/java/com/gomo/app/core/auth/adapter/in/security/AuthArgumentResolver.java similarity index 94% rename from src/main/java/com/gomo/app/support/auth/presentation/security/AuthArgumentResolver.java rename to src/main/java/com/gomo/app/core/auth/adapter/in/security/AuthArgumentResolver.java index 987866a5..27d27be3 100644 --- a/src/main/java/com/gomo/app/support/auth/presentation/security/AuthArgumentResolver.java +++ b/src/main/java/com/gomo/app/core/auth/adapter/in/security/AuthArgumentResolver.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.presentation.security; +package com.gomo.app.core.auth.adapter.in.security; import jakarta.servlet.http.HttpServletRequest; diff --git a/src/main/java/com/gomo/app/core/auth/adapter/in/security/AuthInfo.java b/src/main/java/com/gomo/app/core/auth/adapter/in/security/AuthInfo.java new file mode 100644 index 00000000..fca7ec61 --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/adapter/in/security/AuthInfo.java @@ -0,0 +1,19 @@ +package com.gomo.app.core.auth.adapter.in.security; + +import java.util.UUID; + +import lombok.Getter; + +@Getter +public class AuthInfo { + + private UUID principalId; + + private AuthInfo(UUID principalId) { + this.principalId = principalId; + } + + public static AuthInfo of(UUID principalId) { + return new AuthInfo(principalId); + } +} diff --git a/src/main/java/com/gomo/app/support/auth/presentation/security/AuthenticationFilter.java b/src/main/java/com/gomo/app/core/auth/adapter/in/security/AuthenticationFilter.java similarity index 86% rename from src/main/java/com/gomo/app/support/auth/presentation/security/AuthenticationFilter.java rename to src/main/java/com/gomo/app/core/auth/adapter/in/security/AuthenticationFilter.java index 978fe082..84d004a4 100644 --- a/src/main/java/com/gomo/app/support/auth/presentation/security/AuthenticationFilter.java +++ b/src/main/java/com/gomo/app/core/auth/adapter/in/security/AuthenticationFilter.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.presentation.security; +package com.gomo.app.core.auth.adapter.in.security; import static com.gomo.app.support.logging.MDC.*; @@ -8,8 +8,8 @@ import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; -import com.gomo.app.common.security.jwt.application.port.VerifyJwtPortIn; import com.gomo.app.config.AuthFilterConfiguration; +import com.gomo.app.core.auth.application.port.out.JwtVerifier; import io.jsonwebtoken.JwtException; import jakarta.servlet.FilterChain; @@ -28,7 +28,7 @@ public class AuthenticationFilter extends OncePerRequestFilter { private static final String BEARER_TOKEN = "Bearer "; private final AuthFilterConfiguration config; - private final VerifyJwtPortIn verifyJwtPortIn; + private final JwtVerifier jwtVerifier; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { @@ -55,7 +55,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse } try { token = token.substring(BEARER_TOKEN.length()); - String memberId = verifyJwtPortIn.extractSubject(token); + String memberId = jwtVerifier.extractSubject(token); MDC.put(MEMBER_ID.name(), memberId); log.info("action=MEMBER_AUTHENTICATION, status=success, memberId={}", memberId); request.setAttribute("memberId", memberId); diff --git a/src/main/java/com/gomo/app/support/auth/infrastructure/adapter/SendAuthCodeAdapter.java b/src/main/java/com/gomo/app/core/auth/adapter/out/client/MailClient.java similarity index 76% rename from src/main/java/com/gomo/app/support/auth/infrastructure/adapter/SendAuthCodeAdapter.java rename to src/main/java/com/gomo/app/core/auth/adapter/out/client/MailClient.java index 1a6b5a8c..14a1c7f2 100644 --- a/src/main/java/com/gomo/app/support/auth/infrastructure/adapter/SendAuthCodeAdapter.java +++ b/src/main/java/com/gomo/app/core/auth/adapter/out/client/MailClient.java @@ -1,11 +1,11 @@ -package com.gomo.app.support.auth.infrastructure.adapter; +package com.gomo.app.core.auth.adapter.out.client; import org.springframework.beans.factory.annotation.Value; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; import com.gomo.app.common.arch.Adapter; -import com.gomo.app.support.auth.application.port.SendAuthCodePortOut; +import com.gomo.app.core.auth.application.port.out.AuthCodeSender; import jakarta.mail.MessagingException; import jakarta.mail.internet.MimeMessage; @@ -13,14 +13,15 @@ @RequiredArgsConstructor @Adapter -class SendAuthCodeAdapter implements SendAuthCodePortOut { +class MailClient implements AuthCodeSender { @Value("${spring.mail.username}") String USERNAME; private final JavaMailSender mailSender; + // TODO [2025-10-10] jhl221123 : 빈번한 요청에 대비해야 합니다. @Override - public void toEmail(String email, String authCode) { + public void send(String email, String authCode) { MimeMessage mimeMessage = mailSender.createMimeMessage(); try { MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true); diff --git a/src/main/java/com/gomo/app/core/auth/adapter/out/client/MemberClient.java b/src/main/java/com/gomo/app/core/auth/adapter/out/client/MemberClient.java new file mode 100644 index 00000000..85f614e4 --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/adapter/out/client/MemberClient.java @@ -0,0 +1,47 @@ +package com.gomo.app.core.auth.adapter.out.client; + +import java.util.Optional; +import java.util.UUID; + +import com.gomo.app.common.arch.Adapter; +import com.gomo.app.core.member.application.port.in.EmailChecker; +import com.gomo.app.core.member.application.port.in.MemberCreator; +import com.gomo.app.core.member.application.port.in.MemberLoginProcessor; +import com.gomo.app.core.member.application.port.in.MemberOAuthLoginProcessor; +import com.gomo.app.core.auth.application.port.command.CreatePrincipalCommand; +import com.gomo.app.core.auth.application.port.out.PrincipalCreator; +import com.gomo.app.core.auth.application.port.out.PrincipalEmailChecker; +import com.gomo.app.core.auth.application.port.out.PrincipalLoginProcessor; +import com.gomo.app.core.auth.application.port.out.PrincipalOAuthLoginProcessor; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Adapter +class MemberClient implements PrincipalCreator, PrincipalEmailChecker, PrincipalLoginProcessor, PrincipalOAuthLoginProcessor { + + private final MemberCreator memberCreator; + private final EmailChecker emailChecker; + private final MemberLoginProcessor memberLoginProcessor; + private final MemberOAuthLoginProcessor memberOAuthLoginProcessor; + + @Override + public UUID create(CreatePrincipalCommand command) { + return memberCreator.create(command.toMemberCommand()); + } + + @Override + public boolean exists(String email) { + return emailChecker.exists(email); + } + + @Override + public UUID login(String email, String password) { + return memberLoginProcessor.login(email, password); + } + + @Override + public Optional login(String email) { + return memberOAuthLoginProcessor.login(email); + } +} diff --git a/src/main/java/com/gomo/app/support/auth/infrastructure/oauth/provider/GoogleOAuthProvider.java b/src/main/java/com/gomo/app/core/auth/adapter/out/client/OAuthGoogleClient.java similarity index 87% rename from src/main/java/com/gomo/app/support/auth/infrastructure/oauth/provider/GoogleOAuthProvider.java rename to src/main/java/com/gomo/app/core/auth/adapter/out/client/OAuthGoogleClient.java index abdfde14..15d4f9f4 100644 --- a/src/main/java/com/gomo/app/support/auth/infrastructure/oauth/provider/GoogleOAuthProvider.java +++ b/src/main/java/com/gomo/app/core/auth/adapter/out/client/OAuthGoogleClient.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.infrastructure.oauth.provider; +package com.gomo.app.core.auth.adapter.out.client; import java.util.Map; @@ -8,14 +8,15 @@ import com.fasterxml.jackson.databind.JsonNode; import com.gomo.app.core.member.domain.model.LoginProvider; -import com.gomo.app.support.auth.domain.model.OAuthPrincipal; +import com.gomo.app.core.auth.application.port.out.OAuthProvider; +import com.gomo.app.core.auth.domain.model.OAuthPrincipal; import lombok.RequiredArgsConstructor; -@Component("google") @RequiredArgsConstructor -public class GoogleOAuthProvider implements OAuthProvider { - +@Component("google") +class OAuthGoogleClient implements OAuthProvider { + private final RestClient restClient; @Value("${oauth.google.client-id}") diff --git a/src/main/java/com/gomo/app/support/auth/infrastructure/oauth/provider/KakaoOAuthProvider.java b/src/main/java/com/gomo/app/core/auth/adapter/out/client/OAuthKakaoClient.java similarity index 90% rename from src/main/java/com/gomo/app/support/auth/infrastructure/oauth/provider/KakaoOAuthProvider.java rename to src/main/java/com/gomo/app/core/auth/adapter/out/client/OAuthKakaoClient.java index 9bdee476..6d781f4e 100644 --- a/src/main/java/com/gomo/app/support/auth/infrastructure/oauth/provider/KakaoOAuthProvider.java +++ b/src/main/java/com/gomo/app/core/auth/adapter/out/client/OAuthKakaoClient.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.infrastructure.oauth.provider; +package com.gomo.app.core.auth.adapter.out.client; import java.nio.charset.StandardCharsets; @@ -12,13 +12,14 @@ import com.fasterxml.jackson.databind.JsonNode; import com.gomo.app.core.member.domain.model.LoginProvider; -import com.gomo.app.support.auth.domain.model.OAuthPrincipal; +import com.gomo.app.core.auth.application.port.out.OAuthProvider; +import com.gomo.app.core.auth.domain.model.OAuthPrincipal; import lombok.RequiredArgsConstructor; -@Component("kakao") @RequiredArgsConstructor -public class KakaoOAuthProvider implements OAuthProvider { +@Component("kakao") +class OAuthKakaoClient implements OAuthProvider { private final RestClient restClient; diff --git a/src/main/java/com/gomo/app/support/auth/infrastructure/oauth/provider/NaverOAuthProvider.java b/src/main/java/com/gomo/app/core/auth/adapter/out/client/OAuthNaverClient.java similarity index 88% rename from src/main/java/com/gomo/app/support/auth/infrastructure/oauth/provider/NaverOAuthProvider.java rename to src/main/java/com/gomo/app/core/auth/adapter/out/client/OAuthNaverClient.java index a9b3b732..09ae35ba 100644 --- a/src/main/java/com/gomo/app/support/auth/infrastructure/oauth/provider/NaverOAuthProvider.java +++ b/src/main/java/com/gomo/app/core/auth/adapter/out/client/OAuthNaverClient.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.infrastructure.oauth.provider; +package com.gomo.app.core.auth.adapter.out.client; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpHeaders; @@ -9,13 +9,14 @@ import com.fasterxml.jackson.databind.JsonNode; import com.gomo.app.core.member.domain.model.LoginProvider; -import com.gomo.app.support.auth.domain.model.OAuthPrincipal; +import com.gomo.app.core.auth.application.port.out.OAuthProvider; +import com.gomo.app.core.auth.domain.model.OAuthPrincipal; import lombok.RequiredArgsConstructor; -@Component("naver") @RequiredArgsConstructor -public class NaverOAuthProvider implements OAuthProvider { +@Component("naver") +class OAuthNaverClient implements OAuthProvider { private final RestClient restClient; diff --git a/src/main/java/com/gomo/app/core/auth/adapter/out/factory/OAuthProviderFactory.java b/src/main/java/com/gomo/app/core/auth/adapter/out/factory/OAuthProviderFactory.java new file mode 100644 index 00000000..81aec61c --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/adapter/out/factory/OAuthProviderFactory.java @@ -0,0 +1,24 @@ +package com.gomo.app.core.auth.adapter.out.factory; + +import java.util.Map; + +import com.gomo.app.common.arch.Adapter; +import com.gomo.app.core.auth.application.port.out.OAuthProvider; +import com.gomo.app.core.auth.application.port.out.OAuthProviderReader; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Adapter +class OAuthProviderFactory implements OAuthProviderReader { + + private final Map providers; + + public OAuthProvider read(String providerName) { + OAuthProvider provider = providers.get(providerName); + if (provider == null) { + throw new IllegalArgumentException("Unsupported OAuth Provider: " + providerName); + } + return provider; + } +} diff --git a/src/main/java/com/gomo/app/common/security/jwt/application/ManageJwtUseCase.java b/src/main/java/com/gomo/app/core/auth/adapter/out/lib/JwtClient.java similarity index 78% rename from src/main/java/com/gomo/app/common/security/jwt/application/ManageJwtUseCase.java rename to src/main/java/com/gomo/app/core/auth/adapter/out/lib/JwtClient.java index 3b96b386..57456199 100644 --- a/src/main/java/com/gomo/app/common/security/jwt/application/ManageJwtUseCase.java +++ b/src/main/java/com/gomo/app/core/auth/adapter/out/lib/JwtClient.java @@ -1,4 +1,4 @@ -package com.gomo.app.common.security.jwt.application; +package com.gomo.app.core.auth.adapter.out.lib; import java.nio.charset.StandardCharsets; import java.util.Date; @@ -9,9 +9,9 @@ import org.springframework.beans.factory.annotation.Value; -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.common.security.jwt.application.port.GenerateJwtPortIn; -import com.gomo.app.common.security.jwt.application.port.VerifyJwtPortIn; +import com.gomo.app.common.arch.Adapter; +import com.gomo.app.core.auth.application.port.out.JwtCreator; +import com.gomo.app.core.auth.application.port.out.JwtVerifier; import io.jsonwebtoken.Claims; import io.jsonwebtoken.ExpiredJwtException; @@ -20,13 +20,14 @@ import lombok.extern.slf4j.Slf4j; @Slf4j -@ApplicationService -class ManageJwtUseCase implements GenerateJwtPortIn, VerifyJwtPortIn { +@Adapter +class JwtClient implements JwtCreator, JwtVerifier { + private final long accessExpirationTime; private final long refreshExpirationTime; private final SecretKey secretKey; - public ManageJwtUseCase( + public JwtClient( @Value("${jwt.secret-key}") String secret, @Value("${jwt.expiration.access}") long accessExpirationTime, @Value("${jwt.expiration.refresh}") long refreshExpirationTime) { @@ -36,22 +37,22 @@ public ManageJwtUseCase( } @Override - public String generateAccessToken(UUID subject) { + public String createAccessToken(UUID subject) { return generateToken(subject.toString(), accessExpirationTime); } @Override - public String generateRefreshToken(UUID subject) { + public String createRefreshToken(UUID subject) { return generateToken(subject.toString(), refreshExpirationTime); } @Override - public String generateTemporaryToken(String subject, long expiration) { + public String createTemporaryToken(String subject, long expiration) { return generateToken(subject, expiration); } @Override - public boolean validateToken(String token) { + public boolean verify(String token) { try { parseClaims(token); return true; diff --git a/src/main/java/com/gomo/app/support/auth/infrastructure/persistence/AuditorAwareImpl.java b/src/main/java/com/gomo/app/core/auth/adapter/out/persistence/AuditorAwareImpl.java similarity index 75% rename from src/main/java/com/gomo/app/support/auth/infrastructure/persistence/AuditorAwareImpl.java rename to src/main/java/com/gomo/app/core/auth/adapter/out/persistence/AuditorAwareImpl.java index 95598dce..bf000100 100644 --- a/src/main/java/com/gomo/app/support/auth/infrastructure/persistence/AuditorAwareImpl.java +++ b/src/main/java/com/gomo/app/core/auth/adapter/out/persistence/AuditorAwareImpl.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.infrastructure.persistence; +package com.gomo.app.core.auth.adapter.out.persistence; import java.util.Optional; @@ -8,18 +8,18 @@ import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; -import com.gomo.app.common.security.jwt.application.port.VerifyJwtPortIn; +import com.gomo.app.core.auth.application.port.out.JwtVerifier; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; +@RequiredArgsConstructor @Profile("prod") @Component -@RequiredArgsConstructor public class AuditorAwareImpl implements AuditorAware { private final ObjectProvider requestProvider; - private final VerifyJwtPortIn verifyJwtPortIn; + private final JwtVerifier jwtVerifier; @Override public Optional getCurrentAuditor() { @@ -29,10 +29,10 @@ public Optional getCurrentAuditor() { } String token = extractTokenFromHeader(request); - if (!StringUtils.hasText(token) || !verifyJwtPortIn.validateToken(token)) { + if (!StringUtils.hasText(token) || !jwtVerifier.verify(token)) { return Optional.of("SYSTEM"); } - String memberId = verifyJwtPortIn.extractSubject(token); + String memberId = jwtVerifier.extractSubject(token); return Optional.of(memberId); } diff --git a/src/main/java/com/gomo/app/support/auth/infrastructure/persistence/RedisAuthCodeRepository.java b/src/main/java/com/gomo/app/core/auth/adapter/out/persistence/RedisAuthCodeRepository.java similarity index 87% rename from src/main/java/com/gomo/app/support/auth/infrastructure/persistence/RedisAuthCodeRepository.java rename to src/main/java/com/gomo/app/core/auth/adapter/out/persistence/RedisAuthCodeRepository.java index f5d0c70a..ce51e0bd 100644 --- a/src/main/java/com/gomo/app/support/auth/infrastructure/persistence/RedisAuthCodeRepository.java +++ b/src/main/java/com/gomo/app/core/auth/adapter/out/persistence/RedisAuthCodeRepository.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.infrastructure.persistence; +package com.gomo.app.core.auth.adapter.out.persistence; import java.util.Optional; import java.util.concurrent.TimeUnit; @@ -7,7 +7,7 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Repository; -import com.gomo.app.support.auth.domain.repository.AuthCodeRepository; +import com.gomo.app.core.auth.domain.repository.AuthCodeRepository; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/com/gomo/app/support/auth/infrastructure/persistence/RedisAuthTokenRepository.java b/src/main/java/com/gomo/app/core/auth/adapter/out/persistence/RedisAuthTokenRepository.java similarity index 78% rename from src/main/java/com/gomo/app/support/auth/infrastructure/persistence/RedisAuthTokenRepository.java rename to src/main/java/com/gomo/app/core/auth/adapter/out/persistence/RedisAuthTokenRepository.java index a4bee575..95e34738 100644 --- a/src/main/java/com/gomo/app/support/auth/infrastructure/persistence/RedisAuthTokenRepository.java +++ b/src/main/java/com/gomo/app/core/auth/adapter/out/persistence/RedisAuthTokenRepository.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.infrastructure.persistence; +package com.gomo.app.core.auth.adapter.out.persistence; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -8,7 +8,7 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Repository; -import com.gomo.app.support.auth.domain.repository.AuthTokenRepository; +import com.gomo.app.core.auth.domain.repository.AuthTokenRepository; import lombok.RequiredArgsConstructor; @@ -23,12 +23,12 @@ public class RedisAuthTokenRepository implements AuthTokenRepository { private long REFRESH_EXP_TIME; @Override - public void setRefreshToken(UUID principalId, String refreshToken) { + public void saveRefreshToken(UUID principalId, String refreshToken) { redisTemplate.opsForValue().set(principalId.toString(), refreshToken, REFRESH_EXP_TIME, TimeUnit.SECONDS); } @Override - public String getRefreshToken(UUID principalId) { + public String findRefreshToken(UUID principalId) { return (String)redisTemplate.opsForValue().get(principalId.toString()); } diff --git a/src/main/java/com/gomo/app/core/auth/application/port/command/CreatePrincipalCommand.java b/src/main/java/com/gomo/app/core/auth/application/port/command/CreatePrincipalCommand.java new file mode 100644 index 00000000..2c82e253 --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/application/port/command/CreatePrincipalCommand.java @@ -0,0 +1,14 @@ +package com.gomo.app.core.auth.application.port.command; + +import com.gomo.app.core.member.application.port.command.CreateMemberCommand; + +public record CreatePrincipalCommand(String email, String password, String handle, String name, String motto, String loginProvider, String temporaryToken) { + + public static CreatePrincipalCommand of(String email, String password, String handle, String name, String motto, String loginProvider, String temporaryToken) { + return new CreatePrincipalCommand(email, password, handle, name, motto, loginProvider, temporaryToken); + } + + public CreateMemberCommand toMemberCommand() { + return CreateMemberCommand.of(email, password, handle, name, motto, loginProvider); + } +} diff --git a/src/main/java/com/gomo/app/support/auth/application/port/dto/AuthTokenDto.java b/src/main/java/com/gomo/app/core/auth/application/port/dto/AuthTokenDto.java similarity index 85% rename from src/main/java/com/gomo/app/support/auth/application/port/dto/AuthTokenDto.java rename to src/main/java/com/gomo/app/core/auth/application/port/dto/AuthTokenDto.java index 8e999f95..9d4ea94f 100644 --- a/src/main/java/com/gomo/app/support/auth/application/port/dto/AuthTokenDto.java +++ b/src/main/java/com/gomo/app/core/auth/application/port/dto/AuthTokenDto.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.application.port.dto; +package com.gomo.app.core.auth.application.port.dto; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/support/auth/application/port/dto/OAuthTokenDto.java b/src/main/java/com/gomo/app/core/auth/application/port/dto/OAuthTokenDto.java similarity index 91% rename from src/main/java/com/gomo/app/support/auth/application/port/dto/OAuthTokenDto.java rename to src/main/java/com/gomo/app/core/auth/application/port/dto/OAuthTokenDto.java index 3092688a..0f790545 100644 --- a/src/main/java/com/gomo/app/support/auth/application/port/dto/OAuthTokenDto.java +++ b/src/main/java/com/gomo/app/core/auth/application/port/dto/OAuthTokenDto.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.application.port.dto; +package com.gomo.app.core.auth.application.port.dto; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/auth/application/port/in/AuthCodeIssuer.java b/src/main/java/com/gomo/app/core/auth/application/port/in/AuthCodeIssuer.java new file mode 100644 index 00000000..387fba36 --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/application/port/in/AuthCodeIssuer.java @@ -0,0 +1,25 @@ +package com.gomo.app.core.auth.application.port.in; + +import com.gomo.app.core.member.domain.exception.EmailDuplicatedException; +import com.gomo.app.core.member.domain.exception.MemberNotFoundException; + +public interface AuthCodeIssuer { + + /** + * Creates and sends an authentication code to a new user's email for verification during the sign-up process. + * This method also checks if the email is already in use as a handle. + * + * @param email The email address to which the sign-up code will be sent. + * @throws EmailDuplicatedException if the provided email is already registered as a handle. + */ + void issueForSignUp(String email); + + /** + * Creates and sends an authentication code to an existing member's email for the purpose of resetting their password. + * This method verifies that a member with the specified email exists before sending the code. + * + * @param email The email address of the member requesting a password reset. + * @throws MemberNotFoundException if no member is found with the specified email address. + */ + void issueForPasswordReset(String email); +} diff --git a/src/main/java/com/gomo/app/core/auth/application/port/in/AuthTokenIssuer.java b/src/main/java/com/gomo/app/core/auth/application/port/in/AuthTokenIssuer.java new file mode 100644 index 00000000..64c6bf50 --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/application/port/in/AuthTokenIssuer.java @@ -0,0 +1,14 @@ +package com.gomo.app.core.auth.application.port.in; + +public interface AuthTokenIssuer { + + /** + * Verifies an authentication code sent to a specific email address. + * Upon successful verification, it creates a temporary token for subsequent processes like completing registration. + * + * @param email The email address for which the code is being verified. + * @param emailCode The authentication code provided by the user. + * @return A temporary token (JWT) that authorizes the next step in the workflow. + */ + String issue(String email, String emailCode); +} diff --git a/src/main/java/com/gomo/app/core/auth/application/port/in/LoginProcessor.java b/src/main/java/com/gomo/app/core/auth/application/port/in/LoginProcessor.java new file mode 100644 index 00000000..dc2de11c --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/application/port/in/LoginProcessor.java @@ -0,0 +1,8 @@ +package com.gomo.app.core.auth.application.port.in; + +import com.gomo.app.core.auth.application.port.dto.AuthTokenDto; + +public interface LoginProcessor { + + AuthTokenDto login(String email, String password); +} diff --git a/src/main/java/com/gomo/app/core/auth/application/port/in/OAuthLoginProcessor.java b/src/main/java/com/gomo/app/core/auth/application/port/in/OAuthLoginProcessor.java new file mode 100644 index 00000000..2773e3ba --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/application/port/in/OAuthLoginProcessor.java @@ -0,0 +1,10 @@ +package com.gomo.app.core.auth.application.port.in; + +import java.util.Optional; + +import com.gomo.app.core.auth.application.port.dto.OAuthTokenDto; + +public interface OAuthLoginProcessor { + + Optional login(String providerName, String code); +} diff --git a/src/main/java/com/gomo/app/support/auth/application/port/DeleteAuthTokenPortIn.java b/src/main/java/com/gomo/app/core/auth/application/port/in/RefreshTokenDeleter.java similarity index 58% rename from src/main/java/com/gomo/app/support/auth/application/port/DeleteAuthTokenPortIn.java rename to src/main/java/com/gomo/app/core/auth/application/port/in/RefreshTokenDeleter.java index c89511cd..f3a0af02 100644 --- a/src/main/java/com/gomo/app/support/auth/application/port/DeleteAuthTokenPortIn.java +++ b/src/main/java/com/gomo/app/core/auth/application/port/in/RefreshTokenDeleter.java @@ -1,13 +1,13 @@ -package com.gomo.app.support.auth.application.port; +package com.gomo.app.core.auth.application.port.in; import java.util.UUID; -public interface DeleteAuthTokenPortIn { +public interface RefreshTokenDeleter { /** * Deletes the currently active refresh token for a given principal. * * @param principalId The id of the principal whose token should be revoked. */ - void deleteRefreshToken(UUID principalId); + void delete(UUID principalId); } diff --git a/src/main/java/com/gomo/app/core/auth/application/port/in/RefreshTokenUpdater.java b/src/main/java/com/gomo/app/core/auth/application/port/in/RefreshTokenUpdater.java new file mode 100644 index 00000000..311590a1 --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/application/port/in/RefreshTokenUpdater.java @@ -0,0 +1,8 @@ +package com.gomo.app.core.auth.application.port.in; + +import com.gomo.app.core.auth.application.port.dto.AuthTokenDto; + +public interface RefreshTokenUpdater { + + AuthTokenDto update(String refreshToken); +} diff --git a/src/main/java/com/gomo/app/core/auth/application/port/in/SignupProcessor.java b/src/main/java/com/gomo/app/core/auth/application/port/in/SignupProcessor.java new file mode 100644 index 00000000..5db7a9f7 --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/application/port/in/SignupProcessor.java @@ -0,0 +1,10 @@ +package com.gomo.app.core.auth.application.port.in; + +import java.util.UUID; + +import com.gomo.app.core.auth.application.port.command.CreatePrincipalCommand; + +public interface SignupProcessor { + + UUID signup(CreatePrincipalCommand command); +} diff --git a/src/main/java/com/gomo/app/support/auth/application/port/SendAuthCodePortOut.java b/src/main/java/com/gomo/app/core/auth/application/port/out/AuthCodeSender.java similarity index 65% rename from src/main/java/com/gomo/app/support/auth/application/port/SendAuthCodePortOut.java rename to src/main/java/com/gomo/app/core/auth/application/port/out/AuthCodeSender.java index 855eaee0..ab8b50b7 100644 --- a/src/main/java/com/gomo/app/support/auth/application/port/SendAuthCodePortOut.java +++ b/src/main/java/com/gomo/app/core/auth/application/port/out/AuthCodeSender.java @@ -1,6 +1,6 @@ -package com.gomo.app.support.auth.application.port; +package com.gomo.app.core.auth.application.port.out; -public interface SendAuthCodePortOut { +public interface AuthCodeSender { /** * Sends a given authentication code to the specified email address. @@ -9,5 +9,5 @@ public interface SendAuthCodePortOut { * @param authCode The authentication code to be sent. * @throws IllegalStateException if the email delivery fails. */ - void toEmail(String email, String authCode); + void send(String email, String authCode); } diff --git a/src/main/java/com/gomo/app/core/auth/application/port/out/JwtCreator.java b/src/main/java/com/gomo/app/core/auth/application/port/out/JwtCreator.java new file mode 100644 index 00000000..049e6030 --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/application/port/out/JwtCreator.java @@ -0,0 +1,19 @@ +package com.gomo.app.core.auth.application.port.out; + +import java.util.UUID; + +public interface JwtCreator { + + String createAccessToken(UUID subject); + + String createRefreshToken(UUID subject); + + /** + * Generates a temporary token. + * + * @param subject token subject + * @param expiration time in seconds + * @return temporary token + */ + String createTemporaryToken(String subject, long expiration); +} diff --git a/src/main/java/com/gomo/app/core/auth/application/port/out/JwtVerifier.java b/src/main/java/com/gomo/app/core/auth/application/port/out/JwtVerifier.java new file mode 100644 index 00000000..cc940d3a --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/application/port/out/JwtVerifier.java @@ -0,0 +1,10 @@ +package com.gomo.app.core.auth.application.port.out; + +public interface JwtVerifier { + + boolean verify(String token); + + String extractSubject(String token); + + long extractExpirationTime(String token); +} diff --git a/src/main/java/com/gomo/app/core/auth/application/port/out/OAuthProvider.java b/src/main/java/com/gomo/app/core/auth/application/port/out/OAuthProvider.java new file mode 100644 index 00000000..c4fe6816 --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/application/port/out/OAuthProvider.java @@ -0,0 +1,8 @@ +package com.gomo.app.core.auth.application.port.out; + +import com.gomo.app.core.auth.domain.model.OAuthPrincipal; + +public interface OAuthProvider { + + OAuthPrincipal authenticate(String code); +} diff --git a/src/main/java/com/gomo/app/core/auth/application/port/out/OAuthProviderReader.java b/src/main/java/com/gomo/app/core/auth/application/port/out/OAuthProviderReader.java new file mode 100644 index 00000000..88bf1ead --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/application/port/out/OAuthProviderReader.java @@ -0,0 +1,6 @@ +package com.gomo.app.core.auth.application.port.out; + +public interface OAuthProviderReader { + + OAuthProvider read(String providerName); +} diff --git a/src/main/java/com/gomo/app/core/auth/application/port/out/PrincipalCreator.java b/src/main/java/com/gomo/app/core/auth/application/port/out/PrincipalCreator.java new file mode 100644 index 00000000..ff080523 --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/application/port/out/PrincipalCreator.java @@ -0,0 +1,10 @@ +package com.gomo.app.core.auth.application.port.out; + +import java.util.UUID; + +import com.gomo.app.core.auth.application.port.command.CreatePrincipalCommand; + +public interface PrincipalCreator { + + UUID create(CreatePrincipalCommand command); +} diff --git a/src/main/java/com/gomo/app/core/auth/application/port/out/PrincipalEmailChecker.java b/src/main/java/com/gomo/app/core/auth/application/port/out/PrincipalEmailChecker.java new file mode 100644 index 00000000..e43508d5 --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/application/port/out/PrincipalEmailChecker.java @@ -0,0 +1,6 @@ +package com.gomo.app.core.auth.application.port.out; + +public interface PrincipalEmailChecker { + + boolean exists(String email); +} diff --git a/src/main/java/com/gomo/app/core/auth/application/port/out/PrincipalLoginProcessor.java b/src/main/java/com/gomo/app/core/auth/application/port/out/PrincipalLoginProcessor.java new file mode 100644 index 00000000..bc130d18 --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/application/port/out/PrincipalLoginProcessor.java @@ -0,0 +1,8 @@ +package com.gomo.app.core.auth.application.port.out; + +import java.util.UUID; + +public interface PrincipalLoginProcessor { + + UUID login(String email, String password); +} diff --git a/src/main/java/com/gomo/app/core/auth/application/port/out/PrincipalOAuthLoginProcessor.java b/src/main/java/com/gomo/app/core/auth/application/port/out/PrincipalOAuthLoginProcessor.java new file mode 100644 index 00000000..b9206a8b --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/application/port/out/PrincipalOAuthLoginProcessor.java @@ -0,0 +1,9 @@ +package com.gomo.app.core.auth.application.port.out; + +import java.util.Optional; +import java.util.UUID; + +public interface PrincipalOAuthLoginProcessor { + + Optional login(String email); +} diff --git a/src/main/java/com/gomo/app/core/auth/application/service/AuthCodeService.java b/src/main/java/com/gomo/app/core/auth/application/service/AuthCodeService.java new file mode 100644 index 00000000..23a5ca36 --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/application/service/AuthCodeService.java @@ -0,0 +1,54 @@ +package com.gomo.app.core.auth.application.service; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.core.auth.application.port.in.AuthCodeIssuer; +import com.gomo.app.core.auth.application.port.out.AuthCodeSender; +import com.gomo.app.core.auth.application.port.out.PrincipalEmailChecker; +import com.gomo.app.core.auth.domain.exception.AuthCodeCreateFailException; +import com.gomo.app.core.auth.domain.exception.AuthErrorCode; +import com.gomo.app.core.auth.domain.exception.InvalidAuthCodeException; +import com.gomo.app.core.auth.domain.model.AuthCode; +import com.gomo.app.core.auth.domain.repository.AuthCodeRepository; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@ApplicationService +class AuthCodeService implements AuthCodeIssuer { + + private final PrincipalEmailChecker principalEmailChecker; + private final AuthCodeSender authCodeSender; + private final AuthCodeRepository authCodeRepository; + + @Override + @AuditLog(action = "AUTH_CODE_ISSUE_FOR_SIGN_UP") + public void issueForSignUp(String email) { + if (principalEmailChecker.exists(email)) { + throw new AuthCodeCreateFailException(AuthErrorCode.PRINCIPAL_DUPLICATED); + } + createAndSendAuthCode(email); + } + + @Override + @AuditLog(action = "AUTH_CODE_ISSUE_FOR_PW_RESET") + public void issueForPasswordReset(String email) { + if (!principalEmailChecker.exists(email)) { + throw new AuthCodeCreateFailException(AuthErrorCode.PRINCIPAL_NOT_FOUND); + } + createAndSendAuthCode(email); + } + + private void createAndSendAuthCode(String email) { + AuthCode authCode = AuthCode.generate(); + authCodeRepository.save(email, authCode.getValue()); + authCodeSender.send(email, authCode.getValue()); + } + + void verify(String email, String authCode) { + authCodeRepository.findByEmail(email) + .filter(code -> code.equals(authCode)) + .orElseThrow(() -> new InvalidAuthCodeException(AuthErrorCode.INVALID_AUTH_CODE)); + authCodeRepository.delete(email); + } +} diff --git a/src/main/java/com/gomo/app/core/auth/application/service/AuthService.java b/src/main/java/com/gomo/app/core/auth/application/service/AuthService.java new file mode 100644 index 00000000..517a3371 --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/application/service/AuthService.java @@ -0,0 +1,49 @@ +package com.gomo.app.core.auth.application.service; + +import static com.gomo.app.core.auth.domain.exception.AuthErrorCode.*; + +import java.util.UUID; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.core.auth.application.port.command.CreatePrincipalCommand; +import com.gomo.app.core.auth.application.port.dto.AuthTokenDto; +import com.gomo.app.core.auth.application.port.in.LoginProcessor; +import com.gomo.app.core.auth.application.port.in.SignupProcessor; +import com.gomo.app.core.auth.application.port.out.JwtVerifier; +import com.gomo.app.core.auth.application.port.out.PrincipalCreator; +import com.gomo.app.core.auth.application.port.out.PrincipalLoginProcessor; +import com.gomo.app.core.auth.domain.exception.AuthenticationFailException; +import com.gomo.app.core.auth.domain.model.AuthToken; +import com.gomo.app.core.member.domain.model.LoginProvider; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@ApplicationService +class AuthService implements SignupProcessor, LoginProcessor { + + private final PrincipalCreator principalCreator; + private final JwtVerifier jwtVerifier; + private final PrincipalLoginProcessor principalLoginProcessor; + private final AuthTokenService authTokenService; + + @Override + @AuditLog(action = "SIGNUP") + public UUID signup(CreatePrincipalCommand command) { + // TODO [2025-11-02] jhl221123 : 토큰 내부 이메일이 동일한지 확인하는 jwt 기능이 추가되어야 합니다. + if (LoginProvider.EMAIL.name().equals(command.loginProvider()) && !jwtVerifier.verify(command.temporaryToken())) { + throw new AuthenticationFailException(INVALID_VERIFIED_EMAIL_TOKEN); + } + return principalCreator.create(command); + } + + @Override + @AuditLog(action = "LOGIN") + public AuthTokenDto login(String email, String password) { + UUID principalId = principalLoginProcessor.login(email, password); + AuthToken authToken = authTokenService.create(principalId); + long expirationTime = jwtVerifier.extractExpirationTime(authToken.getRefreshToken()); + return AuthTokenDto.of(principalId, authToken.getAccessToken(), authToken.getRefreshToken(), expirationTime); + } +} diff --git a/src/main/java/com/gomo/app/core/auth/application/service/AuthTokenService.java b/src/main/java/com/gomo/app/core/auth/application/service/AuthTokenService.java new file mode 100644 index 00000000..37332072 --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/application/service/AuthTokenService.java @@ -0,0 +1,69 @@ +package com.gomo.app.core.auth.application.service; + +import java.util.Objects; +import java.util.UUID; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.core.auth.application.port.dto.AuthTokenDto; +import com.gomo.app.core.auth.application.port.in.AuthTokenIssuer; +import com.gomo.app.core.auth.application.port.in.RefreshTokenDeleter; +import com.gomo.app.core.auth.application.port.in.RefreshTokenUpdater; +import com.gomo.app.core.auth.application.port.out.JwtCreator; +import com.gomo.app.core.auth.application.port.out.JwtVerifier; +import com.gomo.app.core.auth.domain.exception.AuthErrorCode; +import com.gomo.app.core.auth.domain.exception.AuthenticationFailException; +import com.gomo.app.core.auth.domain.model.AuthToken; +import com.gomo.app.core.auth.domain.repository.AuthTokenRepository; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@ApplicationService +class AuthTokenService implements AuthTokenIssuer, RefreshTokenDeleter, RefreshTokenUpdater { + + private final JwtCreator jwtCreator; + private final JwtVerifier jwtVerifier; + private final AuthCodeService authCodeService; + private final AuthTokenRepository authTokenRepository; + + @Override + @AuditLog(action = "VERIFIED_EMAIL_TOKEN_ISSUE") + public String issue(String email, String emailCode) { + Objects.requireNonNull(emailCode); + authCodeService.verify(email, emailCode); + return jwtCreator.createTemporaryToken(email, 1800); + } + + @AuditLog(action = "AUTH_TOKEN_CREATE") + public AuthToken create(UUID principalId) { + String accessToken = jwtCreator.createAccessToken(principalId); + String refreshToken = jwtCreator.createRefreshToken(principalId); + authTokenRepository.saveRefreshToken(principalId, refreshToken); + return AuthToken.of(accessToken, refreshToken); + } + + @Override + @AuditLog(action = "REFRESH_TOKEN_UPDATE") + public AuthTokenDto update(String refreshToken) { + if (refreshToken == null) { + throw new AuthenticationFailException(AuthErrorCode.MISSING_REFRESH_TOKEN); + } + + UUID principalId = UUID.fromString(jwtVerifier.extractSubject(refreshToken)); + String originRefreshToken = authTokenRepository.findRefreshToken(principalId); + if (!originRefreshToken.equals(refreshToken)) { + throw new AuthenticationFailException(AuthErrorCode.INVALID_REFRESH_TOKEN); + } + + AuthToken authToken = create(principalId); + long refreshTokenExpirationTime = jwtVerifier.extractExpirationTime(authToken.getRefreshToken()); + return AuthTokenDto.of(principalId, authToken.getAccessToken(), authToken.getRefreshToken(), refreshTokenExpirationTime); + } + + @Override + @AuditLog(action = "REFRESH_TOKEN_DELETE") + public void delete(UUID principalId) { + authTokenRepository.deleteRefreshToken(principalId); + } +} diff --git a/src/main/java/com/gomo/app/core/auth/application/service/OAuthService.java b/src/main/java/com/gomo/app/core/auth/application/service/OAuthService.java new file mode 100644 index 00000000..c1c9bb14 --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/application/service/OAuthService.java @@ -0,0 +1,55 @@ +package com.gomo.app.core.auth.application.service; + +import java.util.Optional; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.core.auth.application.port.dto.OAuthTokenDto; +import com.gomo.app.core.auth.application.port.in.OAuthLoginProcessor; +import com.gomo.app.core.auth.application.port.out.JwtVerifier; +import com.gomo.app.core.auth.application.port.out.OAuthProvider; +import com.gomo.app.core.auth.application.port.out.OAuthProviderReader; +import com.gomo.app.core.auth.application.port.out.PrincipalOAuthLoginProcessor; +import com.gomo.app.core.auth.domain.model.AuthToken; +import com.gomo.app.core.auth.domain.model.OAuthPrincipal; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@ApplicationService +class OAuthService implements OAuthLoginProcessor { + + private final OAuthProviderReader providerFactory; + private final PrincipalOAuthLoginProcessor principalOAuthLoginProcessor; + private final AuthTokenService authTokenService; + private final JwtVerifier jwtVerifier; + + @Override + @AuditLog(action = "OAUTH_LOGIN") + public Optional login(String providerName, String code) { + OAuthProvider provider = providerFactory.read(providerName); + OAuthPrincipal principal = provider.authenticate(code); + + return principalOAuthLoginProcessor.login(principal.getEmail()) + .map(principalId -> { + AuthToken authToken = authTokenService.create(principalId); + long refreshExpirationTime = jwtVerifier.extractExpirationTime(authToken.getRefreshToken()); + return OAuthTokenDto.withToken( + principalId, + authToken.getAccessToken(), + authToken.getRefreshToken(), + refreshExpirationTime, + principal.getProvider().name(), + principal.getEmail(), + principal.getName() + ); + }) + .or(() -> Optional.of( + OAuthTokenDto.withoutToken( + principal.getProvider().name(), + principal.getEmail(), + principal.getName() + ) + )); + } +} diff --git a/src/main/java/com/gomo/app/core/auth/domain/exception/AuthCodeCreateFailException.java b/src/main/java/com/gomo/app/core/auth/domain/exception/AuthCodeCreateFailException.java new file mode 100644 index 00000000..10c06d89 --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/domain/exception/AuthCodeCreateFailException.java @@ -0,0 +1,14 @@ +package com.gomo.app.core.auth.domain.exception; + +import com.gomo.app.common.exception.ApplicationException; + +public class AuthCodeCreateFailException extends ApplicationException { + + public AuthCodeCreateFailException(AuthErrorCode errorCode) { + super(errorCode.getHttpStatus(), errorCode.getErrorCode(), errorCode.getMessage()); + } + + public AuthCodeCreateFailException(AuthErrorCode errorCode, Throwable cause) { + super(errorCode.getHttpStatus(), errorCode.getErrorCode(), errorCode.getMessage(), cause); + } +} diff --git a/src/main/java/com/gomo/app/support/auth/exception/AuthErrorCode.java b/src/main/java/com/gomo/app/core/auth/domain/exception/AuthErrorCode.java similarity index 64% rename from src/main/java/com/gomo/app/support/auth/exception/AuthErrorCode.java rename to src/main/java/com/gomo/app/core/auth/domain/exception/AuthErrorCode.java index 272b1dcc..65ccc08e 100644 --- a/src/main/java/com/gomo/app/support/auth/exception/AuthErrorCode.java +++ b/src/main/java/com/gomo/app/core/auth/domain/exception/AuthErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.exception; +package com.gomo.app.core.auth.domain.exception; import lombok.Getter; @@ -8,7 +8,10 @@ public enum AuthErrorCode { INVALID_AUTH_CODE(401, "AUT-ROO-001", "Auth code is incorrect"), MISSING_REFRESH_TOKEN(401, "AUT-ROO-002", "Refresh token not found"), INVALID_REFRESH_TOKEN(401, "AUT-ROO-003", "Refresh token is incorrect"), - UNSUPPORTED_LOGIN_METHOD(401, "AUT-ROO-004", "OAuth member cannot login with password"); + UNSUPPORTED_LOGIN_METHOD(401, "AUT-ROO-004", "OAuth member cannot login with password"), + PRINCIPAL_DUPLICATED(409, "AUT-ROO-005", "Principal already exists"), + PRINCIPAL_NOT_FOUND(404, "AUT-ROO-006", "Principal not found"), + INVALID_VERIFIED_EMAIL_TOKEN(401, "AUT-ROO-007", "Verified email token is incorrect"); private final int httpStatus; private final String errorCode; diff --git a/src/main/java/com/gomo/app/support/auth/exception/AuthenticationFailException.java b/src/main/java/com/gomo/app/core/auth/domain/exception/AuthenticationFailException.java similarity index 88% rename from src/main/java/com/gomo/app/support/auth/exception/AuthenticationFailException.java rename to src/main/java/com/gomo/app/core/auth/domain/exception/AuthenticationFailException.java index 76c3a1ad..0eb57233 100644 --- a/src/main/java/com/gomo/app/support/auth/exception/AuthenticationFailException.java +++ b/src/main/java/com/gomo/app/core/auth/domain/exception/AuthenticationFailException.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.exception; +package com.gomo.app.core.auth.domain.exception; import com.gomo.app.common.exception.ApplicationException; diff --git a/src/main/java/com/gomo/app/support/auth/exception/InvalidAuthCodeException.java b/src/main/java/com/gomo/app/core/auth/domain/exception/InvalidAuthCodeException.java similarity index 87% rename from src/main/java/com/gomo/app/support/auth/exception/InvalidAuthCodeException.java rename to src/main/java/com/gomo/app/core/auth/domain/exception/InvalidAuthCodeException.java index 0a699195..df448e89 100644 --- a/src/main/java/com/gomo/app/support/auth/exception/InvalidAuthCodeException.java +++ b/src/main/java/com/gomo/app/core/auth/domain/exception/InvalidAuthCodeException.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.exception; +package com.gomo.app.core.auth.domain.exception; import com.gomo.app.common.exception.ApplicationException; diff --git a/src/main/java/com/gomo/app/support/auth/domain/model/AuthCode.java b/src/main/java/com/gomo/app/core/auth/domain/model/AuthCode.java similarity index 93% rename from src/main/java/com/gomo/app/support/auth/domain/model/AuthCode.java rename to src/main/java/com/gomo/app/core/auth/domain/model/AuthCode.java index 1b49f8a1..5e22e2cb 100644 --- a/src/main/java/com/gomo/app/support/auth/domain/model/AuthCode.java +++ b/src/main/java/com/gomo/app/core/auth/domain/model/AuthCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.domain.model; +package com.gomo.app.core.auth.domain.model; import java.util.Random; diff --git a/src/main/java/com/gomo/app/support/auth/domain/model/AuthToken.java b/src/main/java/com/gomo/app/core/auth/domain/model/AuthToken.java similarity index 90% rename from src/main/java/com/gomo/app/support/auth/domain/model/AuthToken.java rename to src/main/java/com/gomo/app/core/auth/domain/model/AuthToken.java index aa5be14c..9bf29213 100644 --- a/src/main/java/com/gomo/app/support/auth/domain/model/AuthToken.java +++ b/src/main/java/com/gomo/app/core/auth/domain/model/AuthToken.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.domain.model; +package com.gomo.app.core.auth.domain.model; import com.gomo.app.common.arch.ValueObject; diff --git a/src/main/java/com/gomo/app/support/auth/domain/model/OAuthPrincipal.java b/src/main/java/com/gomo/app/core/auth/domain/model/OAuthPrincipal.java similarity index 92% rename from src/main/java/com/gomo/app/support/auth/domain/model/OAuthPrincipal.java rename to src/main/java/com/gomo/app/core/auth/domain/model/OAuthPrincipal.java index 841561fc..6df4966a 100644 --- a/src/main/java/com/gomo/app/support/auth/domain/model/OAuthPrincipal.java +++ b/src/main/java/com/gomo/app/core/auth/domain/model/OAuthPrincipal.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.domain.model; +package com.gomo.app.core.auth.domain.model; import com.gomo.app.common.arch.ValueObject; import com.gomo.app.core.member.domain.model.LoginProvider; diff --git a/src/main/java/com/gomo/app/support/auth/domain/repository/AuthCodeRepository.java b/src/main/java/com/gomo/app/core/auth/domain/repository/AuthCodeRepository.java similarity index 78% rename from src/main/java/com/gomo/app/support/auth/domain/repository/AuthCodeRepository.java rename to src/main/java/com/gomo/app/core/auth/domain/repository/AuthCodeRepository.java index a0cb5d23..13f1658c 100644 --- a/src/main/java/com/gomo/app/support/auth/domain/repository/AuthCodeRepository.java +++ b/src/main/java/com/gomo/app/core/auth/domain/repository/AuthCodeRepository.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.domain.repository; +package com.gomo.app.core.auth.domain.repository; import java.util.Optional; diff --git a/src/main/java/com/gomo/app/core/auth/domain/repository/AuthTokenRepository.java b/src/main/java/com/gomo/app/core/auth/domain/repository/AuthTokenRepository.java new file mode 100644 index 00000000..017d2b03 --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/domain/repository/AuthTokenRepository.java @@ -0,0 +1,12 @@ +package com.gomo.app.core.auth.domain.repository; + +import java.util.UUID; + +public interface AuthTokenRepository { + + void saveRefreshToken(UUID principalId, String refreshToken); + + String findRefreshToken(UUID principalId); + + void deleteRefreshToken(UUID principalId); +} diff --git a/src/main/java/com/gomo/app/core/interest/presentation/api/InterestApi.java b/src/main/java/com/gomo/app/core/interest/adapter/in/api/InterestApi.java similarity index 55% rename from src/main/java/com/gomo/app/core/interest/presentation/api/InterestApi.java rename to src/main/java/com/gomo/app/core/interest/adapter/in/api/InterestApi.java index f530b604..744f77d1 100644 --- a/src/main/java/com/gomo/app/core/interest/presentation/api/InterestApi.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/InterestApi.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.api; +package com.gomo.app.core.interest.adapter.in.api; import static org.springframework.http.HttpStatus.*; @@ -17,18 +17,18 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; -import com.gomo.app.core.interest.application.port.ReadInterestPortIn; +import com.gomo.app.core.interest.adapter.in.api.request.CreateInterestRequest; +import com.gomo.app.core.interest.adapter.in.api.request.UpdateInterestRequest; +import com.gomo.app.core.interest.adapter.in.api.response.CreateInterestResponse; +import com.gomo.app.core.interest.adapter.in.api.response.ListInterestResponse; +import com.gomo.app.core.interest.adapter.in.api.response.ReadInterestResponse; import com.gomo.app.core.interest.application.port.dto.InterestDto; -import com.gomo.app.core.interest.application.usecase.CreateInterestUseCase; -import com.gomo.app.core.interest.application.usecase.DeleteInterestUseCase; -import com.gomo.app.core.interest.application.usecase.UpdateInterestUseCase; -import com.gomo.app.core.interest.presentation.api.request.CreateInterestRequest; -import com.gomo.app.core.interest.presentation.api.request.UpdateInterestRequest; -import com.gomo.app.core.interest.presentation.api.response.CreateInterestResponse; -import com.gomo.app.core.interest.presentation.api.response.ListInterestResponse; -import com.gomo.app.core.interest.presentation.api.response.ReadInterestResponse; -import com.gomo.app.support.auth.presentation.security.Auth; -import com.gomo.app.support.auth.presentation.security.AuthInfo; +import com.gomo.app.core.interest.application.port.in.InterestCreator; +import com.gomo.app.core.interest.application.port.in.InterestDeleter; +import com.gomo.app.core.interest.application.port.in.InterestReader; +import com.gomo.app.core.interest.application.port.in.InterestUpdater; +import com.gomo.app.core.auth.adapter.in.security.Auth; +import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -37,26 +37,26 @@ @CoreApi public class InterestApi { - private final CreateInterestUseCase createInterestUseCase; - private final ReadInterestPortIn readInterestPortIn; - private final UpdateInterestUseCase updateInterestUseCase; - private final DeleteInterestUseCase deleteInterestUseCase; + private final InterestCreator interestCreator; + private final InterestReader interestReader; + private final InterestUpdater interestUpdater; + private final InterestDeleter interestDeleter; @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity create(@Auth AuthInfo authInfo, @ModelAttribute CreateInterestRequest request) { - UUID interestId = createInterestUseCase.create(request.toCommand(authInfo.getMemberId())); + UUID interestId = interestCreator.create(request.toCommand(authInfo.getPrincipalId())); return ResponseEntity.status(CREATED).body(CreateInterestResponse.of(interestId)); } @GetMapping("/{id}") public ResponseEntity find(@PathVariable("id") UUID interestId) { - InterestDto dto = readInterestPortIn.find(interestId); + InterestDto dto = interestReader.read(interestId); return ResponseEntity.status(OK).body(ReadInterestResponse.from(dto)); } @GetMapping public ResponseEntity list(@Auth AuthInfo authInfo) { - List responses = readInterestPortIn.findAll(authInfo.getMemberId()).stream() + List responses = interestReader.readAll(authInfo.getPrincipalId()).stream() .map(ReadInterestResponse::from) .toList(); return ResponseEntity.status(OK).body(ListInterestResponse.of(responses)); @@ -64,13 +64,13 @@ public ResponseEntity list(@Auth AuthInfo authInfo) { @PutMapping("/{id}") public ResponseEntity update(@Auth AuthInfo authInfo, @PathVariable("id") UUID interestId, @RequestBody UpdateInterestRequest request) { - updateInterestUseCase.update(request.toCommand(authInfo.getMemberId(), interestId)); + interestUpdater.update(request.toCommand(authInfo.getPrincipalId(), interestId)); return ResponseEntity.noContent().build(); } @DeleteMapping("/{id}") public ResponseEntity delete(@Auth AuthInfo authInfo, @PathVariable("id") UUID interestId) { - deleteInterestUseCase.delete(authInfo.getMemberId(), interestId); + interestDeleter.delete(authInfo.getPrincipalId(), interestId); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/interest/presentation/api/InterestLogoApi.java b/src/main/java/com/gomo/app/core/interest/adapter/in/api/InterestLogoApi.java similarity index 74% rename from src/main/java/com/gomo/app/core/interest/presentation/api/InterestLogoApi.java rename to src/main/java/com/gomo/app/core/interest/adapter/in/api/InterestLogoApi.java index 7df2ef7c..1423f75e 100644 --- a/src/main/java/com/gomo/app/core/interest/presentation/api/InterestLogoApi.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/InterestLogoApi.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.api; +package com.gomo.app.core.interest.adapter.in.api; import java.util.UUID; @@ -10,7 +10,7 @@ import org.springframework.web.multipart.MultipartFile; import com.gomo.app.common.arch.CoreApi; -import com.gomo.app.core.interest.application.usecase.UpdateLogoUseCase; +import com.gomo.app.core.interest.application.port.in.LogoUpdater; import lombok.RequiredArgsConstructor; @@ -19,11 +19,11 @@ @CoreApi public class InterestLogoApi { - private final UpdateLogoUseCase updateLogoUseCase; + private final LogoUpdater logoUpdater; @PutMapping public ResponseEntity update(@PathVariable("id") UUID interestId, @RequestPart MultipartFile updatedLogo) { - updateLogoUseCase.update(interestId, updatedLogo); + logoUpdater.update(interestId, updatedLogo); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/interest/presentation/api/InterestNetworkApi.java b/src/main/java/com/gomo/app/core/interest/adapter/in/api/InterestNetworkApi.java similarity index 52% rename from src/main/java/com/gomo/app/core/interest/presentation/api/InterestNetworkApi.java rename to src/main/java/com/gomo/app/core/interest/adapter/in/api/InterestNetworkApi.java index 669ab61c..ae0394c3 100644 --- a/src/main/java/com/gomo/app/core/interest/presentation/api/InterestNetworkApi.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/InterestNetworkApi.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.api; +package com.gomo.app.core.interest.adapter.in.api; import static org.springframework.http.HttpStatus.*; @@ -13,15 +13,15 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.core.interest.adapter.in.api.request.CreateInterestRelationRequest; +import com.gomo.app.core.interest.adapter.in.api.response.CreateInterestRelationResponse; +import com.gomo.app.core.interest.adapter.in.api.response.InterestNetworkResponse; import com.gomo.app.core.interest.application.port.dto.InterestNetworkDto; -import com.gomo.app.core.interest.application.usecase.CreateInterestRelationUseCase; -import com.gomo.app.core.interest.application.usecase.DeleteInterestRelationUseCase; -import com.gomo.app.core.interest.application.usecase.ReadInterestNetworkUseCase; -import com.gomo.app.core.interest.presentation.api.request.CreateInterestRelationRequest; -import com.gomo.app.core.interest.presentation.api.response.CreateInterestRelationResponse; -import com.gomo.app.core.interest.presentation.api.response.InterestNetworkResponse; -import com.gomo.app.support.auth.presentation.security.Auth; -import com.gomo.app.support.auth.presentation.security.AuthInfo; +import com.gomo.app.core.interest.application.port.in.InterestNetworkReader; +import com.gomo.app.core.interest.application.port.in.InterestRelationCreator; +import com.gomo.app.core.interest.application.port.in.InterestRelationDeleter; +import com.gomo.app.core.auth.adapter.in.security.Auth; +import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -30,25 +30,25 @@ @CoreApi public class InterestNetworkApi { - private final CreateInterestRelationUseCase createInterestRelationUseCase; - private final ReadInterestNetworkUseCase readInterestNetworkUseCase; - private final DeleteInterestRelationUseCase deleteInterestRelationUseCase; + private final InterestRelationCreator interestRelationCreator; + private final InterestNetworkReader interestNetworkReader; + private final InterestRelationDeleter interestRelationDeleter; @PostMapping("/relations") public ResponseEntity createRelation(@Auth AuthInfo authInfo, @RequestBody CreateInterestRelationRequest request) { - UUID relationId = createInterestRelationUseCase.create(authInfo.getMemberId(), request.getParentInterestId(), request.getChildInterestId()); + UUID relationId = interestRelationCreator.create(authInfo.getPrincipalId(), request.getParentInterestId(), request.getChildInterestId()); return ResponseEntity.status(CREATED).body(CreateInterestRelationResponse.of(relationId)); } @GetMapping public ResponseEntity find(@Auth AuthInfo authInfo) { - InterestNetworkDto interestNetworkDto = readInterestNetworkUseCase.find(authInfo.getMemberId()); + InterestNetworkDto interestNetworkDto = interestNetworkReader.read(authInfo.getPrincipalId()); return ResponseEntity.ok(InterestNetworkResponse.from(interestNetworkDto)); } @DeleteMapping("/relations/{id}") public ResponseEntity deleteRelation(@Auth AuthInfo authInfo, @PathVariable("id") UUID interestRelationId) { - deleteInterestRelationUseCase.delete(authInfo.getMemberId(), interestRelationId); + interestRelationDeleter.delete(authInfo.getPrincipalId(), interestRelationId); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/interest/presentation/api/MajorInterestApi.java b/src/main/java/com/gomo/app/core/interest/adapter/in/api/MajorInterestApi.java similarity index 55% rename from src/main/java/com/gomo/app/core/interest/presentation/api/MajorInterestApi.java rename to src/main/java/com/gomo/app/core/interest/adapter/in/api/MajorInterestApi.java index b41903a9..7807ddb5 100644 --- a/src/main/java/com/gomo/app/core/interest/presentation/api/MajorInterestApi.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/MajorInterestApi.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.api; +package com.gomo.app.core.interest.adapter.in.api; import static org.springframework.http.HttpStatus.*; @@ -13,14 +13,14 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.core.interest.adapter.in.api.response.CreateMajorInterestResponse; +import com.gomo.app.core.interest.adapter.in.api.response.ListMajorInterestResponse; import com.gomo.app.core.interest.application.port.dto.MajorInterestDto; -import com.gomo.app.core.interest.application.usecase.CreateMajorInterestUseCase; -import com.gomo.app.core.interest.application.usecase.DeleteMajorInterestUseCase; -import com.gomo.app.core.interest.application.usecase.ReadMajorInterestUseCase; -import com.gomo.app.core.interest.presentation.api.response.CreateMajorInterestResponse; -import com.gomo.app.core.interest.presentation.api.response.ListMajorInterestResponse; -import com.gomo.app.support.auth.presentation.security.Auth; -import com.gomo.app.support.auth.presentation.security.AuthInfo; +import com.gomo.app.core.interest.application.port.in.MajorInterestCreator; +import com.gomo.app.core.interest.application.port.in.MajorInterestDeleter; +import com.gomo.app.core.interest.application.port.in.MajorInterestReader; +import com.gomo.app.core.auth.adapter.in.security.Auth; +import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -29,25 +29,25 @@ @CoreApi public class MajorInterestApi { - private final CreateMajorInterestUseCase createMajorInterestUseCase; - private final ReadMajorInterestUseCase readMajorInterestUseCase; - private final DeleteMajorInterestUseCase deleteMajorInterestUseCase; + private final MajorInterestCreator majorInterestCreator; + private final MajorInterestReader majorInterestReader; + private final MajorInterestDeleter majorInterestDeleter; @PostMapping("/{id}/majors") public ResponseEntity create(@Auth AuthInfo authInfo, @PathVariable("id") UUID interestId) { - UUID majorInterestId = createMajorInterestUseCase.create(authInfo.getMemberId(), interestId); + UUID majorInterestId = majorInterestCreator.create(authInfo.getPrincipalId(), interestId); return ResponseEntity.status(CREATED).body(CreateMajorInterestResponse.of(majorInterestId)); } @GetMapping("/majors") public ResponseEntity findAll(@Auth AuthInfo authInfo) { - List dtos = readMajorInterestUseCase.findAll(authInfo.getMemberId()); + List dtos = majorInterestReader.readAll(authInfo.getPrincipalId()); return ResponseEntity.ok(ListMajorInterestResponse.of(dtos)); } @DeleteMapping("/majors/{id}") public ResponseEntity delete(@Auth AuthInfo authInfo, @PathVariable("id") UUID majorInterestId) { - deleteMajorInterestUseCase.delete(authInfo.getMemberId(), majorInterestId); + majorInterestDeleter.delete(authInfo.getPrincipalId(), majorInterestId); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/interest/presentation/api/OrderUpdateMajorInterestApi.java b/src/main/java/com/gomo/app/core/interest/adapter/in/api/OrderUpdateMajorInterestApi.java similarity index 52% rename from src/main/java/com/gomo/app/core/interest/presentation/api/OrderUpdateMajorInterestApi.java rename to src/main/java/com/gomo/app/core/interest/adapter/in/api/OrderUpdateMajorInterestApi.java index 3e29ed5e..c3adf122 100644 --- a/src/main/java/com/gomo/app/core/interest/presentation/api/OrderUpdateMajorInterestApi.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/OrderUpdateMajorInterestApi.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.api; +package com.gomo.app.core.interest.adapter.in.api; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PutMapping; @@ -6,10 +6,10 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; -import com.gomo.app.core.interest.application.usecase.OrderUpdateMajorInterestUseCase; -import com.gomo.app.core.interest.presentation.api.request.OrderUpdateMajorInterestRequest; -import com.gomo.app.support.auth.presentation.security.Auth; -import com.gomo.app.support.auth.presentation.security.AuthInfo; +import com.gomo.app.core.interest.adapter.in.api.request.OrderUpdateMajorInterestRequest; +import com.gomo.app.core.interest.application.port.in.MajorInterestOrderUpdater; +import com.gomo.app.core.auth.adapter.in.security.Auth; +import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -18,11 +18,11 @@ @CoreApi public class OrderUpdateMajorInterestApi { - private final OrderUpdateMajorInterestUseCase orderUpdateMajorInterestUseCase; + private final MajorInterestOrderUpdater majorInterestOrderUpdater; @PutMapping public ResponseEntity update(@Auth AuthInfo authInfo, @RequestBody OrderUpdateMajorInterestRequest request) { - orderUpdateMajorInterestUseCase.update(request.toCommand(authInfo.getMemberId())); + majorInterestOrderUpdater.update(request.toCommand(authInfo.getPrincipalId())); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/interest/presentation/api/request/CreateInterestRelationRequest.java b/src/main/java/com/gomo/app/core/interest/adapter/in/api/request/CreateInterestRelationRequest.java similarity index 85% rename from src/main/java/com/gomo/app/core/interest/presentation/api/request/CreateInterestRelationRequest.java rename to src/main/java/com/gomo/app/core/interest/adapter/in/api/request/CreateInterestRelationRequest.java index bcbca464..05ed1db0 100644 --- a/src/main/java/com/gomo/app/core/interest/presentation/api/request/CreateInterestRelationRequest.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/request/CreateInterestRelationRequest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.api.request; +package com.gomo.app.core.interest.adapter.in.api.request; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/interest/presentation/api/request/CreateInterestRequest.java b/src/main/java/com/gomo/app/core/interest/adapter/in/api/request/CreateInterestRequest.java similarity index 89% rename from src/main/java/com/gomo/app/core/interest/presentation/api/request/CreateInterestRequest.java rename to src/main/java/com/gomo/app/core/interest/adapter/in/api/request/CreateInterestRequest.java index 55787473..26b24e5f 100644 --- a/src/main/java/com/gomo/app/core/interest/presentation/api/request/CreateInterestRequest.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/request/CreateInterestRequest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.api.request; +package com.gomo.app.core.interest.adapter.in.api.request; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/interest/presentation/api/request/OrderUpdateMajorInterestRequest.java b/src/main/java/com/gomo/app/core/interest/adapter/in/api/request/OrderUpdateMajorInterestRequest.java similarity index 89% rename from src/main/java/com/gomo/app/core/interest/presentation/api/request/OrderUpdateMajorInterestRequest.java rename to src/main/java/com/gomo/app/core/interest/adapter/in/api/request/OrderUpdateMajorInterestRequest.java index 2e4f5968..2cade31e 100644 --- a/src/main/java/com/gomo/app/core/interest/presentation/api/request/OrderUpdateMajorInterestRequest.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/request/OrderUpdateMajorInterestRequest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.api.request; +package com.gomo.app.core.interest.adapter.in.api.request; import java.util.List; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/interest/presentation/api/request/UpdateInterestRequest.java b/src/main/java/com/gomo/app/core/interest/adapter/in/api/request/UpdateInterestRequest.java similarity index 87% rename from src/main/java/com/gomo/app/core/interest/presentation/api/request/UpdateInterestRequest.java rename to src/main/java/com/gomo/app/core/interest/adapter/in/api/request/UpdateInterestRequest.java index c540b2af..44093d62 100644 --- a/src/main/java/com/gomo/app/core/interest/presentation/api/request/UpdateInterestRequest.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/request/UpdateInterestRequest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.api.request; +package com.gomo.app.core.interest.adapter.in.api.request; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/interest/presentation/api/response/CreateInterestRelationResponse.java b/src/main/java/com/gomo/app/core/interest/adapter/in/api/response/CreateInterestRelationResponse.java similarity index 79% rename from src/main/java/com/gomo/app/core/interest/presentation/api/response/CreateInterestRelationResponse.java rename to src/main/java/com/gomo/app/core/interest/adapter/in/api/response/CreateInterestRelationResponse.java index 247ebfe8..def966a0 100644 --- a/src/main/java/com/gomo/app/core/interest/presentation/api/response/CreateInterestRelationResponse.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/response/CreateInterestRelationResponse.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.api.response; +package com.gomo.app.core.interest.adapter.in.api.response; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/interest/presentation/api/response/CreateInterestResponse.java b/src/main/java/com/gomo/app/core/interest/adapter/in/api/response/CreateInterestResponse.java similarity index 77% rename from src/main/java/com/gomo/app/core/interest/presentation/api/response/CreateInterestResponse.java rename to src/main/java/com/gomo/app/core/interest/adapter/in/api/response/CreateInterestResponse.java index 5df20561..0be5ea0c 100644 --- a/src/main/java/com/gomo/app/core/interest/presentation/api/response/CreateInterestResponse.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/response/CreateInterestResponse.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.api.response; +package com.gomo.app.core.interest.adapter.in.api.response; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/interest/presentation/api/response/CreateMajorInterestResponse.java b/src/main/java/com/gomo/app/core/interest/adapter/in/api/response/CreateMajorInterestResponse.java similarity index 79% rename from src/main/java/com/gomo/app/core/interest/presentation/api/response/CreateMajorInterestResponse.java rename to src/main/java/com/gomo/app/core/interest/adapter/in/api/response/CreateMajorInterestResponse.java index 0835d143..7ad33d36 100644 --- a/src/main/java/com/gomo/app/core/interest/presentation/api/response/CreateMajorInterestResponse.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/response/CreateMajorInterestResponse.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.api.response; +package com.gomo.app.core.interest.adapter.in.api.response; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/interest/presentation/api/response/InterestNetworkResponse.java b/src/main/java/com/gomo/app/core/interest/adapter/in/api/response/InterestNetworkResponse.java similarity index 91% rename from src/main/java/com/gomo/app/core/interest/presentation/api/response/InterestNetworkResponse.java rename to src/main/java/com/gomo/app/core/interest/adapter/in/api/response/InterestNetworkResponse.java index 5f2453c3..159956c8 100644 --- a/src/main/java/com/gomo/app/core/interest/presentation/api/response/InterestNetworkResponse.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/response/InterestNetworkResponse.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.api.response; +package com.gomo.app.core.interest.adapter.in.api.response; import java.util.List; diff --git a/src/main/java/com/gomo/app/core/interest/presentation/api/response/ListInterestResponse.java b/src/main/java/com/gomo/app/core/interest/adapter/in/api/response/ListInterestResponse.java similarity index 82% rename from src/main/java/com/gomo/app/core/interest/presentation/api/response/ListInterestResponse.java rename to src/main/java/com/gomo/app/core/interest/adapter/in/api/response/ListInterestResponse.java index 4163c1a5..56d659b4 100644 --- a/src/main/java/com/gomo/app/core/interest/presentation/api/response/ListInterestResponse.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/response/ListInterestResponse.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.api.response; +package com.gomo.app.core.interest.adapter.in.api.response; import java.util.List; diff --git a/src/main/java/com/gomo/app/core/interest/presentation/api/response/ListMajorInterestResponse.java b/src/main/java/com/gomo/app/core/interest/adapter/in/api/response/ListMajorInterestResponse.java similarity index 87% rename from src/main/java/com/gomo/app/core/interest/presentation/api/response/ListMajorInterestResponse.java rename to src/main/java/com/gomo/app/core/interest/adapter/in/api/response/ListMajorInterestResponse.java index ba346d90..73a92f36 100644 --- a/src/main/java/com/gomo/app/core/interest/presentation/api/response/ListMajorInterestResponse.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/response/ListMajorInterestResponse.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.api.response; +package com.gomo.app.core.interest.adapter.in.api.response; import java.util.List; diff --git a/src/main/java/com/gomo/app/core/interest/presentation/api/response/ReadInterestRelationResponse.java b/src/main/java/com/gomo/app/core/interest/adapter/in/api/response/ReadInterestRelationResponse.java similarity index 89% rename from src/main/java/com/gomo/app/core/interest/presentation/api/response/ReadInterestRelationResponse.java rename to src/main/java/com/gomo/app/core/interest/adapter/in/api/response/ReadInterestRelationResponse.java index caaa3b3d..e61e5d8e 100644 --- a/src/main/java/com/gomo/app/core/interest/presentation/api/response/ReadInterestRelationResponse.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/response/ReadInterestRelationResponse.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.api.response; +package com.gomo.app.core.interest.adapter.in.api.response; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/interest/presentation/api/response/ReadInterestResponse.java b/src/main/java/com/gomo/app/core/interest/adapter/in/api/response/ReadInterestResponse.java similarity index 91% rename from src/main/java/com/gomo/app/core/interest/presentation/api/response/ReadInterestResponse.java rename to src/main/java/com/gomo/app/core/interest/adapter/in/api/response/ReadInterestResponse.java index 59a01cbc..e97dd560 100644 --- a/src/main/java/com/gomo/app/core/interest/presentation/api/response/ReadInterestResponse.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/response/ReadInterestResponse.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.api.response; +package com.gomo.app.core.interest.adapter.in.api.response; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/interest/presentation/api/response/ReadMajorInterestResponse.java b/src/main/java/com/gomo/app/core/interest/adapter/in/api/response/ReadMajorInterestResponse.java similarity index 90% rename from src/main/java/com/gomo/app/core/interest/presentation/api/response/ReadMajorInterestResponse.java rename to src/main/java/com/gomo/app/core/interest/adapter/in/api/response/ReadMajorInterestResponse.java index 0fd7d553..f2daa31a 100644 --- a/src/main/java/com/gomo/app/core/interest/presentation/api/response/ReadMajorInterestResponse.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/response/ReadMajorInterestResponse.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.api.response; +package com.gomo.app.core.interest.adapter.in.api.response; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/interest/presentation/consumer/CompleteQuestEventScoreConsumer.java b/src/main/java/com/gomo/app/core/interest/adapter/in/consumer/CompleteQuestEventScoreConsumer.java similarity index 67% rename from src/main/java/com/gomo/app/core/interest/presentation/consumer/CompleteQuestEventScoreConsumer.java rename to src/main/java/com/gomo/app/core/interest/adapter/in/consumer/CompleteQuestEventScoreConsumer.java index c96457ec..8cd7c5d3 100644 --- a/src/main/java/com/gomo/app/core/interest/presentation/consumer/CompleteQuestEventScoreConsumer.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/in/consumer/CompleteQuestEventScoreConsumer.java @@ -1,11 +1,11 @@ -package com.gomo.app.core.interest.presentation.consumer; +package com.gomo.app.core.interest.adapter.in.consumer; import org.springframework.amqp.rabbit.annotation.RabbitListener; import com.gomo.app.common.arch.EventConsumer; import com.gomo.app.common.util.JsonParser; -import com.gomo.app.core.interest.application.port.AdjustProficiencyPortIn; -import com.gomo.app.core.quest.event.CompleteQuestEvent; +import com.gomo.app.core.interest.application.port.in.ProficiencyPropagator; +import com.gomo.app.core.quest.domain.event.CompleteQuestEvent; import com.gomo.app.support.evententry.application.port.IdempotentEventEntryConsumer; import com.gomo.app.support.evententry.domain.model.EventEntry; @@ -15,12 +15,12 @@ @EventConsumer public class CompleteQuestEventScoreConsumer { - private final AdjustProficiencyPortIn adjustProficiencyPortIn; + private final ProficiencyPropagator proficiencyPropagator; @IdempotentEventEntryConsumer @RabbitListener(queues = "event.quest.assign.complete.score") public void handleEvent(EventEntry eventEntry) { CompleteQuestEvent event = JsonParser.fromJson(eventEntry.getPayload(), CompleteQuestEvent.class); - adjustProficiencyPortIn.adjust(event.getSubjectId(), event.getScoreReward()); + proficiencyPropagator.propagate(event.getSubjectId(), event.getScoreReward()); } } diff --git a/src/main/java/com/gomo/app/core/interest/adapter/out/client/LogoClient.java b/src/main/java/com/gomo/app/core/interest/adapter/out/client/LogoClient.java new file mode 100644 index 00000000..f9c5067a --- /dev/null +++ b/src/main/java/com/gomo/app/core/interest/adapter/out/client/LogoClient.java @@ -0,0 +1,31 @@ +package com.gomo.app.core.interest.adapter.out.client; + +import java.util.Optional; + +import org.springframework.web.multipart.MultipartFile; + +import com.gomo.app.common.arch.Adapter; +import com.gomo.app.core.interest.application.port.out.LogoDeleter; +import com.gomo.app.core.interest.application.port.out.LogoUploader; +import com.gomo.app.support.image.application.port.in.ImageDeleter; +import com.gomo.app.support.image.application.port.in.ImageUploader; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Adapter +class LogoClient implements LogoUploader, LogoDeleter { + + private final ImageUploader imageUploader; + private final ImageDeleter imageDeleter; + + @Override + public Optional upload(MultipartFile logo) { + return imageUploader.upload(logo); + } + + @Override + public void delete(String logoUrl) { + imageDeleter.delete(logoUrl); + } +} diff --git a/src/main/java/com/gomo/app/core/interest/infrastructure/adapter/ReadRegistrantAdapter.java b/src/main/java/com/gomo/app/core/interest/adapter/out/client/RegistrantClient.java similarity index 52% rename from src/main/java/com/gomo/app/core/interest/infrastructure/adapter/ReadRegistrantAdapter.java rename to src/main/java/com/gomo/app/core/interest/adapter/out/client/RegistrantClient.java index d95584e6..a79b247a 100644 --- a/src/main/java/com/gomo/app/core/interest/infrastructure/adapter/ReadRegistrantAdapter.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/out/client/RegistrantClient.java @@ -1,24 +1,24 @@ -package com.gomo.app.core.interest.infrastructure.adapter; +package com.gomo.app.core.interest.adapter.out.client; import java.util.UUID; import com.gomo.app.common.arch.Adapter; -import com.gomo.app.core.interest.application.port.ReadRegistrantPortOut; import com.gomo.app.core.interest.application.port.dto.RegistrantDto; -import com.gomo.app.core.member.application.port.ReadMemberPortIn; +import com.gomo.app.core.interest.application.port.out.RegistrantReader; import com.gomo.app.core.member.application.port.dto.MemberDto; +import com.gomo.app.core.member.application.port.in.MemberReader; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @Adapter -class ReadRegistrantAdapter implements ReadRegistrantPortOut { +class RegistrantClient implements RegistrantReader { - private final ReadMemberPortIn readMemberPortIn; + private final MemberReader memberReader; @Override public RegistrantDto find(UUID registrantId) { - MemberDto memberDto = readMemberPortIn.find(registrantId); + MemberDto memberDto = memberReader.read(registrantId); return RegistrantDto.of(memberDto.id(), memberDto.subscriptionPlan()); } } diff --git a/src/main/java/com/gomo/app/core/interest/infrastructure/repository/LevelThresholdPolicyRepositoryImpl.java b/src/main/java/com/gomo/app/core/interest/adapter/out/persistence/JDBCLevelThresholdPolicyRepository.java similarity index 81% rename from src/main/java/com/gomo/app/core/interest/infrastructure/repository/LevelThresholdPolicyRepositoryImpl.java rename to src/main/java/com/gomo/app/core/interest/adapter/out/persistence/JDBCLevelThresholdPolicyRepository.java index 6c5f19a5..8c9ac206 100644 --- a/src/main/java/com/gomo/app/core/interest/infrastructure/repository/LevelThresholdPolicyRepositoryImpl.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/out/persistence/JDBCLevelThresholdPolicyRepository.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.infrastructure.repository; +package com.gomo.app.core.interest.adapter.out.persistence; import java.util.List; @@ -12,7 +12,7 @@ @RequiredArgsConstructor @Repository -class LevelThresholdPolicyRepositoryImpl implements LevelThresholdPolicyRepository { +class JDBCLevelThresholdPolicyRepository implements LevelThresholdPolicyRepository { private final JdbcTemplate jdbcTemplate; diff --git a/src/main/java/com/gomo/app/core/interest/application/port/in/InterestCreator.java b/src/main/java/com/gomo/app/core/interest/application/port/in/InterestCreator.java new file mode 100644 index 00000000..a2d2511c --- /dev/null +++ b/src/main/java/com/gomo/app/core/interest/application/port/in/InterestCreator.java @@ -0,0 +1,19 @@ +package com.gomo.app.core.interest.application.port.in; + +import java.util.UUID; + +import com.gomo.app.core.interest.application.port.command.CreateInterestCommand; +import com.gomo.app.core.interest.domain.exception.InterestConstraintViolationException; + +public interface InterestCreator { + + /** + * Creates a new interest with the provided details. + * + * @param command A {@link CreateInterestCommand} object containing the necessary information to create a new interest, + * such as registrantId, name, logo file, and color code. + * @return The {@link UUID} of the newly created interest. + * @throws InterestConstraintViolationException if the registrant has reached the maximum number of interests allowed by their subscription plan. + */ + UUID create(CreateInterestCommand command); +} diff --git a/src/main/java/com/gomo/app/core/interest/application/port/in/InterestDeleter.java b/src/main/java/com/gomo/app/core/interest/application/port/in/InterestDeleter.java new file mode 100644 index 00000000..454f807c --- /dev/null +++ b/src/main/java/com/gomo/app/core/interest/application/port/in/InterestDeleter.java @@ -0,0 +1,20 @@ +package com.gomo.app.core.interest.application.port.in; + +import java.util.UUID; + +import com.gomo.app.core.interest.domain.exception.InterestAccessDeniedException; +import com.gomo.app.core.interest.domain.exception.InterestNotFoundException; + +public interface InterestDeleter { + + /** + * Deletes a specific interest and all its associated data. + * This includes the interest's logo, its designation as a major interest, and any relationships it is part of. + * + * @param registrantId The id of the registrant requesting the deletion, used to verify authority. + * @param interestId The id of the interest to be deleted. + * @throws InterestNotFoundException if no interest exists with the provided ID. + * @throws InterestAccessDeniedException if the registrant does not have the authority to delete the specified interest. + */ + void delete(UUID registrantId, UUID interestId); +} diff --git a/src/main/java/com/gomo/app/core/interest/application/port/in/InterestNetworkReader.java b/src/main/java/com/gomo/app/core/interest/application/port/in/InterestNetworkReader.java new file mode 100644 index 00000000..04c8b816 --- /dev/null +++ b/src/main/java/com/gomo/app/core/interest/application/port/in/InterestNetworkReader.java @@ -0,0 +1,18 @@ +package com.gomo.app.core.interest.application.port.in; + +import java.util.UUID; + +import com.gomo.app.core.interest.application.port.dto.InterestNetworkDto; + +public interface InterestNetworkReader { + + /** + * Retrieves the complete network of interests and their relationships for a specific registrant. + * The network consists of all interests (nodes) and the relationships between them (edges). + * + * @param registrantId The id of the registrant whose interest network is to be retrieved. + * @return An {@link InterestNetworkDto} containing a list of all interests and their relationships. + * Returns a DTO with empty lists if the registrant has no interests; this method does not return null. + */ + InterestNetworkDto read(UUID registrantId); +} diff --git a/src/main/java/com/gomo/app/core/interest/application/port/ReadInterestPortIn.java b/src/main/java/com/gomo/app/core/interest/application/port/in/InterestReader.java similarity index 78% rename from src/main/java/com/gomo/app/core/interest/application/port/ReadInterestPortIn.java rename to src/main/java/com/gomo/app/core/interest/application/port/in/InterestReader.java index 3ea553a2..f1f3228a 100644 --- a/src/main/java/com/gomo/app/core/interest/application/port/ReadInterestPortIn.java +++ b/src/main/java/com/gomo/app/core/interest/application/port/in/InterestReader.java @@ -1,13 +1,13 @@ -package com.gomo.app.core.interest.application.port; +package com.gomo.app.core.interest.application.port.in; import java.util.List; import java.util.Set; import java.util.UUID; import com.gomo.app.core.interest.application.port.dto.InterestDto; -import com.gomo.app.core.interest.exception.InterestNotFoundException; +import com.gomo.app.core.interest.domain.exception.InterestNotFoundException; -public interface ReadInterestPortIn { +public interface InterestReader { /** * Retrieves a specific interest in its id. @@ -16,7 +16,7 @@ public interface ReadInterestPortIn { * @return An {@link InterestDto} containing the details of the found interest. * @throws InterestNotFoundException if no interest exists with the provided ID. */ - InterestDto find(UUID interestId); + InterestDto read(UUID interestId); /** * Retrieves a list of all interests associated with a specific registrant. @@ -25,7 +25,7 @@ public interface ReadInterestPortIn { * @return A list of {@link InterestDto} objects. The list will be empty if the * registrant has no associated interests; this method does not return null. */ - List findAll(UUID registrantId); + List readAll(UUID registrantId); /** * Retrieves a list of all interests associated with registrants. @@ -34,5 +34,5 @@ public interface ReadInterestPortIn { * @return A list of {@link InterestDto} objects. The list will be empty if the * registrant has no associated interests; this method does not return null. */ - List findAllByRegistrantIds(Set registrantIds); + List readAllByRegistrantIds(Set registrantIds); } diff --git a/src/main/java/com/gomo/app/core/interest/application/port/in/InterestRelationCreator.java b/src/main/java/com/gomo/app/core/interest/application/port/in/InterestRelationCreator.java new file mode 100644 index 00000000..8cc83b52 --- /dev/null +++ b/src/main/java/com/gomo/app/core/interest/application/port/in/InterestRelationCreator.java @@ -0,0 +1,19 @@ +package com.gomo.app.core.interest.application.port.in; + +import java.util.UUID; + +import com.gomo.app.core.interest.domain.exception.InterestNotFoundException; + +public interface InterestRelationCreator { + + /** + * Creates a parent-child relationship between two interests for a specific registrant. + * + * @param registrantId The id of the registrant who is creating the relationship. + * @param parentInterestId The id of the interest that will be the parent. + * @param childInterestId The id of the interest that will be the child. + * @return The {@link UUID} of the newly created interest relationship. + * @throws InterestNotFoundException if either the parent or child interest does not exist with the provided IDs. + */ + UUID create(UUID registrantId, UUID parentInterestId, UUID childInterestId); +} diff --git a/src/main/java/com/gomo/app/core/interest/application/port/in/InterestRelationDeleter.java b/src/main/java/com/gomo/app/core/interest/application/port/in/InterestRelationDeleter.java new file mode 100644 index 00000000..c8c06947 --- /dev/null +++ b/src/main/java/com/gomo/app/core/interest/application/port/in/InterestRelationDeleter.java @@ -0,0 +1,21 @@ +package com.gomo.app.core.interest.application.port.in; + +import java.util.UUID; + +import com.gomo.app.core.interest.domain.exception.InterestNotFoundException; +import com.gomo.app.core.interest.domain.exception.InterestRelationAccessDeniedException; +import com.gomo.app.core.interest.domain.exception.InterestRelationNotFoundException; + +public interface InterestRelationDeleter { + + /** + * Deletes a specific interest relationship. + * + * @param registrantId The id of the registrant requesting the deletion. This is used to verify authority. + * @param interestRelationId The id of the interest relationship to be deleted. + * @throws InterestRelationNotFoundException if no interest relationship exists with the provided ID. + * @throws InterestRelationAccessDeniedException if the registrant does not have the authority to delete the specified relationship. + * @throws InterestNotFoundException if either the parent or child interest does not exist with the provided IDs. + */ + void delete(UUID registrantId, UUID interestRelationId); +} diff --git a/src/main/java/com/gomo/app/core/interest/application/port/in/InterestUpdater.java b/src/main/java/com/gomo/app/core/interest/application/port/in/InterestUpdater.java new file mode 100644 index 00000000..5840af8b --- /dev/null +++ b/src/main/java/com/gomo/app/core/interest/application/port/in/InterestUpdater.java @@ -0,0 +1,18 @@ +package com.gomo.app.core.interest.application.port.in; + +import com.gomo.app.core.interest.application.port.command.UpdateInterestCommand; +import com.gomo.app.core.interest.domain.exception.InterestAccessDeniedException; +import com.gomo.app.core.interest.domain.exception.InterestNotFoundException; + +public interface InterestUpdater { + + /** + * Updates the properties of an existing interest, such as its name and color code. + * + * @param command A {@link UpdateInterestCommand} containing the details for the update, + * including the interest ID, the registrant ID for validation, and the new values. + * @throws InterestNotFoundException if no interest exists with the ID provided in the command. + * @throws InterestAccessDeniedException if the registrant does not have the authority to modify the specified interest. + */ + void update(UpdateInterestCommand command); +} diff --git a/src/main/java/com/gomo/app/core/interest/application/port/in/LogoUpdater.java b/src/main/java/com/gomo/app/core/interest/application/port/in/LogoUpdater.java new file mode 100644 index 00000000..1f7a6520 --- /dev/null +++ b/src/main/java/com/gomo/app/core/interest/application/port/in/LogoUpdater.java @@ -0,0 +1,20 @@ +package com.gomo.app.core.interest.application.port.in; + +import java.util.UUID; + +import org.springframework.web.multipart.MultipartFile; + +import com.gomo.app.core.interest.domain.exception.InterestNotFoundException; + +public interface LogoUpdater { + + /** + * Updates the logo for a specific interest. + * If a previous custom logo exists, it will be deleted and replaced by the new one. + * + * @param interestId The id of the interest to be updated. + * @param updatedLogo The new logo image file. + * @throws InterestNotFoundException if no interest exists with the provided ID. + */ + void update(UUID interestId, MultipartFile updatedLogo); +} diff --git a/src/main/java/com/gomo/app/core/interest/application/port/in/MajorInterestCreator.java b/src/main/java/com/gomo/app/core/interest/application/port/in/MajorInterestCreator.java new file mode 100644 index 00000000..6b2804a9 --- /dev/null +++ b/src/main/java/com/gomo/app/core/interest/application/port/in/MajorInterestCreator.java @@ -0,0 +1,22 @@ +package com.gomo.app.core.interest.application.port.in; + +import java.util.UUID; + +import com.gomo.app.core.interest.domain.exception.InterestAccessDeniedException; +import com.gomo.app.core.interest.domain.exception.InterestNotFoundException; +import com.gomo.app.core.interest.domain.exception.MajorInterestDuplicatedException; + +public interface MajorInterestCreator { + + /** + * Designates a specific interest as a major interest for the registrant. + * + * @param registrantId The id of the registrant who owns the interest. + * @param interestId The id of the interest to be designated as a major interest. + * @return The {@link UUID} of the newly created major interest mapping. + * @throws InterestNotFoundException if no interest exists with the provided ID. + * @throws InterestAccessDeniedException if the registrant does not have the authority to modify the specified interest. + * @throws MajorInterestDuplicatedException if the interest is already designated as a major interest. + */ + UUID create(UUID registrantId, UUID interestId); +} diff --git a/src/main/java/com/gomo/app/core/interest/application/port/in/MajorInterestDeleter.java b/src/main/java/com/gomo/app/core/interest/application/port/in/MajorInterestDeleter.java new file mode 100644 index 00000000..5ae4dada --- /dev/null +++ b/src/main/java/com/gomo/app/core/interest/application/port/in/MajorInterestDeleter.java @@ -0,0 +1,19 @@ +package com.gomo.app.core.interest.application.port.in; + +import java.util.UUID; + +import com.gomo.app.core.interest.domain.exception.MajorInterestAccessDeniedException; +import com.gomo.app.core.interest.domain.exception.MajorInterestNotFoundException; + +public interface MajorInterestDeleter { + + /** + * Deletes the designation of an interest as a major interest. + * + * @param registrantId The id of the registrant requesting the deletion, used for authority validation. + * @param majorInterestId The id of the major interest mapping to be deleted. + * @throws MajorInterestNotFoundException if no major interest mapping exists with the provided ID. + * @throws MajorInterestAccessDeniedException if the registrant does not have the authority to delete the specified major interest. + */ + void delete(UUID registrantId, UUID majorInterestId); +} diff --git a/src/main/java/com/gomo/app/core/interest/application/port/in/MajorInterestOrderUpdater.java b/src/main/java/com/gomo/app/core/interest/application/port/in/MajorInterestOrderUpdater.java new file mode 100644 index 00000000..615fc485 --- /dev/null +++ b/src/main/java/com/gomo/app/core/interest/application/port/in/MajorInterestOrderUpdater.java @@ -0,0 +1,14 @@ +package com.gomo.app.core.interest.application.port.in; + +import com.gomo.app.core.interest.application.port.command.OrderUpdateMajorInterestCommand; + +public interface MajorInterestOrderUpdater { + + /** + * Updates the display order of major interests for a specific registrant. + * + * @param command A {@link OrderUpdateMajorInterestCommand} containing the registrant's ID and + * a collection of major interest IDs with their new display orders. + */ + void update(OrderUpdateMajorInterestCommand command); +} diff --git a/src/main/java/com/gomo/app/core/interest/application/port/in/MajorInterestReader.java b/src/main/java/com/gomo/app/core/interest/application/port/in/MajorInterestReader.java new file mode 100644 index 00000000..963eba9b --- /dev/null +++ b/src/main/java/com/gomo/app/core/interest/application/port/in/MajorInterestReader.java @@ -0,0 +1,18 @@ +package com.gomo.app.core.interest.application.port.in; + +import java.util.List; +import java.util.UUID; + +import com.gomo.app.core.interest.application.port.dto.MajorInterestDto; + +public interface MajorInterestReader { + + /** + * Retrieves a list of all major interests for a specific registrant, sorted by their display order. + * + * @param registrantId The id of the registrant whose major interests are to be retrieved. + * @return A list of {@link MajorInterestDto} objects, sorted by display order. + * The list will be empty if the registrant has no major interests; this method does not return null. + */ + List readAll(UUID registrantId); +} diff --git a/src/main/java/com/gomo/app/core/interest/application/port/AdjustProficiencyPortIn.java b/src/main/java/com/gomo/app/core/interest/application/port/in/ProficiencyPropagator.java similarity index 52% rename from src/main/java/com/gomo/app/core/interest/application/port/AdjustProficiencyPortIn.java rename to src/main/java/com/gomo/app/core/interest/application/port/in/ProficiencyPropagator.java index 29a6efe0..7a810561 100644 --- a/src/main/java/com/gomo/app/core/interest/application/port/AdjustProficiencyPortIn.java +++ b/src/main/java/com/gomo/app/core/interest/application/port/in/ProficiencyPropagator.java @@ -1,15 +1,15 @@ -package com.gomo.app.core.interest.application.port; +package com.gomo.app.core.interest.application.port.in; import java.util.UUID; -public interface AdjustProficiencyPortIn { +public interface ProficiencyPropagator { /** - * Adjusts the proficiency score of a specific interest in a given amount. + * Propagates changes of the proficiency score of a specific interest in a given amount. * * @param interestId The id of the interest to be adjusted. * @param deltaScore The change in score to be applied. * This value can be positive to increase proficiency or negative to decrease it. */ - void adjust(UUID interestId, int deltaScore); + void propagate(UUID interestId, int deltaScore); } diff --git a/src/main/java/com/gomo/app/core/interest/application/port/out/LogoDeleter.java b/src/main/java/com/gomo/app/core/interest/application/port/out/LogoDeleter.java new file mode 100644 index 00000000..0f2c1095 --- /dev/null +++ b/src/main/java/com/gomo/app/core/interest/application/port/out/LogoDeleter.java @@ -0,0 +1,6 @@ +package com.gomo.app.core.interest.application.port.out; + +public interface LogoDeleter { + + void delete(String logoUrl); +} diff --git a/src/main/java/com/gomo/app/core/interest/application/port/out/LogoUploader.java b/src/main/java/com/gomo/app/core/interest/application/port/out/LogoUploader.java new file mode 100644 index 00000000..612d592e --- /dev/null +++ b/src/main/java/com/gomo/app/core/interest/application/port/out/LogoUploader.java @@ -0,0 +1,10 @@ +package com.gomo.app.core.interest.application.port.out; + +import java.util.Optional; + +import org.springframework.web.multipart.MultipartFile; + +public interface LogoUploader { + + Optional upload(MultipartFile logo); +} diff --git a/src/main/java/com/gomo/app/core/interest/application/port/ReadRegistrantPortOut.java b/src/main/java/com/gomo/app/core/interest/application/port/out/RegistrantReader.java similarity index 78% rename from src/main/java/com/gomo/app/core/interest/application/port/ReadRegistrantPortOut.java rename to src/main/java/com/gomo/app/core/interest/application/port/out/RegistrantReader.java index eb510039..d0855f8f 100644 --- a/src/main/java/com/gomo/app/core/interest/application/port/ReadRegistrantPortOut.java +++ b/src/main/java/com/gomo/app/core/interest/application/port/out/RegistrantReader.java @@ -1,10 +1,10 @@ -package com.gomo.app.core.interest.application.port; +package com.gomo.app.core.interest.application.port.out; import java.util.UUID; import com.gomo.app.core.interest.application.port.dto.RegistrantDto; -public interface ReadRegistrantPortOut { +public interface RegistrantReader { /** * Retrieves the essential details of a single registrant by id. diff --git a/src/main/java/com/gomo/app/core/interest/application/usecase/CreateInterestUseCase.java b/src/main/java/com/gomo/app/core/interest/application/service/InterestCreateService.java similarity index 69% rename from src/main/java/com/gomo/app/core/interest/application/usecase/CreateInterestUseCase.java rename to src/main/java/com/gomo/app/core/interest/application/service/InterestCreateService.java index bf99a82c..9a37e5ce 100644 --- a/src/main/java/com/gomo/app/core/interest/application/usecase/CreateInterestUseCase.java +++ b/src/main/java/com/gomo/app/core/interest/application/service/InterestCreateService.java @@ -1,37 +1,38 @@ -package com.gomo.app.core.interest.application.usecase; +package com.gomo.app.core.interest.application.service; import java.util.UUID; import org.springframework.transaction.annotation.Transactional; import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.logging.AuditLog; import com.gomo.app.common.util.UUIDGenerator; -import com.gomo.app.core.interest.application.port.ReadRegistrantPortOut; import com.gomo.app.core.interest.application.port.command.CreateInterestCommand; import com.gomo.app.core.interest.application.port.dto.RegistrantDto; +import com.gomo.app.core.interest.application.port.in.InterestCreator; +import com.gomo.app.core.interest.application.port.out.LogoUploader; +import com.gomo.app.core.interest.application.port.out.RegistrantReader; import com.gomo.app.core.interest.domain.model.Interest; import com.gomo.app.core.interest.domain.model.InterestName; import com.gomo.app.core.interest.domain.model.Logo; import com.gomo.app.core.interest.domain.model.Registrant; import com.gomo.app.core.interest.domain.repository.InterestRepository; -import com.gomo.app.support.image.application.port.UploadImagePortIn; -import com.gomo.app.support.logging.AuditLog; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @Transactional @ApplicationService -public class CreateInterestUseCase { +class InterestCreateService implements InterestCreator { - private final ReadRegistrantPortOut readRegistrantPortOut; - private final UploadImagePortIn uploadImagePortIn; + private final RegistrantReader registrantReader; + private final LogoUploader logoUploader; private final InterestRepository interestRepository; @AuditLog(action = "CREATE_INTEREST") public UUID create(CreateInterestCommand command) { ensureNotExceedInterestQuota(command.registrantId()); - String logoUrl = uploadImagePortIn.upload(command.logoFile()).orElse(null); + String logoUrl = logoUploader.upload(command.logoFile()).orElse(null); Interest interest = Interest.of( UUIDGenerator.generate(), command.registrantId(), @@ -44,7 +45,7 @@ public UUID create(CreateInterestCommand command) { } private void ensureNotExceedInterestQuota(UUID registrantId) { - RegistrantDto dto = readRegistrantPortOut.find(registrantId); + RegistrantDto dto = registrantReader.find(registrantId); Registrant registrant = Registrant.of(dto.id(), dto.subscriptionPlan()); long interestCount = interestRepository.countAllByRegistrantId(registrant.getId()); registrant.validateInterestQuota(interestCount); diff --git a/src/main/java/com/gomo/app/core/interest/application/service/InterestDeleteService.java b/src/main/java/com/gomo/app/core/interest/application/service/InterestDeleteService.java new file mode 100644 index 00000000..40d492ca --- /dev/null +++ b/src/main/java/com/gomo/app/core/interest/application/service/InterestDeleteService.java @@ -0,0 +1,59 @@ +package com.gomo.app.core.interest.application.service; + +import java.util.List; +import java.util.UUID; + +import org.springframework.transaction.annotation.Transactional; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.core.interest.application.port.in.InterestDeleter; +import com.gomo.app.core.interest.application.port.out.LogoDeleter; +import com.gomo.app.core.interest.domain.model.Interest; +import com.gomo.app.core.interest.domain.model.InterestRelation; +import com.gomo.app.core.interest.domain.repository.InterestRepository; +import com.gomo.app.core.interest.domain.repository.MajorInterestRepository; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Transactional +@ApplicationService +class InterestDeleteService implements InterestDeleter { + + private final LogoDeleter logoDeleter; + private final MajorInterestRepository majorInterestRepository; + private final InterestRelationService interestRelationService; + private final InterestService interestService; + private final InterestRepository interestRepository; + + @AuditLog(action = "DELETE_INTEREST") + public void delete(UUID registrantId, UUID interestId) { + Interest interest = interestService.readById(interestId); + interest.validateAuthority(registrantId); + + deleteLogoUrl(interest); + deleteMajorInterest(interestId); + deleteInterestRelations(registrantId, interestId); + interestRepository.delete(interest); + } + + private void deleteLogoUrl(Interest interest) { + if (!interest.hasDefaultLogo()) { + logoDeleter.delete(interest.getLogo().getUrl()); + } + } + + private void deleteMajorInterest(UUID interestId) { + majorInterestRepository.deleteByInterestId(interestId); + } + + private void deleteInterestRelations(UUID registrantId, UUID interestId) { + List interestRelations = interestRelationService.readAllByInterestId(interestId); + if (!interestRelations.isEmpty()) { + for (InterestRelation relation : interestRelations) { + interestRelationService.delete(registrantId, relation.getId()); + } + } + } +} diff --git a/src/main/java/com/gomo/app/core/interest/application/service/InterestNetworkService.java b/src/main/java/com/gomo/app/core/interest/application/service/InterestNetworkService.java new file mode 100644 index 00000000..1f7bb6b3 --- /dev/null +++ b/src/main/java/com/gomo/app/core/interest/application/service/InterestNetworkService.java @@ -0,0 +1,28 @@ +package com.gomo.app.core.interest.application.service; + +import java.util.List; +import java.util.UUID; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.core.interest.application.port.dto.InterestDto; +import com.gomo.app.core.interest.application.port.dto.InterestNetworkDto; +import com.gomo.app.core.interest.application.port.dto.InterestRelationDto; +import com.gomo.app.core.interest.application.port.in.InterestNetworkReader; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@ApplicationService +class InterestNetworkService implements InterestNetworkReader { + + private final InterestService interestService; + private final InterestRelationService interestRelationService; + + public InterestNetworkDto read(UUID registrantId) { + List interestDtos = interestService.readAll(registrantId); + List relationDtos = interestRelationService.readAllByRegistrantId(registrantId).stream() + .map(InterestRelationDto::from) + .toList(); + return InterestNetworkDto.of(interestDtos, relationDtos); + } +} diff --git a/src/main/java/com/gomo/app/core/interest/application/service/InterestRelationService.java b/src/main/java/com/gomo/app/core/interest/application/service/InterestRelationService.java new file mode 100644 index 00000000..25cac4f4 --- /dev/null +++ b/src/main/java/com/gomo/app/core/interest/application/service/InterestRelationService.java @@ -0,0 +1,82 @@ +package com.gomo.app.core.interest.application.service; + +import java.util.List; +import java.util.UUID; + +import org.springframework.transaction.annotation.Transactional; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.common.util.UUIDGenerator; +import com.gomo.app.core.interest.application.port.in.InterestRelationCreator; +import com.gomo.app.core.interest.application.port.in.InterestRelationDeleter; +import com.gomo.app.core.interest.domain.exception.InterestRelationDuplicatedException; +import com.gomo.app.core.interest.domain.exception.InterestRelationNotFoundException; +import com.gomo.app.core.interest.domain.exception.code.InterestRelationErrorCode; +import com.gomo.app.core.interest.domain.model.Interest; +import com.gomo.app.core.interest.domain.model.InterestRelation; +import com.gomo.app.core.interest.domain.repository.InterestRelationRepository; +import com.gomo.app.core.interest.domain.service.InterestNetworkBuilder; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Transactional +@ApplicationService +class InterestRelationService implements InterestRelationCreator, InterestRelationDeleter { + + private final InterestService interestService; + private final ProficiencyService proficiencyService; + private final InterestRelationRepository interestRelationRepository; + private final InterestNetworkBuilder interestNetworkBuilder; + + @AuditLog(action = "CREATE_INTEREST_RELATION") + public UUID create(UUID registrantId, UUID parentInterestId, UUID childInterestId) { + ensureNotDuplicated(parentInterestId, childInterestId); + InterestRelation interestRelation = InterestRelation.of( + UUIDGenerator.generate(), + registrantId, + parentInterestId, + childInterestId + ); + + List relations = interestRelationRepository.findAllByRegistrantId(registrantId); + relations.add(interestRelation); + interestNetworkBuilder.validateAcyclic(relations, parentInterestId); + + Interest childInterest = interestService.readById(childInterestId); + int deltaScore = childInterest.getProficiency().getTotalScore(); + proficiencyService.propagate(parentInterestId, deltaScore); + return interestRelationRepository.save(interestRelation).getId(); + } + + InterestRelation readById(UUID interestRelationId) { + return interestRelationRepository.findById(interestRelationId) + .orElseThrow(() -> new InterestRelationNotFoundException(InterestRelationErrorCode.NOT_FOUND)); + } + + List readAllByInterestId(UUID interestId) { + return interestRelationRepository.findAllByInterestId(interestId); + } + + List readAllByRegistrantId(UUID registrantId) { + return interestRelationRepository.findAllByRegistrantId(registrantId); + } + + @AuditLog(action = "DELETE_INTEREST_RELATION") + public void delete(UUID registrantId, UUID interestRelationId) { + InterestRelation interestRelation = readById(interestRelationId); + interestRelation.validateAuthority(registrantId); + + Interest childInterest = interestService.readById(interestRelation.getChildInterestId()); + int deltaScore = -1 * childInterest.getProficiency().getTotalScore(); + proficiencyService.propagate(interestRelation.getParentInterestId(), deltaScore); + interestRelationRepository.delete(interestRelation); + } + + private void ensureNotDuplicated(UUID parentInterestId, UUID childInterestId) { + if (interestRelationRepository.existsRelationFor(parentInterestId, childInterestId)) { + throw new InterestRelationDuplicatedException(InterestRelationErrorCode.DUPLICATED); + } + } +} diff --git a/src/main/java/com/gomo/app/core/interest/application/usecase/ReadInterestUseCase.java b/src/main/java/com/gomo/app/core/interest/application/service/InterestService.java similarity index 56% rename from src/main/java/com/gomo/app/core/interest/application/usecase/ReadInterestUseCase.java rename to src/main/java/com/gomo/app/core/interest/application/service/InterestService.java index a4e13cfb..f7d24b64 100644 --- a/src/main/java/com/gomo/app/core/interest/application/usecase/ReadInterestUseCase.java +++ b/src/main/java/com/gomo/app/core/interest/application/service/InterestService.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.application.usecase; +package com.gomo.app.core.interest.application.service; import java.util.List; import java.util.Map; @@ -6,29 +6,37 @@ import java.util.UUID; import java.util.stream.Collectors; +import org.springframework.transaction.annotation.Transactional; + import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.interest.application.port.ReadInterestPortIn; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.core.interest.application.port.command.UpdateInterestCommand; import com.gomo.app.core.interest.application.port.dto.InterestDto; +import com.gomo.app.core.interest.application.port.in.InterestReader; +import com.gomo.app.core.interest.application.port.in.InterestUpdater; +import com.gomo.app.core.interest.domain.exception.InterestNotFoundException; +import com.gomo.app.core.interest.domain.exception.code.InterestErrorCode; import com.gomo.app.core.interest.domain.model.Interest; +import com.gomo.app.core.interest.domain.model.InterestName; import com.gomo.app.core.interest.domain.model.MajorInterest; import com.gomo.app.core.interest.domain.repository.InterestRepository; import com.gomo.app.core.interest.domain.repository.MajorInterestRepository; -import com.gomo.app.core.interest.domain.service.InterestService; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor +@Transactional @ApplicationService -class ReadInterestUseCase implements ReadInterestPortIn { +class InterestService implements InterestReader, InterestUpdater { - private final InterestService interestService; private final InterestRepository interestRepository; private final MajorInterestRepository majorInterestRepository; - // TODO [2025-10-18] jhl221123 : InterestDto 에서 majorInterestId를 제거하고, 두 가지 타입의 DTO를 필요에 따라 제공해야합니다. + // TODO [2025-10-18] jhl221123 : InterestDto 에서 majorInterestId를 제거하고, InterestDetailDto를 추가해야합니다. @Override - public InterestDto find(UUID interestId) { - Interest interest = interestService.find(interestId); + @Transactional(readOnly = true) + public InterestDto read(UUID interestId) { + Interest interest = readById(interestId); UUID majorInterestId = majorInterestRepository.findByInterestId(interestId) .map(MajorInterest::getId) .orElse(null); @@ -36,7 +44,8 @@ public InterestDto find(UUID interestId) { } @Override - public List findAll(UUID registrantId) { + @Transactional(readOnly = true) + public List readAll(UUID registrantId) { List interests = interestRepository.findAllByRegistrantId(registrantId); List interestIds = interests.stream().map(Interest::getId).toList(); Map majorIdsByInterestId = majorInterestRepository.findAllByRegistrantIdAndInterestIdIn(registrantId, interestIds).stream() @@ -49,7 +58,8 @@ public List findAll(UUID registrantId) { } @Override - public List findAllByRegistrantIds(Set registrantIds) { + @Transactional(readOnly = true) + public List readAllByRegistrantIds(Set registrantIds) { List interests = interestRepository.findAllByRegistrantIdIn(registrantIds); List interestIds = interests.stream().map(Interest::getId).toList(); Map majorIdsByInterestId = majorInterestRepository.findByInterestIdIn(interestIds).stream() @@ -60,4 +70,17 @@ public List findAllByRegistrantIds(Set registrantIds) { return InterestDto.of(interest, majorInterestId); }).toList(); } + + Interest readById(UUID interestId) { + return interestRepository.findById(interestId) + .orElseThrow(() -> new InterestNotFoundException(InterestErrorCode.NOT_FOUND)); + } + + @AuditLog(action = "UPDATE_INTEREST") + public void update(UpdateInterestCommand command) { + Interest interest = readById(command.interestId()); + interest.validateAuthority(command.registrantId()); + interest.updateName(InterestName.of(command.name())); + interest.updateColorCode(command.colorCode()); + } } diff --git a/src/main/java/com/gomo/app/core/interest/application/usecase/UpdateLogoUseCase.java b/src/main/java/com/gomo/app/core/interest/application/service/LogoService.java similarity index 52% rename from src/main/java/com/gomo/app/core/interest/application/usecase/UpdateLogoUseCase.java rename to src/main/java/com/gomo/app/core/interest/application/service/LogoService.java index 8f9bb041..63457d0a 100644 --- a/src/main/java/com/gomo/app/core/interest/application/usecase/UpdateLogoUseCase.java +++ b/src/main/java/com/gomo/app/core/interest/application/service/LogoService.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.application.usecase; +package com.gomo.app.core.interest.application.service; import java.util.UUID; @@ -6,35 +6,35 @@ import org.springframework.web.multipart.MultipartFile; import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.core.interest.application.port.in.LogoUpdater; +import com.gomo.app.core.interest.application.port.out.LogoDeleter; +import com.gomo.app.core.interest.application.port.out.LogoUploader; import com.gomo.app.core.interest.domain.model.Interest; import com.gomo.app.core.interest.domain.model.Logo; -import com.gomo.app.core.interest.domain.service.InterestService; -import com.gomo.app.support.image.application.port.DeleteImagePortIn; -import com.gomo.app.support.image.application.port.UploadImagePortIn; -import com.gomo.app.support.logging.AuditLog; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @Transactional @ApplicationService -public class UpdateLogoUseCase { +class LogoService implements LogoUpdater { - private final UploadImagePortIn uploadImagePortIn; - private final DeleteImagePortIn deleteImagePortIn; + private final LogoUploader logoUploader; + private final LogoDeleter logoDeleter; private final InterestService interestService; @AuditLog(action = "UPDATE_INTEREST_LOGO") public void update(UUID interestId, MultipartFile updatedLogo) { - Interest interest = interestService.find(interestId); - String logoUrl = uploadImagePortIn.upload(updatedLogo).orElse(null); + Interest interest = interestService.readById(interestId); + String logoUrl = logoUploader.upload(updatedLogo).orElse(null); deletePreviousLogo(interest); interest.updateLogo(Logo.of(logoUrl)); } private void deletePreviousLogo(Interest interest) { if (!interest.hasDefaultLogo()) { - deleteImagePortIn.delete(interest.getLogo().getUrl()); + logoDeleter.delete(interest.getLogo().getUrl()); } } } diff --git a/src/main/java/com/gomo/app/core/interest/application/service/MajorInterestService.java b/src/main/java/com/gomo/app/core/interest/application/service/MajorInterestService.java new file mode 100644 index 00000000..b1d8c857 --- /dev/null +++ b/src/main/java/com/gomo/app/core/interest/application/service/MajorInterestService.java @@ -0,0 +1,95 @@ +package com.gomo.app.core.interest.application.service; + +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.springframework.transaction.annotation.Transactional; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.displayorder.OrderChangeable; +import com.gomo.app.common.displayorder.OrderChanger; +import com.gomo.app.common.displayorder.OrderUpdateOrderChangeableCommand; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.common.util.UUIDGenerator; +import com.gomo.app.core.interest.application.port.command.OrderUpdateMajorInterestCommand; +import com.gomo.app.core.interest.application.port.dto.MajorInterestDto; +import com.gomo.app.core.interest.application.port.in.MajorInterestCreator; +import com.gomo.app.core.interest.application.port.in.MajorInterestDeleter; +import com.gomo.app.core.interest.application.port.in.MajorInterestOrderUpdater; +import com.gomo.app.core.interest.application.port.in.MajorInterestReader; +import com.gomo.app.core.interest.domain.exception.MajorInterestDuplicatedException; +import com.gomo.app.core.interest.domain.exception.MajorInterestNotFoundException; +import com.gomo.app.core.interest.domain.exception.code.MajorInterestErrorCode; +import com.gomo.app.core.interest.domain.model.Interest; +import com.gomo.app.core.interest.domain.model.MajorInterest; +import com.gomo.app.core.interest.domain.repository.InterestRepository; +import com.gomo.app.core.interest.domain.repository.MajorInterestRepository; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Transactional +@ApplicationService +class MajorInterestService implements MajorInterestCreator, MajorInterestReader, MajorInterestOrderUpdater, MajorInterestDeleter { + + private final InterestService interestService; + private final MajorInterestRepository majorInterestRepository; + private final InterestRepository interestRepository; + + @Override + @AuditLog(action = "CREATE_MAJOR_INTEREST") + public UUID create(UUID registrantId, UUID interestId) { + Interest interest = interestService.readById(interestId); + interest.validateAuthority(registrantId); + ensureNotDuplicated(interest); + int highestOrder = majorInterestRepository.findMaxDisplayOrder(interest.getRegistrantId()); + MajorInterest next = MajorInterest.createNext(UUIDGenerator.generate(), interest.getRegistrantId(), interest.getId(), highestOrder); + MajorInterest saved = majorInterestRepository.save(next); + return saved.getId(); + } + + private void ensureNotDuplicated(Interest interest) { + majorInterestRepository.findByInterestId(interest.getId()) + .ifPresent(exists -> { + throw new MajorInterestDuplicatedException(MajorInterestErrorCode.DUPLICATED); + }); + } + + @Override + @Transactional(readOnly = true) + public List readAll(UUID registrantId) { + List majorInterests = majorInterestRepository.findAllByRegistrantIdOrderByDisplayOrder(registrantId); + Map majorInterestByInterestId = majorInterests.stream() + .collect((Collectors.toMap(MajorInterest::getInterestId, Function.identity()))); + + List interests = interestRepository.findAllById(majorInterestByInterestId.keySet()); + return interests.stream() + .map(interest -> MajorInterestDto.from(majorInterestByInterestId.get(interest.getId()), interest)) + .toList(); + } + + MajorInterest readById(UUID majorInterestId) { + return majorInterestRepository.findById(majorInterestId) + .orElseThrow(() -> new MajorInterestNotFoundException(MajorInterestErrorCode.NOT_FOUND)); + } + + @AuditLog(action = "UPDATE_MAJOR_INTEREST_ORDER") + public void update(OrderUpdateMajorInterestCommand command) { + Map majorInterestMap = majorInterestRepository.findAllByRegistrantIdOrderByDisplayOrder(command.registrantId()).stream() + .collect(Collectors.toMap( + majorInterest -> majorInterest.getId(), + majorInterest -> majorInterest + )); + OrderChanger.change(OrderUpdateOrderChangeableCommand.of(majorInterestMap, command.updatedOrders())); + } + + @AuditLog(action = "DELETE_MAJOR_INTEREST") + public void delete(UUID registrantId, UUID majorInterestId) { + MajorInterest majorInterest = readById(majorInterestId); + majorInterest.validateAuthority(registrantId); + majorInterestRepository.delete(majorInterest); + } +} diff --git a/src/main/java/com/gomo/app/core/interest/application/service/ProficiencyService.java b/src/main/java/com/gomo/app/core/interest/application/service/ProficiencyService.java new file mode 100644 index 00000000..7eb03fdb --- /dev/null +++ b/src/main/java/com/gomo/app/core/interest/application/service/ProficiencyService.java @@ -0,0 +1,66 @@ +package com.gomo.app.core.interest.application.service; + +import java.util.ArrayDeque; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import org.springframework.transaction.annotation.Transactional; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.core.interest.application.port.in.ProficiencyPropagator; +import com.gomo.app.core.interest.domain.model.Interest; +import com.gomo.app.core.interest.domain.model.InterestRelation; +import com.gomo.app.core.interest.domain.repository.InterestRelationRepository; +import com.gomo.app.core.interest.domain.service.InterestNetworkBuilder; +import com.gomo.app.core.interest.domain.service.ProficiencyCalculator; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Transactional +@ApplicationService +class ProficiencyService implements ProficiencyPropagator { + + private final InterestService interestService; + private final InterestRelationRepository interestRelationRepository; + private final InterestNetworkBuilder interestNetworkBuilder; + private final ProficiencyCalculator proficiencyCalculator; + + @Override + public void propagate(UUID interestId, int deltaScore) { + Interest interest = interestService.readById(interestId); + List relations = interestRelationRepository.findAllByRegistrantId(interest.registrantId()); + Map> parentInterestByChildId = interestNetworkBuilder.buildParentInterestByChildId(relations); + Set adjustSuccessIds = new HashSet<>(); + ArrayDeque candidateInterests = new ArrayDeque<>(); + candidateInterests.addLast(interest); + while (!candidateInterests.isEmpty()) { + Interest current = candidateInterests.removeFirst(); + if (adjustSuccessIds.contains(current.getId())) { + continue; + } + adjustProficiency(current, deltaScore, adjustSuccessIds); + Set parents = parentInterestByChildId.get(current.getId()); + enqueueParents(parents, candidateInterests, adjustSuccessIds); + } + } + + private void adjustProficiency(Interest interest, int deltaTotalScore, Set adjustSuccessIds) { + interest.adjustProficiency(deltaTotalScore, proficiencyCalculator); + adjustSuccessIds.add(interest.getId()); + } + + private void enqueueParents(Set parents, ArrayDeque queue, Set adjustSuccessIds) { + if (parents == null || parents.isEmpty()) { + return; + } + for (Interest parent : parents) { + if (!adjustSuccessIds.contains(parent.getId())) { + queue.addLast(parent); + } + } + } +} diff --git a/src/main/java/com/gomo/app/core/interest/application/usecase/AdjustProficiencyUseCase.java b/src/main/java/com/gomo/app/core/interest/application/usecase/AdjustProficiencyUseCase.java deleted file mode 100644 index 3b9e274e..00000000 --- a/src/main/java/com/gomo/app/core/interest/application/usecase/AdjustProficiencyUseCase.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.gomo.app.core.interest.application.usecase; - -import java.util.UUID; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.interest.application.port.AdjustProficiencyPortIn; -import com.gomo.app.core.interest.domain.model.Interest; -import com.gomo.app.core.interest.domain.service.InterestService; -import com.gomo.app.core.interest.domain.service.ProficiencyService; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -class AdjustProficiencyUseCase implements AdjustProficiencyPortIn { - - private final InterestService interestService; - private final ProficiencyService proficiencyService; - - @Override - public void adjust(UUID interestId, int deltaScore) { - Interest interest = interestService.find(interestId); - proficiencyService.adjust(interest, deltaScore); - } -} diff --git a/src/main/java/com/gomo/app/core/interest/application/usecase/CreateInterestRelationUseCase.java b/src/main/java/com/gomo/app/core/interest/application/usecase/CreateInterestRelationUseCase.java deleted file mode 100644 index c4e9c21a..00000000 --- a/src/main/java/com/gomo/app/core/interest/application/usecase/CreateInterestRelationUseCase.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.gomo.app.core.interest.application.usecase; - -import java.util.UUID; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.interest.domain.model.Interest; -import com.gomo.app.core.interest.domain.model.InterestRelation; -import com.gomo.app.core.interest.domain.service.InterestRelationService; -import com.gomo.app.core.interest.domain.service.InterestService; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -public class CreateInterestRelationUseCase { - - private final InterestService interestService; - private final InterestRelationService interestRelationService; - - @AuditLog(action = "CREATE_INTEREST_RELATION") - public UUID create(UUID registrantId, UUID parentInterestId, UUID childInterestId) { - Interest parentInterest = interestService.find(parentInterestId); - Interest childInterest = interestService.find(childInterestId); - InterestRelation interestRelation = interestRelationService.create(registrantId, parentInterest, childInterest); - return interestRelation.getId(); - } -} diff --git a/src/main/java/com/gomo/app/core/interest/application/usecase/CreateMajorInterestUseCase.java b/src/main/java/com/gomo/app/core/interest/application/usecase/CreateMajorInterestUseCase.java deleted file mode 100644 index 0256478d..00000000 --- a/src/main/java/com/gomo/app/core/interest/application/usecase/CreateMajorInterestUseCase.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.gomo.app.core.interest.application.usecase; - -import java.util.UUID; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.interest.domain.model.Interest; -import com.gomo.app.core.interest.domain.model.MajorInterest; -import com.gomo.app.core.interest.domain.service.InterestService; -import com.gomo.app.core.interest.domain.service.MajorInterestService; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -public class CreateMajorInterestUseCase { - - private final InterestService interestService; - private final MajorInterestService majorInterestService; - - @AuditLog(action = "CREATE_MAJOR_INTEREST") - public UUID create(UUID registrantId, UUID interestId) { - Interest interest = interestService.find(interestId); - interest.validateAuthority(registrantId); - MajorInterest majorInterest = majorInterestService.create(interest); - return majorInterest.getId(); - } -} diff --git a/src/main/java/com/gomo/app/core/interest/application/usecase/DeleteInterestRelationUseCase.java b/src/main/java/com/gomo/app/core/interest/application/usecase/DeleteInterestRelationUseCase.java deleted file mode 100644 index 80887cf0..00000000 --- a/src/main/java/com/gomo/app/core/interest/application/usecase/DeleteInterestRelationUseCase.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.gomo.app.core.interest.application.usecase; - -import java.util.UUID; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.interest.domain.model.Interest; -import com.gomo.app.core.interest.domain.model.InterestRelation; -import com.gomo.app.core.interest.domain.service.InterestRelationService; -import com.gomo.app.core.interest.domain.service.InterestService; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -public class DeleteInterestRelationUseCase { - - private final InterestService interestService; - private final InterestRelationService interestRelationService; - - @AuditLog(action = "DELETE_INTEREST_RELATION") - public void delete(UUID registrantId, UUID interestRelationId) { - InterestRelation interestRelation = interestRelationService.find(interestRelationId); - interestRelation.validateAuthority(registrantId); - Interest parentInterest = interestService.find(interestRelation.getParentInterestId()); - Interest childInterest = interestService.find(interestRelation.getChildInterestId()); - interestRelationService.delete(interestRelation, parentInterest, childInterest); - } -} diff --git a/src/main/java/com/gomo/app/core/interest/application/usecase/DeleteInterestUseCase.java b/src/main/java/com/gomo/app/core/interest/application/usecase/DeleteInterestUseCase.java deleted file mode 100644 index cbac2cc0..00000000 --- a/src/main/java/com/gomo/app/core/interest/application/usecase/DeleteInterestUseCase.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.gomo.app.core.interest.application.usecase; - -import java.util.List; -import java.util.UUID; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.interest.domain.model.Interest; -import com.gomo.app.core.interest.domain.model.InterestRelation; -import com.gomo.app.core.interest.domain.repository.InterestRepository; -import com.gomo.app.core.interest.domain.repository.MajorInterestRepository; -import com.gomo.app.core.interest.domain.service.InterestRelationService; -import com.gomo.app.core.interest.domain.service.InterestService; -import com.gomo.app.support.image.application.port.DeleteImagePortIn; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -public class DeleteInterestUseCase { - - private final DeleteImagePortIn deleteImagePortIn; - private final MajorInterestRepository majorInterestRepository; - private final InterestRelationService interestRelationService; - private final InterestService interestService; - private final InterestRepository interestRepository; - - /* - TODO : 도메인 정책과 서비스 결합도에 관한 리팩터링 - 관심사와 로고, 주요관심사, 관계선을 함께 제거하는 것은 도메인 정책입니다. - 하지만 관련 로직을 도메인 서비스가 처리하면 도메인 서비스의 외부 의존성이 높아집니다. - 지금처럼 유스케이스에서 트랜잭션으로 처리하면 설계상 일관성은 유지되지만, 도메인 모델이 빈약해집니다. - 따라서 유스케이스는 관심사 삭제만 수행 -> 관심사 도메인 서비스는 이벤트 발행 -> 서로 다른 모듈에서 소비 - 동시에 Zipkin, Jaeger 등의 도구를 활용해 분산 환경에서 이벤트 트래킹을 준비해야합니다. - */ - @AuditLog(action = "DELETE_INTEREST") - public void delete(UUID registrantId, UUID interestId) { - Interest interest = interestService.find(interestId); - interest.validateAuthority(registrantId); - - deleteLogoUrl(interest); - deleteMajorInterest(interestId); - deleteInterestRelations(interestId); - interestRepository.delete(interest); - } - - private void deleteLogoUrl(Interest interest) { - if (!interest.hasDefaultLogo()) { - deleteImagePortIn.delete(interest.getLogo().getUrl()); - } - } - - private void deleteMajorInterest(UUID interestId) { - majorInterestRepository.deleteByInterestId(interestId); - } - - private void deleteInterestRelations(UUID interestId) { - List interestRelations = interestRelationService.findAllByInterestId(interestId); - if (!interestRelations.isEmpty()) { - for (InterestRelation relation : interestRelations) { - Interest parentInterest = interestService.find(relation.getParentInterestId()); - Interest childInterest = interestService.find(relation.getChildInterestId()); - interestRelationService.delete(relation, parentInterest, childInterest); - } - } - } -} diff --git a/src/main/java/com/gomo/app/core/interest/application/usecase/DeleteMajorInterestUseCase.java b/src/main/java/com/gomo/app/core/interest/application/usecase/DeleteMajorInterestUseCase.java deleted file mode 100644 index c6127aab..00000000 --- a/src/main/java/com/gomo/app/core/interest/application/usecase/DeleteMajorInterestUseCase.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.gomo.app.core.interest.application.usecase; - -import java.util.UUID; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.interest.domain.model.MajorInterest; -import com.gomo.app.core.interest.domain.repository.MajorInterestRepository; -import com.gomo.app.core.interest.domain.service.MajorInterestService; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -public class DeleteMajorInterestUseCase { - - private final MajorInterestService majorInterestService; - private final MajorInterestRepository majorInterestRepository; - - @AuditLog(action = "DELETE_MAJOR_INTEREST") - public void delete(UUID registrantId, UUID majorInterestId) { - MajorInterest majorInterest = majorInterestService.find(majorInterestId); - majorInterest.validateAuthority(registrantId); - majorInterestRepository.delete(majorInterest); - } -} diff --git a/src/main/java/com/gomo/app/core/interest/application/usecase/OrderUpdateMajorInterestUseCase.java b/src/main/java/com/gomo/app/core/interest/application/usecase/OrderUpdateMajorInterestUseCase.java deleted file mode 100644 index 7d96bfdf..00000000 --- a/src/main/java/com/gomo/app/core/interest/application/usecase/OrderUpdateMajorInterestUseCase.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.gomo.app.core.interest.application.usecase; - -import java.util.Map; -import java.util.UUID; -import java.util.stream.Collectors; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.common.displayorder.OrderChangeable; -import com.gomo.app.common.displayorder.OrderChanger; -import com.gomo.app.common.displayorder.OrderUpdateOrderChangeableCommand; -import com.gomo.app.core.interest.application.port.command.OrderUpdateMajorInterestCommand; -import com.gomo.app.core.interest.domain.repository.MajorInterestRepository; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -public class OrderUpdateMajorInterestUseCase { - - private final MajorInterestRepository majorInterestRepository; - - @AuditLog(action = "UPDATE_MAJOR_INTEREST_ORDER") - public void update(OrderUpdateMajorInterestCommand command) { - Map majorInterestMap = majorInterestRepository.findAllByRegistrantIdOrderByDisplayOrder(command.registrantId()).stream() - .collect(Collectors.toMap( - majorInterest -> majorInterest.getId(), - majorInterest -> majorInterest - )); - - OrderChanger.change(OrderUpdateOrderChangeableCommand.of(majorInterestMap, command.updatedOrders())); - } -} diff --git a/src/main/java/com/gomo/app/core/interest/application/usecase/ReadInterestNetworkUseCase.java b/src/main/java/com/gomo/app/core/interest/application/usecase/ReadInterestNetworkUseCase.java deleted file mode 100644 index 27d5c114..00000000 --- a/src/main/java/com/gomo/app/core/interest/application/usecase/ReadInterestNetworkUseCase.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.gomo.app.core.interest.application.usecase; - -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.stream.Collectors; - -import org.jetbrains.annotations.NotNull; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.interest.application.port.dto.InterestDto; -import com.gomo.app.core.interest.application.port.dto.InterestNetworkDto; -import com.gomo.app.core.interest.application.port.dto.InterestRelationDto; -import com.gomo.app.core.interest.domain.model.Interest; -import com.gomo.app.core.interest.domain.model.MajorInterest; -import com.gomo.app.core.interest.domain.repository.InterestRelationRepository; -import com.gomo.app.core.interest.domain.repository.InterestRepository; -import com.gomo.app.core.interest.domain.repository.MajorInterestRepository; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -public class ReadInterestNetworkUseCase { - - private final InterestRepository interestRepository; - private final MajorInterestRepository majorInterestRepository; - private final InterestRelationRepository interestRelationRepository; - - public InterestNetworkDto find(UUID registrantId) { - List interestDtos = getInterestDtos(registrantId); - List relationDtos = getRelationDtos(registrantId); - return InterestNetworkDto.of(interestDtos, relationDtos); - } - - @NotNull - private List getInterestDtos(UUID registrantId) { - List interests = interestRepository.findAllByRegistrantId(registrantId); - List interestIds = interests.stream().map(Interest::getId).toList(); - Map majorInterestMap = majorInterestRepository.findAllByRegistrantIdAndInterestIdIn(registrantId, interestIds).stream() - .collect(Collectors.toMap(MajorInterest::getInterestId, MajorInterest::getId)); - - return interests.stream().map(interest -> { - UUID majorInterestId = majorInterestMap.get(interest.getId()); - return InterestDto.of(interest, majorInterestId); - }).toList(); - } - - @NotNull - private List getRelationDtos(UUID id) { - return interestRelationRepository.findAllByRegistrantId(id).stream() - .map(InterestRelationDto::from) - .toList(); - } -} diff --git a/src/main/java/com/gomo/app/core/interest/application/usecase/ReadMajorInterestUseCase.java b/src/main/java/com/gomo/app/core/interest/application/usecase/ReadMajorInterestUseCase.java deleted file mode 100644 index f26a81f3..00000000 --- a/src/main/java/com/gomo/app/core/interest/application/usecase/ReadMajorInterestUseCase.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.gomo.app.core.interest.application.usecase; - -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.function.Function; -import java.util.stream.Collectors; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.interest.application.port.dto.MajorInterestDto; -import com.gomo.app.core.interest.domain.model.Interest; -import com.gomo.app.core.interest.domain.model.MajorInterest; -import com.gomo.app.core.interest.domain.repository.InterestRepository; -import com.gomo.app.core.interest.domain.repository.MajorInterestRepository; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -public class ReadMajorInterestUseCase { - - private final MajorInterestRepository majorInterestRepository; - private final InterestRepository interestRepository; - - public List findAll(UUID registrantId) { - List majorInterests = majorInterestRepository.findAllByRegistrantIdOrderByDisplayOrder(registrantId); - Map majorInterestMap = majorInterests.stream() - .collect((Collectors.toMap(MajorInterest::getInterestId, Function.identity()))); - - List interests = interestRepository.findAllByIdIsIn(majorInterestMap.keySet()); - return interests.stream() - .map(interest -> MajorInterestDto.from(majorInterestMap.get(interest.getId()), interest)) - .toList(); - } -} diff --git a/src/main/java/com/gomo/app/core/interest/application/usecase/UpdateInterestUseCase.java b/src/main/java/com/gomo/app/core/interest/application/usecase/UpdateInterestUseCase.java deleted file mode 100644 index 77c549f2..00000000 --- a/src/main/java/com/gomo/app/core/interest/application/usecase/UpdateInterestUseCase.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.gomo.app.core.interest.application.usecase; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.interest.application.port.command.UpdateInterestCommand; -import com.gomo.app.core.interest.domain.model.Interest; -import com.gomo.app.core.interest.domain.model.InterestName; -import com.gomo.app.core.interest.domain.service.InterestService; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -public class UpdateInterestUseCase { - - private final InterestService interestService; - - @AuditLog(action = "UPDATE_INTEREST") - public void update(UpdateInterestCommand command) { - Interest interest = interestService.find(command.interestId()); - interest.validateAuthority(command.registrantId()); - interest.updateName(InterestName.of(command.name())); - interest.updateColorCode(command.colorCode()); - } -} diff --git a/src/main/java/com/gomo/app/core/interest/exception/InterestAccessDeniedException.java b/src/main/java/com/gomo/app/core/interest/domain/exception/InterestAccessDeniedException.java similarity index 77% rename from src/main/java/com/gomo/app/core/interest/exception/InterestAccessDeniedException.java rename to src/main/java/com/gomo/app/core/interest/domain/exception/InterestAccessDeniedException.java index 6e08e589..fa80882b 100644 --- a/src/main/java/com/gomo/app/core/interest/exception/InterestAccessDeniedException.java +++ b/src/main/java/com/gomo/app/core/interest/domain/exception/InterestAccessDeniedException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.interest.exception; +package com.gomo.app.core.interest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.interest.exception.code.InterestErrorCode; +import com.gomo.app.core.interest.domain.exception.code.InterestErrorCode; public class InterestAccessDeniedException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/interest/exception/InterestConstraintViolationException.java b/src/main/java/com/gomo/app/core/interest/domain/exception/InterestConstraintViolationException.java similarity index 77% rename from src/main/java/com/gomo/app/core/interest/exception/InterestConstraintViolationException.java rename to src/main/java/com/gomo/app/core/interest/domain/exception/InterestConstraintViolationException.java index 5853c2f6..0ca500fb 100644 --- a/src/main/java/com/gomo/app/core/interest/exception/InterestConstraintViolationException.java +++ b/src/main/java/com/gomo/app/core/interest/domain/exception/InterestConstraintViolationException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.interest.exception; +package com.gomo.app.core.interest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.interest.exception.code.InterestErrorCode; +import com.gomo.app.core.interest.domain.exception.code.InterestErrorCode; public class InterestConstraintViolationException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/interest/exception/InterestNameConstraintViolationException.java b/src/main/java/com/gomo/app/core/interest/domain/exception/InterestNameConstraintViolationException.java similarity index 77% rename from src/main/java/com/gomo/app/core/interest/exception/InterestNameConstraintViolationException.java rename to src/main/java/com/gomo/app/core/interest/domain/exception/InterestNameConstraintViolationException.java index 3c941a71..212f1f52 100644 --- a/src/main/java/com/gomo/app/core/interest/exception/InterestNameConstraintViolationException.java +++ b/src/main/java/com/gomo/app/core/interest/domain/exception/InterestNameConstraintViolationException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.interest.exception; +package com.gomo.app.core.interest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.interest.exception.code.InterestNameErrorCode; +import com.gomo.app.core.interest.domain.exception.code.InterestNameErrorCode; public class InterestNameConstraintViolationException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/interest/exception/InterestNotFoundException.java b/src/main/java/com/gomo/app/core/interest/domain/exception/InterestNotFoundException.java similarity index 76% rename from src/main/java/com/gomo/app/core/interest/exception/InterestNotFoundException.java rename to src/main/java/com/gomo/app/core/interest/domain/exception/InterestNotFoundException.java index 5dba4f3d..b55fd3e0 100644 --- a/src/main/java/com/gomo/app/core/interest/exception/InterestNotFoundException.java +++ b/src/main/java/com/gomo/app/core/interest/domain/exception/InterestNotFoundException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.interest.exception; +package com.gomo.app.core.interest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.interest.exception.code.InterestErrorCode; +import com.gomo.app.core.interest.domain.exception.code.InterestErrorCode; public class InterestNotFoundException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/interest/exception/InterestRelationAccessDeniedException.java b/src/main/java/com/gomo/app/core/interest/domain/exception/InterestRelationAccessDeniedException.java similarity index 77% rename from src/main/java/com/gomo/app/core/interest/exception/InterestRelationAccessDeniedException.java rename to src/main/java/com/gomo/app/core/interest/domain/exception/InterestRelationAccessDeniedException.java index f87b3467..02f5fb64 100644 --- a/src/main/java/com/gomo/app/core/interest/exception/InterestRelationAccessDeniedException.java +++ b/src/main/java/com/gomo/app/core/interest/domain/exception/InterestRelationAccessDeniedException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.interest.exception; +package com.gomo.app.core.interest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.interest.exception.code.InterestRelationErrorCode; +import com.gomo.app.core.interest.domain.exception.code.InterestRelationErrorCode; public class InterestRelationAccessDeniedException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/interest/exception/InterestRelationCycleException.java b/src/main/java/com/gomo/app/core/interest/domain/exception/InterestRelationCycleException.java similarity index 76% rename from src/main/java/com/gomo/app/core/interest/exception/InterestRelationCycleException.java rename to src/main/java/com/gomo/app/core/interest/domain/exception/InterestRelationCycleException.java index dc3efa55..7b27b850 100644 --- a/src/main/java/com/gomo/app/core/interest/exception/InterestRelationCycleException.java +++ b/src/main/java/com/gomo/app/core/interest/domain/exception/InterestRelationCycleException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.interest.exception; +package com.gomo.app.core.interest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.interest.exception.code.InterestRelationErrorCode; +import com.gomo.app.core.interest.domain.exception.code.InterestRelationErrorCode; public class InterestRelationCycleException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/interest/exception/InterestRelationDuplicatedException.java b/src/main/java/com/gomo/app/core/interest/domain/exception/InterestRelationDuplicatedException.java similarity index 77% rename from src/main/java/com/gomo/app/core/interest/exception/InterestRelationDuplicatedException.java rename to src/main/java/com/gomo/app/core/interest/domain/exception/InterestRelationDuplicatedException.java index c3b23e5d..fbb57cf1 100644 --- a/src/main/java/com/gomo/app/core/interest/exception/InterestRelationDuplicatedException.java +++ b/src/main/java/com/gomo/app/core/interest/domain/exception/InterestRelationDuplicatedException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.interest.exception; +package com.gomo.app.core.interest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.interest.exception.code.InterestRelationErrorCode; +import com.gomo.app.core.interest.domain.exception.code.InterestRelationErrorCode; public class InterestRelationDuplicatedException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/interest/exception/InterestRelationNotFoundException.java b/src/main/java/com/gomo/app/core/interest/domain/exception/InterestRelationNotFoundException.java similarity index 77% rename from src/main/java/com/gomo/app/core/interest/exception/InterestRelationNotFoundException.java rename to src/main/java/com/gomo/app/core/interest/domain/exception/InterestRelationNotFoundException.java index dc51c2fb..ad04c056 100644 --- a/src/main/java/com/gomo/app/core/interest/exception/InterestRelationNotFoundException.java +++ b/src/main/java/com/gomo/app/core/interest/domain/exception/InterestRelationNotFoundException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.interest.exception; +package com.gomo.app.core.interest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.interest.exception.code.InterestRelationErrorCode; +import com.gomo.app.core.interest.domain.exception.code.InterestRelationErrorCode; public class InterestRelationNotFoundException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/interest/exception/LevelConstraintViolationException.java b/src/main/java/com/gomo/app/core/interest/domain/exception/LevelConstraintViolationException.java similarity index 77% rename from src/main/java/com/gomo/app/core/interest/exception/LevelConstraintViolationException.java rename to src/main/java/com/gomo/app/core/interest/domain/exception/LevelConstraintViolationException.java index 8a978ebc..7f47f2cd 100644 --- a/src/main/java/com/gomo/app/core/interest/exception/LevelConstraintViolationException.java +++ b/src/main/java/com/gomo/app/core/interest/domain/exception/LevelConstraintViolationException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.interest.exception; +package com.gomo.app.core.interest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.interest.exception.code.LevelErrorCode; +import com.gomo.app.core.interest.domain.exception.code.LevelErrorCode; public class LevelConstraintViolationException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/interest/exception/MajorInterestAccessDeniedException.java b/src/main/java/com/gomo/app/core/interest/domain/exception/MajorInterestAccessDeniedException.java similarity index 77% rename from src/main/java/com/gomo/app/core/interest/exception/MajorInterestAccessDeniedException.java rename to src/main/java/com/gomo/app/core/interest/domain/exception/MajorInterestAccessDeniedException.java index 559ceb47..a70ee72b 100644 --- a/src/main/java/com/gomo/app/core/interest/exception/MajorInterestAccessDeniedException.java +++ b/src/main/java/com/gomo/app/core/interest/domain/exception/MajorInterestAccessDeniedException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.interest.exception; +package com.gomo.app.core.interest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.interest.exception.code.MajorInterestErrorCode; +import com.gomo.app.core.interest.domain.exception.code.MajorInterestErrorCode; public class MajorInterestAccessDeniedException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/interest/exception/MajorInterestDuplicatedException.java b/src/main/java/com/gomo/app/core/interest/domain/exception/MajorInterestDuplicatedException.java similarity index 77% rename from src/main/java/com/gomo/app/core/interest/exception/MajorInterestDuplicatedException.java rename to src/main/java/com/gomo/app/core/interest/domain/exception/MajorInterestDuplicatedException.java index 8aab529b..91901375 100644 --- a/src/main/java/com/gomo/app/core/interest/exception/MajorInterestDuplicatedException.java +++ b/src/main/java/com/gomo/app/core/interest/domain/exception/MajorInterestDuplicatedException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.interest.exception; +package com.gomo.app.core.interest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.interest.exception.code.MajorInterestErrorCode; +import com.gomo.app.core.interest.domain.exception.code.MajorInterestErrorCode; public class MajorInterestDuplicatedException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/interest/exception/MajorInterestNotFoundException.java b/src/main/java/com/gomo/app/core/interest/domain/exception/MajorInterestNotFoundException.java similarity index 76% rename from src/main/java/com/gomo/app/core/interest/exception/MajorInterestNotFoundException.java rename to src/main/java/com/gomo/app/core/interest/domain/exception/MajorInterestNotFoundException.java index bb674114..07500038 100644 --- a/src/main/java/com/gomo/app/core/interest/exception/MajorInterestNotFoundException.java +++ b/src/main/java/com/gomo/app/core/interest/domain/exception/MajorInterestNotFoundException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.interest.exception; +package com.gomo.app.core.interest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.interest.exception.code.MajorInterestErrorCode; +import com.gomo.app.core.interest.domain.exception.code.MajorInterestErrorCode; public class MajorInterestNotFoundException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/interest/exception/ProficiencyAdjustFailureException.java b/src/main/java/com/gomo/app/core/interest/domain/exception/ProficiencyAdjustFailureException.java similarity index 77% rename from src/main/java/com/gomo/app/core/interest/exception/ProficiencyAdjustFailureException.java rename to src/main/java/com/gomo/app/core/interest/domain/exception/ProficiencyAdjustFailureException.java index d500c98e..a324b49b 100644 --- a/src/main/java/com/gomo/app/core/interest/exception/ProficiencyAdjustFailureException.java +++ b/src/main/java/com/gomo/app/core/interest/domain/exception/ProficiencyAdjustFailureException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.interest.exception; +package com.gomo.app.core.interest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.interest.exception.code.ProficiencyErrorCode; +import com.gomo.app.core.interest.domain.exception.code.ProficiencyErrorCode; public class ProficiencyAdjustFailureException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/interest/exception/ScoreConstraintViolationException.java b/src/main/java/com/gomo/app/core/interest/domain/exception/ScoreConstraintViolationException.java similarity index 77% rename from src/main/java/com/gomo/app/core/interest/exception/ScoreConstraintViolationException.java rename to src/main/java/com/gomo/app/core/interest/domain/exception/ScoreConstraintViolationException.java index 051e3e3f..4862d03c 100644 --- a/src/main/java/com/gomo/app/core/interest/exception/ScoreConstraintViolationException.java +++ b/src/main/java/com/gomo/app/core/interest/domain/exception/ScoreConstraintViolationException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.interest.exception; +package com.gomo.app.core.interest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.interest.exception.code.ScoreErrorCode; +import com.gomo.app.core.interest.domain.exception.code.ScoreErrorCode; public class ScoreConstraintViolationException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/interest/exception/code/InterestErrorCode.java b/src/main/java/com/gomo/app/core/interest/domain/exception/code/InterestErrorCode.java similarity index 87% rename from src/main/java/com/gomo/app/core/interest/exception/code/InterestErrorCode.java rename to src/main/java/com/gomo/app/core/interest/domain/exception/code/InterestErrorCode.java index 395ab629..4bbe7a73 100644 --- a/src/main/java/com/gomo/app/core/interest/exception/code/InterestErrorCode.java +++ b/src/main/java/com/gomo/app/core/interest/domain/exception/code/InterestErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.exception.code; +package com.gomo.app.core.interest.domain.exception.code; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/interest/exception/code/InterestNameErrorCode.java b/src/main/java/com/gomo/app/core/interest/domain/exception/code/InterestNameErrorCode.java similarity index 87% rename from src/main/java/com/gomo/app/core/interest/exception/code/InterestNameErrorCode.java rename to src/main/java/com/gomo/app/core/interest/domain/exception/code/InterestNameErrorCode.java index b96f26e0..1b0aa866 100644 --- a/src/main/java/com/gomo/app/core/interest/exception/code/InterestNameErrorCode.java +++ b/src/main/java/com/gomo/app/core/interest/domain/exception/code/InterestNameErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.exception.code; +package com.gomo.app.core.interest.domain.exception.code; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/interest/exception/code/InterestRelationErrorCode.java b/src/main/java/com/gomo/app/core/interest/domain/exception/code/InterestRelationErrorCode.java similarity index 81% rename from src/main/java/com/gomo/app/core/interest/exception/code/InterestRelationErrorCode.java rename to src/main/java/com/gomo/app/core/interest/domain/exception/code/InterestRelationErrorCode.java index d0f72b47..c9dd8c2c 100644 --- a/src/main/java/com/gomo/app/core/interest/exception/code/InterestRelationErrorCode.java +++ b/src/main/java/com/gomo/app/core/interest/domain/exception/code/InterestRelationErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.exception.code; +package com.gomo.app.core.interest.domain.exception.code; import lombok.Getter; @@ -6,7 +6,7 @@ public enum InterestRelationErrorCode { NOT_FOUND(404, "INT-REL-001", "Interest relation not found"), - ACCESS_DENIED(403 ,"INT-REL-002", "Access denied for the interest relation"), + ACCESS_DENIED(403, "INT-REL-002", "Access denied for the interest relation"), DUPLICATED(409, "INT-REL-003", "Interest relation already exists"), UNEXPECTED_CYCLE(422, "INT-REL-004", "Cycle detected in the interest network by adding this relation, which is not allowed"); diff --git a/src/main/java/com/gomo/app/core/interest/exception/code/LevelErrorCode.java b/src/main/java/com/gomo/app/core/interest/domain/exception/code/LevelErrorCode.java similarity index 88% rename from src/main/java/com/gomo/app/core/interest/exception/code/LevelErrorCode.java rename to src/main/java/com/gomo/app/core/interest/domain/exception/code/LevelErrorCode.java index 5c3d27cf..c354f361 100644 --- a/src/main/java/com/gomo/app/core/interest/exception/code/LevelErrorCode.java +++ b/src/main/java/com/gomo/app/core/interest/domain/exception/code/LevelErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.exception.code; +package com.gomo.app.core.interest.domain.exception.code; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/interest/exception/code/MajorInterestErrorCode.java b/src/main/java/com/gomo/app/core/interest/domain/exception/code/MajorInterestErrorCode.java similarity index 87% rename from src/main/java/com/gomo/app/core/interest/exception/code/MajorInterestErrorCode.java rename to src/main/java/com/gomo/app/core/interest/domain/exception/code/MajorInterestErrorCode.java index 0236895f..59534945 100644 --- a/src/main/java/com/gomo/app/core/interest/exception/code/MajorInterestErrorCode.java +++ b/src/main/java/com/gomo/app/core/interest/domain/exception/code/MajorInterestErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.exception.code; +package com.gomo.app.core.interest.domain.exception.code; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/interest/exception/code/ProficiencyErrorCode.java b/src/main/java/com/gomo/app/core/interest/domain/exception/code/ProficiencyErrorCode.java similarity index 86% rename from src/main/java/com/gomo/app/core/interest/exception/code/ProficiencyErrorCode.java rename to src/main/java/com/gomo/app/core/interest/domain/exception/code/ProficiencyErrorCode.java index ebe599dd..a086eb80 100644 --- a/src/main/java/com/gomo/app/core/interest/exception/code/ProficiencyErrorCode.java +++ b/src/main/java/com/gomo/app/core/interest/domain/exception/code/ProficiencyErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.exception.code; +package com.gomo.app.core.interest.domain.exception.code; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/interest/exception/code/ScoreErrorCode.java b/src/main/java/com/gomo/app/core/interest/domain/exception/code/ScoreErrorCode.java similarity index 83% rename from src/main/java/com/gomo/app/core/interest/exception/code/ScoreErrorCode.java rename to src/main/java/com/gomo/app/core/interest/domain/exception/code/ScoreErrorCode.java index 7e78e423..833f1368 100644 --- a/src/main/java/com/gomo/app/core/interest/exception/code/ScoreErrorCode.java +++ b/src/main/java/com/gomo/app/core/interest/domain/exception/code/ScoreErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.exception.code; +package com.gomo.app.core.interest.domain.exception.code; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/interest/domain/model/Interest.java b/src/main/java/com/gomo/app/core/interest/domain/model/Interest.java index 54e63da7..f585ff8b 100644 --- a/src/main/java/com/gomo/app/core/interest/domain/model/Interest.java +++ b/src/main/java/com/gomo/app/core/interest/domain/model/Interest.java @@ -4,8 +4,9 @@ import com.gomo.app.common.arch.Authorizable; import com.gomo.app.common.jpa.BaseAudit; -import com.gomo.app.core.interest.exception.InterestAccessDeniedException; -import com.gomo.app.core.interest.exception.code.InterestErrorCode; +import com.gomo.app.core.interest.domain.exception.InterestAccessDeniedException; +import com.gomo.app.core.interest.domain.exception.code.InterestErrorCode; +import com.gomo.app.core.interest.domain.service.ProficiencyCalculator; import jakarta.persistence.AttributeOverride; import jakarta.persistence.AttributeOverrides; diff --git a/src/main/java/com/gomo/app/core/interest/domain/model/InterestName.java b/src/main/java/com/gomo/app/core/interest/domain/model/InterestName.java index 53c5e595..d0a322c4 100644 --- a/src/main/java/com/gomo/app/core/interest/domain/model/InterestName.java +++ b/src/main/java/com/gomo/app/core/interest/domain/model/InterestName.java @@ -3,8 +3,8 @@ import java.util.regex.Pattern; import com.gomo.app.common.arch.ValueObject; -import com.gomo.app.core.interest.exception.InterestNameConstraintViolationException; -import com.gomo.app.core.interest.exception.code.InterestNameErrorCode; +import com.gomo.app.core.interest.domain.exception.InterestNameConstraintViolationException; +import com.gomo.app.core.interest.domain.exception.code.InterestNameErrorCode; import jakarta.persistence.Embeddable; import lombok.Getter; @@ -19,7 +19,8 @@ public class InterestName { private String interestName; - protected InterestName() {} + protected InterestName() { + } private InterestName(String interestName) { ensureNotBlank(interestName); @@ -37,19 +38,19 @@ public InterestName update(String updatedInterestName) { } private void ensureNotBlank(String interestName) { - if(interestName == null || interestName.isBlank()) { + if (interestName == null || interestName.isBlank()) { throw new InterestNameConstraintViolationException(InterestNameErrorCode.BLANK); } } private void ensureValidLength(String interestName) { - if(interestName.length() > MAX_LENGTH) { + if (interestName.length() > MAX_LENGTH) { throw new InterestNameConstraintViolationException(InterestNameErrorCode.TOO_LONG); } } private void ensureNoForbiddenName(String interestName) { - if(FORBIDDEN_PATTERN.matcher(interestName).find()) { + if (FORBIDDEN_PATTERN.matcher(interestName).find()) { throw new InterestNameConstraintViolationException(InterestNameErrorCode.FORBIDDEN); } } diff --git a/src/main/java/com/gomo/app/core/interest/domain/model/InterestRelation.java b/src/main/java/com/gomo/app/core/interest/domain/model/InterestRelation.java index 233d858d..c065e884 100644 --- a/src/main/java/com/gomo/app/core/interest/domain/model/InterestRelation.java +++ b/src/main/java/com/gomo/app/core/interest/domain/model/InterestRelation.java @@ -1,12 +1,12 @@ package com.gomo.app.core.interest.domain.model; -import static com.gomo.app.core.interest.exception.code.InterestRelationErrorCode.*; +import static com.gomo.app.core.interest.domain.exception.code.InterestRelationErrorCode.*; import java.util.UUID; import com.gomo.app.common.arch.Authorizable; import com.gomo.app.common.jpa.BaseAudit; -import com.gomo.app.core.interest.exception.InterestRelationAccessDeniedException; +import com.gomo.app.core.interest.domain.exception.InterestRelationAccessDeniedException; import jakarta.persistence.Entity; import jakarta.persistence.Id; diff --git a/src/main/java/com/gomo/app/core/interest/domain/model/Level.java b/src/main/java/com/gomo/app/core/interest/domain/model/Level.java index 181d2acc..00df1bea 100644 --- a/src/main/java/com/gomo/app/core/interest/domain/model/Level.java +++ b/src/main/java/com/gomo/app/core/interest/domain/model/Level.java @@ -1,8 +1,8 @@ package com.gomo.app.core.interest.domain.model; import com.gomo.app.common.arch.ValueObject; -import com.gomo.app.core.interest.exception.LevelConstraintViolationException; -import com.gomo.app.core.interest.exception.code.LevelErrorCode; +import com.gomo.app.core.interest.domain.exception.LevelConstraintViolationException; +import com.gomo.app.core.interest.domain.exception.code.LevelErrorCode; import jakarta.persistence.Embeddable; import lombok.EqualsAndHashCode; diff --git a/src/main/java/com/gomo/app/core/interest/domain/model/MajorInterest.java b/src/main/java/com/gomo/app/core/interest/domain/model/MajorInterest.java index 2da5b21f..06ced58b 100644 --- a/src/main/java/com/gomo/app/core/interest/domain/model/MajorInterest.java +++ b/src/main/java/com/gomo/app/core/interest/domain/model/MajorInterest.java @@ -1,6 +1,6 @@ package com.gomo.app.core.interest.domain.model; -import static com.gomo.app.core.interest.exception.code.MajorInterestErrorCode.*; +import static com.gomo.app.core.interest.domain.exception.code.MajorInterestErrorCode.*; import java.util.UUID; @@ -8,7 +8,7 @@ import com.gomo.app.common.displayorder.DisplayOrder; import com.gomo.app.common.displayorder.OrderChangeable; import com.gomo.app.common.jpa.BaseAudit; -import com.gomo.app.core.interest.exception.MajorInterestAccessDeniedException; +import com.gomo.app.core.interest.domain.exception.MajorInterestAccessDeniedException; import jakarta.persistence.Embedded; import jakarta.persistence.Entity; @@ -41,6 +41,11 @@ public static MajorInterest of(UUID id, UUID registrantId, UUID interestId, Disp return new MajorInterest(id, registrantId, interestId, displayOrder); } + public static MajorInterest createNext(UUID id, UUID registrantId, UUID interestId, int currentHighestOrder) { + DisplayOrder nextOrder = DisplayOrder.of(currentHighestOrder + 1); + return MajorInterest.of(id, registrantId, interestId, nextOrder); + } + public int displayOrder() { return this.displayOrder.getDisplayOrder(); } diff --git a/src/main/java/com/gomo/app/core/interest/domain/model/Proficiency.java b/src/main/java/com/gomo/app/core/interest/domain/model/Proficiency.java index a7b2d4b6..77c765e6 100644 --- a/src/main/java/com/gomo/app/core/interest/domain/model/Proficiency.java +++ b/src/main/java/com/gomo/app/core/interest/domain/model/Proficiency.java @@ -1,6 +1,7 @@ package com.gomo.app.core.interest.domain.model; import com.gomo.app.common.arch.ValueObject; +import com.gomo.app.core.interest.domain.service.ProficiencyCalculator; import jakarta.persistence.Embeddable; import jakarta.persistence.Embedded; diff --git a/src/main/java/com/gomo/app/core/interest/domain/model/Registrant.java b/src/main/java/com/gomo/app/core/interest/domain/model/Registrant.java index 7634cbcd..3fecfbb7 100644 --- a/src/main/java/com/gomo/app/core/interest/domain/model/Registrant.java +++ b/src/main/java/com/gomo/app/core/interest/domain/model/Registrant.java @@ -3,8 +3,8 @@ import java.util.UUID; import com.gomo.app.common.arch.ValueObject; -import com.gomo.app.core.interest.exception.InterestConstraintViolationException; -import com.gomo.app.core.interest.exception.code.InterestErrorCode; +import com.gomo.app.core.interest.domain.exception.InterestConstraintViolationException; +import com.gomo.app.core.interest.domain.exception.code.InterestErrorCode; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/interest/domain/model/Score.java b/src/main/java/com/gomo/app/core/interest/domain/model/Score.java index 220e34f7..7d35b590 100644 --- a/src/main/java/com/gomo/app/core/interest/domain/model/Score.java +++ b/src/main/java/com/gomo/app/core/interest/domain/model/Score.java @@ -1,8 +1,8 @@ package com.gomo.app.core.interest.domain.model; import com.gomo.app.common.arch.ValueObject; -import com.gomo.app.core.interest.exception.ScoreConstraintViolationException; -import com.gomo.app.core.interest.exception.code.ScoreErrorCode; +import com.gomo.app.core.interest.domain.exception.ScoreConstraintViolationException; +import com.gomo.app.core.interest.domain.exception.code.ScoreErrorCode; import jakarta.persistence.Embeddable; import lombok.EqualsAndHashCode; diff --git a/src/main/java/com/gomo/app/core/interest/domain/repository/InterestRepository.java b/src/main/java/com/gomo/app/core/interest/domain/repository/InterestRepository.java index 717fd6d3..d6de0c2f 100644 --- a/src/main/java/com/gomo/app/core/interest/domain/repository/InterestRepository.java +++ b/src/main/java/com/gomo/app/core/interest/domain/repository/InterestRepository.java @@ -16,14 +16,6 @@ public interface InterestRepository extends JpaRepository { List findAllByRegistrantIdIn(Set registrantIds); - List findAllByIdIsIn(Set interestIds); - - // TODO to : 값이 null이 아닌 데이터만 조회하기 때문에 메서드 이름 수정이 필요해 보입니다. - // 이미지 삭제 스케줄 기능에만 사용된다면 해당 메서드 자체를 제거해주세요. - // ※ @Query 어노테이션을 활용해 직접 작성한 메서드는 테스트를 작성해야 합니다. - @Query("SELECT i.logo FROM Interest i WHERE i.logo IS NOT NULL") - List findAllLogoUrl(); - @Modifying @Query("DELETE FROM Interest i WHERE i.registrantId = :registrantId") void deleteAllByRegistrantId(UUID registrantId); diff --git a/src/main/java/com/gomo/app/core/interest/domain/service/InterestNetworkBuilder.java b/src/main/java/com/gomo/app/core/interest/domain/service/InterestNetworkBuilder.java new file mode 100644 index 00000000..9b8f1196 --- /dev/null +++ b/src/main/java/com/gomo/app/core/interest/domain/service/InterestNetworkBuilder.java @@ -0,0 +1,109 @@ +package com.gomo.app.core.interest.domain.service; + +import java.util.ArrayDeque; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.gomo.app.common.arch.DomainService; +import com.gomo.app.core.interest.domain.exception.InterestRelationCycleException; +import com.gomo.app.core.interest.domain.exception.code.InterestRelationErrorCode; +import com.gomo.app.core.interest.domain.model.Interest; +import com.gomo.app.core.interest.domain.model.InterestRelation; +import com.gomo.app.core.interest.domain.repository.InterestRepository; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@DomainService +public class InterestNetworkBuilder { + + private final InterestRepository interestRepository; + + public Map> buildChildIdByParentId(List relations) { + return buildNetwork(relations, InterestRelation::getParentInterestId, InterestRelation::getChildInterestId); + } + + public Map> buildParentInterestByChildId(List relations) { + if (relations.isEmpty()) { + return Collections.emptyMap(); + } + Map interestMap = buildInterestById(relations); + return buildNetwork(relations, InterestRelation::getChildInterestId, relation -> interestMap.get(relation.getParentInterestId())); + } + + /** + * Builds a network from the given relations. + * + * @param relations source data for building the network + * @param keyMapper function to extract the key from a relation + * @param valueMapper function to extract values for the value set + * @param key type of the network + * @param value type contained in the value set + * @return constructed network + */ + private Map> buildNetwork(List relations, Function keyMapper, Function valueMapper) { + Map> network = new HashMap<>(); + for (InterestRelation relation : relations) { + K key = keyMapper.apply(relation); + V value = valueMapper.apply(relation); + + if (key != null && value != null) { + network.computeIfAbsent(key, k -> new HashSet<>()).add(value); + } + } + return network; + } + + private Map buildInterestById(List relations) { + Set interestIds = relations.stream() + .flatMap(r -> Stream.of(r.getParentInterestId(), r.getChildInterestId())) + .collect(Collectors.toSet()); + return interestRepository.findAllById(interestIds).stream().collect(Collectors.toMap(Interest::getId, Function.identity())); + } + + public void validateAcyclic(List relations, UUID startNode) { + Map> childIdByParentId = buildChildIdByParentId(relations); + ArrayDeque nodeQueue = new ArrayDeque<>(); + Set visitedNodes = new HashSet<>(); + + nodeQueue.addLast(startNode); + while (!nodeQueue.isEmpty()) { + UUID currentNode = nodeQueue.removeFirst(); + + if (isAlreadyVisited(visitedNodes, currentNode)) { + continue; + } + visitedNodes.add(currentNode); + + Set neighbors = childIdByParentId.get(currentNode); + if (neighbors != null) { + for (UUID neighbor : neighbors) { + if (isCycleReturningToStart(neighbor, startNode)) { + throw new InterestRelationCycleException(InterestRelationErrorCode.UNEXPECTED_CYCLE); + } + + if (isAlreadyVisited(visitedNodes, neighbor)) { + continue; + } + nodeQueue.addLast(neighbor); + } + } + } + } + + private boolean isCycleReturningToStart(UUID neighbor, UUID startNode) { + return neighbor.equals(startNode); + } + + private boolean isAlreadyVisited(Set visitedNodes, UUID currentNode) { + return visitedNodes.contains(currentNode); + } +} diff --git a/src/main/java/com/gomo/app/core/interest/domain/service/InterestRelationService.java b/src/main/java/com/gomo/app/core/interest/domain/service/InterestRelationService.java deleted file mode 100644 index bd1c3148..00000000 --- a/src/main/java/com/gomo/app/core/interest/domain/service/InterestRelationService.java +++ /dev/null @@ -1,137 +0,0 @@ -package com.gomo.app.core.interest.domain.service; - -import java.util.ArrayDeque; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - -import org.jetbrains.annotations.NotNull; -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.DomainService; -import com.gomo.app.common.util.UUIDGenerator; -import com.gomo.app.core.interest.domain.model.Interest; -import com.gomo.app.core.interest.domain.model.InterestRelation; -import com.gomo.app.core.interest.domain.repository.InterestRelationRepository; -import com.gomo.app.core.interest.exception.InterestRelationCycleException; -import com.gomo.app.core.interest.exception.InterestRelationDuplicatedException; -import com.gomo.app.core.interest.exception.InterestRelationNotFoundException; -import com.gomo.app.core.interest.exception.code.InterestRelationErrorCode; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@DomainService -public class InterestRelationService { - - private final ProficiencyService proficiencyService; - private final InterestRelationRepository interestRelationRepository; - - @Transactional - public InterestRelation create(UUID registrantId, Interest parentInterest, Interest childInterest) { - UUID parentInterestId = parentInterest.getId(); - UUID childInterestId = childInterest.getId(); - - ensureNotDuplicated(parentInterestId, childInterestId); - InterestRelation interestRelation = InterestRelation.of( - UUIDGenerator.generate(), - registrantId, - parentInterestId, - childInterestId - ); - ensureDoesNotCreateCycle(registrantId, interestRelation); - - enhanceProficiencyOfParentInterests(parentInterest, childInterest); - return interestRelationRepository.save(interestRelation); - } - - public InterestRelation find(UUID interestRelationId) { - return interestRelationRepository.findById(interestRelationId) - .orElseThrow(() -> new InterestRelationNotFoundException(InterestRelationErrorCode.NOT_FOUND)); - } - - public List findAllByInterestId(UUID interestId) { - return interestRelationRepository.findAllByInterestId(interestId); - } - - @Transactional - public void delete(InterestRelation interestRelation, Interest parentInterest, Interest childInterest) { - reduceProficiencyOfParentInterests(parentInterest, childInterest); - interestRelationRepository.delete(interestRelation); - } - - private void ensureNotDuplicated(UUID parentInterestId, UUID childInterestId) { - if (interestRelationRepository.existsRelationFor(parentInterestId, childInterestId)) { - throw new InterestRelationDuplicatedException(InterestRelationErrorCode.DUPLICATED); - } - } - - private void ensureDoesNotCreateCycle(UUID registrantId, InterestRelation proposedRelation) { - Map> interestGraph = buildInterestGraph(registrantId, proposedRelation); - UUID startNode = proposedRelation.getParentInterestId(); - ensureAcyclicGraph(startNode, interestGraph); - } - - @NotNull - private Map> buildInterestGraph(UUID registrantId, InterestRelation proposedRelation) { - List existingRelations = interestRelationRepository.findAllByRegistrantId(registrantId); - existingRelations.add(proposedRelation); - - Map> interestGraph = new HashMap<>(); - for (InterestRelation relation : existingRelations) { - UUID parentId = relation.getParentInterestId(); - UUID childId = relation.getChildInterestId(); - interestGraph.computeIfAbsent(parentId, k -> new HashSet<>()).add(childId); - } - - return interestGraph; - } - - private void ensureAcyclicGraph(UUID startNode, Map> interestGraph) { - ArrayDeque nodeQueue = new ArrayDeque<>(); - Set visitedNodes = new HashSet<>(); - - nodeQueue.addLast(startNode); - while (!nodeQueue.isEmpty()) { - UUID currentNode = nodeQueue.removeFirst(); - - if (isAlreadyVisited(visitedNodes, currentNode)) { - continue; - } - visitedNodes.add(currentNode); - - Set neighbors = interestGraph.get(currentNode); - if (neighbors != null) { - for (UUID neighbor : neighbors) { - if (isCycleReturningToStart(neighbor, startNode)) { - throw new InterestRelationCycleException(InterestRelationErrorCode.UNEXPECTED_CYCLE); - } - - if (isAlreadyVisited(visitedNodes, neighbor)) { - continue; - } - nodeQueue.addLast(neighbor); - } - } - } - } - - private boolean isCycleReturningToStart(UUID neighbor, UUID startNode) { - return neighbor.equals(startNode); - } - - private boolean isAlreadyVisited(Set visitedNodes, UUID currentNode) { - return visitedNodes.contains(currentNode); - } - - private void enhanceProficiencyOfParentInterests(Interest parentInterest, Interest childInterest) { - proficiencyService.adjust(parentInterest, childInterest.getProficiency().getTotalScore()); - } - - private void reduceProficiencyOfParentInterests(Interest parentInterest, Interest childInterest) { - proficiencyService.adjust(parentInterest, -1 * childInterest.getProficiency().getTotalScore()); - } -} diff --git a/src/main/java/com/gomo/app/core/interest/domain/service/InterestService.java b/src/main/java/com/gomo/app/core/interest/domain/service/InterestService.java deleted file mode 100644 index 35650871..00000000 --- a/src/main/java/com/gomo/app/core/interest/domain/service/InterestService.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.gomo.app.core.interest.domain.service; - -import java.util.UUID; - -import com.gomo.app.common.arch.DomainService; -import com.gomo.app.core.interest.domain.model.Interest; -import com.gomo.app.core.interest.domain.repository.InterestRepository; -import com.gomo.app.core.interest.exception.InterestNotFoundException; -import com.gomo.app.core.interest.exception.code.InterestErrorCode; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@DomainService -public class InterestService { - - private final InterestRepository interestRepository; - - public Interest find(UUID interestId) { - return interestRepository.findById(interestId) - .orElseThrow(() -> new InterestNotFoundException(InterestErrorCode.NOT_FOUND)); - } -} diff --git a/src/main/java/com/gomo/app/core/interest/domain/service/LogoService.java b/src/main/java/com/gomo/app/core/interest/domain/service/LogoService.java deleted file mode 100644 index 1c4786e2..00000000 --- a/src/main/java/com/gomo/app/core/interest/domain/service/LogoService.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.gomo.app.core.interest.domain.service; - -import java.util.HashSet; -import java.util.Set; - -import com.gomo.app.common.arch.DomainService; -import com.gomo.app.core.interest.domain.repository.InterestRepository; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@DomainService -public class LogoService { - - private final InterestRepository interestRepository; - - public Set findAllUrls() { - return new HashSet<>(interestRepository.findAllLogoUrl()); - } -} diff --git a/src/main/java/com/gomo/app/core/interest/domain/service/MajorInterestService.java b/src/main/java/com/gomo/app/core/interest/domain/service/MajorInterestService.java deleted file mode 100644 index 5cffcdf8..00000000 --- a/src/main/java/com/gomo/app/core/interest/domain/service/MajorInterestService.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.gomo.app.core.interest.domain.service; - -import java.util.UUID; - -import org.jetbrains.annotations.NotNull; - -import com.gomo.app.common.arch.DomainService; -import com.gomo.app.common.displayorder.DisplayOrder; -import com.gomo.app.common.util.UUIDGenerator; -import com.gomo.app.core.interest.domain.model.Interest; -import com.gomo.app.core.interest.domain.model.MajorInterest; -import com.gomo.app.core.interest.domain.repository.MajorInterestRepository; -import com.gomo.app.core.interest.exception.MajorInterestDuplicatedException; -import com.gomo.app.core.interest.exception.MajorInterestNotFoundException; -import com.gomo.app.core.interest.exception.code.MajorInterestErrorCode; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@DomainService -public class MajorInterestService { - - private final MajorInterestRepository majorInterestRepository; - - public MajorInterest create(Interest interest) { - ensureNotDuplicated(interest); - - int maxDisplayOrder = majorInterestRepository.findMaxDisplayOrder(interest.getRegistrantId()); - return majorInterestRepository.save(createMajorInterest(interest, maxDisplayOrder)); - } - - public MajorInterest find(UUID majorInterestId) { - return majorInterestRepository.findById(majorInterestId) - .orElseThrow(() -> new MajorInterestNotFoundException(MajorInterestErrorCode.NOT_FOUND)); - } - - private void ensureNotDuplicated(Interest interest) { - majorInterestRepository.findByInterestId(interest.getId()) - .ifPresent(exists -> { - throw new MajorInterestDuplicatedException(MajorInterestErrorCode.DUPLICATED); - }); - } - - @NotNull - private static MajorInterest createMajorInterest(Interest interest, int maxDisplayOrder) { - return MajorInterest.of( - UUIDGenerator.generate(), - interest.getRegistrantId(), - interest.getId(), - DisplayOrder.of(maxDisplayOrder + 1) - ); - } -} diff --git a/src/main/java/com/gomo/app/core/interest/domain/model/ProficiencyCalculator.java b/src/main/java/com/gomo/app/core/interest/domain/service/ProficiencyCalculator.java similarity index 76% rename from src/main/java/com/gomo/app/core/interest/domain/model/ProficiencyCalculator.java rename to src/main/java/com/gomo/app/core/interest/domain/service/ProficiencyCalculator.java index 03e6ee77..3288bf0f 100644 --- a/src/main/java/com/gomo/app/core/interest/domain/model/ProficiencyCalculator.java +++ b/src/main/java/com/gomo/app/core/interest/domain/service/ProficiencyCalculator.java @@ -1,25 +1,33 @@ -package com.gomo.app.core.interest.domain.model; +package com.gomo.app.core.interest.domain.service; import java.util.ArrayList; import java.util.List; -import com.gomo.app.common.arch.ValueObject; -import com.gomo.app.core.interest.exception.ProficiencyAdjustFailureException; -import com.gomo.app.core.interest.exception.code.ProficiencyErrorCode; +import com.gomo.app.common.arch.DomainService; +import com.gomo.app.core.interest.domain.exception.ProficiencyAdjustFailureException; +import com.gomo.app.core.interest.domain.exception.code.ProficiencyErrorCode; +import com.gomo.app.core.interest.domain.model.Level; +import com.gomo.app.core.interest.domain.model.LevelThresholdPolicy; +import com.gomo.app.core.interest.domain.model.Proficiency; +import com.gomo.app.core.interest.domain.model.Score; +import com.gomo.app.core.interest.domain.repository.LevelThresholdPolicyRepository; -@ValueObject +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@DomainService public class ProficiencyCalculator { - private final List policies; + private final LevelThresholdPolicyRepository levelThresholdPolicyRepository; + private List policies; - private ProficiencyCalculator(List levelThresholdPolicies) { + @PostConstruct + protected void initialize() { + List levelThresholdPolicies = levelThresholdPolicyRepository.findAll(); this.policies = convertToCalculatedPolicies(levelThresholdPolicies); } - public static ProficiencyCalculator from(List levelThresholdPolicies) { - return new ProficiencyCalculator(levelThresholdPolicies); - } - /** * Converts a list of {@link LevelThresholdPolicy} objects into * {@link CalculatedLevelPolicy} objects with cumulative scores. diff --git a/src/main/java/com/gomo/app/core/interest/domain/service/ProficiencyService.java b/src/main/java/com/gomo/app/core/interest/domain/service/ProficiencyService.java deleted file mode 100644 index 259ff7c6..00000000 --- a/src/main/java/com/gomo/app/core/interest/domain/service/ProficiencyService.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.gomo.app.core.interest.domain.service; - -import java.util.ArrayDeque; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.DomainService; -import com.gomo.app.core.interest.domain.model.Interest; -import com.gomo.app.core.interest.domain.model.InterestRelation; -import com.gomo.app.core.interest.domain.model.LevelThresholdPolicy; -import com.gomo.app.core.interest.domain.model.ProficiencyCalculator; -import com.gomo.app.core.interest.domain.repository.InterestRelationRepository; -import com.gomo.app.core.interest.domain.repository.InterestRepository; -import com.gomo.app.core.interest.domain.repository.LevelThresholdPolicyRepository; - -import jakarta.annotation.PostConstruct; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@DomainService -public class ProficiencyService { - - private final InterestRepository interestRepository; - private final InterestRelationRepository interestRelationRepository; - private final LevelThresholdPolicyRepository levelThresholdPolicyRepository; - private ProficiencyCalculator proficiencyCalculator; - - @PostConstruct - protected void initialize() { - List levelThresholdPolicies = levelThresholdPolicyRepository.findAll(); - proficiencyCalculator = ProficiencyCalculator.from(levelThresholdPolicies); - } - - @Transactional - public void adjust(Interest interest, int deltaTotalScore) { - Map> childToParentMap = buildChildToParentMap(interest.getRegistrantId()); - - Set adjustSuccessIds = new HashSet<>(); - ArrayDeque candidateInterests = new ArrayDeque<>(); - candidateInterests.addLast(interest); - while (!candidateInterests.isEmpty()) { - Interest current = candidateInterests.removeFirst(); - if (alreadyAdjustedInterest(current.getId(), adjustSuccessIds)) { - continue; - } - - adjustProficiency(current, deltaTotalScore, adjustSuccessIds, proficiencyCalculator); - enqueueParents(childToParentMap.get(current.getId()), candidateInterests, adjustSuccessIds); - } - } - - private void adjustProficiency(Interest interest, int deltaTotalScore, Set adjustSuccessIds, ProficiencyCalculator proficiencyCalculator) { - interest.adjustProficiency(deltaTotalScore, proficiencyCalculator); - adjustSuccessIds.add(interest.getId()); - } - - private void enqueueParents(Set parents, ArrayDeque queue, Set adjustSuccessIds) { - if (existParentInterests(parents)) { - for (Interest parent : parents) { - if (!alreadyAdjustedInterest(parent.getId(), adjustSuccessIds)) { - queue.addLast(parent); - } - } - } - } - - private boolean existParentInterests(Set parents) { - return parents != null; - } - - private boolean alreadyAdjustedInterest(UUID currentId, Set adjustSuccessIds) { - return adjustSuccessIds.contains(currentId); - } - - private Map> buildChildToParentMap(UUID registrantId) { - List allRelations = interestRelationRepository.findAllByRegistrantId(registrantId); - - Set interestIds = new HashSet<>(); - for (InterestRelation relation : allRelations) { - interestIds.add(relation.getChildInterestId()); - interestIds.add(relation.getParentInterestId()); - } - - List interests = interestRepository.findAllById(interestIds); - Map interestMap = new HashMap<>(); - for (Interest interest : interests) { - interestMap.put(interest.getId(), interest); - } - - Map> childToParentMap = new HashMap<>(); - for (InterestRelation relation : allRelations) { - UUID childId = relation.getChildInterestId(); - UUID parentId = relation.getParentInterestId(); - childToParentMap.computeIfAbsent(childId, k -> new HashSet<>()).add(interestMap.get(parentId)); - } - - return childToParentMap; - } -} diff --git a/src/main/java/com/gomo/app/core/member/presentation/HandleApi.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/HandleApi.java similarity index 56% rename from src/main/java/com/gomo/app/core/member/presentation/HandleApi.java rename to src/main/java/com/gomo/app/core/member/adapter/in/api/HandleApi.java index 16f9ff11..2e27104f 100644 --- a/src/main/java/com/gomo/app/core/member/presentation/HandleApi.java +++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/HandleApi.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.presentation; +package com.gomo.app.core.member.adapter.in.api; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -8,11 +8,11 @@ import org.springframework.web.bind.annotation.RequestParam; import com.gomo.app.common.arch.CoreApi; -import com.gomo.app.core.member.application.usecase.CheckHandleUseCase; -import com.gomo.app.core.member.application.usecase.UpdateHandleUseCase; -import com.gomo.app.core.member.presentation.request.UpdateHandleRequest; -import com.gomo.app.support.auth.presentation.security.Auth; -import com.gomo.app.support.auth.presentation.security.AuthInfo; +import com.gomo.app.core.member.adapter.in.api.request.UpdateHandleRequest; +import com.gomo.app.core.member.application.port.in.HandleUpdater; +import com.gomo.app.core.member.application.port.in.HandleValidator; +import com.gomo.app.core.auth.adapter.in.security.Auth; +import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -21,18 +21,18 @@ @CoreApi public class HandleApi { - private final CheckHandleUseCase checkHandleUseCase; - private final UpdateHandleUseCase updateHandleUseCase; + private final HandleValidator handleValidator; + private final HandleUpdater handleUpdater; @GetMapping("/duplicate") public ResponseEntity checkHandleDuplicated(@RequestParam String handle) { - checkHandleUseCase.checkHandleDuplicated(handle); + handleValidator.validateDuplicated(handle); return ResponseEntity.ok().build(); } @PutMapping public ResponseEntity update(@Auth AuthInfo authInfo, @RequestBody UpdateHandleRequest request) { - updateHandleUseCase.update(authInfo.getMemberId(), request.getHandle()); + handleUpdater.update(authInfo.getPrincipalId(), request.getHandle()); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/member/adapter/in/api/MemberApi.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/MemberApi.java new file mode 100644 index 00000000..028eb6be --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/MemberApi.java @@ -0,0 +1,48 @@ +package com.gomo.app.core.member.adapter.in.api; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; + +import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.core.member.adapter.in.api.request.UpdateMemberRequest; +import com.gomo.app.core.member.adapter.in.api.response.ReadMemberResponse; +import com.gomo.app.core.member.application.port.dto.MemberDto; +import com.gomo.app.core.member.application.port.in.MemberDeleter; +import com.gomo.app.core.member.application.port.in.MemberReader; +import com.gomo.app.core.member.application.port.in.MemberUpdater; +import com.gomo.app.core.auth.adapter.in.security.Auth; +import com.gomo.app.core.auth.adapter.in.security.AuthInfo; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@RequestMapping("/members") +@CoreApi +public class MemberApi { + + private final MemberReader memberReader; + private final MemberUpdater memberUpdater; + private final MemberDeleter memberDeleter; + + @GetMapping + public ResponseEntity read(@Auth AuthInfo authInfo) { + MemberDto dto = memberReader.read(authInfo.getPrincipalId()); + return ResponseEntity.ok(ReadMemberResponse.of(dto)); + } + + @PutMapping + public ResponseEntity update(@Auth AuthInfo authInfo, @RequestBody UpdateMemberRequest request) { + memberUpdater.update(authInfo.getPrincipalId(), request.getName(), request.getMotto()); + return ResponseEntity.noContent().build(); + } + + @DeleteMapping + public ResponseEntity delete(@Auth AuthInfo authInfo) { + memberDeleter.delete(authInfo.getPrincipalId()); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/com/gomo/app/core/member/adapter/in/api/PasswordApi.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/PasswordApi.java new file mode 100644 index 00000000..fe7cbb01 --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/PasswordApi.java @@ -0,0 +1,37 @@ +package com.gomo.app.core.member.adapter.in.api; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; + +import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.core.member.adapter.in.api.request.ResetPasswordRequest; +import com.gomo.app.core.member.adapter.in.api.request.UpdatePasswordRequest; +import com.gomo.app.core.member.application.port.in.PasswordResetter; +import com.gomo.app.core.member.application.port.in.PasswordUpdater; +import com.gomo.app.core.auth.adapter.in.security.Auth; +import com.gomo.app.core.auth.adapter.in.security.AuthInfo; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@RequestMapping("/members/passwords") +@CoreApi +public class PasswordApi { + + private final PasswordUpdater passwordUpdater; + private final PasswordResetter passwordResetter; + + @PutMapping + public ResponseEntity update(@Auth AuthInfo authInfo, @RequestBody UpdatePasswordRequest request) { + passwordUpdater.update(authInfo.getPrincipalId(), request.getOriginPassword(), request.getNewPassword()); + return ResponseEntity.noContent().build(); + } + + @PutMapping("/reset") + public ResponseEntity reset(@RequestBody ResetPasswordRequest request) { + passwordResetter.reset(request.getEmail(), request.getNewPassword(), request.getTemporaryToken()); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/com/gomo/app/core/member/presentation/ProfileBannerApi.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/ProfileBannerApi.java similarity index 55% rename from src/main/java/com/gomo/app/core/member/presentation/ProfileBannerApi.java rename to src/main/java/com/gomo/app/core/member/adapter/in/api/ProfileBannerApi.java index d638edb0..9ff540fe 100644 --- a/src/main/java/com/gomo/app/core/member/presentation/ProfileBannerApi.java +++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/ProfileBannerApi.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.presentation; +package com.gomo.app.core.member.adapter.in.api; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; @@ -8,11 +8,11 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; -import com.gomo.app.core.member.application.usecase.DeleteProfileBannerUseCase; -import com.gomo.app.core.member.application.usecase.UpdateProfileBannerUseCase; -import com.gomo.app.core.member.presentation.request.UpdateProfileBannerRequest; -import com.gomo.app.support.auth.presentation.security.Auth; -import com.gomo.app.support.auth.presentation.security.AuthInfo; +import com.gomo.app.core.member.adapter.in.api.request.UpdateProfileBannerRequest; +import com.gomo.app.core.member.application.port.in.ProfileBannerDeleter; +import com.gomo.app.core.member.application.port.in.ProfileBannerUpdater; +import com.gomo.app.core.auth.adapter.in.security.Auth; +import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -21,18 +21,18 @@ @CoreApi public class ProfileBannerApi { - private final UpdateProfileBannerUseCase updateProfileBannerUseCase; - private final DeleteProfileBannerUseCase deleteProfileBannerUseCase; + private final ProfileBannerUpdater profileBannerUpdater; + private final ProfileBannerDeleter profileBannerDeleter; @PutMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity update(@Auth AuthInfo authInfo, @ModelAttribute UpdateProfileBannerRequest request) { - updateProfileBannerUseCase.update(authInfo.getMemberId(), request.getProfileBanner()); + profileBannerUpdater.update(authInfo.getPrincipalId(), request.getProfileBanner()); return ResponseEntity.noContent().build(); } @DeleteMapping public ResponseEntity delete(@Auth AuthInfo authInfo) { - deleteProfileBannerUseCase.delete(authInfo.getMemberId()); + profileBannerDeleter.delete(authInfo.getPrincipalId()); return ResponseEntity.ok().build(); } } diff --git a/src/main/java/com/gomo/app/core/member/presentation/ProfileImageApi.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/ProfileImageApi.java similarity index 54% rename from src/main/java/com/gomo/app/core/member/presentation/ProfileImageApi.java rename to src/main/java/com/gomo/app/core/member/adapter/in/api/ProfileImageApi.java index e86a70c3..cc673a20 100644 --- a/src/main/java/com/gomo/app/core/member/presentation/ProfileImageApi.java +++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/ProfileImageApi.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.presentation; +package com.gomo.app.core.member.adapter.in.api; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; @@ -8,11 +8,11 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; -import com.gomo.app.core.member.application.usecase.DeleteProfileImageUseCase; -import com.gomo.app.core.member.application.usecase.UpdateProfileImageUseCase; -import com.gomo.app.core.member.presentation.request.UpdateProfileImageRequest; -import com.gomo.app.support.auth.presentation.security.Auth; -import com.gomo.app.support.auth.presentation.security.AuthInfo; +import com.gomo.app.core.member.adapter.in.api.request.UpdateProfileImageRequest; +import com.gomo.app.core.member.application.port.in.ProfileImageDeleter; +import com.gomo.app.core.member.application.port.in.ProfileImageUpdater; +import com.gomo.app.core.auth.adapter.in.security.Auth; +import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -21,18 +21,18 @@ @CoreApi public class ProfileImageApi { - private final UpdateProfileImageUseCase updateProfileImageUseCase; - private final DeleteProfileImageUseCase deleteProfileImageUseCase; + private final ProfileImageUpdater profileImageUpdater; + private final ProfileImageDeleter profileImageDeleter; @PutMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity update(@Auth AuthInfo authInfo, @ModelAttribute UpdateProfileImageRequest request) { - updateProfileImageUseCase.update(authInfo.getMemberId(), request.getProfileImage()); + profileImageUpdater.update(authInfo.getPrincipalId(), request.getProfileImage()); return ResponseEntity.noContent().build(); } @DeleteMapping public ResponseEntity delete(@Auth AuthInfo authInfo) { - deleteProfileImageUseCase.delete(authInfo.getMemberId()); + profileImageDeleter.delete(authInfo.getPrincipalId()); return ResponseEntity.ok().build(); } } diff --git a/src/main/java/com/gomo/app/core/member/presentation/QuestPropertyApi.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/QuestPropertyApi.java similarity index 51% rename from src/main/java/com/gomo/app/core/member/presentation/QuestPropertyApi.java rename to src/main/java/com/gomo/app/core/member/adapter/in/api/QuestPropertyApi.java index de43a640..f9019c49 100644 --- a/src/main/java/com/gomo/app/core/member/presentation/QuestPropertyApi.java +++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/QuestPropertyApi.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.presentation; +package com.gomo.app.core.member.adapter.in.api; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -7,13 +7,13 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.core.member.adapter.in.api.request.UpdateQuestPropertyRequest; +import com.gomo.app.core.member.adapter.in.api.response.ReadQuestPropertyResponse; import com.gomo.app.core.member.application.port.dto.QuestPropertyDto; -import com.gomo.app.core.member.application.usecase.ReadQuestPropertyUseCase; -import com.gomo.app.core.member.application.usecase.UpdateQuestPropertyUseCase; -import com.gomo.app.core.member.presentation.request.UpdateQuestPropertyRequest; -import com.gomo.app.core.member.presentation.response.ReadQuestPropertyResponse; -import com.gomo.app.support.auth.presentation.security.Auth; -import com.gomo.app.support.auth.presentation.security.AuthInfo; +import com.gomo.app.core.member.application.port.in.QuestPropertyReader; +import com.gomo.app.core.member.application.port.in.QuestPropertyUpdater; +import com.gomo.app.core.auth.adapter.in.security.Auth; +import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -22,18 +22,18 @@ @CoreApi public class QuestPropertyApi { - private final ReadQuestPropertyUseCase readQuestPropertyUseCase; - private final UpdateQuestPropertyUseCase updateQuestPropertyUseCase; + private final QuestPropertyReader questPropertyReader; + private final QuestPropertyUpdater questPropertyUpdater; @GetMapping public ResponseEntity find(@Auth AuthInfo authInfo) { - QuestPropertyDto dto = readQuestPropertyUseCase.find(authInfo.getMemberId()); + QuestPropertyDto dto = questPropertyReader.read(authInfo.getPrincipalId()); return ResponseEntity.ok(ReadQuestPropertyResponse.of(dto)); } @PutMapping public ResponseEntity update(@Auth AuthInfo authInfo, @RequestBody UpdateQuestPropertyRequest request) { - updateQuestPropertyUseCase.update(request.toCommand(authInfo.getMemberId())); + questPropertyUpdater.update(request.toCommand(authInfo.getPrincipalId())); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/member/presentation/WidgetApi.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/WidgetApi.java similarity index 54% rename from src/main/java/com/gomo/app/core/member/presentation/WidgetApi.java rename to src/main/java/com/gomo/app/core/member/adapter/in/api/WidgetApi.java index dddacec6..ecb23dbc 100644 --- a/src/main/java/com/gomo/app/core/member/presentation/WidgetApi.java +++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/WidgetApi.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.presentation; +package com.gomo.app.core.member.adapter.in.api; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PutMapping; @@ -6,10 +6,10 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; -import com.gomo.app.core.member.application.usecase.UpdateWidgetUseCase; -import com.gomo.app.core.member.presentation.request.UpdateWidgetRequest; -import com.gomo.app.support.auth.presentation.security.Auth; -import com.gomo.app.support.auth.presentation.security.AuthInfo; +import com.gomo.app.core.member.adapter.in.api.request.UpdateWidgetRequest; +import com.gomo.app.core.member.application.port.in.WidgetUpdater; +import com.gomo.app.core.auth.adapter.in.security.Auth; +import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -18,11 +18,11 @@ @CoreApi public class WidgetApi { - private final UpdateWidgetUseCase updateWidgetUseCase; + private final WidgetUpdater widgetUpdater; @PutMapping public ResponseEntity update(@Auth AuthInfo authInfo, @RequestBody UpdateWidgetRequest request) { - updateWidgetUseCase.update(authInfo.getMemberId(), request.getSnapshot()); + widgetUpdater.update(authInfo.getPrincipalId(), request.getSnapshot()); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/member/presentation/request/ResetPasswordRequest.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/request/ResetPasswordRequest.java similarity index 90% rename from src/main/java/com/gomo/app/core/member/presentation/request/ResetPasswordRequest.java rename to src/main/java/com/gomo/app/core/member/adapter/in/api/request/ResetPasswordRequest.java index 7b8a069f..8ced64cc 100644 --- a/src/main/java/com/gomo/app/core/member/presentation/request/ResetPasswordRequest.java +++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/request/ResetPasswordRequest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.presentation.request; +package com.gomo.app.core.member.adapter.in.api.request; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/member/presentation/request/UpdateHandleRequest.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/request/UpdateHandleRequest.java similarity index 78% rename from src/main/java/com/gomo/app/core/member/presentation/request/UpdateHandleRequest.java rename to src/main/java/com/gomo/app/core/member/adapter/in/api/request/UpdateHandleRequest.java index 7e35df0a..00b7b82e 100644 --- a/src/main/java/com/gomo/app/core/member/presentation/request/UpdateHandleRequest.java +++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/request/UpdateHandleRequest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.presentation.request; +package com.gomo.app.core.member.adapter.in.api.request; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/member/presentation/request/UpdateMemberRequest.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/request/UpdateMemberRequest.java similarity index 82% rename from src/main/java/com/gomo/app/core/member/presentation/request/UpdateMemberRequest.java rename to src/main/java/com/gomo/app/core/member/adapter/in/api/request/UpdateMemberRequest.java index 286cbe56..c06a95bc 100644 --- a/src/main/java/com/gomo/app/core/member/presentation/request/UpdateMemberRequest.java +++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/request/UpdateMemberRequest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.presentation.request; +package com.gomo.app.core.member.adapter.in.api.request; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/member/presentation/request/UpdatePasswordRequest.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/request/UpdatePasswordRequest.java similarity index 85% rename from src/main/java/com/gomo/app/core/member/presentation/request/UpdatePasswordRequest.java rename to src/main/java/com/gomo/app/core/member/adapter/in/api/request/UpdatePasswordRequest.java index 755ee30c..4dc89ff6 100644 --- a/src/main/java/com/gomo/app/core/member/presentation/request/UpdatePasswordRequest.java +++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/request/UpdatePasswordRequest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.presentation.request; +package com.gomo.app.core.member.adapter.in.api.request; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/member/presentation/request/UpdateProfileBannerRequest.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/request/UpdateProfileBannerRequest.java similarity index 84% rename from src/main/java/com/gomo/app/core/member/presentation/request/UpdateProfileBannerRequest.java rename to src/main/java/com/gomo/app/core/member/adapter/in/api/request/UpdateProfileBannerRequest.java index d38adbf1..43eeb78a 100644 --- a/src/main/java/com/gomo/app/core/member/presentation/request/UpdateProfileBannerRequest.java +++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/request/UpdateProfileBannerRequest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.presentation.request; +package com.gomo.app.core.member.adapter.in.api.request; import org.springframework.web.multipart.MultipartFile; diff --git a/src/main/java/com/gomo/app/core/member/presentation/request/UpdateProfileImageRequest.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/request/UpdateProfileImageRequest.java similarity index 84% rename from src/main/java/com/gomo/app/core/member/presentation/request/UpdateProfileImageRequest.java rename to src/main/java/com/gomo/app/core/member/adapter/in/api/request/UpdateProfileImageRequest.java index 41da9323..a7d77db4 100644 --- a/src/main/java/com/gomo/app/core/member/presentation/request/UpdateProfileImageRequest.java +++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/request/UpdateProfileImageRequest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.presentation.request; +package com.gomo.app.core.member.adapter.in.api.request; import org.springframework.web.multipart.MultipartFile; diff --git a/src/main/java/com/gomo/app/core/member/presentation/request/UpdateQuestPropertyRequest.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/request/UpdateQuestPropertyRequest.java similarity index 91% rename from src/main/java/com/gomo/app/core/member/presentation/request/UpdateQuestPropertyRequest.java rename to src/main/java/com/gomo/app/core/member/adapter/in/api/request/UpdateQuestPropertyRequest.java index 11a268c6..b15bbf51 100644 --- a/src/main/java/com/gomo/app/core/member/presentation/request/UpdateQuestPropertyRequest.java +++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/request/UpdateQuestPropertyRequest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.presentation.request; +package com.gomo.app.core.member.adapter.in.api.request; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/member/presentation/request/UpdateWidgetRequest.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/request/UpdateWidgetRequest.java similarity index 79% rename from src/main/java/com/gomo/app/core/member/presentation/request/UpdateWidgetRequest.java rename to src/main/java/com/gomo/app/core/member/adapter/in/api/request/UpdateWidgetRequest.java index ef9bdbda..762fd874 100644 --- a/src/main/java/com/gomo/app/core/member/presentation/request/UpdateWidgetRequest.java +++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/request/UpdateWidgetRequest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.presentation.request; +package com.gomo.app.core.member.adapter.in.api.request; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/member/presentation/response/ReadMemberResponse.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/response/ReadMemberResponse.java similarity index 93% rename from src/main/java/com/gomo/app/core/member/presentation/response/ReadMemberResponse.java rename to src/main/java/com/gomo/app/core/member/adapter/in/api/response/ReadMemberResponse.java index 75642d08..87cd98cf 100644 --- a/src/main/java/com/gomo/app/core/member/presentation/response/ReadMemberResponse.java +++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/response/ReadMemberResponse.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.presentation.response; +package com.gomo.app.core.member.adapter.in.api.response; import java.time.LocalDateTime; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/member/presentation/response/ReadQuestPropertyResponse.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/response/ReadQuestPropertyResponse.java similarity index 89% rename from src/main/java/com/gomo/app/core/member/presentation/response/ReadQuestPropertyResponse.java rename to src/main/java/com/gomo/app/core/member/adapter/in/api/response/ReadQuestPropertyResponse.java index c9045750..5d068e38 100644 --- a/src/main/java/com/gomo/app/core/member/presentation/response/ReadQuestPropertyResponse.java +++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/response/ReadQuestPropertyResponse.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.presentation.response; +package com.gomo.app.core.member.adapter.in.api.response; import com.gomo.app.core.member.application.port.dto.QuestPropertyDto; diff --git a/src/main/java/com/gomo/app/core/member/adapter/out/MemberEventPublisher.java b/src/main/java/com/gomo/app/core/member/adapter/out/MemberEventPublisher.java new file mode 100644 index 00000000..3339f114 --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/adapter/out/MemberEventPublisher.java @@ -0,0 +1,25 @@ +package com.gomo.app.core.member.adapter.out; + +import java.util.UUID; + +import com.gomo.app.common.arch.Adapter; +import com.gomo.app.core.member.application.port.out.MemberCreateEventPublisher; +import com.gomo.app.core.point.application.port.in.PointWalletCreator; +import com.gomo.app.core.streak.application.port.in.AchieverCreator; + +import lombok.RequiredArgsConstructor; + +// TODO [2025-10-29] jhl221123 : spring modulith 도입해 이벤트 기반 통신으로 전환한 후 제거해야합니다. +@RequiredArgsConstructor +@Adapter +class MemberEventPublisher implements MemberCreateEventPublisher { + + private final PointWalletCreator pointWalletCreator; + private final AchieverCreator achieverCreator; + + @Override + public void publish(UUID memberId) { + pointWalletCreator.create(memberId); + achieverCreator.create(memberId); + } +} diff --git a/src/main/java/com/gomo/app/core/member/adapter/out/client/AuthClient.java b/src/main/java/com/gomo/app/core/member/adapter/out/client/AuthClient.java new file mode 100644 index 00000000..53a4e701 --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/adapter/out/client/AuthClient.java @@ -0,0 +1,21 @@ +package com.gomo.app.core.member.adapter.out.client; + +import java.util.UUID; + +import com.gomo.app.common.arch.Adapter; +import com.gomo.app.core.member.application.port.out.MemberLogoutProcessor; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Adapter +class AuthClient implements MemberLogoutProcessor { + + // TODO [2025-11-02] jhl221123 : 회원 탈퇴 도메인 이벤트를 발행하고, 해당 클라이언트는 제거해야 모듈간 의존성 방향을 올바르게 유지할 수 있습니다. + // private final RefreshTokenDeleter refreshTokenDeleter; + + @Override + public void logout(UUID memberId) { + // refreshTokenDeleter.delete(memberId); + } +} diff --git a/src/main/java/com/gomo/app/core/member/adapter/out/client/EmailTokenClient.java b/src/main/java/com/gomo/app/core/member/adapter/out/client/EmailTokenClient.java new file mode 100644 index 00000000..39ddf001 --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/adapter/out/client/EmailTokenClient.java @@ -0,0 +1,24 @@ +package com.gomo.app.core.member.adapter.out.client; + +import com.gomo.app.common.arch.Adapter; +import com.gomo.app.core.member.application.port.out.EmailTokenVerifier; +import com.gomo.app.core.auth.application.port.out.JwtVerifier; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Adapter +class EmailTokenClient implements EmailTokenVerifier { + + private final JwtVerifier jwtVerifier; + + // TODO [2025-11-02] jhl221123 : 인증 모듈의 책임입니다. + @Override + public void verify(String temporaryToken) { + // TODO [2025-10-18] jhl221123 : jwt 형식 뿐 아니라 내부 이메일이 요청한 이메일과 같은지 검증이 필요합니다. + // TODO [2025-10-19] jhl221123 : 커스텀 예외를 반환하도록 수정해야합니다. + if (!jwtVerifier.verify(temporaryToken)) { + throw new IllegalArgumentException("Invalid temporary token"); + } + } +} diff --git a/src/main/java/com/gomo/app/core/member/adapter/out/client/PointBalanceClient.java b/src/main/java/com/gomo/app/core/member/adapter/out/client/PointBalanceClient.java new file mode 100644 index 00000000..a6d6565e --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/adapter/out/client/PointBalanceClient.java @@ -0,0 +1,21 @@ +package com.gomo.app.core.member.adapter.out.client; + +import java.util.UUID; + +import com.gomo.app.common.arch.Adapter; +import com.gomo.app.core.member.application.port.out.PointBalanceReader; +import com.gomo.app.core.point.application.port.in.BalanceReader; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Adapter +class PointBalanceClient implements PointBalanceReader { + + private final BalanceReader balanceReader; + + @Override + public int read(UUID memberId) { + return balanceReader.read(memberId); + } +} diff --git a/src/main/java/com/gomo/app/core/member/adapter/out/client/ProfileAssetClient.java b/src/main/java/com/gomo/app/core/member/adapter/out/client/ProfileAssetClient.java new file mode 100644 index 00000000..0003ccd5 --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/adapter/out/client/ProfileAssetClient.java @@ -0,0 +1,21 @@ +package com.gomo.app.core.member.adapter.out.client; + +import org.springframework.web.multipart.MultipartFile; + +import com.gomo.app.common.arch.Adapter; +import com.gomo.app.core.member.application.port.out.ProfileAssetUploader; +import com.gomo.app.support.image.application.port.in.ImageUploader; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Adapter +class ProfileAssetClient implements ProfileAssetUploader { + + private final ImageUploader imageUploader; + + @Override + public String upload(MultipartFile image) { + return imageUploader.upload(image).orElse(null); + } +} diff --git a/src/main/java/com/gomo/app/core/member/adapter/out/lib/BcryptEncoder.java b/src/main/java/com/gomo/app/core/member/adapter/out/lib/BcryptEncoder.java new file mode 100644 index 00000000..6f8f4fb0 --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/adapter/out/lib/BcryptEncoder.java @@ -0,0 +1,25 @@ +package com.gomo.app.core.member.adapter.out.lib; + +import org.springframework.security.crypto.password.PasswordEncoder; + +import com.gomo.app.common.arch.Adapter; +import com.gomo.app.core.member.application.port.out.PasswordEncodeManager; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Adapter +class BcryptEncoder implements PasswordEncodeManager { + + private final PasswordEncoder passwordEncoder; + + @Override + public String encode(String rawPassword) { + return passwordEncoder.encode(rawPassword); + } + + @Override + public boolean verify(String rawPassword, String encodedPassword) { + return passwordEncoder.matches(rawPassword, encodedPassword); + } +} diff --git a/src/main/java/com/gomo/app/core/member/application/port/LoginMemberPortIn.java b/src/main/java/com/gomo/app/core/member/application/port/LoginMemberPortIn.java deleted file mode 100644 index ba2a2f16..00000000 --- a/src/main/java/com/gomo/app/core/member/application/port/LoginMemberPortIn.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.gomo.app.core.member.application.port; - -import java.util.UUID; - -import com.gomo.app.core.member.exception.MemberAuthenticationFailedException; - -public interface LoginMemberPortIn { - - /** - * Authenticates a member using their email and password. - * - * @param email The member's email address. - * @param password The member's plain-text password for verification. - * @return The id (UUID) of the successfully authenticated member. - * @throws MemberAuthenticationFailedException if the credentials do not match. - */ - UUID authenticate(String email, String password); -} diff --git a/src/main/java/com/gomo/app/core/member/application/port/ReadActiveMemberPortIn.java b/src/main/java/com/gomo/app/core/member/application/port/ReadActiveMemberPortIn.java deleted file mode 100644 index 29fd1ca8..00000000 --- a/src/main/java/com/gomo/app/core/member/application/port/ReadActiveMemberPortIn.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.gomo.app.core.member.application.port; - -import java.time.LocalDate; -import java.util.List; - -import com.gomo.app.core.member.application.port.dto.ActiveMemberDto; - -public interface ReadActiveMemberPortIn { - - /** - * Retrieves a list of members who are considered active and have logged in on or after the specified date. - * - * @param loginCutoffDate The reference date. The query will find members who have logged in - * on or after this date. - * @return A list of {@link ActiveMemberDto}s. Returns an empty list if no active - * members match the criteria; this method does not return null. - */ - List findAll(LocalDate loginCutoffDate); -} diff --git a/src/main/java/com/gomo/app/core/member/application/port/command/CreateMemberCommand.java b/src/main/java/com/gomo/app/core/member/application/port/command/CreateMemberCommand.java index 64b54ba5..3c20927f 100644 --- a/src/main/java/com/gomo/app/core/member/application/port/command/CreateMemberCommand.java +++ b/src/main/java/com/gomo/app/core/member/application/port/command/CreateMemberCommand.java @@ -1,8 +1,8 @@ package com.gomo.app.core.member.application.port.command; -public record CreateMemberCommand(String email, String rawPassword, String handle, String name, String motto, String loginProvider, String temporaryToken) { +public record CreateMemberCommand(String email, String password, String handle, String name, String motto, String loginProvider) { - public static CreateMemberCommand of(String email, String rawPassword, String handle, String name, String motto, String loginProvider, String temporaryToken) { - return new CreateMemberCommand(email, rawPassword, handle, name, motto, loginProvider, temporaryToken); + public static CreateMemberCommand of(String email, String rawPassword, String handle, String name, String motto, String loginProvider) { + return new CreateMemberCommand(email, rawPassword, handle, name, motto, loginProvider); } } diff --git a/src/main/java/com/gomo/app/core/member/application/port/dto/UpdateProfileBannerDto.java b/src/main/java/com/gomo/app/core/member/application/port/dto/UpdateProfileBannerDto.java deleted file mode 100644 index d4e587cd..00000000 --- a/src/main/java/com/gomo/app/core/member/application/port/dto/UpdateProfileBannerDto.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.gomo.app.core.member.application.port.dto; - -public record UpdateProfileBannerDto(String profileBannerUrl) { - - public static UpdateProfileBannerDto of(String profileBannerUrl) { - return new UpdateProfileBannerDto(profileBannerUrl); - } -} diff --git a/src/main/java/com/gomo/app/core/member/application/port/dto/UpdateProfileImageDto.java b/src/main/java/com/gomo/app/core/member/application/port/dto/UpdateProfileImageDto.java deleted file mode 100644 index 9dfe600a..00000000 --- a/src/main/java/com/gomo/app/core/member/application/port/dto/UpdateProfileImageDto.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.gomo.app.core.member.application.port.dto; - -public record UpdateProfileImageDto(String profileImageUrl) { - - public static UpdateProfileImageDto of(String profileImageUrl) { - return new UpdateProfileImageDto(profileImageUrl); - } -} diff --git a/src/main/java/com/gomo/app/core/member/application/port/in/EmailChecker.java b/src/main/java/com/gomo/app/core/member/application/port/in/EmailChecker.java new file mode 100644 index 00000000..db618619 --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/port/in/EmailChecker.java @@ -0,0 +1,16 @@ +package com.gomo.app.core.member.application.port.in; + +import com.gomo.app.core.member.domain.exception.EmailConstraintViolationException; + +public interface EmailChecker { + + /** + * Checks if an email address is already registered by a member. + * This method also implicitly validates the format of the email string. + * + * @param email The email address to check. + * @return {@code true} if a member with the specified email already exists, {@code false} otherwise. + * @throws EmailConstraintViolationException if the provided email string does not follow a valid email format. + */ + boolean exists(String email); +} diff --git a/src/main/java/com/gomo/app/core/member/application/port/in/HandleUpdater.java b/src/main/java/com/gomo/app/core/member/application/port/in/HandleUpdater.java new file mode 100644 index 00000000..ca583496 --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/port/in/HandleUpdater.java @@ -0,0 +1,20 @@ +package com.gomo.app.core.member.application.port.in; + +import java.util.UUID; + +import com.gomo.app.core.member.domain.exception.HandleDuplicatedException; +import com.gomo.app.core.member.domain.exception.MemberNotFoundException; + +public interface HandleUpdater { + + /** + * Updates the handle for a specific member. + * It ensures the new handle is not already in use before applying the change. + * + * @param memberId The ID of the member whose handle is to be updated. + * @param handle The new handle to be set. + * @throws MemberNotFoundException if no member is found with the provided ID. + * @throws HandleDuplicatedException if the new handle is already in use by another member. + */ + void update(UUID memberId, String handle); +} diff --git a/src/main/java/com/gomo/app/core/member/application/port/in/HandleValidator.java b/src/main/java/com/gomo/app/core/member/application/port/in/HandleValidator.java new file mode 100644 index 00000000..8534a4e3 --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/port/in/HandleValidator.java @@ -0,0 +1,14 @@ +package com.gomo.app.core.member.application.port.in; + +import com.gomo.app.core.member.domain.exception.HandleDuplicatedException; + +public interface HandleValidator { + + /** + * Validates for the duplication of a member handle to ensure its uniqueness. + * + * @param handle The handle to be checked for duplication. + * @throws HandleDuplicatedException if the provided handle is already in use by another member. + */ + void validateDuplicated(String handle); +} diff --git a/src/main/java/com/gomo/app/core/member/application/port/in/MemberCreator.java b/src/main/java/com/gomo/app/core/member/application/port/in/MemberCreator.java new file mode 100644 index 00000000..9f4722ae --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/port/in/MemberCreator.java @@ -0,0 +1,20 @@ +package com.gomo.app.core.member.application.port.in; + +import java.util.UUID; + +import com.gomo.app.core.member.application.port.command.CreateMemberCommand; +import com.gomo.app.core.member.domain.exception.EmailDuplicatedException; +import com.gomo.app.core.member.domain.exception.HandleDuplicatedException; + +public interface MemberCreator { + + /** + * Creates a new member, validates their information, and publishes an event upon successful creation. + * + * @param command A {@link CreateMemberCommand} object containing all necessary information for member. + * @return The {@link UUID} of the newly created member. + * @throws EmailDuplicatedException if the provided email is already registered. + * @throws HandleDuplicatedException if the provided handle is already in use. + */ + UUID create(CreateMemberCommand command); +} diff --git a/src/main/java/com/gomo/app/core/member/application/port/in/MemberDeleter.java b/src/main/java/com/gomo/app/core/member/application/port/in/MemberDeleter.java new file mode 100644 index 00000000..0250117b --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/port/in/MemberDeleter.java @@ -0,0 +1,16 @@ +package com.gomo.app.core.member.application.port.in; + +import java.util.UUID; + +import com.gomo.app.core.member.domain.exception.MemberNotFoundException; + +public interface MemberDeleter { + + /** + * Deletes a member's account and performs associated cleanup tasks, such as deleting authentication tokens. + * + * @param memberId The ID of the member to be deleted. + * @throws MemberNotFoundException if no member is found with the provided ID. + */ + void delete(UUID memberId); +} diff --git a/src/main/java/com/gomo/app/core/member/application/port/in/MemberLoginProcessor.java b/src/main/java/com/gomo/app/core/member/application/port/in/MemberLoginProcessor.java new file mode 100644 index 00000000..2728210e --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/port/in/MemberLoginProcessor.java @@ -0,0 +1,18 @@ +package com.gomo.app.core.member.application.port.in; + +import java.util.UUID; + +import com.gomo.app.core.member.domain.exception.MemberAuthenticationFailedException; + +public interface MemberLoginProcessor { + + /** + * Login a member using their email and password. + * + * @param email The member's email address. + * @param password The member's plain-text password for verification. + * @return The id (UUID) of the login member. + * @throws MemberAuthenticationFailedException if the credentials do not match. + */ + UUID login(String email, String password); +} diff --git a/src/main/java/com/gomo/app/core/member/application/port/OAuthLoginMemberPortIn.java b/src/main/java/com/gomo/app/core/member/application/port/in/MemberOAuthLoginProcessor.java similarity index 60% rename from src/main/java/com/gomo/app/core/member/application/port/OAuthLoginMemberPortIn.java rename to src/main/java/com/gomo/app/core/member/application/port/in/MemberOAuthLoginProcessor.java index 3b11c01e..c92d1273 100644 --- a/src/main/java/com/gomo/app/core/member/application/port/OAuthLoginMemberPortIn.java +++ b/src/main/java/com/gomo/app/core/member/application/port/in/MemberOAuthLoginProcessor.java @@ -1,16 +1,16 @@ -package com.gomo.app.core.member.application.port; +package com.gomo.app.core.member.application.port.in; import java.util.Optional; import java.util.UUID; -public interface OAuthLoginMemberPortIn { +public interface MemberOAuthLoginProcessor { /** - * Authenticates a member using an email address obtained from an OAuth provider. + * Login a member using an email address obtained from an OAuth provider. * * @param email The email address provided by the OAuth identity provider. * @return An {@code Optional} containing the member's id (UUID) if a corresponding member is found. * Returns an empty {@code Optional} if no member is associated with the provided email. */ - Optional oauthAuthenticate(String email); + Optional login(String email); } diff --git a/src/main/java/com/gomo/app/core/member/application/port/ReadMemberPortIn.java b/src/main/java/com/gomo/app/core/member/application/port/in/MemberReader.java similarity index 65% rename from src/main/java/com/gomo/app/core/member/application/port/ReadMemberPortIn.java rename to src/main/java/com/gomo/app/core/member/application/port/in/MemberReader.java index 2e6ca25c..dd3e85b2 100644 --- a/src/main/java/com/gomo/app/core/member/application/port/ReadMemberPortIn.java +++ b/src/main/java/com/gomo/app/core/member/application/port/in/MemberReader.java @@ -1,11 +1,11 @@ -package com.gomo.app.core.member.application.port; +package com.gomo.app.core.member.application.port.in; import java.util.UUID; import com.gomo.app.core.member.application.port.dto.MemberDto; -import com.gomo.app.core.member.exception.MemberNotFoundException; +import com.gomo.app.core.member.domain.exception.MemberNotFoundException; -public interface ReadMemberPortIn { +public interface MemberReader { /** * Retrieves a specific member by id. @@ -14,5 +14,5 @@ public interface ReadMemberPortIn { * @return A {@link MemberDto} containing the member's information. * @throws MemberNotFoundException if no member with the specified ID can be found. */ - MemberDto find(UUID id); + MemberDto read(UUID id); } diff --git a/src/main/java/com/gomo/app/core/member/application/port/in/MemberUpdater.java b/src/main/java/com/gomo/app/core/member/application/port/in/MemberUpdater.java new file mode 100644 index 00000000..2d15acfe --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/port/in/MemberUpdater.java @@ -0,0 +1,18 @@ +package com.gomo.app.core.member.application.port.in; + +import java.util.UUID; + +import com.gomo.app.core.member.domain.exception.MemberNotFoundException; + +public interface MemberUpdater { + + /** + * Updates the basic information (name and motto) for a specific member. + * + * @param id The ID of the member to be updated. + * @param name The new name to be set. + * @param motto The new motto to be set. + * @throws MemberNotFoundException if no member is found with the provided ID. + */ + void update(UUID id, String name, String motto); +} diff --git a/src/main/java/com/gomo/app/core/member/application/port/in/PasswordResetter.java b/src/main/java/com/gomo/app/core/member/application/port/in/PasswordResetter.java new file mode 100644 index 00000000..f69e19b2 --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/port/in/PasswordResetter.java @@ -0,0 +1,17 @@ +package com.gomo.app.core.member.application.port.in; + +import com.gomo.app.core.member.domain.exception.MemberNotFoundException; + +public interface PasswordResetter { + + /** + * Resets the password for a member after validating a temporary token. + * + * @param email The email address of the member for whom the password reset is being performed. + * @param newPassword The new raw password to be set. + * @param temporaryToken The verification token required to authorize the password change. + * @throws MemberNotFoundException if no member is found with the specified email address. + * @throws IllegalArgumentException if the provided temporary token is invalid. + */ + void reset(String email, String newPassword, String temporaryToken); +} diff --git a/src/main/java/com/gomo/app/core/member/application/port/in/PasswordUpdater.java b/src/main/java/com/gomo/app/core/member/application/port/in/PasswordUpdater.java new file mode 100644 index 00000000..ed00e7bb --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/port/in/PasswordUpdater.java @@ -0,0 +1,20 @@ +package com.gomo.app.core.member.application.port.in; + +import java.util.UUID; + +import com.gomo.app.core.member.domain.exception.MemberAuthenticationFailedException; +import com.gomo.app.core.member.domain.exception.MemberNotFoundException; + +public interface PasswordUpdater { + + /** + * Updates the password for a specific member after verifying their current password. + * + * @param memberId The ID of the member whose password is to be updated. + * @param originPassword The member's current (original) password for verification. + * @param newPassword The new password to be set. + * @throws MemberNotFoundException if no member is found with the provided ID. + * @throws MemberAuthenticationFailedException if the provided original password does not match the member's current password. + */ + void update(UUID memberId, String originPassword, String newPassword); +} diff --git a/src/main/java/com/gomo/app/core/member/application/port/in/ProfileBannerDeleter.java b/src/main/java/com/gomo/app/core/member/application/port/in/ProfileBannerDeleter.java new file mode 100644 index 00000000..6c7ec38c --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/port/in/ProfileBannerDeleter.java @@ -0,0 +1,16 @@ +package com.gomo.app.core.member.application.port.in; + +import java.util.UUID; + +import com.gomo.app.core.member.domain.exception.MemberNotFoundException; + +public interface ProfileBannerDeleter { + + /** + * Deletes the profile banner for a specific member, reverting it to the default. + * + * @param memberId The ID of the member whose profile banner is to be deleted. + * @throws MemberNotFoundException if no member is found with the provided ID. + */ + void delete(UUID memberId); +} diff --git a/src/main/java/com/gomo/app/core/member/application/port/in/ProfileBannerUpdater.java b/src/main/java/com/gomo/app/core/member/application/port/in/ProfileBannerUpdater.java new file mode 100644 index 00000000..ed415a62 --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/port/in/ProfileBannerUpdater.java @@ -0,0 +1,19 @@ +package com.gomo.app.core.member.application.port.in; + +import java.util.UUID; + +import org.springframework.web.multipart.MultipartFile; + +import com.gomo.app.core.member.domain.exception.MemberNotFoundException; + +public interface ProfileBannerUpdater { + + /** + * Updates the profile banner for a specific member by uploading a new image. + * + * @param memberId The ID of the member whose profile banner is to be updated. + * @param profileBanner The new banner image file to be uploaded. + * @throws MemberNotFoundException if no member is found with the provided ID. + */ + void update(UUID memberId, MultipartFile profileBanner); +} diff --git a/src/main/java/com/gomo/app/core/member/application/port/in/ProfileImageDeleter.java b/src/main/java/com/gomo/app/core/member/application/port/in/ProfileImageDeleter.java new file mode 100644 index 00000000..6bde1b77 --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/port/in/ProfileImageDeleter.java @@ -0,0 +1,16 @@ +package com.gomo.app.core.member.application.port.in; + +import java.util.UUID; + +import com.gomo.app.core.member.domain.exception.MemberNotFoundException; + +public interface ProfileImageDeleter { + + /** + * Deletes the profile image for a specific member, reverting it to the default. + * + * @param memberId The ID of the member whose profile image is to be deleted. + * @throws MemberNotFoundException if no member is found with the provided ID. + */ + void delete(UUID memberId); +} diff --git a/src/main/java/com/gomo/app/core/member/application/port/in/ProfileImageUpdater.java b/src/main/java/com/gomo/app/core/member/application/port/in/ProfileImageUpdater.java new file mode 100644 index 00000000..93152580 --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/port/in/ProfileImageUpdater.java @@ -0,0 +1,19 @@ +package com.gomo.app.core.member.application.port.in; + +import java.util.UUID; + +import org.springframework.web.multipart.MultipartFile; + +import com.gomo.app.core.member.domain.exception.MemberNotFoundException; + +public interface ProfileImageUpdater { + + /** + * Updates the profile image for a specific member by uploading a new image. + * + * @param memberId The ID of the member whose profile image is to be updated. + * @param profileImage The new profile image file to be uploaded. + * @throws MemberNotFoundException if no member is found with the provided ID. + */ + void update(UUID memberId, MultipartFile profileImage); +} diff --git a/src/main/java/com/gomo/app/core/member/application/port/in/QuestPropertyReader.java b/src/main/java/com/gomo/app/core/member/application/port/in/QuestPropertyReader.java new file mode 100644 index 00000000..b51664c8 --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/port/in/QuestPropertyReader.java @@ -0,0 +1,18 @@ +package com.gomo.app.core.member.application.port.in; + +import java.util.UUID; + +import com.gomo.app.core.member.application.port.dto.QuestPropertyDto; +import com.gomo.app.core.member.domain.exception.MemberNotFoundException; + +public interface QuestPropertyReader { + + /** + * Retrieves the quest-related properties for a specific member. + * + * @param memberId The ID of the member whose quest properties are to be retrieved. + * @return A {@link QuestPropertyDto} containing the member's quest properties. + * @throws MemberNotFoundException if no member is found with the provided ID. + */ + QuestPropertyDto read(UUID memberId); +} diff --git a/src/main/java/com/gomo/app/core/member/application/port/in/QuestPropertyUpdater.java b/src/main/java/com/gomo/app/core/member/application/port/in/QuestPropertyUpdater.java new file mode 100644 index 00000000..8cce8b93 --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/port/in/QuestPropertyUpdater.java @@ -0,0 +1,15 @@ +package com.gomo.app.core.member.application.port.in; + +import com.gomo.app.core.member.application.port.command.UpdateQuestPropertyCommand; +import com.gomo.app.core.member.domain.exception.MemberNotFoundException; + +public interface QuestPropertyUpdater { + + /** + * Updates the quest-related properties for a specific member. + * + * @param command A {@link UpdateQuestPropertyCommand} containing the member's ID and the new quest property values. + * @throws MemberNotFoundException if no member is found with the ID provided in the command. + */ + void update(UpdateQuestPropertyCommand command); +} diff --git a/src/main/java/com/gomo/app/core/member/application/port/in/WidgetUpdater.java b/src/main/java/com/gomo/app/core/member/application/port/in/WidgetUpdater.java new file mode 100644 index 00000000..9901c546 --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/port/in/WidgetUpdater.java @@ -0,0 +1,18 @@ +package com.gomo.app.core.member.application.port.in; + +import java.util.UUID; + +import com.gomo.app.core.member.domain.exception.MemberNotFoundException; + +public interface WidgetUpdater { + + /** + * Updates the widget snapshot for a specific member. + * The snapshot typically contains the state or configuration of a UI widget. + * + * @param memberId The ID of the member whose widget snapshot is to be updated. + * @param snapshot The new widget snapshot, likely in a serialized format like JSON. + * @throws MemberNotFoundException if no member is found with the provided ID. + */ + void update(UUID memberId, String snapshot); +} diff --git a/src/main/java/com/gomo/app/core/member/application/port/out/EmailTokenVerifier.java b/src/main/java/com/gomo/app/core/member/application/port/out/EmailTokenVerifier.java new file mode 100644 index 00000000..d699a6db --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/port/out/EmailTokenVerifier.java @@ -0,0 +1,14 @@ +package com.gomo.app.core.member.application.port.out; + +public interface EmailTokenVerifier { + + // TODO [2025-11-02] jhl221123 : 인증 모듈의 책임입니다. + + /** + * Verifies the validity of a temporary token, typically used for processes like email verification. + * + * @param temporaryToken The temporary token string to be validated. + * @throws IllegalArgumentException if the token is invalid, expired, or malformed. + */ + void verify(String temporaryToken); +} diff --git a/src/main/java/com/gomo/app/core/member/application/port/out/MemberCreateEventPublisher.java b/src/main/java/com/gomo/app/core/member/application/port/out/MemberCreateEventPublisher.java new file mode 100644 index 00000000..eff873b7 --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/port/out/MemberCreateEventPublisher.java @@ -0,0 +1,9 @@ +package com.gomo.app.core.member.application.port.out; + +import java.util.UUID; + +public interface MemberCreateEventPublisher { + + // TODO [2025-10-29] jhl221123 : spring modulith 도입해 이벤트 기반 통신으로 전환한 후 제거해야합니다. + void publish(UUID memberId); +} diff --git a/src/main/java/com/gomo/app/core/member/application/port/out/MemberLogoutProcessor.java b/src/main/java/com/gomo/app/core/member/application/port/out/MemberLogoutProcessor.java new file mode 100644 index 00000000..7c7a45fa --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/port/out/MemberLogoutProcessor.java @@ -0,0 +1,13 @@ +package com.gomo.app.core.member.application.port.out; + +import java.util.UUID; + +public interface MemberLogoutProcessor { + + /** + * Invalidates the authentication session for a specific member. + * + * @param memberId The ID of the member whose authentication session is to be invalidated. + */ + void logout(UUID memberId); +} diff --git a/src/main/java/com/gomo/app/core/member/application/port/out/PasswordEncodeManager.java b/src/main/java/com/gomo/app/core/member/application/port/out/PasswordEncodeManager.java new file mode 100644 index 00000000..66316c4d --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/port/out/PasswordEncodeManager.java @@ -0,0 +1,21 @@ +package com.gomo.app.core.member.application.port.out; + +public interface PasswordEncodeManager { + + /** + * Encodes a given plain-text password. + * + * @param rawPassword The plain-text password to be encoded. + * @return The resulting encoded (hashed and salted) password as a string. + */ + String encode(String rawPassword); + + /** + * Verifies if a raw password matches a stored, encoded password. + * + * @param rawPassword The plain-text password submitted for verification. + * @param encodedPassword The stored, encoded password from the database to compare against. + * @return {@code true} if the raw password matches the encoded password, {@code false} otherwise. + */ + boolean verify(String rawPassword, String encodedPassword); +} diff --git a/src/main/java/com/gomo/app/core/member/application/port/out/PointBalanceReader.java b/src/main/java/com/gomo/app/core/member/application/port/out/PointBalanceReader.java new file mode 100644 index 00000000..8b1d8a7f --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/port/out/PointBalanceReader.java @@ -0,0 +1,14 @@ +package com.gomo.app.core.member.application.port.out; + +import java.util.UUID; + +public interface PointBalanceReader { + + /** + * Retrieves the current point balance for a specific member. + * + * @param memberId The ID of the member whose point balance is to be retrieved. + * @return The current point balance as an integer. + */ + int read(UUID memberId); +} diff --git a/src/main/java/com/gomo/app/core/member/application/port/out/ProfileAssetUploader.java b/src/main/java/com/gomo/app/core/member/application/port/out/ProfileAssetUploader.java new file mode 100644 index 00000000..7a64bd72 --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/port/out/ProfileAssetUploader.java @@ -0,0 +1,14 @@ +package com.gomo.app.core.member.application.port.out; + +import org.springframework.web.multipart.MultipartFile; + +public interface ProfileAssetUploader { + + /** + * Uploads a given image file, typically for a member's profile or banner. + * + * @param file The image file to be uploaded. + * @return The URL of the uploaded image as a {@link String}. Returns null if the file is empty or null. + */ + String upload(MultipartFile file); +} diff --git a/src/main/java/com/gomo/app/core/member/application/service/EmailService.java b/src/main/java/com/gomo/app/core/member/application/service/EmailService.java new file mode 100644 index 00000000..06b049ed --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/service/EmailService.java @@ -0,0 +1,29 @@ +package com.gomo.app.core.member.application.service; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.core.member.application.port.in.EmailChecker; +import com.gomo.app.core.member.domain.exception.EmailDuplicatedException; +import com.gomo.app.core.member.domain.exception.code.EmailErrorCode; +import com.gomo.app.core.member.domain.model.Email; +import com.gomo.app.core.member.domain.repository.MemberRepository; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@ApplicationService +class EmailService implements EmailChecker { + + private final MemberRepository memberRepository; + + void validateDuplicated(String email) { + memberRepository.findByEmail(Email.of(email)).ifPresent(m -> { + throw new EmailDuplicatedException(EmailErrorCode.DUPLICATED); + }); + } + + @Override + public boolean exists(String email) { + Email verifiedEmail = Email.of(email); + return memberRepository.findByEmail(verifiedEmail).isPresent(); + } +} diff --git a/src/main/java/com/gomo/app/core/member/application/service/HandleService.java b/src/main/java/com/gomo/app/core/member/application/service/HandleService.java new file mode 100644 index 00000000..945916db --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/service/HandleService.java @@ -0,0 +1,42 @@ +package com.gomo.app.core.member.application.service; + +import java.util.UUID; + +import org.springframework.transaction.annotation.Transactional; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.core.member.application.port.in.HandleUpdater; +import com.gomo.app.core.member.application.port.in.HandleValidator; +import com.gomo.app.core.member.domain.exception.HandleDuplicatedException; +import com.gomo.app.core.member.domain.exception.code.HandleErrorCode; +import com.gomo.app.core.member.domain.model.Handle; +import com.gomo.app.core.member.domain.model.Member; +import com.gomo.app.core.member.domain.repository.MemberRepository; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Transactional +@ApplicationService +class HandleService implements HandleUpdater, HandleValidator { + + private final MemberService memberService; + private final MemberRepository memberRepository; + + @Override + @AuditLog(action = "UPDATE_HANDLE") + public void update(UUID memberId, String handle) { + Member member = memberService.findById(memberId); + validateDuplicated(handle); + member.updateHandle(handle); + } + + @Override + @Transactional(readOnly = true) + public void validateDuplicated(String handle) { + memberRepository.findByHandle(Handle.of(handle)).ifPresent(m -> { + throw new HandleDuplicatedException(HandleErrorCode.DUPLICATED); + }); + } +} diff --git a/src/main/java/com/gomo/app/core/member/application/service/MemberCreateService.java b/src/main/java/com/gomo/app/core/member/application/service/MemberCreateService.java new file mode 100644 index 00000000..6f3cbfb5 --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/service/MemberCreateService.java @@ -0,0 +1,59 @@ +package com.gomo.app.core.member.application.service; + +import java.util.UUID; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.common.util.UUIDGenerator; +import com.gomo.app.core.member.application.port.command.CreateMemberCommand; +import com.gomo.app.core.member.application.port.in.MemberCreator; +import com.gomo.app.core.member.application.port.out.MemberCreateEventPublisher; +import com.gomo.app.core.member.domain.model.Email; +import com.gomo.app.core.member.domain.model.Handle; +import com.gomo.app.core.member.domain.model.LoginProvider; +import com.gomo.app.core.member.domain.model.Member; +import com.gomo.app.core.member.domain.model.MemberName; +import com.gomo.app.core.member.domain.model.Motto; +import com.gomo.app.core.member.domain.model.Password; +import com.gomo.app.core.member.domain.repository.MemberRepository; + +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Transactional +@ApplicationService +class MemberCreateService implements MemberCreator { + + private final PasswordService passwordService; + private final HandleService handleService; + private final EmailService emailService; + private final MemberCreateEventPublisher memberCreateEventPublisher; + private final MemberRepository memberRepository; + + @Override + @AuditLog(action = "CREATE_MEMBER") + public UUID create(CreateMemberCommand command) { + String email = command.email(); + emailService.validateDuplicated(command.email()); + + String handle = command.handle(); + handleService.validateDuplicated(handle); + + UUID memberId = UUIDGenerator.generate(); + Password encodedPassword = passwordService.encode(command.loginProvider(), command.password(), memberId); + Member member = Member.of( + memberId, + Email.of(email), + encodedPassword, + Handle.of(handle), + MemberName.of(command.name()), + Motto.of(command.motto()), + LoginProvider.valueOf(command.loginProvider()) + ); + + Member savedMember = memberRepository.save(member); + memberCreateEventPublisher.publish(savedMember.getId()); + return savedMember.getId(); + } +} diff --git a/src/main/java/com/gomo/app/core/member/application/service/MemberLoginService.java b/src/main/java/com/gomo/app/core/member/application/service/MemberLoginService.java new file mode 100644 index 00000000..9e5cc23c --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/service/MemberLoginService.java @@ -0,0 +1,32 @@ +package com.gomo.app.core.member.application.service; + +import java.time.LocalDateTime; +import java.util.UUID; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.core.member.application.port.in.MemberLoginProcessor; +import com.gomo.app.core.member.domain.model.Member; + +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Transactional +@ApplicationService +class MemberLoginService implements MemberLoginProcessor { + + private final PasswordService passwordService; + private final MemberService memberService; + + @Override + @AuditLog(action = "AUTHENTICATE_MEMBER") + public UUID login(String email, String password) { + Member member = memberService.findByEmail(email); + passwordService.verify(member, password); + member.validateActive(); + member.validateLoginProviderIsEmail(); + member.updateLastLoginDateTime(LocalDateTime.now()); + return member.getId(); + } +} diff --git a/src/main/java/com/gomo/app/core/member/application/usecase/OAuthLoginMemberUseCase.java b/src/main/java/com/gomo/app/core/member/application/service/MemberOAuthLoginService.java similarity index 67% rename from src/main/java/com/gomo/app/core/member/application/usecase/OAuthLoginMemberUseCase.java rename to src/main/java/com/gomo/app/core/member/application/service/MemberOAuthLoginService.java index 7a361a82..625fa8b2 100644 --- a/src/main/java/com/gomo/app/core/member/application/usecase/OAuthLoginMemberUseCase.java +++ b/src/main/java/com/gomo/app/core/member/application/service/MemberOAuthLoginService.java @@ -1,30 +1,28 @@ -package com.gomo.app.core.member.application.usecase; +package com.gomo.app.core.member.application.service; import java.time.LocalDateTime; import java.util.Optional; import java.util.UUID; import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.member.application.port.OAuthLoginMemberPortIn; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.core.member.application.port.in.MemberOAuthLoginProcessor; import com.gomo.app.core.member.domain.model.Email; import com.gomo.app.core.member.domain.repository.MemberRepository; -import com.gomo.app.support.logging.AuditLog; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -@Slf4j @RequiredArgsConstructor -@ApplicationService @Transactional -class OAuthLoginMemberUseCase implements OAuthLoginMemberPortIn { +@ApplicationService +class MemberOAuthLoginService implements MemberOAuthLoginProcessor { private final MemberRepository memberRepository; - @AuditLog(action = "OAUTH_AUTHENTICATE_MEMBER") @Override - public Optional oauthAuthenticate(String email) { + @AuditLog(action = "OAUTH_AUTHENTICATE_MEMBER") + public Optional login(String email) { return memberRepository.findByEmail(Email.of(email)).map( member -> { member.validateActive(); diff --git a/src/main/java/com/gomo/app/core/member/application/service/MemberService.java b/src/main/java/com/gomo/app/core/member/application/service/MemberService.java new file mode 100644 index 00000000..29a8d86c --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/service/MemberService.java @@ -0,0 +1,62 @@ +package com.gomo.app.core.member.application.service; + +import java.util.UUID; + +import org.springframework.transaction.annotation.Transactional; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.core.member.application.port.dto.MemberDto; +import com.gomo.app.core.member.application.port.in.MemberDeleter; +import com.gomo.app.core.member.application.port.in.MemberReader; +import com.gomo.app.core.member.application.port.in.MemberUpdater; +import com.gomo.app.core.member.application.port.out.MemberLogoutProcessor; +import com.gomo.app.core.member.application.port.out.PointBalanceReader; +import com.gomo.app.core.member.domain.exception.MemberNotFoundException; +import com.gomo.app.core.member.domain.exception.code.MemberErrorCode; +import com.gomo.app.core.member.domain.model.Email; +import com.gomo.app.core.member.domain.model.Member; +import com.gomo.app.core.member.domain.repository.MemberRepository; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Transactional +@ApplicationService +class MemberService implements MemberReader, MemberUpdater, MemberDeleter { + + private final MemberRepository memberRepository; + private final PointBalanceReader pointBalanceReader; + private final MemberLogoutProcessor memberLogoutProcessor; + + @Override + @Transactional(readOnly = true) + public MemberDto read(UUID id) { + Member member = findById(id); + int balance = pointBalanceReader.read(member.getId()); + return MemberDto.from(member, balance); + } + + Member findById(UUID id) { + return memberRepository.findById(id).orElseThrow(() -> new MemberNotFoundException(MemberErrorCode.NOT_FOUND)); + } + + Member findByEmail(String email) { + return memberRepository.findByEmail(Email.of(email)).orElseThrow(() -> new MemberNotFoundException(MemberErrorCode.NOT_FOUND)); + } + + @Override + @AuditLog(action = "UPDATE_MEMBER") + public void update(UUID id, String name, String motto) { + Member member = findById(id); + member.updateMemberInfo(name, motto); + } + + @Override + @AuditLog(action = "DELETE_MEMBER") + public void delete(UUID memberId) { + Member member = findById(memberId); + memberLogoutProcessor.logout(memberId); + member.delete(); + } +} diff --git a/src/main/java/com/gomo/app/core/member/application/service/PasswordService.java b/src/main/java/com/gomo/app/core/member/application/service/PasswordService.java new file mode 100644 index 00000000..6a1fb59e --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/service/PasswordService.java @@ -0,0 +1,59 @@ +package com.gomo.app.core.member.application.service; + +import static com.gomo.app.core.member.domain.exception.code.MemberErrorCode.*; + +import java.util.UUID; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.core.member.application.port.in.PasswordResetter; +import com.gomo.app.core.member.application.port.in.PasswordUpdater; +import com.gomo.app.core.member.application.port.out.EmailTokenVerifier; +import com.gomo.app.core.member.application.port.out.PasswordEncodeManager; +import com.gomo.app.core.member.domain.exception.MemberAuthenticationFailedException; +import com.gomo.app.core.member.domain.model.LoginProvider; +import com.gomo.app.core.member.domain.model.Member; +import com.gomo.app.core.member.domain.model.Password; + +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Transactional +@ApplicationService +class PasswordService implements PasswordResetter, PasswordUpdater { + + private final EmailTokenVerifier emailTokenVerifier; + private final PasswordEncodeManager passwordEncodeManager; + private final MemberService memberService; + + @Override + @AuditLog(action = "PASSWORD_RESET") + public void reset(String email, String newPassword, String temporaryToken) { + emailTokenVerifier.verify(temporaryToken); + + Member member = memberService.findByEmail(email); + String encoded = passwordEncodeManager.encode(Password.ofRaw(newPassword).getPassword()); + member.updatePassword(Password.ofEncoded(encoded)); + } + + @Override + @AuditLog(action = "PASSWORD_UPDATE") + public void update(UUID memberId, String originPassword, String newPassword) { + Member member = memberService.findById(memberId); + verify(member, originPassword); + String encoded = passwordEncodeManager.encode(Password.ofRaw(newPassword).getPassword()); + member.updatePassword(Password.ofEncoded(encoded)); + } + + void verify(Member member, String originPassword) { + if (!passwordEncodeManager.verify(Password.ofRaw(originPassword).getPassword(), member.password())) { + throw new MemberAuthenticationFailedException(AUTHENTICATION_FAILED); + } + } + + Password encode(String loginProvider, String rawPassword, UUID memberId) { + Password verifiedPassword = LoginProvider.EMAIL.name().equals(loginProvider) ? Password.ofRaw(rawPassword) : Password.forOAuth(memberId.toString()); + return Password.ofEncoded(passwordEncodeManager.encode(verifiedPassword.getPassword())); + } +} diff --git a/src/main/java/com/gomo/app/core/member/application/service/ProfileBannerService.java b/src/main/java/com/gomo/app/core/member/application/service/ProfileBannerService.java new file mode 100644 index 00000000..f41981fe --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/service/ProfileBannerService.java @@ -0,0 +1,39 @@ +package com.gomo.app.core.member.application.service; + +import java.util.UUID; + +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.core.member.application.port.in.ProfileBannerDeleter; +import com.gomo.app.core.member.application.port.in.ProfileBannerUpdater; +import com.gomo.app.core.member.application.port.out.ProfileAssetUploader; +import com.gomo.app.core.member.domain.model.Member; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Transactional +@ApplicationService +class ProfileBannerService implements ProfileBannerUpdater, ProfileBannerDeleter { + + private final MemberService memberService; + private final ProfileAssetUploader profileAssetUploader; + + @Override + @AuditLog(action = "PROFILE_BANNER_UPDATE") + public void update(UUID memberId, MultipartFile profileBanner) { + Member member = memberService.findById(memberId); + String bannerUrl = profileAssetUploader.upload(profileBanner); + member.updateProfileBanner(bannerUrl); + } + + @Override + @AuditLog(action = "PROFILE_BANNER_DELETE") + public void delete(UUID memberId) { + Member member = memberService.findById(memberId); + member.deleteBanner(); + } +} diff --git a/src/main/java/com/gomo/app/core/member/application/service/ProfileImageService.java b/src/main/java/com/gomo/app/core/member/application/service/ProfileImageService.java new file mode 100644 index 00000000..d8de0903 --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/service/ProfileImageService.java @@ -0,0 +1,39 @@ +package com.gomo.app.core.member.application.service; + +import java.util.UUID; + +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.core.member.application.port.in.ProfileImageDeleter; +import com.gomo.app.core.member.application.port.in.ProfileImageUpdater; +import com.gomo.app.core.member.application.port.out.ProfileAssetUploader; +import com.gomo.app.core.member.domain.model.Member; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Transactional +@ApplicationService +class ProfileImageService implements ProfileImageUpdater, ProfileImageDeleter { + + private final MemberService memberService; + private final ProfileAssetUploader profileAssetUploader; + + @Override + @AuditLog(action = "PROFILE_IMAGE_UPDATE") + public void update(UUID memberId, MultipartFile profileImage) { + Member member = memberService.findById(memberId); + String profileUrl = profileAssetUploader.upload(profileImage); + member.updateProfileImage(profileUrl); + } + + @Override + @AuditLog(action = "PROFILE_IMAGE_DELETE") + public void delete(UUID memberId) { + Member member = memberService.findById(memberId); + member.deleteProfile(); + } +} diff --git a/src/main/java/com/gomo/app/core/member/application/service/QuestPropertyService.java b/src/main/java/com/gomo/app/core/member/application/service/QuestPropertyService.java new file mode 100644 index 00000000..077be8bf --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/service/QuestPropertyService.java @@ -0,0 +1,40 @@ +package com.gomo.app.core.member.application.service; + +import java.util.UUID; + +import org.springframework.transaction.annotation.Transactional; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.core.member.application.port.command.UpdateQuestPropertyCommand; +import com.gomo.app.core.member.application.port.dto.QuestPropertyDto; +import com.gomo.app.core.member.application.port.in.QuestPropertyReader; +import com.gomo.app.core.member.application.port.in.QuestPropertyUpdater; +import com.gomo.app.core.member.domain.model.Member; +import com.gomo.app.core.member.domain.model.QuestProperty; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Transactional +@ApplicationService +class QuestPropertyService implements QuestPropertyReader, QuestPropertyUpdater { + + private final MemberService memberService; + + @Override + @Transactional(readOnly = true) + public QuestPropertyDto read(UUID memberId) { + Member member = memberService.findById(memberId); + QuestProperty questProperty = member.getQuestProperty(); + return QuestPropertyDto.from(questProperty); + } + + @Override + @AuditLog(action = "QUEST_PROPERTY_UPDATE") + public void update(UpdateQuestPropertyCommand command) { + Member member = memberService.findById(command.memberId()); + QuestProperty questProperty = command.toDomain(); + member.updateQuestProperty(questProperty); + } +} diff --git a/src/main/java/com/gomo/app/core/member/application/usecase/UpdateWidgetUseCase.java b/src/main/java/com/gomo/app/core/member/application/service/WidgetService.java similarity index 56% rename from src/main/java/com/gomo/app/core/member/application/usecase/UpdateWidgetUseCase.java rename to src/main/java/com/gomo/app/core/member/application/service/WidgetService.java index 4ae5de0b..1d89272b 100644 --- a/src/main/java/com/gomo/app/core/member/application/usecase/UpdateWidgetUseCase.java +++ b/src/main/java/com/gomo/app/core/member/application/service/WidgetService.java @@ -1,11 +1,11 @@ -package com.gomo.app.core.member.application.usecase; +package com.gomo.app.core.member.application.service; import java.util.UUID; import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.core.member.application.port.in.WidgetUpdater; import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.service.MemberService; -import com.gomo.app.support.logging.AuditLog; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; @@ -13,13 +13,14 @@ @RequiredArgsConstructor @Transactional @ApplicationService -public class UpdateWidgetUseCase { +class WidgetService implements WidgetUpdater { private final MemberService memberService; - @AuditLog(action = "UPDATE_WIDGET") + @Override + @AuditLog(action = "WIDGET_UPDATE") public void update(UUID memberId, String snapshot) { - Member member = memberService.find(memberId); + Member member = memberService.findById(memberId); member.updateWidget(snapshot); } } diff --git a/src/main/java/com/gomo/app/core/member/application/usecase/CheckHandleUseCase.java b/src/main/java/com/gomo/app/core/member/application/usecase/CheckHandleUseCase.java deleted file mode 100644 index cd82c590..00000000 --- a/src/main/java/com/gomo/app/core/member/application/usecase/CheckHandleUseCase.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.member.domain.model.Handle; -import com.gomo.app.core.member.domain.service.MemberService; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -public class CheckHandleUseCase { - - private final MemberService memberService; - - public void checkHandleDuplicated(String handle) { - memberService.checkHandleDuplicated(Handle.of(handle)); - } -} diff --git a/src/main/java/com/gomo/app/core/member/application/usecase/CreateEmailCodeUseCase.java b/src/main/java/com/gomo/app/core/member/application/usecase/CreateEmailCodeUseCase.java deleted file mode 100644 index 83b5a224..00000000 --- a/src/main/java/com/gomo/app/core/member/application/usecase/CreateEmailCodeUseCase.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.member.domain.model.Email; -import com.gomo.app.core.member.domain.service.MemberService; -import com.gomo.app.support.auth.application.port.CreateAuthCodePortIn; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -public class CreateEmailCodeUseCase { - - private final CreateAuthCodePortIn createAuthCodePortIn; - private final MemberService memberService; - - // TODO [2025-10-19] jhl221123 : 코드를 반환하지 않고 테스트를 처리할 수 있도록 수정해야 합니다. - @AuditLog(action = "CREATE_SIGNUP_EMAIL_CODE") - public String createForSignUp(String email) { - memberService.checkEmailDuplicated(Email.of(email)); - return createAuthCodePortIn.sendToEmail(email); - } - - @AuditLog(action = "CREATE_PW_RESET_EMAIL_CODE") - public String createForPasswordReset(String email) { - memberService.findByEmail(Email.of(email)); - return createAuthCodePortIn.sendToEmail(email); - } -} diff --git a/src/main/java/com/gomo/app/core/member/application/usecase/CreateMemberUseCase.java b/src/main/java/com/gomo/app/core/member/application/usecase/CreateMemberUseCase.java deleted file mode 100644 index 0a8cd42a..00000000 --- a/src/main/java/com/gomo/app/core/member/application/usecase/CreateMemberUseCase.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import java.util.UUID; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.common.security.encoder.application.port.EncodePasswordPortIn; -import com.gomo.app.common.security.jwt.application.port.VerifyJwtPortIn; -import com.gomo.app.common.util.UUIDGenerator; -import com.gomo.app.core.member.application.port.command.CreateMemberCommand; -import com.gomo.app.core.member.domain.model.Email; -import com.gomo.app.core.member.domain.model.Handle; -import com.gomo.app.core.member.domain.model.LoginProvider; -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.model.MemberName; -import com.gomo.app.core.member.domain.model.Motto; -import com.gomo.app.core.member.domain.model.Password; -import com.gomo.app.core.member.domain.repository.MemberRepository; -import com.gomo.app.core.member.domain.service.MemberService; -import com.gomo.app.core.point.application.port.CreatePointWalletPortIn; -import com.gomo.app.core.streak.application.port.CreateAchieverPortIn; -import com.gomo.app.support.logging.AuditLog; -import com.gomo.app.support.logging.Timed; - -import jakarta.transaction.Transactional; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -public class CreateMemberUseCase { - - private final VerifyJwtPortIn verifyJwtPortIn; - private final EncodePasswordPortIn encodePasswordPortIn; - private final CreatePointWalletPortIn createPointWalletPortIn; - private final CreateAchieverPortIn createAchieverPortIn; - private final MemberService memberService; - private final MemberRepository memberRepository; - - @AuditLog(action = "CREATE_MEMBER") - @Timed - public UUID create(CreateMemberCommand command) { - // TODO [2025-10-18] jhl221123 : jwt 형식 뿐 아니라 내부 이메일이 요청한 이메일과 같은지 검증이 필요합니다. - // TODO [2025-10-19] jhl221123 : 커스텀 예외를 반환하도록 수정해야합니다. - if (!verifyJwtPortIn.validateToken(command.temporaryToken())) { - throw new IllegalArgumentException("Invalid temporary token"); - } - - Email email = Email.of(command.email()); - memberService.checkEmailDuplicated(email); - - Handle handle = Handle.of(command.handle()); - memberService.checkHandleDuplicated(handle); - - UUID memberId = UUIDGenerator.generate(); - Password verifiedPassword = LoginProvider.EMAIL.name().equals(command.loginProvider()) - ? Password.ofRaw(command.rawPassword()) : Password.forOAuth(memberId.toString()); - Password encodedPassword = Password.ofEncoded(encodePasswordPortIn.encode(verifiedPassword.getPassword())); - - Member member = Member.of( - memberId, - email, - encodedPassword, - handle, - MemberName.of(command.name()), - Motto.of(command.motto()), - LoginProvider.valueOf(command.loginProvider()) - ); - Member savedMember = memberRepository.save(member); - createPointWalletPortIn.create(savedMember.getId()); - createAchieverPortIn.create(savedMember.getId()); - return savedMember.getId(); - } -} diff --git a/src/main/java/com/gomo/app/core/member/application/usecase/DeleteMemberUseCase.java b/src/main/java/com/gomo/app/core/member/application/usecase/DeleteMemberUseCase.java deleted file mode 100644 index a2772060..00000000 --- a/src/main/java/com/gomo/app/core/member/application/usecase/DeleteMemberUseCase.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import java.util.UUID; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.service.MemberService; -import com.gomo.app.support.auth.application.port.DeleteAuthTokenPortIn; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -public class DeleteMemberUseCase { - - private final DeleteAuthTokenPortIn deleteAuthTokenPortIn; - private final MemberService memberService; - - @AuditLog(action = "DELETE_MEMBER") - public void delete(UUID memberId) { - Member member = memberService.find(memberId); - deleteAuthTokenPortIn.deleteRefreshToken(memberId); - member.delete(); - } -} diff --git a/src/main/java/com/gomo/app/core/member/application/usecase/DeleteProfileBannerUseCase.java b/src/main/java/com/gomo/app/core/member/application/usecase/DeleteProfileBannerUseCase.java deleted file mode 100644 index 7187ef95..00000000 --- a/src/main/java/com/gomo/app/core/member/application/usecase/DeleteProfileBannerUseCase.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import java.util.UUID; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.service.MemberService; -import com.gomo.app.support.logging.AuditLog; - -import jakarta.transaction.Transactional; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -public class DeleteProfileBannerUseCase { - - private final MemberService memberService; - - @AuditLog(action = "DELETE_PROFILE_BANNER") - public void delete(UUID memberId) { - Member member = memberService.find(memberId); - member.deleteBanner(); - } -} diff --git a/src/main/java/com/gomo/app/core/member/application/usecase/DeleteProfileImageUseCase.java b/src/main/java/com/gomo/app/core/member/application/usecase/DeleteProfileImageUseCase.java deleted file mode 100644 index a019f29a..00000000 --- a/src/main/java/com/gomo/app/core/member/application/usecase/DeleteProfileImageUseCase.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import java.util.UUID; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.service.MemberService; -import com.gomo.app.support.logging.AuditLog; - -import jakarta.transaction.Transactional; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -public class DeleteProfileImageUseCase { - - private final MemberService memberService; - - @AuditLog(action = "DELETE_PROFILE_IMAGE") - public void delete(UUID memberId) { - Member member = memberService.find(memberId); - member.deleteProfile(); - } -} diff --git a/src/main/java/com/gomo/app/core/member/application/usecase/LoginMemberUseCase.java b/src/main/java/com/gomo/app/core/member/application/usecase/LoginMemberUseCase.java deleted file mode 100644 index 8c5cf1b7..00000000 --- a/src/main/java/com/gomo/app/core/member/application/usecase/LoginMemberUseCase.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import static com.gomo.app.core.member.exception.code.MemberErrorCode.*; - -import java.time.LocalDateTime; -import java.util.UUID; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.common.security.encoder.application.port.VerifyPasswordPortIn; -import com.gomo.app.core.member.application.port.LoginMemberPortIn; -import com.gomo.app.core.member.domain.model.Email; -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.model.Password; -import com.gomo.app.core.member.domain.service.MemberService; -import com.gomo.app.core.member.exception.MemberAuthenticationFailedException; -import com.gomo.app.support.logging.AuditLog; - -import jakarta.transaction.Transactional; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -@Transactional -class LoginMemberUseCase implements LoginMemberPortIn { - - private final VerifyPasswordPortIn verifyPasswordPortIn; - private final MemberService memberService; - - @AuditLog(action = "AUTHENTICATE_MEMBER") - @Override - public UUID authenticate(String email, String password) { - Member member = memberService.findByEmail(Email.of(email)); - ensureCorrectPassword(member, password); - member.validateActive(); - member.validateLoginProviderIsEmail(); - member.updateLastLoginDateTime(LocalDateTime.now()); - return member.getId(); - } - - private void ensureCorrectPassword(Member member, String inputPassword) { - if (!verifyPasswordPortIn.matches(Password.ofRaw(inputPassword).getPassword(), member.password())) { - throw new MemberAuthenticationFailedException(AUTHENTICATION_FAILED); - } - } -} diff --git a/src/main/java/com/gomo/app/core/member/application/usecase/ReadMemberUseCase.java b/src/main/java/com/gomo/app/core/member/application/usecase/ReadMemberUseCase.java deleted file mode 100644 index a0d78bd0..00000000 --- a/src/main/java/com/gomo/app/core/member/application/usecase/ReadMemberUseCase.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import java.util.UUID; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.member.application.port.ReadMemberPortIn; -import com.gomo.app.core.member.application.port.dto.MemberDto; -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.service.MemberService; -import com.gomo.app.core.point.application.port.ReadBalancePortIn; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -class ReadMemberUseCase implements ReadMemberPortIn { - - private final ReadBalancePortIn readBalancePortIn; - private final MemberService memberService; - - @Override - public MemberDto find(UUID id) { - Member member = memberService.find(id); - int balance = readBalancePortIn.find(member.getId()); - return MemberDto.from(member, balance); - } -} diff --git a/src/main/java/com/gomo/app/core/member/application/usecase/ReadQuestPropertyUseCase.java b/src/main/java/com/gomo/app/core/member/application/usecase/ReadQuestPropertyUseCase.java deleted file mode 100644 index 343976b3..00000000 --- a/src/main/java/com/gomo/app/core/member/application/usecase/ReadQuestPropertyUseCase.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import java.util.UUID; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.member.application.port.dto.QuestPropertyDto; -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.model.QuestProperty; -import com.gomo.app.core.member.domain.service.MemberService; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -public class ReadQuestPropertyUseCase { - - private final MemberService memberService; - - public QuestPropertyDto find(UUID memberId) { - Member member = memberService.find(memberId); - QuestProperty questProperty = member.getQuestProperty(); - return QuestPropertyDto.from(questProperty); - } -} diff --git a/src/main/java/com/gomo/app/core/member/application/usecase/ResetPasswordUseCase.java b/src/main/java/com/gomo/app/core/member/application/usecase/ResetPasswordUseCase.java deleted file mode 100644 index 2f1a4c85..00000000 --- a/src/main/java/com/gomo/app/core/member/application/usecase/ResetPasswordUseCase.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.common.security.encoder.application.port.EncodePasswordPortIn; -import com.gomo.app.common.security.jwt.application.port.VerifyJwtPortIn; -import com.gomo.app.core.member.domain.model.Email; -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.model.Password; -import com.gomo.app.core.member.domain.service.MemberService; - -import jakarta.transaction.Transactional; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -@Transactional -public class ResetPasswordUseCase { - - private final VerifyJwtPortIn verifyJwtPortIn; - private final EncodePasswordPortIn encodePasswordPortIn; - private final MemberService memberService; - - public void reset(String email, String newPassword, String temporaryToken) { - if (!verifyJwtPortIn.validateToken(temporaryToken)) { - throw new IllegalArgumentException("Invalid temporary token"); - } - - Member member = memberService.findByEmail(Email.of(email)); - String encoded = encodePasswordPortIn.encode(Password.ofRaw(newPassword).getPassword()); - member.updatePassword(Password.ofEncoded(encoded)); - } -} diff --git a/src/main/java/com/gomo/app/core/member/application/usecase/UpdateHandleUseCase.java b/src/main/java/com/gomo/app/core/member/application/usecase/UpdateHandleUseCase.java deleted file mode 100644 index f9b7387d..00000000 --- a/src/main/java/com/gomo/app/core/member/application/usecase/UpdateHandleUseCase.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import java.util.UUID; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.member.domain.model.Handle; -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.service.MemberService; -import com.gomo.app.support.logging.AuditLog; - -import jakarta.transaction.Transactional; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -public class UpdateHandleUseCase { - - private final MemberService memberService; - - @AuditLog(action = "UPDATE_HANDLE") - public void update(UUID memberId, String handle) { - Member member = memberService.find(memberId); - memberService.checkHandleDuplicated(Handle.of(handle)); - member.updateHandle(handle); - } -} diff --git a/src/main/java/com/gomo/app/core/member/application/usecase/UpdateMemberUseCase.java b/src/main/java/com/gomo/app/core/member/application/usecase/UpdateMemberUseCase.java deleted file mode 100644 index 1f43c606..00000000 --- a/src/main/java/com/gomo/app/core/member/application/usecase/UpdateMemberUseCase.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import java.util.UUID; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.service.MemberService; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -public class UpdateMemberUseCase { - - private final MemberService memberService; - - @AuditLog(action = "UPDATE_MEMBER") - public void update(UUID id, String name, String motto) { - Member member = memberService.find(id); - member.updateMemberInfo(name, motto); - } -} diff --git a/src/main/java/com/gomo/app/core/member/application/usecase/UpdatePasswordUseCase.java b/src/main/java/com/gomo/app/core/member/application/usecase/UpdatePasswordUseCase.java deleted file mode 100644 index 837625ae..00000000 --- a/src/main/java/com/gomo/app/core/member/application/usecase/UpdatePasswordUseCase.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import static com.gomo.app.core.member.exception.code.MemberErrorCode.*; - -import java.util.UUID; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.common.security.encoder.application.port.EncodePasswordPortIn; -import com.gomo.app.common.security.encoder.application.port.VerifyPasswordPortIn; -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.model.Password; -import com.gomo.app.core.member.domain.service.MemberService; -import com.gomo.app.core.member.exception.MemberAuthenticationFailedException; -import com.gomo.app.support.logging.AuditLog; - -import jakarta.transaction.Transactional; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -public class UpdatePasswordUseCase { - - private final VerifyPasswordPortIn verifyPasswordPortIn; - private final EncodePasswordPortIn encodePasswordPortIn; - private final MemberService memberService; - - @AuditLog(action = "UPDATE_PASSWORD") - public void update(UUID memberId, String originPassword, String newPassword) { - Member member = memberService.find(memberId); - ensureCorrectPassword(member, originPassword); - String encoded = encodePasswordPortIn.encode(Password.ofRaw(newPassword).getPassword()); - member.updatePassword(Password.ofEncoded(encoded)); - } - - private void ensureCorrectPassword(Member member, String originPassword) { - if (!verifyPasswordPortIn.matches(Password.ofRaw(originPassword).getPassword(), member.password())) { - throw new MemberAuthenticationFailedException(AUTHENTICATION_FAILED); - } - } -} diff --git a/src/main/java/com/gomo/app/core/member/application/usecase/UpdateProfileBannerUseCase.java b/src/main/java/com/gomo/app/core/member/application/usecase/UpdateProfileBannerUseCase.java deleted file mode 100644 index eaa02d53..00000000 --- a/src/main/java/com/gomo/app/core/member/application/usecase/UpdateProfileBannerUseCase.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import java.util.UUID; - -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.multipart.MultipartFile; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.member.application.port.dto.UpdateProfileBannerDto; -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.service.MemberService; -import com.gomo.app.support.image.application.port.UploadImagePortIn; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -public class UpdateProfileBannerUseCase { - - private final UploadImagePortIn uploadImagePortIn; - private final MemberService memberService; - - @AuditLog(action = "UPDATE_PROFILE_BANNER") - public UpdateProfileBannerDto update(UUID memberId, MultipartFile profileBanner) { - Member member = memberService.find(memberId); - String bannerUrl = uploadImagePortIn.upload(profileBanner).orElse(null); - member.updateProfileBanner(bannerUrl); - return UpdateProfileBannerDto.of(bannerUrl); - } -} diff --git a/src/main/java/com/gomo/app/core/member/application/usecase/UpdateProfileImageUseCase.java b/src/main/java/com/gomo/app/core/member/application/usecase/UpdateProfileImageUseCase.java deleted file mode 100644 index 4f5e1786..00000000 --- a/src/main/java/com/gomo/app/core/member/application/usecase/UpdateProfileImageUseCase.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import java.util.UUID; - -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.multipart.MultipartFile; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.member.application.port.dto.UpdateProfileImageDto; -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.service.MemberService; -import com.gomo.app.support.image.application.port.UploadImagePortIn; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -public class UpdateProfileImageUseCase { - - private final UploadImagePortIn uploadImagePortIn; - private final MemberService memberService; - - @AuditLog(action = "UPDATE_PROFILE_IMAGE") - public UpdateProfileImageDto update(UUID memberId, MultipartFile profileImage) { - Member member = memberService.find(memberId); - String profileUrl = uploadImagePortIn.upload(profileImage).orElse(null); - ; - member.updateProfileImage(profileUrl); - return UpdateProfileImageDto.of(profileUrl); - } -} diff --git a/src/main/java/com/gomo/app/core/member/application/usecase/UpdateQuestPropertyUseCase.java b/src/main/java/com/gomo/app/core/member/application/usecase/UpdateQuestPropertyUseCase.java deleted file mode 100644 index cb6772d7..00000000 --- a/src/main/java/com/gomo/app/core/member/application/usecase/UpdateQuestPropertyUseCase.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.member.application.port.command.UpdateQuestPropertyCommand; -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.model.QuestProperty; -import com.gomo.app.core.member.domain.service.MemberService; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -public class UpdateQuestPropertyUseCase { - - private final MemberService memberService; - - @AuditLog(action = "UPDATE_QUEST_PROPERTY") - public void update(UpdateQuestPropertyCommand command) { - Member member = memberService.find(command.memberId()); - QuestProperty questProperty = command.toDomain(); - member.updateQuestProperty(questProperty); - } -} diff --git a/src/main/java/com/gomo/app/core/member/application/usecase/VerifyEmailCodeUseCase.java b/src/main/java/com/gomo/app/core/member/application/usecase/VerifyEmailCodeUseCase.java deleted file mode 100644 index e94eab6b..00000000 --- a/src/main/java/com/gomo/app/core/member/application/usecase/VerifyEmailCodeUseCase.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.common.security.jwt.application.port.GenerateJwtPortIn; -import com.gomo.app.support.auth.application.port.VerifyAuthCodePortIn; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -public class VerifyEmailCodeUseCase { - - private final VerifyAuthCodePortIn verifyAuthCodePortIn; - private final GenerateJwtPortIn generateJwtPortIn; - - @AuditLog(action = "VERIFY_EMAIL_CODE") - public String verify(String email, String authCode) { - verifyAuthCodePortIn.verify(email, authCode); - return generateJwtPortIn.generateTemporaryToken(email, 1800); - } -} diff --git a/src/main/java/com/gomo/app/core/member/exception/ActivateStatusException.java b/src/main/java/com/gomo/app/core/member/domain/exception/ActivateStatusException.java similarity index 76% rename from src/main/java/com/gomo/app/core/member/exception/ActivateStatusException.java rename to src/main/java/com/gomo/app/core/member/domain/exception/ActivateStatusException.java index 8bfbfd93..ebd4c24d 100644 --- a/src/main/java/com/gomo/app/core/member/exception/ActivateStatusException.java +++ b/src/main/java/com/gomo/app/core/member/domain/exception/ActivateStatusException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.member.exception; +package com.gomo.app.core.member.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.member.exception.code.ActivateStatusErrorCode; +import com.gomo.app.core.member.domain.exception.code.ActivateStatusErrorCode; public class ActivateStatusException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/member/exception/EmailConstraintViolationException.java b/src/main/java/com/gomo/app/core/member/domain/exception/EmailConstraintViolationException.java similarity index 78% rename from src/main/java/com/gomo/app/core/member/exception/EmailConstraintViolationException.java rename to src/main/java/com/gomo/app/core/member/domain/exception/EmailConstraintViolationException.java index 3e403414..6000f2f3 100644 --- a/src/main/java/com/gomo/app/core/member/exception/EmailConstraintViolationException.java +++ b/src/main/java/com/gomo/app/core/member/domain/exception/EmailConstraintViolationException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.member.exception; +package com.gomo.app.core.member.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.member.exception.code.EmailErrorCode; +import com.gomo.app.core.member.domain.exception.code.EmailErrorCode; public class EmailConstraintViolationException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/member/exception/EmailDuplicatedException.java b/src/main/java/com/gomo/app/core/member/domain/exception/EmailDuplicatedException.java similarity index 77% rename from src/main/java/com/gomo/app/core/member/exception/EmailDuplicatedException.java rename to src/main/java/com/gomo/app/core/member/domain/exception/EmailDuplicatedException.java index f47217bc..1e77ff7a 100644 --- a/src/main/java/com/gomo/app/core/member/exception/EmailDuplicatedException.java +++ b/src/main/java/com/gomo/app/core/member/domain/exception/EmailDuplicatedException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.member.exception; +package com.gomo.app.core.member.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.member.exception.code.EmailErrorCode; +import com.gomo.app.core.member.domain.exception.code.EmailErrorCode; public class EmailDuplicatedException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/member/exception/HandleConstraintViolationException.java b/src/main/java/com/gomo/app/core/member/domain/exception/HandleConstraintViolationException.java similarity index 78% rename from src/main/java/com/gomo/app/core/member/exception/HandleConstraintViolationException.java rename to src/main/java/com/gomo/app/core/member/domain/exception/HandleConstraintViolationException.java index 27d85cf3..36a90dee 100644 --- a/src/main/java/com/gomo/app/core/member/exception/HandleConstraintViolationException.java +++ b/src/main/java/com/gomo/app/core/member/domain/exception/HandleConstraintViolationException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.member.exception; +package com.gomo.app.core.member.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.member.exception.code.HandleErrorCode; +import com.gomo.app.core.member.domain.exception.code.HandleErrorCode; public class HandleConstraintViolationException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/member/exception/HandleDuplicatedException.java b/src/main/java/com/gomo/app/core/member/domain/exception/HandleDuplicatedException.java similarity index 77% rename from src/main/java/com/gomo/app/core/member/exception/HandleDuplicatedException.java rename to src/main/java/com/gomo/app/core/member/domain/exception/HandleDuplicatedException.java index 803c0f3f..83be3d08 100644 --- a/src/main/java/com/gomo/app/core/member/exception/HandleDuplicatedException.java +++ b/src/main/java/com/gomo/app/core/member/domain/exception/HandleDuplicatedException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.member.exception; +package com.gomo.app.core.member.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.member.exception.code.HandleErrorCode; +import com.gomo.app.core.member.domain.exception.code.HandleErrorCode; public class HandleDuplicatedException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/member/domain/exception/MemberAuthenticationFailedException.java b/src/main/java/com/gomo/app/core/member/domain/exception/MemberAuthenticationFailedException.java new file mode 100644 index 00000000..fc8910d7 --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/domain/exception/MemberAuthenticationFailedException.java @@ -0,0 +1,15 @@ +package com.gomo.app.core.member.domain.exception; + +import com.gomo.app.common.exception.ApplicationException; +import com.gomo.app.core.member.domain.exception.code.MemberErrorCode; + +public class MemberAuthenticationFailedException extends ApplicationException { + + public MemberAuthenticationFailedException(MemberErrorCode errorCode) { + super(errorCode.getHttpStatus(), errorCode.getErrorCode(), errorCode.getMessage()); + } + + public MemberAuthenticationFailedException(MemberErrorCode errorCode, Throwable cause) { + super(errorCode.getHttpStatus(), errorCode.getErrorCode(), errorCode.getMessage(), cause); + } +} diff --git a/src/main/java/com/gomo/app/core/member/domain/exception/MemberDuplicatedException.java b/src/main/java/com/gomo/app/core/member/domain/exception/MemberDuplicatedException.java new file mode 100644 index 00000000..17fafb7c --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/domain/exception/MemberDuplicatedException.java @@ -0,0 +1,15 @@ +package com.gomo.app.core.member.domain.exception; + +import com.gomo.app.common.exception.ApplicationException; +import com.gomo.app.core.member.domain.exception.code.MemberErrorCode; + +public class MemberDuplicatedException extends ApplicationException { + + public MemberDuplicatedException(MemberErrorCode errorCode) { + super(errorCode.getHttpStatus(), errorCode.getErrorCode(), errorCode.getMessage()); + } + + public MemberDuplicatedException(MemberErrorCode errorCode, Throwable cause) { + super(errorCode.getHttpStatus(), errorCode.getErrorCode(), errorCode.getMessage(), cause); + } +} diff --git a/src/main/java/com/gomo/app/core/member/exception/MemberNameConstraintViolationException.java b/src/main/java/com/gomo/app/core/member/domain/exception/MemberNameConstraintViolationException.java similarity index 78% rename from src/main/java/com/gomo/app/core/member/exception/MemberNameConstraintViolationException.java rename to src/main/java/com/gomo/app/core/member/domain/exception/MemberNameConstraintViolationException.java index 2bb5f289..7d478c03 100644 --- a/src/main/java/com/gomo/app/core/member/exception/MemberNameConstraintViolationException.java +++ b/src/main/java/com/gomo/app/core/member/domain/exception/MemberNameConstraintViolationException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.member.exception; +package com.gomo.app.core.member.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.member.exception.code.MemberNameErrorCode; +import com.gomo.app.core.member.domain.exception.code.MemberNameErrorCode; public class MemberNameConstraintViolationException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/member/exception/MemberNotFoundException.java b/src/main/java/com/gomo/app/core/member/domain/exception/MemberNotFoundException.java similarity index 76% rename from src/main/java/com/gomo/app/core/member/exception/MemberNotFoundException.java rename to src/main/java/com/gomo/app/core/member/domain/exception/MemberNotFoundException.java index 13a1df3a..3d2143f6 100644 --- a/src/main/java/com/gomo/app/core/member/exception/MemberNotFoundException.java +++ b/src/main/java/com/gomo/app/core/member/domain/exception/MemberNotFoundException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.member.exception; +package com.gomo.app.core.member.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.member.exception.code.MemberErrorCode; +import com.gomo.app.core.member.domain.exception.code.MemberErrorCode; public class MemberNotFoundException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/member/exception/MottoConstraintViolationException.java b/src/main/java/com/gomo/app/core/member/domain/exception/MottoConstraintViolationException.java similarity index 78% rename from src/main/java/com/gomo/app/core/member/exception/MottoConstraintViolationException.java rename to src/main/java/com/gomo/app/core/member/domain/exception/MottoConstraintViolationException.java index 4d74b662..280473d8 100644 --- a/src/main/java/com/gomo/app/core/member/exception/MottoConstraintViolationException.java +++ b/src/main/java/com/gomo/app/core/member/domain/exception/MottoConstraintViolationException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.member.exception; +package com.gomo.app.core.member.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.member.exception.code.MottoErrorCode; +import com.gomo.app.core.member.domain.exception.code.MottoErrorCode; public class MottoConstraintViolationException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/member/exception/PasswordConstraintViolationException.java b/src/main/java/com/gomo/app/core/member/domain/exception/PasswordConstraintViolationException.java similarity index 78% rename from src/main/java/com/gomo/app/core/member/exception/PasswordConstraintViolationException.java rename to src/main/java/com/gomo/app/core/member/domain/exception/PasswordConstraintViolationException.java index d565055b..14d478b1 100644 --- a/src/main/java/com/gomo/app/core/member/exception/PasswordConstraintViolationException.java +++ b/src/main/java/com/gomo/app/core/member/domain/exception/PasswordConstraintViolationException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.member.exception; +package com.gomo.app.core.member.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.member.exception.code.PasswordErrorCode; +import com.gomo.app.core.member.domain.exception.code.PasswordErrorCode; public class PasswordConstraintViolationException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/member/exception/PasswordMismatchException.java b/src/main/java/com/gomo/app/core/member/domain/exception/PasswordMismatchException.java similarity index 77% rename from src/main/java/com/gomo/app/core/member/exception/PasswordMismatchException.java rename to src/main/java/com/gomo/app/core/member/domain/exception/PasswordMismatchException.java index 4ef565fd..4b7bc654 100644 --- a/src/main/java/com/gomo/app/core/member/exception/PasswordMismatchException.java +++ b/src/main/java/com/gomo/app/core/member/domain/exception/PasswordMismatchException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.member.exception; +package com.gomo.app.core.member.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.member.exception.code.MemberErrorCode; +import com.gomo.app.core.member.domain.exception.code.MemberErrorCode; public class PasswordMismatchException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/member/exception/QuestPropertyConstraintViolationException.java b/src/main/java/com/gomo/app/core/member/domain/exception/QuestPropertyConstraintViolationException.java similarity index 78% rename from src/main/java/com/gomo/app/core/member/exception/QuestPropertyConstraintViolationException.java rename to src/main/java/com/gomo/app/core/member/domain/exception/QuestPropertyConstraintViolationException.java index d50243b7..c4512e3d 100644 --- a/src/main/java/com/gomo/app/core/member/exception/QuestPropertyConstraintViolationException.java +++ b/src/main/java/com/gomo/app/core/member/domain/exception/QuestPropertyConstraintViolationException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.member.exception; +package com.gomo.app.core.member.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.member.exception.code.QuestPropertyErrorCode; +import com.gomo.app.core.member.domain.exception.code.QuestPropertyErrorCode; public class QuestPropertyConstraintViolationException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/member/exception/code/ActivateStatusErrorCode.java b/src/main/java/com/gomo/app/core/member/domain/exception/code/ActivateStatusErrorCode.java similarity index 86% rename from src/main/java/com/gomo/app/core/member/exception/code/ActivateStatusErrorCode.java rename to src/main/java/com/gomo/app/core/member/domain/exception/code/ActivateStatusErrorCode.java index ae185419..28d88633 100644 --- a/src/main/java/com/gomo/app/core/member/exception/code/ActivateStatusErrorCode.java +++ b/src/main/java/com/gomo/app/core/member/domain/exception/code/ActivateStatusErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.exception.code; +package com.gomo.app.core.member.domain.exception.code; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/member/exception/code/EmailErrorCode.java b/src/main/java/com/gomo/app/core/member/domain/exception/code/EmailErrorCode.java similarity index 89% rename from src/main/java/com/gomo/app/core/member/exception/code/EmailErrorCode.java rename to src/main/java/com/gomo/app/core/member/domain/exception/code/EmailErrorCode.java index a7c08311..2ae0a63d 100644 --- a/src/main/java/com/gomo/app/core/member/exception/code/EmailErrorCode.java +++ b/src/main/java/com/gomo/app/core/member/domain/exception/code/EmailErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.exception.code; +package com.gomo.app.core.member.domain.exception.code; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/member/exception/code/HandleErrorCode.java b/src/main/java/com/gomo/app/core/member/domain/exception/code/HandleErrorCode.java similarity index 89% rename from src/main/java/com/gomo/app/core/member/exception/code/HandleErrorCode.java rename to src/main/java/com/gomo/app/core/member/domain/exception/code/HandleErrorCode.java index 145da5e8..d5b2fbef 100644 --- a/src/main/java/com/gomo/app/core/member/exception/code/HandleErrorCode.java +++ b/src/main/java/com/gomo/app/core/member/domain/exception/code/HandleErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.exception.code; +package com.gomo.app.core.member.domain.exception.code; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/member/exception/code/MemberErrorCode.java b/src/main/java/com/gomo/app/core/member/domain/exception/code/MemberErrorCode.java similarity index 87% rename from src/main/java/com/gomo/app/core/member/exception/code/MemberErrorCode.java rename to src/main/java/com/gomo/app/core/member/domain/exception/code/MemberErrorCode.java index 8705e84c..eedd4a67 100644 --- a/src/main/java/com/gomo/app/core/member/exception/code/MemberErrorCode.java +++ b/src/main/java/com/gomo/app/core/member/domain/exception/code/MemberErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.exception.code; +package com.gomo.app.core.member.domain.exception.code; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/member/exception/code/MemberNameErrorCode.java b/src/main/java/com/gomo/app/core/member/domain/exception/code/MemberNameErrorCode.java similarity index 88% rename from src/main/java/com/gomo/app/core/member/exception/code/MemberNameErrorCode.java rename to src/main/java/com/gomo/app/core/member/domain/exception/code/MemberNameErrorCode.java index e7fdb02d..afa2b024 100644 --- a/src/main/java/com/gomo/app/core/member/exception/code/MemberNameErrorCode.java +++ b/src/main/java/com/gomo/app/core/member/domain/exception/code/MemberNameErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.exception.code; +package com.gomo.app.core.member.domain.exception.code; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/member/exception/code/MottoErrorCode.java b/src/main/java/com/gomo/app/core/member/domain/exception/code/MottoErrorCode.java similarity index 86% rename from src/main/java/com/gomo/app/core/member/exception/code/MottoErrorCode.java rename to src/main/java/com/gomo/app/core/member/domain/exception/code/MottoErrorCode.java index 6e4a86fa..44d12a9e 100644 --- a/src/main/java/com/gomo/app/core/member/exception/code/MottoErrorCode.java +++ b/src/main/java/com/gomo/app/core/member/domain/exception/code/MottoErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.exception.code; +package com.gomo.app.core.member.domain.exception.code; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/member/exception/code/PasswordErrorCode.java b/src/main/java/com/gomo/app/core/member/domain/exception/code/PasswordErrorCode.java similarity index 92% rename from src/main/java/com/gomo/app/core/member/exception/code/PasswordErrorCode.java rename to src/main/java/com/gomo/app/core/member/domain/exception/code/PasswordErrorCode.java index 238ad833..4616cf0c 100644 --- a/src/main/java/com/gomo/app/core/member/exception/code/PasswordErrorCode.java +++ b/src/main/java/com/gomo/app/core/member/domain/exception/code/PasswordErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.exception.code; +package com.gomo.app.core.member.domain.exception.code; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/member/exception/code/QuestPropertyErrorCode.java b/src/main/java/com/gomo/app/core/member/domain/exception/code/QuestPropertyErrorCode.java similarity index 87% rename from src/main/java/com/gomo/app/core/member/exception/code/QuestPropertyErrorCode.java rename to src/main/java/com/gomo/app/core/member/domain/exception/code/QuestPropertyErrorCode.java index 292c9fbc..71e6f3a0 100644 --- a/src/main/java/com/gomo/app/core/member/exception/code/QuestPropertyErrorCode.java +++ b/src/main/java/com/gomo/app/core/member/domain/exception/code/QuestPropertyErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.exception.code; +package com.gomo.app.core.member.domain.exception.code; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/member/domain/model/Email.java b/src/main/java/com/gomo/app/core/member/domain/model/Email.java index 9f8fda65..e8ef08d3 100644 --- a/src/main/java/com/gomo/app/core/member/domain/model/Email.java +++ b/src/main/java/com/gomo/app/core/member/domain/model/Email.java @@ -3,8 +3,8 @@ import java.util.regex.Pattern; import com.gomo.app.common.arch.ValueObject; -import com.gomo.app.core.member.exception.EmailConstraintViolationException; -import com.gomo.app.core.member.exception.code.EmailErrorCode; +import com.gomo.app.core.member.domain.exception.EmailConstraintViolationException; +import com.gomo.app.core.member.domain.exception.code.EmailErrorCode; import jakarta.persistence.Embeddable; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/member/domain/model/Handle.java b/src/main/java/com/gomo/app/core/member/domain/model/Handle.java index 564ff9e9..c53711e7 100644 --- a/src/main/java/com/gomo/app/core/member/domain/model/Handle.java +++ b/src/main/java/com/gomo/app/core/member/domain/model/Handle.java @@ -3,8 +3,8 @@ import java.util.regex.Pattern; import com.gomo.app.common.arch.ValueObject; -import com.gomo.app.core.member.exception.HandleConstraintViolationException; -import com.gomo.app.core.member.exception.code.HandleErrorCode; +import com.gomo.app.core.member.domain.exception.HandleConstraintViolationException; +import com.gomo.app.core.member.domain.exception.code.HandleErrorCode; import jakarta.persistence.Embeddable; import lombok.EqualsAndHashCode; diff --git a/src/main/java/com/gomo/app/core/member/domain/model/Member.java b/src/main/java/com/gomo/app/core/member/domain/model/Member.java index e2a80824..8cd6453e 100644 --- a/src/main/java/com/gomo/app/core/member/domain/model/Member.java +++ b/src/main/java/com/gomo/app/core/member/domain/model/Member.java @@ -4,10 +4,10 @@ import java.util.UUID; import com.gomo.app.common.jpa.LogicalDeleteBaseAudit; -import com.gomo.app.core.member.exception.ActivateStatusException; -import com.gomo.app.core.member.exception.code.ActivateStatusErrorCode; -import com.gomo.app.support.auth.exception.AuthErrorCode; -import com.gomo.app.support.auth.exception.AuthenticationFailException; +import com.gomo.app.core.member.domain.exception.ActivateStatusException; +import com.gomo.app.core.member.domain.exception.code.ActivateStatusErrorCode; +import com.gomo.app.core.auth.domain.exception.AuthErrorCode; +import com.gomo.app.core.auth.domain.exception.AuthenticationFailException; import jakarta.persistence.AttributeOverride; import jakarta.persistence.AttributeOverrides; diff --git a/src/main/java/com/gomo/app/core/member/domain/model/MemberName.java b/src/main/java/com/gomo/app/core/member/domain/model/MemberName.java index 0dadbd70..5f7c2806 100644 --- a/src/main/java/com/gomo/app/core/member/domain/model/MemberName.java +++ b/src/main/java/com/gomo/app/core/member/domain/model/MemberName.java @@ -3,8 +3,8 @@ import java.util.regex.Pattern; import com.gomo.app.common.arch.ValueObject; -import com.gomo.app.core.member.exception.MemberNameConstraintViolationException; -import com.gomo.app.core.member.exception.code.MemberNameErrorCode; +import com.gomo.app.core.member.domain.exception.MemberNameConstraintViolationException; +import com.gomo.app.core.member.domain.exception.code.MemberNameErrorCode; import jakarta.persistence.Embeddable; import lombok.Getter; @@ -14,54 +14,54 @@ @ValueObject public class MemberName { - private static final int MAX_NAME_LENGTH = 20; - private static final int MIN_NAME_LENGTH = 2; - private static final Pattern NAME_RULE = Pattern.compile("^(?!.*\\\\.\\\\.)(?!.*--)(?!.*__)[a-zA-Z0-9ㄱ-힣._-]+$"); + private static final int MAX_NAME_LENGTH = 20; + private static final int MIN_NAME_LENGTH = 2; + private static final Pattern NAME_RULE = Pattern.compile("^(?!.*\\\\.\\\\.)(?!.*--)(?!.*__)[a-zA-Z0-9ㄱ-힣._-]+$"); - private String name; + private String name; - protected MemberName() { - } + protected MemberName() { + } - private MemberName(String name) { - ensureNotBlank(name); - ensureNameLength(name); - ensureNameRule(name); - this.name = name; - } + private MemberName(String name) { + ensureNotBlank(name); + ensureNameLength(name); + ensureNameRule(name); + this.name = name; + } - public static MemberName of(String name) { - return new MemberName(name); - } + public static MemberName of(String name) { + return new MemberName(name); + } - public MemberName update(String name) { - return MemberName.of(name); - } + public MemberName update(String name) { + return MemberName.of(name); + } - private void ensureNotBlank(String name){ - if(name == null || name.isBlank()){ - throw new MemberNameConstraintViolationException(MemberNameErrorCode.BLANK); - } - } + private void ensureNotBlank(String name) { + if (name == null || name.isBlank()) { + throw new MemberNameConstraintViolationException(MemberNameErrorCode.BLANK); + } + } - private void ensureNameLength(String name){ - if(name.length() < MIN_NAME_LENGTH){ - throw new MemberNameConstraintViolationException(MemberNameErrorCode.TOO_SHORT); - } + private void ensureNameLength(String name) { + if (name.length() < MIN_NAME_LENGTH) { + throw new MemberNameConstraintViolationException(MemberNameErrorCode.TOO_SHORT); + } - if(name.length() > MAX_NAME_LENGTH){ - throw new MemberNameConstraintViolationException(MemberNameErrorCode.TOO_LONG); - } - } + if (name.length() > MAX_NAME_LENGTH) { + throw new MemberNameConstraintViolationException(MemberNameErrorCode.TOO_LONG); + } + } - private void ensureNameRule(String name){ - if(!NAME_RULE.matcher(name).matches()){ - throw new MemberNameConstraintViolationException(MemberNameErrorCode.FORBIDDEN); - } - } + private void ensureNameRule(String name) { + if (!NAME_RULE.matcher(name).matches()) { + throw new MemberNameConstraintViolationException(MemberNameErrorCode.FORBIDDEN); + } + } - @Override - public String toString() { - return this.name; - } + @Override + public String toString() { + return this.name; + } } diff --git a/src/main/java/com/gomo/app/core/member/domain/model/Motto.java b/src/main/java/com/gomo/app/core/member/domain/model/Motto.java index 09f13349..83840819 100644 --- a/src/main/java/com/gomo/app/core/member/domain/model/Motto.java +++ b/src/main/java/com/gomo/app/core/member/domain/model/Motto.java @@ -3,8 +3,8 @@ import java.util.regex.Pattern; import com.gomo.app.common.arch.ValueObject; -import com.gomo.app.core.member.exception.MottoConstraintViolationException; -import com.gomo.app.core.member.exception.code.MottoErrorCode; +import com.gomo.app.core.member.domain.exception.MottoConstraintViolationException; +import com.gomo.app.core.member.domain.exception.code.MottoErrorCode; import jakarta.persistence.Embeddable; import lombok.Getter; @@ -14,42 +14,42 @@ @ValueObject public class Motto { - private static final int MAX_MOTTO_LENGTH = 200; - private static final Pattern VALID_MOTTO_PATTERN = Pattern.compile("^[a-zA-Z0-9ㄱ-힣!@#$%^&*()_+=,.?\\s]+$"); + private static final int MAX_MOTTO_LENGTH = 200; + private static final Pattern VALID_MOTTO_PATTERN = Pattern.compile("^[a-zA-Z0-9ㄱ-힣!@#$%^&*()_+=,.?\\s]+$"); - private String motto; + private String motto; - protected Motto() { - } + protected Motto() { + } - private Motto(String motto) { - ensureValidMottoLength(motto); - ensureValidMottoRules(motto); - this.motto = motto; - } + private Motto(String motto) { + ensureValidMottoLength(motto); + ensureValidMottoRules(motto); + this.motto = motto; + } - public static Motto of(String motto) { - return new Motto(motto); - } + public static Motto of(String motto) { + return new Motto(motto); + } - public Motto update(String motto) { - return Motto.of(motto); - } + public Motto update(String motto) { + return Motto.of(motto); + } - private void ensureValidMottoLength(String motto){ - if(motto.length() > MAX_MOTTO_LENGTH){ - throw new MottoConstraintViolationException(MottoErrorCode.TOO_LONG); - } - } + private void ensureValidMottoLength(String motto) { + if (motto.length() > MAX_MOTTO_LENGTH) { + throw new MottoConstraintViolationException(MottoErrorCode.TOO_LONG); + } + } - private void ensureValidMottoRules(String motto){ - if(!VALID_MOTTO_PATTERN.matcher(motto).matches()){ - throw new MottoConstraintViolationException(MottoErrorCode.FORBIDDEN); - } - } + private void ensureValidMottoRules(String motto) { + if (!VALID_MOTTO_PATTERN.matcher(motto).matches()) { + throw new MottoConstraintViolationException(MottoErrorCode.FORBIDDEN); + } + } - @Override - public String toString() { - return this.motto; - } + @Override + public String toString() { + return this.motto; + } } diff --git a/src/main/java/com/gomo/app/core/member/domain/model/Password.java b/src/main/java/com/gomo/app/core/member/domain/model/Password.java index 14f96148..c33aec03 100644 --- a/src/main/java/com/gomo/app/core/member/domain/model/Password.java +++ b/src/main/java/com/gomo/app/core/member/domain/model/Password.java @@ -3,8 +3,8 @@ import java.util.regex.Pattern; import com.gomo.app.common.arch.ValueObject; -import com.gomo.app.core.member.exception.PasswordConstraintViolationException; -import com.gomo.app.core.member.exception.code.PasswordErrorCode; +import com.gomo.app.core.member.domain.exception.PasswordConstraintViolationException; +import com.gomo.app.core.member.domain.exception.code.PasswordErrorCode; import jakarta.persistence.Embeddable; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/member/domain/model/QuestProperty.java b/src/main/java/com/gomo/app/core/member/domain/model/QuestProperty.java index 2c20a2dd..e7175f75 100644 --- a/src/main/java/com/gomo/app/core/member/domain/model/QuestProperty.java +++ b/src/main/java/com/gomo/app/core/member/domain/model/QuestProperty.java @@ -1,8 +1,8 @@ package com.gomo.app.core.member.domain.model; import com.gomo.app.common.arch.ValueObject; -import com.gomo.app.core.member.exception.QuestPropertyConstraintViolationException; -import com.gomo.app.core.member.exception.code.QuestPropertyErrorCode; +import com.gomo.app.core.member.domain.exception.QuestPropertyConstraintViolationException; +import com.gomo.app.core.member.domain.exception.code.QuestPropertyErrorCode; import jakarta.persistence.AttributeOverride; import jakarta.persistence.AttributeOverrides; diff --git a/src/main/java/com/gomo/app/core/member/domain/service/MemberService.java b/src/main/java/com/gomo/app/core/member/domain/service/MemberService.java deleted file mode 100644 index e3bc3a55..00000000 --- a/src/main/java/com/gomo/app/core/member/domain/service/MemberService.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.gomo.app.core.member.domain.service; - -import java.util.UUID; - -import com.gomo.app.common.arch.DomainService; -import com.gomo.app.core.member.domain.model.Email; -import com.gomo.app.core.member.domain.model.Handle; -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.repository.MemberRepository; -import com.gomo.app.core.member.exception.EmailDuplicatedException; -import com.gomo.app.core.member.exception.HandleDuplicatedException; -import com.gomo.app.core.member.exception.MemberNotFoundException; -import com.gomo.app.core.member.exception.code.EmailErrorCode; -import com.gomo.app.core.member.exception.code.HandleErrorCode; -import com.gomo.app.core.member.exception.code.MemberErrorCode; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@DomainService -public class MemberService { - - private final MemberRepository memberRepository; - - public Member find(UUID memberId) { - return memberRepository.findById(memberId) - .orElseThrow(() -> new MemberNotFoundException(MemberErrorCode.NOT_FOUND)); - } - - public Member findByEmail(Email email) { - return memberRepository.findByEmail(email) - .orElseThrow(() -> new MemberNotFoundException(MemberErrorCode.NOT_FOUND)); - } - - public void checkEmailDuplicated(Email email) { - memberRepository.findByEmail(email).ifPresent(m -> { - throw new EmailDuplicatedException(EmailErrorCode.DUPLICATED); - }); - } - - public void checkHandleDuplicated(Handle handle) { - memberRepository.findByHandle(handle).ifPresent(m -> { - throw new HandleDuplicatedException(HandleErrorCode.DUPLICATED); - }); - } -} diff --git a/src/main/java/com/gomo/app/core/member/domain/service/ProfileImageService.java b/src/main/java/com/gomo/app/core/member/domain/service/ProfileImageService.java deleted file mode 100644 index 9f77e14a..00000000 --- a/src/main/java/com/gomo/app/core/member/domain/service/ProfileImageService.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.gomo.app.core.member.domain.service; - -import java.util.HashSet; -import java.util.Set; - -import com.gomo.app.common.arch.DomainService; -import com.gomo.app.core.member.domain.repository.MemberRepository; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@DomainService -public class ProfileImageService { - - private final MemberRepository memberRepository; - - public Set getAllProfileImageUrl(){ - return new HashSet<>(memberRepository.findAllByProfileImageUrl()); - } -} diff --git a/src/main/java/com/gomo/app/core/member/exception/MemberAuthenticationFailedException.java b/src/main/java/com/gomo/app/core/member/exception/MemberAuthenticationFailedException.java deleted file mode 100644 index 00977361..00000000 --- a/src/main/java/com/gomo/app/core/member/exception/MemberAuthenticationFailedException.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.gomo.app.core.member.exception; - -import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.member.exception.code.MemberErrorCode; - -public class MemberAuthenticationFailedException extends ApplicationException { - - public MemberAuthenticationFailedException(MemberErrorCode errorCode) { - super(errorCode.getHttpStatus(), errorCode.getErrorCode(), errorCode.getMessage()); - } - - public MemberAuthenticationFailedException(MemberErrorCode errorCode, Throwable cause) { - super(errorCode.getHttpStatus(), errorCode.getErrorCode(), errorCode.getMessage(), cause); - } -} diff --git a/src/main/java/com/gomo/app/core/member/exception/MemberDuplicatedException.java b/src/main/java/com/gomo/app/core/member/exception/MemberDuplicatedException.java deleted file mode 100644 index a2aa68a4..00000000 --- a/src/main/java/com/gomo/app/core/member/exception/MemberDuplicatedException.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.gomo.app.core.member.exception; - -import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.member.exception.code.MemberErrorCode; - -public class MemberDuplicatedException extends ApplicationException { - - public MemberDuplicatedException(MemberErrorCode errorCode) { - super(errorCode.getHttpStatus(), errorCode.getErrorCode(), errorCode.getMessage()); - } - - public MemberDuplicatedException(MemberErrorCode errorCode, Throwable cause) { - super(errorCode.getHttpStatus(), errorCode.getErrorCode(), errorCode.getMessage(), cause); - } -} diff --git a/src/main/java/com/gomo/app/core/member/presentation/EmailCodeApi.java b/src/main/java/com/gomo/app/core/member/presentation/EmailCodeApi.java deleted file mode 100644 index 859ff50f..00000000 --- a/src/main/java/com/gomo/app/core/member/presentation/EmailCodeApi.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.gomo.app.core.member.presentation; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; - -import com.gomo.app.common.arch.CoreApi; -import com.gomo.app.core.member.application.usecase.CreateEmailCodeUseCase; -import com.gomo.app.core.member.application.usecase.VerifyEmailCodeUseCase; -import com.gomo.app.core.member.presentation.request.CreateEmailCodeRequest; -import com.gomo.app.core.member.presentation.request.VerifyEmailCodeRequest; -import com.gomo.app.core.member.presentation.response.CreateEmailCodeResponse; -import com.gomo.app.core.member.presentation.response.VerifyEmailCodeResponse; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@RequestMapping("/members/emails/codes") -@CoreApi -public class EmailCodeApi { - - private final CreateEmailCodeUseCase createEmailCodeUseCase; - private final VerifyEmailCodeUseCase verifyEmailCodeUseCase; - - @PostMapping("/signup") - public ResponseEntity create(@RequestBody CreateEmailCodeRequest request) { - String emailCode = createEmailCodeUseCase.createForSignUp(request.getEmail()); - return ResponseEntity.status(HttpStatus.CREATED).body(CreateEmailCodeResponse.of(emailCode)); - } - - @PostMapping("/passwords/reset") - public ResponseEntity createForPassword(@RequestBody CreateEmailCodeRequest request) { - String emailCode = createEmailCodeUseCase.createForPasswordReset(request.getEmail()); - return ResponseEntity.status(HttpStatus.CREATED).body(CreateEmailCodeResponse.of(emailCode)); - } - - @PostMapping("/verify") - public ResponseEntity verify(@RequestBody VerifyEmailCodeRequest request) { - String temporaryToken = verifyEmailCodeUseCase.verify(request.getEmail(), request.getCode()); - return ResponseEntity.status(HttpStatus.OK).body(VerifyEmailCodeResponse.of(temporaryToken)); - } -} diff --git a/src/main/java/com/gomo/app/core/member/presentation/MemberApi.java b/src/main/java/com/gomo/app/core/member/presentation/MemberApi.java deleted file mode 100644 index 9839f561..00000000 --- a/src/main/java/com/gomo/app/core/member/presentation/MemberApi.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.gomo.app.core.member.presentation; - -import java.util.UUID; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; - -import com.gomo.app.common.arch.CoreApi; -import com.gomo.app.core.member.application.port.ReadMemberPortIn; -import com.gomo.app.core.member.application.port.dto.MemberDto; -import com.gomo.app.core.member.application.usecase.CreateMemberUseCase; -import com.gomo.app.core.member.application.usecase.DeleteMemberUseCase; -import com.gomo.app.core.member.application.usecase.UpdateMemberUseCase; -import com.gomo.app.core.member.presentation.request.CreateMemberRequest; -import com.gomo.app.core.member.presentation.request.UpdateMemberRequest; -import com.gomo.app.core.member.presentation.response.CreateMemberResponse; -import com.gomo.app.core.member.presentation.response.ReadMemberResponse; -import com.gomo.app.support.auth.presentation.security.Auth; -import com.gomo.app.support.auth.presentation.security.AuthInfo; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@RequestMapping("/members") -@CoreApi -public class MemberApi { - - private final CreateMemberUseCase createMemberUseCase; - private final ReadMemberPortIn readMemberPortIn; - private final UpdateMemberUseCase updateMemberUseCase; - private final DeleteMemberUseCase deleteMemberUseCase; - - @PostMapping - public ResponseEntity create(@RequestBody CreateMemberRequest request) { - UUID memberId = createMemberUseCase.create(request.toCommand()); - return ResponseEntity.status(HttpStatus.CREATED).body(CreateMemberResponse.of(memberId)); - } - - @GetMapping - public ResponseEntity read(@Auth AuthInfo authInfo) { - MemberDto dto = readMemberPortIn.find(authInfo.getMemberId()); - return ResponseEntity.ok(ReadMemberResponse.of(dto)); - } - - @PutMapping - public ResponseEntity update(@Auth AuthInfo authInfo, @RequestBody UpdateMemberRequest request) { - updateMemberUseCase.update(authInfo.getMemberId(), request.getName(), request.getMotto()); - return ResponseEntity.noContent().build(); - } - - @DeleteMapping - public ResponseEntity delete(@Auth AuthInfo authInfo) { - deleteMemberUseCase.delete(authInfo.getMemberId()); - return ResponseEntity.noContent().build(); - } -} diff --git a/src/main/java/com/gomo/app/core/member/presentation/PasswordApi.java b/src/main/java/com/gomo/app/core/member/presentation/PasswordApi.java deleted file mode 100644 index 14f45986..00000000 --- a/src/main/java/com/gomo/app/core/member/presentation/PasswordApi.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.gomo.app.core.member.presentation; - -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; - -import com.gomo.app.common.arch.CoreApi; -import com.gomo.app.core.member.application.usecase.ResetPasswordUseCase; -import com.gomo.app.core.member.application.usecase.UpdatePasswordUseCase; -import com.gomo.app.core.member.presentation.request.ResetPasswordRequest; -import com.gomo.app.core.member.presentation.request.UpdatePasswordRequest; -import com.gomo.app.support.auth.presentation.security.Auth; -import com.gomo.app.support.auth.presentation.security.AuthInfo; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@RequestMapping("/members/passwords") -@CoreApi -public class PasswordApi { - - private final UpdatePasswordUseCase updatePasswordUseCase; - private final ResetPasswordUseCase resetPasswordUseCase; - - @PutMapping - public ResponseEntity update(@Auth AuthInfo authInfo, @RequestBody UpdatePasswordRequest request) { - updatePasswordUseCase.update(authInfo.getMemberId(), request.getOriginPassword(), request.getNewPassword()); - return ResponseEntity.noContent().build(); - } - - @PutMapping("/reset") - public ResponseEntity reset(@RequestBody ResetPasswordRequest request) { - resetPasswordUseCase.reset(request.getEmail(), request.getNewPassword(), request.getTemporaryToken()); - return ResponseEntity.noContent().build(); - } -} diff --git a/src/main/java/com/gomo/app/core/member/presentation/request/CreateMemberRequest.java b/src/main/java/com/gomo/app/core/member/presentation/request/CreateMemberRequest.java deleted file mode 100644 index b878e538..00000000 --- a/src/main/java/com/gomo/app/core/member/presentation/request/CreateMemberRequest.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.gomo.app.core.member.presentation.request; - -import com.gomo.app.core.member.application.port.command.CreateMemberCommand; - -import lombok.Getter; - -@Getter -public class CreateMemberRequest { - - private final String email; - private final String password; - private final String handle; - private final String name; - private final String motto; - private final String loginProvider; - private final String temporaryToken; - - private CreateMemberRequest(String email, String password, String handle, String name, String motto, String loginProvider, String temporaryToken) { - this.email = email; - this.password = password; - this.handle = handle; - this.name = name; - this.motto = motto; - this.loginProvider = loginProvider; - this.temporaryToken = temporaryToken; - } - - public static CreateMemberRequest of(String email, String password, String handle, String name, String motto, String loginProvider, String temporaryToken) { - return new CreateMemberRequest(email, password, handle, name, motto, loginProvider, temporaryToken); - } - - public CreateMemberCommand toCommand() { - return CreateMemberCommand.of(email, password, handle, name, motto, loginProvider, temporaryToken); - } -} diff --git a/src/main/java/com/gomo/app/core/member/presentation/response/CreateEmailCodeResponse.java b/src/main/java/com/gomo/app/core/member/presentation/response/CreateEmailCodeResponse.java deleted file mode 100644 index 9b9c407e..00000000 --- a/src/main/java/com/gomo/app/core/member/presentation/response/CreateEmailCodeResponse.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.gomo.app.core.member.presentation.response; - -import lombok.Getter; -import lombok.ToString; - -@Getter -@ToString -public class CreateEmailCodeResponse { - - private final String code; - - private CreateEmailCodeResponse(String code) { - this.code = code; - } - - public static CreateEmailCodeResponse of(String code) { - return new CreateEmailCodeResponse(code); - } -} diff --git a/src/main/java/com/gomo/app/core/member/presentation/response/CreateMemberResponse.java b/src/main/java/com/gomo/app/core/member/presentation/response/CreateMemberResponse.java deleted file mode 100644 index ffa193a5..00000000 --- a/src/main/java/com/gomo/app/core/member/presentation/response/CreateMemberResponse.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.gomo.app.core.member.presentation.response; - -import java.util.UUID; - -import lombok.Getter; -import lombok.ToString; - -@Getter -@ToString -public class CreateMemberResponse { - - private final UUID id; - - private CreateMemberResponse(UUID id) { - this.id = id; - } - - public static CreateMemberResponse of(UUID id) { - return new CreateMemberResponse(id); - } -} diff --git a/src/main/java/com/gomo/app/core/point/presentation/api/PointApi.java b/src/main/java/com/gomo/app/core/point/adapter/in/api/PointApi.java similarity index 53% rename from src/main/java/com/gomo/app/core/point/presentation/api/PointApi.java rename to src/main/java/com/gomo/app/core/point/adapter/in/api/PointApi.java index fa53f4eb..9345b926 100644 --- a/src/main/java/com/gomo/app/core/point/presentation/api/PointApi.java +++ b/src/main/java/com/gomo/app/core/point/adapter/in/api/PointApi.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.point.presentation.api; +package com.gomo.app.core.point.adapter.in.api; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -7,13 +7,13 @@ import com.gomo.app.common.arch.CoreApi; import com.gomo.app.common.web.PageRequest; -import com.gomo.app.core.point.application.port.ReadBalancePortIn; +import com.gomo.app.core.point.adapter.in.api.response.ListPointResponse; +import com.gomo.app.core.point.adapter.in.api.response.ReadBalanceResponse; import com.gomo.app.core.point.application.port.dto.ListPointDto; -import com.gomo.app.core.point.application.usecase.ReadPointUseCase; -import com.gomo.app.core.point.presentation.api.response.ListPointResponse; -import com.gomo.app.core.point.presentation.api.response.ReadBalanceResponse; -import com.gomo.app.support.auth.presentation.security.Auth; -import com.gomo.app.support.auth.presentation.security.AuthInfo; +import com.gomo.app.core.point.application.port.in.BalanceReader; +import com.gomo.app.core.point.application.port.in.PointReader; +import com.gomo.app.core.auth.adapter.in.security.Auth; +import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -22,18 +22,18 @@ @CoreApi public class PointApi { - private final ReadPointUseCase readPointUseCase; - private final ReadBalancePortIn readBalancePortIn; + private final PointReader pointReader; + private final BalanceReader balanceReader; @GetMapping public ResponseEntity findAll(@Auth AuthInfo authInfo, @ModelAttribute PageRequest pageRequest) { - ListPointDto dto = readPointUseCase.findAll(authInfo.getMemberId(), pageRequest); + ListPointDto dto = pointReader.readAll(authInfo.getPrincipalId(), pageRequest); return ResponseEntity.ok(ListPointResponse.from(dto)); } @GetMapping("/balances") public ResponseEntity findBalance(@Auth AuthInfo authInfo) { - int balance = readBalancePortIn.find(authInfo.getMemberId()); + int balance = balanceReader.read(authInfo.getPrincipalId()); return ResponseEntity.ok(ReadBalanceResponse.of(balance)); } } diff --git a/src/main/java/com/gomo/app/core/point/presentation/api/response/ListPointResponse.java b/src/main/java/com/gomo/app/core/point/adapter/in/api/response/ListPointResponse.java similarity index 87% rename from src/main/java/com/gomo/app/core/point/presentation/api/response/ListPointResponse.java rename to src/main/java/com/gomo/app/core/point/adapter/in/api/response/ListPointResponse.java index 4cb1d2ee..00f00316 100644 --- a/src/main/java/com/gomo/app/core/point/presentation/api/response/ListPointResponse.java +++ b/src/main/java/com/gomo/app/core/point/adapter/in/api/response/ListPointResponse.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.point.presentation.api.response; +package com.gomo.app.core.point.adapter.in.api.response; import java.util.List; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/point/presentation/api/response/ReadBalanceResponse.java b/src/main/java/com/gomo/app/core/point/adapter/in/api/response/ReadBalanceResponse.java similarity index 77% rename from src/main/java/com/gomo/app/core/point/presentation/api/response/ReadBalanceResponse.java rename to src/main/java/com/gomo/app/core/point/adapter/in/api/response/ReadBalanceResponse.java index bdb47f34..c608cac0 100644 --- a/src/main/java/com/gomo/app/core/point/presentation/api/response/ReadBalanceResponse.java +++ b/src/main/java/com/gomo/app/core/point/adapter/in/api/response/ReadBalanceResponse.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.point.presentation.api.response; +package com.gomo.app.core.point.adapter.in.api.response; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/point/presentation/api/response/ReadPointResponse.java b/src/main/java/com/gomo/app/core/point/adapter/in/api/response/ReadPointResponse.java similarity index 91% rename from src/main/java/com/gomo/app/core/point/presentation/api/response/ReadPointResponse.java rename to src/main/java/com/gomo/app/core/point/adapter/in/api/response/ReadPointResponse.java index 9dc5ab47..b81ddd30 100644 --- a/src/main/java/com/gomo/app/core/point/presentation/api/response/ReadPointResponse.java +++ b/src/main/java/com/gomo/app/core/point/adapter/in/api/response/ReadPointResponse.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.point.presentation.api.response; +package com.gomo.app.core.point.adapter.in.api.response; import java.time.LocalDateTime; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/point/presentation/consumer/CompleteQuestEventPointConsumer.java b/src/main/java/com/gomo/app/core/point/adapter/in/consumer/CompleteQuestEventPointConsumer.java similarity index 66% rename from src/main/java/com/gomo/app/core/point/presentation/consumer/CompleteQuestEventPointConsumer.java rename to src/main/java/com/gomo/app/core/point/adapter/in/consumer/CompleteQuestEventPointConsumer.java index 562d5256..5e6cd85e 100644 --- a/src/main/java/com/gomo/app/core/point/presentation/consumer/CompleteQuestEventPointConsumer.java +++ b/src/main/java/com/gomo/app/core/point/adapter/in/consumer/CompleteQuestEventPointConsumer.java @@ -1,11 +1,11 @@ -package com.gomo.app.core.point.presentation.consumer; +package com.gomo.app.core.point.adapter.in.consumer; import org.springframework.amqp.rabbit.annotation.RabbitListener; import com.gomo.app.common.arch.EventConsumer; import com.gomo.app.common.util.JsonParser; -import com.gomo.app.core.point.application.port.CreatePointPortIn; -import com.gomo.app.core.quest.event.CompleteQuestEvent; +import com.gomo.app.core.point.application.port.in.PointCreator; +import com.gomo.app.core.quest.domain.event.CompleteQuestEvent; import com.gomo.app.support.evententry.application.port.IdempotentEventEntryConsumer; import com.gomo.app.support.evententry.domain.model.EventEntry; @@ -15,12 +15,12 @@ @EventConsumer public class CompleteQuestEventPointConsumer { - private final CreatePointPortIn createPointPortIn; + private final PointCreator pointCreator; @IdempotentEventEntryConsumer @RabbitListener(queues = "event.quest.assign.complete.point") public void handleEvent(EventEntry eventEntry) { CompleteQuestEvent event = JsonParser.fromJson(eventEntry.getPayload(), CompleteQuestEvent.class); - createPointPortIn.create(event.getParticipantId(), "QUEST", "GAIN", event.getPointReward()); + pointCreator.create(event.getParticipantId(), "QUEST", "GAIN", event.getPointReward()); } } diff --git a/src/main/java/com/gomo/app/core/point/application/port/ReadBalancePortIn.java b/src/main/java/com/gomo/app/core/point/application/port/in/BalanceReader.java similarity index 63% rename from src/main/java/com/gomo/app/core/point/application/port/ReadBalancePortIn.java rename to src/main/java/com/gomo/app/core/point/application/port/in/BalanceReader.java index 093c9d27..6baa19af 100644 --- a/src/main/java/com/gomo/app/core/point/application/port/ReadBalancePortIn.java +++ b/src/main/java/com/gomo/app/core/point/application/port/in/BalanceReader.java @@ -1,10 +1,10 @@ -package com.gomo.app.core.point.application.port; +package com.gomo.app.core.point.application.port.in; import java.util.UUID; -import com.gomo.app.core.point.exception.PointWalletNotFoundException; +import com.gomo.app.core.point.domain.exception.PointWalletNotFoundException; -public interface ReadBalancePortIn { +public interface BalanceReader { /** * Retrieves the current balance of a specific point wallet. @@ -13,5 +13,5 @@ public interface ReadBalancePortIn { * @return The current point balance as an integer. * @throws PointWalletNotFoundException if no wallet is found for the given transactor ID. */ - int find(UUID transactorId); + int read(UUID transactorId); } diff --git a/src/main/java/com/gomo/app/core/point/application/port/CreatePointPortIn.java b/src/main/java/com/gomo/app/core/point/application/port/in/PointCreator.java similarity index 90% rename from src/main/java/com/gomo/app/core/point/application/port/CreatePointPortIn.java rename to src/main/java/com/gomo/app/core/point/application/port/in/PointCreator.java index e5356aa4..91945b8c 100644 --- a/src/main/java/com/gomo/app/core/point/application/port/CreatePointPortIn.java +++ b/src/main/java/com/gomo/app/core/point/application/port/in/PointCreator.java @@ -1,11 +1,11 @@ -package com.gomo.app.core.point.application.port; +package com.gomo.app.core.point.application.port.in; import java.util.UUID; import com.gomo.app.core.point.domain.model.SourceType; import com.gomo.app.core.point.domain.model.TransactionType; -public interface CreatePointPortIn { +public interface PointCreator { /** * Creates a new point transaction. diff --git a/src/main/java/com/gomo/app/core/point/application/port/in/PointReader.java b/src/main/java/com/gomo/app/core/point/application/port/in/PointReader.java new file mode 100644 index 00000000..71df8feb --- /dev/null +++ b/src/main/java/com/gomo/app/core/point/application/port/in/PointReader.java @@ -0,0 +1,19 @@ +package com.gomo.app.core.point.application.port.in; + +import java.util.UUID; + +import com.gomo.app.common.web.PageRequest; +import com.gomo.app.core.point.application.port.dto.ListPointDto; + +public interface PointReader { + + /** + * Retrieves a paginated list of point transaction histories for a specific transactor. + * + * @param transactorId The ID of the transactor (e.g., a member) whose point history is to be retrieved. + * @param pageRequest A {@link PageRequest} object containing cursor-based pagination details. + * @return A {@link ListPointDto} containing the list of point transactions for the requested page. + * The list will be empty if there are no transactions; this method does not return null. + */ + ListPointDto readAll(UUID transactorId, PageRequest pageRequest); +} diff --git a/src/main/java/com/gomo/app/core/point/application/port/CreatePointWalletPortIn.java b/src/main/java/com/gomo/app/core/point/application/port/in/PointWalletCreator.java similarity index 60% rename from src/main/java/com/gomo/app/core/point/application/port/CreatePointWalletPortIn.java rename to src/main/java/com/gomo/app/core/point/application/port/in/PointWalletCreator.java index 85742cc3..55013ad3 100644 --- a/src/main/java/com/gomo/app/core/point/application/port/CreatePointWalletPortIn.java +++ b/src/main/java/com/gomo/app/core/point/application/port/in/PointWalletCreator.java @@ -1,15 +1,15 @@ -package com.gomo.app.core.point.application.port; +package com.gomo.app.core.point.application.port.in; import java.util.UUID; -public interface CreatePointWalletPortIn { +public interface PointWalletCreator { /** * Creates a new point wallet for the given transactor. * * @param transactorId The id of the entity (e.g., member ID) for whom the wallet is being created. * @return The id (UUID) of the newly created point wallet. - * @throws PointWalletAlreadyExistsException if a wallet for the given transactor ID already exists. + * @throws IllegalStateException if a wallet for the given transactor ID already exists. */ UUID create(UUID transactorId); } diff --git a/src/main/java/com/gomo/app/core/point/application/service/BalanceService.java b/src/main/java/com/gomo/app/core/point/application/service/BalanceService.java new file mode 100644 index 00000000..9415a0a7 --- /dev/null +++ b/src/main/java/com/gomo/app/core/point/application/service/BalanceService.java @@ -0,0 +1,22 @@ +package com.gomo.app.core.point.application.service; + +import java.util.UUID; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.core.point.application.port.in.BalanceReader; +import com.gomo.app.core.point.domain.model.Balance; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@ApplicationService +class BalanceService implements BalanceReader { + + private final PointWalletService pointWalletService; + + @Override + public int read(UUID transactorId) { + Balance balance = pointWalletService.readBalance(transactorId); + return balance.getAmount(); + } +} diff --git a/src/main/java/com/gomo/app/core/point/application/service/PointService.java b/src/main/java/com/gomo/app/core/point/application/service/PointService.java new file mode 100644 index 00000000..4ecb3dde --- /dev/null +++ b/src/main/java/com/gomo/app/core/point/application/service/PointService.java @@ -0,0 +1,73 @@ +package com.gomo.app.core.point.application.service; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.UUID; + +import org.jetbrains.annotations.Nullable; +import org.springframework.transaction.annotation.Transactional; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.common.util.UUIDGenerator; +import com.gomo.app.common.web.PageRequest; +import com.gomo.app.core.point.application.port.dto.ListPointDto; +import com.gomo.app.core.point.application.port.dto.PointDto; +import com.gomo.app.core.point.application.port.in.PointCreator; +import com.gomo.app.core.point.application.port.in.PointReader; +import com.gomo.app.core.point.domain.model.Point; +import com.gomo.app.core.point.domain.model.SourceType; +import com.gomo.app.core.point.domain.model.TransactionType; +import com.gomo.app.core.point.domain.repository.PointRepository; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Transactional +@ApplicationService +class PointService implements PointCreator, PointReader { + + private final PointWalletService pointWalletService; + private final PointRepository pointRepository; + + @Override + @AuditLog(action = "POINT_CREATE") + public void create(UUID transactorId, String sourceType, String transactionType, int amount) { + SourceType source = SourceType.valueOf(sourceType); + TransactionType transaction = TransactionType.valueOf(transactionType); + Point point = Point.of( + UUIDGenerator.generate(), + transactorId, + source, + transaction, + amount, + source.getDescription() + transaction.getDescription(), + LocalDateTime.now() + ); + + pointWalletService.adjustPointBalance(transactorId, transaction, amount); + pointRepository.save(point); + } + + @Override + @Transactional(readOnly = true) + public ListPointDto readAll(UUID transactorId, PageRequest pageRequest) { + List points = pointRepository.findAllByTransactorId( + transactorId.toString(), + pageRequest.getLastElementTime(), + pageRequest.getLastElementId(), + pageRequest.getSize()) + .stream() + .map(PointDto::from) + .toList(); + return ListPointDto.of(points, getLastElementId(points)); + } + + @Nullable + private UUID getLastElementId(List list) { + if (list.isEmpty()) { + return null; + } + return list.getLast().id(); + } +} diff --git a/src/main/java/com/gomo/app/core/point/application/service/PointWalletService.java b/src/main/java/com/gomo/app/core/point/application/service/PointWalletService.java new file mode 100644 index 00000000..4fb930ab --- /dev/null +++ b/src/main/java/com/gomo/app/core/point/application/service/PointWalletService.java @@ -0,0 +1,56 @@ +package com.gomo.app.core.point.application.service; + +import java.util.UUID; + +import org.springframework.transaction.annotation.Transactional; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.common.util.UUIDGenerator; +import com.gomo.app.core.point.application.port.in.PointWalletCreator; +import com.gomo.app.core.point.domain.exception.PointWalletNotFoundException; +import com.gomo.app.core.point.domain.exception.code.PointWalletErrorCode; +import com.gomo.app.core.point.domain.model.Balance; +import com.gomo.app.core.point.domain.model.PointWallet; +import com.gomo.app.core.point.domain.model.TransactionType; +import com.gomo.app.core.point.domain.repository.PointWalletRepository; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Transactional +@ApplicationService +class PointWalletService implements PointWalletCreator { + + private final PointWalletRepository pointWalletRepository; + + @Override + @AuditLog(action = "CREATE_POINT_WALLET") + public UUID create(UUID transactorId) { + ensureNotDuplicated(transactorId); + PointWallet pointWallet = PointWallet.createDefault(UUIDGenerator.generate(), transactorId); + PointWallet savedPointWallet = pointWalletRepository.save(pointWallet); + return savedPointWallet.getId(); + } + + private void ensureNotDuplicated(UUID transactorId) { + if (pointWalletRepository.existsByTransactorId(transactorId)) { + throw new IllegalStateException("Point wallet already exists with transactorId " + transactorId); + } + } + + void adjustPointBalance(UUID transactorId, TransactionType transactionType, int deltaAmount) { + PointWallet pointWallet = readByTransactorId(transactorId); + pointWallet.adjustBalance(transactionType.getOperationType() * deltaAmount); + } + + Balance readBalance(UUID transactorId) { + PointWallet pointWallet = readByTransactorId(transactorId); + return pointWallet.getBalance(); + } + + PointWallet readByTransactorId(UUID transactorId) { + return pointWalletRepository.findByTransactorId(transactorId) + .orElseThrow(() -> new PointWalletNotFoundException(PointWalletErrorCode.NOT_FOUND)); + } +} diff --git a/src/main/java/com/gomo/app/core/point/application/usecase/CreatePointUseCase.java b/src/main/java/com/gomo/app/core/point/application/usecase/CreatePointUseCase.java deleted file mode 100644 index fab617e5..00000000 --- a/src/main/java/com/gomo/app/core/point/application/usecase/CreatePointUseCase.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.gomo.app.core.point.application.usecase; - -import java.util.UUID; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.point.application.port.CreatePointPortIn; -import com.gomo.app.core.point.domain.model.SourceType; -import com.gomo.app.core.point.domain.model.TransactionType; -import com.gomo.app.core.point.domain.service.PointService; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -class CreatePointUseCase implements CreatePointPortIn { - - private final PointService pointService; - - @Override - public void create(UUID transactorId, String sourceType, String transactionType, int amount) { - pointService.create(transactorId, SourceType.valueOf(sourceType), TransactionType.valueOf(transactionType), amount); - } -} diff --git a/src/main/java/com/gomo/app/core/point/application/usecase/CreatePointWalletUseCase.java b/src/main/java/com/gomo/app/core/point/application/usecase/CreatePointWalletUseCase.java deleted file mode 100644 index 45a949d1..00000000 --- a/src/main/java/com/gomo/app/core/point/application/usecase/CreatePointWalletUseCase.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.gomo.app.core.point.application.usecase; - -import java.util.UUID; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.common.util.UUIDGenerator; -import com.gomo.app.core.point.application.port.CreatePointWalletPortIn; -import com.gomo.app.core.point.domain.model.PointWallet; -import com.gomo.app.core.point.domain.repository.PointWalletRepository; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -class CreatePointWalletUseCase implements CreatePointWalletPortIn { - - private final PointWalletRepository pointWalletRepository; - - // TODO [2025-10-10] jhl221123 : 이미 해당 transactor의 포인트 지갑이 존재한다면 예외가 발생해야한다. - @AuditLog(action = "CREATE_POINT_WALLET") - @Override - public UUID create(UUID transactorId) { - PointWallet pointWallet = PointWallet.createDefault(UUIDGenerator.generate(), transactorId); - PointWallet savedPointWallet = pointWalletRepository.save(pointWallet); - return savedPointWallet.getId(); - } -} diff --git a/src/main/java/com/gomo/app/core/point/application/usecase/ReadBalanceUseCase.java b/src/main/java/com/gomo/app/core/point/application/usecase/ReadBalanceUseCase.java deleted file mode 100644 index 2fe48158..00000000 --- a/src/main/java/com/gomo/app/core/point/application/usecase/ReadBalanceUseCase.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.gomo.app.core.point.application.usecase; - -import java.util.UUID; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.point.application.port.ReadBalancePortIn; -import com.gomo.app.core.point.domain.model.Balance; -import com.gomo.app.core.point.domain.service.PointWalletService; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -class ReadBalanceUseCase implements ReadBalancePortIn { - - private final PointWalletService pointWalletService; - - @Override - public int find(UUID transactorId) { - Balance balance = pointWalletService.findBalance(transactorId); - return balance.getAmount(); - } -} diff --git a/src/main/java/com/gomo/app/core/point/application/usecase/ReadPointUseCase.java b/src/main/java/com/gomo/app/core/point/application/usecase/ReadPointUseCase.java deleted file mode 100644 index 9674520b..00000000 --- a/src/main/java/com/gomo/app/core/point/application/usecase/ReadPointUseCase.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.gomo.app.core.point.application.usecase; - -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -import org.jetbrains.annotations.Nullable; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.common.web.PageRequest; -import com.gomo.app.core.point.application.port.dto.ListPointDto; -import com.gomo.app.core.point.application.port.dto.PointDto; -import com.gomo.app.core.point.domain.repository.PointRepository; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -public class ReadPointUseCase { - - private final PointRepository pointRepository; - - public ListPointDto findAll(UUID transactorId, PageRequest pageRequest) { - List points = pointRepository.findAllByTransactorId( - transactorId.toString(), - Optional.ofNullable(pageRequest.getLastElementId()).map(UUID::toString).orElse(null), - pageRequest.getSize()) - .stream() - .map(PointDto::from) - .toList(); - return ListPointDto.of(points, getLastElementId(points)); - } - - @Nullable - private UUID getLastElementId(List list) { - if (list.isEmpty()) { - return null; - } - return list.getLast().id(); - } -} diff --git a/src/main/java/com/gomo/app/core/point/exception/InsufficientBalanceException.java b/src/main/java/com/gomo/app/core/point/domain/exception/InsufficientBalanceException.java similarity index 77% rename from src/main/java/com/gomo/app/core/point/exception/InsufficientBalanceException.java rename to src/main/java/com/gomo/app/core/point/domain/exception/InsufficientBalanceException.java index 9046be08..bc90fde2 100644 --- a/src/main/java/com/gomo/app/core/point/exception/InsufficientBalanceException.java +++ b/src/main/java/com/gomo/app/core/point/domain/exception/InsufficientBalanceException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.point.exception; +package com.gomo.app.core.point.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.point.exception.code.BalanceErrorCode; +import com.gomo.app.core.point.domain.exception.code.BalanceErrorCode; public class InsufficientBalanceException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/point/exception/PointConstraintViolationException.java b/src/main/java/com/gomo/app/core/point/domain/exception/PointConstraintViolationException.java similarity index 78% rename from src/main/java/com/gomo/app/core/point/exception/PointConstraintViolationException.java rename to src/main/java/com/gomo/app/core/point/domain/exception/PointConstraintViolationException.java index a20f516c..32a25538 100644 --- a/src/main/java/com/gomo/app/core/point/exception/PointConstraintViolationException.java +++ b/src/main/java/com/gomo/app/core/point/domain/exception/PointConstraintViolationException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.point.exception; +package com.gomo.app.core.point.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.point.exception.code.PointErrorCode; +import com.gomo.app.core.point.domain.exception.code.PointErrorCode; public class PointConstraintViolationException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/point/exception/PointWalletNotFoundException.java b/src/main/java/com/gomo/app/core/point/domain/exception/PointWalletNotFoundException.java similarity index 77% rename from src/main/java/com/gomo/app/core/point/exception/PointWalletNotFoundException.java rename to src/main/java/com/gomo/app/core/point/domain/exception/PointWalletNotFoundException.java index c6746cea..10d1b2fe 100644 --- a/src/main/java/com/gomo/app/core/point/exception/PointWalletNotFoundException.java +++ b/src/main/java/com/gomo/app/core/point/domain/exception/PointWalletNotFoundException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.point.exception; +package com.gomo.app.core.point.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.point.exception.code.PointWalletErrorCode; +import com.gomo.app.core.point.domain.exception.code.PointWalletErrorCode; public class PointWalletNotFoundException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/point/exception/code/BalanceErrorCode.java b/src/main/java/com/gomo/app/core/point/domain/exception/code/BalanceErrorCode.java similarity index 84% rename from src/main/java/com/gomo/app/core/point/exception/code/BalanceErrorCode.java rename to src/main/java/com/gomo/app/core/point/domain/exception/code/BalanceErrorCode.java index 8b62d6c0..4a3ff447 100644 --- a/src/main/java/com/gomo/app/core/point/exception/code/BalanceErrorCode.java +++ b/src/main/java/com/gomo/app/core/point/domain/exception/code/BalanceErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.point.exception.code; +package com.gomo.app.core.point.domain.exception.code; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/point/exception/code/PointErrorCode.java b/src/main/java/com/gomo/app/core/point/domain/exception/code/PointErrorCode.java similarity index 87% rename from src/main/java/com/gomo/app/core/point/exception/code/PointErrorCode.java rename to src/main/java/com/gomo/app/core/point/domain/exception/code/PointErrorCode.java index c4779d49..64022a7a 100644 --- a/src/main/java/com/gomo/app/core/point/exception/code/PointErrorCode.java +++ b/src/main/java/com/gomo/app/core/point/domain/exception/code/PointErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.point.exception.code; +package com.gomo.app.core.point.domain.exception.code; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/point/exception/code/PointWalletErrorCode.java b/src/main/java/com/gomo/app/core/point/domain/exception/code/PointWalletErrorCode.java similarity index 86% rename from src/main/java/com/gomo/app/core/point/exception/code/PointWalletErrorCode.java rename to src/main/java/com/gomo/app/core/point/domain/exception/code/PointWalletErrorCode.java index 628eaf04..36a29637 100644 --- a/src/main/java/com/gomo/app/core/point/exception/code/PointWalletErrorCode.java +++ b/src/main/java/com/gomo/app/core/point/domain/exception/code/PointWalletErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.point.exception.code; +package com.gomo.app.core.point.domain.exception.code; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/point/domain/model/Balance.java b/src/main/java/com/gomo/app/core/point/domain/model/Balance.java index 2a504a69..846d7e58 100644 --- a/src/main/java/com/gomo/app/core/point/domain/model/Balance.java +++ b/src/main/java/com/gomo/app/core/point/domain/model/Balance.java @@ -1,8 +1,8 @@ package com.gomo.app.core.point.domain.model; import com.gomo.app.common.arch.ValueObject; -import com.gomo.app.core.point.exception.InsufficientBalanceException; -import com.gomo.app.core.point.exception.code.BalanceErrorCode; +import com.gomo.app.core.point.domain.exception.InsufficientBalanceException; +import com.gomo.app.core.point.domain.exception.code.BalanceErrorCode; import jakarta.persistence.Embeddable; import lombok.Getter; @@ -32,7 +32,7 @@ public Balance update(int deltaAmount) { } private void ensureAmountNotNegative(int amount) { - if(amount < 0) { + if (amount < 0) { throw new InsufficientBalanceException(BalanceErrorCode.INSUFFICIENT_BALANCE); } } diff --git a/src/main/java/com/gomo/app/core/point/domain/model/Point.java b/src/main/java/com/gomo/app/core/point/domain/model/Point.java index 67d02230..eaa16d5b 100644 --- a/src/main/java/com/gomo/app/core/point/domain/model/Point.java +++ b/src/main/java/com/gomo/app/core/point/domain/model/Point.java @@ -4,8 +4,8 @@ import java.util.UUID; import com.gomo.app.common.jpa.BaseAudit; -import com.gomo.app.core.point.exception.PointConstraintViolationException; -import com.gomo.app.core.point.exception.code.PointErrorCode; +import com.gomo.app.core.point.domain.exception.PointConstraintViolationException; +import com.gomo.app.core.point.domain.exception.code.PointErrorCode; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; diff --git a/src/main/java/com/gomo/app/core/point/domain/repository/PointRepository.java b/src/main/java/com/gomo/app/core/point/domain/repository/PointRepository.java index 8b6f6b6e..c9770e1d 100644 --- a/src/main/java/com/gomo/app/core/point/domain/repository/PointRepository.java +++ b/src/main/java/com/gomo/app/core/point/domain/repository/PointRepository.java @@ -1,5 +1,6 @@ package com.gomo.app.core.point.domain.repository; +import java.time.LocalDateTime; import java.util.List; import java.util.UUID; @@ -12,14 +13,17 @@ public interface PointRepository extends JpaRepository { + // TODO [2025-11-01] jhl221123 : 복합 인덱스 추가 후, 성능 테스트 필요 @Query(value = "select p.* from point p " + "where p.transactor_id = UNHEX(REPLACE(:transactorId, '-', '')) " + - "and (UNHEX(REPLACE(:lastElementId, '-', '')) is null " + - "or p.id < UNHEX(REPLACE(:lastElementId, '-', ''))) " + - "order by p.transaction_date_time desc " + + "and (:lastTransactionDateTime is null or " + + "p.transaction_date_time < :lastTransactionDateTime or " + + "(p.transaction_date_time = :lastTransactionDateTime and p.id < UNHEX(REPLACE(:lastElementId, '-', '')))) " + + "order by p.transaction_date_time desc, p.id desc " + "limit :size", nativeQuery = true) List findAllByTransactorId( @Param("transactorId") String transactorId, + @Param("lastTransactionDateTime") LocalDateTime lastTransactionDateTime, @Param("lastElementId") String lastElementId, @Param("size") int size ); diff --git a/src/main/java/com/gomo/app/core/point/domain/repository/PointWalletRepository.java b/src/main/java/com/gomo/app/core/point/domain/repository/PointWalletRepository.java index 4f4fff51..52935fc2 100644 --- a/src/main/java/com/gomo/app/core/point/domain/repository/PointWalletRepository.java +++ b/src/main/java/com/gomo/app/core/point/domain/repository/PointWalletRepository.java @@ -12,4 +12,6 @@ public interface PointWalletRepository extends JpaRepository Optional findByTransactorId(UUID transactorId); void deletePointWalletByTransactorId(UUID transactorId); + + boolean existsByTransactorId(UUID transactorId); } diff --git a/src/main/java/com/gomo/app/core/point/domain/service/PointService.java b/src/main/java/com/gomo/app/core/point/domain/service/PointService.java deleted file mode 100644 index 6492940e..00000000 --- a/src/main/java/com/gomo/app/core/point/domain/service/PointService.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.gomo.app.core.point.domain.service; - -import java.time.LocalDateTime; -import java.util.UUID; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.DomainService; -import com.gomo.app.common.util.UUIDGenerator; -import com.gomo.app.core.point.domain.model.Point; -import com.gomo.app.core.point.domain.model.SourceType; -import com.gomo.app.core.point.domain.model.TransactionType; -import com.gomo.app.core.point.domain.repository.PointRepository; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@DomainService -public class PointService { - - private final PointWalletService pointWalletService; - private final PointRepository pointRepository; - - @Transactional - public UUID create(UUID transactorId, SourceType sourceType, TransactionType transactionType, int amount) { - Point point = Point.of( - UUIDGenerator.generate(), - transactorId, - sourceType, - transactionType, - amount, - sourceType.getDescription() + transactionType.getDescription(), - LocalDateTime.now() - ); - - pointWalletService.adjustPointBalance(transactorId, transactionType, amount); - Point savedPoint = pointRepository.save(point); - return savedPoint.getId(); - } -} diff --git a/src/main/java/com/gomo/app/core/point/domain/service/PointWalletService.java b/src/main/java/com/gomo/app/core/point/domain/service/PointWalletService.java deleted file mode 100644 index e2ea046b..00000000 --- a/src/main/java/com/gomo/app/core/point/domain/service/PointWalletService.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.gomo.app.core.point.domain.service; - -import java.util.UUID; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.DomainService; -import com.gomo.app.core.point.domain.model.Balance; -import com.gomo.app.core.point.domain.model.PointWallet; -import com.gomo.app.core.point.domain.model.TransactionType; -import com.gomo.app.core.point.domain.repository.PointWalletRepository; -import com.gomo.app.core.point.exception.PointWalletNotFoundException; -import com.gomo.app.core.point.exception.code.PointWalletErrorCode; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@DomainService -public class PointWalletService { - - private final PointWalletRepository pointWalletRepository; - - @Transactional - public void adjustPointBalance(UUID transactorId, TransactionType transactionType, int deltaAmount) { - PointWallet pointWallet = findPointWalletByTransactorId(transactorId); - pointWallet.adjustBalance(transactionType.getOperationType() * deltaAmount); - } - - public Balance findBalance(UUID transactorId) { - PointWallet pointWallet = findPointWalletByTransactorId(transactorId); - return pointWallet.getBalance(); - } - - private PointWallet findPointWalletByTransactorId(UUID transactorId) { - return pointWalletRepository.findByTransactorId(transactorId) - .orElseThrow(() -> new PointWalletNotFoundException(PointWalletErrorCode.NOT_FOUND)); - } -} diff --git a/src/main/java/com/gomo/app/core/quest/adapter/in/api/AssignQuestApi.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/AssignQuestApi.java new file mode 100644 index 00000000..479c82fb --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/AssignQuestApi.java @@ -0,0 +1,64 @@ +package com.gomo.app.core.quest.adapter.in.api; + +import static org.springframework.http.HttpStatus.*; + +import java.util.UUID; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; + +import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.core.quest.adapter.in.api.request.CreateAssignQuestRequest; +import com.gomo.app.core.quest.adapter.in.api.request.UpdateAssignQuestRequest; +import com.gomo.app.core.quest.adapter.in.api.response.CreateAssignQuestResponse; +import com.gomo.app.core.quest.adapter.in.api.response.ListAssignQuestDetailResponse; +import com.gomo.app.core.quest.application.port.dto.ListAssignQuestDetailDto; +import com.gomo.app.core.quest.application.port.in.AssignQuestCreator; +import com.gomo.app.core.quest.application.port.in.AssignQuestDeleter; +import com.gomo.app.core.quest.application.port.in.AssignQuestDetailReader; +import com.gomo.app.core.quest.application.port.in.AssignQuestUpdater; +import com.gomo.app.core.auth.adapter.in.security.Auth; +import com.gomo.app.core.auth.adapter.in.security.AuthInfo; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@RequestMapping("/quests/assigns") +@CoreApi +public class AssignQuestApi { + + private final AssignQuestCreator assignQuestCreator; + private final AssignQuestDetailReader assignQuestDetailReader; + private final AssignQuestUpdater assignQuestUpdater; + private final AssignQuestDeleter assignQuestDeleter; + + @PostMapping + public ResponseEntity create(@Auth AuthInfo authInfo, @RequestBody CreateAssignQuestRequest request) { + UUID assignQuestId = assignQuestCreator.create(request.toCommand(authInfo.getPrincipalId())); + return ResponseEntity.status(CREATED).body(CreateAssignQuestResponse.of(assignQuestId)); + } + + @GetMapping + public ResponseEntity findAll(@Auth AuthInfo authInfo) { + ListAssignQuestDetailDto dto = assignQuestDetailReader.readAll(authInfo.getPrincipalId()); + return ResponseEntity.ok(ListAssignQuestDetailResponse.from(dto)); + } + + @PutMapping("/{id}") + public ResponseEntity update(@Auth AuthInfo authInfo, @PathVariable("id") UUID assignQuestId, @RequestBody UpdateAssignQuestRequest request) { + assignQuestUpdater.update(request.toCommand(authInfo.getPrincipalId(), assignQuestId)); + return ResponseEntity.noContent().build(); + } + + @DeleteMapping("/{id}") + public ResponseEntity delete(@Auth AuthInfo authInfo, @PathVariable("id") UUID assignQuestId) { + assignQuestDeleter.delete(authInfo.getPrincipalId(), assignQuestId); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/com/gomo/app/core/quest/adapter/in/api/CalendarAssignQuestApi.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/CalendarAssignQuestApi.java new file mode 100644 index 00000000..2300ae06 --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/CalendarAssignQuestApi.java @@ -0,0 +1,36 @@ +package com.gomo.app.core.quest.adapter.in.api; + +import java.time.LocalDateTime; +import java.util.List; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.core.quest.adapter.in.api.response.ListAssignQuestResponse; +import com.gomo.app.core.quest.adapter.in.api.response.ReadAssignQuestResponse; +import com.gomo.app.core.quest.application.port.command.ListAssignQuestCommand; +import com.gomo.app.core.quest.application.port.dto.AssignQuestDto; +import com.gomo.app.core.quest.application.port.in.AssignQuestReader; +import com.gomo.app.core.auth.adapter.in.security.Auth; +import com.gomo.app.core.auth.adapter.in.security.AuthInfo; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@RequestMapping("/quests/assigns/calendars") +@CoreApi +public class CalendarAssignQuestApi { + + private final AssignQuestReader assignQuestReader; + + @GetMapping + public ResponseEntity find(@Auth AuthInfo authInfo, @RequestParam boolean isCompleted, + @RequestParam LocalDateTime startDateTime, @RequestParam LocalDateTime endDateTime) { + ListAssignQuestCommand command = ListAssignQuestCommand.of(authInfo.getPrincipalId(), isCompleted, startDateTime, endDateTime); + List calendarDtos = assignQuestReader.readAll(command); + return ResponseEntity.ok(ListAssignQuestResponse.of(calendarDtos.stream().map(ReadAssignQuestResponse::from).toList())); + } +} diff --git a/src/main/java/com/gomo/app/core/quest/presentation/api/CompleteAssignQuestApi.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/CompleteAssignQuestApi.java similarity index 57% rename from src/main/java/com/gomo/app/core/quest/presentation/api/CompleteAssignQuestApi.java rename to src/main/java/com/gomo/app/core/quest/adapter/in/api/CompleteAssignQuestApi.java index c04faadc..3ceb0bd6 100644 --- a/src/main/java/com/gomo/app/core/quest/presentation/api/CompleteAssignQuestApi.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/CompleteAssignQuestApi.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.api; +package com.gomo.app.core.quest.adapter.in.api; import java.time.LocalDateTime; import java.util.UUID; @@ -10,10 +10,10 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; -import com.gomo.app.core.quest.application.usecase.CompleteAssignQuestUseCase; -import com.gomo.app.core.quest.presentation.api.request.CompleteAssignQuestRequest; -import com.gomo.app.support.auth.presentation.security.Auth; -import com.gomo.app.support.auth.presentation.security.AuthInfo; +import com.gomo.app.core.quest.adapter.in.api.request.CompleteAssignQuestRequest; +import com.gomo.app.core.quest.application.port.in.AssignQuestCompleter; +import com.gomo.app.core.auth.adapter.in.security.Auth; +import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -22,11 +22,11 @@ @CoreApi public class CompleteAssignQuestApi { - private final CompleteAssignQuestUseCase completeAssignQuestUseCase; + private final AssignQuestCompleter assignQuestCompleter; @PutMapping public ResponseEntity complete(@Auth AuthInfo authInfo, @PathVariable("id") UUID assignQuestId, @RequestBody CompleteAssignQuestRequest request) { - completeAssignQuestUseCase.complete(request.toCommand(authInfo.getMemberId(), assignQuestId, LocalDateTime.now())); + assignQuestCompleter.complete(request.toCommand(authInfo.getPrincipalId(), assignQuestId, LocalDateTime.now())); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/quest/presentation/api/ConfirmAssignQuestApi.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/ConfirmAssignQuestApi.java similarity index 59% rename from src/main/java/com/gomo/app/core/quest/presentation/api/ConfirmAssignQuestApi.java rename to src/main/java/com/gomo/app/core/quest/adapter/in/api/ConfirmAssignQuestApi.java index 0dace2d2..50583c20 100644 --- a/src/main/java/com/gomo/app/core/quest/presentation/api/ConfirmAssignQuestApi.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/ConfirmAssignQuestApi.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.api; +package com.gomo.app.core.quest.adapter.in.api; import java.util.UUID; @@ -8,9 +8,9 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; -import com.gomo.app.core.quest.application.usecase.ConfirmAssignQuestUseCase; -import com.gomo.app.support.auth.presentation.security.Auth; -import com.gomo.app.support.auth.presentation.security.AuthInfo; +import com.gomo.app.core.quest.application.port.in.AssignQuestConfirmer; +import com.gomo.app.core.auth.adapter.in.security.Auth; +import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -19,11 +19,11 @@ @CoreApi public class ConfirmAssignQuestApi { - private final ConfirmAssignQuestUseCase confirmAssignQuestUseCase; + private final AssignQuestConfirmer assignQuestConfirmer; @PutMapping public ResponseEntity confirm(@Auth AuthInfo authInfo, @PathVariable("id") UUID assignQuestId) { - confirmAssignQuestUseCase.confirm(authInfo.getMemberId(), assignQuestId); + assignQuestConfirmer.confirm(authInfo.getPrincipalId(), assignQuestId); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/quest/presentation/api/OrderUpdateAssignQuestApi.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/OrderUpdateAssignQuestApi.java similarity index 53% rename from src/main/java/com/gomo/app/core/quest/presentation/api/OrderUpdateAssignQuestApi.java rename to src/main/java/com/gomo/app/core/quest/adapter/in/api/OrderUpdateAssignQuestApi.java index 59d7b35f..e9dd13c3 100644 --- a/src/main/java/com/gomo/app/core/quest/presentation/api/OrderUpdateAssignQuestApi.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/OrderUpdateAssignQuestApi.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.api; +package com.gomo.app.core.quest.adapter.in.api; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PutMapping; @@ -6,10 +6,10 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; -import com.gomo.app.core.quest.application.usecase.OrderUpdateAssignQuestUseCase; -import com.gomo.app.core.quest.presentation.api.request.OrderUpdateAssignQuestRequest; -import com.gomo.app.support.auth.presentation.security.Auth; -import com.gomo.app.support.auth.presentation.security.AuthInfo; +import com.gomo.app.core.quest.adapter.in.api.request.OrderUpdateAssignQuestRequest; +import com.gomo.app.core.quest.application.port.in.AssignQuestOrderUpdater; +import com.gomo.app.core.auth.adapter.in.security.Auth; +import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -18,11 +18,11 @@ @CoreApi public class OrderUpdateAssignQuestApi { - private final OrderUpdateAssignQuestUseCase orderUpdateAssignQuestUseCase; + private final AssignQuestOrderUpdater assignQuestOrderUpdater; @PutMapping public ResponseEntity update(@Auth AuthInfo authInfo, @RequestBody OrderUpdateAssignQuestRequest request) { - orderUpdateAssignQuestUseCase.update(request.toCommand(authInfo.getMemberId())); + assignQuestOrderUpdater.update(request.toCommand(authInfo.getPrincipalId())); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/quest/presentation/api/OrderUpdateRepeatQuestApi.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/OrderUpdateRepeatQuestApi.java similarity index 53% rename from src/main/java/com/gomo/app/core/quest/presentation/api/OrderUpdateRepeatQuestApi.java rename to src/main/java/com/gomo/app/core/quest/adapter/in/api/OrderUpdateRepeatQuestApi.java index 95818be2..cfad5d5e 100644 --- a/src/main/java/com/gomo/app/core/quest/presentation/api/OrderUpdateRepeatQuestApi.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/OrderUpdateRepeatQuestApi.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.api; +package com.gomo.app.core.quest.adapter.in.api; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PutMapping; @@ -6,10 +6,10 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; -import com.gomo.app.core.quest.application.usecase.OrderUpdateRepeatQuestUseCase; -import com.gomo.app.core.quest.presentation.api.request.OrderUpdateRepeatQuestRequest; -import com.gomo.app.support.auth.presentation.security.Auth; -import com.gomo.app.support.auth.presentation.security.AuthInfo; +import com.gomo.app.core.quest.adapter.in.api.request.OrderUpdateRepeatQuestRequest; +import com.gomo.app.core.quest.application.port.in.RepeatQuestOrderUpdater; +import com.gomo.app.core.auth.adapter.in.security.Auth; +import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -18,11 +18,11 @@ @CoreApi public class OrderUpdateRepeatQuestApi { - private final OrderUpdateRepeatQuestUseCase orderUpdateRepeatQuestUseCase; + private final RepeatQuestOrderUpdater repeatQuestOrderUpdater; @PutMapping public ResponseEntity update(@Auth AuthInfo authInfo, @RequestBody OrderUpdateRepeatQuestRequest request) { - orderUpdateRepeatQuestUseCase.update(request.toCommand(authInfo.getMemberId())); + repeatQuestOrderUpdater.update(request.toCommand(authInfo.getPrincipalId())); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/quest/adapter/in/api/ReRollAssignQuestApi.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/ReRollAssignQuestApi.java new file mode 100644 index 00000000..a0bac53d --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/ReRollAssignQuestApi.java @@ -0,0 +1,32 @@ +package com.gomo.app.core.quest.adapter.in.api; + +import static org.springframework.http.HttpStatus.*; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; + +import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.core.quest.adapter.in.api.request.ReRollAssignQuestRequest; +import com.gomo.app.core.quest.adapter.in.api.response.ReadAssignQuestDetailResponse; +import com.gomo.app.core.quest.application.port.dto.AssignQuestDetailDto; +import com.gomo.app.core.quest.application.port.in.AssignQuestReRoller; +import com.gomo.app.core.auth.adapter.in.security.Auth; +import com.gomo.app.core.auth.adapter.in.security.AuthInfo; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@RequestMapping("/quests/assigns/re-roll") +@CoreApi +public class ReRollAssignQuestApi { + + private final AssignQuestReRoller assignQuestReRoller; + + @PostMapping + public ResponseEntity reRoll(@Auth AuthInfo authInfo, @RequestBody ReRollAssignQuestRequest request) { + AssignQuestDetailDto assignQuestDetailDto = assignQuestReRoller.reRoll(authInfo.getPrincipalId(), request.getAssignQuestId()); + return ResponseEntity.status(CREATED).body(ReadAssignQuestDetailResponse.from(assignQuestDetailDto)); + } +} diff --git a/src/main/java/com/gomo/app/core/quest/presentation/api/RepeatQuestApi.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/RepeatQuestApi.java similarity index 52% rename from src/main/java/com/gomo/app/core/quest/presentation/api/RepeatQuestApi.java rename to src/main/java/com/gomo/app/core/quest/adapter/in/api/RepeatQuestApi.java index 45861588..9ab4876e 100644 --- a/src/main/java/com/gomo/app/core/quest/presentation/api/RepeatQuestApi.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/RepeatQuestApi.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.api; +package com.gomo.app.core.quest.adapter.in.api; import static org.springframework.http.HttpStatus.*; @@ -14,17 +14,17 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.core.quest.adapter.in.api.request.CreateRepeatQuestRequest; +import com.gomo.app.core.quest.adapter.in.api.request.UpdateRepeatQuestRequest; +import com.gomo.app.core.quest.adapter.in.api.response.CreateRepeatQuestResponse; +import com.gomo.app.core.quest.adapter.in.api.response.ListRepeatQuestResponse; import com.gomo.app.core.quest.application.port.dto.ListRepeatQuestDto; -import com.gomo.app.core.quest.application.usecase.CreateRepeatQuestUseCase; -import com.gomo.app.core.quest.application.usecase.DeleteRepeatQuestUseCase; -import com.gomo.app.core.quest.application.usecase.ReadRepeatQuestUseCase; -import com.gomo.app.core.quest.application.usecase.UpdateRepeatQuestUseCase; -import com.gomo.app.core.quest.presentation.api.request.CreateRepeatQuestRequest; -import com.gomo.app.core.quest.presentation.api.request.UpdateRepeatQuestRequest; -import com.gomo.app.core.quest.presentation.api.response.CreateRepeatQuestResponse; -import com.gomo.app.core.quest.presentation.api.response.ListRepeatQuestResponse; -import com.gomo.app.support.auth.presentation.security.Auth; -import com.gomo.app.support.auth.presentation.security.AuthInfo; +import com.gomo.app.core.quest.application.port.in.RepeatQuestCreator; +import com.gomo.app.core.quest.application.port.in.RepeatQuestDeleter; +import com.gomo.app.core.quest.application.port.in.RepeatQuestReader; +import com.gomo.app.core.quest.application.port.in.RepeatQuestUpdater; +import com.gomo.app.core.auth.adapter.in.security.Auth; +import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -33,32 +33,32 @@ @CoreApi public class RepeatQuestApi { - private final CreateRepeatQuestUseCase createRepeatQuestUseCase; - private final ReadRepeatQuestUseCase readRepeatQuestUseCase; - private final UpdateRepeatQuestUseCase updateRepeatQuestUseCase; - private final DeleteRepeatQuestUseCase deleteRepeatQuestUseCase; + private final RepeatQuestCreator repeatQuestCreator; + private final RepeatQuestReader repeatQuestReader; + private final RepeatQuestUpdater repeatQuestUpdater; + private final RepeatQuestDeleter repeatQuestDeleter; @PostMapping public ResponseEntity create(@Auth AuthInfo authInfo, @RequestBody CreateRepeatQuestRequest request) { - UUID repeatQuestId = createRepeatQuestUseCase.create(request.toCommand(authInfo.getMemberId())); + UUID repeatQuestId = repeatQuestCreator.create(request.toCommand(authInfo.getPrincipalId())); return ResponseEntity.status(CREATED).body(CreateRepeatQuestResponse.of(repeatQuestId)); } @GetMapping public ResponseEntity findAll(@Auth AuthInfo authInfo) { - ListRepeatQuestDto dto = readRepeatQuestUseCase.findAll(authInfo.getMemberId()); + ListRepeatQuestDto dto = repeatQuestReader.readAll(authInfo.getPrincipalId()); return ResponseEntity.ok(ListRepeatQuestResponse.from(dto)); } @PutMapping("/{id}") public ResponseEntity update(@Auth AuthInfo authInfo, @PathVariable("id") UUID repeatQuestId, @RequestBody UpdateRepeatQuestRequest request) { - updateRepeatQuestUseCase.update(request.toCommand(authInfo.getMemberId(), repeatQuestId)); + repeatQuestUpdater.update(request.toCommand(authInfo.getPrincipalId(), repeatQuestId)); return ResponseEntity.noContent().build(); } @DeleteMapping("/{id}") public ResponseEntity delete(@Auth AuthInfo authInfo, @PathVariable("id") UUID repeatQuestId) { - deleteRepeatQuestUseCase.delete(authInfo.getMemberId(), repeatQuestId); + repeatQuestDeleter.delete(authInfo.getPrincipalId(), repeatQuestId); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/quest/presentation/api/request/CompleteAssignQuestRequest.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/request/CompleteAssignQuestRequest.java similarity index 88% rename from src/main/java/com/gomo/app/core/quest/presentation/api/request/CompleteAssignQuestRequest.java rename to src/main/java/com/gomo/app/core/quest/adapter/in/api/request/CompleteAssignQuestRequest.java index 9ab0f180..09b0deaf 100644 --- a/src/main/java/com/gomo/app/core/quest/presentation/api/request/CompleteAssignQuestRequest.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/request/CompleteAssignQuestRequest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.api.request; +package com.gomo.app.core.quest.adapter.in.api.request; import java.time.LocalDateTime; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/quest/presentation/api/request/CreateAssignQuestRequest.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/request/CreateAssignQuestRequest.java similarity index 90% rename from src/main/java/com/gomo/app/core/quest/presentation/api/request/CreateAssignQuestRequest.java rename to src/main/java/com/gomo/app/core/quest/adapter/in/api/request/CreateAssignQuestRequest.java index 52f5c496..136aca25 100644 --- a/src/main/java/com/gomo/app/core/quest/presentation/api/request/CreateAssignQuestRequest.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/request/CreateAssignQuestRequest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.api.request; +package com.gomo.app.core.quest.adapter.in.api.request; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/quest/presentation/api/request/CreateRepeatQuestRequest.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/request/CreateRepeatQuestRequest.java similarity index 90% rename from src/main/java/com/gomo/app/core/quest/presentation/api/request/CreateRepeatQuestRequest.java rename to src/main/java/com/gomo/app/core/quest/adapter/in/api/request/CreateRepeatQuestRequest.java index 24c13f12..2bb3c898 100644 --- a/src/main/java/com/gomo/app/core/quest/presentation/api/request/CreateRepeatQuestRequest.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/request/CreateRepeatQuestRequest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.api.request; +package com.gomo.app.core.quest.adapter.in.api.request; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/quest/presentation/api/request/OrderUpdateAssignQuestRequest.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/request/OrderUpdateAssignQuestRequest.java similarity index 90% rename from src/main/java/com/gomo/app/core/quest/presentation/api/request/OrderUpdateAssignQuestRequest.java rename to src/main/java/com/gomo/app/core/quest/adapter/in/api/request/OrderUpdateAssignQuestRequest.java index a3de8cb5..3ee7d3b6 100644 --- a/src/main/java/com/gomo/app/core/quest/presentation/api/request/OrderUpdateAssignQuestRequest.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/request/OrderUpdateAssignQuestRequest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.api.request; +package com.gomo.app.core.quest.adapter.in.api.request; import java.util.List; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/quest/presentation/api/request/OrderUpdateRepeatQuestRequest.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/request/OrderUpdateRepeatQuestRequest.java similarity index 90% rename from src/main/java/com/gomo/app/core/quest/presentation/api/request/OrderUpdateRepeatQuestRequest.java rename to src/main/java/com/gomo/app/core/quest/adapter/in/api/request/OrderUpdateRepeatQuestRequest.java index efc03b2e..c0463630 100644 --- a/src/main/java/com/gomo/app/core/quest/presentation/api/request/OrderUpdateRepeatQuestRequest.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/request/OrderUpdateRepeatQuestRequest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.api.request; +package com.gomo.app.core.quest.adapter.in.api.request; import java.util.List; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/quest/presentation/api/request/ReRollAssignQuestRequest.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/request/ReRollAssignQuestRequest.java similarity index 81% rename from src/main/java/com/gomo/app/core/quest/presentation/api/request/ReRollAssignQuestRequest.java rename to src/main/java/com/gomo/app/core/quest/adapter/in/api/request/ReRollAssignQuestRequest.java index b3882c73..eb0433c7 100644 --- a/src/main/java/com/gomo/app/core/quest/presentation/api/request/ReRollAssignQuestRequest.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/request/ReRollAssignQuestRequest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.api.request; +package com.gomo.app.core.quest.adapter.in.api.request; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/quest/presentation/api/request/UpdateAssignQuestRequest.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/request/UpdateAssignQuestRequest.java similarity index 91% rename from src/main/java/com/gomo/app/core/quest/presentation/api/request/UpdateAssignQuestRequest.java rename to src/main/java/com/gomo/app/core/quest/adapter/in/api/request/UpdateAssignQuestRequest.java index 0eb339fa..339be5d7 100644 --- a/src/main/java/com/gomo/app/core/quest/presentation/api/request/UpdateAssignQuestRequest.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/request/UpdateAssignQuestRequest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.api.request; +package com.gomo.app.core.quest.adapter.in.api.request; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/quest/presentation/api/request/UpdateRepeatQuestRequest.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/request/UpdateRepeatQuestRequest.java similarity index 91% rename from src/main/java/com/gomo/app/core/quest/presentation/api/request/UpdateRepeatQuestRequest.java rename to src/main/java/com/gomo/app/core/quest/adapter/in/api/request/UpdateRepeatQuestRequest.java index b4b4b6fd..76780400 100644 --- a/src/main/java/com/gomo/app/core/quest/presentation/api/request/UpdateRepeatQuestRequest.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/request/UpdateRepeatQuestRequest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.api.request; +package com.gomo.app.core.quest.adapter.in.api.request; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/quest/presentation/api/response/CreateAssignQuestResponse.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/response/CreateAssignQuestResponse.java similarity index 78% rename from src/main/java/com/gomo/app/core/quest/presentation/api/response/CreateAssignQuestResponse.java rename to src/main/java/com/gomo/app/core/quest/adapter/in/api/response/CreateAssignQuestResponse.java index 4e1b3827..29a0a401 100644 --- a/src/main/java/com/gomo/app/core/quest/presentation/api/response/CreateAssignQuestResponse.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/response/CreateAssignQuestResponse.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.api.response; +package com.gomo.app.core.quest.adapter.in.api.response; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/quest/presentation/api/response/CreateRepeatQuestResponse.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/response/CreateRepeatQuestResponse.java similarity index 78% rename from src/main/java/com/gomo/app/core/quest/presentation/api/response/CreateRepeatQuestResponse.java rename to src/main/java/com/gomo/app/core/quest/adapter/in/api/response/CreateRepeatQuestResponse.java index 36e6a11e..fc6aeb0e 100644 --- a/src/main/java/com/gomo/app/core/quest/presentation/api/response/CreateRepeatQuestResponse.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/response/CreateRepeatQuestResponse.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.api.response; +package com.gomo.app.core.quest.adapter.in.api.response; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/quest/adapter/in/api/response/ListAssignQuestDetailResponse.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/response/ListAssignQuestDetailResponse.java new file mode 100644 index 00000000..d057aa41 --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/response/ListAssignQuestDetailResponse.java @@ -0,0 +1,33 @@ +package com.gomo.app.core.quest.adapter.in.api.response; + +import java.util.List; + +import com.gomo.app.core.quest.application.port.dto.ListAssignQuestDetailDto; + +import lombok.Getter; + +@Getter +public class ListAssignQuestDetailResponse { + + private List dailyQuests; + private List weeklyQuests; + private List monthlyQuests; + + private ListAssignQuestDetailResponse( + List dailyQuests, + List weeklyQuests, + List monthlyQuests + ) { + this.dailyQuests = dailyQuests; + this.weeklyQuests = weeklyQuests; + this.monthlyQuests = monthlyQuests; + } + + public static ListAssignQuestDetailResponse from(ListAssignQuestDetailDto dto) { + return new ListAssignQuestDetailResponse( + dto.dailyQuests().stream().map(ReadAssignQuestDetailResponse::from).toList(), + dto.weeklyQuests().stream().map(ReadAssignQuestDetailResponse::from).toList(), + dto.monthlyQuests().stream().map(ReadAssignQuestDetailResponse::from).toList() + ); + } +} diff --git a/src/main/java/com/gomo/app/core/quest/adapter/in/api/response/ListAssignQuestResponse.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/response/ListAssignQuestResponse.java new file mode 100644 index 00000000..604f3344 --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/response/ListAssignQuestResponse.java @@ -0,0 +1,19 @@ +package com.gomo.app.core.quest.adapter.in.api.response; + +import java.util.List; + +import lombok.Getter; + +@Getter +public class ListAssignQuestResponse { + + private List assignQuests; + + private ListAssignQuestResponse(List assignQuests) { + this.assignQuests = assignQuests; + } + + public static ListAssignQuestResponse of(List assignQuests) { + return new ListAssignQuestResponse(assignQuests); + } +} diff --git a/src/main/java/com/gomo/app/core/quest/presentation/api/response/ListRepeatQuestResponse.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/response/ListRepeatQuestResponse.java similarity index 91% rename from src/main/java/com/gomo/app/core/quest/presentation/api/response/ListRepeatQuestResponse.java rename to src/main/java/com/gomo/app/core/quest/adapter/in/api/response/ListRepeatQuestResponse.java index 656bafc4..c206d2a6 100644 --- a/src/main/java/com/gomo/app/core/quest/presentation/api/response/ListRepeatQuestResponse.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/response/ListRepeatQuestResponse.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.api.response; +package com.gomo.app.core.quest.adapter.in.api.response; import java.util.List; diff --git a/src/main/java/com/gomo/app/core/quest/presentation/api/response/ReadAssignQuestResponse.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/response/ReadAssignQuestDetailResponse.java similarity index 78% rename from src/main/java/com/gomo/app/core/quest/presentation/api/response/ReadAssignQuestResponse.java rename to src/main/java/com/gomo/app/core/quest/adapter/in/api/response/ReadAssignQuestDetailResponse.java index dd369eb7..55dd98a8 100644 --- a/src/main/java/com/gomo/app/core/quest/presentation/api/response/ReadAssignQuestResponse.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/response/ReadAssignQuestDetailResponse.java @@ -1,14 +1,14 @@ -package com.gomo.app.core.quest.presentation.api.response; +package com.gomo.app.core.quest.adapter.in.api.response; import java.time.LocalDateTime; import java.util.UUID; -import com.gomo.app.core.quest.application.port.dto.AssignQuestDto; +import com.gomo.app.core.quest.application.port.dto.AssignQuestDetailDto; import lombok.Getter; @Getter -public class ReadAssignQuestResponse { +public class ReadAssignQuestDetailResponse { private UUID id; private UUID subjectId; @@ -23,7 +23,7 @@ public class ReadAssignQuestResponse { private LocalDateTime startDateTime; private int displayOrder; - private ReadAssignQuestResponse( + private ReadAssignQuestDetailResponse( UUID id, UUID subjectId, String questType, @@ -51,8 +51,8 @@ private ReadAssignQuestResponse( this.displayOrder = displayOrder; } - public static ReadAssignQuestResponse from(AssignQuestDto dto) { - return new ReadAssignQuestResponse( + public static ReadAssignQuestDetailResponse from(AssignQuestDetailDto dto) { + return new ReadAssignQuestDetailResponse( dto.id(), dto.subjectId(), dto.questType(), diff --git a/src/main/java/com/gomo/app/core/quest/presentation/api/response/CalendarAssignQuestResponse.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/response/ReadAssignQuestResponse.java similarity index 68% rename from src/main/java/com/gomo/app/core/quest/presentation/api/response/CalendarAssignQuestResponse.java rename to src/main/java/com/gomo/app/core/quest/adapter/in/api/response/ReadAssignQuestResponse.java index 3dd71eba..96c78a38 100644 --- a/src/main/java/com/gomo/app/core/quest/presentation/api/response/CalendarAssignQuestResponse.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/response/ReadAssignQuestResponse.java @@ -1,15 +1,15 @@ -package com.gomo.app.core.quest.presentation.api.response; +package com.gomo.app.core.quest.adapter.in.api.response; import java.time.LocalDateTime; import java.util.UUID; -import com.gomo.app.core.quest.application.port.dto.CalendarAssignQuestDto; +import com.gomo.app.core.quest.application.port.dto.AssignQuestDto; import com.gomo.app.core.quest.domain.model.quest.QuestType; import lombok.Getter; @Getter -public class CalendarAssignQuestResponse { +public class ReadAssignQuestResponse { private UUID id; private QuestType questType; @@ -19,7 +19,7 @@ public class CalendarAssignQuestResponse { private boolean isCompleted; private LocalDateTime completedDateTime; - private CalendarAssignQuestResponse( + private ReadAssignQuestResponse( UUID id, QuestType questType, String subjectName, @@ -37,8 +37,8 @@ private CalendarAssignQuestResponse( this.completedDateTime = completedDateTime; } - public static CalendarAssignQuestResponse from(CalendarAssignQuestDto dto) { - return new CalendarAssignQuestResponse( + public static ReadAssignQuestResponse from(AssignQuestDto dto) { + return new ReadAssignQuestResponse( dto.id(), dto.questType(), dto.subjectName(), diff --git a/src/main/java/com/gomo/app/core/quest/presentation/api/response/ReadRepeatQuestResponse.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/response/ReadRepeatQuestResponse.java similarity index 90% rename from src/main/java/com/gomo/app/core/quest/presentation/api/response/ReadRepeatQuestResponse.java rename to src/main/java/com/gomo/app/core/quest/adapter/in/api/response/ReadRepeatQuestResponse.java index 51a070ae..719cb296 100644 --- a/src/main/java/com/gomo/app/core/quest/presentation/api/response/ReadRepeatQuestResponse.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/response/ReadRepeatQuestResponse.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.api.response; +package com.gomo.app.core.quest.adapter.in.api.response; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/quest/presentation/consumer/FillQuestPoolEventConsumer.java b/src/main/java/com/gomo/app/core/quest/adapter/in/consumer/FillQuestPoolEventConsumer.java similarity index 69% rename from src/main/java/com/gomo/app/core/quest/presentation/consumer/FillQuestPoolEventConsumer.java rename to src/main/java/com/gomo/app/core/quest/adapter/in/consumer/FillQuestPoolEventConsumer.java index 5aed1191..6a6f0705 100644 --- a/src/main/java/com/gomo/app/core/quest/presentation/consumer/FillQuestPoolEventConsumer.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/consumer/FillQuestPoolEventConsumer.java @@ -1,13 +1,13 @@ -package com.gomo.app.core.quest.presentation.consumer; +package com.gomo.app.core.quest.adapter.in.consumer; import org.springframework.amqp.rabbit.annotation.RabbitListener; import com.gomo.app.common.arch.EventConsumer; import com.gomo.app.common.util.JsonParser; -import com.gomo.app.core.quest.application.port.CreateQuestPoolPortIn; import com.gomo.app.core.quest.application.port.command.CreateQuestPoolCommand; -import com.gomo.app.core.quest.event.CreateQuestPoolEvent; -import com.gomo.app.support.messagebroker.application.port.IdempotentDirectEventConsumer; +import com.gomo.app.core.quest.application.port.in.QuestPoolCreator; +import com.gomo.app.core.quest.domain.event.CreateQuestPoolEvent; +import com.gomo.app.support.messagebroker.application.port.in.IdempotentDirectEventConsumer; import com.gomo.app.support.messagebroker.domain.model.DirectEvent; import lombok.RequiredArgsConstructor; @@ -16,7 +16,7 @@ @EventConsumer public class FillQuestPoolEventConsumer { - private final CreateQuestPoolPortIn createQuestPoolPortIn; + private final QuestPoolCreator questPoolCreator; @IdempotentDirectEventConsumer @RabbitListener(queues = "event.quest.pool.fill") @@ -28,6 +28,6 @@ public void handleEvent(DirectEvent directEvent) { event.getQuestType(), (int)event.getLimit() ); - createQuestPoolPortIn.create(createQuestPoolCommand); + questPoolCreator.create(createQuestPoolCommand); } } diff --git a/src/main/java/com/gomo/app/core/quest/infrastructure/adapter/LlmCreateQuestContentAdapter.java b/src/main/java/com/gomo/app/core/quest/adapter/out/client/LlmQuestContentClient.java similarity index 85% rename from src/main/java/com/gomo/app/core/quest/infrastructure/adapter/LlmCreateQuestContentAdapter.java rename to src/main/java/com/gomo/app/core/quest/adapter/out/client/LlmQuestContentClient.java index 34488d7a..e3777377 100644 --- a/src/main/java/com/gomo/app/core/quest/infrastructure/adapter/LlmCreateQuestContentAdapter.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/out/client/LlmQuestContentClient.java @@ -1,12 +1,12 @@ -package com.gomo.app.core.quest.infrastructure.adapter; +package com.gomo.app.core.quest.adapter.out.client; import java.util.List; import java.util.stream.IntStream; import com.gomo.app.common.arch.Adapter; -import com.gomo.app.core.quest.application.port.CreateQuestContentPortOut; import com.gomo.app.core.quest.application.port.command.CreateQuestContentCommand; import com.gomo.app.core.quest.application.port.dto.QuestContentDto; +import com.gomo.app.core.quest.application.port.out.QuestContentCreator; import com.gomo.app.support.llm.application.GenerateTextPortIn; import lombok.RequiredArgsConstructor; @@ -15,7 +15,7 @@ @Slf4j @RequiredArgsConstructor @Adapter -class LlmCreateQuestContentAdapter implements CreateQuestContentPortOut { +class LlmQuestContentClient implements QuestContentCreator { private final GenerateTextPortIn generateTextPortIn; diff --git a/src/main/java/com/gomo/app/core/quest/infrastructure/adapter/ReadParticipantAdapter.java b/src/main/java/com/gomo/app/core/quest/adapter/out/client/ParticipantClient.java similarity index 53% rename from src/main/java/com/gomo/app/core/quest/infrastructure/adapter/ReadParticipantAdapter.java rename to src/main/java/com/gomo/app/core/quest/adapter/out/client/ParticipantClient.java index a019d482..562272c6 100644 --- a/src/main/java/com/gomo/app/core/quest/infrastructure/adapter/ReadParticipantAdapter.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/out/client/ParticipantClient.java @@ -1,24 +1,24 @@ -package com.gomo.app.core.quest.infrastructure.adapter; +package com.gomo.app.core.quest.adapter.out.client; import java.util.UUID; import com.gomo.app.common.arch.Adapter; -import com.gomo.app.core.member.application.port.ReadMemberPortIn; import com.gomo.app.core.member.application.port.dto.MemberDto; -import com.gomo.app.core.quest.application.port.ReadParticipantPortOut; +import com.gomo.app.core.member.application.port.in.MemberReader; import com.gomo.app.core.quest.application.port.dto.ParticipantDto; +import com.gomo.app.core.quest.application.port.out.ParticipantReader; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @Adapter -class ReadParticipantAdapter implements ReadParticipantPortOut { +class ParticipantClient implements ParticipantReader { - private final ReadMemberPortIn readMemberPortIn; + private final MemberReader memberReader; @Override - public ParticipantDto find(UUID participantId) { - MemberDto memberDto = readMemberPortIn.find(participantId); + public ParticipantDto read(UUID participantId) { + MemberDto memberDto = memberReader.read(participantId); return ParticipantDto.of( memberDto.id(), memberDto.questProperty().dailyThreshold(), diff --git a/src/main/java/com/gomo/app/core/quest/adapter/out/client/SubjectClient.java b/src/main/java/com/gomo/app/core/quest/adapter/out/client/SubjectClient.java new file mode 100644 index 00000000..188a4abd --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/adapter/out/client/SubjectClient.java @@ -0,0 +1,41 @@ +package com.gomo.app.core.quest.adapter.out.client; + +import java.util.List; +import java.util.Set; +import java.util.UUID; + +import com.gomo.app.common.arch.Adapter; +import com.gomo.app.core.interest.application.port.in.InterestReader; +import com.gomo.app.core.quest.application.port.dto.SubjectDto; +import com.gomo.app.core.quest.application.port.out.SubjectReader; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Adapter +class SubjectClient implements SubjectReader { + + private final InterestReader interestReader; + + @Override + public List readAll(UUID participantId) { + return interestReader.readAll(participantId).stream() + .map(dto -> SubjectDto.of( + dto.id(), + dto.registrantId(), + dto.name(), + dto.proficiency().level() + )).toList(); + } + + @Override + public List readAllByParticipantIds(Set participantIds) { + return interestReader.readAllByRegistrantIds(participantIds).stream() + .map(dto -> SubjectDto.of( + dto.id(), + dto.registrantId(), + dto.name(), + dto.proficiency().level() + )).toList(); + } +} diff --git a/src/main/java/com/gomo/app/core/quest/infrastructure/repository/InMemoryQuestRewardPolicyRepository.java b/src/main/java/com/gomo/app/core/quest/adapter/out/persistence/InMemoryQuestRewardPolicyRepository.java similarity index 91% rename from src/main/java/com/gomo/app/core/quest/infrastructure/repository/InMemoryQuestRewardPolicyRepository.java rename to src/main/java/com/gomo/app/core/quest/adapter/out/persistence/InMemoryQuestRewardPolicyRepository.java index 2259fe26..4bd6bbdf 100644 --- a/src/main/java/com/gomo/app/core/quest/infrastructure/repository/InMemoryQuestRewardPolicyRepository.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/out/persistence/InMemoryQuestRewardPolicyRepository.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.infrastructure.repository; +package com.gomo.app.core.quest.adapter.out.persistence; import java.util.List; diff --git a/src/main/java/com/gomo/app/core/quest/infrastructure/repository/JdbcBulkAssignQuestRepository.java b/src/main/java/com/gomo/app/core/quest/adapter/out/persistence/JdbcBulkAssignQuestRepository.java similarity index 97% rename from src/main/java/com/gomo/app/core/quest/infrastructure/repository/JdbcBulkAssignQuestRepository.java rename to src/main/java/com/gomo/app/core/quest/adapter/out/persistence/JdbcBulkAssignQuestRepository.java index fb238eea..339e187d 100644 --- a/src/main/java/com/gomo/app/core/quest/infrastructure/repository/JdbcBulkAssignQuestRepository.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/out/persistence/JdbcBulkAssignQuestRepository.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.infrastructure.repository; +package com.gomo.app.core.quest.adapter.out.persistence; import java.sql.PreparedStatement; import java.sql.Timestamp; diff --git a/src/main/java/com/gomo/app/core/quest/application/port/command/CalendarAssignQuestCommand.java b/src/main/java/com/gomo/app/core/quest/application/port/command/CalendarAssignQuestCommand.java deleted file mode 100644 index c3b7a17f..00000000 --- a/src/main/java/com/gomo/app/core/quest/application/port/command/CalendarAssignQuestCommand.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.gomo.app.core.quest.application.port.command; - -import java.time.LocalDateTime; -import java.util.UUID; - -public record CalendarAssignQuestCommand(UUID participantId, boolean isCompleted, LocalDateTime startDate, LocalDateTime endDate) { - - public static CalendarAssignQuestCommand of(UUID participantId, boolean isCompleted, LocalDateTime startDate, LocalDateTime endDate) { - return new CalendarAssignQuestCommand(participantId, isCompleted, startDate, endDate); - } -} diff --git a/src/main/java/com/gomo/app/core/quest/application/port/command/ListAssignQuestCommand.java b/src/main/java/com/gomo/app/core/quest/application/port/command/ListAssignQuestCommand.java new file mode 100644 index 00000000..0e7ea205 --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/application/port/command/ListAssignQuestCommand.java @@ -0,0 +1,11 @@ +package com.gomo.app.core.quest.application.port.command; + +import java.time.LocalDateTime; +import java.util.UUID; + +public record ListAssignQuestCommand(UUID participantId, boolean isCompleted, LocalDateTime startDate, LocalDateTime endDate) { + + public static ListAssignQuestCommand of(UUID participantId, boolean isCompleted, LocalDateTime startDate, LocalDateTime endDate) { + return new ListAssignQuestCommand(participantId, isCompleted, startDate, endDate); + } +} diff --git a/src/main/java/com/gomo/app/core/quest/application/port/dto/ActiveParticipantDto.java b/src/main/java/com/gomo/app/core/quest/application/port/dto/ActiveParticipantDto.java deleted file mode 100644 index 3ca53193..00000000 --- a/src/main/java/com/gomo/app/core/quest/application/port/dto/ActiveParticipantDto.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.gomo.app.core.quest.application.port.dto; - -import java.util.UUID; - -public record ActiveParticipantDto(UUID participantId, int dailyQuota, int weeklyQuota, int monthlyQuota) { - - public static ActiveParticipantDto of(UUID participantId, int dailyQuota, int weeklyQuota, int monthlyQuota) { - return new ActiveParticipantDto(participantId, dailyQuota, weeklyQuota, monthlyQuota); - } -} diff --git a/src/main/java/com/gomo/app/core/quest/application/port/dto/AssignQuestDetailDto.java b/src/main/java/com/gomo/app/core/quest/application/port/dto/AssignQuestDetailDto.java new file mode 100644 index 00000000..98919ac6 --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/application/port/dto/AssignQuestDetailDto.java @@ -0,0 +1,27 @@ +package com.gomo.app.core.quest.application.port.dto; + +import java.time.LocalDateTime; +import java.util.UUID; + +import com.gomo.app.core.quest.domain.model.assign.AssignQuest; + +public record AssignQuestDetailDto(UUID id, UUID subjectId, String questType, int point, int score, String subjectName, String content, boolean isConfirmed, + boolean isCompleted, String proof, LocalDateTime startDateTime, LocalDateTime completedDateTime, int displayOrder) { + public static AssignQuestDetailDto from(AssignQuest assignQuest, int point, int score) { + return new AssignQuestDetailDto( + assignQuest.getId(), + assignQuest.subjectId(), + assignQuest.questType().name(), + point, + score, + assignQuest.subjectName(), + assignQuest.content(), + assignQuest.isConfirmed(), + assignQuest.isCompleted(), + assignQuest.getProof().getUrl(), + assignQuest.getStartDateTime(), + assignQuest.getCompletedDateTime(), + assignQuest.displayOrder() + ); + } +} diff --git a/src/main/java/com/gomo/app/core/quest/application/port/dto/AssignQuestDto.java b/src/main/java/com/gomo/app/core/quest/application/port/dto/AssignQuestDto.java index a19a4490..01fa62a8 100644 --- a/src/main/java/com/gomo/app/core/quest/application/port/dto/AssignQuestDto.java +++ b/src/main/java/com/gomo/app/core/quest/application/port/dto/AssignQuestDto.java @@ -4,24 +4,19 @@ import java.util.UUID; import com.gomo.app.core.quest.domain.model.assign.AssignQuest; +import com.gomo.app.core.quest.domain.model.quest.QuestType; -public record AssignQuestDto(UUID id, UUID subjectId, String questType, int point, int score, String subjectName, String content, boolean isConfirmed, - boolean isCompleted, String proof, LocalDateTime startDateTime, int displayOrder) { +public record AssignQuestDto(UUID id, QuestType questType, String subjectName, String content, String proof, boolean isCompleted, LocalDateTime completedDateTime) { - public static AssignQuestDto from(AssignQuest assignQuest, int point, int score) { + public static AssignQuestDto of(AssignQuest assignQuest) { return new AssignQuestDto( assignQuest.getId(), - assignQuest.subjectId(), - assignQuest.questType().name(), - point, - score, + assignQuest.questType(), assignQuest.subjectName(), assignQuest.content(), - assignQuest.isConfirmed(), + assignQuest.getProof().toString(), assignQuest.isCompleted(), - assignQuest.getProof().getUrl(), - assignQuest.getStartDateTime(), - assignQuest.displayOrder() + assignQuest.getCompletedDateTime() ); } } diff --git a/src/main/java/com/gomo/app/core/quest/application/port/dto/CalendarAssignQuestDto.java b/src/main/java/com/gomo/app/core/quest/application/port/dto/CalendarAssignQuestDto.java deleted file mode 100644 index a4733649..00000000 --- a/src/main/java/com/gomo/app/core/quest/application/port/dto/CalendarAssignQuestDto.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.gomo.app.core.quest.application.port.dto; - -import java.time.LocalDateTime; -import java.util.UUID; - -import com.gomo.app.core.quest.domain.model.assign.AssignQuest; -import com.gomo.app.core.quest.domain.model.quest.QuestType; - -public record CalendarAssignQuestDto(UUID id, QuestType questType, String subjectName, String content, String proof, boolean isCompleted, - LocalDateTime completedDateTime) { - - public static CalendarAssignQuestDto of(AssignQuest assignQuest) { - return new CalendarAssignQuestDto( - assignQuest.getId(), - assignQuest.questType(), - assignQuest.subjectName(), - assignQuest.content(), - assignQuest.getProof().toString(), - assignQuest.isCompleted(), - assignQuest.getCompletedDateTime() - ); - } -} diff --git a/src/main/java/com/gomo/app/core/quest/application/port/dto/ListAssignQuestDetailDto.java b/src/main/java/com/gomo/app/core/quest/application/port/dto/ListAssignQuestDetailDto.java new file mode 100644 index 00000000..7d5a06e0 --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/application/port/dto/ListAssignQuestDetailDto.java @@ -0,0 +1,10 @@ +package com.gomo.app.core.quest.application.port.dto; + +import java.util.List; + +public record ListAssignQuestDetailDto(List dailyQuests, List weeklyQuests, List monthlyQuests) { + + public static ListAssignQuestDetailDto of(List dailyQuests, List weeklyQuests, List monthlyQuests) { + return new ListAssignQuestDetailDto(dailyQuests, weeklyQuests, monthlyQuests); + } +} diff --git a/src/main/java/com/gomo/app/core/quest/application/port/dto/ListAssignQuestDto.java b/src/main/java/com/gomo/app/core/quest/application/port/dto/ListAssignQuestDto.java deleted file mode 100644 index 0ecbf1b9..00000000 --- a/src/main/java/com/gomo/app/core/quest/application/port/dto/ListAssignQuestDto.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.gomo.app.core.quest.application.port.dto; - -import java.util.List; - -public record ListAssignQuestDto(List dailyQuests, List weeklyQuests, List monthlyQuests) { - - public static ListAssignQuestDto of(List dailyQuests, List weeklyQuests, List monthlyQuests) { - return new ListAssignQuestDto(dailyQuests, weeklyQuests, monthlyQuests); - } -} diff --git a/src/main/java/com/gomo/app/core/quest/application/port/dto/RepeatQuestDto.java b/src/main/java/com/gomo/app/core/quest/application/port/dto/RepeatQuestDto.java index 11a41f31..6aacb43c 100644 --- a/src/main/java/com/gomo/app/core/quest/application/port/dto/RepeatQuestDto.java +++ b/src/main/java/com/gomo/app/core/quest/application/port/dto/RepeatQuestDto.java @@ -4,8 +4,7 @@ import com.gomo.app.core.quest.domain.model.repeat.RepeatQuest; -public record RepeatQuestDto(UUID id, UUID subjectId, String questType, int point, int score, String subjectName, String content, int displayOrder -) { +public record RepeatQuestDto(UUID id, UUID subjectId, String questType, int point, int score, String subjectName, String content, int displayOrder) { public static RepeatQuestDto from(RepeatQuest repeatQuest, int point, int score) { return new RepeatQuestDto( diff --git a/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestCompleter.java b/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestCompleter.java new file mode 100644 index 00000000..fc6d715a --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestCompleter.java @@ -0,0 +1,8 @@ +package com.gomo.app.core.quest.application.port.in; + +import com.gomo.app.core.quest.application.port.command.CompleteAssignQuestCommand; + +public interface AssignQuestCompleter { + + void complete(CompleteAssignQuestCommand command); +} diff --git a/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestConfirmer.java b/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestConfirmer.java new file mode 100644 index 00000000..eb347aa4 --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestConfirmer.java @@ -0,0 +1,8 @@ +package com.gomo.app.core.quest.application.port.in; + +import java.util.UUID; + +public interface AssignQuestConfirmer { + + void confirm(UUID accessorId, UUID assignQuestId); +} diff --git a/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestCreator.java b/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestCreator.java new file mode 100644 index 00000000..6c23fa16 --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestCreator.java @@ -0,0 +1,10 @@ +package com.gomo.app.core.quest.application.port.in; + +import java.util.UUID; + +import com.gomo.app.core.quest.application.port.command.CreateAssignQuestCommand; + +public interface AssignQuestCreator { + + UUID create(CreateAssignQuestCommand command); +} diff --git a/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestDeleter.java b/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestDeleter.java new file mode 100644 index 00000000..7b6f002c --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestDeleter.java @@ -0,0 +1,8 @@ +package com.gomo.app.core.quest.application.port.in; + +import java.util.UUID; + +public interface AssignQuestDeleter { + + void delete(UUID participantId, UUID assignQuestId); +} diff --git a/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestDetailReader.java b/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestDetailReader.java new file mode 100644 index 00000000..a1c36f84 --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestDetailReader.java @@ -0,0 +1,10 @@ +package com.gomo.app.core.quest.application.port.in; + +import java.util.UUID; + +import com.gomo.app.core.quest.application.port.dto.ListAssignQuestDetailDto; + +public interface AssignQuestDetailReader { + + ListAssignQuestDetailDto readAll(UUID participantId); +} diff --git a/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestOrderUpdater.java b/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestOrderUpdater.java new file mode 100644 index 00000000..e6e78da6 --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestOrderUpdater.java @@ -0,0 +1,8 @@ +package com.gomo.app.core.quest.application.port.in; + +import com.gomo.app.core.quest.application.port.command.OrderUpdateAssignQuestCommand; + +public interface AssignQuestOrderUpdater { + + void update(OrderUpdateAssignQuestCommand command); +} diff --git a/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestReRoller.java b/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestReRoller.java new file mode 100644 index 00000000..49499f74 --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestReRoller.java @@ -0,0 +1,10 @@ +package com.gomo.app.core.quest.application.port.in; + +import java.util.UUID; + +import com.gomo.app.core.quest.application.port.dto.AssignQuestDetailDto; + +public interface AssignQuestReRoller { + + AssignQuestDetailDto reRoll(UUID participantId, UUID assignQuestId); +} diff --git a/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestReader.java b/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestReader.java new file mode 100644 index 00000000..9e5b9908 --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestReader.java @@ -0,0 +1,11 @@ +package com.gomo.app.core.quest.application.port.in; + +import java.util.List; + +import com.gomo.app.core.quest.application.port.command.ListAssignQuestCommand; +import com.gomo.app.core.quest.application.port.dto.AssignQuestDto; + +public interface AssignQuestReader { + + List readAll(ListAssignQuestCommand command); +} diff --git a/src/main/java/com/gomo/app/core/quest/application/port/AutoCreateAssignQuestPortIn.java b/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestRoutineCreator.java similarity index 84% rename from src/main/java/com/gomo/app/core/quest/application/port/AutoCreateAssignQuestPortIn.java rename to src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestRoutineCreator.java index e2b70730..d22c8836 100644 --- a/src/main/java/com/gomo/app/core/quest/application/port/AutoCreateAssignQuestPortIn.java +++ b/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestRoutineCreator.java @@ -1,11 +1,11 @@ -package com.gomo.app.core.quest.application.port; +package com.gomo.app.core.quest.application.port.in; import java.util.List; import com.gomo.app.core.quest.application.port.dto.ParticipantDto; import com.gomo.app.core.quest.domain.model.quest.QuestType; -public interface AutoCreateAssignQuestPortIn { +public interface AssignQuestRoutineCreator { /** * Creates assign quests for a given list of participants based on a specified routine type. diff --git a/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestUpdater.java b/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestUpdater.java new file mode 100644 index 00000000..9cb565c0 --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/application/port/in/AssignQuestUpdater.java @@ -0,0 +1,8 @@ +package com.gomo.app.core.quest.application.port.in; + +import com.gomo.app.core.quest.application.port.command.UpdateAssignQuestCommand; + +public interface AssignQuestUpdater { + + void update(UpdateAssignQuestCommand command); +} diff --git a/src/main/java/com/gomo/app/core/quest/application/port/CreateQuestPoolPortIn.java b/src/main/java/com/gomo/app/core/quest/application/port/in/QuestPoolCreator.java similarity index 81% rename from src/main/java/com/gomo/app/core/quest/application/port/CreateQuestPoolPortIn.java rename to src/main/java/com/gomo/app/core/quest/application/port/in/QuestPoolCreator.java index 04213ec8..2e9d6509 100644 --- a/src/main/java/com/gomo/app/core/quest/application/port/CreateQuestPoolPortIn.java +++ b/src/main/java/com/gomo/app/core/quest/application/port/in/QuestPoolCreator.java @@ -1,8 +1,8 @@ -package com.gomo.app.core.quest.application.port; +package com.gomo.app.core.quest.application.port.in; import com.gomo.app.core.quest.application.port.command.CreateQuestPoolCommand; -public interface CreateQuestPoolPortIn { +public interface QuestPoolCreator { /** * Creates a quest pool for a specific participant based on the provided command. diff --git a/src/main/java/com/gomo/app/core/quest/application/port/PublishCreateQuestPoolPortIn.java b/src/main/java/com/gomo/app/core/quest/application/port/in/QuestPoolEventPublisher.java similarity index 59% rename from src/main/java/com/gomo/app/core/quest/application/port/PublishCreateQuestPoolPortIn.java rename to src/main/java/com/gomo/app/core/quest/application/port/in/QuestPoolEventPublisher.java index 968cc01e..34bf0dec 100644 --- a/src/main/java/com/gomo/app/core/quest/application/port/PublishCreateQuestPoolPortIn.java +++ b/src/main/java/com/gomo/app/core/quest/application/port/in/QuestPoolEventPublisher.java @@ -1,8 +1,8 @@ -package com.gomo.app.core.quest.application.port; +package com.gomo.app.core.quest.application.port.in; import com.gomo.app.core.quest.application.port.command.PublishCreateQuestPoolCommand; -public interface PublishCreateQuestPoolPortIn { +public interface QuestPoolEventPublisher { void publish(PublishCreateQuestPoolCommand command); } diff --git a/src/main/java/com/gomo/app/core/quest/application/port/in/RepeatQuestCreator.java b/src/main/java/com/gomo/app/core/quest/application/port/in/RepeatQuestCreator.java new file mode 100644 index 00000000..49dcfe12 --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/application/port/in/RepeatQuestCreator.java @@ -0,0 +1,10 @@ +package com.gomo.app.core.quest.application.port.in; + +import java.util.UUID; + +import com.gomo.app.core.quest.application.port.command.CreateRepeatQuestCommand; + +public interface RepeatQuestCreator { + + UUID create(CreateRepeatQuestCommand command); +} diff --git a/src/main/java/com/gomo/app/core/quest/application/port/in/RepeatQuestDeleter.java b/src/main/java/com/gomo/app/core/quest/application/port/in/RepeatQuestDeleter.java new file mode 100644 index 00000000..90cb21c1 --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/application/port/in/RepeatQuestDeleter.java @@ -0,0 +1,8 @@ +package com.gomo.app.core.quest.application.port.in; + +import java.util.UUID; + +public interface RepeatQuestDeleter { + + void delete(UUID participantId, UUID repeatQuestId); +} diff --git a/src/main/java/com/gomo/app/core/quest/application/port/in/RepeatQuestOrderUpdater.java b/src/main/java/com/gomo/app/core/quest/application/port/in/RepeatQuestOrderUpdater.java new file mode 100644 index 00000000..cc556ebc --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/application/port/in/RepeatQuestOrderUpdater.java @@ -0,0 +1,8 @@ +package com.gomo.app.core.quest.application.port.in; + +import com.gomo.app.core.quest.application.port.command.OrderUpdateRepeatQuestCommand; + +public interface RepeatQuestOrderUpdater { + + void update(OrderUpdateRepeatQuestCommand command); +} diff --git a/src/main/java/com/gomo/app/core/quest/application/port/in/RepeatQuestReader.java b/src/main/java/com/gomo/app/core/quest/application/port/in/RepeatQuestReader.java new file mode 100644 index 00000000..53c1d0eb --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/application/port/in/RepeatQuestReader.java @@ -0,0 +1,10 @@ +package com.gomo.app.core.quest.application.port.in; + +import java.util.UUID; + +import com.gomo.app.core.quest.application.port.dto.ListRepeatQuestDto; + +public interface RepeatQuestReader { + + ListRepeatQuestDto readAll(UUID participantId); +} diff --git a/src/main/java/com/gomo/app/core/quest/application/port/in/RepeatQuestUpdater.java b/src/main/java/com/gomo/app/core/quest/application/port/in/RepeatQuestUpdater.java new file mode 100644 index 00000000..63849b56 --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/application/port/in/RepeatQuestUpdater.java @@ -0,0 +1,8 @@ +package com.gomo.app.core.quest.application.port.in; + +import com.gomo.app.core.quest.application.port.command.UpdateRepeatQuestCommand; + +public interface RepeatQuestUpdater { + + void update(UpdateRepeatQuestCommand command); +} diff --git a/src/main/java/com/gomo/app/core/quest/application/port/ReadParticipantPortOut.java b/src/main/java/com/gomo/app/core/quest/application/port/out/ParticipantReader.java similarity index 57% rename from src/main/java/com/gomo/app/core/quest/application/port/ReadParticipantPortOut.java rename to src/main/java/com/gomo/app/core/quest/application/port/out/ParticipantReader.java index 0daed948..6da4a773 100644 --- a/src/main/java/com/gomo/app/core/quest/application/port/ReadParticipantPortOut.java +++ b/src/main/java/com/gomo/app/core/quest/application/port/out/ParticipantReader.java @@ -1,16 +1,16 @@ -package com.gomo.app.core.quest.application.port; +package com.gomo.app.core.quest.application.port.out; import java.util.UUID; import com.gomo.app.core.quest.application.port.dto.ParticipantDto; -public interface ReadParticipantPortOut { +public interface ParticipantReader { /** - * Finds a single participant by id. + * Retrieves a single participant by id. * * @param participantId The id of the participant to find. * @return A {@link ParticipantDto} with the participant's data. */ - ParticipantDto find(UUID participantId); + ParticipantDto read(UUID participantId); } diff --git a/src/main/java/com/gomo/app/core/quest/application/port/CreateQuestContentPortOut.java b/src/main/java/com/gomo/app/core/quest/application/port/out/QuestContentCreator.java similarity index 84% rename from src/main/java/com/gomo/app/core/quest/application/port/CreateQuestContentPortOut.java rename to src/main/java/com/gomo/app/core/quest/application/port/out/QuestContentCreator.java index 11708d75..6dabc81a 100644 --- a/src/main/java/com/gomo/app/core/quest/application/port/CreateQuestContentPortOut.java +++ b/src/main/java/com/gomo/app/core/quest/application/port/out/QuestContentCreator.java @@ -1,11 +1,11 @@ -package com.gomo.app.core.quest.application.port; +package com.gomo.app.core.quest.application.port.out; import java.util.List; import com.gomo.app.core.quest.application.port.command.CreateQuestContentCommand; import com.gomo.app.core.quest.application.port.dto.QuestContentDto; -public interface CreateQuestContentPortOut { +public interface QuestContentCreator { /** * Creates new quest content based on the provided command. diff --git a/src/main/java/com/gomo/app/core/quest/application/port/ReadSubjectPortOut.java b/src/main/java/com/gomo/app/core/quest/application/port/out/SubjectReader.java similarity index 79% rename from src/main/java/com/gomo/app/core/quest/application/port/ReadSubjectPortOut.java rename to src/main/java/com/gomo/app/core/quest/application/port/out/SubjectReader.java index 02b9e16c..2abcbfb3 100644 --- a/src/main/java/com/gomo/app/core/quest/application/port/ReadSubjectPortOut.java +++ b/src/main/java/com/gomo/app/core/quest/application/port/out/SubjectReader.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.application.port; +package com.gomo.app.core.quest.application.port.out; import java.util.List; import java.util.Set; @@ -6,7 +6,7 @@ import com.gomo.app.core.quest.application.port.dto.SubjectDto; -public interface ReadSubjectPortOut { +public interface SubjectReader { /** * Retrieves all subjects related to a specific participant. @@ -15,7 +15,7 @@ public interface ReadSubjectPortOut { * @return A list of {@link SubjectDto}s. Returns an empty list if the participant * has no associated subjects; this method does not return null. */ - List findAll(UUID participantId); + List readAll(UUID participantId); /** * Retrieves all subjects related to participants. @@ -24,5 +24,5 @@ public interface ReadSubjectPortOut { * @return A list of {@link SubjectDto}s. Returns an empty list if participants * has no associated subjects; this method does not return null. */ - List findAllByParticipantIds(Set participantIds); + List readAllByParticipantIds(Set participantIds); } diff --git a/src/main/java/com/gomo/app/core/quest/application/usecase/CompleteAssignQuestUseCase.java b/src/main/java/com/gomo/app/core/quest/application/service/AssignQuestCompleteService.java similarity index 69% rename from src/main/java/com/gomo/app/core/quest/application/usecase/CompleteAssignQuestUseCase.java rename to src/main/java/com/gomo/app/core/quest/application/service/AssignQuestCompleteService.java index 4395660d..068fa2fd 100644 --- a/src/main/java/com/gomo/app/core/quest/application/usecase/CompleteAssignQuestUseCase.java +++ b/src/main/java/com/gomo/app/core/quest/application/service/AssignQuestCompleteService.java @@ -1,45 +1,44 @@ -package com.gomo.app.core.quest.application.usecase; +package com.gomo.app.core.quest.application.service; import java.util.UUID; import org.springframework.transaction.annotation.Transactional; import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.logging.AuditLog; import com.gomo.app.common.util.JsonParser; import com.gomo.app.common.util.TimestampGenerator; import com.gomo.app.core.quest.application.port.command.CompleteAssignQuestCommand; +import com.gomo.app.core.quest.application.port.in.AssignQuestCompleter; +import com.gomo.app.core.quest.domain.event.CompleteQuestEvent; import com.gomo.app.core.quest.domain.model.assign.AssignQuest; import com.gomo.app.core.quest.domain.model.assign.CompletionProof; import com.gomo.app.core.quest.domain.model.reward.QuestReward; -import com.gomo.app.core.quest.domain.service.AssignQuestService; -import com.gomo.app.core.quest.domain.service.QuestRewardService; -import com.gomo.app.core.quest.event.CompleteQuestEvent; +import com.gomo.app.core.quest.domain.service.QuestRewardProvider; import com.gomo.app.support.evententry.application.port.CreateEventEntryPortIn; -import com.gomo.app.support.logging.AuditLog; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -@Slf4j @RequiredArgsConstructor @Transactional @ApplicationService -public class CompleteAssignQuestUseCase { +class AssignQuestCompleteService implements AssignQuestCompleter { private final AssignQuestService assignQuestService; - private final QuestRewardService questRewardService; + private final QuestRewardProvider questRewardProvider; private final CreateEventEntryPortIn createEventEntryPortIn; - @AuditLog(action = "COMPLETE_ASSIGN_QUEST") + @Override + @AuditLog(action = "ASSIGN_QUEST_COMPLETE") public void complete(CompleteAssignQuestCommand command) { - AssignQuest assignQuest = assignQuestService.find(command.assignQuestId()); + AssignQuest assignQuest = assignQuestService.readById(command.assignQuestId()); assignQuest.validateAuthority(command.participantId()); assignQuest.complete(CompletionProof.of(command.proof()), command.completedDateTime()); createQuestCompletionEvent(command.participantId(), assignQuest); } private void createQuestCompletionEvent(UUID participantId, AssignQuest assignQuest) { - QuestReward questReward = questRewardService.find(assignQuest.questType()); + QuestReward questReward = questRewardProvider.provide(assignQuest.questType()); long timestamp = TimestampGenerator.generate(); CompleteQuestEvent completeQuestEvent = CompleteQuestEvent.of( participantId, diff --git a/src/main/java/com/gomo/app/core/quest/application/usecase/CreateAssignQuestUseCase.java b/src/main/java/com/gomo/app/core/quest/application/service/AssignQuestCreateService.java similarity index 58% rename from src/main/java/com/gomo/app/core/quest/application/usecase/CreateAssignQuestUseCase.java rename to src/main/java/com/gomo/app/core/quest/application/service/AssignQuestCreateService.java index 4f8b0695..a754f5e1 100644 --- a/src/main/java/com/gomo/app/core/quest/application/usecase/CreateAssignQuestUseCase.java +++ b/src/main/java/com/gomo/app/core/quest/application/service/AssignQuestCreateService.java @@ -1,16 +1,21 @@ -package com.gomo.app.core.quest.application.usecase; +package com.gomo.app.core.quest.application.service; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.UUID; +import org.jetbrains.annotations.NotNull; import org.springframework.transaction.annotation.Transactional; import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.displayorder.DisplayOrder; +import com.gomo.app.common.logging.AuditLog; import com.gomo.app.common.util.DateRangeCalculator; -import com.gomo.app.core.quest.application.port.ReadParticipantPortOut; +import com.gomo.app.common.util.UUIDGenerator; import com.gomo.app.core.quest.application.port.command.CreateAssignQuestCommand; import com.gomo.app.core.quest.application.port.dto.ParticipantDto; +import com.gomo.app.core.quest.application.port.in.AssignQuestCreator; +import com.gomo.app.core.quest.application.port.out.ParticipantReader; import com.gomo.app.core.quest.domain.model.assign.AssignQuest; import com.gomo.app.core.quest.domain.model.participant.Participant; import com.gomo.app.core.quest.domain.model.participant.QuestQuota; @@ -19,38 +24,28 @@ import com.gomo.app.core.quest.domain.model.quest.QuestType; import com.gomo.app.core.quest.domain.model.subject.SubjectName; import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; -import com.gomo.app.core.quest.domain.service.AssignQuestService; -import com.gomo.app.support.logging.AuditLog; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @Transactional @ApplicationService -public class CreateAssignQuestUseCase { +class AssignQuestCreateService implements AssignQuestCreator { - private final ReadParticipantPortOut readParticipantPortOut; - private final AssignQuestService assignQuestService; + private final ParticipantReader participantReader; private final AssignQuestRepository assignQuestRepository; - @AuditLog(action = "CREATE_ASSIGN_QUEST") + @AuditLog(action = "ASSIGN_QUEST_CREATE") public UUID create(CreateAssignQuestCommand command) { UUID participantId = command.participantId(); QuestType questType = QuestType.valueOf(command.questType()); ensureNotExceedQuestQuota(participantId, questType); - Quest quest = Quest.of( - participantId, - command.subjectId(), - SubjectName.of(command.subjectName()), - questType, - QuestContent.of(command.content()) - ); - AssignQuest savedAssignQuest = assignQuestService.create(participantId, quest); - return savedAssignQuest.getId(); + AssignQuest assignQuest = assignQuestRepository.save(createAssignQuest(command, participantId, questType)); + return assignQuest.getId(); } private void ensureNotExceedQuestQuota(UUID participantId, QuestType questType) { - ParticipantDto dto = readParticipantPortOut.find(participantId); + ParticipantDto dto = participantReader.read(participantId); Participant participant = Participant.of( dto.id(), QuestQuota.of(dto.dailyQuota(), dto.weeklyQuota(), dto.monthlyQuota()) @@ -65,4 +60,37 @@ private int countParticipatingQuest(UUID participantId, QuestType questType) { LocalDateTime endDateTime = DateRangeCalculator.endOf(now, questType.name()); return (int)assignQuestRepository.countParticipatingQuestByQuestType(participantId, questType, startDateTime, endDateTime); } + + @NotNull + private AssignQuest createAssignQuest(CreateAssignQuestCommand command, UUID participantId, QuestType questType) { + Quest quest = Quest.of( + participantId, + command.subjectId(), + SubjectName.of(command.subjectName()), + questType, + QuestContent.of(command.content()) + ); + + int displayOrder = findMaxDisplayOrderOfParticipatingQuest(participantId, quest.getType()) + 1; + return AssignQuest.of( + UUIDGenerator.generate(), + quest, + false, + DisplayOrder.of(displayOrder), + LocalDateTime.now() + ); + } + + private int findMaxDisplayOrderOfParticipatingQuest(UUID participantId, QuestType questType) { + LocalDate now = LocalDate.now(); + LocalDateTime startDateTime = DateRangeCalculator.startOf(now, questType.name()); + LocalDateTime endDateTime = DateRangeCalculator.endOf(now, questType.name()); + + return assignQuestRepository.findMaxDisplayOrderOfParticipatingQuest( + participantId, + questType, + startDateTime, + endDateTime + ); + } } diff --git a/src/main/java/com/gomo/app/core/quest/application/usecase/ReRollAssignQuestUseCase.java b/src/main/java/com/gomo/app/core/quest/application/service/AssignQuestReRollService.java similarity index 56% rename from src/main/java/com/gomo/app/core/quest/application/usecase/ReRollAssignQuestUseCase.java rename to src/main/java/com/gomo/app/core/quest/application/service/AssignQuestReRollService.java index 54fc5e36..25b311c6 100644 --- a/src/main/java/com/gomo/app/core/quest/application/usecase/ReRollAssignQuestUseCase.java +++ b/src/main/java/com/gomo/app/core/quest/application/service/AssignQuestReRollService.java @@ -1,37 +1,38 @@ -package com.gomo.app.core.quest.application.usecase; +package com.gomo.app.core.quest.application.service; import java.util.UUID; import org.springframework.transaction.annotation.Transactional; import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.quest.application.port.dto.AssignQuestDto; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.core.quest.application.port.dto.AssignQuestDetailDto; +import com.gomo.app.core.quest.application.port.in.AssignQuestReRoller; +import com.gomo.app.core.quest.domain.exception.QuestPoolNotFoundException; +import com.gomo.app.core.quest.domain.exception.code.QuestPoolErrorCode; import com.gomo.app.core.quest.domain.model.assign.AssignQuest; import com.gomo.app.core.quest.domain.model.pool.ProcessingStatus; import com.gomo.app.core.quest.domain.model.pool.QuestPool; import com.gomo.app.core.quest.domain.model.pool.SourceType; import com.gomo.app.core.quest.domain.model.reward.QuestReward; import com.gomo.app.core.quest.domain.repository.QuestPoolRepository; -import com.gomo.app.core.quest.domain.service.AssignQuestService; -import com.gomo.app.core.quest.domain.service.QuestRewardService; -import com.gomo.app.core.quest.exception.QuestPoolNotFoundException; -import com.gomo.app.core.quest.exception.code.QuestPoolErrorCode; -import com.gomo.app.support.logging.AuditLog; +import com.gomo.app.core.quest.domain.service.QuestRewardProvider; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @Transactional @ApplicationService -public class ReRollAssignQuestUseCase { +class AssignQuestReRollService implements AssignQuestReRoller { - private final QuestPoolRepository questPoolRepository; private final AssignQuestService assignQuestService; - private final QuestRewardService questRewardService; + private final QuestRewardProvider questRewardProvider; + private final QuestPoolRepository questPoolRepository; - @AuditLog(action = "RE_ROLL_ASSIGN_QUEST") - public AssignQuestDto reRoll(UUID participantId, UUID assignQuestId) { - AssignQuest assignQuest = assignQuestService.find(assignQuestId); + @Override + @AuditLog(action = "ASSIGN_QUEST_RE_ROLL") + public AssignQuestDetailDto reRoll(UUID participantId, UUID assignQuestId) { + AssignQuest assignQuest = assignQuestService.readById(assignQuestId); QuestPool questPool = questPoolRepository.findFirstByQuestParticipantIdAndQuestTypeAndSourceTypeAndProcessingStatus( participantId, assignQuest.questType(), @@ -40,7 +41,7 @@ public AssignQuestDto reRoll(UUID participantId, UUID assignQuestId) { ).orElseThrow(() -> new QuestPoolNotFoundException(QuestPoolErrorCode.NOT_FOUND)); assignQuest.updateQuest(questPool.getQuest()); questPool.updateProcessingStatus(ProcessingStatus.ASSIGNED); - QuestReward questReward = questRewardService.find(assignQuest.questType()); - return AssignQuestDto.from(assignQuest, questReward.pointValue(), questReward.scoreValue()); + QuestReward questReward = questRewardProvider.provide(assignQuest.questType()); + return AssignQuestDetailDto.from(assignQuest, questReward.pointValue(), questReward.scoreValue()); } } diff --git a/src/main/java/com/gomo/app/core/quest/application/usecase/AutoCreateAssignQuestUseCase.java b/src/main/java/com/gomo/app/core/quest/application/service/AssignQuestRoutineService.java similarity index 90% rename from src/main/java/com/gomo/app/core/quest/application/usecase/AutoCreateAssignQuestUseCase.java rename to src/main/java/com/gomo/app/core/quest/application/service/AssignQuestRoutineService.java index 5510718d..838b1f6e 100644 --- a/src/main/java/com/gomo/app/core/quest/application/usecase/AutoCreateAssignQuestUseCase.java +++ b/src/main/java/com/gomo/app/core/quest/application/service/AssignQuestRoutineService.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.application.usecase; +package com.gomo.app.core.quest.application.service; import java.time.LocalDateTime; import java.util.ArrayList; @@ -10,8 +10,9 @@ import com.gomo.app.common.arch.ApplicationService; import com.gomo.app.common.displayorder.DisplayOrder; -import com.gomo.app.core.quest.application.port.AutoCreateAssignQuestPortIn; +import com.gomo.app.common.logging.AuditLog; import com.gomo.app.core.quest.application.port.dto.ParticipantDto; +import com.gomo.app.core.quest.application.port.in.AssignQuestRoutineCreator; import com.gomo.app.core.quest.domain.model.assign.AssignQuest; import com.gomo.app.core.quest.domain.model.participant.Participant; import com.gomo.app.core.quest.domain.model.participant.QuestQuota; @@ -22,30 +23,25 @@ import com.gomo.app.core.quest.domain.repository.BulkAssignQuestRepository; import com.gomo.app.core.quest.domain.repository.QuestPoolRepository; import com.gomo.app.core.quest.domain.repository.RepeatQuestRepository; -import com.gomo.app.support.logging.AuditLog; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; /** - * Implements the {@link AutoCreateAssignQuestPortIn} use case. - *

- * This service automatically creates {@link AssignQuest} entities for each participant. + * This service creates {@link AssignQuest} entities for each participant. * It combines quests from two sources: user-defined {@link RepeatQuest}s and the general {@link QuestPool}, * then saves them to the database in a single bulk operation. */ -@Slf4j @RequiredArgsConstructor @Transactional @ApplicationService -class AutoCreateAssignQuestUseCase implements AutoCreateAssignQuestPortIn { +class AssignQuestRoutineService implements AssignQuestRoutineCreator { private final RepeatQuestRepository repeatQuestRepository; private final QuestPoolRepository questPoolRepository; private final BulkAssignQuestRepository bulkAssignQuestRepository; - @AuditLog(action = "AUTO_CREATE_ASSIGN_QUESTS") @Override + @AuditLog(action = "ASSIGN_QUEST_ROUTINE_CREATE") public void execute(List participantDtos, String questType) { LocalDateTime now = LocalDateTime.now(); List assignQuests = participantDtos.stream() diff --git a/src/main/java/com/gomo/app/core/quest/application/service/AssignQuestService.java b/src/main/java/com/gomo/app/core/quest/application/service/AssignQuestService.java new file mode 100644 index 00000000..7aae1d48 --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/application/service/AssignQuestService.java @@ -0,0 +1,151 @@ +package com.gomo.app.core.quest.application.service; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; + +import org.springframework.transaction.annotation.Transactional; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.displayorder.OrderChangeable; +import com.gomo.app.common.displayorder.OrderChanger; +import com.gomo.app.common.displayorder.OrderUpdateOrderChangeableCommand; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.common.util.DateRangeCalculator; +import com.gomo.app.core.quest.application.port.command.ListAssignQuestCommand; +import com.gomo.app.core.quest.application.port.command.OrderUpdateAssignQuestCommand; +import com.gomo.app.core.quest.application.port.command.UpdateAssignQuestCommand; +import com.gomo.app.core.quest.application.port.dto.AssignQuestDetailDto; +import com.gomo.app.core.quest.application.port.dto.AssignQuestDto; +import com.gomo.app.core.quest.application.port.dto.ListAssignQuestDetailDto; +import com.gomo.app.core.quest.application.port.in.AssignQuestConfirmer; +import com.gomo.app.core.quest.application.port.in.AssignQuestDeleter; +import com.gomo.app.core.quest.application.port.in.AssignQuestDetailReader; +import com.gomo.app.core.quest.application.port.in.AssignQuestOrderUpdater; +import com.gomo.app.core.quest.application.port.in.AssignQuestReader; +import com.gomo.app.core.quest.application.port.in.AssignQuestUpdater; +import com.gomo.app.core.quest.domain.exception.AssignQuestNotFoundException; +import com.gomo.app.core.quest.domain.exception.code.AssignQuestErrorCode; +import com.gomo.app.core.quest.domain.model.assign.AssignQuest; +import com.gomo.app.core.quest.domain.model.quest.QuestContent; +import com.gomo.app.core.quest.domain.model.quest.QuestType; +import com.gomo.app.core.quest.domain.model.reward.QuestReward; +import com.gomo.app.core.quest.domain.model.subject.SubjectName; +import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; +import com.gomo.app.core.quest.domain.service.QuestRewardProvider; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Transactional +@ApplicationService +class AssignQuestService + implements AssignQuestReader, AssignQuestDetailReader, AssignQuestUpdater, AssignQuestOrderUpdater, AssignQuestDeleter, AssignQuestConfirmer { + + private final QuestRewardProvider questRewardProvider; + private final AssignQuestRepository assignQuestRepository; + + @Override + @Transactional(readOnly = true) + public List readAll(ListAssignQuestCommand command) { + UUID targetId = command.participantId(); + LocalDateTime startDate = command.startDate(); + LocalDateTime endDate = command.endDate(); + List calendars; + if (command.isCompleted()) { + calendars = assignQuestRepository.findByQuestParticipantIdAndCompletedDateTimeBetween(targetId, startDate, endDate) + .stream() + .map(AssignQuestDto::of) + .toList(); + } else { + calendars = assignQuestRepository.findByQuestParticipantIdAndStartDateTimeBetweenAndIsCompletedFalse(targetId, startDate, endDate) + .stream() + .map(AssignQuestDto::of) + .toList(); + } + return calendars; + } + + @Override + @Transactional(readOnly = true) + public ListAssignQuestDetailDto readAll(UUID participantId) { + List dailyQuests = readAllByQuestType(participantId, QuestType.DAILY); + List weeklyQuests = readAllByQuestType(participantId, QuestType.WEEKLY); + List monthlyQuests = readAllByQuestType(participantId, QuestType.MONTHLY); + return ListAssignQuestDetailDto.of(dailyQuests, weeklyQuests, monthlyQuests); + } + + private List readAllByQuestType(UUID participantId, QuestType questType) { + return assignQuestRepository.findParticipatingQuestByQuestType( + participantId, + questType, + DateRangeCalculator.startOf(LocalDate.now(), questType.name()), + DateRangeCalculator.endOf(LocalDate.now(), questType.name()) + ).stream().map(assignQuest -> { + QuestReward questReward = questRewardProvider.provide(questType); + return AssignQuestDetailDto.from(assignQuest, questReward.pointValue(), questReward.scoreValue()); + }).toList(); + } + + AssignQuest readById(UUID assignQuestId) { + return assignQuestRepository.findById(assignQuestId) + .orElseThrow(() -> new AssignQuestNotFoundException(AssignQuestErrorCode.NOT_FOUND)); + } + + @Override + @AuditLog(action = "ASSIGN_QUEST_UPDATE") + public void update(UpdateAssignQuestCommand command) { + AssignQuest assignQuest = readById(command.assignQuestId()); + assignQuest.validateAuthority(command.participantId()); + + QuestType requestedQuestType = QuestType.valueOf(command.questType()); + assignQuest.ensureSameQuestType(requestedQuestType); + assignQuest.ensureNotConfirmed(); + assignQuest.ensureNotCompleted(); + + assignQuest.updateQuest( + command.subjectId(), + SubjectName.of(command.subjectName()), + requestedQuestType, + QuestContent.of(command.content()) + ); + } + + @Override + @AuditLog(action = "ASSIGN_QUEST_ORDER_UPDATE") + public void update(OrderUpdateAssignQuestCommand command) { + LocalDate now = LocalDate.now(); + QuestType questType = QuestType.valueOf(command.questType()); + Map assignQuestMap = assignQuestRepository.findParticipatingQuestByQuestTypeWithoutCompleted( + command.participantId(), + questType, + DateRangeCalculator.startOf(now, questType.name()), + DateRangeCalculator.endOf(now, questType.name()) + ).stream().collect(Collectors.toMap( + assignQuest -> assignQuest.getId(), + assignQuest -> assignQuest + )); + OrderChanger.change(OrderUpdateOrderChangeableCommand.of(assignQuestMap, command.updatedOrders())); + } + + @Override + @AuditLog(action = "ASSIGN_QUEST_CONFIRM") + public void confirm(UUID accessorId, UUID assignQuestId) { + AssignQuest assignQuest = readById(assignQuestId); + assignQuest.validateAuthority(accessorId); + assignQuest.confirm(); + } + + @Override + @AuditLog(action = "ASSIGN_QUEST_DELETE") + public void delete(UUID participantId, UUID assignQuestId) { + AssignQuest assignQuest = readById(assignQuestId); + assignQuest.validateAuthority(participantId); + assignQuest.ensureNotConfirmed(); + assignQuest.ensureNotCompleted(); + assignQuestRepository.delete(assignQuest); + } +} diff --git a/src/main/java/com/gomo/app/core/quest/application/usecase/CreateQuestPoolUseCase.java b/src/main/java/com/gomo/app/core/quest/application/service/QuestPoolCreateService.java similarity index 76% rename from src/main/java/com/gomo/app/core/quest/application/usecase/CreateQuestPoolUseCase.java rename to src/main/java/com/gomo/app/core/quest/application/service/QuestPoolCreateService.java index d4be2cfa..f1c30639 100644 --- a/src/main/java/com/gomo/app/core/quest/application/usecase/CreateQuestPoolUseCase.java +++ b/src/main/java/com/gomo/app/core/quest/application/service/QuestPoolCreateService.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.application.usecase; +package com.gomo.app.core.quest.application.service; import java.util.List; import java.util.UUID; @@ -6,11 +6,12 @@ import org.springframework.transaction.annotation.Transactional; import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.logging.AuditLog; import com.gomo.app.common.util.UUIDGenerator; -import com.gomo.app.core.quest.application.port.CreateQuestContentPortOut; -import com.gomo.app.core.quest.application.port.CreateQuestPoolPortIn; import com.gomo.app.core.quest.application.port.command.CreateQuestContentCommand; import com.gomo.app.core.quest.application.port.command.CreateQuestPoolCommand; +import com.gomo.app.core.quest.application.port.in.QuestPoolCreator; +import com.gomo.app.core.quest.application.port.out.QuestContentCreator; import com.gomo.app.core.quest.domain.model.pool.ProcessingStatus; import com.gomo.app.core.quest.domain.model.pool.QuestPool; import com.gomo.app.core.quest.domain.model.pool.SourceType; @@ -19,7 +20,6 @@ import com.gomo.app.core.quest.domain.model.quest.QuestType; import com.gomo.app.core.quest.domain.model.subject.SubjectName; import com.gomo.app.core.quest.domain.repository.QuestPoolRepository; -import com.gomo.app.support.logging.AuditLog; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -28,12 +28,12 @@ @RequiredArgsConstructor @Transactional @ApplicationService -class CreateQuestPoolUseCase implements CreateQuestPoolPortIn { +class QuestPoolCreateService implements QuestPoolCreator { - private final CreateQuestContentPortOut createQuestContentPortOut; + private final QuestContentCreator questContentCreator; private final QuestPoolRepository questPoolRepository; - @AuditLog(action = "CREATE_QUEST_POOL") + @AuditLog(action = "QUEST_POOL_CREATE") @Override public void create(CreateQuestPoolCommand command) { UUID participantId = command.participantId(); @@ -46,7 +46,7 @@ public void create(CreateQuestPoolCommand command) { int limit = command.limit(); if (existCount >= limit) { - log.debug("Already fully created quest pool with participant id={}, quest type={}, limit={}", participantId, questType, limit); + log.debug("Skipped creating quest pool. Quest pool is already full with participant id={}, quest type={}, limit={}", participantId, questType, limit); return; } @@ -54,7 +54,7 @@ public void create(CreateQuestPoolCommand command) { .map(subject -> CreateQuestContentCommand.Subject.of(subject.id(), subject.name(), subject.level())) .toList(); int createCount = limit - existCount; - List questPools = createQuestContentPortOut.create(CreateQuestContentCommand.of(participantId, subjects, questType, createCount)).stream() + List questPools = questContentCreator.create(CreateQuestContentCommand.of(participantId, subjects, questType, createCount)).stream() .map(dto -> { Quest quest = Quest.of( dto.participantId(), diff --git a/src/main/java/com/gomo/app/core/quest/application/usecase/PublishCreateQuestPoolUseCase.java b/src/main/java/com/gomo/app/core/quest/application/service/QuestPoolEventService.java similarity index 68% rename from src/main/java/com/gomo/app/core/quest/application/usecase/PublishCreateQuestPoolUseCase.java rename to src/main/java/com/gomo/app/core/quest/application/service/QuestPoolEventService.java index 9bbfddba..5baa9aee 100644 --- a/src/main/java/com/gomo/app/core/quest/application/usecase/PublishCreateQuestPoolUseCase.java +++ b/src/main/java/com/gomo/app/core/quest/application/service/QuestPoolEventService.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.application.usecase; +package com.gomo.app.core.quest.application.service; import java.util.List; import java.util.Map; @@ -8,40 +8,38 @@ import com.gomo.app.common.arch.ApplicationService; import com.gomo.app.common.event.EventRouter; +import com.gomo.app.common.logging.AuditLog; import com.gomo.app.common.util.JsonParser; import com.gomo.app.common.util.TimestampGenerator; import com.gomo.app.common.util.UUIDGenerator; -import com.gomo.app.core.quest.application.port.PublishCreateQuestPoolPortIn; -import com.gomo.app.core.quest.application.port.ReadSubjectPortOut; import com.gomo.app.core.quest.application.port.command.PublishCreateQuestPoolCommand; import com.gomo.app.core.quest.application.port.dto.SubjectDto; +import com.gomo.app.core.quest.application.port.in.QuestPoolEventPublisher; +import com.gomo.app.core.quest.application.port.out.SubjectReader; +import com.gomo.app.core.quest.domain.event.CreateQuestPoolEvent; import com.gomo.app.core.quest.domain.model.participant.Participant; -import com.gomo.app.core.quest.event.CreateQuestPoolEvent; -import com.gomo.app.support.logging.AuditLog; -import com.gomo.app.support.messagebroker.application.port.PublishMessagePortIn; +import com.gomo.app.support.messagebroker.application.port.in.MessagePublisher; import com.gomo.app.support.messagebroker.domain.model.DirectEvent; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -@Slf4j @RequiredArgsConstructor @ApplicationService -class PublishCreateQuestPoolUseCase implements PublishCreateQuestPoolPortIn { +class QuestPoolEventService implements QuestPoolEventPublisher { - private final ReadSubjectPortOut readSubjectPortOut; + private final SubjectReader subjectReader; private final EventRouter eventRouter; - private final PublishMessagePortIn publishMessagePortIn; + private final MessagePublisher messagePublisher; - @AuditLog(action = "PUBLISH_CREATE_QUEST_POOL_EVENT") @Override + @AuditLog(action = "QUEST_POOL_CREATE_EVENT_PUBLISH") public void publish(PublishCreateQuestPoolCommand command) { List participants = command.participants(); Set participantIds = participants.stream() .map(Participant::getId) .collect(Collectors.toSet()); - Map> interestsByMemberId = readSubjectPortOut.findAllByParticipantIds(participantIds).stream() + Map> interestsByMemberId = subjectReader.readAllByParticipantIds(participantIds).stream() .collect(Collectors.groupingBy(SubjectDto::participantId)); for (Participant participant : participants) { UUID participantId = participant.getId(); @@ -58,7 +56,7 @@ public void publish(PublishCreateQuestPoolCommand command) { String exchange = eventRouter.getExchange(eventName); String routingKey = eventRouter.getRoutingKey(eventName); DirectEvent directEvent = DirectEvent.of(UUIDGenerator.generate(), eventName, JsonParser.toJson(event)); - publishMessagePortIn.send(exchange, routingKey, JsonParser.toJson(directEvent)); + messagePublisher.send(exchange, routingKey, JsonParser.toJson(directEvent)); } } } diff --git a/src/main/java/com/gomo/app/core/quest/application/usecase/CreateRepeatQuestUseCase.java b/src/main/java/com/gomo/app/core/quest/application/service/RepeatQuestCreateService.java similarity index 61% rename from src/main/java/com/gomo/app/core/quest/application/usecase/CreateRepeatQuestUseCase.java rename to src/main/java/com/gomo/app/core/quest/application/service/RepeatQuestCreateService.java index 8e5bb63f..02a0c6dd 100644 --- a/src/main/java/com/gomo/app/core/quest/application/usecase/CreateRepeatQuestUseCase.java +++ b/src/main/java/com/gomo/app/core/quest/application/service/RepeatQuestCreateService.java @@ -1,13 +1,18 @@ -package com.gomo.app.core.quest.application.usecase; +package com.gomo.app.core.quest.application.service; import java.util.UUID; +import org.jetbrains.annotations.NotNull; import org.springframework.transaction.annotation.Transactional; import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.quest.application.port.ReadParticipantPortOut; +import com.gomo.app.common.displayorder.DisplayOrder; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.common.util.UUIDGenerator; import com.gomo.app.core.quest.application.port.command.CreateRepeatQuestCommand; import com.gomo.app.core.quest.application.port.dto.ParticipantDto; +import com.gomo.app.core.quest.application.port.in.RepeatQuestCreator; +import com.gomo.app.core.quest.application.port.out.ParticipantReader; import com.gomo.app.core.quest.domain.model.participant.Participant; import com.gomo.app.core.quest.domain.model.participant.QuestQuota; import com.gomo.app.core.quest.domain.model.quest.Quest; @@ -16,38 +21,28 @@ import com.gomo.app.core.quest.domain.model.repeat.RepeatQuest; import com.gomo.app.core.quest.domain.model.subject.SubjectName; import com.gomo.app.core.quest.domain.repository.RepeatQuestRepository; -import com.gomo.app.core.quest.domain.service.RepeatQuestService; -import com.gomo.app.support.logging.AuditLog; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @Transactional @ApplicationService -public class CreateRepeatQuestUseCase { +class RepeatQuestCreateService implements RepeatQuestCreator { - private final ReadParticipantPortOut readParticipantPortOut; - private final RepeatQuestService repeatQuestService; + private final ParticipantReader participantReader; private final RepeatQuestRepository repeatQuestRepository; - @AuditLog(action = "CREATE_REPEAT_QUEST") + @AuditLog(action = "REPEAT_QUEST_CREATE") public UUID create(CreateRepeatQuestCommand command) { UUID participantId = command.participantId(); QuestType questType = QuestType.valueOf(command.questType()); ensureNotExceedQuestQuota(participantId, questType); - Quest quest = Quest.of( - participantId, - command.subjectId(), - SubjectName.of(command.subjectName()), - questType, - QuestContent.of(command.content()) - ); - RepeatQuest savedRepeatQuest = repeatQuestService.create(participantId, quest); + RepeatQuest savedRepeatQuest = repeatQuestRepository.save(createRepeatQuest(command, participantId, questType)); return savedRepeatQuest.getId(); } private void ensureNotExceedQuestQuota(UUID participantId, QuestType questType) { - ParticipantDto dto = readParticipantPortOut.find(participantId); + ParticipantDto dto = participantReader.read(participantId); Participant participant = Participant.of( dto.id(), QuestQuota.of(dto.dailyQuota(), dto.weeklyQuota(), dto.monthlyQuota()) @@ -55,4 +50,17 @@ private void ensureNotExceedQuestQuota(UUID participantId, QuestType questType) int repeatQuestCount = (int)repeatQuestRepository.countByQuestParticipantIdAndQuestType(participant.getId(), questType); participant.validateQuestQuota(questType, repeatQuestCount); } + + @NotNull + private RepeatQuest createRepeatQuest(CreateRepeatQuestCommand command, UUID participantId, QuestType questType) { + Quest quest = Quest.of( + participantId, + command.subjectId(), + SubjectName.of(command.subjectName()), + questType, + QuestContent.of(command.content()) + ); + int nextDisplayOrder = repeatQuestRepository.findMaxDisplayOrderByQuestType(participantId, quest.getType()) + 1; + return RepeatQuest.of(UUIDGenerator.generate(), quest, DisplayOrder.of(nextDisplayOrder)); + } } diff --git a/src/main/java/com/gomo/app/core/quest/application/service/RepeatQuestService.java b/src/main/java/com/gomo/app/core/quest/application/service/RepeatQuestService.java new file mode 100644 index 00000000..f680b736 --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/application/service/RepeatQuestService.java @@ -0,0 +1,109 @@ +package com.gomo.app.core.quest.application.service; + +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; + +import org.springframework.transaction.annotation.Transactional; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.displayorder.OrderChangeable; +import com.gomo.app.common.displayorder.OrderChanger; +import com.gomo.app.common.displayorder.OrderUpdateOrderChangeableCommand; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.core.quest.application.port.command.OrderUpdateRepeatQuestCommand; +import com.gomo.app.core.quest.application.port.command.UpdateRepeatQuestCommand; +import com.gomo.app.core.quest.application.port.dto.ListRepeatQuestDto; +import com.gomo.app.core.quest.application.port.dto.RepeatQuestDto; +import com.gomo.app.core.quest.application.port.in.RepeatQuestDeleter; +import com.gomo.app.core.quest.application.port.in.RepeatQuestOrderUpdater; +import com.gomo.app.core.quest.application.port.in.RepeatQuestReader; +import com.gomo.app.core.quest.application.port.in.RepeatQuestUpdater; +import com.gomo.app.core.quest.domain.exception.QuestTypeConstraintViolationException; +import com.gomo.app.core.quest.domain.exception.RepeatQuestNotFoundException; +import com.gomo.app.core.quest.domain.exception.code.QuestTypeErrorCode; +import com.gomo.app.core.quest.domain.exception.code.RepeatQuestErrorCode; +import com.gomo.app.core.quest.domain.model.quest.QuestContent; +import com.gomo.app.core.quest.domain.model.quest.QuestType; +import com.gomo.app.core.quest.domain.model.repeat.RepeatQuest; +import com.gomo.app.core.quest.domain.model.reward.QuestReward; +import com.gomo.app.core.quest.domain.model.subject.SubjectName; +import com.gomo.app.core.quest.domain.repository.RepeatQuestRepository; +import com.gomo.app.core.quest.domain.service.QuestRewardProvider; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Transactional +@ApplicationService +class RepeatQuestService implements RepeatQuestReader, RepeatQuestUpdater, RepeatQuestOrderUpdater, RepeatQuestDeleter { + + private final QuestRewardProvider questRewardProvider; + private final RepeatQuestRepository repeatQuestRepository; + + RepeatQuest readById(UUID repeatQuestId) { + return repeatQuestRepository.findById(repeatQuestId) + .orElseThrow(() -> new RepeatQuestNotFoundException(RepeatQuestErrorCode.NOT_FOUND)); + } + + @Override + @Transactional(readOnly = true) + public ListRepeatQuestDto readAll(UUID participantId) { + List dailyRepeatQuests = findRepeatQuestResponses(participantId, QuestType.DAILY); + List weeklyRepeatQuests = findRepeatQuestResponses(participantId, QuestType.WEEKLY); + List monthlyRepeatQuests = findRepeatQuestResponses(participantId, QuestType.MONTHLY); + return ListRepeatQuestDto.of(dailyRepeatQuests, weeklyRepeatQuests, monthlyRepeatQuests); + } + + private List findRepeatQuestResponses(UUID participantId, QuestType questType) { + return repeatQuestRepository.findRepeatQuestsByQuestType(participantId, questType).stream() + .map(assignQuest -> { + QuestReward questReward = questRewardProvider.provide(questType); + return RepeatQuestDto.from(assignQuest, questReward.pointValue(), questReward.scoreValue()); + }).toList(); + } + + @Override + @AuditLog(action = "REPEAT_QUEST_UPDATE") + public void update(UpdateRepeatQuestCommand command) { + RepeatQuest repeatQuest = readById(command.repeatQuestId()); + repeatQuest.validateAuthority(command.participantId()); + QuestType requestedQuestType = QuestType.valueOf(command.questType()); + ensureSameQuestType(repeatQuest, requestedQuestType); + + repeatQuest.updateQuest( + command.subjectId(), + SubjectName.of(command.subjectName()), + requestedQuestType, + QuestContent.of(command.content()) + ); + } + + private void ensureSameQuestType(RepeatQuest repeatQuest, QuestType questType) { + if (!repeatQuest.isSameQuestType(questType)) { + throw new QuestTypeConstraintViolationException(QuestTypeErrorCode.MISMATCHED); + } + } + + @Override + @AuditLog(action = "REPEAT_QUEST_ORDER_UPDATE") + public void update(OrderUpdateRepeatQuestCommand command) { + Map repeatQuestMap = repeatQuestRepository.findRepeatQuestsByQuestType( + command.participantId(), + QuestType.valueOf(command.questType()) + ).stream().collect(Collectors.toMap( + repeatQuest -> repeatQuest.getId(), + repeatQuest -> repeatQuest + )); + OrderChanger.change(OrderUpdateOrderChangeableCommand.of(repeatQuestMap, command.updatedOrders())); + } + + @Override + @AuditLog(action = "REPEAT_QUEST_DELETE") + public void delete(UUID participantId, UUID repeatQuestId) { + RepeatQuest repeatQuest = readById(repeatQuestId); + repeatQuest.validateAuthority(participantId); + repeatQuestRepository.delete(repeatQuest); + } +} diff --git a/src/main/java/com/gomo/app/core/quest/application/usecase/CalendarAssignQuestUseCase.java b/src/main/java/com/gomo/app/core/quest/application/usecase/CalendarAssignQuestUseCase.java deleted file mode 100644 index bf7ed5d3..00000000 --- a/src/main/java/com/gomo/app/core/quest/application/usecase/CalendarAssignQuestUseCase.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.gomo.app.core.quest.application.usecase; - -import java.time.LocalDateTime; -import java.util.List; -import java.util.UUID; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.quest.application.port.command.CalendarAssignQuestCommand; -import com.gomo.app.core.quest.application.port.dto.CalendarAssignQuestDto; -import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -public class CalendarAssignQuestUseCase { - - private final AssignQuestRepository assignQuestRepository; - - public List find(CalendarAssignQuestCommand command) { - UUID targetId = command.participantId(); - LocalDateTime startDate = command.startDate(); - LocalDateTime endDate = command.endDate(); - List calendars; - if (command.isCompleted()) { - calendars = assignQuestRepository.findByQuestParticipantIdAndCompletedDateTimeBetween(targetId, startDate, endDate) - .stream() - .map(CalendarAssignQuestDto::of) - .toList(); - } else { - calendars = assignQuestRepository.findByQuestParticipantIdAndStartDateTimeBetweenAndIsCompletedFalse(targetId, startDate, endDate) - .stream() - .map(CalendarAssignQuestDto::of) - .toList(); - } - return calendars; - } -} diff --git a/src/main/java/com/gomo/app/core/quest/application/usecase/ConfirmAssignQuestUseCase.java b/src/main/java/com/gomo/app/core/quest/application/usecase/ConfirmAssignQuestUseCase.java deleted file mode 100644 index f9b7a1ba..00000000 --- a/src/main/java/com/gomo/app/core/quest/application/usecase/ConfirmAssignQuestUseCase.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.gomo.app.core.quest.application.usecase; - -import java.util.UUID; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.quest.domain.model.assign.AssignQuest; -import com.gomo.app.core.quest.domain.service.AssignQuestService; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -public class ConfirmAssignQuestUseCase { - - private final AssignQuestService assignQuestService; - - @AuditLog(action = "CONFIRM_ASSIGN_QUEST") - public void confirm(UUID accessorId, UUID assignQuestId) { - AssignQuest assignQuest = assignQuestService.find(assignQuestId); - assignQuest.validateAuthority(accessorId); - assignQuest.confirm(); - } -} diff --git a/src/main/java/com/gomo/app/core/quest/application/usecase/DeleteAssignQuestUseCase.java b/src/main/java/com/gomo/app/core/quest/application/usecase/DeleteAssignQuestUseCase.java deleted file mode 100644 index 3cb88fb8..00000000 --- a/src/main/java/com/gomo/app/core/quest/application/usecase/DeleteAssignQuestUseCase.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.gomo.app.core.quest.application.usecase; - -import java.util.UUID; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.quest.domain.model.assign.AssignQuest; -import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; -import com.gomo.app.core.quest.domain.service.AssignQuestService; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -public class DeleteAssignQuestUseCase { - - private final AssignQuestService assignQuestService; - private final AssignQuestRepository assignQuestRepository; - - @AuditLog(action = "DELETE_ASSIGN_QUEST") - public void delete(UUID participantId, UUID assignQuestId) { - AssignQuest assignQuest = assignQuestService.find(assignQuestId); - assignQuest.validateAuthority(participantId); - assignQuest.ensureNotConfirmed(); - assignQuest.ensureNotCompleted(); - assignQuestRepository.delete(assignQuest); - } -} diff --git a/src/main/java/com/gomo/app/core/quest/application/usecase/DeleteRepeatQuestUseCase.java b/src/main/java/com/gomo/app/core/quest/application/usecase/DeleteRepeatQuestUseCase.java deleted file mode 100644 index cd4ccdf4..00000000 --- a/src/main/java/com/gomo/app/core/quest/application/usecase/DeleteRepeatQuestUseCase.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.gomo.app.core.quest.application.usecase; - -import java.util.UUID; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.quest.domain.model.repeat.RepeatQuest; -import com.gomo.app.core.quest.domain.repository.RepeatQuestRepository; -import com.gomo.app.core.quest.domain.service.RepeatQuestService; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -public class DeleteRepeatQuestUseCase { - - private final RepeatQuestService repeatQuestService; - private final RepeatQuestRepository repeatQuestRepository; - - @AuditLog(action = "DELETE_REPEAT_QUEST") - public void delete(UUID participantId, UUID repeatQuestId) { - RepeatQuest repeatQuest = repeatQuestService.find(repeatQuestId); - repeatQuest.validateAuthority(participantId); - repeatQuestRepository.delete(repeatQuest); - } -} diff --git a/src/main/java/com/gomo/app/core/quest/application/usecase/OrderUpdateAssignQuestUseCase.java b/src/main/java/com/gomo/app/core/quest/application/usecase/OrderUpdateAssignQuestUseCase.java deleted file mode 100644 index f5b1d32f..00000000 --- a/src/main/java/com/gomo/app/core/quest/application/usecase/OrderUpdateAssignQuestUseCase.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.gomo.app.core.quest.application.usecase; - -import java.time.LocalDate; -import java.util.Map; -import java.util.UUID; -import java.util.stream.Collectors; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.common.displayorder.OrderChangeable; -import com.gomo.app.common.displayorder.OrderChanger; -import com.gomo.app.common.displayorder.OrderUpdateOrderChangeableCommand; -import com.gomo.app.common.util.DateRangeCalculator; -import com.gomo.app.core.quest.application.port.command.OrderUpdateAssignQuestCommand; -import com.gomo.app.core.quest.domain.model.quest.QuestType; -import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -public class OrderUpdateAssignQuestUseCase { - - private final AssignQuestRepository assignQuestRepository; - - @AuditLog(action = "UPDATE_ASSIGN_QUEST_ORDER") - public void update(OrderUpdateAssignQuestCommand command) { - LocalDate now = LocalDate.now(); - QuestType questType = QuestType.valueOf(command.questType()); - Map assignQuestMap = assignQuestRepository.findParticipatingQuestByQuestTypeWithoutCompleted( - command.participantId(), - questType, - DateRangeCalculator.startOf(now, questType.name()), - DateRangeCalculator.endOf(now, questType.name()) - ).stream().collect(Collectors.toMap( - assignQuest -> assignQuest.getId(), - assignQuest -> assignQuest - )); - OrderChanger.change(OrderUpdateOrderChangeableCommand.of(assignQuestMap, command.updatedOrders())); - } -} diff --git a/src/main/java/com/gomo/app/core/quest/application/usecase/OrderUpdateRepeatQuestUseCase.java b/src/main/java/com/gomo/app/core/quest/application/usecase/OrderUpdateRepeatQuestUseCase.java deleted file mode 100644 index 949091f3..00000000 --- a/src/main/java/com/gomo/app/core/quest/application/usecase/OrderUpdateRepeatQuestUseCase.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.gomo.app.core.quest.application.usecase; - -import java.util.Map; -import java.util.UUID; -import java.util.stream.Collectors; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.common.displayorder.OrderChangeable; -import com.gomo.app.common.displayorder.OrderChanger; -import com.gomo.app.common.displayorder.OrderUpdateOrderChangeableCommand; -import com.gomo.app.core.quest.application.port.command.OrderUpdateRepeatQuestCommand; -import com.gomo.app.core.quest.domain.model.quest.QuestType; -import com.gomo.app.core.quest.domain.repository.RepeatQuestRepository; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -public class OrderUpdateRepeatQuestUseCase { - - private final RepeatQuestRepository repeatQuestRepository; - - @AuditLog(action = "UPDATE_REPEAT_QUEST_ORDER") - public void update(OrderUpdateRepeatQuestCommand command) { - Map repeatQuestMap = repeatQuestRepository.findRepeatQuestsByQuestType( - command.participantId(), - QuestType.valueOf(command.questType()) - ).stream().collect(Collectors.toMap( - repeatQuest -> repeatQuest.getId(), - repeatQuest -> repeatQuest - )); - OrderChanger.change(OrderUpdateOrderChangeableCommand.of(repeatQuestMap, command.updatedOrders())); - } -} diff --git a/src/main/java/com/gomo/app/core/quest/application/usecase/ReadAssignQuestUseCase.java b/src/main/java/com/gomo/app/core/quest/application/usecase/ReadAssignQuestUseCase.java deleted file mode 100644 index 8bdaacdc..00000000 --- a/src/main/java/com/gomo/app/core/quest/application/usecase/ReadAssignQuestUseCase.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.gomo.app.core.quest.application.usecase; - -import java.time.LocalDate; -import java.util.List; -import java.util.UUID; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.common.util.DateRangeCalculator; -import com.gomo.app.core.quest.application.port.dto.AssignQuestDto; -import com.gomo.app.core.quest.application.port.dto.ListAssignQuestDto; -import com.gomo.app.core.quest.domain.model.quest.QuestType; -import com.gomo.app.core.quest.domain.model.reward.QuestReward; -import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; -import com.gomo.app.core.quest.domain.service.QuestRewardService; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -public class ReadAssignQuestUseCase { - - private final QuestRewardService questRewardService; - private final AssignQuestRepository assignQuestRepository; - - public ListAssignQuestDto findAll(UUID participantId) { - List dailyQuests = findAllByQuestType(participantId, QuestType.DAILY); - List weeklyQuests = findAllByQuestType(participantId, QuestType.WEEKLY); - List monthlyQuests = findAllByQuestType(participantId, QuestType.MONTHLY); - return ListAssignQuestDto.of(dailyQuests, weeklyQuests, monthlyQuests); - } - - private List findAllByQuestType(UUID participantId, QuestType questType) { - return assignQuestRepository.findParticipatingQuestByQuestType( - participantId, - questType, - DateRangeCalculator.startOf(LocalDate.now(), questType.name()), - DateRangeCalculator.endOf(LocalDate.now(), questType.name()) - ).stream().map(assignQuest -> { - QuestReward questReward = questRewardService.find(questType); - return AssignQuestDto.from(assignQuest, questReward.pointValue(), questReward.scoreValue()); - }).toList(); - } -} diff --git a/src/main/java/com/gomo/app/core/quest/application/usecase/ReadRepeatQuestUseCase.java b/src/main/java/com/gomo/app/core/quest/application/usecase/ReadRepeatQuestUseCase.java deleted file mode 100644 index 12221e17..00000000 --- a/src/main/java/com/gomo/app/core/quest/application/usecase/ReadRepeatQuestUseCase.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.gomo.app.core.quest.application.usecase; - -import java.util.List; -import java.util.UUID; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.quest.application.port.dto.ListRepeatQuestDto; -import com.gomo.app.core.quest.application.port.dto.RepeatQuestDto; -import com.gomo.app.core.quest.domain.model.quest.QuestType; -import com.gomo.app.core.quest.domain.model.reward.QuestReward; -import com.gomo.app.core.quest.domain.repository.RepeatQuestRepository; -import com.gomo.app.core.quest.domain.service.QuestRewardService; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -public class ReadRepeatQuestUseCase { - - private final QuestRewardService questRewardService; - private final RepeatQuestRepository repeatQuestRepository; - - public ListRepeatQuestDto findAll(UUID participantId) { - List dailyRepeatQuests = findRepeatQuestResponses(participantId, QuestType.DAILY); - List weeklyRepeatQuests = findRepeatQuestResponses(participantId, QuestType.WEEKLY); - List monthlyRepeatQuests = findRepeatQuestResponses(participantId, QuestType.MONTHLY); - return ListRepeatQuestDto.of(dailyRepeatQuests, weeklyRepeatQuests, monthlyRepeatQuests); - } - - private List findRepeatQuestResponses(UUID participantId, QuestType questType) { - return repeatQuestRepository.findRepeatQuestsByQuestType(participantId, questType).stream() - .map(assignQuest -> { - QuestReward questReward = questRewardService.find(questType); - return RepeatQuestDto.from(assignQuest, questReward.pointValue(), questReward.scoreValue()); - }).toList(); - } -} diff --git a/src/main/java/com/gomo/app/core/quest/application/usecase/UpdateAssignQuestUseCase.java b/src/main/java/com/gomo/app/core/quest/application/usecase/UpdateAssignQuestUseCase.java deleted file mode 100644 index 741d6c26..00000000 --- a/src/main/java/com/gomo/app/core/quest/application/usecase/UpdateAssignQuestUseCase.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.gomo.app.core.quest.application.usecase; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.quest.application.port.command.UpdateAssignQuestCommand; -import com.gomo.app.core.quest.domain.model.assign.AssignQuest; -import com.gomo.app.core.quest.domain.model.quest.QuestContent; -import com.gomo.app.core.quest.domain.model.quest.QuestType; -import com.gomo.app.core.quest.domain.model.subject.SubjectName; -import com.gomo.app.core.quest.domain.service.AssignQuestService; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -public class UpdateAssignQuestUseCase { - - private final AssignQuestService assignQuestService; - - @AuditLog(action = "UPDATE_ASSIGN_QUEST") - public void update(UpdateAssignQuestCommand command) { - AssignQuest assignQuest = assignQuestService.find(command.assignQuestId()); - assignQuest.validateAuthority(command.participantId()); - - QuestType requestedQuestType = QuestType.valueOf(command.questType()); - assignQuest.ensureSameQuestType(requestedQuestType); - assignQuest.ensureNotConfirmed(); - assignQuest.ensureNotCompleted(); - - assignQuest.updateQuest( - command.subjectId(), - SubjectName.of(command.subjectName()), - requestedQuestType, - QuestContent.of(command.content()) - ); - } -} diff --git a/src/main/java/com/gomo/app/core/quest/application/usecase/UpdateRepeatQuestUseCase.java b/src/main/java/com/gomo/app/core/quest/application/usecase/UpdateRepeatQuestUseCase.java deleted file mode 100644 index 36fa292b..00000000 --- a/src/main/java/com/gomo/app/core/quest/application/usecase/UpdateRepeatQuestUseCase.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.gomo.app.core.quest.application.usecase; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.quest.application.port.command.UpdateRepeatQuestCommand; -import com.gomo.app.core.quest.domain.model.quest.QuestContent; -import com.gomo.app.core.quest.domain.model.quest.QuestType; -import com.gomo.app.core.quest.domain.model.repeat.RepeatQuest; -import com.gomo.app.core.quest.domain.model.subject.SubjectName; -import com.gomo.app.core.quest.domain.service.RepeatQuestService; -import com.gomo.app.core.quest.exception.QuestTypeConstraintViolationException; -import com.gomo.app.core.quest.exception.code.QuestTypeErrorCode; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -public class UpdateRepeatQuestUseCase { - - private final RepeatQuestService repeatQuestService; - - @AuditLog(action = "UPDATE_REPEAT_QUEST") - public void update(UpdateRepeatQuestCommand command) { - RepeatQuest repeatQuest = repeatQuestService.find(command.repeatQuestId()); - repeatQuest.validateAuthority(command.participantId()); - QuestType requestedQuestType = QuestType.valueOf(command.questType()); - ensureSameQuestType(repeatQuest, requestedQuestType); - - repeatQuest.updateQuest( - command.subjectId(), - SubjectName.of(command.subjectName()), - requestedQuestType, - QuestContent.of(command.content()) - ); - } - - private void ensureSameQuestType(RepeatQuest repeatQuest, QuestType questType) { - if (!repeatQuest.isSameQuestType(questType)) { - throw new QuestTypeConstraintViolationException(QuestTypeErrorCode.MISMATCHED); - } - } -} diff --git a/src/main/java/com/gomo/app/core/quest/event/CompleteQuestEvent.java b/src/main/java/com/gomo/app/core/quest/domain/event/CompleteQuestEvent.java similarity index 94% rename from src/main/java/com/gomo/app/core/quest/event/CompleteQuestEvent.java rename to src/main/java/com/gomo/app/core/quest/domain/event/CompleteQuestEvent.java index 72212308..f664e21d 100644 --- a/src/main/java/com/gomo/app/core/quest/event/CompleteQuestEvent.java +++ b/src/main/java/com/gomo/app/core/quest/domain/event/CompleteQuestEvent.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.event; +package com.gomo.app.core.quest.domain.event; import java.time.LocalDateTime; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/quest/event/CreateQuestPoolEvent.java b/src/main/java/com/gomo/app/core/quest/domain/event/CreateQuestPoolEvent.java similarity index 94% rename from src/main/java/com/gomo/app/core/quest/event/CreateQuestPoolEvent.java rename to src/main/java/com/gomo/app/core/quest/domain/event/CreateQuestPoolEvent.java index 8f1602c2..9aedd81d 100644 --- a/src/main/java/com/gomo/app/core/quest/event/CreateQuestPoolEvent.java +++ b/src/main/java/com/gomo/app/core/quest/domain/event/CreateQuestPoolEvent.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.event; +package com.gomo.app.core.quest.domain.event; import java.util.List; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/quest/exception/AssignQuestAccessDeniedException.java b/src/main/java/com/gomo/app/core/quest/domain/exception/AssignQuestAccessDeniedException.java similarity index 77% rename from src/main/java/com/gomo/app/core/quest/exception/AssignQuestAccessDeniedException.java rename to src/main/java/com/gomo/app/core/quest/domain/exception/AssignQuestAccessDeniedException.java index 8c166a8f..52bf2063 100644 --- a/src/main/java/com/gomo/app/core/quest/exception/AssignQuestAccessDeniedException.java +++ b/src/main/java/com/gomo/app/core/quest/domain/exception/AssignQuestAccessDeniedException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.quest.exception; +package com.gomo.app.core.quest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.quest.exception.code.AssignQuestErrorCode; +import com.gomo.app.core.quest.domain.exception.code.AssignQuestErrorCode; public class AssignQuestAccessDeniedException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/quest/exception/AssignQuestConstraintViolationException.java b/src/main/java/com/gomo/app/core/quest/domain/exception/AssignQuestConstraintViolationException.java similarity index 78% rename from src/main/java/com/gomo/app/core/quest/exception/AssignQuestConstraintViolationException.java rename to src/main/java/com/gomo/app/core/quest/domain/exception/AssignQuestConstraintViolationException.java index 15ded844..f2ae1844 100644 --- a/src/main/java/com/gomo/app/core/quest/exception/AssignQuestConstraintViolationException.java +++ b/src/main/java/com/gomo/app/core/quest/domain/exception/AssignQuestConstraintViolationException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.quest.exception; +package com.gomo.app.core.quest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.quest.exception.code.AssignQuestErrorCode; +import com.gomo.app.core.quest.domain.exception.code.AssignQuestErrorCode; public class AssignQuestConstraintViolationException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/quest/exception/AssignQuestNotFoundException.java b/src/main/java/com/gomo/app/core/quest/domain/exception/AssignQuestNotFoundException.java similarity index 77% rename from src/main/java/com/gomo/app/core/quest/exception/AssignQuestNotFoundException.java rename to src/main/java/com/gomo/app/core/quest/domain/exception/AssignQuestNotFoundException.java index 5866cf71..f654caa0 100644 --- a/src/main/java/com/gomo/app/core/quest/exception/AssignQuestNotFoundException.java +++ b/src/main/java/com/gomo/app/core/quest/domain/exception/AssignQuestNotFoundException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.quest.exception; +package com.gomo.app.core.quest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.quest.exception.code.AssignQuestErrorCode; +import com.gomo.app.core.quest.domain.exception.code.AssignQuestErrorCode; public class AssignQuestNotFoundException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/quest/exception/CompletionProofConstraintViolationException.java b/src/main/java/com/gomo/app/core/quest/domain/exception/CompletionProofConstraintViolationException.java similarity index 78% rename from src/main/java/com/gomo/app/core/quest/exception/CompletionProofConstraintViolationException.java rename to src/main/java/com/gomo/app/core/quest/domain/exception/CompletionProofConstraintViolationException.java index dc88cb5d..4f248fee 100644 --- a/src/main/java/com/gomo/app/core/quest/exception/CompletionProofConstraintViolationException.java +++ b/src/main/java/com/gomo/app/core/quest/domain/exception/CompletionProofConstraintViolationException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.quest.exception; +package com.gomo.app.core.quest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.quest.exception.code.CompletionProofErrorCode; +import com.gomo.app.core.quest.domain.exception.code.CompletionProofErrorCode; public class CompletionProofConstraintViolationException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/quest/exception/InvalidPeriodTypeException.java b/src/main/java/com/gomo/app/core/quest/domain/exception/InvalidPeriodTypeException.java similarity index 77% rename from src/main/java/com/gomo/app/core/quest/exception/InvalidPeriodTypeException.java rename to src/main/java/com/gomo/app/core/quest/domain/exception/InvalidPeriodTypeException.java index 06a77eac..e08e174c 100644 --- a/src/main/java/com/gomo/app/core/quest/exception/InvalidPeriodTypeException.java +++ b/src/main/java/com/gomo/app/core/quest/domain/exception/InvalidPeriodTypeException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.quest.exception; +package com.gomo.app.core.quest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.quest.exception.code.AssignQuestErrorCode; +import com.gomo.app.core.quest.domain.exception.code.AssignQuestErrorCode; public class InvalidPeriodTypeException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/quest/exception/QuestAccessDeniedException.java b/src/main/java/com/gomo/app/core/quest/domain/exception/QuestAccessDeniedException.java similarity index 77% rename from src/main/java/com/gomo/app/core/quest/exception/QuestAccessDeniedException.java rename to src/main/java/com/gomo/app/core/quest/domain/exception/QuestAccessDeniedException.java index ac7c2193..8a8eedb2 100644 --- a/src/main/java/com/gomo/app/core/quest/exception/QuestAccessDeniedException.java +++ b/src/main/java/com/gomo/app/core/quest/domain/exception/QuestAccessDeniedException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.quest.exception; +package com.gomo.app.core.quest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.quest.exception.code.QuestErrorCode; +import com.gomo.app.core.quest.domain.exception.code.QuestErrorCode; public class QuestAccessDeniedException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/quest/exception/QuestConstraintViolationException.java b/src/main/java/com/gomo/app/core/quest/domain/exception/QuestConstraintViolationException.java similarity index 78% rename from src/main/java/com/gomo/app/core/quest/exception/QuestConstraintViolationException.java rename to src/main/java/com/gomo/app/core/quest/domain/exception/QuestConstraintViolationException.java index a66797c6..48ab8772 100644 --- a/src/main/java/com/gomo/app/core/quest/exception/QuestConstraintViolationException.java +++ b/src/main/java/com/gomo/app/core/quest/domain/exception/QuestConstraintViolationException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.quest.exception; +package com.gomo.app.core.quest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.quest.exception.code.QuestErrorCode; +import com.gomo.app.core.quest.domain.exception.code.QuestErrorCode; public class QuestConstraintViolationException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/quest/exception/QuestContentConstraintViolationException.java b/src/main/java/com/gomo/app/core/quest/domain/exception/QuestContentConstraintViolationException.java similarity index 78% rename from src/main/java/com/gomo/app/core/quest/exception/QuestContentConstraintViolationException.java rename to src/main/java/com/gomo/app/core/quest/domain/exception/QuestContentConstraintViolationException.java index e8187f1a..8180252e 100644 --- a/src/main/java/com/gomo/app/core/quest/exception/QuestContentConstraintViolationException.java +++ b/src/main/java/com/gomo/app/core/quest/domain/exception/QuestContentConstraintViolationException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.quest.exception; +package com.gomo.app.core.quest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.quest.exception.code.QuestContentErrorCode; +import com.gomo.app.core.quest.domain.exception.code.QuestContentErrorCode; public class QuestContentConstraintViolationException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/quest/exception/QuestPoolNotFoundException.java b/src/main/java/com/gomo/app/core/quest/domain/exception/QuestPoolNotFoundException.java similarity index 77% rename from src/main/java/com/gomo/app/core/quest/exception/QuestPoolNotFoundException.java rename to src/main/java/com/gomo/app/core/quest/domain/exception/QuestPoolNotFoundException.java index 76dbb7e2..d51649fe 100644 --- a/src/main/java/com/gomo/app/core/quest/exception/QuestPoolNotFoundException.java +++ b/src/main/java/com/gomo/app/core/quest/domain/exception/QuestPoolNotFoundException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.quest.exception; +package com.gomo.app.core.quest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.quest.exception.code.QuestPoolErrorCode; +import com.gomo.app.core.quest.domain.exception.code.QuestPoolErrorCode; public class QuestPoolNotFoundException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/quest/exception/QuestTypeConstraintViolationException.java b/src/main/java/com/gomo/app/core/quest/domain/exception/QuestTypeConstraintViolationException.java similarity index 78% rename from src/main/java/com/gomo/app/core/quest/exception/QuestTypeConstraintViolationException.java rename to src/main/java/com/gomo/app/core/quest/domain/exception/QuestTypeConstraintViolationException.java index 50f2c533..47b4be07 100644 --- a/src/main/java/com/gomo/app/core/quest/exception/QuestTypeConstraintViolationException.java +++ b/src/main/java/com/gomo/app/core/quest/domain/exception/QuestTypeConstraintViolationException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.quest.exception; +package com.gomo.app.core.quest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.quest.exception.code.QuestTypeErrorCode; +import com.gomo.app.core.quest.domain.exception.code.QuestTypeErrorCode; public class QuestTypeConstraintViolationException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/quest/exception/RepeatQuestAccessDeniedException.java b/src/main/java/com/gomo/app/core/quest/domain/exception/RepeatQuestAccessDeniedException.java similarity index 77% rename from src/main/java/com/gomo/app/core/quest/exception/RepeatQuestAccessDeniedException.java rename to src/main/java/com/gomo/app/core/quest/domain/exception/RepeatQuestAccessDeniedException.java index 42b7ed40..ccb93661 100644 --- a/src/main/java/com/gomo/app/core/quest/exception/RepeatQuestAccessDeniedException.java +++ b/src/main/java/com/gomo/app/core/quest/domain/exception/RepeatQuestAccessDeniedException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.quest.exception; +package com.gomo.app.core.quest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.quest.exception.code.RepeatQuestErrorCode; +import com.gomo.app.core.quest.domain.exception.code.RepeatQuestErrorCode; public class RepeatQuestAccessDeniedException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/quest/exception/RepeatQuestNotFoundException.java b/src/main/java/com/gomo/app/core/quest/domain/exception/RepeatQuestNotFoundException.java similarity index 77% rename from src/main/java/com/gomo/app/core/quest/exception/RepeatQuestNotFoundException.java rename to src/main/java/com/gomo/app/core/quest/domain/exception/RepeatQuestNotFoundException.java index be79f11c..05c00b39 100644 --- a/src/main/java/com/gomo/app/core/quest/exception/RepeatQuestNotFoundException.java +++ b/src/main/java/com/gomo/app/core/quest/domain/exception/RepeatQuestNotFoundException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.quest.exception; +package com.gomo.app.core.quest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.quest.exception.code.RepeatQuestErrorCode; +import com.gomo.app.core.quest.domain.exception.code.RepeatQuestErrorCode; public class RepeatQuestNotFoundException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/quest/exception/RepeatQuestThresholdExceededException.java b/src/main/java/com/gomo/app/core/quest/domain/exception/RepeatQuestThresholdExceededException.java similarity index 78% rename from src/main/java/com/gomo/app/core/quest/exception/RepeatQuestThresholdExceededException.java rename to src/main/java/com/gomo/app/core/quest/domain/exception/RepeatQuestThresholdExceededException.java index ed4d54f4..b93ae49c 100644 --- a/src/main/java/com/gomo/app/core/quest/exception/RepeatQuestThresholdExceededException.java +++ b/src/main/java/com/gomo/app/core/quest/domain/exception/RepeatQuestThresholdExceededException.java @@ -1,7 +1,7 @@ -package com.gomo.app.core.quest.exception; +package com.gomo.app.core.quest.domain.exception; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.quest.exception.code.RepeatQuestErrorCode; +import com.gomo.app.core.quest.domain.exception.code.RepeatQuestErrorCode; public class RepeatQuestThresholdExceededException extends ApplicationException { diff --git a/src/main/java/com/gomo/app/core/quest/exception/code/AssignQuestErrorCode.java b/src/main/java/com/gomo/app/core/quest/domain/exception/code/AssignQuestErrorCode.java similarity index 91% rename from src/main/java/com/gomo/app/core/quest/exception/code/AssignQuestErrorCode.java rename to src/main/java/com/gomo/app/core/quest/domain/exception/code/AssignQuestErrorCode.java index 7936ec7a..c479dee0 100644 --- a/src/main/java/com/gomo/app/core/quest/exception/code/AssignQuestErrorCode.java +++ b/src/main/java/com/gomo/app/core/quest/domain/exception/code/AssignQuestErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.exception.code; +package com.gomo.app.core.quest.domain.exception.code; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/quest/exception/code/CompletionProofErrorCode.java b/src/main/java/com/gomo/app/core/quest/domain/exception/code/CompletionProofErrorCode.java similarity index 86% rename from src/main/java/com/gomo/app/core/quest/exception/code/CompletionProofErrorCode.java rename to src/main/java/com/gomo/app/core/quest/domain/exception/code/CompletionProofErrorCode.java index ec299ea3..8ed51fd5 100644 --- a/src/main/java/com/gomo/app/core/quest/exception/code/CompletionProofErrorCode.java +++ b/src/main/java/com/gomo/app/core/quest/domain/exception/code/CompletionProofErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.exception.code; +package com.gomo.app.core.quest.domain.exception.code; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/quest/exception/code/QuestContentErrorCode.java b/src/main/java/com/gomo/app/core/quest/domain/exception/code/QuestContentErrorCode.java similarity index 89% rename from src/main/java/com/gomo/app/core/quest/exception/code/QuestContentErrorCode.java rename to src/main/java/com/gomo/app/core/quest/domain/exception/code/QuestContentErrorCode.java index 8c40ca1c..e73471e1 100644 --- a/src/main/java/com/gomo/app/core/quest/exception/code/QuestContentErrorCode.java +++ b/src/main/java/com/gomo/app/core/quest/domain/exception/code/QuestContentErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.exception.code; +package com.gomo.app.core.quest.domain.exception.code; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/quest/exception/code/QuestErrorCode.java b/src/main/java/com/gomo/app/core/quest/domain/exception/code/QuestErrorCode.java similarity index 85% rename from src/main/java/com/gomo/app/core/quest/exception/code/QuestErrorCode.java rename to src/main/java/com/gomo/app/core/quest/domain/exception/code/QuestErrorCode.java index 92337844..24c76a77 100644 --- a/src/main/java/com/gomo/app/core/quest/exception/code/QuestErrorCode.java +++ b/src/main/java/com/gomo/app/core/quest/domain/exception/code/QuestErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.exception.code; +package com.gomo.app.core.quest.domain.exception.code; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/quest/exception/code/QuestPoolErrorCode.java b/src/main/java/com/gomo/app/core/quest/domain/exception/code/QuestPoolErrorCode.java similarity index 83% rename from src/main/java/com/gomo/app/core/quest/exception/code/QuestPoolErrorCode.java rename to src/main/java/com/gomo/app/core/quest/domain/exception/code/QuestPoolErrorCode.java index 8d372032..9af5010a 100644 --- a/src/main/java/com/gomo/app/core/quest/exception/code/QuestPoolErrorCode.java +++ b/src/main/java/com/gomo/app/core/quest/domain/exception/code/QuestPoolErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.exception.code; +package com.gomo.app.core.quest.domain.exception.code; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/quest/exception/code/QuestTypeErrorCode.java b/src/main/java/com/gomo/app/core/quest/domain/exception/code/QuestTypeErrorCode.java similarity index 86% rename from src/main/java/com/gomo/app/core/quest/exception/code/QuestTypeErrorCode.java rename to src/main/java/com/gomo/app/core/quest/domain/exception/code/QuestTypeErrorCode.java index 35cbb315..793fa602 100644 --- a/src/main/java/com/gomo/app/core/quest/exception/code/QuestTypeErrorCode.java +++ b/src/main/java/com/gomo/app/core/quest/domain/exception/code/QuestTypeErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.exception.code; +package com.gomo.app.core.quest.domain.exception.code; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/quest/exception/code/RepeatQuestErrorCode.java b/src/main/java/com/gomo/app/core/quest/domain/exception/code/RepeatQuestErrorCode.java similarity index 86% rename from src/main/java/com/gomo/app/core/quest/exception/code/RepeatQuestErrorCode.java rename to src/main/java/com/gomo/app/core/quest/domain/exception/code/RepeatQuestErrorCode.java index c7ee248f..dcf96bd0 100644 --- a/src/main/java/com/gomo/app/core/quest/exception/code/RepeatQuestErrorCode.java +++ b/src/main/java/com/gomo/app/core/quest/domain/exception/code/RepeatQuestErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.exception.code; +package com.gomo.app.core.quest.domain.exception.code; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/quest/domain/model/assign/AssignQuest.java b/src/main/java/com/gomo/app/core/quest/domain/model/assign/AssignQuest.java index 9f783a30..c57abfb6 100644 --- a/src/main/java/com/gomo/app/core/quest/domain/model/assign/AssignQuest.java +++ b/src/main/java/com/gomo/app/core/quest/domain/model/assign/AssignQuest.java @@ -11,11 +11,11 @@ import com.gomo.app.core.quest.domain.model.quest.QuestContent; import com.gomo.app.core.quest.domain.model.quest.QuestType; import com.gomo.app.core.quest.domain.model.subject.SubjectName; -import com.gomo.app.core.quest.exception.AssignQuestAccessDeniedException; -import com.gomo.app.core.quest.exception.AssignQuestConstraintViolationException; -import com.gomo.app.core.quest.exception.QuestTypeConstraintViolationException; -import com.gomo.app.core.quest.exception.code.AssignQuestErrorCode; -import com.gomo.app.core.quest.exception.code.QuestTypeErrorCode; +import com.gomo.app.core.quest.domain.exception.AssignQuestAccessDeniedException; +import com.gomo.app.core.quest.domain.exception.AssignQuestConstraintViolationException; +import com.gomo.app.core.quest.domain.exception.QuestTypeConstraintViolationException; +import com.gomo.app.core.quest.domain.exception.code.AssignQuestErrorCode; +import com.gomo.app.core.quest.domain.exception.code.QuestTypeErrorCode; import jakarta.persistence.AttributeOverride; import jakarta.persistence.AttributeOverrides; diff --git a/src/main/java/com/gomo/app/core/quest/domain/model/assign/CompletionProof.java b/src/main/java/com/gomo/app/core/quest/domain/model/assign/CompletionProof.java index b3e78c6f..00fcfcc3 100644 --- a/src/main/java/com/gomo/app/core/quest/domain/model/assign/CompletionProof.java +++ b/src/main/java/com/gomo/app/core/quest/domain/model/assign/CompletionProof.java @@ -3,8 +3,8 @@ import java.util.Objects; import com.gomo.app.common.arch.ValueObject; -import com.gomo.app.core.quest.exception.CompletionProofConstraintViolationException; -import com.gomo.app.core.quest.exception.code.CompletionProofErrorCode; +import com.gomo.app.core.quest.domain.exception.CompletionProofConstraintViolationException; +import com.gomo.app.core.quest.domain.exception.code.CompletionProofErrorCode; import jakarta.persistence.Embeddable; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/quest/domain/model/participant/Participant.java b/src/main/java/com/gomo/app/core/quest/domain/model/participant/Participant.java index c3bb6c95..955b3bc9 100644 --- a/src/main/java/com/gomo/app/core/quest/domain/model/participant/Participant.java +++ b/src/main/java/com/gomo/app/core/quest/domain/model/participant/Participant.java @@ -4,8 +4,8 @@ import com.gomo.app.common.arch.ValueObject; import com.gomo.app.core.quest.domain.model.quest.QuestType; -import com.gomo.app.core.quest.exception.QuestConstraintViolationException; -import com.gomo.app.core.quest.exception.code.QuestErrorCode; +import com.gomo.app.core.quest.domain.exception.QuestConstraintViolationException; +import com.gomo.app.core.quest.domain.exception.code.QuestErrorCode; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/quest/domain/model/pool/QuestPool.java b/src/main/java/com/gomo/app/core/quest/domain/model/pool/QuestPool.java index 179b0207..eac23e4d 100644 --- a/src/main/java/com/gomo/app/core/quest/domain/model/pool/QuestPool.java +++ b/src/main/java/com/gomo/app/core/quest/domain/model/pool/QuestPool.java @@ -9,8 +9,8 @@ import com.gomo.app.common.util.UUIDGenerator; import com.gomo.app.core.quest.domain.model.assign.AssignQuest; import com.gomo.app.core.quest.domain.model.quest.Quest; -import com.gomo.app.core.quest.exception.QuestAccessDeniedException; -import com.gomo.app.core.quest.exception.code.QuestErrorCode; +import com.gomo.app.core.quest.domain.exception.QuestAccessDeniedException; +import com.gomo.app.core.quest.domain.exception.code.QuestErrorCode; import jakarta.persistence.AttributeOverride; import jakarta.persistence.AttributeOverrides; diff --git a/src/main/java/com/gomo/app/core/quest/domain/model/quest/QuestContent.java b/src/main/java/com/gomo/app/core/quest/domain/model/quest/QuestContent.java index fb654115..92057e43 100644 --- a/src/main/java/com/gomo/app/core/quest/domain/model/quest/QuestContent.java +++ b/src/main/java/com/gomo/app/core/quest/domain/model/quest/QuestContent.java @@ -3,8 +3,8 @@ import java.util.regex.Pattern; import com.gomo.app.common.arch.ValueObject; -import com.gomo.app.core.quest.exception.QuestContentConstraintViolationException; -import com.gomo.app.core.quest.exception.code.QuestContentErrorCode; +import com.gomo.app.core.quest.domain.exception.QuestContentConstraintViolationException; +import com.gomo.app.core.quest.domain.exception.code.QuestContentErrorCode; import jakarta.persistence.Embeddable; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/quest/domain/model/repeat/RepeatQuest.java b/src/main/java/com/gomo/app/core/quest/domain/model/repeat/RepeatQuest.java index 50d41003..29e5f871 100644 --- a/src/main/java/com/gomo/app/core/quest/domain/model/repeat/RepeatQuest.java +++ b/src/main/java/com/gomo/app/core/quest/domain/model/repeat/RepeatQuest.java @@ -13,8 +13,8 @@ import com.gomo.app.core.quest.domain.model.quest.QuestContent; import com.gomo.app.core.quest.domain.model.quest.QuestType; import com.gomo.app.core.quest.domain.model.subject.SubjectName; -import com.gomo.app.core.quest.exception.RepeatQuestAccessDeniedException; -import com.gomo.app.core.quest.exception.code.RepeatQuestErrorCode; +import com.gomo.app.core.quest.domain.exception.RepeatQuestAccessDeniedException; +import com.gomo.app.core.quest.domain.exception.code.RepeatQuestErrorCode; import jakarta.persistence.AttributeOverride; import jakarta.persistence.AttributeOverrides; diff --git a/src/main/java/com/gomo/app/core/quest/domain/service/AssignQuestService.java b/src/main/java/com/gomo/app/core/quest/domain/service/AssignQuestService.java deleted file mode 100644 index 29ae834d..00000000 --- a/src/main/java/com/gomo/app/core/quest/domain/service/AssignQuestService.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.gomo.app.core.quest.domain.service; - -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.util.UUID; - -import org.jetbrains.annotations.NotNull; - -import com.gomo.app.common.arch.DomainService; -import com.gomo.app.common.displayorder.DisplayOrder; -import com.gomo.app.common.util.DateRangeCalculator; -import com.gomo.app.common.util.UUIDGenerator; -import com.gomo.app.core.quest.domain.model.assign.AssignQuest; -import com.gomo.app.core.quest.domain.model.quest.Quest; -import com.gomo.app.core.quest.domain.model.quest.QuestType; -import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; -import com.gomo.app.core.quest.exception.AssignQuestNotFoundException; -import com.gomo.app.core.quest.exception.code.AssignQuestErrorCode; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@DomainService -public class AssignQuestService { - - private final AssignQuestRepository assignQuestRepository; - - public AssignQuest create(UUID participantId, Quest quest) { - int displayOrder = findMaxDisplayOrderOfParticipatingQuest(participantId, quest.getType()) + 1; - return assignQuestRepository.save(createAssignQuest(quest, displayOrder)); - } - - public AssignQuest find(UUID assignQuestId) { - return assignQuestRepository.findById(assignQuestId) - .orElseThrow(() -> new AssignQuestNotFoundException(AssignQuestErrorCode.NOT_FOUND)); - } - - @NotNull - private AssignQuest createAssignQuest(Quest quest, int displayOrder) { - return AssignQuest.of( - UUIDGenerator.generate(), - quest, - false, - DisplayOrder.of(displayOrder), - LocalDateTime.now() - ); - } - - private int findMaxDisplayOrderOfParticipatingQuest(UUID participantId, QuestType questType) { - LocalDate now = LocalDate.now(); - LocalDateTime startDateTime = DateRangeCalculator.startOf(now, questType.name()); - LocalDateTime endDateTime = DateRangeCalculator.endOf(now, questType.name()); - - return assignQuestRepository.findMaxDisplayOrderOfParticipatingQuest( - participantId, - questType, - startDateTime, - endDateTime - ); - } -} diff --git a/src/main/java/com/gomo/app/core/quest/domain/service/QuestRewardService.java b/src/main/java/com/gomo/app/core/quest/domain/service/QuestRewardProvider.java similarity index 89% rename from src/main/java/com/gomo/app/core/quest/domain/service/QuestRewardService.java rename to src/main/java/com/gomo/app/core/quest/domain/service/QuestRewardProvider.java index ecd07972..f51803de 100644 --- a/src/main/java/com/gomo/app/core/quest/domain/service/QuestRewardService.java +++ b/src/main/java/com/gomo/app/core/quest/domain/service/QuestRewardProvider.java @@ -15,7 +15,7 @@ @RequiredArgsConstructor @DomainService -public class QuestRewardService { +public class QuestRewardProvider { private Map rewardMap; private final QuestRewardPolicyRepository questRewardPolicyRepository; @@ -26,7 +26,7 @@ protected void initializeCaches() { .collect(Collectors.toMap(QuestRewardPolicy::questType, Function.identity())); } - public QuestReward find(QuestType questType) { + public QuestReward provide(QuestType questType) { if (rewardMap.containsKey(questType)) { return rewardMap.get(questType).questReward(); } diff --git a/src/main/java/com/gomo/app/core/quest/domain/service/RepeatQuestService.java b/src/main/java/com/gomo/app/core/quest/domain/service/RepeatQuestService.java deleted file mode 100644 index 6f166c2c..00000000 --- a/src/main/java/com/gomo/app/core/quest/domain/service/RepeatQuestService.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.gomo.app.core.quest.domain.service; - -import java.util.UUID; - -import org.jetbrains.annotations.NotNull; - -import com.gomo.app.common.arch.DomainService; -import com.gomo.app.common.displayorder.DisplayOrder; -import com.gomo.app.common.util.UUIDGenerator; -import com.gomo.app.core.quest.domain.model.quest.Quest; -import com.gomo.app.core.quest.domain.model.repeat.RepeatQuest; -import com.gomo.app.core.quest.domain.repository.RepeatQuestRepository; -import com.gomo.app.core.quest.exception.RepeatQuestNotFoundException; -import com.gomo.app.core.quest.exception.code.RepeatQuestErrorCode; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@DomainService -public class RepeatQuestService { - - private final RepeatQuestRepository repeatQuestRepository; - - public RepeatQuest create(UUID participantId, Quest quest) { - int displayOrder = repeatQuestRepository.findMaxDisplayOrderByQuestType(participantId, quest.getType()) + 1; - return repeatQuestRepository.save(createRepeatQuest(quest, displayOrder)); - } - - public RepeatQuest find(UUID repeatQuestId) { - return repeatQuestRepository.findById(repeatQuestId) - .orElseThrow(() -> new RepeatQuestNotFoundException(RepeatQuestErrorCode.NOT_FOUND)); - } - - @NotNull - private RepeatQuest createRepeatQuest(Quest quest, int displayOrder) { - return RepeatQuest.of(UUIDGenerator.generate(), quest, DisplayOrder.of(displayOrder)); - } -} diff --git a/src/main/java/com/gomo/app/core/quest/infrastructure/adapter/ReadSubjectAdapter.java b/src/main/java/com/gomo/app/core/quest/infrastructure/adapter/ReadSubjectAdapter.java deleted file mode 100644 index c922a875..00000000 --- a/src/main/java/com/gomo/app/core/quest/infrastructure/adapter/ReadSubjectAdapter.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.gomo.app.core.quest.infrastructure.adapter; - -import java.util.List; -import java.util.Set; -import java.util.UUID; - -import com.gomo.app.common.arch.Adapter; -import com.gomo.app.core.interest.application.port.ReadInterestPortIn; -import com.gomo.app.core.quest.application.port.ReadSubjectPortOut; -import com.gomo.app.core.quest.application.port.dto.SubjectDto; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Adapter -class ReadSubjectAdapter implements ReadSubjectPortOut { - - private final ReadInterestPortIn readInterestPortIn; - - @Override - public List findAll(UUID participantId) { - return readInterestPortIn.findAll(participantId).stream() - .map(dto -> SubjectDto.of( - dto.id(), - dto.registrantId(), - dto.name(), - dto.proficiency().level() - )).toList(); - } - - @Override - public List findAllByParticipantIds(Set participantIds) { - return readInterestPortIn.findAllByRegistrantIds(participantIds).stream() - .map(dto -> SubjectDto.of( - dto.id(), - dto.registrantId(), - dto.name(), - dto.proficiency().level() - )).toList(); - } -} diff --git a/src/main/java/com/gomo/app/core/quest/presentation/api/AssignQuestApi.java b/src/main/java/com/gomo/app/core/quest/presentation/api/AssignQuestApi.java deleted file mode 100644 index 1fa97c30..00000000 --- a/src/main/java/com/gomo/app/core/quest/presentation/api/AssignQuestApi.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.gomo.app.core.quest.presentation.api; - -import static org.springframework.http.HttpStatus.*; - -import java.util.UUID; - -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; - -import com.gomo.app.common.arch.CoreApi; -import com.gomo.app.core.quest.application.port.dto.ListAssignQuestDto; -import com.gomo.app.core.quest.application.usecase.CreateAssignQuestUseCase; -import com.gomo.app.core.quest.application.usecase.DeleteAssignQuestUseCase; -import com.gomo.app.core.quest.application.usecase.ReadAssignQuestUseCase; -import com.gomo.app.core.quest.application.usecase.UpdateAssignQuestUseCase; -import com.gomo.app.core.quest.presentation.api.request.CreateAssignQuestRequest; -import com.gomo.app.core.quest.presentation.api.request.UpdateAssignQuestRequest; -import com.gomo.app.core.quest.presentation.api.response.CreateAssignQuestResponse; -import com.gomo.app.core.quest.presentation.api.response.ListAssignQuestResponse; -import com.gomo.app.support.auth.presentation.security.Auth; -import com.gomo.app.support.auth.presentation.security.AuthInfo; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@RequestMapping("/quests/assigns") -@CoreApi -public class AssignQuestApi { - - private final CreateAssignQuestUseCase createAssignQuestUseCase; - private final ReadAssignQuestUseCase readAssignQuestUseCase; - private final UpdateAssignQuestUseCase updateAssignQuestUseCase; - private final DeleteAssignQuestUseCase deleteAssignQuestUseCase; - - @PostMapping - public ResponseEntity create(@Auth AuthInfo authInfo, @RequestBody CreateAssignQuestRequest request) { - UUID assignQuestId = createAssignQuestUseCase.create(request.toCommand(authInfo.getMemberId())); - return ResponseEntity.status(CREATED).body(CreateAssignQuestResponse.of(assignQuestId)); - } - - @GetMapping - public ResponseEntity findAll(@Auth AuthInfo authInfo) { - ListAssignQuestDto dto = readAssignQuestUseCase.findAll(authInfo.getMemberId()); - return ResponseEntity.ok(ListAssignQuestResponse.from(dto)); - } - - @PutMapping("/{id}") - public ResponseEntity update(@Auth AuthInfo authInfo, @PathVariable("id") UUID assignQuestId, @RequestBody UpdateAssignQuestRequest request) { - updateAssignQuestUseCase.update(request.toCommand(authInfo.getMemberId(), assignQuestId)); - return ResponseEntity.noContent().build(); - } - - @DeleteMapping("/{id}") - public ResponseEntity delete(@Auth AuthInfo authInfo, @PathVariable("id") UUID assignQuestId) { - deleteAssignQuestUseCase.delete(authInfo.getMemberId(), assignQuestId); - return ResponseEntity.noContent().build(); - } -} diff --git a/src/main/java/com/gomo/app/core/quest/presentation/api/CalendarAssignQuestApi.java b/src/main/java/com/gomo/app/core/quest/presentation/api/CalendarAssignQuestApi.java deleted file mode 100644 index 842950f9..00000000 --- a/src/main/java/com/gomo/app/core/quest/presentation/api/CalendarAssignQuestApi.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.gomo.app.core.quest.presentation.api; - -import java.time.LocalDateTime; -import java.util.List; - -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; - -import com.gomo.app.common.arch.CoreApi; -import com.gomo.app.core.quest.application.port.command.CalendarAssignQuestCommand; -import com.gomo.app.core.quest.application.port.dto.CalendarAssignQuestDto; -import com.gomo.app.core.quest.application.usecase.CalendarAssignQuestUseCase; -import com.gomo.app.core.quest.presentation.api.response.CalendarAssignQuestResponse; -import com.gomo.app.core.quest.presentation.api.response.ListCalendarAssignQuestResponse; -import com.gomo.app.support.auth.presentation.security.Auth; -import com.gomo.app.support.auth.presentation.security.AuthInfo; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@RequestMapping("/quests/assigns/calendars") -@CoreApi -public class CalendarAssignQuestApi { - - private final CalendarAssignQuestUseCase calendarAssignQuestUseCase; - - @GetMapping - public ResponseEntity find(@Auth AuthInfo authInfo, @RequestParam boolean isCompleted, - @RequestParam LocalDateTime startDateTime, @RequestParam LocalDateTime endDateTime) { - CalendarAssignQuestCommand command = CalendarAssignQuestCommand.of(authInfo.getMemberId(), isCompleted, startDateTime, endDateTime); - List calendarDtos = calendarAssignQuestUseCase.find(command); - return ResponseEntity.ok(ListCalendarAssignQuestResponse.of(calendarDtos.stream().map(CalendarAssignQuestResponse::from).toList())); - } -} diff --git a/src/main/java/com/gomo/app/core/quest/presentation/api/ReRollAssignQuestApi.java b/src/main/java/com/gomo/app/core/quest/presentation/api/ReRollAssignQuestApi.java deleted file mode 100644 index ddff161b..00000000 --- a/src/main/java/com/gomo/app/core/quest/presentation/api/ReRollAssignQuestApi.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.gomo.app.core.quest.presentation.api; - -import static org.springframework.http.HttpStatus.*; - -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; - -import com.gomo.app.common.arch.CoreApi; -import com.gomo.app.core.quest.application.port.dto.AssignQuestDto; -import com.gomo.app.core.quest.application.usecase.ReRollAssignQuestUseCase; -import com.gomo.app.core.quest.presentation.api.request.ReRollAssignQuestRequest; -import com.gomo.app.core.quest.presentation.api.response.ReadAssignQuestResponse; -import com.gomo.app.support.auth.presentation.security.Auth; -import com.gomo.app.support.auth.presentation.security.AuthInfo; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@RequestMapping("/quests/assigns/re-roll") -@CoreApi -public class ReRollAssignQuestApi { - - private final ReRollAssignQuestUseCase reRollAssignQuestUseCase; - - @PostMapping - public ResponseEntity reRoll(@Auth AuthInfo authInfo, @RequestBody ReRollAssignQuestRequest request) { - AssignQuestDto assignQuestDto = reRollAssignQuestUseCase.reRoll(authInfo.getMemberId(), request.getAssignQuestId()); - return ResponseEntity.status(CREATED).body(ReadAssignQuestResponse.from(assignQuestDto)); - } -} diff --git a/src/main/java/com/gomo/app/core/quest/presentation/api/response/ListAssignQuestResponse.java b/src/main/java/com/gomo/app/core/quest/presentation/api/response/ListAssignQuestResponse.java deleted file mode 100644 index bbebd8c3..00000000 --- a/src/main/java/com/gomo/app/core/quest/presentation/api/response/ListAssignQuestResponse.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.gomo.app.core.quest.presentation.api.response; - -import java.util.List; - -import com.gomo.app.core.quest.application.port.dto.ListAssignQuestDto; - -import lombok.Getter; - -@Getter -public class ListAssignQuestResponse { - - private List dailyQuests; - private List weeklyQuests; - private List monthlyQuests; - - private ListAssignQuestResponse( - List dailyQuests, - List weeklyQuests, - List monthlyQuests - ) { - this.dailyQuests = dailyQuests; - this.weeklyQuests = weeklyQuests; - this.monthlyQuests = monthlyQuests; - } - - public static ListAssignQuestResponse from(ListAssignQuestDto dto) { - return new ListAssignQuestResponse( - dto.dailyQuests().stream().map(ReadAssignQuestResponse::from).toList(), - dto.weeklyQuests().stream().map(ReadAssignQuestResponse::from).toList(), - dto.monthlyQuests().stream().map(ReadAssignQuestResponse::from).toList() - ); - } -} diff --git a/src/main/java/com/gomo/app/core/quest/presentation/api/response/ListCalendarAssignQuestResponse.java b/src/main/java/com/gomo/app/core/quest/presentation/api/response/ListCalendarAssignQuestResponse.java deleted file mode 100644 index f51e26a6..00000000 --- a/src/main/java/com/gomo/app/core/quest/presentation/api/response/ListCalendarAssignQuestResponse.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.gomo.app.core.quest.presentation.api.response; - -import java.util.List; - -import lombok.Getter; - -@Getter -public class ListCalendarAssignQuestResponse { - - private List assignQuests; - - private ListCalendarAssignQuestResponse(List assignQuests) { - this.assignQuests = assignQuests; - } - - public static ListCalendarAssignQuestResponse of(List assignQuests) { - return new ListCalendarAssignQuestResponse(assignQuests); - } -} diff --git a/src/main/java/com/gomo/app/core/streak/presentation/api/AchieverApi.java b/src/main/java/com/gomo/app/core/streak/adapter/in/api/AchieverApi.java similarity index 53% rename from src/main/java/com/gomo/app/core/streak/presentation/api/AchieverApi.java rename to src/main/java/com/gomo/app/core/streak/adapter/in/api/AchieverApi.java index 26db194b..b2859241 100644 --- a/src/main/java/com/gomo/app/core/streak/presentation/api/AchieverApi.java +++ b/src/main/java/com/gomo/app/core/streak/adapter/in/api/AchieverApi.java @@ -1,15 +1,15 @@ -package com.gomo.app.core.streak.presentation.api; +package com.gomo.app.core.streak.adapter.in.api; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.core.streak.adapter.in.api.response.ReadAchieverResponse; import com.gomo.app.core.streak.application.port.dto.AchieverDto; -import com.gomo.app.core.streak.application.usecase.ReadAchieverUseCase; -import com.gomo.app.core.streak.presentation.api.response.ReadAchieverResponse; -import com.gomo.app.support.auth.presentation.security.Auth; -import com.gomo.app.support.auth.presentation.security.AuthInfo; +import com.gomo.app.core.streak.application.port.in.AchieverReader; +import com.gomo.app.core.auth.adapter.in.security.Auth; +import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -18,11 +18,11 @@ @CoreApi public class AchieverApi { - private final ReadAchieverUseCase readAchieverUseCase; + private final AchieverReader achieverReader; @GetMapping public ResponseEntity find(@Auth AuthInfo authInfo) { - AchieverDto achieverDto = readAchieverUseCase.find(authInfo.getMemberId()); + AchieverDto achieverDto = achieverReader.read(authInfo.getPrincipalId()); return ResponseEntity.ok(ReadAchieverResponse.from(achieverDto)); } } diff --git a/src/main/java/com/gomo/app/core/streak/presentation/api/StreakApi.java b/src/main/java/com/gomo/app/core/streak/adapter/in/api/StreakApi.java similarity index 59% rename from src/main/java/com/gomo/app/core/streak/presentation/api/StreakApi.java rename to src/main/java/com/gomo/app/core/streak/adapter/in/api/StreakApi.java index 0150d93d..69756237 100644 --- a/src/main/java/com/gomo/app/core/streak/presentation/api/StreakApi.java +++ b/src/main/java/com/gomo/app/core/streak/adapter/in/api/StreakApi.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.streak.presentation.api; +package com.gomo.app.core.streak.adapter.in.api; import java.time.LocalDate; @@ -8,11 +8,11 @@ import org.springframework.web.bind.annotation.RequestParam; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.core.streak.adapter.in.api.response.ListStreakResponse; import com.gomo.app.core.streak.application.port.dto.ListStreakDto; -import com.gomo.app.core.streak.application.usecase.ReadStreakUseCase; -import com.gomo.app.core.streak.presentation.api.response.ListStreakResponse; -import com.gomo.app.support.auth.presentation.security.Auth; -import com.gomo.app.support.auth.presentation.security.AuthInfo; +import com.gomo.app.core.streak.application.port.in.StreakReader; +import com.gomo.app.core.auth.adapter.in.security.Auth; +import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -21,11 +21,11 @@ @CoreApi public class StreakApi { - private final ReadStreakUseCase readStreakUseCase; + private final StreakReader streakReader; @GetMapping public ResponseEntity findAllByStreakType(@Auth AuthInfo authInfo, @RequestParam LocalDate startDate, @RequestParam LocalDate endDate) { - ListStreakDto dto = readStreakUseCase.findAll(authInfo.getMemberId(), startDate, endDate); + ListStreakDto dto = streakReader.findAll(authInfo.getPrincipalId(), startDate, endDate); return ResponseEntity.ok(ListStreakResponse.from(dto)); } } diff --git a/src/main/java/com/gomo/app/core/streak/presentation/api/response/ListStreakResponse.java b/src/main/java/com/gomo/app/core/streak/adapter/in/api/response/ListStreakResponse.java similarity index 91% rename from src/main/java/com/gomo/app/core/streak/presentation/api/response/ListStreakResponse.java rename to src/main/java/com/gomo/app/core/streak/adapter/in/api/response/ListStreakResponse.java index 6c1563ce..058d1927 100644 --- a/src/main/java/com/gomo/app/core/streak/presentation/api/response/ListStreakResponse.java +++ b/src/main/java/com/gomo/app/core/streak/adapter/in/api/response/ListStreakResponse.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.streak.presentation.api.response; +package com.gomo.app.core.streak.adapter.in.api.response; import java.util.List; diff --git a/src/main/java/com/gomo/app/core/streak/presentation/api/response/ReadAchieverResponse.java b/src/main/java/com/gomo/app/core/streak/adapter/in/api/response/ReadAchieverResponse.java similarity index 87% rename from src/main/java/com/gomo/app/core/streak/presentation/api/response/ReadAchieverResponse.java rename to src/main/java/com/gomo/app/core/streak/adapter/in/api/response/ReadAchieverResponse.java index e3e1b7eb..2b480609 100644 --- a/src/main/java/com/gomo/app/core/streak/presentation/api/response/ReadAchieverResponse.java +++ b/src/main/java/com/gomo/app/core/streak/adapter/in/api/response/ReadAchieverResponse.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.streak.presentation.api.response; +package com.gomo.app.core.streak.adapter.in.api.response; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/streak/presentation/api/response/ReadStreakResponse.java b/src/main/java/com/gomo/app/core/streak/adapter/in/api/response/ReadStreakResponse.java similarity index 89% rename from src/main/java/com/gomo/app/core/streak/presentation/api/response/ReadStreakResponse.java rename to src/main/java/com/gomo/app/core/streak/adapter/in/api/response/ReadStreakResponse.java index a403a896..026becef 100644 --- a/src/main/java/com/gomo/app/core/streak/presentation/api/response/ReadStreakResponse.java +++ b/src/main/java/com/gomo/app/core/streak/adapter/in/api/response/ReadStreakResponse.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.streak.presentation.api.response; +package com.gomo.app.core.streak.adapter.in.api.response; import java.time.LocalDate; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/streak/presentation/consumer/CompleteQuestEventStreakConsumer.java b/src/main/java/com/gomo/app/core/streak/adapter/in/consumer/CompleteQuestEventStreakConsumer.java similarity index 64% rename from src/main/java/com/gomo/app/core/streak/presentation/consumer/CompleteQuestEventStreakConsumer.java rename to src/main/java/com/gomo/app/core/streak/adapter/in/consumer/CompleteQuestEventStreakConsumer.java index eb5c0c71..286d1a30 100644 --- a/src/main/java/com/gomo/app/core/streak/presentation/consumer/CompleteQuestEventStreakConsumer.java +++ b/src/main/java/com/gomo/app/core/streak/adapter/in/consumer/CompleteQuestEventStreakConsumer.java @@ -1,11 +1,11 @@ -package com.gomo.app.core.streak.presentation.consumer; +package com.gomo.app.core.streak.adapter.in.consumer; import org.springframework.amqp.rabbit.annotation.RabbitListener; import com.gomo.app.common.arch.EventConsumer; import com.gomo.app.common.util.JsonParser; -import com.gomo.app.core.quest.event.CompleteQuestEvent; -import com.gomo.app.core.streak.application.port.CreateStreakPortIn; +import com.gomo.app.core.quest.domain.event.CompleteQuestEvent; +import com.gomo.app.core.streak.application.port.in.StreakCreator; import com.gomo.app.support.evententry.application.port.IdempotentEventEntryConsumer; import com.gomo.app.support.evententry.domain.model.EventEntry; @@ -15,12 +15,12 @@ @EventConsumer public class CompleteQuestEventStreakConsumer { - private final CreateStreakPortIn createStreakPortIn; + private final StreakCreator streakCreator; @IdempotentEventEntryConsumer @RabbitListener(queues = "event.quest.assign.complete.streak") public void handleEvent(EventEntry eventEntry) { CompleteQuestEvent event = JsonParser.fromJson(eventEntry.getPayload(), CompleteQuestEvent.class); - createStreakPortIn.create(event.getParticipantId(), event.getQuestType(), event.getQuestCompletionTime().toLocalDate()); + streakCreator.create(event.getParticipantId(), event.getQuestType(), event.getQuestCompletionTime().toLocalDate()); } } diff --git a/src/main/java/com/gomo/app/core/streak/application/port/CreateAchieverPortIn.java b/src/main/java/com/gomo/app/core/streak/application/port/in/AchieverCreator.java similarity index 61% rename from src/main/java/com/gomo/app/core/streak/application/port/CreateAchieverPortIn.java rename to src/main/java/com/gomo/app/core/streak/application/port/in/AchieverCreator.java index 62dad8b5..a2c08e8a 100644 --- a/src/main/java/com/gomo/app/core/streak/application/port/CreateAchieverPortIn.java +++ b/src/main/java/com/gomo/app/core/streak/application/port/in/AchieverCreator.java @@ -1,15 +1,15 @@ -package com.gomo.app.core.streak.application.port; +package com.gomo.app.core.streak.application.port.in; import java.util.UUID; -public interface CreateAchieverPortIn { +public interface AchieverCreator { /** * Creates a new achiever profile within the streak system. * * @param achieverId The id of the entity (e.g., member ID) to be registered as an achiever. * @return The id (UUID) of the newly created achiever. - * @throws AchieverAlreadyExistsException if an achiever for the given ID already exists. + * @throws IllegalStateException if an achiever for the given ID already exists. */ UUID create(UUID achieverId); } diff --git a/src/main/java/com/gomo/app/core/streak/application/port/in/AchieverReader.java b/src/main/java/com/gomo/app/core/streak/application/port/in/AchieverReader.java new file mode 100644 index 00000000..e83c3470 --- /dev/null +++ b/src/main/java/com/gomo/app/core/streak/application/port/in/AchieverReader.java @@ -0,0 +1,18 @@ +package com.gomo.app.core.streak.application.port.in; + +import java.util.UUID; + +import com.gomo.app.core.streak.application.port.dto.AchieverDto; +import com.gomo.app.core.streak.domain.exception.AchieverNotFoundException; + +public interface AchieverReader { + + /** + * Retrieves the details of a specific achiever by their ID. + * + * @param achieverId The ID of the achiever to retrieve. + * @return An {@link AchieverDto} containing the details of the found achiever. + * @throws AchieverNotFoundException if no achiever exists with the provided ID. + */ + AchieverDto read(UUID achieverId); +} diff --git a/src/main/java/com/gomo/app/core/streak/application/port/CreateStreakPortIn.java b/src/main/java/com/gomo/app/core/streak/application/port/in/StreakCreator.java similarity index 85% rename from src/main/java/com/gomo/app/core/streak/application/port/CreateStreakPortIn.java rename to src/main/java/com/gomo/app/core/streak/application/port/in/StreakCreator.java index 275735b8..2c7c5081 100644 --- a/src/main/java/com/gomo/app/core/streak/application/port/CreateStreakPortIn.java +++ b/src/main/java/com/gomo/app/core/streak/application/port/in/StreakCreator.java @@ -1,11 +1,11 @@ -package com.gomo.app.core.streak.application.port; +package com.gomo.app.core.streak.application.port.in; import java.time.LocalDate; import java.util.UUID; import com.gomo.app.core.streak.domain.model.StreakType; -public interface CreateStreakPortIn { +public interface StreakCreator { /** * Creates a streak record for achiever on a specific date. diff --git a/src/main/java/com/gomo/app/core/streak/application/port/in/StreakReader.java b/src/main/java/com/gomo/app/core/streak/application/port/in/StreakReader.java new file mode 100644 index 00000000..c8837e71 --- /dev/null +++ b/src/main/java/com/gomo/app/core/streak/application/port/in/StreakReader.java @@ -0,0 +1,21 @@ +package com.gomo.app.core.streak.application.port.in; + +import java.time.LocalDate; +import java.util.UUID; + +import com.gomo.app.core.streak.application.port.dto.ListStreakDto; + +public interface StreakReader { + + /** + * Retrieves all streaks for a specific achiever within a given date range. + * The results are categorized by streak type (e.g., daily, weekly, monthly). + * + * @param achieverId The ID of the achiever whose streaks are to be retrieved. + * @param startDate The start date of the period (inclusive). + * @param endDate The end date of the period (inclusive). + * @return A {@link ListStreakDto} containing categorized lists of streaks. + * The lists will be empty if no streaks are found for the given period; this method does not return null. + */ + ListStreakDto findAll(UUID achieverId, LocalDate startDate, LocalDate endDate); +} diff --git a/src/main/java/com/gomo/app/core/streak/application/service/AchieverService.java b/src/main/java/com/gomo/app/core/streak/application/service/AchieverService.java new file mode 100644 index 00000000..79d93dde --- /dev/null +++ b/src/main/java/com/gomo/app/core/streak/application/service/AchieverService.java @@ -0,0 +1,49 @@ +package com.gomo.app.core.streak.application.service; + +import java.util.UUID; + +import org.springframework.transaction.annotation.Transactional; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.core.streak.application.port.dto.AchieverDto; +import com.gomo.app.core.streak.application.port.in.AchieverCreator; +import com.gomo.app.core.streak.application.port.in.AchieverReader; +import com.gomo.app.core.streak.domain.exception.AchieverErrorCode; +import com.gomo.app.core.streak.domain.exception.AchieverNotFoundException; +import com.gomo.app.core.streak.domain.model.Achiever; +import com.gomo.app.core.streak.domain.repository.AchieverRepository; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Transactional +@ApplicationService +class AchieverService implements AchieverCreator, AchieverReader { + + private final AchieverRepository achieverRepository; + + @Override + @AuditLog(action = "ACHIEVER_CREATE") + public UUID create(UUID achieverId) { + ensureNotDuplicated(achieverId); + Achiever savedAchiever = achieverRepository.save(Achiever.of(achieverId)); + return savedAchiever.getId(); + } + + private void ensureNotDuplicated(UUID achieverId) { + if (achieverRepository.existsById(achieverId)) { + throw new IllegalStateException("already exists achiever with id: " + achieverId); + } + } + + @Override + @Transactional(readOnly = true) + public AchieverDto read(UUID achieverId) { + return AchieverDto.from(findById(achieverId)); + } + + Achiever findById(UUID achieverId) { + return achieverRepository.findById(achieverId).orElseThrow(() -> new AchieverNotFoundException(AchieverErrorCode.NOT_FOUND)); + } +} diff --git a/src/main/java/com/gomo/app/core/streak/application/service/StreakService.java b/src/main/java/com/gomo/app/core/streak/application/service/StreakService.java new file mode 100644 index 00000000..07b9df86 --- /dev/null +++ b/src/main/java/com/gomo/app/core/streak/application/service/StreakService.java @@ -0,0 +1,70 @@ +package com.gomo.app.core.streak.application.service; + +import java.time.LocalDate; +import java.util.List; +import java.util.UUID; + +import org.jetbrains.annotations.NotNull; +import org.springframework.transaction.annotation.Transactional; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.common.util.UUIDGenerator; +import com.gomo.app.core.streak.application.port.dto.ListStreakDto; +import com.gomo.app.core.streak.application.port.dto.StreakDto; +import com.gomo.app.core.streak.application.port.in.StreakCreator; +import com.gomo.app.core.streak.application.port.in.StreakReader; +import com.gomo.app.core.streak.domain.model.Achiever; +import com.gomo.app.core.streak.domain.model.Streak; +import com.gomo.app.core.streak.domain.model.StreakType; +import com.gomo.app.core.streak.domain.repository.StreakRepository; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Transactional +@ApplicationService +class StreakService implements StreakCreator, StreakReader { + + private final AchieverService achieverService; + private final StreakRepository streakRepository; + + @Override + @AuditLog(action = "STREAK_CREATE") + public void create(UUID achieverId, String streakType, LocalDate creationDate) { + Streak streak = Streak.of(UUIDGenerator.generate(), achieverId, StreakType.valueOf(streakType), creationDate, 1); + increaseStreakDays(streak); + streakRepository.findByAchieverIdAndStreakTypeAndFilledDate(streak.getAchieverId(), streak.getStreakType(), streak.getFilledDate()) + .map(existingStreak -> { + existingStreak.increaseCompletedQuestCount(); + return existingStreak; + }).orElseGet(() -> createInitialStreak(streak)); + } + + private void increaseStreakDays(Streak streak) { + Achiever achiever = achieverService.findById(streak.getAchieverId()); + List priorDayStreaks = streakRepository.findByAchieverIdAndFilledDate(streak.getAchieverId(), streak.getFilledDate().minusDays(1)); + boolean isFilledPriorDay = !priorDayStreaks.isEmpty(); + achiever.updateStreakDays(isFilledPriorDay); + } + + private Streak createInitialStreak(Streak streak) { + return streakRepository.save(streak); + } + + @Override + @Transactional(readOnly = true) + public ListStreakDto findAll(UUID achieverId, LocalDate startDate, LocalDate endDate) { + List dailyStreaks = findStreaksByType(achieverId, StreakType.DAILY, startDate, endDate); + List weeklyStreaks = findStreaksByType(achieverId, StreakType.WEEKLY, startDate, endDate); + List monthlyStreaks = findStreaksByType(achieverId, StreakType.MONTHLY, startDate, endDate); + return ListStreakDto.of(dailyStreaks, weeklyStreaks, monthlyStreaks); + } + + @NotNull + private List findStreaksByType(UUID achieverId, StreakType streakType, LocalDate startDate, LocalDate endDate) { + return streakRepository.findByAchieverIdAndStreakTypeAndFilledDateBetween(achieverId, streakType, startDate, endDate).stream() + .map(StreakDto::from) + .toList(); + } +} diff --git a/src/main/java/com/gomo/app/core/streak/application/usecase/CreateAchieverUseCase.java b/src/main/java/com/gomo/app/core/streak/application/usecase/CreateAchieverUseCase.java deleted file mode 100644 index 818e99dc..00000000 --- a/src/main/java/com/gomo/app/core/streak/application/usecase/CreateAchieverUseCase.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.gomo.app.core.streak.application.usecase; - -import java.util.UUID; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.streak.application.port.CreateAchieverPortIn; -import com.gomo.app.core.streak.domain.model.Achiever; -import com.gomo.app.core.streak.domain.repository.AchieverRepository; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -class CreateAchieverUseCase implements CreateAchieverPortIn { - - private final AchieverRepository achieverRepository; - - // TODO [2025-10-10] jhl221123 : 이미 해당 id로 존재한다면 예외가 발생해야 합니다. - @AuditLog(action = "CREATE_ACHIEVER") - @Override - public UUID create(UUID achieverId) { - Achiever savedAchiever = achieverRepository.save(Achiever.of(achieverId)); - return savedAchiever.getId(); - } -} diff --git a/src/main/java/com/gomo/app/core/streak/application/usecase/CreateStreakUseCase.java b/src/main/java/com/gomo/app/core/streak/application/usecase/CreateStreakUseCase.java deleted file mode 100644 index 7b2cb255..00000000 --- a/src/main/java/com/gomo/app/core/streak/application/usecase/CreateStreakUseCase.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.gomo.app.core.streak.application.usecase; - -import java.time.LocalDate; -import java.util.UUID; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.common.util.UUIDGenerator; -import com.gomo.app.core.streak.application.port.CreateStreakPortIn; -import com.gomo.app.core.streak.domain.model.Streak; -import com.gomo.app.core.streak.domain.model.StreakType; -import com.gomo.app.core.streak.domain.service.StreakService; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -class CreateStreakUseCase implements CreateStreakPortIn { - - private final StreakService streakService; - - @Override - public void create(UUID achieverId, String streakType, LocalDate creationDate) { - Streak streak = Streak.of(UUIDGenerator.generate(), achieverId, StreakType.valueOf(streakType), creationDate, 1); - streakService.fill(streak); - } -} diff --git a/src/main/java/com/gomo/app/core/streak/application/usecase/ReadAchieverUseCase.java b/src/main/java/com/gomo/app/core/streak/application/usecase/ReadAchieverUseCase.java deleted file mode 100644 index 3777ef85..00000000 --- a/src/main/java/com/gomo/app/core/streak/application/usecase/ReadAchieverUseCase.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.gomo.app.core.streak.application.usecase; - -import java.util.UUID; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.streak.application.port.dto.AchieverDto; -import com.gomo.app.core.streak.domain.service.AchieverService; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -public class ReadAchieverUseCase { - - private final AchieverService achieverService; - - public AchieverDto find(UUID achieverId) { - return AchieverDto.from(achieverService.find(achieverId)); - } -} diff --git a/src/main/java/com/gomo/app/core/streak/application/usecase/ReadStreakUseCase.java b/src/main/java/com/gomo/app/core/streak/application/usecase/ReadStreakUseCase.java deleted file mode 100644 index 55957f9b..00000000 --- a/src/main/java/com/gomo/app/core/streak/application/usecase/ReadStreakUseCase.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.gomo.app.core.streak.application.usecase; - -import java.time.LocalDate; -import java.util.List; -import java.util.UUID; - -import org.jetbrains.annotations.NotNull; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.core.streak.application.port.dto.ListStreakDto; -import com.gomo.app.core.streak.application.port.dto.StreakDto; -import com.gomo.app.core.streak.domain.model.StreakType; -import com.gomo.app.core.streak.domain.service.StreakService; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -public class ReadStreakUseCase { - - private final StreakService streakService; - - public ListStreakDto findAll(UUID achieverId, LocalDate startDate, LocalDate endDate) { - List dailyStreaks = findStreaksByType(achieverId, StreakType.DAILY, startDate, endDate); - List weeklyStreaks = findStreaksByType(achieverId, StreakType.WEEKLY, startDate, endDate); - List monthlyStreaks = findStreaksByType(achieverId, StreakType.MONTHLY, startDate, endDate); - return ListStreakDto.of(dailyStreaks, weeklyStreaks, monthlyStreaks); - } - - @NotNull - private List findStreaksByType(UUID achieverId, StreakType streakType, LocalDate startDate, LocalDate endDate) { - return streakService.findAllByStreakType(achieverId, streakType, startDate, endDate).stream() - .map(StreakDto::from) - .toList(); - } -} diff --git a/src/main/java/com/gomo/app/core/streak/exception/AchieverErrorCode.java b/src/main/java/com/gomo/app/core/streak/domain/exception/AchieverErrorCode.java similarity index 86% rename from src/main/java/com/gomo/app/core/streak/exception/AchieverErrorCode.java rename to src/main/java/com/gomo/app/core/streak/domain/exception/AchieverErrorCode.java index 46f9c4e6..b0bf3959 100644 --- a/src/main/java/com/gomo/app/core/streak/exception/AchieverErrorCode.java +++ b/src/main/java/com/gomo/app/core/streak/domain/exception/AchieverErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.streak.exception; +package com.gomo.app.core.streak.domain.exception; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/streak/exception/AchieverNotFoundException.java b/src/main/java/com/gomo/app/core/streak/domain/exception/AchieverNotFoundException.java similarity index 87% rename from src/main/java/com/gomo/app/core/streak/exception/AchieverNotFoundException.java rename to src/main/java/com/gomo/app/core/streak/domain/exception/AchieverNotFoundException.java index 0cc42fb7..176ff722 100644 --- a/src/main/java/com/gomo/app/core/streak/exception/AchieverNotFoundException.java +++ b/src/main/java/com/gomo/app/core/streak/domain/exception/AchieverNotFoundException.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.streak.exception; +package com.gomo.app.core.streak.domain.exception; import com.gomo.app.common.exception.ApplicationException; diff --git a/src/main/java/com/gomo/app/core/streak/domain/service/AchieverService.java b/src/main/java/com/gomo/app/core/streak/domain/service/AchieverService.java deleted file mode 100644 index 492ffb3c..00000000 --- a/src/main/java/com/gomo/app/core/streak/domain/service/AchieverService.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.gomo.app.core.streak.domain.service; - -import java.util.UUID; - -import com.gomo.app.common.arch.DomainService; -import com.gomo.app.core.streak.domain.model.Achiever; -import com.gomo.app.core.streak.domain.repository.AchieverRepository; -import com.gomo.app.core.streak.exception.AchieverErrorCode; -import com.gomo.app.core.streak.exception.AchieverNotFoundException; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@DomainService -public class AchieverService { - - private final AchieverRepository achieverRepository; - - public Achiever find(UUID achieverId) { - return achieverRepository.findById(achieverId).orElseThrow(() -> new AchieverNotFoundException(AchieverErrorCode.NOT_FOUND)); - } -} diff --git a/src/main/java/com/gomo/app/core/streak/domain/service/StreakService.java b/src/main/java/com/gomo/app/core/streak/domain/service/StreakService.java deleted file mode 100644 index 7957ed02..00000000 --- a/src/main/java/com/gomo/app/core/streak/domain/service/StreakService.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.gomo.app.core.streak.domain.service; - -import java.time.LocalDate; -import java.util.List; -import java.util.UUID; - -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.common.arch.DomainService; -import com.gomo.app.core.streak.domain.model.Achiever; -import com.gomo.app.core.streak.domain.model.Streak; -import com.gomo.app.core.streak.domain.model.StreakType; -import com.gomo.app.core.streak.domain.repository.StreakRepository; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@RequiredArgsConstructor -@DomainService -public class StreakService { - - private final AchieverService achieverService; - private final StreakRepository streakRepository; - - @Transactional - public Streak fill(Streak streak) { - increaseStreakDays(streak); - return streakRepository.findByAchieverIdAndStreakTypeAndFilledDate(streak.getAchieverId(), streak.getStreakType(), streak.getFilledDate()) - .map(existingStreak -> { - existingStreak.increaseCompletedQuestCount(); - return existingStreak; - }).orElseGet(() -> createInitialStreak(streak)); - } - - public List findAllByStreakType(UUID achieverId, StreakType streakType, LocalDate startDate, LocalDate endDate) { - return streakRepository.findByAchieverIdAndStreakTypeAndFilledDateBetween(achieverId, streakType, startDate, endDate); - } - - private void increaseStreakDays(Streak streak) { - Achiever achiever = achieverService.find(streak.getAchieverId()); - List priorDayStreaks = streakRepository.findByAchieverIdAndFilledDate(streak.getAchieverId(), streak.getFilledDate().minusDays(1)); - boolean isFilledPriorDay = !priorDayStreaks.isEmpty(); - achiever.updateStreakDays(isFilledPriorDay); - } - - private Streak createInitialStreak(Streak streak) { - return streakRepository.save(streak); - } -} diff --git a/src/main/java/com/gomo/app/core/survey/presentation/SurveyApi.java b/src/main/java/com/gomo/app/core/survey/adapter/in/api/SurveyApi.java similarity index 51% rename from src/main/java/com/gomo/app/core/survey/presentation/SurveyApi.java rename to src/main/java/com/gomo/app/core/survey/adapter/in/api/SurveyApi.java index 12c8d406..b1be8d6d 100644 --- a/src/main/java/com/gomo/app/core/survey/presentation/SurveyApi.java +++ b/src/main/java/com/gomo/app/core/survey/adapter/in/api/SurveyApi.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.survey.presentation; +package com.gomo.app.core.survey.adapter.in.api; import static org.springframework.http.HttpStatus.*; @@ -11,13 +11,13 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; -import com.gomo.app.core.survey.application.CreateSurveyResultUseCase; -import com.gomo.app.core.survey.application.ReadSurveyQuestionUseCase; -import com.gomo.app.core.survey.application.SurveyQuestionDto; -import com.gomo.app.core.survey.presentation.request.CreateSurveyResultRequest; -import com.gomo.app.core.survey.presentation.response.ListSurveyQuestionResponse; -import com.gomo.app.support.auth.presentation.security.Auth; -import com.gomo.app.support.auth.presentation.security.AuthInfo; +import com.gomo.app.core.survey.adapter.in.api.request.CreateSurveyResultRequest; +import com.gomo.app.core.survey.adapter.in.api.response.ListSurveyQuestionResponse; +import com.gomo.app.core.survey.application.dto.SurveyQuestionDto; +import com.gomo.app.core.survey.application.service.SurveyQuestionService; +import com.gomo.app.core.survey.application.service.SurveyResultService; +import com.gomo.app.core.auth.adapter.in.security.Auth; +import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -26,18 +26,18 @@ @CoreApi public class SurveyApi { - private final CreateSurveyResultUseCase createSurveyResultUseCase; - private final ReadSurveyQuestionUseCase readSurveyQuestionUseCase; + private final SurveyResultService surveyResultService; + private final SurveyQuestionService surveyQuestionService; @PostMapping public ResponseEntity createSurveyResult(@Auth AuthInfo authInfo, @RequestBody CreateSurveyResultRequest request) { - createSurveyResultUseCase.create(request.toCommand(authInfo.getMemberId())); + surveyResultService.create(request.toCommand(authInfo.getPrincipalId())); return ResponseEntity.status(CREATED).build(); } @GetMapping public ResponseEntity findSurveyQuestions() { - List dto = readSurveyQuestionUseCase.findAll(); + List dto = surveyQuestionService.findAll(); return ResponseEntity.status(OK).body(ListSurveyQuestionResponse.from(dto)); } } diff --git a/src/main/java/com/gomo/app/core/survey/presentation/request/CreateSurveyResultRequest.java b/src/main/java/com/gomo/app/core/survey/adapter/in/api/request/CreateSurveyResultRequest.java similarity index 80% rename from src/main/java/com/gomo/app/core/survey/presentation/request/CreateSurveyResultRequest.java rename to src/main/java/com/gomo/app/core/survey/adapter/in/api/request/CreateSurveyResultRequest.java index 11d74234..0d214449 100644 --- a/src/main/java/com/gomo/app/core/survey/presentation/request/CreateSurveyResultRequest.java +++ b/src/main/java/com/gomo/app/core/survey/adapter/in/api/request/CreateSurveyResultRequest.java @@ -1,9 +1,9 @@ -package com.gomo.app.core.survey.presentation.request; +package com.gomo.app.core.survey.adapter.in.api.request; import java.util.List; import java.util.UUID; -import com.gomo.app.core.survey.application.CreateSurveyResultCommand; +import com.gomo.app.core.survey.application.command.CreateSurveyResultCommand; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/survey/presentation/request/SelectedSurveyItemRequest.java b/src/main/java/com/gomo/app/core/survey/adapter/in/api/request/SelectedSurveyItemRequest.java similarity index 85% rename from src/main/java/com/gomo/app/core/survey/presentation/request/SelectedSurveyItemRequest.java rename to src/main/java/com/gomo/app/core/survey/adapter/in/api/request/SelectedSurveyItemRequest.java index 34dcffcf..27a95123 100644 --- a/src/main/java/com/gomo/app/core/survey/presentation/request/SelectedSurveyItemRequest.java +++ b/src/main/java/com/gomo/app/core/survey/adapter/in/api/request/SelectedSurveyItemRequest.java @@ -1,8 +1,8 @@ -package com.gomo.app.core.survey.presentation.request; +package com.gomo.app.core.survey.adapter.in.api.request; import java.util.UUID; -import com.gomo.app.core.survey.application.SurveyItemDto; +import com.gomo.app.core.survey.application.dto.SurveyItemDto; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/survey/presentation/response/ListSurveyQuestionResponse.java b/src/main/java/com/gomo/app/core/survey/adapter/in/api/response/ListSurveyQuestionResponse.java similarity index 77% rename from src/main/java/com/gomo/app/core/survey/presentation/response/ListSurveyQuestionResponse.java rename to src/main/java/com/gomo/app/core/survey/adapter/in/api/response/ListSurveyQuestionResponse.java index df80c631..493fa1cd 100644 --- a/src/main/java/com/gomo/app/core/survey/presentation/response/ListSurveyQuestionResponse.java +++ b/src/main/java/com/gomo/app/core/survey/adapter/in/api/response/ListSurveyQuestionResponse.java @@ -1,8 +1,8 @@ -package com.gomo.app.core.survey.presentation.response; +package com.gomo.app.core.survey.adapter.in.api.response; import java.util.List; -import com.gomo.app.core.survey.application.SurveyQuestionDto; +import com.gomo.app.core.survey.application.dto.SurveyQuestionDto; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/survey/presentation/response/ReadSurveyItemResponse.java b/src/main/java/com/gomo/app/core/survey/adapter/in/api/response/ReadSurveyItemResponse.java similarity index 76% rename from src/main/java/com/gomo/app/core/survey/presentation/response/ReadSurveyItemResponse.java rename to src/main/java/com/gomo/app/core/survey/adapter/in/api/response/ReadSurveyItemResponse.java index 23c04a3e..16af733d 100644 --- a/src/main/java/com/gomo/app/core/survey/presentation/response/ReadSurveyItemResponse.java +++ b/src/main/java/com/gomo/app/core/survey/adapter/in/api/response/ReadSurveyItemResponse.java @@ -1,8 +1,8 @@ -package com.gomo.app.core.survey.presentation.response; +package com.gomo.app.core.survey.adapter.in.api.response; import java.util.UUID; -import com.gomo.app.core.survey.application.SurveyItemDto; +import com.gomo.app.core.survey.application.dto.SurveyItemDto; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/survey/presentation/response/ReadSurveyQuestionResponse.java b/src/main/java/com/gomo/app/core/survey/adapter/in/api/response/ReadSurveyQuestionResponse.java similarity index 84% rename from src/main/java/com/gomo/app/core/survey/presentation/response/ReadSurveyQuestionResponse.java rename to src/main/java/com/gomo/app/core/survey/adapter/in/api/response/ReadSurveyQuestionResponse.java index 64cb4dce..837a90ef 100644 --- a/src/main/java/com/gomo/app/core/survey/presentation/response/ReadSurveyQuestionResponse.java +++ b/src/main/java/com/gomo/app/core/survey/adapter/in/api/response/ReadSurveyQuestionResponse.java @@ -1,9 +1,9 @@ -package com.gomo.app.core.survey.presentation.response; +package com.gomo.app.core.survey.adapter.in.api.response; import java.util.List; import java.util.UUID; -import com.gomo.app.core.survey.application.SurveyQuestionDto; +import com.gomo.app.core.survey.application.dto.SurveyQuestionDto; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/survey/infrastructure/SurveyResultRepositoryImpl.java b/src/main/java/com/gomo/app/core/survey/adapter/out/persistence/SurveyResultRepositoryImpl.java similarity index 94% rename from src/main/java/com/gomo/app/core/survey/infrastructure/SurveyResultRepositoryImpl.java rename to src/main/java/com/gomo/app/core/survey/adapter/out/persistence/SurveyResultRepositoryImpl.java index d8fdbc8e..346e6572 100644 --- a/src/main/java/com/gomo/app/core/survey/infrastructure/SurveyResultRepositoryImpl.java +++ b/src/main/java/com/gomo/app/core/survey/adapter/out/persistence/SurveyResultRepositoryImpl.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.survey.infrastructure; +package com.gomo.app.core.survey.adapter.out.persistence; import java.sql.PreparedStatement; import java.sql.SQLException; diff --git a/src/main/java/com/gomo/app/core/survey/application/CreateSurveyResultCommand.java b/src/main/java/com/gomo/app/core/survey/application/command/CreateSurveyResultCommand.java similarity index 73% rename from src/main/java/com/gomo/app/core/survey/application/CreateSurveyResultCommand.java rename to src/main/java/com/gomo/app/core/survey/application/command/CreateSurveyResultCommand.java index 02813257..12d3a9c6 100644 --- a/src/main/java/com/gomo/app/core/survey/application/CreateSurveyResultCommand.java +++ b/src/main/java/com/gomo/app/core/survey/application/command/CreateSurveyResultCommand.java @@ -1,8 +1,10 @@ -package com.gomo.app.core.survey.application; +package com.gomo.app.core.survey.application.command; import java.util.List; import java.util.UUID; +import com.gomo.app.core.survey.application.dto.SurveyItemDto; + public record CreateSurveyResultCommand(UUID respondentId, List selectedSurveyItems) { public static CreateSurveyResultCommand of(UUID respondentId, List surveyResult) { diff --git a/src/main/java/com/gomo/app/core/survey/application/SurveyItemDto.java b/src/main/java/com/gomo/app/core/survey/application/dto/SurveyItemDto.java similarity index 92% rename from src/main/java/com/gomo/app/core/survey/application/SurveyItemDto.java rename to src/main/java/com/gomo/app/core/survey/application/dto/SurveyItemDto.java index c390eea7..9c66858e 100644 --- a/src/main/java/com/gomo/app/core/survey/application/SurveyItemDto.java +++ b/src/main/java/com/gomo/app/core/survey/application/dto/SurveyItemDto.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.survey.application; +package com.gomo.app.core.survey.application.dto; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/survey/application/SurveyQuestionDto.java b/src/main/java/com/gomo/app/core/survey/application/dto/SurveyQuestionDto.java similarity index 93% rename from src/main/java/com/gomo/app/core/survey/application/SurveyQuestionDto.java rename to src/main/java/com/gomo/app/core/survey/application/dto/SurveyQuestionDto.java index e94b0e0f..0809b69d 100644 --- a/src/main/java/com/gomo/app/core/survey/application/SurveyQuestionDto.java +++ b/src/main/java/com/gomo/app/core/survey/application/dto/SurveyQuestionDto.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.survey.application; +package com.gomo.app.core.survey.application.dto; import java.util.List; import java.util.UUID; diff --git a/src/main/java/com/gomo/app/core/survey/application/ReadSurveyQuestionUseCase.java b/src/main/java/com/gomo/app/core/survey/application/service/SurveyQuestionService.java similarity index 76% rename from src/main/java/com/gomo/app/core/survey/application/ReadSurveyQuestionUseCase.java rename to src/main/java/com/gomo/app/core/survey/application/service/SurveyQuestionService.java index 88ebb390..4843d887 100644 --- a/src/main/java/com/gomo/app/core/survey/application/ReadSurveyQuestionUseCase.java +++ b/src/main/java/com/gomo/app/core/survey/application/service/SurveyQuestionService.java @@ -1,8 +1,10 @@ -package com.gomo.app.core.survey.application; +package com.gomo.app.core.survey.application.service; import java.util.List; import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.core.survey.application.dto.SurveyItemDto; +import com.gomo.app.core.survey.application.dto.SurveyQuestionDto; import com.gomo.app.core.survey.domain.repository.SurveyItemRepository; import com.gomo.app.core.survey.domain.repository.SurveyQuestionRepository; @@ -10,7 +12,7 @@ @RequiredArgsConstructor @ApplicationService -public class ReadSurveyQuestionUseCase { +public class SurveyQuestionService { private final SurveyQuestionRepository surveyQuestionRepository; private final SurveyItemRepository surveyItemRepository; diff --git a/src/main/java/com/gomo/app/core/survey/application/CreateSurveyResultUseCase.java b/src/main/java/com/gomo/app/core/survey/application/service/SurveyResultService.java similarity index 78% rename from src/main/java/com/gomo/app/core/survey/application/CreateSurveyResultUseCase.java rename to src/main/java/com/gomo/app/core/survey/application/service/SurveyResultService.java index 1322756c..7a245c52 100644 --- a/src/main/java/com/gomo/app/core/survey/application/CreateSurveyResultUseCase.java +++ b/src/main/java/com/gomo/app/core/survey/application/service/SurveyResultService.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.survey.application; +package com.gomo.app.core.survey.application.service; import java.util.List; import java.util.UUID; @@ -7,16 +7,18 @@ import org.springframework.transaction.annotation.Transactional; import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.core.survey.application.command.CreateSurveyResultCommand; +import com.gomo.app.core.survey.application.dto.SurveyItemDto; import com.gomo.app.core.survey.domain.model.SurveyResult; import com.gomo.app.core.survey.domain.repository.SurveyResultRepository; -import com.gomo.app.support.logging.AuditLog; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @Transactional @ApplicationService -public class CreateSurveyResultUseCase { +public class SurveyResultService { private final SurveyResultRepository surveyResultRepository; diff --git a/src/main/java/com/gomo/app/core/survey/exception/SurveyResultConstraintViolationException.java b/src/main/java/com/gomo/app/core/survey/domain/exception/SurveyResultConstraintViolationException.java similarity index 88% rename from src/main/java/com/gomo/app/core/survey/exception/SurveyResultConstraintViolationException.java rename to src/main/java/com/gomo/app/core/survey/domain/exception/SurveyResultConstraintViolationException.java index d22469b6..fceecba4 100644 --- a/src/main/java/com/gomo/app/core/survey/exception/SurveyResultConstraintViolationException.java +++ b/src/main/java/com/gomo/app/core/survey/domain/exception/SurveyResultConstraintViolationException.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.survey.exception; +package com.gomo.app.core.survey.domain.exception; import com.gomo.app.common.exception.ApplicationException; diff --git a/src/main/java/com/gomo/app/core/survey/exception/SurveyResultErrorCode.java b/src/main/java/com/gomo/app/core/survey/domain/exception/SurveyResultErrorCode.java similarity index 90% rename from src/main/java/com/gomo/app/core/survey/exception/SurveyResultErrorCode.java rename to src/main/java/com/gomo/app/core/survey/domain/exception/SurveyResultErrorCode.java index de3cdb38..86b97b33 100644 --- a/src/main/java/com/gomo/app/core/survey/exception/SurveyResultErrorCode.java +++ b/src/main/java/com/gomo/app/core/survey/domain/exception/SurveyResultErrorCode.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.survey.exception; +package com.gomo.app.core.survey.domain.exception; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/core/survey/domain/model/SurveyResult.java b/src/main/java/com/gomo/app/core/survey/domain/model/SurveyResult.java index 0c64dfe2..a03178ff 100644 --- a/src/main/java/com/gomo/app/core/survey/domain/model/SurveyResult.java +++ b/src/main/java/com/gomo/app/core/survey/domain/model/SurveyResult.java @@ -4,8 +4,8 @@ import java.util.regex.Pattern; import com.gomo.app.common.arch.ValueObject; -import com.gomo.app.core.survey.exception.SurveyResultConstraintViolationException; -import com.gomo.app.core.survey.exception.SurveyResultErrorCode; +import com.gomo.app.core.survey.domain.exception.SurveyResultConstraintViolationException; +import com.gomo.app.core.survey.domain.exception.SurveyResultErrorCode; import lombok.Getter; diff --git a/src/main/java/com/gomo/app/support/auth/application/port/CreateAuthCodePortIn.java b/src/main/java/com/gomo/app/support/auth/application/port/CreateAuthCodePortIn.java deleted file mode 100644 index b2f3ba65..00000000 --- a/src/main/java/com/gomo/app/support/auth/application/port/CreateAuthCodePortIn.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.gomo.app.support.auth.application.port; - -public interface CreateAuthCodePortIn { - - /** - * Generates a new authentication code and sends it to the specified email. - * - * @param email The destination email address where the authentication code will be sent. - * @throws InvalidEmailFormatException if the provided email format is invalid. - * @throws RateLimitExceededException if requests are too frequent. - */ - String sendToEmail(String email); -} diff --git a/src/main/java/com/gomo/app/support/auth/application/port/VerifyAuthCodePortIn.java b/src/main/java/com/gomo/app/support/auth/application/port/VerifyAuthCodePortIn.java deleted file mode 100644 index ec564fcf..00000000 --- a/src/main/java/com/gomo/app/support/auth/application/port/VerifyAuthCodePortIn.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.gomo.app.support.auth.application.port; - -import com.gomo.app.support.auth.exception.InvalidAuthCodeException; - -public interface VerifyAuthCodePortIn { - - /** - * Verifies if the provided authentication code is valid for the given email. - *

- * This method has no return value. A successful execution implies that the code is valid. - * If the code is invalid or expired, an exception will be thrown. - * - * @param email The email address associated with the authentication code. - * @param authCode The user-submitted code to be verified. - * @throws InvalidAuthCodeException if the code does not match or if the code has expired. - */ - void verify(String email, String authCode); -} diff --git a/src/main/java/com/gomo/app/support/auth/application/usecase/AuthenticateUseCase.java b/src/main/java/com/gomo/app/support/auth/application/usecase/AuthenticateUseCase.java deleted file mode 100644 index 336390d2..00000000 --- a/src/main/java/com/gomo/app/support/auth/application/usecase/AuthenticateUseCase.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.gomo.app.support.auth.application.usecase; - -import java.util.UUID; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.common.security.jwt.application.port.VerifyJwtPortIn; -import com.gomo.app.core.member.application.port.LoginMemberPortIn; -import com.gomo.app.support.auth.application.port.dto.AuthTokenDto; -import com.gomo.app.support.auth.domain.model.AuthToken; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -public class AuthenticateUseCase { - - private final LoginMemberPortIn loginMemberPortIn; - private final VerifyJwtPortIn verifyJwtPortIn; - private final CreateAuthTokenInternalService createAuthTokenInternalService; - - @AuditLog(action = "AUTHENTICATE_PRINCIPAL") - public AuthTokenDto authenticate(String email, String password) { - UUID principalId = loginMemberPortIn.authenticate(email, password); - AuthToken authToken = createAuthTokenInternalService.create(principalId); - long expirationTime = verifyJwtPortIn.extractExpirationTime(authToken.getRefreshToken()); - return AuthTokenDto.of(principalId, authToken.getAccessToken(), authToken.getRefreshToken(), expirationTime); - } -} diff --git a/src/main/java/com/gomo/app/support/auth/application/usecase/CreateAuthCodeUseCase.java b/src/main/java/com/gomo/app/support/auth/application/usecase/CreateAuthCodeUseCase.java deleted file mode 100644 index c281e2cd..00000000 --- a/src/main/java/com/gomo/app/support/auth/application/usecase/CreateAuthCodeUseCase.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.gomo.app.support.auth.application.usecase; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.support.auth.application.port.CreateAuthCodePortIn; -import com.gomo.app.support.auth.application.port.SendAuthCodePortOut; -import com.gomo.app.support.auth.domain.model.AuthCode; -import com.gomo.app.support.auth.domain.repository.AuthCodeRepository; -import com.gomo.app.support.logging.AuditLog; - -import jakarta.transaction.Transactional; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -class CreateAuthCodeUseCase implements CreateAuthCodePortIn { - - private final SendAuthCodePortOut sendAuthCodePortOut; - private final AuthCodeRepository authCodeRepository; - - // TODO [2025-10-10] jhl221123 : 회원 도메인에 이메일 검증(Email.of())을 요청해야 합니다. - // TODO [2025-10-10] jhl221123 : 빈번한 요청에 대비해야 합니다. - @AuditLog(action = "SEND_AUTH_CODE") - @Override - public String sendToEmail(String email) { - AuthCode authCode = AuthCode.generate(); - authCodeRepository.save(email, authCode.getValue()); - sendAuthCodePortOut.toEmail(email, authCode.getValue()); - return authCode.getValue(); - } -} diff --git a/src/main/java/com/gomo/app/support/auth/application/usecase/CreateAuthTokenInternalService.java b/src/main/java/com/gomo/app/support/auth/application/usecase/CreateAuthTokenInternalService.java deleted file mode 100644 index acb55512..00000000 --- a/src/main/java/com/gomo/app/support/auth/application/usecase/CreateAuthTokenInternalService.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.gomo.app.support.auth.application.usecase; - -import java.util.UUID; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.common.security.jwt.application.port.GenerateJwtPortIn; -import com.gomo.app.support.auth.domain.model.AuthToken; -import com.gomo.app.support.auth.domain.repository.AuthTokenRepository; -import com.gomo.app.support.logging.AuditLog; - -import jakarta.transaction.Transactional; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Transactional -@ApplicationService -class CreateAuthTokenInternalService { - - private final GenerateJwtPortIn generateJwtPortIn; - private final AuthTokenRepository authTokenRepository; - - @AuditLog(action = "CREATE_AUTH_TOKEN") - public AuthToken create(UUID principalId) { - String accessToken = generateJwtPortIn.generateAccessToken(principalId); - String refreshToken = generateJwtPortIn.generateRefreshToken(principalId); - authTokenRepository.setRefreshToken(principalId, refreshToken); - return AuthToken.of(accessToken, refreshToken); - } -} diff --git a/src/main/java/com/gomo/app/support/auth/application/usecase/DeleteRefreshTokenUseCase.java b/src/main/java/com/gomo/app/support/auth/application/usecase/DeleteRefreshTokenUseCase.java deleted file mode 100644 index 52321ae6..00000000 --- a/src/main/java/com/gomo/app/support/auth/application/usecase/DeleteRefreshTokenUseCase.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.gomo.app.support.auth.application.usecase; - -import java.util.UUID; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.support.auth.application.port.DeleteAuthTokenPortIn; -import com.gomo.app.support.auth.domain.repository.AuthTokenRepository; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -class DeleteRefreshTokenUseCase implements DeleteAuthTokenPortIn { - - private final AuthTokenRepository authTokenRepository; - - @AuditLog(action = "DELETE_REFRESH_TOKEN") - @Override - public void deleteRefreshToken(UUID principalId) { - authTokenRepository.deleteRefreshToken(principalId); - } -} diff --git a/src/main/java/com/gomo/app/support/auth/application/usecase/OAuthUseCase.java b/src/main/java/com/gomo/app/support/auth/application/usecase/OAuthUseCase.java deleted file mode 100644 index e8758959..00000000 --- a/src/main/java/com/gomo/app/support/auth/application/usecase/OAuthUseCase.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.gomo.app.support.auth.application.usecase; - -import java.util.Optional; -import java.util.UUID; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.common.security.jwt.application.port.VerifyJwtPortIn; -import com.gomo.app.core.member.application.port.OAuthLoginMemberPortIn; -import com.gomo.app.support.auth.application.port.dto.OAuthTokenDto; -import com.gomo.app.support.auth.domain.model.AuthToken; -import com.gomo.app.support.auth.domain.model.OAuthPrincipal; -import com.gomo.app.support.auth.infrastructure.oauth.OAuthProviderFactory; -import com.gomo.app.support.auth.infrastructure.oauth.provider.OAuthProvider; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -public class OAuthUseCase { - - private final OAuthProviderFactory providerFactory; - private final OAuthLoginMemberPortIn oAuthLoginMemberPortIn; - private final CreateAuthTokenInternalService createAuthTokenInternalService; - private final VerifyJwtPortIn verifyJwtPortIn; - - @AuditLog(action = "FIND_OAUTH_PRINCIPAL") - public Optional findPrincipal(String providerName, String code) { - OAuthProvider provider = providerFactory.getProvider(providerName); - OAuthPrincipal principal = provider.authenticate(code); - - return oAuthLoginMemberPortIn.oauthAuthenticate(principal.getEmail()) - .map(principalId -> { - AuthToken authToken = createAuthTokenInternalService.create(principalId); - long refreshExpirationTime = verifyJwtPortIn.extractExpirationTime(authToken.getRefreshToken()); - return OAuthTokenDto.withToken( - principalId, - authToken.getAccessToken(), - authToken.getRefreshToken(), - refreshExpirationTime, - principal.getProvider().name(), - principal.getEmail(), - principal.getName() - ); - }) - .or(() -> Optional.of( - OAuthTokenDto.withoutToken( - principal.getProvider().name(), - principal.getEmail(), - principal.getName() - ) - )); - } -} diff --git a/src/main/java/com/gomo/app/support/auth/application/usecase/UpdateRefreshTokenUseCase.java b/src/main/java/com/gomo/app/support/auth/application/usecase/UpdateRefreshTokenUseCase.java deleted file mode 100644 index 0d936483..00000000 --- a/src/main/java/com/gomo/app/support/auth/application/usecase/UpdateRefreshTokenUseCase.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.gomo.app.support.auth.application.usecase; - -import java.util.UUID; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.common.security.jwt.application.port.VerifyJwtPortIn; -import com.gomo.app.support.auth.application.port.dto.AuthTokenDto; -import com.gomo.app.support.auth.domain.model.AuthToken; -import com.gomo.app.support.auth.domain.repository.AuthTokenRepository; -import com.gomo.app.support.auth.exception.AuthErrorCode; -import com.gomo.app.support.auth.exception.AuthenticationFailException; -import com.gomo.app.support.logging.AuditLog; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -public class UpdateRefreshTokenUseCase { - - private final CreateAuthTokenInternalService createAuthTokenInternalService; - private final VerifyJwtPortIn verifyJwtPortIn; - private final AuthTokenRepository authTokenRepository; - - @AuditLog(action = "REFRESH_TOKEN_UPDATE") - public AuthTokenDto update(String refreshToken) { - if (refreshToken == null) { - throw new AuthenticationFailException(AuthErrorCode.MISSING_REFRESH_TOKEN); - } - - UUID principalId = UUID.fromString(verifyJwtPortIn.extractSubject(refreshToken)); - String originRefreshToken = authTokenRepository.getRefreshToken(principalId); - if (!originRefreshToken.equals(refreshToken)) { - throw new AuthenticationFailException(AuthErrorCode.INVALID_REFRESH_TOKEN); - } - - AuthToken authToken = createAuthTokenInternalService.create(principalId); - long refreshTokenExpirationTime = verifyJwtPortIn.extractExpirationTime(authToken.getRefreshToken()); - return AuthTokenDto.of(principalId, authToken.getAccessToken(), authToken.getRefreshToken(), refreshTokenExpirationTime); - } -} diff --git a/src/main/java/com/gomo/app/support/auth/application/usecase/VerifyAuthCodeUseCase.java b/src/main/java/com/gomo/app/support/auth/application/usecase/VerifyAuthCodeUseCase.java deleted file mode 100644 index ddbaab66..00000000 --- a/src/main/java/com/gomo/app/support/auth/application/usecase/VerifyAuthCodeUseCase.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.gomo.app.support.auth.application.usecase; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.support.auth.application.port.VerifyAuthCodePortIn; -import com.gomo.app.support.auth.domain.repository.AuthCodeRepository; -import com.gomo.app.support.auth.exception.AuthErrorCode; -import com.gomo.app.support.auth.exception.InvalidAuthCodeException; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -class VerifyAuthCodeUseCase implements VerifyAuthCodePortIn { - - private final AuthCodeRepository authCodeRepository; - - @Override - public void verify(String email, String authCode) { - authCodeRepository.findByEmail(email) - .filter(code -> code.equals(authCode)) - .orElseThrow(() -> new InvalidAuthCodeException(AuthErrorCode.INVALID_AUTH_CODE)); - authCodeRepository.delete(email); - } -} diff --git a/src/main/java/com/gomo/app/support/auth/domain/repository/AuthTokenRepository.java b/src/main/java/com/gomo/app/support/auth/domain/repository/AuthTokenRepository.java deleted file mode 100644 index 30c69413..00000000 --- a/src/main/java/com/gomo/app/support/auth/domain/repository/AuthTokenRepository.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.gomo.app.support.auth.domain.repository; - -import java.util.UUID; - -public interface AuthTokenRepository { - - void setRefreshToken(UUID principalId, String refreshToken); - - String getRefreshToken(UUID principalId); - - void deleteRefreshToken(UUID principalId); -} diff --git a/src/main/java/com/gomo/app/support/auth/infrastructure/oauth/OAuthProviderFactory.java b/src/main/java/com/gomo/app/support/auth/infrastructure/oauth/OAuthProviderFactory.java deleted file mode 100644 index 844e867a..00000000 --- a/src/main/java/com/gomo/app/support/auth/infrastructure/oauth/OAuthProviderFactory.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.gomo.app.support.auth.infrastructure.oauth; - -import java.util.Map; - -import org.springframework.stereotype.Component; - -import com.gomo.app.support.auth.infrastructure.oauth.provider.OAuthProvider; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Component -public class OAuthProviderFactory { - - private final Map providers; - - public OAuthProvider getProvider(String providerName) { - OAuthProvider provider = providers.get(providerName); - if (provider == null) { - throw new IllegalArgumentException("Unsupported OAuth Provider: " + providerName); - } - return provider; - } -} diff --git a/src/main/java/com/gomo/app/support/auth/infrastructure/oauth/provider/OAuthProvider.java b/src/main/java/com/gomo/app/support/auth/infrastructure/oauth/provider/OAuthProvider.java deleted file mode 100644 index c54ad8a8..00000000 --- a/src/main/java/com/gomo/app/support/auth/infrastructure/oauth/provider/OAuthProvider.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.gomo.app.support.auth.infrastructure.oauth.provider; - -import com.gomo.app.support.auth.domain.model.OAuthPrincipal; - -public interface OAuthProvider { - - OAuthPrincipal authenticate(String code); -} diff --git a/src/main/java/com/gomo/app/support/auth/presentation/security/AuthInfo.java b/src/main/java/com/gomo/app/support/auth/presentation/security/AuthInfo.java deleted file mode 100644 index 0d85e038..00000000 --- a/src/main/java/com/gomo/app/support/auth/presentation/security/AuthInfo.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.gomo.app.support.auth.presentation.security; - -import lombok.Getter; - -import java.util.UUID; - -@Getter -public class AuthInfo { - - private UUID memberId; - - private AuthInfo(UUID memberId) { - this.memberId = memberId; - } - - public static AuthInfo of(UUID memberId) { - return new AuthInfo(memberId); - } -} diff --git a/src/main/java/com/gomo/app/support/evententry/application/usecase/ForwardEventEntryUseCase.java b/src/main/java/com/gomo/app/support/evententry/application/usecase/ForwardEventEntryUseCase.java index 436233b1..44fa47b1 100644 --- a/src/main/java/com/gomo/app/support/evententry/application/usecase/ForwardEventEntryUseCase.java +++ b/src/main/java/com/gomo/app/support/evententry/application/usecase/ForwardEventEntryUseCase.java @@ -11,7 +11,7 @@ import com.gomo.app.support.evententry.application.port.ForwardEventEntryPortIn; import com.gomo.app.support.evententry.domain.model.EventEntry; import com.gomo.app.support.evententry.domain.repository.EventEntryRepository; -import com.gomo.app.support.messagebroker.application.port.PublishMessagePortIn; +import com.gomo.app.support.messagebroker.application.port.in.MessagePublisher; import lombok.RequiredArgsConstructor; @@ -21,7 +21,7 @@ class ForwardEventEntryUseCase implements ForwardEventEntryPortIn { private final EventEntryRepository eventEntryRepository; private final EventRouter eventRouter; - private final PublishMessagePortIn publishMessagePortIn; + private final MessagePublisher messagePublisher; @Override public void execute(int size) { @@ -30,7 +30,7 @@ public void execute(int size) { String eventName = entry.getEventName(); String exchange = eventRouter.getExchange(eventName); String routingKey = eventRouter.getRoutingKey(eventName); - publishMessagePortIn.send(exchange, routingKey, JsonParser.toJson(entry)); + messagePublisher.send(exchange, routingKey, JsonParser.toJson(entry)); entry.update(EventStatus.PROCESSED); } } diff --git a/src/main/java/com/gomo/app/support/image/infrastructure/MinioImageAdapter.java b/src/main/java/com/gomo/app/support/image/adapter/out/client/MinioImageClient.java similarity index 94% rename from src/main/java/com/gomo/app/support/image/infrastructure/MinioImageAdapter.java rename to src/main/java/com/gomo/app/support/image/adapter/out/client/MinioImageClient.java index 6f842167..6a6b685e 100644 --- a/src/main/java/com/gomo/app/support/image/infrastructure/MinioImageAdapter.java +++ b/src/main/java/com/gomo/app/support/image/adapter/out/client/MinioImageClient.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.image.infrastructure; +package com.gomo.app.support.image.adapter.out.client; import java.io.IOException; import java.security.InvalidKeyException; @@ -12,7 +12,7 @@ import org.springframework.web.multipart.MultipartFile; import com.gomo.app.common.arch.Adapter; -import com.gomo.app.support.image.application.port.ManageImagePortOut; +import com.gomo.app.support.image.application.port.out.ImageStore; import com.gomo.app.support.image.exception.ImageErrorCode; import com.gomo.app.support.image.exception.ImageProcessingException; @@ -27,7 +27,7 @@ @RequiredArgsConstructor @Adapter -class MinioImageAdapter implements ManageImagePortOut { +class MinioImageClient implements ImageStore { private final MinioClient minioClient; diff --git a/src/main/java/com/gomo/app/support/image/application/port/DeleteImagePortIn.java b/src/main/java/com/gomo/app/support/image/application/port/in/ImageDeleter.java similarity index 63% rename from src/main/java/com/gomo/app/support/image/application/port/DeleteImagePortIn.java rename to src/main/java/com/gomo/app/support/image/application/port/in/ImageDeleter.java index f01fe6c7..c546e0c3 100644 --- a/src/main/java/com/gomo/app/support/image/application/port/DeleteImagePortIn.java +++ b/src/main/java/com/gomo/app/support/image/application/port/in/ImageDeleter.java @@ -1,6 +1,6 @@ -package com.gomo.app.support.image.application.port; +package com.gomo.app.support.image.application.port.in; -public interface DeleteImagePortIn { +public interface ImageDeleter { /** * Deletes an image specified by its URL. diff --git a/src/main/java/com/gomo/app/support/image/application/port/ReadImagePortIn.java b/src/main/java/com/gomo/app/support/image/application/port/in/ImageReader.java similarity index 68% rename from src/main/java/com/gomo/app/support/image/application/port/ReadImagePortIn.java rename to src/main/java/com/gomo/app/support/image/application/port/in/ImageReader.java index 8ef44913..bc65a6e9 100644 --- a/src/main/java/com/gomo/app/support/image/application/port/ReadImagePortIn.java +++ b/src/main/java/com/gomo/app/support/image/application/port/in/ImageReader.java @@ -1,8 +1,8 @@ -package com.gomo.app.support.image.application.port; +package com.gomo.app.support.image.application.port.in; import java.util.Set; -public interface ReadImagePortIn { +public interface ImageReader { /** * Retrieves all available image URLs. diff --git a/src/main/java/com/gomo/app/support/image/application/port/UploadImagePortIn.java b/src/main/java/com/gomo/app/support/image/application/port/in/ImageUploader.java similarity index 80% rename from src/main/java/com/gomo/app/support/image/application/port/UploadImagePortIn.java rename to src/main/java/com/gomo/app/support/image/application/port/in/ImageUploader.java index 78e02364..d7c1f263 100644 --- a/src/main/java/com/gomo/app/support/image/application/port/UploadImagePortIn.java +++ b/src/main/java/com/gomo/app/support/image/application/port/in/ImageUploader.java @@ -1,10 +1,10 @@ -package com.gomo.app.support.image.application.port; +package com.gomo.app.support.image.application.port.in; import java.util.Optional; import org.springframework.web.multipart.MultipartFile; -public interface UploadImagePortIn { +public interface ImageUploader { /** * Uploads a new image file. diff --git a/src/main/java/com/gomo/app/support/image/application/port/ManageImagePortOut.java b/src/main/java/com/gomo/app/support/image/application/port/out/ImageStore.java similarity index 91% rename from src/main/java/com/gomo/app/support/image/application/port/ManageImagePortOut.java rename to src/main/java/com/gomo/app/support/image/application/port/out/ImageStore.java index 4601801a..d72b2e23 100644 --- a/src/main/java/com/gomo/app/support/image/application/port/ManageImagePortOut.java +++ b/src/main/java/com/gomo/app/support/image/application/port/out/ImageStore.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.image.application.port; +package com.gomo.app.support.image.application.port.out; import java.util.Set; @@ -6,7 +6,7 @@ import com.gomo.app.support.image.exception.ImageProcessingException; -public interface ManageImagePortOut { +public interface ImageStore { /** * Saves the given image file to the underlying storage. diff --git a/src/main/java/com/gomo/app/support/image/application/service/ImageService.java b/src/main/java/com/gomo/app/support/image/application/service/ImageService.java new file mode 100644 index 00000000..2a040feb --- /dev/null +++ b/src/main/java/com/gomo/app/support/image/application/service/ImageService.java @@ -0,0 +1,40 @@ +package com.gomo.app.support.image.application.service; + +import java.util.Optional; +import java.util.Set; + +import org.springframework.web.multipart.MultipartFile; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.support.image.application.port.in.ImageDeleter; +import com.gomo.app.support.image.application.port.in.ImageReader; +import com.gomo.app.support.image.application.port.in.ImageUploader; +import com.gomo.app.support.image.application.port.out.ImageStore; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@ApplicationService +class ImageService implements ImageReader, ImageUploader, ImageDeleter { + + private final ImageStore imageStore; + + @Override + public Set readAllImages() { + return imageStore.findAllImageUrls(); + } + + @Override + public Optional upload(MultipartFile file) { + if (file == null || file.isEmpty()) { + return Optional.empty(); + } + String fileUrl = imageStore.save(file); + return Optional.of(fileUrl); + } + + @Override + public void delete(String imageUrl) { + imageStore.delete(imageUrl); + } +} diff --git a/src/main/java/com/gomo/app/support/image/application/usecase/DeleteImageUseCase.java b/src/main/java/com/gomo/app/support/image/application/usecase/DeleteImageUseCase.java deleted file mode 100644 index 646f9fff..00000000 --- a/src/main/java/com/gomo/app/support/image/application/usecase/DeleteImageUseCase.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.gomo.app.support.image.application.usecase; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.support.image.application.port.DeleteImagePortIn; -import com.gomo.app.support.image.application.port.ManageImagePortOut; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -public class DeleteImageUseCase implements DeleteImagePortIn { - - private final ManageImagePortOut manageImagePortOut; - - @Override - public void delete(String imageUrl) { - manageImagePortOut.delete(imageUrl); - } -} diff --git a/src/main/java/com/gomo/app/support/image/application/usecase/ReadImageUseCase.java b/src/main/java/com/gomo/app/support/image/application/usecase/ReadImageUseCase.java deleted file mode 100644 index 68b1d5ec..00000000 --- a/src/main/java/com/gomo/app/support/image/application/usecase/ReadImageUseCase.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.gomo.app.support.image.application.usecase; - -import java.util.Set; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.support.image.application.port.ManageImagePortOut; -import com.gomo.app.support.image.application.port.ReadImagePortIn; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -public class ReadImageUseCase implements ReadImagePortIn { - - private final ManageImagePortOut manageImagePortOut; - - @Override - public Set readAllImages() { - return manageImagePortOut.findAllImageUrls(); - } -} diff --git a/src/main/java/com/gomo/app/support/image/application/usecase/UploadImageUseCase.java b/src/main/java/com/gomo/app/support/image/application/usecase/UploadImageUseCase.java deleted file mode 100644 index b58847ac..00000000 --- a/src/main/java/com/gomo/app/support/image/application/usecase/UploadImageUseCase.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.gomo.app.support.image.application.usecase; - -import java.util.Optional; - -import org.springframework.web.multipart.MultipartFile; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.support.image.application.port.ManageImagePortOut; -import com.gomo.app.support.image.application.port.UploadImagePortIn; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -public class UploadImageUseCase implements UploadImagePortIn { - - private final ManageImagePortOut manageImagePortOut; - - @Override - public Optional upload(MultipartFile file) { - if (file == null || file.isEmpty()) { - return Optional.empty(); - } - String fileUrl = manageImagePortOut.save(file); - return Optional.of(fileUrl); - } -} diff --git a/src/main/java/com/gomo/app/support/logging/AuditLoggingAspect.java b/src/main/java/com/gomo/app/support/logging/AuditLoggingAspect.java index a7f56c30..9dcc412d 100644 --- a/src/main/java/com/gomo/app/support/logging/AuditLoggingAspect.java +++ b/src/main/java/com/gomo/app/support/logging/AuditLoggingAspect.java @@ -7,6 +7,8 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; +import com.gomo.app.common.logging.AuditLog; + import lombok.extern.slf4j.Slf4j; @Slf4j @@ -15,7 +17,7 @@ @Order(2) public class AuditLoggingAspect { - @Around("@annotation(com.gomo.app.support.logging.AuditLog)") + @Around("@annotation(com.gomo.app.common.logging.AuditLog)") public Object logAuditAction(ProceedingJoinPoint joinPoint) throws Throwable { MethodSignature signature = (MethodSignature)joinPoint.getSignature(); AuditLog auditLog = signature.getMethod().getAnnotation(AuditLog.class); diff --git a/src/main/java/com/gomo/app/support/logging/LoggingFilter.java b/src/main/java/com/gomo/app/support/logging/LoggingFilter.java index 85873d83..4596f7d6 100644 --- a/src/main/java/com/gomo/app/support/logging/LoggingFilter.java +++ b/src/main/java/com/gomo/app/support/logging/LoggingFilter.java @@ -80,6 +80,7 @@ private void loggingResponse(ContentCachingResponseWrapper wrappedResponse, Stri int status = wrappedResponse.getStatus(); String body; if (userAgent.contains("Prometheus")) { + // Condense prometheus health check messages body = "prometheus health check message..."; } else { body = new String(wrappedResponse.getContentAsByteArray(), wrappedResponse.getCharacterEncoding()); diff --git a/src/main/java/com/gomo/app/support/messagebroker/infrastructure/adapter/RabbitMQClient.java b/src/main/java/com/gomo/app/support/messagebroker/adapter/out/client/RabbitMQClient.java similarity index 79% rename from src/main/java/com/gomo/app/support/messagebroker/infrastructure/adapter/RabbitMQClient.java rename to src/main/java/com/gomo/app/support/messagebroker/adapter/out/client/RabbitMQClient.java index b8548d0d..e276f218 100644 --- a/src/main/java/com/gomo/app/support/messagebroker/infrastructure/adapter/RabbitMQClient.java +++ b/src/main/java/com/gomo/app/support/messagebroker/adapter/out/client/RabbitMQClient.java @@ -1,9 +1,9 @@ -package com.gomo.app.support.messagebroker.infrastructure.adapter; +package com.gomo.app.support.messagebroker.adapter.out.client; import org.springframework.amqp.rabbit.core.RabbitTemplate; import com.gomo.app.common.arch.Adapter; -import com.gomo.app.support.messagebroker.application.port.MessageBrokerClientPortOut; +import com.gomo.app.support.messagebroker.application.port.out.MessageBrokerManager; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -11,7 +11,7 @@ @Slf4j @RequiredArgsConstructor @Adapter -class RabbitMQClient implements MessageBrokerClientPortOut { +class RabbitMQClient implements MessageBrokerManager { private final RabbitTemplate rabbitTemplate; diff --git a/src/main/java/com/gomo/app/support/messagebroker/infrastructure/adapter/JdbcProcessedDirectEventRepository.java b/src/main/java/com/gomo/app/support/messagebroker/adapter/out/repository/JdbcProcessedDirectEventRepository.java similarity index 93% rename from src/main/java/com/gomo/app/support/messagebroker/infrastructure/adapter/JdbcProcessedDirectEventRepository.java rename to src/main/java/com/gomo/app/support/messagebroker/adapter/out/repository/JdbcProcessedDirectEventRepository.java index 06024036..951aef41 100644 --- a/src/main/java/com/gomo/app/support/messagebroker/infrastructure/adapter/JdbcProcessedDirectEventRepository.java +++ b/src/main/java/com/gomo/app/support/messagebroker/adapter/out/repository/JdbcProcessedDirectEventRepository.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.messagebroker.infrastructure.adapter; +package com.gomo.app.support.messagebroker.adapter.out.repository; import org.springframework.jdbc.core.JdbcTemplate; diff --git a/src/main/java/com/gomo/app/support/messagebroker/application/PublishMessageUseCase.java b/src/main/java/com/gomo/app/support/messagebroker/application/PublishMessageUseCase.java deleted file mode 100644 index f1f0bc52..00000000 --- a/src/main/java/com/gomo/app/support/messagebroker/application/PublishMessageUseCase.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.gomo.app.support.messagebroker.application; - -import com.gomo.app.common.arch.ApplicationService; -import com.gomo.app.support.logging.AuditLog; -import com.gomo.app.support.messagebroker.application.port.MessageBrokerClientPortOut; -import com.gomo.app.support.messagebroker.application.port.PublishMessagePortIn; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@ApplicationService -class PublishMessageUseCase implements PublishMessagePortIn { - - private final MessageBrokerClientPortOut messageBrokerClientPortOut; - - @AuditLog(action = "PUBLISH_MESSAGE") - @Override - public void send(String destination, String key, String message) { - messageBrokerClientPortOut.send(destination, key, message); - } -} diff --git a/src/main/java/com/gomo/app/support/messagebroker/application/port/IdempotentDirectEventConsumer.java b/src/main/java/com/gomo/app/support/messagebroker/application/port/in/IdempotentDirectEventConsumer.java similarity index 95% rename from src/main/java/com/gomo/app/support/messagebroker/application/port/IdempotentDirectEventConsumer.java rename to src/main/java/com/gomo/app/support/messagebroker/application/port/in/IdempotentDirectEventConsumer.java index d03067cf..bd2eee0f 100644 --- a/src/main/java/com/gomo/app/support/messagebroker/application/port/IdempotentDirectEventConsumer.java +++ b/src/main/java/com/gomo/app/support/messagebroker/application/port/in/IdempotentDirectEventConsumer.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.messagebroker.application.port; +package com.gomo.app.support.messagebroker.application.port.in; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/com/gomo/app/support/messagebroker/application/port/PublishMessagePortIn.java b/src/main/java/com/gomo/app/support/messagebroker/application/port/in/MessagePublisher.java similarity index 86% rename from src/main/java/com/gomo/app/support/messagebroker/application/port/PublishMessagePortIn.java rename to src/main/java/com/gomo/app/support/messagebroker/application/port/in/MessagePublisher.java index d03e7ee2..1f7d6ef8 100644 --- a/src/main/java/com/gomo/app/support/messagebroker/application/port/PublishMessagePortIn.java +++ b/src/main/java/com/gomo/app/support/messagebroker/application/port/in/MessagePublisher.java @@ -1,6 +1,6 @@ -package com.gomo.app.support.messagebroker.application.port; +package com.gomo.app.support.messagebroker.application.port.in; -public interface PublishMessagePortIn { +public interface MessagePublisher { /** * Publishes a message to a specific destination with a given key. diff --git a/src/main/java/com/gomo/app/support/messagebroker/application/port/MessageBrokerClientPortOut.java b/src/main/java/com/gomo/app/support/messagebroker/application/port/out/MessageBrokerManager.java similarity index 84% rename from src/main/java/com/gomo/app/support/messagebroker/application/port/MessageBrokerClientPortOut.java rename to src/main/java/com/gomo/app/support/messagebroker/application/port/out/MessageBrokerManager.java index 69d69f41..7db7bd78 100644 --- a/src/main/java/com/gomo/app/support/messagebroker/application/port/MessageBrokerClientPortOut.java +++ b/src/main/java/com/gomo/app/support/messagebroker/application/port/out/MessageBrokerManager.java @@ -1,6 +1,6 @@ -package com.gomo.app.support.messagebroker.application.port; +package com.gomo.app.support.messagebroker.application.port.out; -public interface MessageBrokerClientPortOut { +public interface MessageBrokerManager { /** * Publishes a message to a specific destination with a given key. diff --git a/src/main/java/com/gomo/app/support/messagebroker/infrastructure/aspect/IdempotentDirectEventConsumerAspect.java b/src/main/java/com/gomo/app/support/messagebroker/application/service/IdempotentDirectEventConsumerAspect.java similarity index 96% rename from src/main/java/com/gomo/app/support/messagebroker/infrastructure/aspect/IdempotentDirectEventConsumerAspect.java rename to src/main/java/com/gomo/app/support/messagebroker/application/service/IdempotentDirectEventConsumerAspect.java index d7063852..43b3653d 100644 --- a/src/main/java/com/gomo/app/support/messagebroker/infrastructure/aspect/IdempotentDirectEventConsumerAspect.java +++ b/src/main/java/com/gomo/app/support/messagebroker/application/service/IdempotentDirectEventConsumerAspect.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.messagebroker.infrastructure.aspect; +package com.gomo.app.support.messagebroker.application.service; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; @@ -33,7 +33,7 @@ public class IdempotentDirectEventConsumerAspect { * @return The result of the original method execution, or null if skipped. * @throws Throwable if the intercepted method throws an exception, triggering a transaction rollback. */ - @Around("@annotation(com.gomo.app.support.messagebroker.application.port.IdempotentDirectEventConsumer)") + @Around("@annotation(com.gomo.app.support.messagebroker.application.port.in.IdempotentDirectEventConsumer)") @Transactional(rollbackFor = Exception.class) public Object handleEvent(ProceedingJoinPoint joinPoint) throws Throwable { DirectEvent directEvent = findDirectEvent(joinPoint); diff --git a/src/main/java/com/gomo/app/support/messagebroker/application/service/MessagePublishService.java b/src/main/java/com/gomo/app/support/messagebroker/application/service/MessagePublishService.java new file mode 100644 index 00000000..2c1aa953 --- /dev/null +++ b/src/main/java/com/gomo/app/support/messagebroker/application/service/MessagePublishService.java @@ -0,0 +1,21 @@ +package com.gomo.app.support.messagebroker.application.service; + +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.logging.AuditLog; +import com.gomo.app.support.messagebroker.application.port.in.MessagePublisher; +import com.gomo.app.support.messagebroker.application.port.out.MessageBrokerManager; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@ApplicationService +class MessagePublishService implements MessagePublisher { + + private final MessageBrokerManager messageBrokerManager; + + @Override + @AuditLog(action = "MESSAGE_PUBLISH") + public void send(String destination, String key, String message) { + messageBrokerManager.send(destination, key, message); + } +} diff --git a/src/test/java/com/gomo/app/common/web/ApplicationExceptionAdviceTest.java b/src/test/java/com/gomo/app/common/web/ApplicationExceptionAdviceTest.java index 5d156d78..b234cfcf 100644 --- a/src/test/java/com/gomo/app/common/web/ApplicationExceptionAdviceTest.java +++ b/src/test/java/com/gomo/app/common/web/ApplicationExceptionAdviceTest.java @@ -17,7 +17,7 @@ import org.springframework.web.multipart.MaxUploadSizeExceededException; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.support.auth.presentation.security.AuthenticationFilter; +import com.gomo.app.core.auth.adapter.in.security.AuthenticationFilter; @WebMvcTest( controllers = ApplicationExceptionAdvice.class, diff --git a/src/test/java/com/gomo/app/core/member/documentation/CreatePasswordAuthCodeDocumentationTest.java b/src/test/java/com/gomo/app/core/auth/adapter/in/api/CreateAuthCodeForPasswordResetDocumentationTest.java similarity index 62% rename from src/test/java/com/gomo/app/core/member/documentation/CreatePasswordAuthCodeDocumentationTest.java rename to src/test/java/com/gomo/app/core/auth/adapter/in/api/CreateAuthCodeForPasswordResetDocumentationTest.java index 2bbdde22..033ddcf1 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/CreatePasswordAuthCodeDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/auth/adapter/in/api/CreateAuthCodeForPasswordResetDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation; +package com.gomo.app.core.auth.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -10,15 +10,15 @@ import org.junit.jupiter.api.Test; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.member.documentation.snippet.CreatePasswordAuthCodeSnippet; -import com.gomo.app.core.member.exception.code.MemberErrorCode; -import com.gomo.app.core.member.presentation.request.CreateEmailCodeRequest; +import com.gomo.app.core.auth.adapter.in.api.request.CreateEmailCodeRequest; +import com.gomo.app.core.auth.adapter.in.api.snippet.CreatePasswordAuthCodeSnippet; +import com.gomo.app.core.auth.domain.exception.AuthErrorCode; import com.gomo.app.test.DocumentationTestBase; -@DisplayName("[Presentation Documentation]: 이메일 인증 코드 테스트") -public class CreatePasswordAuthCodeDocumentationTest extends DocumentationTestBase { +@DisplayName("[Presentation Documentation]: 비밀번호 초기화를 위한 이메일 인증 코드 테스트") +public class CreateAuthCodeForPasswordResetDocumentationTest extends DocumentationTestBase { - private static final String URL = "/members/emails/codes/passwords/reset"; + private static final String URL = "/auth/codes/emails/passwords/reset"; private final RestDocumentationFilter filter = CreatePasswordAuthCodeSnippet.create(); private final RestDocumentationFilter errorFilter = CreatePasswordAuthCodeSnippet.createError(); @@ -44,11 +44,11 @@ void create_auth_code_with_nonexistent_email() { .when() .post(URL) .then() - .statusCode(MemberErrorCode.NOT_FOUND.getHttpStatus()) + .statusCode(AuthErrorCode.PRINCIPAL_NOT_FOUND.getHttpStatus()) .body("timestamp", instanceOf(String.class)) .body("path", equalTo(URL)) - .body("httpStatus", equalTo(MemberErrorCode.NOT_FOUND.getHttpStatus())) - .body("code", equalTo(MemberErrorCode.NOT_FOUND.getErrorCode())) - .body("message", equalTo(MemberErrorCode.NOT_FOUND.getMessage())); + .body("httpStatus", equalTo(AuthErrorCode.PRINCIPAL_NOT_FOUND.getHttpStatus())) + .body("code", equalTo(AuthErrorCode.PRINCIPAL_NOT_FOUND.getErrorCode())) + .body("message", equalTo(AuthErrorCode.PRINCIPAL_NOT_FOUND.getMessage())); } } diff --git a/src/test/java/com/gomo/app/core/member/documentation/CreateEmailAuthCodeDocumentationTest.java b/src/test/java/com/gomo/app/core/auth/adapter/in/api/CreateAuthCodeForSignupDocumentationTest.java similarity index 63% rename from src/test/java/com/gomo/app/core/member/documentation/CreateEmailAuthCodeDocumentationTest.java rename to src/test/java/com/gomo/app/core/auth/adapter/in/api/CreateAuthCodeForSignupDocumentationTest.java index ef89be62..5f16e586 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/CreateEmailAuthCodeDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/auth/adapter/in/api/CreateAuthCodeForSignupDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation; +package com.gomo.app.core.auth.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -10,15 +10,15 @@ import org.junit.jupiter.api.Test; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.member.documentation.snippet.CreateEmailAuthCodeSnippet; -import com.gomo.app.core.member.exception.code.EmailErrorCode; -import com.gomo.app.core.member.presentation.request.CreateEmailCodeRequest; +import com.gomo.app.core.auth.adapter.in.api.request.CreateEmailCodeRequest; +import com.gomo.app.core.auth.adapter.in.api.snippet.CreateEmailAuthCodeSnippet; +import com.gomo.app.core.auth.domain.exception.AuthErrorCode; import com.gomo.app.test.DocumentationTestBase; -@DisplayName("[Presentation Documentation]: 이메일 인증 코드 테스트") -public class CreateEmailAuthCodeDocumentationTest extends DocumentationTestBase { +@DisplayName("[Presentation Documentation]: 회원 가입을 위한 이메일 인증 코드 테스트") +public class CreateAuthCodeForSignupDocumentationTest extends DocumentationTestBase { - private static final String URL = "/members/emails/codes/signup"; + private static final String URL = "/auth/codes/emails/signup"; private final RestDocumentationFilter filter = CreateEmailAuthCodeSnippet.create(); private final RestDocumentationFilter errorFilter = CreateEmailAuthCodeSnippet.createError(); @@ -44,11 +44,11 @@ void create_auth_code_with_duplicated_email() { .when() .post(URL) .then() - .statusCode(EmailErrorCode.DUPLICATED.getHttpStatus()) + .statusCode(AuthErrorCode.PRINCIPAL_DUPLICATED.getHttpStatus()) .body("timestamp", instanceOf(String.class)) .body("path", equalTo(URL)) - .body("httpStatus", equalTo(EmailErrorCode.DUPLICATED.getHttpStatus())) - .body("code", equalTo(EmailErrorCode.DUPLICATED.getErrorCode())) - .body("message", equalTo(EmailErrorCode.DUPLICATED.getMessage())); + .body("httpStatus", equalTo(AuthErrorCode.PRINCIPAL_DUPLICATED.getHttpStatus())) + .body("code", equalTo(AuthErrorCode.PRINCIPAL_DUPLICATED.getErrorCode())) + .body("message", equalTo(AuthErrorCode.PRINCIPAL_DUPLICATED.getMessage())); } } diff --git a/src/test/java/com/gomo/app/support/auth/documentation/LoginMemberDocumentationTest.java b/src/test/java/com/gomo/app/core/auth/adapter/in/api/LoginDocumentationTest.java similarity index 78% rename from src/test/java/com/gomo/app/support/auth/documentation/LoginMemberDocumentationTest.java rename to src/test/java/com/gomo/app/core/auth/adapter/in/api/LoginDocumentationTest.java index 75fa7dd3..791fbf84 100644 --- a/src/test/java/com/gomo/app/support/auth/documentation/LoginMemberDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/auth/adapter/in/api/LoginDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.documentation; +package com.gomo.app.core.auth.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -9,12 +9,12 @@ import org.junit.jupiter.api.Test; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.support.auth.documentation.snippet.LoginMemberSnippet; -import com.gomo.app.support.auth.presentation.request.LoginRequest; +import com.gomo.app.core.auth.adapter.in.api.request.LoginRequest; +import com.gomo.app.core.auth.adapter.in.api.snippet.LoginMemberSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation Documentation]: 회원 로그인 테스트") -public class LoginMemberDocumentationTest extends DocumentationTestBase { +public class LoginDocumentationTest extends DocumentationTestBase { private static final String URL = "/auth/login"; diff --git a/src/test/java/com/gomo/app/support/auth/documentation/LogoutMemberDocumentationTest.java b/src/test/java/com/gomo/app/core/auth/adapter/in/api/LogoutDocumentationTest.java similarity index 83% rename from src/test/java/com/gomo/app/support/auth/documentation/LogoutMemberDocumentationTest.java rename to src/test/java/com/gomo/app/core/auth/adapter/in/api/LogoutDocumentationTest.java index 3f39f469..e3a6ea99 100644 --- a/src/test/java/com/gomo/app/support/auth/documentation/LogoutMemberDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/auth/adapter/in/api/LogoutDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.documentation; +package com.gomo.app.core.auth.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -9,11 +9,11 @@ import org.junit.jupiter.api.Test; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.support.auth.documentation.snippet.LogoutMemberSnippet; +import com.gomo.app.core.auth.adapter.in.api.snippet.LogoutMemberSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation Documentation]: 회원 로그아웃 테스트") -public class LogoutMemberDocumentationTest extends DocumentationTestBase { +public class LogoutDocumentationTest extends DocumentationTestBase { private static final String LOGOUT_MEMBER_URL = "/auth/logout"; private final RestDocumentationFilter filter = LogoutMemberSnippet.create(); diff --git a/src/test/java/com/gomo/app/support/auth/documentation/RefreshTokenDocumentationTest.java b/src/test/java/com/gomo/app/core/auth/adapter/in/api/RefreshTokenDocumentationTest.java similarity index 89% rename from src/test/java/com/gomo/app/support/auth/documentation/RefreshTokenDocumentationTest.java rename to src/test/java/com/gomo/app/core/auth/adapter/in/api/RefreshTokenDocumentationTest.java index 69d33cf0..2f16657a 100644 --- a/src/test/java/com/gomo/app/support/auth/documentation/RefreshTokenDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/auth/adapter/in/api/RefreshTokenDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.documentation; +package com.gomo.app.core.auth.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -9,7 +9,7 @@ import org.junit.jupiter.api.Test; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.support.auth.documentation.snippet.RefreshTokenSnippet; +import com.gomo.app.core.auth.adapter.in.api.snippet.RefreshTokenSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation Documentation]: Refresh Token 재발급 테스트") diff --git a/src/test/java/com/gomo/app/core/member/documentation/CreateMemberDocumentationTest.java b/src/test/java/com/gomo/app/core/auth/adapter/in/api/SignupDocumentationTest.java similarity index 53% rename from src/test/java/com/gomo/app/core/member/documentation/CreateMemberDocumentationTest.java rename to src/test/java/com/gomo/app/core/auth/adapter/in/api/SignupDocumentationTest.java index b4679b75..d958011c 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/CreateMemberDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/auth/adapter/in/api/SignupDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation; +package com.gomo.app.core.auth.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -12,22 +12,22 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.member.documentation.snippet.CreateMemberSnippet; +import com.gomo.app.core.auth.adapter.in.api.request.CreateEmailCodeRequest; +import com.gomo.app.core.auth.adapter.in.api.request.CreatePrincipalRequest; +import com.gomo.app.core.auth.adapter.in.api.request.VerifyEmailCodeRequest; +import com.gomo.app.core.auth.adapter.in.api.snippet.SignupSnippet; +import com.gomo.app.core.auth.domain.repository.AuthCodeRepository; import com.gomo.app.core.member.domain.model.LoginProvider; import com.gomo.app.core.member.domain.repository.MemberRepository; -import com.gomo.app.core.member.presentation.EmailCodeApi; -import com.gomo.app.core.member.presentation.request.CreateEmailCodeRequest; -import com.gomo.app.core.member.presentation.request.CreateMemberRequest; -import com.gomo.app.core.member.presentation.request.VerifyEmailCodeRequest; import com.gomo.app.test.DocumentationTestBase; -@DisplayName("[Presentation Documentation]: 회원 생성 테스트") -public class CreateMemberDocumentationTest extends DocumentationTestBase { +@DisplayName("[Presentation Documentation]: 회원 가입 테스트") +public class SignupDocumentationTest extends DocumentationTestBase { - private static final String CREATE_MEMBER_URL = "/members"; + private static final String URL = "/auth/signup"; - private final RestDocumentationFilter filter = CreateMemberSnippet.create(); - private final RestDocumentationFilter errorFilter = CreateMemberSnippet.createError(); + private final RestDocumentationFilter filter = SignupSnippet.create(); + private final RestDocumentationFilter errorFilter = SignupSnippet.createError(); @Autowired private EmailCodeApi emailCodeApi; @@ -35,23 +35,27 @@ public class CreateMemberDocumentationTest extends DocumentationTestBase { @Autowired private MemberRepository memberRepository; + @Autowired + private AuthCodeRepository authCodeRepository; + @AfterEach void tearDown() { memberRepository.deleteAllInBatch(); } - @DisplayName("사용자를 등록한다.") + @DisplayName("회원 가입한다.") @Test void create_member() { String email = "gomotest3@naver.com"; - String emailCode = emailCodeApi.create(CreateEmailCodeRequest.of(email)).getBody().getCode(); + emailCodeApi.create(CreateEmailCodeRequest.of(email)); + String emailCode = authCodeRepository.findByEmail(email).get(); String temporaryToken = emailCodeApi.verify(VerifyEmailCodeRequest.of(email, emailCode)).getBody().getTemporaryToken(); given(this.specification).filter(filter) .header(CONTENT_TYPE, APPLICATION_JSON_VALUE) - .body(CreateMemberRequest.of(email, "Test123@", "@GOMOTEST3", "gomotest3", "TEST MOTTO", LoginProvider.EMAIL.name(), temporaryToken)) + .body(CreatePrincipalRequest.of(email, "Test123@", "@GOMOTEST3", "gomotest3", "TEST MOTTO", LoginProvider.EMAIL.name(), temporaryToken)) .when() - .post(CREATE_MEMBER_URL) + .post(URL) .then() .statusCode(CREATED.value()) .body("id", hasLength(36)); diff --git a/src/test/java/com/gomo/app/core/member/documentation/VerifyEmailAuthCodeDocumentationTest.java b/src/test/java/com/gomo/app/core/auth/adapter/in/api/VerifyEmailCodeDocumentationTest.java similarity index 74% rename from src/test/java/com/gomo/app/core/member/documentation/VerifyEmailAuthCodeDocumentationTest.java rename to src/test/java/com/gomo/app/core/auth/adapter/in/api/VerifyEmailCodeDocumentationTest.java index 63b9d056..69bad025 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/VerifyEmailAuthCodeDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/auth/adapter/in/api/VerifyEmailCodeDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation; +package com.gomo.app.core.auth.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -12,23 +12,23 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.member.documentation.snippet.VerifyEmailAuthCodeSnippet; -import com.gomo.app.core.member.presentation.request.VerifyEmailCodeRequest; -import com.gomo.app.support.auth.application.port.CreateAuthCodePortIn; -import com.gomo.app.support.auth.domain.repository.AuthCodeRepository; -import com.gomo.app.support.auth.exception.AuthErrorCode; +import com.gomo.app.core.auth.adapter.in.api.request.VerifyEmailCodeRequest; +import com.gomo.app.core.auth.adapter.in.api.snippet.VerifyEmailAuthCodeSnippet; +import com.gomo.app.core.auth.application.port.in.AuthCodeIssuer; +import com.gomo.app.core.auth.domain.exception.AuthErrorCode; +import com.gomo.app.core.auth.domain.repository.AuthCodeRepository; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation Documentation]: 이메일 인증 코드 테스트") -public class VerifyEmailAuthCodeDocumentationTest extends DocumentationTestBase { +public class VerifyEmailCodeDocumentationTest extends DocumentationTestBase { - private static final String URL = "/members/emails/codes/verify"; + private static final String URL = "/auth/codes/emails/verify"; private final RestDocumentationFilter filter = VerifyEmailAuthCodeSnippet.create(); private final RestDocumentationFilter errorFilter = VerifyEmailAuthCodeSnippet.createError(); @Autowired - CreateAuthCodePortIn createAuthCodePortIn; + AuthCodeIssuer authCodeIssuer; @Autowired AuthCodeRepository authCodeRepository; @@ -41,7 +41,7 @@ void teardown() { @DisplayName("사용자가 올바른 인증코드를 이용하여 검증한다.") @Test void verify_email_auth_code_with_correct_code() { - createAuthCodePortIn.sendToEmail(sessionEmail); + authCodeIssuer.issueForPasswordReset(sessionEmail); String authCode = authCodeRepository.findByEmail(sessionEmail).get(); given(this.specification).filter(filter) .header(CONTENT_TYPE, APPLICATION_JSON_VALUE) @@ -57,7 +57,7 @@ void verify_email_auth_code_with_correct_code() { void verify_email_auth_code_with_incorrect_code() { given(this.specification).filter(errorFilter) .header(CONTENT_TYPE, APPLICATION_JSON_VALUE) - .body(VerifyEmailCodeRequest.of(sessionEmail, "000000")) + .body(VerifyEmailCodeRequest.of(sessionEmail, "00000")) .when() .post(URL) .then() diff --git a/src/test/java/com/gomo/app/core/member/documentation/snippet/CreateEmailAuthCodeSnippet.java b/src/test/java/com/gomo/app/core/auth/adapter/in/api/snippet/CreateEmailAuthCodeSnippet.java similarity index 91% rename from src/test/java/com/gomo/app/core/member/documentation/snippet/CreateEmailAuthCodeSnippet.java rename to src/test/java/com/gomo/app/core/auth/adapter/in/api/snippet/CreateEmailAuthCodeSnippet.java index f2618fa1..d4ea463b 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/snippet/CreateEmailAuthCodeSnippet.java +++ b/src/test/java/com/gomo/app/core/auth/adapter/in/api/snippet/CreateEmailAuthCodeSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation.snippet; +package com.gomo.app.core.auth.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; @@ -14,7 +14,7 @@ public class CreateEmailAuthCodeSnippet { - private static final String IDENTIFIER = "member-email-auth-code-create"; + private static final String IDENTIFIER = "auth-code-for-sign-up-create"; private static final Snippet REQUEST_HEADERS = requestHeaders( headerWithName(CONTENT_TYPE).description("Content-Type: `application/json`") diff --git a/src/test/java/com/gomo/app/core/member/documentation/snippet/CreatePasswordAuthCodeSnippet.java b/src/test/java/com/gomo/app/core/auth/adapter/in/api/snippet/CreatePasswordAuthCodeSnippet.java similarity index 91% rename from src/test/java/com/gomo/app/core/member/documentation/snippet/CreatePasswordAuthCodeSnippet.java rename to src/test/java/com/gomo/app/core/auth/adapter/in/api/snippet/CreatePasswordAuthCodeSnippet.java index b96e8f4a..ca22607d 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/snippet/CreatePasswordAuthCodeSnippet.java +++ b/src/test/java/com/gomo/app/core/auth/adapter/in/api/snippet/CreatePasswordAuthCodeSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation.snippet; +package com.gomo.app.core.auth.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; @@ -14,7 +14,7 @@ public class CreatePasswordAuthCodeSnippet { - private static final String IDENTIFIER = "member-password-auth-code-create"; + private static final String IDENTIFIER = "auth-code-for-password-reset-create"; private static final Snippet REQUEST_HEADERS = requestHeaders( headerWithName(CONTENT_TYPE).description("Content-Type: `application/json`") diff --git a/src/test/java/com/gomo/app/support/auth/documentation/snippet/LoginMemberSnippet.java b/src/test/java/com/gomo/app/core/auth/adapter/in/api/snippet/LoginMemberSnippet.java similarity index 96% rename from src/test/java/com/gomo/app/support/auth/documentation/snippet/LoginMemberSnippet.java rename to src/test/java/com/gomo/app/core/auth/adapter/in/api/snippet/LoginMemberSnippet.java index aa42b3cd..d5f29eb1 100644 --- a/src/test/java/com/gomo/app/support/auth/documentation/snippet/LoginMemberSnippet.java +++ b/src/test/java/com/gomo/app/core/auth/adapter/in/api/snippet/LoginMemberSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.documentation.snippet; +package com.gomo.app.core.auth.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/support/auth/documentation/snippet/LogoutMemberSnippet.java b/src/test/java/com/gomo/app/core/auth/adapter/in/api/snippet/LogoutMemberSnippet.java similarity index 95% rename from src/test/java/com/gomo/app/support/auth/documentation/snippet/LogoutMemberSnippet.java rename to src/test/java/com/gomo/app/core/auth/adapter/in/api/snippet/LogoutMemberSnippet.java index 008411de..f1eeae2e 100644 --- a/src/test/java/com/gomo/app/support/auth/documentation/snippet/LogoutMemberSnippet.java +++ b/src/test/java/com/gomo/app/core/auth/adapter/in/api/snippet/LogoutMemberSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.documentation.snippet; +package com.gomo.app.core.auth.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/support/auth/documentation/snippet/RefreshTokenSnippet.java b/src/test/java/com/gomo/app/core/auth/adapter/in/api/snippet/RefreshTokenSnippet.java similarity index 97% rename from src/test/java/com/gomo/app/support/auth/documentation/snippet/RefreshTokenSnippet.java rename to src/test/java/com/gomo/app/core/auth/adapter/in/api/snippet/RefreshTokenSnippet.java index bf357aa7..3db462ad 100644 --- a/src/test/java/com/gomo/app/support/auth/documentation/snippet/RefreshTokenSnippet.java +++ b/src/test/java/com/gomo/app/core/auth/adapter/in/api/snippet/RefreshTokenSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.documentation.snippet; +package com.gomo.app.core.auth.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.cookies.CookieDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/member/documentation/snippet/CreateMemberSnippet.java b/src/test/java/com/gomo/app/core/auth/adapter/in/api/snippet/SignupSnippet.java similarity index 93% rename from src/test/java/com/gomo/app/core/member/documentation/snippet/CreateMemberSnippet.java rename to src/test/java/com/gomo/app/core/auth/adapter/in/api/snippet/SignupSnippet.java index 3ca628cb..f37e548d 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/snippet/CreateMemberSnippet.java +++ b/src/test/java/com/gomo/app/core/auth/adapter/in/api/snippet/SignupSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation.snippet; +package com.gomo.app.core.auth.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; @@ -12,8 +12,8 @@ import com.gomo.app.test.ErrorResponseFields; -public class CreateMemberSnippet { - private static final String IDENTIFIER = "member-create"; +public class SignupSnippet { + private static final String IDENTIFIER = "auth-signup"; private static final Snippet REQUEST_HEADERS = requestHeaders( headerWithName(CONTENT_TYPE).description("Content-Type: `application/json`") diff --git a/src/test/java/com/gomo/app/core/member/documentation/snippet/VerifyEmailAuthCodeSnippet.java b/src/test/java/com/gomo/app/core/auth/adapter/in/api/snippet/VerifyEmailAuthCodeSnippet.java similarity index 86% rename from src/test/java/com/gomo/app/core/member/documentation/snippet/VerifyEmailAuthCodeSnippet.java rename to src/test/java/com/gomo/app/core/auth/adapter/in/api/snippet/VerifyEmailAuthCodeSnippet.java index 40f25e77..b1c5e60a 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/snippet/VerifyEmailAuthCodeSnippet.java +++ b/src/test/java/com/gomo/app/core/auth/adapter/in/api/snippet/VerifyEmailAuthCodeSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation.snippet; +package com.gomo.app.core.auth.adapter.in.api.snippet; import static org.springframework.restdocs.operation.preprocess.Preprocessors.*; import static org.springframework.restdocs.payload.PayloadDocumentation.*; @@ -11,7 +11,7 @@ import com.gomo.app.test.ErrorResponseFields; public class VerifyEmailAuthCodeSnippet { - private static final String IDENTIFIER = "member-email-auth-code-verify"; + private static final String IDENTIFIER = "auth-code-verify"; private static final Snippet REQUEST_FIELDS = requestFields( fieldWithPath("email").description("인증 코드를 받은 이메일 주소"), @@ -19,7 +19,7 @@ public class VerifyEmailAuthCodeSnippet { ); private static final Snippet RESPONSE_FIELDS = responseFields( - fieldWithPath("temporaryToken").type(JsonFieldType.STRING).description("인증된 이메일임을 확인하기 위한 임시 코드") + fieldWithPath("temporaryToken").type(JsonFieldType.STRING).description("인증된 이메일임을 확인하기 위한 임시 토큰") ); public static RestDocumentationFilter create() { diff --git a/src/test/java/com/gomo/app/core/auth/adapter/out/client/MemberClientTest.java b/src/test/java/com/gomo/app/core/auth/adapter/out/client/MemberClientTest.java new file mode 100644 index 00000000..8d23fd1e --- /dev/null +++ b/src/test/java/com/gomo/app/core/auth/adapter/out/client/MemberClientTest.java @@ -0,0 +1,73 @@ +package com.gomo.app.core.auth.adapter.out.client; + +import static org.mockito.Mockito.*; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.core.auth.application.port.command.CreatePrincipalCommand; +import com.gomo.app.core.member.application.port.in.EmailChecker; +import com.gomo.app.core.member.application.port.in.MemberCreator; +import com.gomo.app.core.member.application.port.in.MemberLoginProcessor; +import com.gomo.app.core.member.application.port.in.MemberOAuthLoginProcessor; + +@DisplayName("[Adapter unit]: 인증 요청 테스트") +@ExtendWith(MockitoExtension.class) +class MemberClientTest { + + @InjectMocks + private MemberClient sut; + + @Mock + private MemberCreator memberCreator; + + @Mock + private EmailChecker emailChecker; + + @Mock + private MemberLoginProcessor memberLoginProcessor; + + @Mock + private MemberOAuthLoginProcessor memberOAuthLoginProcessor; + + @DisplayName("회원 생성을 요청한다.") + @Test + void create_principal() { + CreatePrincipalCommand command = CreatePrincipalCommand.of("test@email.com", "password", "handle", "name", "motto", "loginProvider", "temporaryToken"); + sut.create(command); + + verify(memberCreator, times(1)).create(any()); + } + + @DisplayName("이메일 존재 여부를 확인한다.") + @Test + void exists_email() { + String email = "email"; + sut.exists(email); + + verify(emailChecker, times(1)).exists(email); + } + + @DisplayName("일반 회원 로그인 요청한다.") + @Test + void login() { + String email = "email"; + String password = "password"; + sut.login(email, password); + + verify(memberLoginProcessor, times(1)).login(email, password); + } + + @DisplayName("OAuth 회원 로그인 요청한다.") + @Test + void oauth_login() { + String email = "email"; + sut.login(email); + + verify(memberOAuthLoginProcessor, times(1)).login(email); + } +} diff --git a/src/test/java/com/gomo/app/common/security/jwt/application/ManageJwtUseCaseTest.java b/src/test/java/com/gomo/app/core/auth/adapter/out/lib/JwtClientTest.java similarity index 60% rename from src/test/java/com/gomo/app/common/security/jwt/application/ManageJwtUseCaseTest.java rename to src/test/java/com/gomo/app/core/auth/adapter/out/lib/JwtClientTest.java index 70519d89..a3df4759 100644 --- a/src/test/java/com/gomo/app/common/security/jwt/application/ManageJwtUseCaseTest.java +++ b/src/test/java/com/gomo/app/core/auth/adapter/out/lib/JwtClientTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.common.security.jwt.application; +package com.gomo.app.core.auth.adapter.out.lib; import static org.assertj.core.api.Assertions.*; @@ -8,17 +8,17 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -@DisplayName("[Common unit]: jwt 테스트") -class ManageJwtUseCaseTest { +@DisplayName("[Adapter unit]: jwt 테스트") +class JwtClientTest { - private ManageJwtUseCase manageJwtUseCase; + private JwtClient jwtClient; private final String testSecret = "this-is-a-sufficiently-long-secret-key-for-testing-purposes"; private final long accessExp = 60 * 60; private final long refreshExp = 24 * 60 * 60; @BeforeEach void setUp() { - manageJwtUseCase = new ManageJwtUseCase(testSecret, accessExp, refreshExp); + jwtClient = new JwtClient(testSecret, accessExp, refreshExp); } @DisplayName("토큰을 생성한 후, 유효성을 검증한다.") @@ -26,20 +26,20 @@ void setUp() { void generate_and_validate_token() { UUID subject = UUID.randomUUID(); - String accessToken = manageJwtUseCase.generateAccessToken(subject); + String accessToken = jwtClient.createAccessToken(subject); assertThat(accessToken).isNotBlank(); - assertThat(manageJwtUseCase.validateToken(accessToken)).isTrue(); - assertThat(subject.toString()).isEqualTo(manageJwtUseCase.extractSubject(accessToken)); + assertThat(jwtClient.verify(accessToken)).isTrue(); + assertThat(subject.toString()).isEqualTo(jwtClient.extractSubject(accessToken)); } @DisplayName("이미 만료된 토큰의 유효성을 검증한다.") @Test void validate_with_already_expired_token() throws InterruptedException { - String expiredToken = manageJwtUseCase.generateTemporaryToken("test", 1); + String expiredToken = jwtClient.createTemporaryToken("test", 1); Thread.sleep(1100); - boolean actual = manageJwtUseCase.validateToken(expiredToken); + boolean actual = jwtClient.verify(expiredToken); assertThat(actual).isFalse(); } @@ -48,10 +48,10 @@ void validate_with_already_expired_token() throws InterruptedException { @Test void validate_with_invalid_signature() { UUID subject = UUID.randomUUID(); - String token = manageJwtUseCase.generateAccessToken(subject); + String token = jwtClient.createAccessToken(subject); String malformedToken = token.substring(0, token.length() - 1) + "XXX"; - boolean actual = manageJwtUseCase.validateToken(malformedToken); + boolean actual = jwtClient.verify(malformedToken); assertThat(actual).isFalse(); } @@ -59,7 +59,7 @@ void validate_with_invalid_signature() { @DisplayName("null로 유효성을 검증한다.") @Test void validate_with_null_token() { - boolean actual = manageJwtUseCase.validateToken(null); + boolean actual = jwtClient.verify(null); assertThat(actual).isFalse(); } diff --git a/src/test/java/com/gomo/app/support/auth/infrastructure/persistence/RedisAuthCodeRepositoryTest.java b/src/test/java/com/gomo/app/core/auth/adapter/out/persistence/RedisAuthCodeRepositoryTest.java similarity index 87% rename from src/test/java/com/gomo/app/support/auth/infrastructure/persistence/RedisAuthCodeRepositoryTest.java rename to src/test/java/com/gomo/app/core/auth/adapter/out/persistence/RedisAuthCodeRepositoryTest.java index ded29152..2c0c5732 100644 --- a/src/test/java/com/gomo/app/support/auth/infrastructure/persistence/RedisAuthCodeRepositoryTest.java +++ b/src/test/java/com/gomo/app/core/auth/adapter/out/persistence/RedisAuthCodeRepositoryTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.infrastructure.persistence; +package com.gomo.app.core.auth.adapter.out.persistence; import static org.assertj.core.api.Assertions.*; @@ -7,7 +7,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import com.gomo.app.support.auth.domain.repository.AuthCodeRepository; +import com.gomo.app.core.auth.domain.repository.AuthCodeRepository; import com.gomo.app.test.IntegrationTest; @DisplayName("[Domain Integration]: 이메일 인증코드 Redis DB 테스트") diff --git a/src/test/java/com/gomo/app/support/auth/infrastructure/persistence/RedisAuthTokenRepositoryTest.java b/src/test/java/com/gomo/app/core/auth/adapter/out/persistence/RedisAuthTokenRepositoryTest.java similarity index 72% rename from src/test/java/com/gomo/app/support/auth/infrastructure/persistence/RedisAuthTokenRepositoryTest.java rename to src/test/java/com/gomo/app/core/auth/adapter/out/persistence/RedisAuthTokenRepositoryTest.java index c2a98146..da0a618d 100644 --- a/src/test/java/com/gomo/app/support/auth/infrastructure/persistence/RedisAuthTokenRepositoryTest.java +++ b/src/test/java/com/gomo/app/core/auth/adapter/out/persistence/RedisAuthTokenRepositoryTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.infrastructure.persistence; +package com.gomo.app.core.auth.adapter.out.persistence; import static org.assertj.core.api.Assertions.*; @@ -9,7 +9,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import com.gomo.app.support.auth.domain.repository.AuthTokenRepository; +import com.gomo.app.core.auth.domain.repository.AuthTokenRepository; import com.gomo.app.test.IntegrationTest; @DisplayName("[Domain Integration]: Auth 토큰 Redis DB 테스트") @@ -23,19 +23,19 @@ public class RedisAuthTokenRepositoryTest { @BeforeEach void setUp() { - sut.setRefreshToken(TOKEN_ID, "refresh_token"); + sut.saveRefreshToken(TOKEN_ID, "refresh_token"); } @DisplayName("Redis에 저장된 refresh token을 조회 할 수 있다.") @Test void read_refresh_token() { - assertThat(sut.getRefreshToken(TOKEN_ID)).isEqualTo("refresh_token"); + assertThat(sut.findRefreshToken(TOKEN_ID)).isEqualTo("refresh_token"); } @DisplayName("Redis에 저장된 인증코드를 삭제 할 수 있다.") @Test void delete_email_auth_code() { sut.deleteRefreshToken(TOKEN_ID); - assertThat(sut.getRefreshToken(TOKEN_ID)).isNullOrEmpty(); + assertThat(sut.findRefreshToken(TOKEN_ID)).isNullOrEmpty(); } } diff --git a/src/test/java/com/gomo/app/core/auth/application/service/AuthCodeServiceTest.java b/src/test/java/com/gomo/app/core/auth/application/service/AuthCodeServiceTest.java new file mode 100644 index 00000000..ea9cfbd9 --- /dev/null +++ b/src/test/java/com/gomo/app/core/auth/application/service/AuthCodeServiceTest.java @@ -0,0 +1,105 @@ +package com.gomo.app.core.auth.application.service; + +import static com.gomo.app.core.auth.domain.exception.AuthErrorCode.*; +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.Optional; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.core.auth.application.port.out.AuthCodeSender; +import com.gomo.app.core.auth.application.port.out.PrincipalEmailChecker; +import com.gomo.app.core.auth.domain.exception.AuthCodeCreateFailException; +import com.gomo.app.core.auth.domain.exception.InvalidAuthCodeException; +import com.gomo.app.core.auth.domain.repository.AuthCodeRepository; + +@DisplayName("[Application Unit]: 인증 코드 생성 테스트") +@ExtendWith(MockitoExtension.class) +class AuthCodeServiceTest { + + @InjectMocks + private AuthCodeService sut; + + @Mock + private PrincipalEmailChecker principalEmailChecker; + + @Mock + private AuthCodeSender authCodeSender; + + @Mock + private AuthCodeRepository authCodeRepository; + + @DisplayName("인증 코드 검증 후, 삭제한다.") + @Test + void verify_auth_code() { + String authCode = "123456"; + doReturn(Optional.of(authCode)).when(authCodeRepository).findByEmail(any()); + + sut.verify("email@gmail.com", authCode); + + verify(authCodeRepository, times(1)).delete(any()); + } + + @DisplayName("일치하지 않는 인증 코드로 검증한다.") + @Test + void verify_auth_code_with_invalid_code() { + String authCode = "123456"; + String invalidAuthCode = "654321"; + doReturn(Optional.of(authCode)).when(authCodeRepository).findByEmail(any()); + + assertThatThrownBy(() -> sut.verify("email@gmail.com", invalidAuthCode)).isExactlyInstanceOf(InvalidAuthCodeException.class); + } + + @DisplayName("회원가입을 위해 이메일 인증 코드를 생성한다.") + @Test + void create_email_auth_code_for_sign_up() { + String email = "email@gmail.com"; + doReturn(false).when(principalEmailChecker).exists(email); + + sut.issueForSignUp(email); + + verify(authCodeRepository, times(1)).save(any(), any()); + verify(authCodeSender, times(1)).send(any(), any()); + } + + @DisplayName("이미 회원가입이 완료된 이메일로 회원가입 이메일 인증 코드를 생성한다.") + @Test + void create_email_auth_code_for_sign_up_with_existent_email() { + String email = "email@gmail.com"; + doReturn(true).when(principalEmailChecker).exists(email); + + assertThatThrownBy(() -> sut.issueForSignUp(email)) + .isExactlyInstanceOf(AuthCodeCreateFailException.class) + .hasMessageContaining(PRINCIPAL_DUPLICATED.getMessage()); + } + + @DisplayName("비밀번호 초기화를 위해 이메일 인증 코드를 생성한다.") + @Test + void create_email_auth_code_for_password_reset() { + String email = "email@gmail.com"; + doReturn(true).when(principalEmailChecker).exists(email); + + sut.issueForPasswordReset(email); + + verify(authCodeRepository, times(1)).save(any(), any()); + verify(authCodeSender, times(1)).send(any(), any()); + } + + @DisplayName("이미 회원가입이 완료된 이메일로 비밀번호 초기화 이메일 인증 코드를 생성한다.") + @Test + void create_email_auth_code_password_reset_with_existent_email() { + String email = "email@gmail.com"; + doReturn(false).when(principalEmailChecker).exists(email); + + assertThatThrownBy(() -> sut.issueForPasswordReset(email)) + .isExactlyInstanceOf(AuthCodeCreateFailException.class) + .hasMessageContaining(PRINCIPAL_NOT_FOUND.getMessage()); + } +} diff --git a/src/test/java/com/gomo/app/core/auth/application/service/AuthServiceTest.java b/src/test/java/com/gomo/app/core/auth/application/service/AuthServiceTest.java new file mode 100644 index 00000000..e48cf0d0 --- /dev/null +++ b/src/test/java/com/gomo/app/core/auth/application/service/AuthServiceTest.java @@ -0,0 +1,98 @@ +package com.gomo.app.core.auth.application.service; + +import static com.gomo.app.core.auth.domain.exception.AuthErrorCode.*; +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.UUID; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.core.auth.application.port.command.CreatePrincipalCommand; +import com.gomo.app.core.auth.application.port.dto.AuthTokenDto; +import com.gomo.app.core.auth.application.port.out.JwtVerifier; +import com.gomo.app.core.auth.application.port.out.PrincipalCreator; +import com.gomo.app.core.auth.application.port.out.PrincipalLoginProcessor; +import com.gomo.app.core.auth.domain.exception.AuthenticationFailException; +import com.gomo.app.core.auth.domain.model.AuthToken; +import com.gomo.app.core.member.domain.model.LoginProvider; + +@DisplayName("[Application Unit]: 사용자 로그인 테스트") +@ExtendWith(MockitoExtension.class) +public class AuthServiceTest { + + @InjectMocks + private AuthService sut; + + @Mock + private PrincipalCreator principalCreator; + + @Mock + private PrincipalLoginProcessor principalLoginProcessor; + + @Mock + private JwtVerifier jwtVerifier; + + @Mock + private AuthTokenService authTokenService; + + @DisplayName("이메일로 회원 가입한다.") + @Test + void email_signup() { + CreatePrincipalCommand command = CreatePrincipalCommand.of("email@email.com", "Gomo123@", "handle", "name", "motto", LoginProvider.EMAIL.name(), "token"); + UUID principalId = UUID.randomUUID(); + doReturn(true).when(jwtVerifier).verify(anyString()); + doReturn(principalId).when(principalCreator).create(any()); + + UUID actual = sut.signup(command); + + assertThat(actual).isEqualTo(principalId); + } + + @DisplayName("OAuth로 회원 가입한다.") + @ParameterizedTest + @EnumSource(value = LoginProvider.class, names = {"NAVER", "GOOGLE", "KAKAO"}) + void oauth_signup(LoginProvider loginProvider) { + CreatePrincipalCommand command = CreatePrincipalCommand.of("email@email.com", "Gomo123@", "handle", "name", "motto", loginProvider.name(), "token"); + UUID principalId = UUID.randomUUID(); + doReturn(principalId).when(principalCreator).create(any()); + + UUID actual = sut.signup(command); + + assertThat(actual).isEqualTo(principalId); + } + + @DisplayName("유효하지 않은 검증된 이메일 토큰으로 가입한다.") + @Test + void signup_with_invalid_auth_token() { + CreatePrincipalCommand command = CreatePrincipalCommand.of("email@email.com", "Gomo123@", "handle", "name", "motto", LoginProvider.EMAIL.name(), "token"); + doReturn(false).when(jwtVerifier).verify(anyString()); + + assertThatThrownBy(() -> sut.signup(command)) + .isInstanceOf(AuthenticationFailException.class) + .hasMessageContaining(INVALID_VERIFIED_EMAIL_TOKEN.getMessage()); + } + + @DisplayName("사용자가 로그인한다.") + @Test + void login() { + UUID memberId = UUID.randomUUID(); + AuthToken authToken = AuthToken.of("access", "refresh"); + AuthTokenDto expected = AuthTokenDto.of(memberId, authToken.getAccessToken(), authToken.getRefreshToken(), 1L); + doReturn(memberId).when(principalLoginProcessor).login(anyString(), anyString()); + doReturn(authToken).when(authTokenService).create(any()); + doReturn(1L).when(jwtVerifier).extractExpirationTime(anyString()); + + AuthTokenDto actual = sut.login("test@gmail.com", "Gomo123@"); + + assertThat(actual).usingRecursiveComparison().isEqualTo(expected); + } +} diff --git a/src/test/java/com/gomo/app/core/auth/application/service/AuthTokenServiceTest.java b/src/test/java/com/gomo/app/core/auth/application/service/AuthTokenServiceTest.java new file mode 100644 index 00000000..daebe8f1 --- /dev/null +++ b/src/test/java/com/gomo/app/core/auth/application/service/AuthTokenServiceTest.java @@ -0,0 +1,147 @@ +package com.gomo.app.core.auth.application.service; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.UUID; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.core.auth.application.port.dto.AuthTokenDto; +import com.gomo.app.core.auth.application.port.out.JwtCreator; +import com.gomo.app.core.auth.application.port.out.JwtVerifier; +import com.gomo.app.core.auth.domain.exception.AuthErrorCode; +import com.gomo.app.core.auth.domain.exception.AuthenticationFailException; +import com.gomo.app.core.auth.domain.model.AuthToken; +import com.gomo.app.core.auth.domain.repository.AuthTokenRepository; +import com.gomo.app.core.member.domain.model.Member; +import com.gomo.app.core.member.fixture.MemberFixture; + +@DisplayName("[Application Unit]: 인증 토큰 발급 테스트") +@ExtendWith(MockitoExtension.class) +public class AuthTokenServiceTest { + + @InjectMocks + private AuthTokenService sut; + + @Mock + private JwtCreator jwtCreator; + + @Mock + private JwtVerifier jwtVerifier; + + @Mock + private AuthCodeService authCodeService; + + @Mock + private AuthTokenRepository authTokenRepository; + + @Nested + @DisplayName("검증된 이메일 인증토큰 발급 테스트") + class IssueAuthToken { + + String email = "test@email.com"; + + @DisplayName("이메일 인증코드를 검증하고, 검증된 이메일 인증 토큰을 생성한다.") + @Test + void issue_email_auth_code() { + String authCode = "000000"; + + sut.issue(email, authCode); + + verify(authCodeService, times(1)).verify(email, authCode); + verify(jwtCreator, times(1)).createTemporaryToken(email, 1800); + } + + @DisplayName("이메일 검증코드가 null이면 검증에 실패한다") + @Test + void issue_email_auth_code_with_null() { + assertThatThrownBy(() -> sut.issue(email, null)).isInstanceOf(NullPointerException.class); + } + } + + @Nested + @DisplayName("리프레시 토큰 재발급 테스트") + class CreateAuthToken { + + @DisplayName("인증토큰 발급에 성공한다.") + @Test + void create_auth_token() { + AuthToken expected = AuthToken.of("access", "refresh"); + + doReturn("access").when(jwtCreator).createAccessToken(any()); + doReturn("refresh").when(jwtCreator).createRefreshToken(any()); + doNothing().when(authTokenRepository).saveRefreshToken(any(), anyString()); + + AuthToken actual = sut.create(UUID.randomUUID()); + + assertThat(actual).usingRecursiveComparison().isEqualTo(expected); + } + } + + @Nested + @DisplayName("리프레시 토큰 재발급 테스트") + class UpdateRefreshToken { + + private static final String REFRESH_TOKEN = "REFRESH_TOKEN"; + private static final String REFRESH_TOKEN_WRONG = "WRONG_TOKEN"; + + @DisplayName("리프레시 토큰을 재발급한다.") + @Test + void renew_refresh_token() { + Member member = MemberFixture.create(); + AuthToken authToken = AuthToken.of("access", "refresh"); + AuthTokenDto expected = AuthTokenDto.of(member.getId(), authToken.getAccessToken(), authToken.getRefreshToken(), 1L); + + doReturn(member.getId().toString()).when(jwtVerifier).extractSubject(anyString()); + doReturn(REFRESH_TOKEN).when(authTokenRepository).findRefreshToken(member.getId()); + doReturn("access").when(jwtCreator).createAccessToken(any()); + doReturn("refresh").when(jwtCreator).createRefreshToken(any()); + doReturn(1L).when(jwtVerifier).extractExpirationTime(anyString()); + + AuthTokenDto actual = sut.update(REFRESH_TOKEN); + + assertThat(actual).usingRecursiveComparison().isEqualTo(expected); + } + + @DisplayName("리프레시 토큰이 null로 들어올 경우 재발급에 실패한다.") + @Test + void renew_refresh_token_with_null() { + assertThatThrownBy(() -> sut.update(null)) + .isInstanceOf(AuthenticationFailException.class) + .hasMessageContaining(AuthErrorCode.MISSING_REFRESH_TOKEN.getMessage()); + } + + @DisplayName("리프레시 토큰이 저장된 값과 다를 경우 재발급에 실패한다.") + @Test + void renew_refresh_token_with_wrong_token() { + Member member = MemberFixture.create(); + doReturn(member.getId().toString()).when(jwtVerifier).extractSubject(anyString()); + doReturn(REFRESH_TOKEN_WRONG).when(authTokenRepository).findRefreshToken(member.getId()); + + assertThatThrownBy(() -> sut.update(REFRESH_TOKEN)) + .isInstanceOf(AuthenticationFailException.class) + .hasMessageContaining(AuthErrorCode.INVALID_REFRESH_TOKEN.getMessage()); + } + } + + @Nested + @DisplayName("리프레시 토큰 삭제 테스트") + class DeleteAuthToken { + + @DisplayName("리프레시 토큰을 삭제한다.") + @Test + void delete_refresh_token() { + sut.delete(UUID.randomUUID()); + + verify(authTokenRepository, times(1)).deleteRefreshToken(any()); + } + } +} diff --git a/src/test/java/com/gomo/app/support/auth/domain/model/AuthCodeTest.java b/src/test/java/com/gomo/app/core/auth/domain/model/AuthCodeTest.java similarity index 97% rename from src/test/java/com/gomo/app/support/auth/domain/model/AuthCodeTest.java rename to src/test/java/com/gomo/app/core/auth/domain/model/AuthCodeTest.java index b4aa0652..009f2eb4 100644 --- a/src/test/java/com/gomo/app/support/auth/domain/model/AuthCodeTest.java +++ b/src/test/java/com/gomo/app/core/auth/domain/model/AuthCodeTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.auth.domain.model; +package com.gomo.app.core.auth.domain.model; import static org.assertj.core.api.Assertions.*; diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/CreateInterestDocumentationTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/CreateInterestDocumentationTest.java similarity index 91% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/CreateInterestDocumentationTest.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/CreateInterestDocumentationTest.java index c4f8ddcf..35cd96a1 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/CreateInterestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/CreateInterestDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation; +package com.gomo.app.core.interest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -17,9 +17,9 @@ import org.springframework.restdocs.restassured.RestDocumentationFilter; import org.springframework.util.ResourceUtils; +import com.gomo.app.core.interest.adapter.in.api.snippet.CreateInterestSnippet; +import com.gomo.app.core.interest.domain.exception.code.InterestNameErrorCode; import com.gomo.app.core.interest.domain.repository.InterestRepository; -import com.gomo.app.core.interest.exception.code.InterestNameErrorCode; -import com.gomo.app.core.interest.presentation.documentation.snippet.CreateInterestSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 관심사 생성 테스트") diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/CreateInterestRelationDocumentationTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/CreateInterestRelationDocumentationTest.java similarity index 81% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/CreateInterestRelationDocumentationTest.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/CreateInterestRelationDocumentationTest.java index 1b73edba..9a6fbc29 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/CreateInterestRelationDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/CreateInterestRelationDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation; +package com.gomo.app.core.interest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -15,12 +15,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; +import com.gomo.app.core.interest.adapter.in.api.request.CreateInterestRelationRequest; +import com.gomo.app.core.interest.adapter.in.api.request.CreateInterestRequest; +import com.gomo.app.core.interest.adapter.in.api.snippet.CreateInterestRelationSnippet; import com.gomo.app.core.interest.domain.repository.InterestRelationRepository; import com.gomo.app.core.interest.domain.repository.InterestRepository; -import com.gomo.app.core.interest.presentation.api.InterestApi; -import com.gomo.app.core.interest.presentation.api.request.CreateInterestRelationRequest; -import com.gomo.app.core.interest.presentation.api.request.CreateInterestRequest; -import com.gomo.app.core.interest.presentation.documentation.snippet.CreateInterestRelationSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 관심사 관계 생성 테스트") diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/CreateMajorInterestDocumentationTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/CreateMajorInterestDocumentationTest.java similarity index 84% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/CreateMajorInterestDocumentationTest.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/CreateMajorInterestDocumentationTest.java index 4dd717b4..c2b42add 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/CreateMajorInterestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/CreateMajorInterestDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation; +package com.gomo.app.core.interest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -15,13 +15,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; +import com.gomo.app.core.interest.adapter.in.api.request.CreateInterestRequest; +import com.gomo.app.core.interest.adapter.in.api.snippet.CreateMajorInterestSnippet; +import com.gomo.app.core.interest.domain.exception.code.MajorInterestErrorCode; import com.gomo.app.core.interest.domain.repository.InterestRepository; import com.gomo.app.core.interest.domain.repository.MajorInterestRepository; -import com.gomo.app.core.interest.exception.code.MajorInterestErrorCode; -import com.gomo.app.core.interest.presentation.api.InterestApi; -import com.gomo.app.core.interest.presentation.api.MajorInterestApi; -import com.gomo.app.core.interest.presentation.api.request.CreateInterestRequest; -import com.gomo.app.core.interest.presentation.documentation.snippet.CreateMajorInterestSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 주요 관심사 생성 테스트") diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/DeleteInterestDocumentationTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/DeleteInterestDocumentationTest.java similarity index 82% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/DeleteInterestDocumentationTest.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/DeleteInterestDocumentationTest.java index 91e994c0..db0bbb5a 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/DeleteInterestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/DeleteInterestDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation; +package com.gomo.app.core.interest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -14,10 +14,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; +import com.gomo.app.core.interest.adapter.in.api.request.CreateInterestRequest; +import com.gomo.app.core.interest.adapter.in.api.snippet.DeleteInterestSnippet; import com.gomo.app.core.interest.domain.repository.InterestRepository; -import com.gomo.app.core.interest.presentation.api.InterestApi; -import com.gomo.app.core.interest.presentation.api.request.CreateInterestRequest; -import com.gomo.app.core.interest.presentation.documentation.snippet.DeleteInterestSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 관심사 삭제 테스트") diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/DeleteInterestRelationDocumentationTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/DeleteInterestRelationDocumentationTest.java similarity index 81% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/DeleteInterestRelationDocumentationTest.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/DeleteInterestRelationDocumentationTest.java index 957e2791..a6b62793 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/DeleteInterestRelationDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/DeleteInterestRelationDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation; +package com.gomo.app.core.interest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -14,13 +14,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; +import com.gomo.app.core.interest.adapter.in.api.request.CreateInterestRelationRequest; +import com.gomo.app.core.interest.adapter.in.api.request.CreateInterestRequest; +import com.gomo.app.core.interest.adapter.in.api.snippet.DeleteInterestRelationSnippet; import com.gomo.app.core.interest.domain.repository.InterestRelationRepository; import com.gomo.app.core.interest.domain.repository.InterestRepository; -import com.gomo.app.core.interest.presentation.api.InterestApi; -import com.gomo.app.core.interest.presentation.api.InterestNetworkApi; -import com.gomo.app.core.interest.presentation.api.request.CreateInterestRelationRequest; -import com.gomo.app.core.interest.presentation.api.request.CreateInterestRequest; -import com.gomo.app.core.interest.presentation.documentation.snippet.DeleteInterestRelationSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 관심사 관계 삭제 테스트") diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/DeleteMajorInterestDocumentationTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/DeleteMajorInterestDocumentationTest.java similarity index 82% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/DeleteMajorInterestDocumentationTest.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/DeleteMajorInterestDocumentationTest.java index 63b43403..34829d57 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/DeleteMajorInterestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/DeleteMajorInterestDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation; +package com.gomo.app.core.interest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -14,12 +14,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; +import com.gomo.app.core.interest.adapter.in.api.request.CreateInterestRequest; +import com.gomo.app.core.interest.adapter.in.api.snippet.DeleteMajorInterestSnippet; import com.gomo.app.core.interest.domain.repository.InterestRepository; import com.gomo.app.core.interest.domain.repository.MajorInterestRepository; -import com.gomo.app.core.interest.presentation.api.InterestApi; -import com.gomo.app.core.interest.presentation.api.MajorInterestApi; -import com.gomo.app.core.interest.presentation.api.request.CreateInterestRequest; -import com.gomo.app.core.interest.presentation.documentation.snippet.DeleteMajorInterestSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 주요 관심사 삭제 테스트") diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/InterestNetworkDocumentationTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/InterestNetworkDocumentationTest.java similarity index 81% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/InterestNetworkDocumentationTest.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/InterestNetworkDocumentationTest.java index 6e0d4309..6081a7c1 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/InterestNetworkDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/InterestNetworkDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation; +package com.gomo.app.core.interest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -15,13 +15,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; +import com.gomo.app.core.interest.adapter.in.api.request.CreateInterestRelationRequest; +import com.gomo.app.core.interest.adapter.in.api.request.CreateInterestRequest; +import com.gomo.app.core.interest.adapter.in.api.snippet.InterestNetworkSnippet; import com.gomo.app.core.interest.domain.repository.InterestRelationRepository; import com.gomo.app.core.interest.domain.repository.InterestRepository; -import com.gomo.app.core.interest.presentation.api.InterestApi; -import com.gomo.app.core.interest.presentation.api.InterestNetworkApi; -import com.gomo.app.core.interest.presentation.api.request.CreateInterestRelationRequest; -import com.gomo.app.core.interest.presentation.api.request.CreateInterestRequest; -import com.gomo.app.core.interest.presentation.documentation.snippet.InterestNetworkSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 관심사 네트워크 조회 테스트") diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/ListInterestDocumentationTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/ListInterestDocumentationTest.java similarity index 82% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/ListInterestDocumentationTest.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/ListInterestDocumentationTest.java index dd95c21f..98343991 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/ListInterestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/ListInterestDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation; +package com.gomo.app.core.interest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -13,10 +13,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; +import com.gomo.app.core.interest.adapter.in.api.request.CreateInterestRequest; +import com.gomo.app.core.interest.adapter.in.api.snippet.ListInterestSnippet; import com.gomo.app.core.interest.domain.repository.InterestRepository; -import com.gomo.app.core.interest.presentation.api.InterestApi; -import com.gomo.app.core.interest.presentation.api.request.CreateInterestRequest; -import com.gomo.app.core.interest.presentation.documentation.snippet.ListInterestSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 관심사 목록 조회 테스트") diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/ListMajorInterestDocumentationTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/ListMajorInterestDocumentationTest.java similarity index 83% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/ListMajorInterestDocumentationTest.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/ListMajorInterestDocumentationTest.java index 036039dd..d7d33ad2 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/ListMajorInterestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/ListMajorInterestDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation; +package com.gomo.app.core.interest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -15,12 +15,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; +import com.gomo.app.core.interest.adapter.in.api.request.CreateInterestRequest; +import com.gomo.app.core.interest.adapter.in.api.snippet.ListMajorInterestSnippet; import com.gomo.app.core.interest.domain.repository.InterestRepository; import com.gomo.app.core.interest.domain.repository.MajorInterestRepository; -import com.gomo.app.core.interest.presentation.api.InterestApi; -import com.gomo.app.core.interest.presentation.api.MajorInterestApi; -import com.gomo.app.core.interest.presentation.api.request.CreateInterestRequest; -import com.gomo.app.core.interest.presentation.documentation.snippet.ListMajorInterestSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 주요 관심사 목록 조회 테스트") diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/OrderUpdateMajorInterestDocumentationTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/OrderUpdateMajorInterestDocumentationTest.java similarity index 82% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/OrderUpdateMajorInterestDocumentationTest.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/OrderUpdateMajorInterestDocumentationTest.java index 438eb0c7..d3c5ee08 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/OrderUpdateMajorInterestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/OrderUpdateMajorInterestDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation; +package com.gomo.app.core.interest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -17,13 +17,11 @@ import org.springframework.restdocs.restassured.RestDocumentationFilter; import com.gomo.app.common.displayorder.UpdatedOrderDto; +import com.gomo.app.core.interest.adapter.in.api.request.CreateInterestRequest; +import com.gomo.app.core.interest.adapter.in.api.request.OrderUpdateMajorInterestRequest; +import com.gomo.app.core.interest.adapter.in.api.snippet.OrderUpdateMajorInterestSnippet; import com.gomo.app.core.interest.domain.repository.InterestRepository; import com.gomo.app.core.interest.domain.repository.MajorInterestRepository; -import com.gomo.app.core.interest.presentation.api.InterestApi; -import com.gomo.app.core.interest.presentation.api.MajorInterestApi; -import com.gomo.app.core.interest.presentation.api.request.CreateInterestRequest; -import com.gomo.app.core.interest.presentation.api.request.OrderUpdateMajorInterestRequest; -import com.gomo.app.core.interest.presentation.documentation.snippet.OrderUpdateMajorInterestSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 주요 관심사 정렬 순서 변경 테스트") diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/ReadInterestDocumentationTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/ReadInterestDocumentationTest.java similarity index 82% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/ReadInterestDocumentationTest.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/ReadInterestDocumentationTest.java index 02442b60..86fe6801 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/ReadInterestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/ReadInterestDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation; +package com.gomo.app.core.interest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -14,10 +14,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; +import com.gomo.app.core.interest.adapter.in.api.request.CreateInterestRequest; +import com.gomo.app.core.interest.adapter.in.api.snippet.ReadInterestSnippet; import com.gomo.app.core.interest.domain.repository.InterestRepository; -import com.gomo.app.core.interest.presentation.api.InterestApi; -import com.gomo.app.core.interest.presentation.api.request.CreateInterestRequest; -import com.gomo.app.core.interest.presentation.documentation.snippet.ReadInterestSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 관심사 단건 조회 테스트") diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/UpdateInterestDocumentationTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/UpdateInterestDocumentationTest.java similarity index 83% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/UpdateInterestDocumentationTest.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/UpdateInterestDocumentationTest.java index af94fb49..1c385d35 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/UpdateInterestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/UpdateInterestDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation; +package com.gomo.app.core.interest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -15,12 +15,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; +import com.gomo.app.core.interest.adapter.in.api.request.CreateInterestRequest; +import com.gomo.app.core.interest.adapter.in.api.request.UpdateInterestRequest; +import com.gomo.app.core.interest.adapter.in.api.snippet.UpdateInterestSnippet; +import com.gomo.app.core.interest.domain.exception.code.InterestNameErrorCode; import com.gomo.app.core.interest.domain.repository.InterestRepository; -import com.gomo.app.core.interest.exception.code.InterestNameErrorCode; -import com.gomo.app.core.interest.presentation.api.InterestApi; -import com.gomo.app.core.interest.presentation.api.request.CreateInterestRequest; -import com.gomo.app.core.interest.presentation.api.request.UpdateInterestRequest; -import com.gomo.app.core.interest.presentation.documentation.snippet.UpdateInterestSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 관심사 수정 테스트") diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/UpdateInterestLogoDocumentationTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/UpdateInterestLogoDocumentationTest.java similarity index 88% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/UpdateInterestLogoDocumentationTest.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/UpdateInterestLogoDocumentationTest.java index a9d9615a..607f9c0a 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/UpdateInterestLogoDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/UpdateInterestLogoDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation; +package com.gomo.app.core.interest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -19,10 +19,9 @@ import org.springframework.restdocs.restassured.RestDocumentationFilter; import org.springframework.util.ResourceUtils; +import com.gomo.app.core.interest.adapter.in.api.request.CreateInterestRequest; +import com.gomo.app.core.interest.adapter.in.api.snippet.UpdateInterestLogoSnippet; import com.gomo.app.core.interest.domain.repository.InterestRepository; -import com.gomo.app.core.interest.presentation.api.InterestApi; -import com.gomo.app.core.interest.presentation.api.request.CreateInterestRequest; -import com.gomo.app.core.interest.presentation.documentation.snippet.UpdateInterestLogoSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 관심사 로고 수정 테스트") diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/CreateInterestRelationSnippet.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/CreateInterestRelationSnippet.java similarity index 93% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/CreateInterestRelationSnippet.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/CreateInterestRelationSnippet.java index bfa64983..8ae75685 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/CreateInterestRelationSnippet.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/CreateInterestRelationSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation.snippet; +package com.gomo.app.core.interest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/CreateInterestSnippet.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/CreateInterestSnippet.java similarity index 93% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/CreateInterestSnippet.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/CreateInterestSnippet.java index da9c01a5..07114dba 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/CreateInterestSnippet.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/CreateInterestSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation.snippet; +package com.gomo.app.core.interest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/CreateMajorInterestSnippet.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/CreateMajorInterestSnippet.java similarity index 93% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/CreateMajorInterestSnippet.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/CreateMajorInterestSnippet.java index 2b9ed069..bcc3220c 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/CreateMajorInterestSnippet.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/CreateMajorInterestSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation.snippet; +package com.gomo.app.core.interest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/DeleteInterestRelationSnippet.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/DeleteInterestRelationSnippet.java similarity index 92% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/DeleteInterestRelationSnippet.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/DeleteInterestRelationSnippet.java index dc4e7892..fc3498af 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/DeleteInterestRelationSnippet.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/DeleteInterestRelationSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation.snippet; +package com.gomo.app.core.interest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/DeleteInterestSnippet.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/DeleteInterestSnippet.java similarity index 92% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/DeleteInterestSnippet.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/DeleteInterestSnippet.java index 5820534b..9a4c365a 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/DeleteInterestSnippet.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/DeleteInterestSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation.snippet; +package com.gomo.app.core.interest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/DeleteMajorInterestSnippet.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/DeleteMajorInterestSnippet.java similarity index 92% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/DeleteMajorInterestSnippet.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/DeleteMajorInterestSnippet.java index 605c23bd..58f9aa93 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/DeleteMajorInterestSnippet.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/DeleteMajorInterestSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation.snippet; +package com.gomo.app.core.interest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/InterestNetworkSnippet.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/InterestNetworkSnippet.java similarity index 95% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/InterestNetworkSnippet.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/InterestNetworkSnippet.java index f7195630..23e7dd2e 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/InterestNetworkSnippet.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/InterestNetworkSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation.snippet; +package com.gomo.app.core.interest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/ListInterestSnippet.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/ListInterestSnippet.java similarity index 95% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/ListInterestSnippet.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/ListInterestSnippet.java index 63bc6d1d..e2ab318a 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/ListInterestSnippet.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/ListInterestSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation.snippet; +package com.gomo.app.core.interest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/ListMajorInterestSnippet.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/ListMajorInterestSnippet.java similarity index 94% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/ListMajorInterestSnippet.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/ListMajorInterestSnippet.java index 5dc636de..943a9060 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/ListMajorInterestSnippet.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/ListMajorInterestSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation.snippet; +package com.gomo.app.core.interest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/OrderUpdateMajorInterestSnippet.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/OrderUpdateMajorInterestSnippet.java similarity index 93% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/OrderUpdateMajorInterestSnippet.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/OrderUpdateMajorInterestSnippet.java index 0031f344..892b684f 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/OrderUpdateMajorInterestSnippet.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/OrderUpdateMajorInterestSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation.snippet; +package com.gomo.app.core.interest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/ReadInterestSnippet.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/ReadInterestSnippet.java similarity index 95% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/ReadInterestSnippet.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/ReadInterestSnippet.java index b4d05472..4077990a 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/ReadInterestSnippet.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/ReadInterestSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation.snippet; +package com.gomo.app.core.interest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/UpdateInterestLogoSnippet.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/UpdateInterestLogoSnippet.java similarity index 93% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/UpdateInterestLogoSnippet.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/UpdateInterestLogoSnippet.java index 95decbc3..82a90e4b 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/UpdateInterestLogoSnippet.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/UpdateInterestLogoSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation.snippet; +package com.gomo.app.core.interest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/UpdateInterestSnippet.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/UpdateInterestSnippet.java similarity index 93% rename from src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/UpdateInterestSnippet.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/UpdateInterestSnippet.java index f9e8bc4b..c60fb020 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/documentation/snippet/UpdateInterestSnippet.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/snippet/UpdateInterestSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.documentation.snippet; +package com.gomo.app.core.interest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/interest/presentation/consumer/CompleteQuestEventScoreConsumerTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/consumer/CompleteQuestEventScoreConsumerTest.java similarity index 83% rename from src/test/java/com/gomo/app/core/interest/presentation/consumer/CompleteQuestEventScoreConsumerTest.java rename to src/test/java/com/gomo/app/core/interest/adapter/in/consumer/CompleteQuestEventScoreConsumerTest.java index 74fd418e..f651a000 100644 --- a/src/test/java/com/gomo/app/core/interest/presentation/consumer/CompleteQuestEventScoreConsumerTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/consumer/CompleteQuestEventScoreConsumerTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.presentation.consumer; +package com.gomo.app.core.interest.adapter.in.consumer; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; @@ -16,8 +16,8 @@ import org.mockito.junit.jupiter.MockitoExtension; import com.gomo.app.common.util.JsonParser; -import com.gomo.app.core.interest.application.port.AdjustProficiencyPortIn; -import com.gomo.app.core.quest.event.CompleteQuestEvent; +import com.gomo.app.core.interest.application.port.in.ProficiencyPropagator; +import com.gomo.app.core.quest.domain.event.CompleteQuestEvent; import com.gomo.app.support.evententry.domain.model.EventEntry; @DisplayName("[Consumer unit]: 퀘스트 완료(점수) 이벤트 처리 테스트") @@ -28,7 +28,7 @@ class CompleteQuestEventScoreConsumerTest { private CompleteQuestEventScoreConsumer sut; @Mock - private AdjustProficiencyPortIn adjustProficiencyPortIn; + private ProficiencyPropagator proficiencyPropagator; @DisplayName("숙련도 향상 이벤트를 처리한다.") @Test @@ -41,7 +41,7 @@ void event_process() { sut.handleEvent(eventEntry); - verify(adjustProficiencyPortIn, times(1)).adjust(any(), anyInt()); + verify(proficiencyPropagator, times(1)).propagate(any(), anyInt()); } } @@ -50,7 +50,7 @@ void event_process() { void cannot_process_event_by_score() { EventEntry eventEntry = EventEntry.of("CompleteQuestEvent", "payload", 1L); CompleteQuestEvent event = CompleteQuestEvent.of(UUID.randomUUID(), UUID.randomUUID(), "DAILY", 2, 10, LocalDateTime.now(), 1L); - doThrow(new IllegalStateException("Proficiency service failure")).when(adjustProficiencyPortIn).adjust(any(), anyInt()); + doThrow(new IllegalStateException("Proficiency service failure")).when(proficiencyPropagator).propagate(any(), anyInt()); try (MockedStatic mockedJsonParser = mockStatic(JsonParser.class)) { mockedJsonParser.when(() -> JsonParser.fromJson(any(), eq(CompleteQuestEvent.class))).thenReturn(event); diff --git a/src/test/java/com/gomo/app/core/interest/adapter/out/client/LogoClientTest.java b/src/test/java/com/gomo/app/core/interest/adapter/out/client/LogoClientTest.java new file mode 100644 index 00000000..c592689a --- /dev/null +++ b/src/test/java/com/gomo/app/core/interest/adapter/out/client/LogoClientTest.java @@ -0,0 +1,51 @@ +package com.gomo.app.core.interest.adapter.out.client; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.Optional; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.mock.web.MockMultipartFile; + +import com.gomo.app.support.image.application.port.in.ImageDeleter; +import com.gomo.app.support.image.application.port.in.ImageUploader; + +@DisplayName("[Adapter unit]: 이미지 업로드 테스트") +@ExtendWith(MockitoExtension.class) +class LogoClientTest { + + @InjectMocks + private LogoClient sut; + + @Mock + private ImageUploader imageUploader; + + @Mock + private ImageDeleter imageDeleter; + + @DisplayName("이미지를 업로드한다.") + @Test + void upload_image() { + String imageUrl = "image_url"; + doReturn(Optional.of(imageUrl)).when(imageUploader).upload(any()); + + Optional actual = sut.upload(new MockMultipartFile("image", "image.jpg", "image/jpeg", "image/png".getBytes())); + + assertThat(actual.get()).isEqualTo(imageUrl); + } + + @DisplayName("이미지를 삭제한다.") + @Test + void delete_image() { + sut.delete("imageUrl"); + + verify(imageDeleter, times(1)).delete(any()); + } +} diff --git a/src/test/java/com/gomo/app/core/interest/infrastructure/adapter/ReadRegistrantAdapterTest.java b/src/test/java/com/gomo/app/core/interest/adapter/out/client/RegistrantClientTest.java similarity index 78% rename from src/test/java/com/gomo/app/core/interest/infrastructure/adapter/ReadRegistrantAdapterTest.java rename to src/test/java/com/gomo/app/core/interest/adapter/out/client/RegistrantClientTest.java index f6d625bb..875f9417 100644 --- a/src/test/java/com/gomo/app/core/interest/infrastructure/adapter/ReadRegistrantAdapterTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/out/client/RegistrantClientTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.infrastructure.adapter; +package com.gomo.app.core.interest.adapter.out.client; import static org.mockito.Mockito.*; @@ -11,26 +11,26 @@ import org.mockito.junit.jupiter.MockitoExtension; import com.gomo.app.core.interest.application.port.dto.RegistrantDto; -import com.gomo.app.core.member.application.port.ReadMemberPortIn; import com.gomo.app.core.member.application.port.dto.MemberDto; +import com.gomo.app.core.member.application.port.in.MemberReader; import com.gomo.app.core.member.domain.model.SubscriptionPlan; import com.gomo.app.core.member.fixture.MemberFixture; @DisplayName("[Adapter unit]: 등록자 조회") @ExtendWith(MockitoExtension.class) -class ReadRegistrantAdapterTest { +class RegistrantClientTest { @InjectMocks - ReadRegistrantAdapter sut; + RegistrantClient sut; @Mock - ReadMemberPortIn readMemberPortIn; + MemberReader memberReader; @DisplayName("관심사 등록자를 조회한다.") @Test void find_registrant() { MemberDto memberDto = MemberDto.from(MemberFixture.create(SubscriptionPlan.PREMIUM), 1000); - doReturn(memberDto).when(readMemberPortIn).find(any()); + doReturn(memberDto).when(memberReader).read(any()); RegistrantDto registrantDto = sut.find(memberDto.id()); diff --git a/src/test/java/com/gomo/app/core/interest/infrastructure/repository/LevelThresholdPolicyRepositoryImplTest.java b/src/test/java/com/gomo/app/core/interest/adapter/out/persistence/JDBCLevelThresholdPolicyRepositoryTest.java similarity index 80% rename from src/test/java/com/gomo/app/core/interest/infrastructure/repository/LevelThresholdPolicyRepositoryImplTest.java rename to src/test/java/com/gomo/app/core/interest/adapter/out/persistence/JDBCLevelThresholdPolicyRepositoryTest.java index 51cacb84..e4ede808 100644 --- a/src/test/java/com/gomo/app/core/interest/infrastructure/repository/LevelThresholdPolicyRepositoryImplTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/out/persistence/JDBCLevelThresholdPolicyRepositoryTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.infrastructure.repository; +package com.gomo.app.core.interest.adapter.out.persistence; import static org.assertj.core.api.Assertions.*; @@ -13,10 +13,10 @@ @DisplayName("[Domain integration]: 레벨별 임계 점수 정책 DB 통합 테스트") @IntegrationTest -class LevelThresholdPolicyRepositoryImplTest { +class JDBCLevelThresholdPolicyRepositoryTest { @Autowired - LevelThresholdPolicyRepositoryImpl repository; + JDBCLevelThresholdPolicyRepository repository; @DisplayName("레벨별 임계 점수 정책 목록을 조회한다") @Test diff --git a/src/test/java/com/gomo/app/core/interest/application/usecase/CreateInterestUseCaseTest.java b/src/test/java/com/gomo/app/core/interest/application/service/InterestCreateServiceTest.java similarity index 74% rename from src/test/java/com/gomo/app/core/interest/application/usecase/CreateInterestUseCaseTest.java rename to src/test/java/com/gomo/app/core/interest/application/service/InterestCreateServiceTest.java index 407d68b7..0ab05e48 100644 --- a/src/test/java/com/gomo/app/core/interest/application/usecase/CreateInterestUseCaseTest.java +++ b/src/test/java/com/gomo/app/core/interest/application/service/InterestCreateServiceTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.application.usecase; +package com.gomo.app.core.interest.application.service; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; @@ -14,27 +14,27 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.mock.web.MockMultipartFile; -import com.gomo.app.core.interest.application.port.ReadRegistrantPortOut; import com.gomo.app.core.interest.application.port.command.CreateInterestCommand; import com.gomo.app.core.interest.application.port.dto.RegistrantDto; +import com.gomo.app.core.interest.application.port.out.LogoUploader; +import com.gomo.app.core.interest.application.port.out.RegistrantReader; import com.gomo.app.core.interest.domain.model.Interest; import com.gomo.app.core.interest.domain.model.InterestQuota; import com.gomo.app.core.interest.domain.repository.InterestRepository; import com.gomo.app.core.interest.fixture.InterestFixture; -import com.gomo.app.support.image.application.port.UploadImagePortIn; @DisplayName("[Application unit]: 관심사 등록 테스트") @ExtendWith(MockitoExtension.class) -public class CreateInterestUseCaseTest { +public class InterestCreateServiceTest { @InjectMocks - private CreateInterestUseCase sut; + private InterestCreateService sut; @Mock - private ReadRegistrantPortOut readRegistrantPortOut; + private RegistrantReader registrantReader; @Mock - private UploadImagePortIn uploadImagePortIn; + private LogoUploader logoUploader; @Mock private InterestRepository interestRepository; @@ -43,8 +43,8 @@ public class CreateInterestUseCaseTest { @Test void create_interest() { Interest interest = InterestFixture.create(); - doReturn(RegistrantDto.of(UUID.randomUUID(), "BASIC")).when(readRegistrantPortOut).find(any()); - doReturn(Optional.of(interest.logoUrl())).when(uploadImagePortIn).upload(any(MockMultipartFile.class)); + doReturn(RegistrantDto.of(UUID.randomUUID(), "BASIC")).when(registrantReader).find(any()); + doReturn(Optional.of(interest.logoUrl())).when(logoUploader).upload(any(MockMultipartFile.class)); doReturn((long)(InterestQuota.BASIC.getMaxCount() - 1)).when(interestRepository).countAllByRegistrantId(any()); doReturn(interest).when(interestRepository).save(any(Interest.class)); diff --git a/src/test/java/com/gomo/app/core/interest/application/usecase/DeleteInterestUseCaseTest.java b/src/test/java/com/gomo/app/core/interest/application/service/InterestDeleteServiceTest.java similarity index 70% rename from src/test/java/com/gomo/app/core/interest/application/usecase/DeleteInterestUseCaseTest.java rename to src/test/java/com/gomo/app/core/interest/application/service/InterestDeleteServiceTest.java index e64bf533..cffa6182 100644 --- a/src/test/java/com/gomo/app/core/interest/application/usecase/DeleteInterestUseCaseTest.java +++ b/src/test/java/com/gomo/app/core/interest/application/service/InterestDeleteServiceTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.application.usecase; +package com.gomo.app.core.interest.application.service; import static org.mockito.Mockito.*; @@ -13,29 +13,27 @@ import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; +import com.gomo.app.core.interest.application.port.out.LogoDeleter; import com.gomo.app.core.interest.domain.model.Interest; import com.gomo.app.core.interest.domain.model.InterestRelation; import com.gomo.app.core.interest.domain.model.Logo; import com.gomo.app.core.interest.domain.repository.InterestRepository; import com.gomo.app.core.interest.domain.repository.MajorInterestRepository; -import com.gomo.app.core.interest.domain.service.InterestRelationService; -import com.gomo.app.core.interest.domain.service.InterestService; import com.gomo.app.core.interest.fixture.InterestFixture; import com.gomo.app.core.interest.fixture.InterestRelationFixture; -import com.gomo.app.support.image.application.port.DeleteImagePortIn; @DisplayName("[Application unit]: 관심사 삭제 테스트") @ExtendWith(MockitoExtension.class) -public class DeleteInterestUseCaseTest { +public class InterestDeleteServiceTest { @InjectMocks - private DeleteInterestUseCase sut; + private InterestDeleteService sut; @Mock private InterestService interestService; @Mock - private DeleteImagePortIn deleteImagePortIn; + private LogoDeleter logoDeleter; @Mock private InterestRelationService interestRelationService; @@ -50,8 +48,8 @@ public class DeleteInterestUseCaseTest { @Test void delete_interest() { Interest interest = InterestFixture.create(); - doReturn(interest).when(interestService).find(any()); - doReturn(List.of(InterestRelationFixture.create())).when(interestRelationService).findAllByInterestId(any(UUID.class)); + doReturn(interest).when(interestService).readById(any()); + doReturn(List.of(InterestRelationFixture.create())).when(interestRelationService).readAllByInterestId(any(UUID.class)); sut.delete(interest.getRegistrantId(), interest.getId()); @@ -62,9 +60,9 @@ void delete_interest() { @Test void delete_interest_by_unauthorized_accessor() { Interest interest = Mockito.mock(Interest.class); - doReturn(interest).when(interestService).find(any()); + doReturn(interest).when(interestService).readById(any()); doReturn(Logo.of("logoFile")).when(interest).getLogo(); - doReturn(List.of(InterestRelationFixture.create())).when(interestRelationService).findAllByInterestId(any(UUID.class)); + doReturn(List.of(InterestRelationFixture.create())).when(interestRelationService).readAllByInterestId(any(UUID.class)); sut.delete(UUID.randomUUID(), UUID.randomUUID()); @@ -75,32 +73,32 @@ void delete_interest_by_unauthorized_accessor() { @Test void does_not_delete_interest_logo() { Interest interest = InterestFixture.create(Logo.of(null)); - doReturn(interest).when(interestService).find(any()); - doReturn(List.of(InterestRelationFixture.create())).when(interestRelationService).findAllByInterestId(any(UUID.class)); + doReturn(interest).when(interestService).readById(any()); + doReturn(List.of(InterestRelationFixture.create())).when(interestRelationService).readAllByInterestId(any(UUID.class)); sut.delete(interest.getRegistrantId(), interest.getId()); - verify(deleteImagePortIn, times(0)).delete(any()); + verify(logoDeleter, times(0)).delete(any()); } @DisplayName("관심사의 로고가 사용자가 업로드한 로고라면 이미지는 삭제된다.") @Test void delete_interest_logo() { Interest interest = InterestFixture.create(); - doReturn(interest).when(interestService).find(any()); - doReturn(List.of(InterestRelationFixture.create())).when(interestRelationService).findAllByInterestId(any(UUID.class)); + doReturn(interest).when(interestService).readById(any()); + doReturn(List.of(InterestRelationFixture.create())).when(interestRelationService).readAllByInterestId(any(UUID.class)); sut.delete(interest.getRegistrantId(), interest.getId()); - verify(deleteImagePortIn, times(1)).delete(any()); + verify(logoDeleter, times(1)).delete(any()); } @DisplayName("관심사를 삭제할 때, 주요 관심사도 함께 삭제된다.") @Test void delete_major_interest() { Interest interest = InterestFixture.create(); - doReturn(interest).when(interestService).find(any()); - doReturn(List.of(InterestRelationFixture.create())).when(interestRelationService).findAllByInterestId(any(UUID.class)); + doReturn(interest).when(interestService).readById(any()); + doReturn(List.of(InterestRelationFixture.create())).when(interestRelationService).readAllByInterestId(any(UUID.class)); sut.delete(interest.getRegistrantId(), interest.getId()); @@ -112,23 +110,23 @@ void delete_major_interest() { void delete_major_interest_relation() { Interest interest = InterestFixture.create(); List interestRelations = List.of(InterestRelationFixture.create()); - doReturn(interest).when(interestService).find(any()); - doReturn(interestRelations).when(interestRelationService).findAllByInterestId(any(UUID.class)); + doReturn(interest).when(interestService).readById(any()); + doReturn(interestRelations).when(interestRelationService).readAllByInterestId(any(UUID.class)); sut.delete(interest.getRegistrantId(), interest.getId()); - verify(interestRelationService, times(interestRelations.size())).delete(any(), any(), any()); + verify(interestRelationService, times(interestRelations.size())).delete(any(), any()); } @DisplayName("관심사를 삭제할 때, 관심사와 연결된 관계선이 없다면 관계선은 삭제하지 않는다.") @Test void does_not_delete_major_interest_relation() { Interest interest = InterestFixture.create(); - doReturn(interest).when(interestService).find(any()); - doReturn(List.of()).when(interestRelationService).findAllByInterestId(any(UUID.class)); + doReturn(interest).when(interestService).readById(any()); + doReturn(List.of()).when(interestRelationService).readAllByInterestId(any(UUID.class)); sut.delete(interest.getRegistrantId(), interest.getId()); - verify(interestRelationService, times(0)).delete(any(), any(), any()); + verify(interestRelationService, times(0)).delete(any(), any()); } } diff --git a/src/test/java/com/gomo/app/core/interest/application/service/InterestNetworkServiceTest.java b/src/test/java/com/gomo/app/core/interest/application/service/InterestNetworkServiceTest.java new file mode 100644 index 00000000..3f536d62 --- /dev/null +++ b/src/test/java/com/gomo/app/core/interest/application/service/InterestNetworkServiceTest.java @@ -0,0 +1,55 @@ +package com.gomo.app.core.interest.application.service; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.List; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.core.interest.application.port.dto.InterestDto; +import com.gomo.app.core.interest.application.port.dto.InterestNetworkDto; +import com.gomo.app.core.interest.domain.model.Interest; +import com.gomo.app.core.interest.domain.model.InterestRelation; +import com.gomo.app.core.interest.domain.model.MajorInterest; +import com.gomo.app.core.interest.fixture.InterestFixture; +import com.gomo.app.core.interest.fixture.InterestRelationFixture; +import com.gomo.app.core.interest.fixture.MajorInterestFixture; + +@DisplayName("[Application unit]: 관심사 네트워크 조회 테스트") +@ExtendWith(MockitoExtension.class) +public class InterestNetworkServiceTest { + + @InjectMocks + private InterestNetworkService sut; + + @Mock + private InterestService interestService; + + @Mock + private InterestRelationService interestRelationService; + + @DisplayName("관심사 네트워크를 조회한다.") + @Test + void read_interest_network() { + Interest expected1 = InterestFixture.create(); + Interest expected2 = InterestFixture.create(); + MajorInterest majorInterest = MajorInterestFixture.create(expected1.getRegistrantId(), expected1.getId()); + InterestDto dto1 = InterestDto.of(expected1, majorInterest.getId()); + InterestDto dto2 = InterestDto.of(expected2, null); + doReturn(List.of(dto1, dto2)).when(interestService).readAll(any()); + + InterestRelation relation = InterestRelationFixture.create(); + doReturn(List.of(relation)).when(interestRelationService).readAllByRegistrantId(any()); + + InterestNetworkDto actual = sut.read(relation.getRegistrantId()); + + assertThat(actual.interestDtos()).hasSize(2); + assertThat(actual.relationDtos()).hasSize(1); + } +} diff --git a/src/test/java/com/gomo/app/core/interest/application/service/InterestRelationServiceTest.java b/src/test/java/com/gomo/app/core/interest/application/service/InterestRelationServiceTest.java new file mode 100644 index 00000000..5199bd8b --- /dev/null +++ b/src/test/java/com/gomo/app/core/interest/application/service/InterestRelationServiceTest.java @@ -0,0 +1,171 @@ +package com.gomo.app.core.interest.application.service; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.core.interest.domain.exception.InterestRelationAccessDeniedException; +import com.gomo.app.core.interest.domain.exception.InterestRelationCycleException; +import com.gomo.app.core.interest.domain.exception.InterestRelationDuplicatedException; +import com.gomo.app.core.interest.domain.exception.InterestRelationNotFoundException; +import com.gomo.app.core.interest.domain.exception.code.InterestRelationErrorCode; +import com.gomo.app.core.interest.domain.model.Interest; +import com.gomo.app.core.interest.domain.model.InterestRelation; +import com.gomo.app.core.interest.domain.repository.InterestRelationRepository; +import com.gomo.app.core.interest.domain.service.InterestNetworkBuilder; +import com.gomo.app.core.interest.fixture.InterestFixture; +import com.gomo.app.core.interest.fixture.InterestRelationFixture; + +@DisplayName("[Application unit]: 관심사 관계 등록 테스트") +@ExtendWith(MockitoExtension.class) +public class InterestRelationServiceTest { + + @InjectMocks + private InterestRelationService sut; + + @Mock + private InterestService interestService; + + @Mock + private ProficiencyService proficiencyService; + + @Mock + private InterestRelationRepository interestRelationRepository; + + @Mock + private InterestNetworkBuilder interestNetworkBuilder; + + @Captor + private ArgumentCaptor> relationsCaptor; + + @DisplayName("관심사 관계를 등록한다.") + @Test + void create_interest_relation() { + Interest parentInterest = InterestFixture.create(); + Interest childInterest = InterestFixture.create(); + InterestRelation interestRelation = InterestRelationFixture.create(parentInterest, childInterest); + doReturn(false).when(interestRelationRepository).existsRelationFor(any(), any()); + doReturn(new ArrayList<>()).when(interestRelationRepository).findAllByRegistrantId(any()); + doReturn(interestRelation).when(interestRelationRepository).save(any()); + doNothing().when(interestNetworkBuilder).validateAcyclic(anyList(), any(UUID.class)); + doReturn(childInterest).when(interestService).readById(childInterest.getId()); + + UUID actual = sut.create(interestRelation.getRegistrantId(), parentInterest.getId(), childInterest.getId()); + + assertThat(actual).isEqualTo(interestRelation.getId()); + verify(interestNetworkBuilder, times(1)).validateAcyclic(anyList(), any(UUID.class)); + verify(proficiencyService, times(1)).propagate(any(), eq(0)); + } + + @DisplayName("관심사 관계선은 중복 생성할 수 없다.") + @Test + void create_duplicated_relation() { + UUID registrantId = UUID.randomUUID(); + + doReturn(true).when(interestRelationRepository).existsRelationFor(any(), any()); + + assertThatThrownBy(() -> sut.create(registrantId, UUID.randomUUID(), UUID.randomUUID())) + .isInstanceOf(InterestRelationDuplicatedException.class) + .hasMessageContaining(InterestRelationErrorCode.DUPLICATED.getMessage()); + verify(interestNetworkBuilder, never()).validateAcyclic(any(), any()); + } + + @DisplayName("순환이 발생하는 관심사 관계선은 생성할 수 없다.") + @Test + void create_cyclic_relation() { + UUID registrantId = UUID.randomUUID(); + Interest depth1 = InterestFixture.create(registrantId, "depth1"); + Interest depth2 = InterestFixture.create(registrantId, "depth2"); + Interest depth3 = InterestFixture.create(registrantId, "depth3"); + InterestRelation depth1ToDepth2 = InterestRelationFixture.create(depth1, depth2); + InterestRelation depth2ToDepth3 = InterestRelationFixture.create(depth2, depth3); + List relations = new ArrayList<>(List.of(depth1ToDepth2, depth2ToDepth3)); + doReturn(false).when(interestRelationRepository).existsRelationFor(any(), any()); + doReturn(relations).when(interestRelationRepository).findAllByRegistrantId(any()); + doThrow(new InterestRelationCycleException(InterestRelationErrorCode.UNEXPECTED_CYCLE)).when(interestNetworkBuilder) + .validateAcyclic(anyList(), eq(depth3.getId())); + + assertThatThrownBy(() -> sut.create(registrantId, depth3.getId(), depth1.getId())) + .isInstanceOf(InterestRelationCycleException.class) + .hasMessageContaining(InterestRelationErrorCode.UNEXPECTED_CYCLE.getMessage()); + } + + @DisplayName("관심사 관계를 삭제한다.") + @Test + void delete_interest_relation() { + Interest parentInterest = InterestFixture.create(); + Interest childInterest = InterestFixture.create(); + InterestRelation interestRelation = InterestRelationFixture.create(parentInterest, childInterest); + doReturn(childInterest).when(interestService).readById(childInterest.getId()); + doReturn(Optional.of(interestRelation)).when(interestRelationRepository).findById(any()); + + sut.delete(interestRelation.getRegistrantId(), interestRelation.getId()); + + verify(proficiencyService, times(1)).propagate(any(), eq(0)); + verify(interestRelationRepository, times(1)).delete(any()); + } + + @DisplayName("권한 없는 접근자는 관심사를 삭제할 수 없다.") + @Test + void delete_interest_by_unauthorized_accessor() { + InterestRelation interestRelation = mock(InterestRelation.class); + doReturn(Optional.of(interestRelation)).when(interestRelationRepository).findById(any()); + doThrow(InterestRelationAccessDeniedException.class).when(interestRelation).validateAuthority(any(UUID.class)); + + assertThatThrownBy(() -> sut.delete(UUID.randomUUID(), UUID.randomUUID())).isInstanceOf(InterestRelationAccessDeniedException.class); + } + + @DisplayName("관심사 관계선을 조회한다.") + @Test + void find_relation() { + InterestRelation interestRelation = InterestRelationFixture.create(); + doReturn(Optional.of(interestRelation)).when(interestRelationRepository).findById(any()); + + InterestRelation actual = sut.readById(interestRelation.getId()); + + assertThat(actual.getId()).isEqualTo(interestRelation.getId()); + } + + @DisplayName("존재하지 않는 관심사 관계선을 조회한다.") + @Test + void find_nonexistent_relation() { + doReturn(Optional.empty()).when(interestRelationRepository).findById(any()); + + assertThatThrownBy(() -> sut.readById(UUID.randomUUID())) + .isInstanceOf(InterestRelationNotFoundException.class) + .hasMessageContaining(InterestRelationErrorCode.NOT_FOUND.getMessage()); + } + + @DisplayName("특정 관심사와 연관된 모든 관계선 목록을 조회한다.") + @Test + void find_all_relation_by_interest() { + doReturn(List.of(InterestRelationFixture.create(), InterestRelationFixture.create())).when(interestRelationRepository).findAllByInterestId(any()); + + List actual = sut.readAllByInterestId(UUID.randomUUID()); + + assertThat(actual).hasSize(2); + } + + @DisplayName("등록자의 모든 관심사 관계선 목록을 조회한다.") + @Test + void find_all_relation_by_registrant() { + doReturn(List.of(InterestRelationFixture.create(), InterestRelationFixture.create())).when(interestRelationRepository).findAllByRegistrantId(any()); + + List actual = sut.readAllByRegistrantId(UUID.randomUUID()); + + assertThat(actual).hasSize(2); + } +} diff --git a/src/test/java/com/gomo/app/core/interest/application/usecase/ReadInterestUseCaseTest.java b/src/test/java/com/gomo/app/core/interest/application/service/InterestServiceTest.java similarity index 60% rename from src/test/java/com/gomo/app/core/interest/application/usecase/ReadInterestUseCaseTest.java rename to src/test/java/com/gomo/app/core/interest/application/service/InterestServiceTest.java index 23ff452a..0ee44233 100644 --- a/src/test/java/com/gomo/app/core/interest/application/usecase/ReadInterestUseCaseTest.java +++ b/src/test/java/com/gomo/app/core/interest/application/service/InterestServiceTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.application.usecase; +package com.gomo.app.core.interest.application.service; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; @@ -15,26 +15,26 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; +import com.gomo.app.core.interest.application.port.command.UpdateInterestCommand; import com.gomo.app.core.interest.application.port.dto.InterestDto; +import com.gomo.app.core.interest.domain.exception.InterestNotFoundException; +import com.gomo.app.core.interest.domain.exception.code.InterestErrorCode; import com.gomo.app.core.interest.domain.model.Interest; import com.gomo.app.core.interest.domain.model.MajorInterest; import com.gomo.app.core.interest.domain.repository.InterestRepository; import com.gomo.app.core.interest.domain.repository.MajorInterestRepository; -import com.gomo.app.core.interest.domain.service.InterestService; import com.gomo.app.core.interest.fixture.InterestFixture; import com.gomo.app.core.interest.fixture.MajorInterestFixture; -@DisplayName("[Application unit]: 관심사 조회 테스트") +@DisplayName("[Application unit]: 관심사 서비스 테스트") @ExtendWith(MockitoExtension.class) -public class ReadInterestUseCaseTest { +public class InterestServiceTest { @InjectMocks - private ReadInterestUseCase sut; - - @Mock - private InterestService interestService; + private InterestService sut; @Mock private InterestRepository interestRepository; @@ -44,13 +44,13 @@ public class ReadInterestUseCaseTest { @DisplayName("관심사를 단건 조회한다.") @Test - void find_interest() { + void read_interest() { Interest expected = InterestFixture.create(); MajorInterest majorInterest = MajorInterestFixture.create(expected.getRegistrantId(), expected.getId()); - doReturn(expected).when(interestService).find(any()); + doReturn(Optional.of(expected)).when(interestRepository).findById(any()); doReturn(Optional.of(majorInterest)).when(majorInterestRepository).findByInterestId(any()); - InterestDto actual = sut.find(expected.getId()); + InterestDto actual = sut.read(expected.getId()); assertThat(actual) .extracting("id", "registrantId", "name", "logoUrl", "majorInterestId") @@ -65,14 +65,14 @@ void find_interest() { @DisplayName("관심사 목록을 조회한다.") @Test - void find_interest_list() { + void read_interest_list() { Interest expected1 = InterestFixture.create(); Interest expected2 = InterestFixture.create(); MajorInterest majorInterest = MajorInterestFixture.create(expected1.getRegistrantId(), expected1.getId()); doReturn(List.of(expected1, expected2)).when(interestRepository).findAllByRegistrantId(any()); doReturn(List.of(majorInterest)).when(majorInterestRepository).findAllByRegistrantIdAndInterestIdIn(any(), any()); - List actual = sut.findAll(expected1.getRegistrantId()); + List actual = sut.readAll(expected1.getRegistrantId()); assertThat(actual) .hasSize(2) @@ -82,14 +82,14 @@ void find_interest_list() { @DisplayName("등록자 아이디 목록으로 관심사 목록을 조회한다.") @Test - void find_interest_list_by_registrant_ids() { + void read_interest_list_by_registrant_ids() { Interest expected1 = InterestFixture.create(); Interest expected2 = InterestFixture.create(); MajorInterest majorInterest = MajorInterestFixture.create(expected1.getRegistrantId(), expected1.getId()); doReturn(List.of(expected1, expected2)).when(interestRepository).findAllByRegistrantIdIn(any()); doReturn(List.of(majorInterest)).when(majorInterestRepository).findByInterestIdIn(any()); - List actual = sut.findAllByRegistrantIds(Set.of(expected1.getRegistrantId(), expected2.getRegistrantId())); + List actual = sut.readAllByRegistrantIds(Set.of(expected1.getRegistrantId(), expected2.getRegistrantId())); assertThat(actual) .hasSize(2) @@ -97,6 +97,47 @@ void find_interest_list_by_registrant_ids() { .containsExactly(createTuple(expected1, majorInterest.getId()), createTuple(expected2, null)); } + @DisplayName("관심사를 조회한다.") + @Test + void read_interest_entity() { + Interest interest = InterestFixture.create(); + doReturn(Optional.of(interest)).when(interestRepository).findById(any()); + + Interest actual = sut.readById(interest.getId()); + + assertThat(actual.getId()).isEqualTo(interest.getId()); + } + + @DisplayName("존재하지 않는 관심사를 조회한다.") + @Test + void read_nonexistent_interest_entity() { + doReturn(Optional.empty()).when(interestRepository).findById(any()); + + assertThatThrownBy(() -> sut.readById(UUID.randomUUID())) + .isInstanceOf(InterestNotFoundException.class) + .hasMessageContaining(InterestErrorCode.NOT_FOUND.getMessage()); + } + + @DisplayName("관심사를 수정한다.") + @Test + void update_interest() { + Interest interest = InterestFixture.create(); + doReturn(Optional.of(interest)).when(interestRepository).findById(any()); + + sut.update(UpdateInterestCommand.of(interest.registrantId(), interest.getId(), "name", "#FF0000")); + } + + @DisplayName("관심사를 수정하기 전, 권한 검사를 한다.") + @Test + void update_interest_by_unauthorized_accessor() { + Interest interest = Mockito.mock(Interest.class); + doReturn(Optional.of(interest)).when(interestRepository).findById(any()); + + sut.update(UpdateInterestCommand.of(UUID.randomUUID(), UUID.randomUUID(), "name", "#FF0000")); + + verify(interest, times(1)).validateAuthority(any(UUID.class)); + } + private @NotNull Tuple createTuple(Interest interest, UUID majorInterestId) { return tuple( interest.getId(), diff --git a/src/test/java/com/gomo/app/core/interest/application/usecase/UpdateLogoUseCaseTest.java b/src/test/java/com/gomo/app/core/interest/application/service/LogoServiceTest.java similarity index 54% rename from src/test/java/com/gomo/app/core/interest/application/usecase/UpdateLogoUseCaseTest.java rename to src/test/java/com/gomo/app/core/interest/application/service/LogoServiceTest.java index 5fef662e..182901fb 100644 --- a/src/test/java/com/gomo/app/core/interest/application/usecase/UpdateLogoUseCaseTest.java +++ b/src/test/java/com/gomo/app/core/interest/application/service/LogoServiceTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.application.usecase; +package com.gomo.app.core.interest.application.service; import static org.mockito.Mockito.*; @@ -14,50 +14,47 @@ import org.springframework.mock.web.MockMultipartFile; import org.springframework.web.multipart.MultipartFile; +import com.gomo.app.core.interest.application.port.out.LogoDeleter; +import com.gomo.app.core.interest.application.port.out.LogoUploader; import com.gomo.app.core.interest.domain.model.Logo; -import com.gomo.app.core.interest.domain.service.InterestService; import com.gomo.app.core.interest.fixture.InterestFixture; -import com.gomo.app.support.image.application.port.DeleteImagePortIn; -import com.gomo.app.support.image.application.port.UploadImagePortIn; @DisplayName("[Application unit]: 관심사 로고 수정 테스트") @ExtendWith(MockitoExtension.class) -public class UpdateLogoUseCaseTest { +public class LogoServiceTest { @InjectMocks - private UpdateLogoUseCase sut; + private LogoService sut; @Mock private InterestService interestService; @Mock - private UploadImagePortIn uploadImagePortIn; + private LogoUploader logoUploader; @Mock - private DeleteImagePortIn deleteImagePortIn; + private LogoDeleter logoDeleter; @DisplayName("사용자가 등록해둔 관심사 로고를 새로운 로고로 변경한다.") @Test void update_interest() { - doReturn(InterestFixture.create()).when(interestService).find(any()); - doReturn(Optional.of("logoUrl")).when(uploadImagePortIn).upload(any(MultipartFile.class)); + doReturn(InterestFixture.create()).when(interestService).readById(any()); + doReturn(Optional.of("logoUrl")).when(logoUploader).upload(any(MultipartFile.class)); sut.update(UUID.randomUUID(), new MockMultipartFile("logoFile", "mock image data".getBytes())); - verify(interestService, times(1)).find(any()); - verify(uploadImagePortIn, times(1)).upload(any(MockMultipartFile.class)); - verify(deleteImagePortIn, times(1)).delete(any(String.class)); + verify(logoUploader, times(1)).upload(any(MockMultipartFile.class)); + verify(logoDeleter, times(1)).delete(any(String.class)); } @DisplayName("기본 관심사 로고를 새로운 로고로 변경한다.") @Test void update_interest_by_unauthorized_accessor() { - doReturn(InterestFixture.create(Logo.of(null))).when(interestService).find(any()); - doReturn(Optional.of("logoUrl")).when(uploadImagePortIn).upload(any(MultipartFile.class)); + doReturn(InterestFixture.create(Logo.of(null))).when(interestService).readById(any()); + doReturn(Optional.of("logoUrl")).when(logoUploader).upload(any(MultipartFile.class)); sut.update(UUID.randomUUID(), new MockMultipartFile("logoFile", "mock image data".getBytes())); - verify(interestService, times(1)).find(any()); - verify(uploadImagePortIn, times(1)).upload(any(MockMultipartFile.class)); + verify(logoUploader, times(1)).upload(any(MockMultipartFile.class)); } } diff --git a/src/test/java/com/gomo/app/core/interest/application/service/MajorInterestServiceTest.java b/src/test/java/com/gomo/app/core/interest/application/service/MajorInterestServiceTest.java new file mode 100644 index 00000000..2b4f0306 --- /dev/null +++ b/src/test/java/com/gomo/app/core/interest/application/service/MajorInterestServiceTest.java @@ -0,0 +1,171 @@ +package com.gomo.app.core.interest.application.service; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.common.displayorder.OrderChanger; +import com.gomo.app.common.displayorder.UpdatedOrderDto; +import com.gomo.app.core.interest.application.port.command.OrderUpdateMajorInterestCommand; +import com.gomo.app.core.interest.application.port.dto.MajorInterestDto; +import com.gomo.app.core.interest.domain.exception.InterestAccessDeniedException; +import com.gomo.app.core.interest.domain.exception.MajorInterestAccessDeniedException; +import com.gomo.app.core.interest.domain.exception.MajorInterestDuplicatedException; +import com.gomo.app.core.interest.domain.model.Interest; +import com.gomo.app.core.interest.domain.model.MajorInterest; +import com.gomo.app.core.interest.domain.repository.InterestRepository; +import com.gomo.app.core.interest.domain.repository.MajorInterestRepository; +import com.gomo.app.core.interest.fixture.InterestFixture; +import com.gomo.app.core.interest.fixture.MajorInterestFixture; + +@DisplayName("[Application unit]: 주요 관심사 서비스 테스트") +@ExtendWith(MockitoExtension.class) +public class MajorInterestServiceTest { + + @InjectMocks + private MajorInterestService sut; + + @Mock + private InterestService interestService; + + @Mock + private MajorInterestRepository majorInterestRepository; + + @Mock + private InterestRepository interestRepository; + + @DisplayName("주요 관심사를 등록한다.") + @Test + void create_major_interest() { + MajorInterest majorInterest = MajorInterestFixture.create(); + doReturn(InterestFixture.create(majorInterest.getRegistrantId())).when(interestService).readById(any()); + doReturn(4).when(majorInterestRepository).findMaxDisplayOrder(any()); + doReturn(majorInterest).when(majorInterestRepository).save(any()); + + UUID actual = sut.create(majorInterest.getRegistrantId(), majorInterest.getInterestId()); + + assertThat(actual).isEqualTo(majorInterest.getId()); + } + + @DisplayName("권한 없는 접근자는 주요 관심사를 등록할 수 없다.") + @Test + void create_major_interest_by_unauthorized_accessor() { + Interest interest = mock(Interest.class); + doReturn(interest).when(interestService).readById(any()); + doThrow(InterestAccessDeniedException.class).when(interest).validateAuthority(any(UUID.class)); + + assertThatThrownBy(() -> sut.create(UUID.randomUUID(), UUID.randomUUID())).isInstanceOf(InterestAccessDeniedException.class); + } + + @DisplayName("이미 주요 관심사로 등록된 관심사는 중복해서 등록할 수 없다.") + @Test + void create_major_interest_with_already_existing_major_interest() { + UUID registrantId = UUID.randomUUID(); + doReturn(InterestFixture.create(registrantId)).when(interestService).readById(any()); + doThrow(MajorInterestDuplicatedException.class).when(majorInterestRepository).findByInterestId(any()); + + assertThatThrownBy(() -> sut.create(registrantId, UUID.randomUUID())) + .isInstanceOf(MajorInterestDuplicatedException.class); + } + + @DisplayName("주요 관심사 목록을 정렬 순서에 맞게 조회한다.") + @Test + void read_interest_by_display_order() { + MajorInterest expected1 = MajorInterestFixture.create(); + MajorInterest expected2 = MajorInterestFixture.create(); + List interests = getInterests(expected1, expected2); + doReturn(interests).when(interestRepository).findAllById(any()); + doReturn(List.of(expected1, expected2)).when(majorInterestRepository).findAllByRegistrantIdOrderByDisplayOrder(any()); + + List actual = sut.readAll(expected1.getRegistrantId()); + + assertThat(actual) + .hasSize(2) + .extracting("id", "interestId", "name") + .containsExactly( + tuple(expected1.getId(), expected1.getInterestId(), "interest1"), + tuple(expected2.getId(), expected2.getInterestId(), "interest2") + ); + } + + private List getInterests(MajorInterest expected1, MajorInterest expected2) { + return List.of( + InterestFixture.create(expected1.getInterestId(), UUID.randomUUID(), "interest1"), + InterestFixture.create(expected2.getInterestId(), UUID.randomUUID(), "interest2") + ); + } + + @DisplayName("주요 관심사를 조회한다.") + @Test + void read_major_interest() { + MajorInterest majorInterest = MajorInterestFixture.create(); + doReturn(Optional.of(majorInterest)).when(majorInterestRepository).findById(any()); + + MajorInterest actual = sut.readById(majorInterest.getId()); + + assertThat(actual).isEqualTo(majorInterest); + } + + @DisplayName("주요 관심사를 삭제한다.") + @Test + void delete_interest() { + MajorInterest majorInterest = MajorInterestFixture.create(); + doReturn(Optional.of(majorInterest)).when(majorInterestRepository).findById(any()); + + sut.delete(majorInterest.getRegistrantId(), majorInterest.getId()); + + verify(majorInterestRepository, times(1)).delete(any(MajorInterest.class)); + } + + @DisplayName("권한 없는 접근자는 주요 관심사를 삭제할 수 없다.") + @Test + void delete_interest_by_unauthorized_accessor() { + MajorInterest majorInterest = mock(MajorInterest.class); + doThrow(MajorInterestAccessDeniedException.class).when(majorInterest).validateAuthority(any(UUID.class)); + doReturn(Optional.of(majorInterest)).when(majorInterestRepository).findById(any()); + + assertThatThrownBy(() -> sut.delete(UUID.randomUUID(), UUID.randomUUID())) + .isInstanceOf(MajorInterestAccessDeniedException.class); + } + + @DisplayName("주요 관심사 정렬 순서를 변경한다.") + @Test + void update_interest_display_order() { + doReturn(getMajorInterests()).when(majorInterestRepository).findAllByRegistrantIdOrderByDisplayOrder(any()); + + try (MockedStatic mockedOrderChanger = mockStatic(OrderChanger.class)) { + sut.update(OrderUpdateMajorInterestCommand.of( + UUID.randomUUID(), + List.of( + UpdatedOrderDto.of(UUID.randomUUID(), 1), + UpdatedOrderDto.of(UUID.randomUUID(), 2), + UpdatedOrderDto.of(UUID.randomUUID(), 3) + ) + ) + ); + + verify(majorInterestRepository, times(1)).findAllByRegistrantIdOrderByDisplayOrder(any()); + mockedOrderChanger.verify(() -> OrderChanger.change(any()), times(1)); + } + } + + private @NotNull List getMajorInterests() { + return List.of( + MajorInterestFixture.create(), + MajorInterestFixture.create(), + MajorInterestFixture.create() + ); + } +} diff --git a/src/test/java/com/gomo/app/core/interest/application/service/ProficiencyServiceTest.java b/src/test/java/com/gomo/app/core/interest/application/service/ProficiencyServiceTest.java new file mode 100644 index 00000000..06b9f76a --- /dev/null +++ b/src/test/java/com/gomo/app/core/interest/application/service/ProficiencyServiceTest.java @@ -0,0 +1,67 @@ +package com.gomo.app.core.interest.application.service; + +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.core.interest.domain.model.Interest; +import com.gomo.app.core.interest.domain.model.InterestRelation; +import com.gomo.app.core.interest.domain.repository.InterestRelationRepository; +import com.gomo.app.core.interest.domain.service.InterestNetworkBuilder; +import com.gomo.app.core.interest.domain.service.ProficiencyCalculator; +import com.gomo.app.core.interest.fixture.InterestFixture; +import com.gomo.app.core.interest.fixture.InterestRelationFixture; + +@DisplayName("[Application unit]: 숙련도 조정 테스트") +@ExtendWith(MockitoExtension.class) +class ProficiencyServiceTest { + + @InjectMocks + private ProficiencyService sut; + + @Mock + private InterestService interestService; + + @Mock + private InterestNetworkBuilder interestNetworkBuilder; + + @Mock + private InterestRelationRepository interestRelationRepository; + + @Mock + private ProficiencyCalculator proficiencyCalculator; + + @DisplayName("하위 관심사의 숙련도가 조정되면, 모든 상위 관심사의 숙련도도 동일한 수치만큼 조정된다.") + @Test + void propagate_proficiency() { + Interest depth1 = spy(InterestFixture.create()); + Interest depth2 = spy(InterestFixture.create()); + Interest depth3 = spy(InterestFixture.create()); + InterestRelation depth1ToDepth2 = InterestRelationFixture.create(depth1, depth2); + InterestRelation depth2ToDepth3 = InterestRelationFixture.create(depth2, depth3); + Map> map = Map.of( + depth2.getId(), Set.of(depth1), + depth3.getId(), Set.of(depth2) + ); + doReturn(depth3).when(interestService).readById(any()); + doReturn(List.of(depth1ToDepth2, depth2ToDepth3)).when(interestRelationRepository).findAllByRegistrantId(any()); + doReturn(map).when(interestNetworkBuilder).buildParentInterestByChildId(any()); + + sut.propagate(depth3.getId(), 20); + + verify(depth1, times(1)).adjustProficiency(eq(20), any()); + verify(depth2, times(1)).adjustProficiency(eq(20), any()); + verify(depth3, times(1)).adjustProficiency(eq(20), any()); + } +} diff --git a/src/test/java/com/gomo/app/core/interest/application/usecase/AdjustProficiencyUseCaseTest.java b/src/test/java/com/gomo/app/core/interest/application/usecase/AdjustProficiencyUseCaseTest.java deleted file mode 100644 index 0813628b..00000000 --- a/src/test/java/com/gomo/app/core/interest/application/usecase/AdjustProficiencyUseCaseTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.gomo.app.core.interest.application.usecase; - -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.interest.domain.service.InterestService; -import com.gomo.app.core.interest.domain.service.ProficiencyService; -import com.gomo.app.core.interest.fixture.InterestFixture; - -@DisplayName("[Application unit]: 숙련도 조정 테스트") -@ExtendWith(MockitoExtension.class) -class AdjustProficiencyUseCaseTest { - - @InjectMocks - private AdjustProficiencyUseCase sut; - - @Mock - private InterestService interestService; - - @Mock - private ProficiencyService proficiencyService; - - @DisplayName("숙련도를 조정한다.") - @Test - void adjust_proficiency() { - doReturn(InterestFixture.create()).when(interestService).find(any()); - - sut.adjust(UUID.randomUUID(), 10); - - verify(proficiencyService, times(1)).adjust(any(), anyInt()); - } -} diff --git a/src/test/java/com/gomo/app/core/interest/application/usecase/CreateInterestRelationUseCaseTest.java b/src/test/java/com/gomo/app/core/interest/application/usecase/CreateInterestRelationUseCaseTest.java deleted file mode 100644 index b920eb07..00000000 --- a/src/test/java/com/gomo/app/core/interest/application/usecase/CreateInterestRelationUseCaseTest.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.gomo.app.core.interest.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.interest.domain.model.Interest; -import com.gomo.app.core.interest.domain.model.InterestRelation; -import com.gomo.app.core.interest.domain.service.InterestRelationService; -import com.gomo.app.core.interest.domain.service.InterestService; -import com.gomo.app.core.interest.fixture.InterestFixture; -import com.gomo.app.core.interest.fixture.InterestRelationFixture; - -@DisplayName("[Application unit]: 관심사 관계 등록 테스트") -@ExtendWith(MockitoExtension.class) -public class CreateInterestRelationUseCaseTest { - - @InjectMocks - private CreateInterestRelationUseCase sut; - - @Mock - private InterestService interestService; - - @Mock - private InterestRelationService interestRelationService; - - @DisplayName("관심사 관계를 등록한다.") - @Test - void create_interest_relation() { - Interest parentInterest = InterestFixture.create(); - Interest childInterest = InterestFixture.create(); - InterestRelation interestRelation = InterestRelationFixture.create(parentInterest, childInterest); - doReturn(parentInterest).when(interestService).find(parentInterest.getId()); - doReturn(childInterest).when(interestService).find(childInterest.getId()); - doReturn(interestRelation).when(interestRelationService).create(any(), any(), any()); - - UUID actual = sut.create(interestRelation.getRegistrantId(), parentInterest.getId(), childInterest.getId()); - - assertThat(actual).isEqualTo(interestRelation.getId()); - } -} diff --git a/src/test/java/com/gomo/app/core/interest/application/usecase/CreateMajorInterestUseCaseTest.java b/src/test/java/com/gomo/app/core/interest/application/usecase/CreateMajorInterestUseCaseTest.java deleted file mode 100644 index 536e584c..00000000 --- a/src/test/java/com/gomo/app/core/interest/application/usecase/CreateMajorInterestUseCaseTest.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.gomo.app.core.interest.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.interest.domain.model.Interest; -import com.gomo.app.core.interest.domain.model.MajorInterest; -import com.gomo.app.core.interest.domain.service.InterestService; -import com.gomo.app.core.interest.domain.service.MajorInterestService; -import com.gomo.app.core.interest.exception.InterestAccessDeniedException; -import com.gomo.app.core.interest.fixture.InterestFixture; -import com.gomo.app.core.interest.fixture.MajorInterestFixture; - -@DisplayName("[Application unit]: 주요 관심사 등록 테스트") -@ExtendWith(MockitoExtension.class) -public class CreateMajorInterestUseCaseTest { - - @InjectMocks - private CreateMajorInterestUseCase sut; - - @Mock - private InterestService interestService; - - @Mock - private MajorInterestService majorInterestService; - - @DisplayName("주요 관심사를 등록한다.") - @Test - void create_major_interest() { - MajorInterest majorInterest = MajorInterestFixture.create(); - doReturn(InterestFixture.create(majorInterest.getRegistrantId())).when(interestService).find(any()); - doReturn(majorInterest).when(majorInterestService).create(any(Interest.class)); - - UUID actual = sut.create(majorInterest.getRegistrantId(), majorInterest.getInterestId()); - - assertThat(actual).isEqualTo(majorInterest.getId()); - } - - @DisplayName("권한 없는 접근자는 주요 관심사를 등록할 수 없다.") - @Test - void create_major_interest_by_unauthorized_accessor() { - Interest interest = mock(Interest.class); - doReturn(interest).when(interestService).find(any()); - doThrow(InterestAccessDeniedException.class).when(interest).validateAuthority(any(UUID.class)); - - assertThatThrownBy(() -> sut.create(UUID.randomUUID(), UUID.randomUUID())).isInstanceOf(InterestAccessDeniedException.class); - } -} diff --git a/src/test/java/com/gomo/app/core/interest/application/usecase/DeleteInterestRelationUseCaseTest.java b/src/test/java/com/gomo/app/core/interest/application/usecase/DeleteInterestRelationUseCaseTest.java deleted file mode 100644 index a38f66f8..00000000 --- a/src/test/java/com/gomo/app/core/interest/application/usecase/DeleteInterestRelationUseCaseTest.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.gomo.app.core.interest.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.interest.domain.model.Interest; -import com.gomo.app.core.interest.domain.model.InterestRelation; -import com.gomo.app.core.interest.domain.service.InterestRelationService; -import com.gomo.app.core.interest.domain.service.InterestService; -import com.gomo.app.core.interest.exception.InterestRelationAccessDeniedException; -import com.gomo.app.core.interest.fixture.InterestFixture; -import com.gomo.app.core.interest.fixture.InterestRelationFixture; - -@DisplayName("[Application unit]: 관심사 관계 삭제 테스트") -@ExtendWith(MockitoExtension.class) -public class DeleteInterestRelationUseCaseTest { - - @InjectMocks - private DeleteInterestRelationUseCase sut; - - @Mock - private InterestService interestService; - - @Mock - private InterestRelationService interestRelationService; - - @DisplayName("관심사 관계를 삭제한다.") - @Test - void delete_interest_relation() { - Interest parentInterest = InterestFixture.create(); - Interest childInterest = InterestFixture.create(); - InterestRelation interestRelation = InterestRelationFixture.create(parentInterest, childInterest); - doReturn(parentInterest).when(interestService).find(parentInterest.getId()); - doReturn(childInterest).when(interestService).find(childInterest.getId()); - doReturn(interestRelation).when(interestRelationService).find(any()); - - sut.delete(interestRelation.getRegistrantId(), interestRelation.getId()); - - verify(interestRelationService, times(1)).delete(any(), any(), any()); - } - - @DisplayName("권한 없는 접근자는 관심사를 삭제할 수 없다.") - @Test - void delete_interest_by_unauthorized_accessor() { - InterestRelation interestRelation = mock(InterestRelation.class); - doReturn(interestRelation).when(interestRelationService).find(any()); - doThrow(InterestRelationAccessDeniedException.class).when(interestRelation).validateAuthority(any(UUID.class)); - - assertThatThrownBy(() -> sut.delete(UUID.randomUUID(), UUID.randomUUID())).isInstanceOf(InterestRelationAccessDeniedException.class); - } -} diff --git a/src/test/java/com/gomo/app/core/interest/application/usecase/DeleteMajorInterestUseCaseTest.java b/src/test/java/com/gomo/app/core/interest/application/usecase/DeleteMajorInterestUseCaseTest.java deleted file mode 100644 index 45d228bc..00000000 --- a/src/test/java/com/gomo/app/core/interest/application/usecase/DeleteMajorInterestUseCaseTest.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.gomo.app.core.interest.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.interest.domain.model.MajorInterest; -import com.gomo.app.core.interest.domain.repository.MajorInterestRepository; -import com.gomo.app.core.interest.domain.service.MajorInterestService; -import com.gomo.app.core.interest.exception.MajorInterestAccessDeniedException; -import com.gomo.app.core.interest.fixture.MajorInterestFixture; - -@DisplayName("[Application unit]: 주요 관심사 삭제 테스트") -@ExtendWith(MockitoExtension.class) -public class DeleteMajorInterestUseCaseTest { - - @InjectMocks - private DeleteMajorInterestUseCase sut; - - @Mock - private MajorInterestService majorInterestService; - - @Mock - private MajorInterestRepository majorInterestRepository; - - @DisplayName("주요 관심사를 삭제한다.") - @Test - void delete_interest() { - MajorInterest majorInterest = MajorInterestFixture.create(); - doReturn(majorInterest).when(majorInterestService).find(any()); - - sut.delete(majorInterest.getRegistrantId(), majorInterest.getId()); - - verify(majorInterestRepository, times(1)).delete(any(MajorInterest.class)); - } - - @DisplayName("권한 없는 접근자는 주요 관심사를 삭제할 수 없다.") - @Test - void delete_interest_by_unauthorized_accessor() { - MajorInterest majorInterest = mock(MajorInterest.class); - doThrow(MajorInterestAccessDeniedException.class).when(majorInterest).validateAuthority(any(UUID.class)); - doReturn(majorInterest).when(majorInterestService).find(any()); - - assertThatThrownBy(() -> sut.delete(UUID.randomUUID(), UUID.randomUUID())) - .isInstanceOf(MajorInterestAccessDeniedException.class); - } -} diff --git a/src/test/java/com/gomo/app/core/interest/application/usecase/OrderUpdateMajorInterestUseCaseTest.java b/src/test/java/com/gomo/app/core/interest/application/usecase/OrderUpdateMajorInterestUseCaseTest.java deleted file mode 100644 index e8327020..00000000 --- a/src/test/java/com/gomo/app/core/interest/application/usecase/OrderUpdateMajorInterestUseCaseTest.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.gomo.app.core.interest.application.usecase; - -import static org.mockito.Mockito.*; - -import java.util.List; -import java.util.UUID; - -import org.jetbrains.annotations.NotNull; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockedStatic; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.common.displayorder.OrderChanger; -import com.gomo.app.common.displayorder.UpdatedOrderDto; -import com.gomo.app.core.interest.application.port.command.OrderUpdateMajorInterestCommand; -import com.gomo.app.core.interest.domain.model.MajorInterest; -import com.gomo.app.core.interest.domain.repository.MajorInterestRepository; -import com.gomo.app.core.interest.fixture.MajorInterestFixture; - -@DisplayName("[Application unit]: 주요 관심사 정렬 순서 변경 테스트") -@ExtendWith(MockitoExtension.class) -public class OrderUpdateMajorInterestUseCaseTest { - - @InjectMocks - private OrderUpdateMajorInterestUseCase sut; - - @Mock - private MajorInterestRepository majorInterestRepository; - - @DisplayName("주요 관심사 정렬 순서를 변경한다.") - @Test - void update_interest_display_order() { - doReturn(getMajorInterests()).when(majorInterestRepository).findAllByRegistrantIdOrderByDisplayOrder(any()); - - try (MockedStatic mockedOrderChanger = mockStatic(OrderChanger.class)) { - sut.update(OrderUpdateMajorInterestCommand.of( - UUID.randomUUID(), - List.of( - UpdatedOrderDto.of(UUID.randomUUID(), 1), - UpdatedOrderDto.of(UUID.randomUUID(), 2), - UpdatedOrderDto.of(UUID.randomUUID(), 3) - ) - ) - ); - - verify(majorInterestRepository, times(1)).findAllByRegistrantIdOrderByDisplayOrder(any()); - mockedOrderChanger.verify(() -> OrderChanger.change(any()), times(1)); - } - } - - private @NotNull List getMajorInterests() { - return List.of( - MajorInterestFixture.create(), - MajorInterestFixture.create(), - MajorInterestFixture.create() - ); - } -} diff --git a/src/test/java/com/gomo/app/core/interest/application/usecase/ReadInterestNetworkUseCaseTest.java b/src/test/java/com/gomo/app/core/interest/application/usecase/ReadInterestNetworkUseCaseTest.java deleted file mode 100644 index 42beb783..00000000 --- a/src/test/java/com/gomo/app/core/interest/application/usecase/ReadInterestNetworkUseCaseTest.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.gomo.app.core.interest.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.List; -import java.util.UUID; - -import org.assertj.core.groups.Tuple; -import org.jetbrains.annotations.NotNull; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.interest.application.port.dto.InterestNetworkDto; -import com.gomo.app.core.interest.domain.model.Interest; -import com.gomo.app.core.interest.domain.model.InterestRelation; -import com.gomo.app.core.interest.domain.model.MajorInterest; -import com.gomo.app.core.interest.domain.repository.InterestRelationRepository; -import com.gomo.app.core.interest.domain.repository.InterestRepository; -import com.gomo.app.core.interest.domain.repository.MajorInterestRepository; -import com.gomo.app.core.interest.fixture.InterestFixture; -import com.gomo.app.core.interest.fixture.InterestRelationFixture; -import com.gomo.app.core.interest.fixture.MajorInterestFixture; - -@DisplayName("[Application unit]: 관심사 네트워크 조회 테스트") -@ExtendWith(MockitoExtension.class) -public class ReadInterestNetworkUseCaseTest { - - @InjectMocks - private ReadInterestNetworkUseCase sut; - - @Mock - private InterestRepository interestRepository; - - @Mock - private MajorInterestRepository majorInterestRepository; - - @Mock - private InterestRelationRepository interestRelationRepository; - - @DisplayName("관심사 네트워크를 조회한다.") - @Test - void find_interest_network() { - Interest expected1 = InterestFixture.create(); - Interest expected2 = InterestFixture.create(); - MajorInterest majorInterest = MajorInterestFixture.create(expected1.getRegistrantId(), expected1.getId()); - doReturn(List.of(expected1, expected2)).when(interestRepository).findAllByRegistrantId(any()); - doReturn(List.of(majorInterest)).when(majorInterestRepository).findAllByRegistrantIdAndInterestIdIn(any(), any()); - - InterestRelation relation = InterestRelationFixture.create(); - doReturn(List.of(relation)).when(interestRelationRepository).findAllByRegistrantId(any()); - - InterestNetworkDto actual = sut.find(relation.getRegistrantId()); - - assertThat(actual.interestDtos()) - .hasSize(2) - .extracting("id", "registrantId", "name", "logoUrl", "proficiency.level", "proficiency.score", "proficiency.totalScore", "majorInterestId") - .containsExactly(createInterestTuple(expected1, majorInterest.getId()), createInterestTuple(expected2, null)); - - assertThat(actual.relationDtos()) - .hasSize(1) - .extracting("id", "registrantId", "parentInterestId", "childInterestId") - .containsExactly(createRelationTuple(relation)); - } - - private @NotNull Tuple createRelationTuple(InterestRelation relation) { - return tuple(relation.getId(), relation.getRegistrantId(), relation.getParentInterestId(), - relation.getChildInterestId()); - } - - private @NotNull Tuple createInterestTuple(Interest interest, UUID majorInterestId) { - return tuple( - interest.getId(), - interest.getRegistrantId(), - interest.name(), - interest.logoUrl(), - interest.getProficiency().level(), - interest.getProficiency().score(), - interest.getProficiency().getTotalScore(), - majorInterestId - ); - } -} diff --git a/src/test/java/com/gomo/app/core/interest/application/usecase/ReadMajorInterestUseCaseTest.java b/src/test/java/com/gomo/app/core/interest/application/usecase/ReadMajorInterestUseCaseTest.java deleted file mode 100644 index c000fefe..00000000 --- a/src/test/java/com/gomo/app/core/interest/application/usecase/ReadMajorInterestUseCaseTest.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.gomo.app.core.interest.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.List; -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.interest.application.port.dto.MajorInterestDto; -import com.gomo.app.core.interest.domain.model.Interest; -import com.gomo.app.core.interest.domain.model.MajorInterest; -import com.gomo.app.core.interest.domain.repository.InterestRepository; -import com.gomo.app.core.interest.domain.repository.MajorInterestRepository; -import com.gomo.app.core.interest.fixture.InterestFixture; -import com.gomo.app.core.interest.fixture.MajorInterestFixture; - -@DisplayName("[Application unit]: 주요 관심사 조회 테스트") -@ExtendWith(MockitoExtension.class) -public class ReadMajorInterestUseCaseTest { - - @InjectMocks - private ReadMajorInterestUseCase sut; - - @Mock - private MajorInterestRepository majorInterestRepository; - - @Mock - private InterestRepository interestRepository; - - @DisplayName("주요 관심사 목록을 정렬 순서에 맞게 조회한다.") - @Test - void find_interest_by_display_order() { - MajorInterest expected1 = MajorInterestFixture.create(); - MajorInterest expected2 = MajorInterestFixture.create(); - List interests = getInterests(expected1, expected2); - doReturn(interests).when(interestRepository).findAllByIdIsIn(any()); - doReturn(List.of(expected1, expected2)).when(majorInterestRepository).findAllByRegistrantIdOrderByDisplayOrder(any()); - - List actual = sut.findAll(expected1.getRegistrantId()); - - assertThat(actual) - .hasSize(2) - .extracting("id", "interestId", "name") - .containsExactly( - tuple(expected1.getId(), expected1.getInterestId(), "interest1"), - tuple(expected2.getId(), expected2.getInterestId(), "interest2") - ); - } - - private List getInterests(MajorInterest expected1, MajorInterest expected2) { - return List.of( - InterestFixture.create(expected1.getInterestId(), UUID.randomUUID(), "interest1"), - InterestFixture.create(expected2.getInterestId(), UUID.randomUUID(), "interest2") - ); - } -} diff --git a/src/test/java/com/gomo/app/core/interest/application/usecase/UpdateInterestUseCaseTest.java b/src/test/java/com/gomo/app/core/interest/application/usecase/UpdateInterestUseCaseTest.java deleted file mode 100644 index 5541d735..00000000 --- a/src/test/java/com/gomo/app/core/interest/application/usecase/UpdateInterestUseCaseTest.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.gomo.app.core.interest.application.usecase; - -import static org.mockito.Mockito.*; - -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.interest.application.port.command.UpdateInterestCommand; -import com.gomo.app.core.interest.domain.model.Interest; -import com.gomo.app.core.interest.domain.service.InterestService; -import com.gomo.app.core.interest.fixture.InterestFixture; - -@DisplayName("[Application unit]: 관심사 수정 테스트") -@ExtendWith(MockitoExtension.class) -public class UpdateInterestUseCaseTest { - - @InjectMocks - private UpdateInterestUseCase sut; - - @Mock - private InterestService interestService; - - @DisplayName("관심사를 수정한다.") - @Test - void update_interest() { - Interest interest = InterestFixture.create(); - doReturn(interest).when(interestService).find(any()); - - sut.update(UpdateInterestCommand.of(interest.registrantId(), interest.getId(), "name", "#FF0000")); - - verify(interestService, times(1)).find(any()); - } - - @DisplayName("관심사를 수정하기 전, 권한 검사를 한다.") - @Test - void update_interest_by_unauthorized_accessor() { - Interest interest = Mockito.mock(Interest.class); - doReturn(interest).when(interestService).find(any()); - - sut.update(UpdateInterestCommand.of(UUID.randomUUID(), UUID.randomUUID(), "name", "#FF0000")); - - verify(interest, times(1)).validateAuthority(any(UUID.class)); - } -} diff --git a/src/test/java/com/gomo/app/core/interest/domain/model/InterestNameTest.java b/src/test/java/com/gomo/app/core/interest/domain/model/InterestNameTest.java index 28cc9d8a..919170e2 100644 --- a/src/test/java/com/gomo/app/core/interest/domain/model/InterestNameTest.java +++ b/src/test/java/com/gomo/app/core/interest/domain/model/InterestNameTest.java @@ -8,8 +8,8 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import com.gomo.app.core.interest.exception.InterestNameConstraintViolationException; -import com.gomo.app.core.interest.exception.code.InterestNameErrorCode; +import com.gomo.app.core.interest.domain.exception.InterestNameConstraintViolationException; +import com.gomo.app.core.interest.domain.exception.code.InterestNameErrorCode; @DisplayName("[Domain unit]: 관심사 이름 생성 및 수정 테스트") public class InterestNameTest { diff --git a/src/test/java/com/gomo/app/core/interest/domain/model/InterestRelationTest.java b/src/test/java/com/gomo/app/core/interest/domain/model/InterestRelationTest.java index d42498ef..747bc8da 100644 --- a/src/test/java/com/gomo/app/core/interest/domain/model/InterestRelationTest.java +++ b/src/test/java/com/gomo/app/core/interest/domain/model/InterestRelationTest.java @@ -7,7 +7,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import com.gomo.app.core.interest.exception.InterestRelationAccessDeniedException; +import com.gomo.app.core.interest.domain.exception.InterestRelationAccessDeniedException; @DisplayName("[Domain unit]: 관심사 관계 생성 및 접근 테스트") public class InterestRelationTest { diff --git a/src/test/java/com/gomo/app/core/interest/domain/model/InterestTest.java b/src/test/java/com/gomo/app/core/interest/domain/model/InterestTest.java index 495b20ec..33bdee85 100644 --- a/src/test/java/com/gomo/app/core/interest/domain/model/InterestTest.java +++ b/src/test/java/com/gomo/app/core/interest/domain/model/InterestTest.java @@ -9,7 +9,8 @@ import org.junit.jupiter.api.Test; import org.mockito.Mockito; -import com.gomo.app.core.interest.exception.InterestAccessDeniedException; +import com.gomo.app.core.interest.domain.exception.InterestAccessDeniedException; +import com.gomo.app.core.interest.domain.service.ProficiencyCalculator; @DisplayName("[Domain unit]: 관심사 생성 및 수정 테스트") public class InterestTest { diff --git a/src/test/java/com/gomo/app/core/interest/domain/model/LevelTest.java b/src/test/java/com/gomo/app/core/interest/domain/model/LevelTest.java index 44f097ce..d05bfe62 100644 --- a/src/test/java/com/gomo/app/core/interest/domain/model/LevelTest.java +++ b/src/test/java/com/gomo/app/core/interest/domain/model/LevelTest.java @@ -5,8 +5,8 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import com.gomo.app.core.interest.exception.LevelConstraintViolationException; -import com.gomo.app.core.interest.exception.code.LevelErrorCode; +import com.gomo.app.core.interest.domain.exception.LevelConstraintViolationException; +import com.gomo.app.core.interest.domain.exception.code.LevelErrorCode; @DisplayName("[Domain unit]: 레벨 생성 및 증가 테스트") public class LevelTest { diff --git a/src/test/java/com/gomo/app/core/interest/domain/model/MajorInterestTest.java b/src/test/java/com/gomo/app/core/interest/domain/model/MajorInterestTest.java index c7b0f4b2..dc9175b4 100644 --- a/src/test/java/com/gomo/app/core/interest/domain/model/MajorInterestTest.java +++ b/src/test/java/com/gomo/app/core/interest/domain/model/MajorInterestTest.java @@ -8,7 +8,7 @@ import org.junit.jupiter.api.Test; import com.gomo.app.common.displayorder.DisplayOrder; -import com.gomo.app.core.interest.exception.MajorInterestAccessDeniedException; +import com.gomo.app.core.interest.domain.exception.MajorInterestAccessDeniedException; @DisplayName("[Domain unit]: 주요 관심사 생성 및 수정 테스트") public class MajorInterestTest { @@ -29,6 +29,15 @@ void create_major_interest() { .containsExactly(ID, REGISTRANT_ID, INTEREST_ID, DISPLAY_ORDER); } + @DisplayName("다음 순서의 주요 관심사를 생성한다.") + @Test + void create_next_major_interest() { + int displayOrder = DISPLAY_ORDER.getDisplayOrder(); + MajorInterest majorInterest = MajorInterest.createNext(ID, REGISTRANT_ID, INTEREST_ID, displayOrder); + + assertThat(majorInterest.displayOrder()).isEqualTo(displayOrder + 1); + } + @DisplayName("주요 관심사 정렬 순서를 변경한다.") @Test void update_major_interest_with_display_order() { diff --git a/src/test/java/com/gomo/app/core/interest/domain/model/ProficiencyTest.java b/src/test/java/com/gomo/app/core/interest/domain/model/ProficiencyTest.java index 22f85711..29d4d872 100644 --- a/src/test/java/com/gomo/app/core/interest/domain/model/ProficiencyTest.java +++ b/src/test/java/com/gomo/app/core/interest/domain/model/ProficiencyTest.java @@ -7,6 +7,8 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import com.gomo.app.core.interest.domain.service.ProficiencyCalculator; + @DisplayName("[Domain unit]: 숙련도 생성 및 향상 테스트") public class ProficiencyTest { diff --git a/src/test/java/com/gomo/app/core/interest/domain/model/RegistrantTest.java b/src/test/java/com/gomo/app/core/interest/domain/model/RegistrantTest.java index 91f387ac..ac795c26 100644 --- a/src/test/java/com/gomo/app/core/interest/domain/model/RegistrantTest.java +++ b/src/test/java/com/gomo/app/core/interest/domain/model/RegistrantTest.java @@ -7,8 +7,8 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import com.gomo.app.core.interest.exception.InterestConstraintViolationException; -import com.gomo.app.core.interest.exception.code.InterestErrorCode; +import com.gomo.app.core.interest.domain.exception.InterestConstraintViolationException; +import com.gomo.app.core.interest.domain.exception.code.InterestErrorCode; @DisplayName("[Domain unit]: 관심사 등록자 엔티티 테스트") public class RegistrantTest { diff --git a/src/test/java/com/gomo/app/core/interest/domain/model/ScoreTest.java b/src/test/java/com/gomo/app/core/interest/domain/model/ScoreTest.java index 67c6fbb0..05e5d7d9 100644 --- a/src/test/java/com/gomo/app/core/interest/domain/model/ScoreTest.java +++ b/src/test/java/com/gomo/app/core/interest/domain/model/ScoreTest.java @@ -5,8 +5,8 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import com.gomo.app.core.interest.exception.ScoreConstraintViolationException; -import com.gomo.app.core.interest.exception.code.ScoreErrorCode; +import com.gomo.app.core.interest.domain.exception.ScoreConstraintViolationException; +import com.gomo.app.core.interest.domain.exception.code.ScoreErrorCode; @DisplayName("[Domain unit]: 점수 생성, 증가, 조정, 레벨 증가량 확인 테스트") public class ScoreTest { diff --git a/src/test/java/com/gomo/app/core/interest/infrastructure/repository/InterestRelationRepositoryTest.java b/src/test/java/com/gomo/app/core/interest/domain/repository/InterestRelationRepositoryTest.java similarity index 91% rename from src/test/java/com/gomo/app/core/interest/infrastructure/repository/InterestRelationRepositoryTest.java rename to src/test/java/com/gomo/app/core/interest/domain/repository/InterestRelationRepositoryTest.java index 8a2de3e2..1fd6241e 100644 --- a/src/test/java/com/gomo/app/core/interest/infrastructure/repository/InterestRelationRepositoryTest.java +++ b/src/test/java/com/gomo/app/core/interest/domain/repository/InterestRelationRepositoryTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.infrastructure.repository; +package com.gomo.app.core.interest.domain.repository; import static org.assertj.core.api.Assertions.*; @@ -12,8 +12,6 @@ import com.gomo.app.core.interest.domain.model.Interest; import com.gomo.app.core.interest.domain.model.InterestRelation; -import com.gomo.app.core.interest.domain.repository.InterestRelationRepository; -import com.gomo.app.core.interest.domain.repository.InterestRepository; import com.gomo.app.core.interest.fixture.InterestFixture; import com.gomo.app.core.interest.fixture.InterestRelationFixture; import com.gomo.app.test.IntegrationTest; diff --git a/src/test/java/com/gomo/app/core/interest/infrastructure/repository/MajorInterestRepositoryTest.java b/src/test/java/com/gomo/app/core/interest/domain/repository/MajorInterestRepositoryTest.java similarity index 89% rename from src/test/java/com/gomo/app/core/interest/infrastructure/repository/MajorInterestRepositoryTest.java rename to src/test/java/com/gomo/app/core/interest/domain/repository/MajorInterestRepositoryTest.java index 86585d2e..4613d95f 100644 --- a/src/test/java/com/gomo/app/core/interest/infrastructure/repository/MajorInterestRepositoryTest.java +++ b/src/test/java/com/gomo/app/core/interest/domain/repository/MajorInterestRepositoryTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.interest.infrastructure.repository; +package com.gomo.app.core.interest.domain.repository; import static org.assertj.core.api.Assertions.*; @@ -13,8 +13,6 @@ import com.gomo.app.core.interest.domain.model.Interest; import com.gomo.app.core.interest.domain.model.MajorInterest; -import com.gomo.app.core.interest.domain.repository.InterestRepository; -import com.gomo.app.core.interest.domain.repository.MajorInterestRepository; import com.gomo.app.core.interest.fixture.InterestFixture; import com.gomo.app.core.interest.fixture.MajorInterestFixture; import com.gomo.app.test.IntegrationTest; diff --git a/src/test/java/com/gomo/app/core/interest/domain/service/InterestNetworkBuilderTest.java b/src/test/java/com/gomo/app/core/interest/domain/service/InterestNetworkBuilderTest.java new file mode 100644 index 00000000..ad3b615e --- /dev/null +++ b/src/test/java/com/gomo/app/core/interest/domain/service/InterestNetworkBuilderTest.java @@ -0,0 +1,179 @@ +package com.gomo.app.core.interest.domain.service; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.core.interest.domain.exception.InterestRelationCycleException; +import com.gomo.app.core.interest.domain.model.Interest; +import com.gomo.app.core.interest.domain.model.InterestRelation; +import com.gomo.app.core.interest.domain.repository.InterestRepository; +import com.gomo.app.core.interest.fixture.InterestFixture; +import com.gomo.app.core.interest.fixture.InterestRelationFixture; + +@DisplayName("[Domain unit]: 관심사 네트워크 서비스 테스트") +@ExtendWith(MockitoExtension.class) +class InterestNetworkBuilderTest { + + @InjectMocks + private InterestNetworkBuilder sut; + + @Mock + private InterestRepository interestRepository; + + @Nested + @DisplayName("관심사 네트워크 생성 테스트: 부모 관심사 id -> 자식 관심사 id 목록") + class BuildChildIdByParentId { + + @DisplayName("관심사 관계선이 존재할 때, 부모 ID를 Key로 자식 ID Set을 Value로 갖는 그래프를 생성한다.") + @Test + void build_network() { + UUID registrantId = UUID.randomUUID(); + Interest parent1 = InterestFixture.create(registrantId); + Interest parent2 = InterestFixture.create(registrantId); + Interest child1 = InterestFixture.create(registrantId); + Interest child2 = InterestFixture.create(registrantId); + List relations = List.of( + InterestRelationFixture.create(parent1, child1), + InterestRelationFixture.create(parent1, child2), + InterestRelationFixture.create(parent2, child2) + ); + + Map> network = sut.buildChildIdByParentId(relations); + + assertThat(network).hasSize(2); + assertThat(network.get(parent1.getId())).containsExactlyInAnyOrder(child1.getId(), child2.getId()); + assertThat(network.get(parent2.getId())).containsExactlyInAnyOrder(child2.getId()); + verify(interestRepository, never()).findAllById(any()); + } + + @DisplayName("관심사 관계선이 없으면 빈 그래프를 반환한다.") + @Test + void build_empty_network() { + Map> graph = sut.buildChildIdByParentId(Collections.emptyList()); + + assertThat(graph).isEmpty(); + } + } + + @Nested + @DisplayName("관심사 네트워크 생성 테스트: 자식 관심사 id -> 부모 관심사 목록") + class BuildParentInterestByChildId { + + @DisplayName("관심사 관계선이 존재할 때, 자식 ID를 Key로 부모 Interest Set을 Value로 갖는 그래프를 생성한다.") + @Test + void build_network() { + UUID registrantId = UUID.randomUUID(); + Interest parent1 = InterestFixture.create(registrantId, "parent1"); + Interest parent2 = InterestFixture.create(registrantId, "parent2"); + Interest child1 = InterestFixture.create(registrantId, "child1"); + Interest child2 = InterestFixture.create(registrantId, "child2"); + List relations = List.of( + InterestRelationFixture.create(parent1, child1), + InterestRelationFixture.create(parent2, child1), + InterestRelationFixture.create(parent2, child2) + ); + List allInterests = List.of(parent1, parent2, child1, child2); + Set allInterestIds = allInterests.stream().map(Interest::getId).collect(Collectors.toSet()); + doReturn(allInterests).when(interestRepository).findAllById(allInterestIds); + + Map> graph = sut.buildParentInterestByChildId(relations); + + assertThat(graph).hasSize(2); + assertThat(graph.get(child1.getId())).containsExactlyInAnyOrder(parent1, parent2); + assertThat(graph.get(child2.getId())).containsExactlyInAnyOrder(parent2); + verify(interestRepository, times(1)).findAllById(any()); + } + + @DisplayName("관심사 관계선이 없으면 빈 그래프를 반환하고, 불필요한 관심사 조회를 하지 않는다.") + @Test + void build_empty_network() { + Map> graph = sut.buildParentInterestByChildId(Collections.emptyList()); + + assertThat(graph).isEmpty(); + verify(interestRepository, never()).findAllById(any()); + } + } + + @Nested + @DisplayName("네트워크 순환 구조 검증 테스트") + class ValidateAcyclic { + + @DisplayName("순환이 없는 그래프는 예외를 발생시키지 않는다.") + @Test + void validate_not_acyclic_graph() { + Interest depth1 = InterestFixture.create(); + Interest depth2 = InterestFixture.create(); + Interest depth3 = InterestFixture.create(); + InterestRelation depth1ToDepth2 = InterestRelationFixture.create(depth1, depth2); + InterestRelation depth2ToDepth3 = InterestRelationFixture.create(depth2, depth3); + List relations = List.of(depth1ToDepth2, depth2ToDepth3); + + assertThatCode(() -> sut.validateAcyclic(relations, depth1.getId())).doesNotThrowAnyException(); + } + + @DisplayName("직접적인 순환(A -> B, B -> A)이 존재하면 예외를 발생시킨다.") + @Test + void validate_direct_acyclic_graph() { + Interest depth1 = InterestFixture.create(); + Interest depth2 = InterestFixture.create(); + InterestRelation depth1ToDepth2 = InterestRelationFixture.create(depth1, depth2); + InterestRelation depth2ToDepth1 = InterestRelationFixture.create(depth2, depth1); + List relations = List.of(depth1ToDepth2, depth2ToDepth1); + + assertThatThrownBy(() -> sut.validateAcyclic(relations, depth1.getId())).isInstanceOf(InterestRelationCycleException.class); + } + + @DisplayName("간접적인 순환(A -> B -> C -> A)이 존재하면 예외를 발생시킨다.") + @Test + void validate_indirect_acyclic_graph() { + Interest depth1 = InterestFixture.create(); + Interest depth2 = InterestFixture.create(); + Interest depth3 = InterestFixture.create(); + InterestRelation depth1ToDepth2 = InterestRelationFixture.create(depth1, depth2); + InterestRelation depth2ToDepth3 = InterestRelationFixture.create(depth2, depth3); + InterestRelation depth3ToDepth1 = InterestRelationFixture.create(depth3, depth1); + List relations = List.of(depth1ToDepth2, depth2ToDepth3, depth3ToDepth1); + + assertThatThrownBy(() -> sut.validateAcyclic(relations, depth1.getId())).isInstanceOf(InterestRelationCycleException.class); + } + + @DisplayName("자기 자신을 참조하는 순환(A -> A)이 존재하면 예외를 발생시킨다.") + @Test + void validate_self_acyclic_graph() { + Interest depth1 = InterestFixture.create(); + List relations = List.of(InterestRelationFixture.create(depth1, depth1)); + + assertThatThrownBy(() -> sut.validateAcyclic(relations, depth1.getId())).isInstanceOf(InterestRelationCycleException.class); + } + + @DisplayName("시작 노드에서 도달할 수 없는 곳은 순환이 있어도 예외를 발생시키지 않는다.") + @Test + void validate_acyclic_graph_doesnt_reach_from_start() { + Interest depth1 = InterestFixture.create(); + Interest depth2 = InterestFixture.create(); + Interest depth3 = InterestFixture.create(); + Interest depth4 = InterestFixture.create(); + InterestRelation depth1ToDepth2 = InterestRelationFixture.create(depth1, depth2); + InterestRelation depth3ToDepth4 = InterestRelationFixture.create(depth3, depth4); + InterestRelation depth4ToDepth3 = InterestRelationFixture.create(depth4, depth3); + List relations = List.of(depth1ToDepth2, depth3ToDepth4, depth4ToDepth3); + + assertThatCode(() -> sut.validateAcyclic(relations, depth1.getId())).doesNotThrowAnyException(); + } + } +} diff --git a/src/test/java/com/gomo/app/core/interest/domain/service/InterestRelationServiceTest.java b/src/test/java/com/gomo/app/core/interest/domain/service/InterestRelationServiceTest.java deleted file mode 100644 index c39bcc95..00000000 --- a/src/test/java/com/gomo/app/core/interest/domain/service/InterestRelationServiceTest.java +++ /dev/null @@ -1,151 +0,0 @@ -package com.gomo.app.core.interest.domain.service; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.interest.domain.model.Interest; -import com.gomo.app.core.interest.domain.model.InterestRelation; -import com.gomo.app.core.interest.domain.repository.InterestRelationRepository; -import com.gomo.app.core.interest.exception.InterestRelationCycleException; -import com.gomo.app.core.interest.exception.InterestRelationDuplicatedException; -import com.gomo.app.core.interest.exception.InterestRelationNotFoundException; -import com.gomo.app.core.interest.exception.code.InterestRelationErrorCode; -import com.gomo.app.core.interest.fixture.InterestFixture; -import com.gomo.app.core.interest.fixture.InterestRelationFixture; - -@DisplayName("[Domain unit]: 관심사 관계선 생성 테스트") -@ExtendWith(MockitoExtension.class) -public class InterestRelationServiceTest { - - @InjectMocks - private InterestRelationService sut; - - @Mock - private ProficiencyService proficiencyService; - - @Mock - private InterestRelationRepository interestRelationRepository; - - @DisplayName("관심사 관계선을 생성하면 상위 관심사의 총 점수가 하위 관심사의 총 점수 만큼 증가한다.") - @Test - void create_relation() { - UUID registrantId = UUID.randomUUID(); - Interest depth1 = InterestFixture.create(registrantId, "depth1"); - Interest depth2 = InterestFixture.create(registrantId, "depth2"); - - doReturn(false).when(interestRelationRepository).existsRelationFor(any(), any()); - doReturn(new ArrayList<>()).when(interestRelationRepository).findAllByRegistrantId(any()); - - sut.create(registrantId, depth1, depth2); - - verify(proficiencyService, times(1)).adjust(any(), eq(0)); - verify(interestRelationRepository, times(1)).save(any()); - } - - @DisplayName("관심사 관계선은 중복 생성할 수 없다.") - @Test - void create_duplicated_relation() { - UUID registrantId = UUID.randomUUID(); - - doReturn(true).when(interestRelationRepository).existsRelationFor(any(), any()); - - assertThatThrownBy(() -> sut.create(registrantId, InterestFixture.create(), InterestFixture.create())) - .isInstanceOf(InterestRelationDuplicatedException.class) - .hasMessageContaining(InterestRelationErrorCode.DUPLICATED.getMessage()); - } - - @DisplayName("같은 방향으로 순환이 발생하지 않는 관심사 관계선을 추가한다.") - @Test - void create_no_cyclic_relation() { - // given: 1 -> 2, 2 -> 3, when: 1 -> 3 - UUID registrantId = UUID.randomUUID(); - Interest depth1 = InterestFixture.create(registrantId, "depth1"); - Interest depth2 = InterestFixture.create(registrantId, "depth2"); - Interest depth3 = InterestFixture.create(registrantId, "depth3"); - InterestRelation depth1ToDepth2 = InterestRelationFixture.create(depth1, depth2); - InterestRelation depth2ToDepth3 = InterestRelationFixture.create(depth2, depth3); - List relations = new ArrayList<>(); - relations.add(depth1ToDepth2); - relations.add(depth2ToDepth3); - - doReturn(false).when(interestRelationRepository).existsRelationFor(any(), any()); - doReturn(relations).when(interestRelationRepository).findAllByRegistrantId(any()); - - assertThatCode(() -> sut.create(registrantId, depth1, depth3)).doesNotThrowAnyException(); - } - - @DisplayName("같은 방향으로 순환이 발생하는 관심사 관계선은 생성할 수 없다.") - @Test - void create_cyclic_relation() { - // given: 1 -> 2, 2 -> 3, when: 3 -> 1 - UUID registrantId = UUID.randomUUID(); - Interest depth1 = InterestFixture.create(registrantId, "depth1"); - Interest depth2 = InterestFixture.create(registrantId, "depth2"); - Interest depth3 = InterestFixture.create(registrantId, "depth3"); - InterestRelation depth1ToDepth2 = InterestRelationFixture.create(depth1, depth2); - InterestRelation depth2ToDepth3 = InterestRelationFixture.create(depth2, depth3); - List relations = new ArrayList<>(); - relations.add(depth1ToDepth2); - relations.add(depth2ToDepth3); - - doReturn(false).when(interestRelationRepository).existsRelationFor(any(), any()); - doReturn(relations).when(interestRelationRepository).findAllByRegistrantId(any()); - - assertThatThrownBy(() -> sut.create(registrantId, depth3, depth1)) - .isInstanceOf(InterestRelationCycleException.class) - .hasMessageContaining(InterestRelationErrorCode.UNEXPECTED_CYCLE.getMessage()); - } - - @DisplayName("관심사 관계선을 조회한다.") - @Test - void find_relation() { - InterestRelation interestRelation = InterestRelationFixture.create(); - doReturn(Optional.of(interestRelation)).when(interestRelationRepository).findById(any()); - - InterestRelation actual = sut.find(interestRelation.getId()); - - assertThat(actual.getId()).isEqualTo(interestRelation.getId()); - } - - @DisplayName("존재하지 않는 관심사 관계선을 조회한다.") - @Test - void find_nonexistent_relation() { - doReturn(Optional.empty()).when(interestRelationRepository).findById(any()); - - assertThatThrownBy(() -> sut.find(UUID.randomUUID())) - .isInstanceOf(InterestRelationNotFoundException.class) - .hasMessageContaining(InterestRelationErrorCode.NOT_FOUND.getMessage()); - } - - @DisplayName("관심사 관계선 목록을 조회한다.") - @Test - void find_all_relation_by_interest() { - doReturn(List.of(InterestRelationFixture.create(), InterestRelationFixture.create())).when(interestRelationRepository).findAllByInterestId(any()); - - List actual = sut.findAllByInterestId(UUID.randomUUID()); - - assertThat(actual).hasSize(2); - } - - @DisplayName("관심사 관계선을 삭제하면 상위 관심사의 총 점수가 하위 관심사의 총 점수 만큼 감소한다.") - @Test - void delete_relation() { - sut.delete(InterestRelationFixture.create(), InterestFixture.create(), InterestFixture.create()); - - verify(proficiencyService, times(1)).adjust(any(), eq(0)); - verify(interestRelationRepository, times(1)).delete(any()); - } -} diff --git a/src/test/java/com/gomo/app/core/interest/domain/service/InterestServiceTest.java b/src/test/java/com/gomo/app/core/interest/domain/service/InterestServiceTest.java deleted file mode 100644 index e3b44c5e..00000000 --- a/src/test/java/com/gomo/app/core/interest/domain/service/InterestServiceTest.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.gomo.app.core.interest.domain.service; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.Optional; -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.interest.domain.model.Interest; -import com.gomo.app.core.interest.domain.repository.InterestRepository; -import com.gomo.app.core.interest.exception.InterestNotFoundException; -import com.gomo.app.core.interest.exception.code.InterestErrorCode; -import com.gomo.app.core.interest.fixture.InterestFixture; - -@DisplayName("[Domain unit]: 관심사 조회 테스트") -@ExtendWith(MockitoExtension.class) -public class InterestServiceTest { - - @InjectMocks - private InterestService sut; - - @Mock - private InterestRepository interestRepository; - - @DisplayName("관심사를 조회한다.") - @Test - void read_interest() { - Interest interest = InterestFixture.create(); - doReturn(Optional.of(interest)).when(interestRepository).findById(any()); - - Interest actual = sut.find(interest.getId()); - - assertThat(actual.getId()).isEqualTo(interest.getId()); - } - - @DisplayName("존재하지 않는 관심사를 조회한다.") - @Test - void read_nonexistent_interest() { - doReturn(Optional.empty()).when(interestRepository).findById(any()); - - assertThatThrownBy(() -> sut.find(UUID.randomUUID())) - .isInstanceOf(InterestNotFoundException.class) - .hasMessageContaining(InterestErrorCode.NOT_FOUND.getMessage()); - } -} diff --git a/src/test/java/com/gomo/app/core/interest/domain/service/LogoServiceTest.java b/src/test/java/com/gomo/app/core/interest/domain/service/LogoServiceTest.java deleted file mode 100644 index cf1abfec..00000000 --- a/src/test/java/com/gomo/app/core/interest/domain/service/LogoServiceTest.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.gomo.app.core.interest.domain.service; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.List; -import java.util.Set; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.interest.domain.repository.InterestRepository; - -@DisplayName("[Domain unit]: 로고 서비스 테스트") -@ExtendWith(MockitoExtension.class) -class LogoServiceTest { - - @InjectMocks - private LogoService sut; - - @Mock - private InterestRepository interestRepository; - - @DisplayName("모든 로고 url을 조회한다.") - @Test - void find_all_logo_url() { - doReturn(List.of("logoA", "logoB", "logoC")).when(interestRepository).findAllLogoUrl(); - - Set urls = sut.findAllUrls(); - - assertThat(urls.size()).isEqualTo(3); - } -} diff --git a/src/test/java/com/gomo/app/core/interest/domain/service/MajorInterestServiceTest.java b/src/test/java/com/gomo/app/core/interest/domain/service/MajorInterestServiceTest.java deleted file mode 100644 index 4dcc1ad2..00000000 --- a/src/test/java/com/gomo/app/core/interest/domain/service/MajorInterestServiceTest.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.gomo.app.core.interest.domain.service; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.interest.domain.model.MajorInterest; -import com.gomo.app.core.interest.domain.repository.MajorInterestRepository; -import com.gomo.app.core.interest.exception.MajorInterestDuplicatedException; -import com.gomo.app.core.interest.fixture.InterestFixture; -import com.gomo.app.core.interest.fixture.MajorInterestFixture; - -@DisplayName("[Domain unit]: 주요 관심사 생성 테스트") -@ExtendWith(MockitoExtension.class) -public class MajorInterestServiceTest { - - @InjectMocks - private MajorInterestService sut; - - @Mock - private MajorInterestRepository majorInterestRepository; - - @DisplayName("주요 관심사를 생성한다.") - @Test - void create_major_interest() { - MajorInterest majorInterest = MajorInterestFixture.create(); - - doReturn(4).when(majorInterestRepository).findMaxDisplayOrder(any()); - doReturn(majorInterest).when(majorInterestRepository).save(any()); - - MajorInterest actual = sut.create(InterestFixture.create()); - - assertThat(actual.getId()).isEqualTo(majorInterest.getId()); - } - - @DisplayName("이미 주요 관심사로 등록된 관심사는 중복해서 등록할 수 없다.") - @Test - void create_major_interest_with_already_existing_major_interest() { - doThrow(MajorInterestDuplicatedException.class).when(majorInterestRepository).findByInterestId(any()); - - assertThatThrownBy(() -> sut.create(InterestFixture.create())) - .isInstanceOf(MajorInterestDuplicatedException.class); - } - - @DisplayName("새로 생성된 반복 퀘스트의 정렬 순서는 현재 등록된 반복 퀘스트의 마지막 번호 + 1이다.") - @Test - void create_major_interest_with_display_order() { - int maxDisplayOrder = 4; - - doReturn(maxDisplayOrder).when(majorInterestRepository).findMaxDisplayOrder(any()); - doReturn(MajorInterestFixture.create(maxDisplayOrder + 1)).when(majorInterestRepository).save(any()); - - MajorInterest actual = sut.create(InterestFixture.create()); - - assertThat(actual.getDisplayOrder().getDisplayOrder()).isEqualTo(maxDisplayOrder + 1); - } -} diff --git a/src/test/java/com/gomo/app/core/interest/domain/model/ProficiencyCalculatorTest.java b/src/test/java/com/gomo/app/core/interest/domain/service/ProficiencyCalculatorTest.java similarity index 66% rename from src/test/java/com/gomo/app/core/interest/domain/model/ProficiencyCalculatorTest.java rename to src/test/java/com/gomo/app/core/interest/domain/service/ProficiencyCalculatorTest.java index 62635e4e..3c63eaec 100644 --- a/src/test/java/com/gomo/app/core/interest/domain/model/ProficiencyCalculatorTest.java +++ b/src/test/java/com/gomo/app/core/interest/domain/service/ProficiencyCalculatorTest.java @@ -1,16 +1,31 @@ -package com.gomo.app.core.interest.domain.model; +package com.gomo.app.core.interest.domain.service; import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.core.interest.domain.exception.ProficiencyAdjustFailureException; +import com.gomo.app.core.interest.domain.model.LevelThresholdPolicy; +import com.gomo.app.core.interest.domain.model.Proficiency; +import com.gomo.app.core.interest.domain.repository.LevelThresholdPolicyRepository; + +@DisplayName("[Domain unit]: 숙련도 연산 테스트") +@ExtendWith(MockitoExtension.class) +class ProficiencyCalculatorTest { -import com.gomo.app.core.interest.exception.ProficiencyAdjustFailureException; + @InjectMocks + private ProficiencyCalculator proficiencyCalculator; -@DisplayName("[Domain unit]: 숙련도 정책 연산 테스트") -class ProficiencyCalculatorTest { + @Mock + private LevelThresholdPolicyRepository levelThresholdPolicyRepository; @Test @DisplayName("총점이 0이라면 숙련도는 첫 번째 레벨의 0점이다.") @@ -18,8 +33,9 @@ void calculate_proficiency_with_zero_total_score() { List levelThresholdPolicies = List.of( LevelThresholdPolicy.of(1, 10) ); - ProficiencyCalculator proficiencyCalculator = ProficiencyCalculator.from(levelThresholdPolicies); + doReturn(levelThresholdPolicies).when(levelThresholdPolicyRepository).findAll(); + proficiencyCalculator.initialize(); Proficiency actual = proficiencyCalculator.calculate(0); assertThat(actual.level()).isEqualTo(1); @@ -33,8 +49,9 @@ void calculate_proficiency_with_total_score() { List levelThresholdPolicies = List.of( LevelThresholdPolicy.of(1, 10) ); - ProficiencyCalculator proficiencyCalculator = ProficiencyCalculator.from(levelThresholdPolicies); + doReturn(levelThresholdPolicies).when(levelThresholdPolicyRepository).findAll(); + proficiencyCalculator.initialize(); Proficiency actual = proficiencyCalculator.calculate(5); assertThat(actual.level()).isEqualTo(1); @@ -50,8 +67,9 @@ void calculate_proficiency_at_level_boundary() { LevelThresholdPolicy.of(2, 20), LevelThresholdPolicy.of(3, 30) ); - ProficiencyCalculator proficiencyCalculator = ProficiencyCalculator.from(levelThresholdPolicies); + doReturn(levelThresholdPolicies).when(levelThresholdPolicyRepository).findAll(); + proficiencyCalculator.initialize(); Proficiency actual = proficiencyCalculator.calculate(10); assertThat(actual.level()).isEqualTo(2); @@ -68,8 +86,9 @@ void calculate_proficiency_in_level_interval() { LevelThresholdPolicy.of(3, 30), LevelThresholdPolicy.of(4, 40) ); - ProficiencyCalculator proficiencyCalculator = ProficiencyCalculator.from(levelThresholdPolicies); + doReturn(levelThresholdPolicies).when(levelThresholdPolicyRepository).findAll(); + proficiencyCalculator.initialize(); Proficiency actual = proficiencyCalculator.calculate(31); assertThat(actual.level()).isEqualTo(3); @@ -85,8 +104,9 @@ void calculate_proficiency_at_highest_level() { LevelThresholdPolicy.of(2, 20), LevelThresholdPolicy.of(3, 30) ); - ProficiencyCalculator proficiencyCalculator = ProficiencyCalculator.from(levelThresholdPolicies); + doReturn(levelThresholdPolicies).when(levelThresholdPolicyRepository).findAll(); + proficiencyCalculator.initialize(); Proficiency actual = proficiencyCalculator.calculate(100); assertThat(actual.level()).isEqualTo(3); @@ -97,14 +117,16 @@ void calculate_proficiency_at_highest_level() { @Test @DisplayName("총점은 음수일 수 없다.") void calculate_proficiency_with_negative_total_score() { - ProficiencyCalculator proficiencyCalculator = ProficiencyCalculator.from(List.of()); + doReturn(List.of()).when(levelThresholdPolicyRepository).findAll(); + proficiencyCalculator.initialize(); assertThatThrownBy(() -> proficiencyCalculator.calculate(-1)).isInstanceOf(ProficiencyAdjustFailureException.class); } @Test @DisplayName("정책 목록은 항상 초기화되어 있어야 한다.") void initialize_policies() { - ProficiencyCalculator proficiencyCalculator = ProficiencyCalculator.from(List.of()); + doReturn(List.of()).when(levelThresholdPolicyRepository).findAll(); + proficiencyCalculator.initialize(); assertThatThrownBy(() -> proficiencyCalculator.calculate(10)).isInstanceOf(IllegalStateException.class); } } diff --git a/src/test/java/com/gomo/app/core/interest/domain/service/ProficiencyServiceTest.java b/src/test/java/com/gomo/app/core/interest/domain/service/ProficiencyServiceTest.java deleted file mode 100644 index ad007d93..00000000 --- a/src/test/java/com/gomo/app/core/interest/domain/service/ProficiencyServiceTest.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.gomo.app.core.interest.domain.service; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.List; -import java.util.UUID; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.interest.domain.model.Interest; -import com.gomo.app.core.interest.domain.model.InterestRelation; -import com.gomo.app.core.interest.domain.model.LevelThresholdPolicy; -import com.gomo.app.core.interest.domain.repository.InterestRelationRepository; -import com.gomo.app.core.interest.domain.repository.InterestRepository; -import com.gomo.app.core.interest.domain.repository.LevelThresholdPolicyRepository; -import com.gomo.app.core.interest.fixture.InterestFixture; -import com.gomo.app.core.interest.fixture.InterestRelationFixture; - -@DisplayName("[Domain unit]: 숙련도 향상 테스트") -@ExtendWith(MockitoExtension.class) -public class ProficiencyServiceTest { - - @InjectMocks - private ProficiencyService sut; - - @Mock - private LevelThresholdPolicyRepository levelThresholdPolicyRepository; - - @Mock - private InterestRepository interestRepository; - - @Mock - private InterestRelationRepository interestRelationRepository; - - private UUID registrantId; - - @BeforeEach - public void setUp() { - registrantId = UUID.randomUUID(); - List levelThresholdPolicies = List.of( - LevelThresholdPolicy.of(1, 40) - ); - doReturn(levelThresholdPolicies).when(levelThresholdPolicyRepository).findAll(); - } - - @DisplayName("하위 관심사의 숙련도가 향상된다면, 모든 상위 관심사의 숙련도도 동일한 수치만큼 향상된다.") - @Test - void enhance_proficiency() { - Interest depth1 = InterestFixture.create(registrantId, "depth1", 15); - Interest depth2 = InterestFixture.create(registrantId, "depth2", 10); - Interest depth3 = InterestFixture.create(registrantId, "depth3", 5); - InterestRelation depth1ToDepth2 = InterestRelationFixture.create(depth1, depth2); - InterestRelation depth2ToDepth3 = InterestRelationFixture.create(depth2, depth3); - doReturn(List.of(depth1, depth2, depth3)).when(interestRepository).findAllById(any()); - doReturn(List.of(depth1ToDepth2, depth2ToDepth3)).when(interestRelationRepository).findAllByRegistrantId(registrantId); - - sut.initialize(); - sut.adjust(depth3, 20); - - assertThat(depth1.getProficiency().score()).isEqualTo(35); - assertThat(depth2.getProficiency().score()).isEqualTo(30); - assertThat(depth3.getProficiency().score()).isEqualTo(25); - } - - @DisplayName("하위 관심사의 숙련도가 감소하면, 모든 상위 관심사의 숙련도도 동일한 수치만큼 감소한다.") - @Test - void reduce_proficiency() { - Interest depth1 = InterestFixture.create(registrantId, "depth1", 15); - Interest depth2 = InterestFixture.create(registrantId, "depth2", 10); - Interest depth3 = InterestFixture.create(registrantId, "depth3", 5); - InterestRelation depth1ToDepth2 = InterestRelationFixture.create(depth1, depth2); - InterestRelation depth2ToDepth3 = InterestRelationFixture.create(depth2, depth3); - - doReturn(List.of(depth1, depth2, depth3)).when(interestRepository).findAllById(any()); - doReturn(List.of(depth1ToDepth2, depth2ToDepth3)).when(interestRelationRepository).findAllByRegistrantId(registrantId); - - sut.initialize(); - sut.adjust(depth3, -5); - - assertThat(depth1.getProficiency().score()).isEqualTo(10); - assertThat(depth2.getProficiency().score()).isEqualTo(5); - assertThat(depth3.getProficiency().score()).isEqualTo(0); - } -} diff --git a/src/test/java/com/gomo/app/core/member/documentation/CheckHandleDuplicateDocumentationTest.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/CheckHandleDuplicateDocumentationTest.java similarity index 90% rename from src/test/java/com/gomo/app/core/member/documentation/CheckHandleDuplicateDocumentationTest.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/CheckHandleDuplicateDocumentationTest.java index 3ed709e3..5667ba11 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/CheckHandleDuplicateDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/CheckHandleDuplicateDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation; +package com.gomo.app.core.member.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -10,8 +10,8 @@ import org.junit.jupiter.api.Test; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.member.documentation.snippet.CheckHandleDuplicateSnippet; -import com.gomo.app.core.member.exception.code.HandleErrorCode; +import com.gomo.app.core.member.adapter.in.api.snippet.CheckHandleDuplicateSnippet; +import com.gomo.app.core.member.domain.exception.code.HandleErrorCode; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation Documentation]: 핸들 중복 테스트") diff --git a/src/test/java/com/gomo/app/core/member/documentation/DeleteMemberDocumentationTest.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/DeleteMemberDocumentationTest.java similarity index 92% rename from src/test/java/com/gomo/app/core/member/documentation/DeleteMemberDocumentationTest.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/DeleteMemberDocumentationTest.java index 97ebc8d3..31b1c31d 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/DeleteMemberDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/DeleteMemberDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation; +package com.gomo.app.core.member.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -11,7 +11,7 @@ import org.junit.jupiter.api.Test; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.member.documentation.snippet.DeleteMemberSnippet; +import com.gomo.app.core.member.adapter.in.api.snippet.DeleteMemberSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 회원 탈퇴 테스트") diff --git a/src/test/java/com/gomo/app/core/member/documentation/DeleteProfileBannerDocumentationTest.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/DeleteProfileBannerDocumentationTest.java similarity index 89% rename from src/test/java/com/gomo/app/core/member/documentation/DeleteProfileBannerDocumentationTest.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/DeleteProfileBannerDocumentationTest.java index 930d9af6..8d16c9f0 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/DeleteProfileBannerDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/DeleteProfileBannerDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation; +package com.gomo.app.core.member.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -9,7 +9,7 @@ import org.junit.jupiter.api.Test; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.member.documentation.snippet.DeleteProfileBannerSnippet; +import com.gomo.app.core.member.adapter.in.api.snippet.DeleteProfileBannerSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation Documentation]: 프로필 배너 삭제 테스트") diff --git a/src/test/java/com/gomo/app/core/member/documentation/DeleteProfileImageDocumentationTest.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/DeleteProfileImageDocumentationTest.java similarity index 89% rename from src/test/java/com/gomo/app/core/member/documentation/DeleteProfileImageDocumentationTest.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/DeleteProfileImageDocumentationTest.java index 6bf5664e..d4d69734 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/DeleteProfileImageDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/DeleteProfileImageDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation; +package com.gomo.app.core.member.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -9,7 +9,7 @@ import org.junit.jupiter.api.Test; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.member.documentation.snippet.DeleteProfileImageSnippet; +import com.gomo.app.core.member.adapter.in.api.snippet.DeleteProfileImageSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation Documentation]: 프로필 이미지 삭제 테스트") diff --git a/src/test/java/com/gomo/app/core/member/documentation/ReadMemberDocumentationTest.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/ReadMemberDocumentationTest.java similarity index 93% rename from src/test/java/com/gomo/app/core/member/documentation/ReadMemberDocumentationTest.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/ReadMemberDocumentationTest.java index 1bf730de..832c34d8 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/ReadMemberDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/ReadMemberDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation; +package com.gomo.app.core.member.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -10,7 +10,7 @@ import org.junit.jupiter.api.Test; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.member.documentation.snippet.ReadMemberSnippet; +import com.gomo.app.core.member.adapter.in.api.snippet.ReadMemberSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation Documentation]: 사용자 정보 조회 테스트") diff --git a/src/test/java/com/gomo/app/core/member/documentation/ReadQuestPropertyDocumentationTest.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/ReadQuestPropertyDocumentationTest.java similarity index 90% rename from src/test/java/com/gomo/app/core/member/documentation/ReadQuestPropertyDocumentationTest.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/ReadQuestPropertyDocumentationTest.java index 83ae7e12..c1059236 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/ReadQuestPropertyDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/ReadQuestPropertyDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation; +package com.gomo.app.core.member.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -10,7 +10,7 @@ import org.junit.jupiter.api.Test; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.member.documentation.snippet.ReadQuestPropertySnippet; +import com.gomo.app.core.member.adapter.in.api.snippet.ReadQuestPropertySnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation Documentation]: 퀘스트 설정 값을 조회한다.") diff --git a/src/test/java/com/gomo/app/core/member/documentation/ResetPasswordDocumentationTest.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/ResetPasswordDocumentationTest.java similarity index 84% rename from src/test/java/com/gomo/app/core/member/documentation/ResetPasswordDocumentationTest.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/ResetPasswordDocumentationTest.java index c7291115..5094d2c7 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/ResetPasswordDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/ResetPasswordDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation; +package com.gomo.app.core.member.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -11,9 +11,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.member.documentation.snippet.ResetPasswordSnippet; +import com.gomo.app.core.member.adapter.in.api.request.ResetPasswordRequest; +import com.gomo.app.core.member.adapter.in.api.snippet.ResetPasswordSnippet; import com.gomo.app.core.member.domain.repository.MemberRepository; -import com.gomo.app.core.member.presentation.request.ResetPasswordRequest; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation Documentation]: 비밀번호 초기화 테스트") @@ -36,7 +36,7 @@ void tearDown() { @Test void update_password() { String email = "testmember@naver.com"; - String temporaryToken = generateJwtPortIn.generateTemporaryToken(email, 300); + String temporaryToken = jwtCreator.createTemporaryToken(email, 300); given(this.specification).filter(filter) .header(CONTENT_TYPE, APPLICATION_JSON_VALUE) .body(ResetPasswordRequest.of(email, "Test1234!", temporaryToken)) diff --git a/src/test/java/com/gomo/app/core/member/documentation/UpdateHandleDocumentationTest.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/UpdateHandleDocumentationTest.java similarity index 87% rename from src/test/java/com/gomo/app/core/member/documentation/UpdateHandleDocumentationTest.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/UpdateHandleDocumentationTest.java index dc6c0b19..21585842 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/UpdateHandleDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/UpdateHandleDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation; +package com.gomo.app.core.member.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -10,9 +10,9 @@ import org.junit.jupiter.api.Test; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.member.documentation.snippet.UpdateHandleSnippet; -import com.gomo.app.core.member.exception.code.HandleErrorCode; -import com.gomo.app.core.member.presentation.request.UpdateHandleRequest; +import com.gomo.app.core.member.adapter.in.api.request.UpdateHandleRequest; +import com.gomo.app.core.member.adapter.in.api.snippet.UpdateHandleSnippet; +import com.gomo.app.core.member.domain.exception.code.HandleErrorCode; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation Documentation]: 핸들 수정 테스트") diff --git a/src/test/java/com/gomo/app/core/member/documentation/UpdateMemberDocumentationTest.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/UpdateMemberDocumentationTest.java similarity index 85% rename from src/test/java/com/gomo/app/core/member/documentation/UpdateMemberDocumentationTest.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/UpdateMemberDocumentationTest.java index bb4c71b3..7ad207c4 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/UpdateMemberDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/UpdateMemberDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation; +package com.gomo.app.core.member.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -9,8 +9,8 @@ import org.junit.jupiter.api.Test; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.member.documentation.snippet.UpdateMemberSnippet; -import com.gomo.app.core.member.presentation.request.UpdateMemberRequest; +import com.gomo.app.core.member.adapter.in.api.request.UpdateMemberRequest; +import com.gomo.app.core.member.adapter.in.api.snippet.UpdateMemberSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 회원 기본 정보 수정 테스트") diff --git a/src/test/java/com/gomo/app/core/member/documentation/UpdatePasswordDocumentationTest.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/UpdatePasswordDocumentationTest.java similarity index 85% rename from src/test/java/com/gomo/app/core/member/documentation/UpdatePasswordDocumentationTest.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/UpdatePasswordDocumentationTest.java index 4509c3ee..0bf92ca3 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/UpdatePasswordDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/UpdatePasswordDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation; +package com.gomo.app.core.member.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -9,8 +9,8 @@ import org.junit.jupiter.api.Test; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.member.documentation.snippet.UpdatePasswordSnippet; -import com.gomo.app.core.member.presentation.request.UpdatePasswordRequest; +import com.gomo.app.core.member.adapter.in.api.request.UpdatePasswordRequest; +import com.gomo.app.core.member.adapter.in.api.snippet.UpdatePasswordSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation Documentation]: 비밀번호 수정 테스트") diff --git a/src/test/java/com/gomo/app/core/member/documentation/UpdateProfileBannerDocumentationTest.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/UpdateProfileBannerDocumentationTest.java similarity index 91% rename from src/test/java/com/gomo/app/core/member/documentation/UpdateProfileBannerDocumentationTest.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/UpdateProfileBannerDocumentationTest.java index 03568459..3f4a1c78 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/UpdateProfileBannerDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/UpdateProfileBannerDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation; +package com.gomo.app.core.member.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -13,7 +13,7 @@ import org.springframework.restdocs.restassured.RestDocumentationFilter; import org.springframework.util.ResourceUtils; -import com.gomo.app.core.member.documentation.snippet.UpdateProfileBannerSnippet; +import com.gomo.app.core.member.adapter.in.api.snippet.UpdateProfileBannerSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation Documentation]: 프로필 배너 변경 테스트") diff --git a/src/test/java/com/gomo/app/core/member/documentation/UpdateProfileImageDocumentationTest.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/UpdateProfileImageDocumentationTest.java similarity index 91% rename from src/test/java/com/gomo/app/core/member/documentation/UpdateProfileImageDocumentationTest.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/UpdateProfileImageDocumentationTest.java index 92d3f60c..7597faf6 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/UpdateProfileImageDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/UpdateProfileImageDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation; +package com.gomo.app.core.member.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -13,7 +13,7 @@ import org.springframework.restdocs.restassured.RestDocumentationFilter; import org.springframework.util.ResourceUtils; -import com.gomo.app.core.member.documentation.snippet.UpdateProfileImageSnippet; +import com.gomo.app.core.member.adapter.in.api.snippet.UpdateProfileImageSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation Documentation]: 프로필 이미지 수정 테스트") diff --git a/src/test/java/com/gomo/app/core/member/documentation/UpdateQuestPropertyDocumentationTest.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/UpdateQuestPropertyDocumentationTest.java similarity index 84% rename from src/test/java/com/gomo/app/core/member/documentation/UpdateQuestPropertyDocumentationTest.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/UpdateQuestPropertyDocumentationTest.java index 6f9b6b9f..24e95e68 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/UpdateQuestPropertyDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/UpdateQuestPropertyDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation; +package com.gomo.app.core.member.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -9,8 +9,8 @@ import org.junit.jupiter.api.Test; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.member.documentation.snippet.UpdateQuestPropertySnippet; -import com.gomo.app.core.member.presentation.request.UpdateQuestPropertyRequest; +import com.gomo.app.core.member.adapter.in.api.request.UpdateQuestPropertyRequest; +import com.gomo.app.core.member.adapter.in.api.snippet.UpdateQuestPropertySnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation Documentation]: 퀘스트 설정 값을 변경한다.") diff --git a/src/test/java/com/gomo/app/core/member/documentation/UpdateWidgetDocumentationTest.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/UpdateWidgetDocumentationTest.java similarity index 85% rename from src/test/java/com/gomo/app/core/member/documentation/UpdateWidgetDocumentationTest.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/UpdateWidgetDocumentationTest.java index 5b1478f2..7ca2da43 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/UpdateWidgetDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/UpdateWidgetDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation; +package com.gomo.app.core.member.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -9,8 +9,8 @@ import org.junit.jupiter.api.Test; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.member.documentation.snippet.UpdateWidgetSnippet; -import com.gomo.app.core.member.presentation.request.UpdateWidgetRequest; +import com.gomo.app.core.member.adapter.in.api.request.UpdateWidgetRequest; +import com.gomo.app.core.member.adapter.in.api.snippet.UpdateWidgetSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation Documentation]: 위젯 스냅샷 수정 테스트") diff --git a/src/test/java/com/gomo/app/core/member/documentation/snippet/CheckHandleDuplicateSnippet.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/CheckHandleDuplicateSnippet.java similarity index 95% rename from src/test/java/com/gomo/app/core/member/documentation/snippet/CheckHandleDuplicateSnippet.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/CheckHandleDuplicateSnippet.java index cf4b088c..9e5dce6f 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/snippet/CheckHandleDuplicateSnippet.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/CheckHandleDuplicateSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation.snippet; +package com.gomo.app.core.member.adapter.in.api.snippet; import static org.springframework.restdocs.operation.preprocess.Preprocessors.*; import static org.springframework.restdocs.request.RequestDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/member/documentation/snippet/DeleteMemberSnippet.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/DeleteMemberSnippet.java similarity index 95% rename from src/test/java/com/gomo/app/core/member/documentation/snippet/DeleteMemberSnippet.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/DeleteMemberSnippet.java index e21b8eba..a770ae81 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/snippet/DeleteMemberSnippet.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/DeleteMemberSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation.snippet; +package com.gomo.app.core.member.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/member/documentation/snippet/DeleteProfileBannerSnippet.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/DeleteProfileBannerSnippet.java similarity index 95% rename from src/test/java/com/gomo/app/core/member/documentation/snippet/DeleteProfileBannerSnippet.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/DeleteProfileBannerSnippet.java index b126a2f7..5bb2dfe8 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/snippet/DeleteProfileBannerSnippet.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/DeleteProfileBannerSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation.snippet; +package com.gomo.app.core.member.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/member/documentation/snippet/DeleteProfileImageSnippet.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/DeleteProfileImageSnippet.java similarity index 95% rename from src/test/java/com/gomo/app/core/member/documentation/snippet/DeleteProfileImageSnippet.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/DeleteProfileImageSnippet.java index cc0d25e8..fde5dd1d 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/snippet/DeleteProfileImageSnippet.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/DeleteProfileImageSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation.snippet; +package com.gomo.app.core.member.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/member/documentation/snippet/ReadMemberSnippet.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/ReadMemberSnippet.java similarity index 97% rename from src/test/java/com/gomo/app/core/member/documentation/snippet/ReadMemberSnippet.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/ReadMemberSnippet.java index b0363e42..158614ec 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/snippet/ReadMemberSnippet.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/ReadMemberSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation.snippet; +package com.gomo.app.core.member.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/member/documentation/snippet/ReadQuestPropertySnippet.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/ReadQuestPropertySnippet.java similarity index 96% rename from src/test/java/com/gomo/app/core/member/documentation/snippet/ReadQuestPropertySnippet.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/ReadQuestPropertySnippet.java index 3d2e1e0e..5513e500 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/snippet/ReadQuestPropertySnippet.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/ReadQuestPropertySnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation.snippet; +package com.gomo.app.core.member.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/member/documentation/snippet/ResetPasswordSnippet.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/ResetPasswordSnippet.java similarity index 96% rename from src/test/java/com/gomo/app/core/member/documentation/snippet/ResetPasswordSnippet.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/ResetPasswordSnippet.java index 43d8d234..16499bea 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/snippet/ResetPasswordSnippet.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/ResetPasswordSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation.snippet; +package com.gomo.app.core.member.adapter.in.api.snippet; import static com.gomo.app.test.ErrorResponseFields.*; import static org.springframework.http.HttpHeaders.*; diff --git a/src/test/java/com/gomo/app/core/member/documentation/snippet/UpdateHandleSnippet.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/UpdateHandleSnippet.java similarity index 96% rename from src/test/java/com/gomo/app/core/member/documentation/snippet/UpdateHandleSnippet.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/UpdateHandleSnippet.java index 29aa8cff..cac9bf75 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/snippet/UpdateHandleSnippet.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/UpdateHandleSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation.snippet; +package com.gomo.app.core.member.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/member/documentation/snippet/UpdateMemberSnippet.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/UpdateMemberSnippet.java similarity index 96% rename from src/test/java/com/gomo/app/core/member/documentation/snippet/UpdateMemberSnippet.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/UpdateMemberSnippet.java index b894ea98..c6ecad6c 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/snippet/UpdateMemberSnippet.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/UpdateMemberSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation.snippet; +package com.gomo.app.core.member.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/member/documentation/snippet/UpdatePasswordSnippet.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/UpdatePasswordSnippet.java similarity index 96% rename from src/test/java/com/gomo/app/core/member/documentation/snippet/UpdatePasswordSnippet.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/UpdatePasswordSnippet.java index d0ad4be7..2ad095ef 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/snippet/UpdatePasswordSnippet.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/UpdatePasswordSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation.snippet; +package com.gomo.app.core.member.adapter.in.api.snippet; import static com.gomo.app.test.ErrorResponseFields.*; import static org.springframework.http.HttpHeaders.*; diff --git a/src/test/java/com/gomo/app/core/member/documentation/snippet/UpdateProfileBannerSnippet.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/UpdateProfileBannerSnippet.java similarity index 96% rename from src/test/java/com/gomo/app/core/member/documentation/snippet/UpdateProfileBannerSnippet.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/UpdateProfileBannerSnippet.java index 8eb2da33..8df2a35b 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/snippet/UpdateProfileBannerSnippet.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/UpdateProfileBannerSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation.snippet; +package com.gomo.app.core.member.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/member/documentation/snippet/UpdateProfileImageSnippet.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/UpdateProfileImageSnippet.java similarity index 96% rename from src/test/java/com/gomo/app/core/member/documentation/snippet/UpdateProfileImageSnippet.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/UpdateProfileImageSnippet.java index 77620b5d..fa75e244 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/snippet/UpdateProfileImageSnippet.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/UpdateProfileImageSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation.snippet; +package com.gomo.app.core.member.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/member/documentation/snippet/UpdateQuestPropertySnippet.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/UpdateQuestPropertySnippet.java similarity index 96% rename from src/test/java/com/gomo/app/core/member/documentation/snippet/UpdateQuestPropertySnippet.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/UpdateQuestPropertySnippet.java index c6e260a7..df49638b 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/snippet/UpdateQuestPropertySnippet.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/UpdateQuestPropertySnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation.snippet; +package com.gomo.app.core.member.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/member/documentation/snippet/UpdateWidgetSnippet.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/UpdateWidgetSnippet.java similarity index 96% rename from src/test/java/com/gomo/app/core/member/documentation/snippet/UpdateWidgetSnippet.java rename to src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/UpdateWidgetSnippet.java index 2be50fc6..473fa5f4 100644 --- a/src/test/java/com/gomo/app/core/member/documentation/snippet/UpdateWidgetSnippet.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/UpdateWidgetSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.documentation.snippet; +package com.gomo.app.core.member.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/member/adapter/out/client/AuthClientTest.java b/src/test/java/com/gomo/app/core/member/adapter/out/client/AuthClientTest.java new file mode 100644 index 00000000..bb8e548a --- /dev/null +++ b/src/test/java/com/gomo/app/core/member/adapter/out/client/AuthClientTest.java @@ -0,0 +1,28 @@ +package com.gomo.app.core.member.adapter.out.client; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.core.auth.application.port.in.RefreshTokenDeleter; + +@DisplayName("[Adapter Unit]: 리프레시 토큰 삭제 요청 테스트") +@ExtendWith(MockitoExtension.class) +class AuthClientTest { + + @InjectMocks + private AuthClient sut; + + @Mock + private RefreshTokenDeleter refreshTokenDeleter; + + // @DisplayName("리프레시 토큰 삭제를 요청한다.") + // @Test + // void invalidate_refresh_token() { + // sut.logout(UUID.randomUUID()); + // + // verify(refreshTokenDeleter, times(1)).delete(any()); + // } +} diff --git a/src/test/java/com/gomo/app/core/member/adapter/out/client/PointBalanceClientTest.java b/src/test/java/com/gomo/app/core/member/adapter/out/client/PointBalanceClientTest.java new file mode 100644 index 00000000..47d7183f --- /dev/null +++ b/src/test/java/com/gomo/app/core/member/adapter/out/client/PointBalanceClientTest.java @@ -0,0 +1,33 @@ +package com.gomo.app.core.member.adapter.out.client; + +import static org.mockito.Mockito.*; + +import java.util.UUID; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.core.point.application.port.in.BalanceReader; + +@DisplayName("[Adapter Unit]: 포인트 잔고 조회 테스트") +@ExtendWith(MockitoExtension.class) +class PointBalanceClientTest { + + @InjectMocks + private PointBalanceClient sut; + + @Mock + private BalanceReader balanceReader; + + @DisplayName("포인트 잔고를 조회한다.") + @Test + void read_point_balance() { + sut.read(UUID.randomUUID()); + + verify(balanceReader, times(1)).read(any()); + } +} diff --git a/src/test/java/com/gomo/app/core/member/adapter/out/client/ProfileAssetClientTest.java b/src/test/java/com/gomo/app/core/member/adapter/out/client/ProfileAssetClientTest.java new file mode 100644 index 00000000..1e87b2da --- /dev/null +++ b/src/test/java/com/gomo/app/core/member/adapter/out/client/ProfileAssetClientTest.java @@ -0,0 +1,49 @@ +package com.gomo.app.core.member.adapter.out.client; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.Optional; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.mock.web.MockMultipartFile; + +import com.gomo.app.support.image.application.port.in.ImageUploader; + +@DisplayName("[Adapter unit]: 프로필 관련 에셋 업로드 테스트") +@ExtendWith(MockitoExtension.class) +class ProfileAssetClientTest { + + @InjectMocks + private ProfileAssetClient sut; + + @Mock + private ImageUploader imageUploader; + + @DisplayName("이미지를 업로드한다.") + @Test + void upload_image() { + String imageUrl = "image_url"; + doReturn(Optional.of(imageUrl)).when(imageUploader).upload(any()); + + String actual = sut.upload(new MockMultipartFile("image", "image.jpg", "image/jpeg", "image/png".getBytes())); + + assertThat(actual).isEqualTo(imageUrl); + } + + @DisplayName("이미지를 업로드하지 못한다.") + @Test + void upload_image_with_null() { + doReturn(Optional.empty()).when(imageUploader).upload(any()); + + String actual = sut.upload(null); + + assertThat(actual).isNull(); + } +} diff --git a/src/test/java/com/gomo/app/core/member/adapter/out/client/TemporaryTokenClientTest.java b/src/test/java/com/gomo/app/core/member/adapter/out/client/TemporaryTokenClientTest.java new file mode 100644 index 00000000..1922ee2b --- /dev/null +++ b/src/test/java/com/gomo/app/core/member/adapter/out/client/TemporaryTokenClientTest.java @@ -0,0 +1,43 @@ +package com.gomo.app.core.member.adapter.out.client; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.core.auth.application.port.out.JwtVerifier; + +@DisplayName("[Adapter Unit]: 임시토큰 요청 테스트") +@ExtendWith(MockitoExtension.class) +class TemporaryTokenClientTest { + + @InjectMocks + private EmailTokenClient sut; + + @Mock + private JwtVerifier jwtVerifier; + + @DisplayName("임시토큰을 검증한다.") + @Test + void verify_temporary_token() { + doReturn(true).when(jwtVerifier).verify(any()); + + assertThatCode(() -> sut.verify("temporaryToken")).doesNotThrowAnyException(); + verify(jwtVerifier, times(1)).verify(any()); + } + + @DisplayName("유효하지 않은 임시토큰으로 검증한다.") + @Test + void verify_invalid_temporary_token() { + doReturn(false).when(jwtVerifier).verify(any()); + + assertThatThrownBy(() -> sut.verify("temporaryToken")).isExactlyInstanceOf(IllegalArgumentException.class); + verify(jwtVerifier, times(1)).verify(any()); + } +} diff --git a/src/test/java/com/gomo/app/common/security/encoder/application/PasswordEncodeUseCaseTest.java b/src/test/java/com/gomo/app/core/member/adapter/out/lib/BcryptEncoderTest.java similarity index 80% rename from src/test/java/com/gomo/app/common/security/encoder/application/PasswordEncodeUseCaseTest.java rename to src/test/java/com/gomo/app/core/member/adapter/out/lib/BcryptEncoderTest.java index 35124247..3014fea9 100644 --- a/src/test/java/com/gomo/app/common/security/encoder/application/PasswordEncodeUseCaseTest.java +++ b/src/test/java/com/gomo/app/core/member/adapter/out/lib/BcryptEncoderTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.common.security.encoder.application; +package com.gomo.app.core.member.adapter.out.lib; import static org.assertj.core.api.AssertionsForClassTypes.*; import static org.mockito.Mockito.*; @@ -11,22 +11,22 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.security.crypto.password.PasswordEncoder; -@DisplayName("[Application Unit]: PasswordService 테스트") +@DisplayName("[Adapter Unit]: 비밀번호 암호화 및 검증 테스트") @ExtendWith(MockitoExtension.class) -public class PasswordEncodeUseCaseTest { +class BcryptEncoderTest { private static final String RAW_PASSWORD = "password"; private static final String ENCODED_PASSWORD = "encoded_password"; @InjectMocks - private PasswordEncodeUseCase sut; + private BcryptEncoder sut; @Mock private PasswordEncoder passwordEncoder; @DisplayName("비밀번호를 인코딩한다") @Test - void encodePassword() { + void encode_password() { when(passwordEncoder.encode(RAW_PASSWORD)).thenReturn(ENCODED_PASSWORD); String actual = sut.encode(RAW_PASSWORD); @@ -38,7 +38,7 @@ void encodePassword() { void return_true_with_matched_password() { when(passwordEncoder.matches(RAW_PASSWORD, ENCODED_PASSWORD)).thenReturn(true); - boolean actual = sut.matches(RAW_PASSWORD, ENCODED_PASSWORD); + boolean actual = sut.verify(RAW_PASSWORD, ENCODED_PASSWORD); assertThat(actual).isTrue(); } @@ -47,7 +47,7 @@ void return_true_with_matched_password() { void return_true_with_unmatched_password() { when(passwordEncoder.matches(RAW_PASSWORD, ENCODED_PASSWORD)).thenReturn(false); - boolean actual = sut.matches(RAW_PASSWORD, ENCODED_PASSWORD); + boolean actual = sut.verify(RAW_PASSWORD, ENCODED_PASSWORD); assertThat(actual).isFalse(); } } diff --git a/src/test/java/com/gomo/app/core/member/application/service/EmailServiceTest.java b/src/test/java/com/gomo/app/core/member/application/service/EmailServiceTest.java new file mode 100644 index 00000000..c4f6999f --- /dev/null +++ b/src/test/java/com/gomo/app/core/member/application/service/EmailServiceTest.java @@ -0,0 +1,69 @@ +package com.gomo.app.core.member.application.service; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.Optional; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.core.member.domain.exception.EmailDuplicatedException; +import com.gomo.app.core.member.domain.exception.code.EmailErrorCode; +import com.gomo.app.core.member.domain.model.Email; +import com.gomo.app.core.member.domain.model.Member; +import com.gomo.app.core.member.domain.repository.MemberRepository; + +@DisplayName("[Application unit] : 사용자 이메일 중복 검증 테스트") +@ExtendWith(MockitoExtension.class) +class EmailServiceTest { + + @InjectMocks + private EmailService sut; + + @Mock + private MemberRepository memberRepository; + + @DisplayName("이메일이 중복되지 않는다.") + @Test + void validate_non_duplicated_email() { + doReturn(Optional.empty()).when(memberRepository).findByEmail(any(Email.class)); + + assertThatCode(() -> sut.validateDuplicated("nonexistent@naver.com")).doesNotThrowAnyException(); + } + + @DisplayName("이메일이 중복된다.") + @Test + void validate_duplicated_email() { + doReturn(Optional.of(mock(Member.class))).when(memberRepository).findByEmail(any(Email.class)); + + assertThatThrownBy(() -> sut.validateDuplicated("gomo@naver.com")) + .isInstanceOf(EmailDuplicatedException.class) + .hasMessageContaining(EmailErrorCode.DUPLICATED.getMessage()); + } + + @DisplayName("이메일이 이미 존재한다.") + @Test + void exists_email() { + doReturn(Optional.of(mock(Member.class))).when(memberRepository).findByEmail(any(Email.class)); + + boolean actual = sut.exists("email@email.com"); + + assertThat(actual).isTrue(); + } + + @DisplayName("이메일이 존재하지 않는다.") + @Test + void exists_nonexistent_email() { + doReturn(Optional.empty()).when(memberRepository).findByEmail(any(Email.class)); + + boolean actual = sut.exists("email@email.com"); + + assertThat(actual).isFalse(); + } +} diff --git a/src/test/java/com/gomo/app/core/member/application/service/HandleServiceTest.java b/src/test/java/com/gomo/app/core/member/application/service/HandleServiceTest.java new file mode 100644 index 00000000..c84cc1fe --- /dev/null +++ b/src/test/java/com/gomo/app/core/member/application/service/HandleServiceTest.java @@ -0,0 +1,66 @@ +package com.gomo.app.core.member.application.service; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.Optional; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.core.member.domain.exception.HandleDuplicatedException; +import com.gomo.app.core.member.domain.exception.code.HandleErrorCode; +import com.gomo.app.core.member.domain.model.Handle; +import com.gomo.app.core.member.domain.model.Member; +import com.gomo.app.core.member.domain.repository.MemberRepository; +import com.gomo.app.core.member.fixture.MemberFixture; + +@DisplayName("[Application unit]: 핸들 업데이트 테스트") +@ExtendWith(MockitoExtension.class) +public class HandleServiceTest { + + @InjectMocks + private HandleService sut; + + @Mock + private MemberService memberService; + + @Mock + private MemberRepository memberRepository; + + private final static String UPDATED_HANDLE = "@updatedhandle"; + + @DisplayName("핸들 업데이트를 성공한다") + @Test + void update_handle_success() { + Member member = MemberFixture.create(); + doReturn(member).when(memberService).findById(member.getId()); + doReturn(Optional.empty()).when(memberRepository).findByHandle(any(Handle.class)); + + sut.update(member.getId(), UPDATED_HANDLE); + + assertThat(member.handle()).isEqualTo(UPDATED_HANDLE); + } + + @DisplayName("핸들이 중복되지 않는다.") + @Test + void validate_non_duplicated_handle() { + doReturn(Optional.empty()).when(memberRepository).findByHandle(any(Handle.class)); + + assertThatCode(() -> sut.validateDuplicated("@nonexistent")).doesNotThrowAnyException(); + } + + @DisplayName("핸들이 중복된다.") + @Test + void validate_duplicated_handle() { + doReturn(Optional.of(mock(Member.class))).when(memberRepository).findByHandle(any(Handle.class)); + + assertThatThrownBy(() -> sut.validateDuplicated("@gomo")) + .isInstanceOf(HandleDuplicatedException.class) + .hasMessageContaining(HandleErrorCode.DUPLICATED.getMessage()); + } +} diff --git a/src/test/java/com/gomo/app/core/member/application/service/MemberCreateServiceTest.java b/src/test/java/com/gomo/app/core/member/application/service/MemberCreateServiceTest.java new file mode 100644 index 00000000..74c8c06b --- /dev/null +++ b/src/test/java/com/gomo/app/core/member/application/service/MemberCreateServiceTest.java @@ -0,0 +1,58 @@ +package com.gomo.app.core.member.application.service; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.UUID; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.core.member.application.port.command.CreateMemberCommand; +import com.gomo.app.core.member.application.port.out.MemberCreateEventPublisher; +import com.gomo.app.core.member.domain.model.Member; +import com.gomo.app.core.member.domain.repository.MemberRepository; +import com.gomo.app.core.member.fixture.MemberFixture; + +@DisplayName("[Application unit] : 멤버 생성 테스트") +@ExtendWith(MockitoExtension.class) +public class MemberCreateServiceTest { + + @InjectMocks + private MemberCreateService sut; + + @Mock + private PasswordService passwordService; + + @Mock + private EmailService emailService; + + @Mock + private HandleService handleService; + + @Mock + private MemberRepository memberRepository; + + @Mock + private MemberCreateEventPublisher memberCreateEventPublisher; + + @DisplayName("회원을 등록한다") + @Test + void create_member() { + Member member = MemberFixture.create(); + doReturn(member.getPassword()).when(passwordService).encode(any(), any(), any()); + doReturn(member).when(memberRepository).save(any(Member.class)); + + UUID actual = sut.create( + CreateMemberCommand.of(member.email(), member.password(), member.handle(), member.name(), member.motto(), member.getLoginProvider().name())); + + assertThat(actual).isEqualTo(member.getId()); + verify(emailService, times(1)).validateDuplicated(any()); + verify(handleService, times(1)).validateDuplicated(any()); + verify(memberCreateEventPublisher, times(1)).publish(any()); + } +} diff --git a/src/test/java/com/gomo/app/core/member/application/usecase/LoginMemberUseCaseTest.java b/src/test/java/com/gomo/app/core/member/application/service/MemberLoginServiceTest.java similarity index 67% rename from src/test/java/com/gomo/app/core/member/application/usecase/LoginMemberUseCaseTest.java rename to src/test/java/com/gomo/app/core/member/application/service/MemberLoginServiceTest.java index e9b78335..9191cdac 100644 --- a/src/test/java/com/gomo/app/core/member/application/usecase/LoginMemberUseCaseTest.java +++ b/src/test/java/com/gomo/app/core/member/application/service/MemberLoginServiceTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.application.usecase; +package com.gomo.app.core.member.application.service; import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; @@ -13,31 +13,31 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import com.gomo.app.common.security.encoder.application.port.VerifyPasswordPortIn; import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.service.MemberService; import com.gomo.app.core.member.fixture.MemberFixture; @DisplayName("[Application unit]: 회원 로그인 테스트") @ExtendWith(MockitoExtension.class) -class LoginMemberUseCaseTest { +class MemberLoginServiceTest { @InjectMocks - private LoginMemberUseCase sut; + private MemberLoginService sut; @Mock private MemberService memberService; @Mock - private VerifyPasswordPortIn verifyPasswordPortIn; + private PasswordService passwordService; @DisplayName("회원 정보를 확인하고, 로그인 날짜를 갱신한다.") @Test void login_member() { Member member = MemberFixture.create(); doReturn(member).when(memberService).findByEmail(any()); - doReturn(true).when(verifyPasswordPortIn).matches(any(), any()); - UUID actual = sut.authenticate(member.email(), member.password()); + + UUID actual = sut.login(member.email(), member.password()); + assertThat(actual).isEqualTo(member.getId()); + verify(passwordService, times(1)).verify(any(), any()); } } diff --git a/src/test/java/com/gomo/app/core/member/application/usecase/OAuthLoginMemberUseCaseTest.java b/src/test/java/com/gomo/app/core/member/application/service/MemberOAuthLoginServiceTest.java similarity index 82% rename from src/test/java/com/gomo/app/core/member/application/usecase/OAuthLoginMemberUseCaseTest.java rename to src/test/java/com/gomo/app/core/member/application/service/MemberOAuthLoginServiceTest.java index 2320c3bc..6ae95ed2 100644 --- a/src/test/java/com/gomo/app/core/member/application/usecase/OAuthLoginMemberUseCaseTest.java +++ b/src/test/java/com/gomo/app/core/member/application/service/MemberOAuthLoginServiceTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.application.usecase; +package com.gomo.app.core.member.application.service; import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; @@ -20,10 +20,10 @@ @DisplayName("[Application unit]: OAuth 회원 로그인 테스트") @ExtendWith(MockitoExtension.class) -class OAuthLoginMemberUseCaseTest { +class MemberOAuthLoginServiceTest { @InjectMocks - private OAuthLoginMemberUseCase sut; + private MemberOAuthLoginService sut; @Mock private MemberRepository memberRepository; @@ -33,7 +33,7 @@ class OAuthLoginMemberUseCaseTest { void oauth_login_member() { Member member = MemberFixture.create(); doReturn(Optional.of(member)).when(memberRepository).findByEmail(any()); - Optional actual = sut.oauthAuthenticate(member.email()); + Optional actual = sut.login(member.email()); assertThat(actual.isPresent()).isTrue(); } @@ -41,7 +41,7 @@ void oauth_login_member() { @Test void oauth_login_member_not_found() { doReturn(Optional.empty()).when(memberRepository).findByEmail(any()); - Optional actual = sut.oauthAuthenticate("email@gmail.com"); + Optional actual = sut.login("email@gmail.com"); assertThat(actual.isPresent()).isFalse(); } } diff --git a/src/test/java/com/gomo/app/core/member/application/service/MemberServiceTest.java b/src/test/java/com/gomo/app/core/member/application/service/MemberServiceTest.java new file mode 100644 index 00000000..69aa1e85 --- /dev/null +++ b/src/test/java/com/gomo/app/core/member/application/service/MemberServiceTest.java @@ -0,0 +1,121 @@ +package com.gomo.app.core.member.application.service; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.Optional; +import java.util.UUID; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.core.member.application.port.dto.MemberDto; +import com.gomo.app.core.member.application.port.out.MemberLogoutProcessor; +import com.gomo.app.core.member.application.port.out.PointBalanceReader; +import com.gomo.app.core.member.domain.exception.MemberNotFoundException; +import com.gomo.app.core.member.domain.exception.code.MemberErrorCode; +import com.gomo.app.core.member.domain.model.ActivateStatus; +import com.gomo.app.core.member.domain.model.Email; +import com.gomo.app.core.member.domain.model.Member; +import com.gomo.app.core.member.domain.repository.MemberRepository; +import com.gomo.app.core.member.fixture.MemberFixture; + +@DisplayName("[Application unit]: 멤버 조회 테스트") +@ExtendWith(MockitoExtension.class) +public class MemberServiceTest { + + @InjectMocks + private MemberService sut; + + @Mock + private MemberRepository memberRepository; + + @Mock + private PointBalanceReader pointBalanceReader; + + @Mock + private MemberLogoutProcessor memberLogoutProcessor; + + private static final int BALANCE = 5000; + + @DisplayName("멤버 조회에 성공한다") + @Test + void read_member_successfully() { + Member member = MemberFixture.create(); + MemberDto expected = MemberDto.from(member, BALANCE); + + doReturn(Optional.of(member)).when(memberRepository).findById(any()); + doReturn(BALANCE).when(pointBalanceReader).read(any()); + + MemberDto actual = sut.read(member.getId()); + + assertThat(actual).usingRecursiveComparison().isEqualTo(expected); + } + + @DisplayName("회원 엔티티를 조회한다.") + @Test + void read_member() { + doReturn(Optional.of(mock(Member.class))).when(memberRepository).findById(any()); + + Member actual = sut.findById(UUID.randomUUID()); + + assertThat(actual).isNotNull(); + } + + @DisplayName("존재하지 않는 회원 엔티티를 조회한다.") + @Test + void read_nonexistent_member() { + doReturn(Optional.empty()).when(memberRepository).findById(any()); + + assertThatThrownBy(() -> sut.findById(UUID.randomUUID())) + .isInstanceOf(MemberNotFoundException.class) + .hasMessageContaining(MemberErrorCode.NOT_FOUND.getMessage()); + } + + @DisplayName("이메일로 회원 엔티티를 조회한다.") + @Test + void read_member_by_mail() { + doReturn(Optional.of(mock(Member.class))).when(memberRepository).findByEmail(any(Email.class)); + + Member actual = sut.findByEmail("gomo@naver.com"); + + assertThat(actual).isNotNull(); + } + + @DisplayName("이메일로 존재하지 않는 회원 엔티티를 조회한다.") + @Test + void read_nonexistent_member_by_email() { + doReturn(Optional.empty()).when(memberRepository).findByEmail(any(Email.class)); + + assertThatThrownBy(() -> sut.findByEmail("nonexistent@naver.com")) + .isInstanceOf(MemberNotFoundException.class) + .hasMessageContaining(MemberErrorCode.NOT_FOUND.getMessage()); + } + + @DisplayName("회원 정보(모토, 이름)을 수정한다.") + @Test + void update_member_name_and_motto() { + Member member = MemberFixture.create(); + doReturn(Optional.of(member)).when(memberRepository).findById(member.getId()); + sut.update(member.getId(), "NEW_NAME", "NEW_MOTTO"); + assertThat(member.name()).isEqualTo("NEW_NAME"); + assertThat(member.motto()).isEqualTo("NEW_MOTTO"); + } + + @DisplayName("멤버 삭제 테스트") + @Test + void delete_member() { + Member member = MemberFixture.create(); + doReturn(Optional.of(member)).when(memberRepository).findById(member.getId()); + doNothing().when(memberLogoutProcessor).logout(member.getId()); + + sut.delete(member.getId()); + + assertThat(member.getActivateStatus()).isEqualTo(ActivateStatus.DELETED); + } +} diff --git a/src/test/java/com/gomo/app/core/member/application/service/PasswordServiceTest.java b/src/test/java/com/gomo/app/core/member/application/service/PasswordServiceTest.java new file mode 100644 index 00000000..f837822b --- /dev/null +++ b/src/test/java/com/gomo/app/core/member/application/service/PasswordServiceTest.java @@ -0,0 +1,111 @@ +package com.gomo.app.core.member.application.service; + +import static com.gomo.app.core.member.domain.exception.code.MemberErrorCode.*; +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.UUID; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.core.member.application.port.out.EmailTokenVerifier; +import com.gomo.app.core.member.application.port.out.PasswordEncodeManager; +import com.gomo.app.core.member.domain.exception.MemberAuthenticationFailedException; +import com.gomo.app.core.member.domain.model.LoginProvider; +import com.gomo.app.core.member.domain.model.Member; +import com.gomo.app.core.member.domain.model.Password; +import com.gomo.app.core.member.fixture.MemberFixture; + +@DisplayName("[Application unit] : 비밀번호 초기화 테스트") +@ExtendWith(MockitoExtension.class) +class PasswordServiceTest { + + @InjectMocks + private PasswordService sut; + + @Mock + private EmailTokenVerifier emailTokenVerifier; + + @Mock + private PasswordEncodeManager passwordEncodeManager; + + @Mock + private MemberService memberService; + + @DisplayName("비밀번호를 초기화한다.") + @Test + void reset_password() { + Member member = MemberFixture.create(); + String encoded = "encoded_password"; + doReturn(member).when(memberService).findByEmail(any()); + doReturn(encoded).when(passwordEncodeManager).encode(any()); + + sut.reset(member.email(), "New1234@", "temporaryToken"); + + assertThat(member.password()).isEqualTo(encoded); + verify(emailTokenVerifier, times(1)).verify(any()); + } + + @DisplayName("비밀번호를 변경한다.") + @Test + void update_password() { + Member member = MemberFixture.create(); + String encoded = "encoded_password"; + doReturn(member).when(memberService).findById(any()); + doReturn(true).when(passwordEncodeManager).verify(any(), any()); + doReturn(encoded).when(passwordEncodeManager).encode(any()); + + sut.update(member.getId(), "Origin123@", "New1234@"); + + assertThat(member.password()).isEqualTo(encoded); + } + + @DisplayName("비밀번호를 검증한다.") + @Test + void verify_password() { + doReturn(true).when(passwordEncodeManager).verify(any(), any()); + + assertThatCode(() -> sut.verify(MemberFixture.create(), "Origin123@")).doesNotThrowAnyException(); + } + + @DisplayName("기존 비밀번호 불일치로 비밀번호 검증에 실패한다.") + @Test + void verify_password_with_wrong_password() { + doReturn(false).when(passwordEncodeManager).verify(any(), any()); + + assertThatThrownBy(() -> sut.verify(MemberFixture.create(), "Origin123@")) + .isInstanceOf(MemberAuthenticationFailedException.class) + .hasMessageContaining(AUTHENTICATION_FAILED.getMessage()); + } + + @DisplayName("이메일로 가입한 회원의 비밀번호를 암호화한다.") + @Test + void encode_password_with_email_member() { + String password = "Test123@"; + String encoded = "encoded"; + doReturn(encoded).when(passwordEncodeManager).encode(password); + + Password actual = sut.encode(LoginProvider.EMAIL.name(), password, UUID.randomUUID()); + + assertThat(actual.getPassword()).isEqualTo(encoded); + } + + @DisplayName("OAuth로 가입한 회원의 비밀번호를 암호화한다.") + @Test + void encode_password_with_oauth_member() { + UUID memberId = UUID.randomUUID(); + Password oauthPassword = Password.forOAuth(memberId.toString()); + String encoded = "encoded"; + doReturn(encoded).when(passwordEncodeManager).encode(oauthPassword.getPassword()); + + Password actual = sut.encode(LoginProvider.NAVER.name(), "Test123@", memberId); + + assertThat(actual.getPassword()).isEqualTo(encoded); + } +} diff --git a/src/test/java/com/gomo/app/core/member/application/usecase/UpdateProfileBannerUseCaseTest.java b/src/test/java/com/gomo/app/core/member/application/service/ProfileBannerServiceTest.java similarity index 50% rename from src/test/java/com/gomo/app/core/member/application/usecase/UpdateProfileBannerUseCaseTest.java rename to src/test/java/com/gomo/app/core/member/application/service/ProfileBannerServiceTest.java index 33fc2a78..e856865e 100644 --- a/src/test/java/com/gomo/app/core/member/application/usecase/UpdateProfileBannerUseCaseTest.java +++ b/src/test/java/com/gomo/app/core/member/application/service/ProfileBannerServiceTest.java @@ -1,10 +1,8 @@ -package com.gomo.app.core.member.application.usecase; +package com.gomo.app.core.member.application.service; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; -import java.util.Optional; - import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -13,24 +11,22 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.mock.web.MockMultipartFile; -import com.gomo.app.core.member.application.port.dto.UpdateProfileBannerDto; +import com.gomo.app.core.member.application.port.out.ProfileAssetUploader; import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.service.MemberService; import com.gomo.app.core.member.fixture.MemberFixture; -import com.gomo.app.support.image.application.port.UploadImagePortIn; -@DisplayName("[Application Unit]: 배너 이미지 수정 기능 테스트") +@DisplayName("[Application Unit]: 배너 이미지 서비스 기능 테스트") @ExtendWith(MockitoExtension.class) -public class UpdateProfileBannerUseCaseTest { +public class ProfileBannerServiceTest { @InjectMocks - private UpdateProfileBannerUseCase sut; + private ProfileBannerService sut; @Mock private MemberService memberService; @Mock - private UploadImagePortIn uploadImagePortIn; + private ProfileAssetUploader profileAssetUploader; private static final String NEW_IMAGE_URL = "https://example.com/profile.jpg"; @@ -39,13 +35,23 @@ public class UpdateProfileBannerUseCaseTest { void update_profile_banner() { Member member = MemberFixture.create(); MockMultipartFile request = new MockMultipartFile("banner", "mock image data".getBytes()); - UpdateProfileBannerDto expected = UpdateProfileBannerDto.of(NEW_IMAGE_URL); - doReturn(member).when(memberService).find(member.getId()); - doReturn(Optional.of(NEW_IMAGE_URL)).when(uploadImagePortIn).upload(any(MockMultipartFile.class)); + doReturn(member).when(memberService).findById(member.getId()); + doReturn(NEW_IMAGE_URL).when(profileAssetUploader).upload(any(MockMultipartFile.class)); + + sut.update(member.getId(), request); + + assertThat(member.getProfileBanner().getUrl()).isEqualTo(NEW_IMAGE_URL); + } + + @DisplayName("프로필 배너 이미지를 삭제한다.") + @Test + void delete_profile_banner() { + Member member = MemberFixture.create(); + doReturn(member).when(memberService).findById(member.getId()); - UpdateProfileBannerDto actual = sut.update(member.getId(), request); + sut.delete(member.getId()); - assertThat(actual).usingRecursiveComparison().isEqualTo(expected); + assertThat(member.profileBannerUrl()).isEqualTo("DEFAULT_IMAGE"); } } diff --git a/src/test/java/com/gomo/app/core/member/application/usecase/UpdateQuestPropertyUseCaseTest.java b/src/test/java/com/gomo/app/core/member/application/service/QuestPropertyServiceTest.java similarity index 58% rename from src/test/java/com/gomo/app/core/member/application/usecase/UpdateQuestPropertyUseCaseTest.java rename to src/test/java/com/gomo/app/core/member/application/service/QuestPropertyServiceTest.java index 85fe2db5..f6784086 100644 --- a/src/test/java/com/gomo/app/core/member/application/usecase/UpdateQuestPropertyUseCaseTest.java +++ b/src/test/java/com/gomo/app/core/member/application/service/QuestPropertyServiceTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.application.usecase; +package com.gomo.app.core.member.application.service; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; @@ -11,28 +11,40 @@ import org.mockito.junit.jupiter.MockitoExtension; import com.gomo.app.core.member.application.port.command.UpdateQuestPropertyCommand; +import com.gomo.app.core.member.application.port.dto.QuestPropertyDto; import com.gomo.app.core.member.domain.model.Member; import com.gomo.app.core.member.domain.model.QuestProperty; -import com.gomo.app.core.member.domain.service.MemberService; import com.gomo.app.core.member.fixture.MemberFixture; @DisplayName("[Application Unit]: 퀘스트 설정 업데이트 기능 테스트") @ExtendWith(MockitoExtension.class) -public class UpdateQuestPropertyUseCaseTest { +public class QuestPropertyServiceTest { @InjectMocks - private UpdateQuestPropertyUseCase sut; + private QuestPropertyService sut; @Mock private MemberService memberService; - @DisplayName("퀘스트 설정 업데이트 기능 테스트") + @DisplayName("회원의 퀘스트 설정 정보를 조회한다.") + @Test + void read_quest_property_successfully() { + Member member = MemberFixture.create(3); + QuestPropertyDto expected = QuestPropertyDto.from(member.getQuestProperty()); + doReturn(member).when(memberService).findById(member.getId()); + + QuestPropertyDto actual = sut.read(member.getId()); + + assertThat(actual).usingRecursiveComparison().isEqualTo(expected); + } + + @DisplayName("회원의 퀘스트 설정 정보를 수정한다.") @Test void update_quest_property() { Member member = MemberFixture.create(); UpdateQuestPropertyCommand command = UpdateQuestPropertyCommand.of(member.getId(), 1, 3, 5); QuestProperty expected = command.toDomain(); - doReturn(member).when(memberService).find(member.getId()); + doReturn(member).when(memberService).findById(member.getId()); sut.update(command); diff --git a/src/test/java/com/gomo/app/core/member/application/usecase/UpdateProfileImageUseCaseTest.java b/src/test/java/com/gomo/app/core/member/application/service/TempProfileImageServiceTest.java similarity index 50% rename from src/test/java/com/gomo/app/core/member/application/usecase/UpdateProfileImageUseCaseTest.java rename to src/test/java/com/gomo/app/core/member/application/service/TempProfileImageServiceTest.java index 8c065aa6..de8f5e71 100644 --- a/src/test/java/com/gomo/app/core/member/application/usecase/UpdateProfileImageUseCaseTest.java +++ b/src/test/java/com/gomo/app/core/member/application/service/TempProfileImageServiceTest.java @@ -1,10 +1,8 @@ -package com.gomo.app.core.member.application.usecase; +package com.gomo.app.core.member.application.service; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; -import java.util.Optional; - import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -13,24 +11,22 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.mock.web.MockMultipartFile; -import com.gomo.app.core.member.application.port.dto.UpdateProfileImageDto; +import com.gomo.app.core.member.application.port.out.ProfileAssetUploader; import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.service.MemberService; import com.gomo.app.core.member.fixture.MemberFixture; -import com.gomo.app.support.image.application.port.UploadImagePortIn; -@DisplayName("[Application Unit]: 프로필 이미지 수정 기능 테스트") +@DisplayName("[Application Unit]: 프로필 이미지 서비스 기능 테스트") @ExtendWith(MockitoExtension.class) -public class UpdateProfileImageUseCaseTest { +public class TempProfileImageServiceTest { @InjectMocks - private UpdateProfileImageUseCase sut; + private ProfileImageService sut; @Mock private MemberService memberService; @Mock - private UploadImagePortIn uploadImagePort; + private ProfileAssetUploader profileAssetUploader; private static final String NEW_IMAGE_URL = "https://example.com/profile.jpg"; @@ -39,14 +35,23 @@ public class UpdateProfileImageUseCaseTest { void update_profile_image() { Member member = MemberFixture.create(); MockMultipartFile request = new MockMultipartFile("banner", "mock image data".getBytes()); - UpdateProfileImageDto expected = UpdateProfileImageDto.of(NEW_IMAGE_URL); - doReturn(member).when(memberService).find(member.getId()); - doReturn(Optional.of(NEW_IMAGE_URL)).when(uploadImagePort).upload(any(MockMultipartFile.class)); + doReturn(member).when(memberService).findById(member.getId()); + doReturn(NEW_IMAGE_URL).when(profileAssetUploader).upload(any(MockMultipartFile.class)); - UpdateProfileImageDto actual = sut.update(member.getId(), request); + sut.update(member.getId(), request); - assertThat(actual).usingRecursiveComparison().isEqualTo(expected); + assertThat(member.getProfileImage().getUrl()).isEqualTo(NEW_IMAGE_URL); } + @DisplayName("프로필 이미지를 삭제한다.") + @Test + void delete_profile_image() { + Member member = MemberFixture.create(); + doReturn(member).when(memberService).findById(member.getId()); + + sut.delete(member.getId()); + + assertThat(member.profileImageUrl()).isEqualTo("DEFAULT_IMAGE"); + } } diff --git a/src/test/java/com/gomo/app/core/member/application/usecase/UpdateWidgetUseCaseTest.java b/src/test/java/com/gomo/app/core/member/application/service/WidgetServiceTest.java similarity index 79% rename from src/test/java/com/gomo/app/core/member/application/usecase/UpdateWidgetUseCaseTest.java rename to src/test/java/com/gomo/app/core/member/application/service/WidgetServiceTest.java index 08080bea..9fa2aa11 100644 --- a/src/test/java/com/gomo/app/core/member/application/usecase/UpdateWidgetUseCaseTest.java +++ b/src/test/java/com/gomo/app/core/member/application/service/WidgetServiceTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.application.usecase; +package com.gomo.app.core.member.application.service; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; @@ -11,15 +11,14 @@ import org.mockito.junit.jupiter.MockitoExtension; import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.service.MemberService; import com.gomo.app.core.member.fixture.MemberFixture; @DisplayName("[Application unit]: 위젯 스냅샷 수정 테스트") @ExtendWith(MockitoExtension.class) -class UpdateWidgetUseCaseTest { +class WidgetServiceTest { @InjectMocks - private UpdateWidgetUseCase sut; + private WidgetService sut; @Mock private MemberService memberService; @@ -29,7 +28,7 @@ class UpdateWidgetUseCaseTest { void update_widget_snapshot() { String updatedSnapshot = "{ \"test\": \"test_snapshot\" }"; Member member = MemberFixture.create(); - doReturn(member).when(memberService).find(member.getId()); + doReturn(member).when(memberService).findById(member.getId()); sut.update(member.getId(), updatedSnapshot); diff --git a/src/test/java/com/gomo/app/core/member/application/usecase/CheckHandleUseCaseTest.java b/src/test/java/com/gomo/app/core/member/application/usecase/CheckHandleUseCaseTest.java deleted file mode 100644 index 6321cd01..00000000 --- a/src/test/java/com/gomo/app/core/member/application/usecase/CheckHandleUseCaseTest.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.member.domain.model.Handle; -import com.gomo.app.core.member.domain.service.MemberService; - -@DisplayName("[Application unit] : 유저 핸들 중복체크 테스트") -@ExtendWith(MockitoExtension.class) -public class CheckHandleUseCaseTest { - - @InjectMocks - private CheckHandleUseCase sut; - - @Mock - private MemberService memberService; - - @DisplayName("핸들 중복을 확인한다.") - @Test - void check_handle_dupliated() { - String testHandle = "@testhandle"; - - doNothing().when(memberService).checkHandleDuplicated(any(Handle.class)); - - assertThatCode(() -> sut.checkHandleDuplicated(testHandle)).doesNotThrowAnyException(); - } - -} diff --git a/src/test/java/com/gomo/app/core/member/application/usecase/CreateEmailCodeUseCaseTest.java b/src/test/java/com/gomo/app/core/member/application/usecase/CreateEmailCodeUseCaseTest.java deleted file mode 100644 index b9497166..00000000 --- a/src/test/java/com/gomo/app/core/member/application/usecase/CreateEmailCodeUseCaseTest.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.member.domain.model.Email; -import com.gomo.app.core.member.domain.service.MemberService; -import com.gomo.app.core.member.fixture.MemberFixture; -import com.gomo.app.support.auth.application.port.CreateAuthCodePortIn; - -@DisplayName("[Application unit] : 이메일 인증코드 생성 및 전송 테스트") -@ExtendWith(MockitoExtension.class) -public class CreateEmailCodeUseCaseTest { - - @InjectMocks - private CreateEmailCodeUseCase sut; - - @Mock - private MemberService memberService; - - @Mock - private CreateAuthCodePortIn createAuthCodePortIn; - - private static final String EMAIL = "test@gmail.com"; - - @DisplayName("회원가입 관련 이메일 인증 코드를 생성한다.") - @Test - void create_email_auth_code_successfully() { - String authCode = "000000"; - doNothing().when(memberService).checkEmailDuplicated(any(Email.class)); - doReturn(authCode).when(createAuthCodePortIn).sendToEmail(anyString()); - - String actual = sut.createForSignUp(EMAIL); - - assertThat(actual).isEqualTo(authCode); - } - - @DisplayName("비밀번호 초기화 관련 이메일 인증 코드를 생성한다.") - @Test - void create_email_auth_code_for_password_successfully() { - String authCode = "000000"; - doReturn(MemberFixture.create()).when(memberService).findByEmail(any(Email.class)); - doReturn(authCode).when(createAuthCodePortIn).sendToEmail(anyString()); - - String actual = sut.createForPasswordReset(EMAIL); - - assertThat(actual).isEqualTo(authCode); - } -} diff --git a/src/test/java/com/gomo/app/core/member/application/usecase/CreateMemberUseCaseTest.java b/src/test/java/com/gomo/app/core/member/application/usecase/CreateMemberUseCaseTest.java deleted file mode 100644 index 7c6826a2..00000000 --- a/src/test/java/com/gomo/app/core/member/application/usecase/CreateMemberUseCaseTest.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.common.security.encoder.application.port.EncodePasswordPortIn; -import com.gomo.app.common.security.jwt.application.port.VerifyJwtPortIn; -import com.gomo.app.core.member.application.port.command.CreateMemberCommand; -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.repository.MemberRepository; -import com.gomo.app.core.member.domain.service.MemberService; -import com.gomo.app.core.member.fixture.MemberFixture; -import com.gomo.app.core.point.application.port.CreatePointWalletPortIn; -import com.gomo.app.core.streak.application.port.CreateAchieverPortIn; - -@DisplayName("[Application unit] : 멤버 생성 테스트") -@ExtendWith(MockitoExtension.class) -public class CreateMemberUseCaseTest { - - @InjectMocks - private CreateMemberUseCase sut; - - @Mock - private VerifyJwtPortIn verifyJwtPortIn; - - @Mock - private EncodePasswordPortIn encodePasswordPortIn; - - @Mock - private MemberService memberService; - - @Mock - private MemberRepository memberRepository; - - @Mock - private CreatePointWalletPortIn createPointWalletPortIn; - - @Mock - CreateAchieverPortIn createAchieverPortIn; - - @DisplayName("회원을 등록한다") - @Test - void create_member() { - Member member = MemberFixture.create(); - doReturn(true).when(verifyJwtPortIn).validateToken(anyString()); - doReturn(member.password()).when(encodePasswordPortIn).encode(anyString()); - doReturn(member).when(memberRepository).save(any(Member.class)); - - UUID actual = sut.create(CreateMemberCommand.of( - member.email(), member.password(), member.handle(), member.name(), member.motto(), member.getLoginProvider().name(), "temporaryToken" - )); - - assertThat(actual).isEqualTo(member.getId()); - verify(memberService, times(1)).checkEmailDuplicated(any()); - verify(memberService, times(1)).checkHandleDuplicated(any()); - verify(createPointWalletPortIn, times(1)).create(any()); - verify(createAchieverPortIn, times(1)).create(any()); - } - - @DisplayName("임시 코드 검증에 실패한다.") - @Test - void fail_validate_temporary_code() { - Member member = MemberFixture.create(); - CreateMemberCommand command = CreateMemberCommand.of(member.email(), member.password(), member.handle(), member.name(), member.motto(), - member.getLoginProvider().name(), null); - doReturn(false).when(verifyJwtPortIn).validateToken(null); - - assertThatThrownBy(() -> sut.create(command)).isInstanceOf(IllegalArgumentException.class); - } -} diff --git a/src/test/java/com/gomo/app/core/member/application/usecase/DeleteMemberUseCaseTest.java b/src/test/java/com/gomo/app/core/member/application/usecase/DeleteMemberUseCaseTest.java deleted file mode 100644 index 9d1fc5f7..00000000 --- a/src/test/java/com/gomo/app/core/member/application/usecase/DeleteMemberUseCaseTest.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.member.domain.model.ActivateStatus; -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.service.MemberService; -import com.gomo.app.core.member.fixture.MemberFixture; -import com.gomo.app.support.auth.application.port.DeleteAuthTokenPortIn; - -@DisplayName("[Application Unit]: 멤버 삭제 테스트") -@ExtendWith(MockitoExtension.class) -public class DeleteMemberUseCaseTest { - - @InjectMocks - private DeleteMemberUseCase sut; - - @Mock - private MemberService memberService; - - @Mock - private DeleteAuthTokenPortIn deleteAuthTokenPortIn; - - @DisplayName("멤버 삭제 테스트") - @Test - void delete_member_successfully() { - Member member = MemberFixture.create(); - doReturn(member).when(memberService).find(member.getId()); - doNothing().when(deleteAuthTokenPortIn).deleteRefreshToken(member.getId()); - - sut.delete(member.getId()); - - assertThat(member.getActivateStatus()).isEqualTo(ActivateStatus.DELETED); - } - -} diff --git a/src/test/java/com/gomo/app/core/member/application/usecase/DeleteProfileBannerUseCaseTest.java b/src/test/java/com/gomo/app/core/member/application/usecase/DeleteProfileBannerUseCaseTest.java deleted file mode 100644 index 29da4ef5..00000000 --- a/src/test/java/com/gomo/app/core/member/application/usecase/DeleteProfileBannerUseCaseTest.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.service.MemberService; -import com.gomo.app.core.member.fixture.MemberFixture; - -@DisplayName("[Application Unit]: 멤버 프로필 배너 삭제 테스트") -@ExtendWith(MockitoExtension.class) -public class DeleteProfileBannerUseCaseTest { - - @InjectMocks - private DeleteProfileBannerUseCase sut; - - @Mock - private MemberService memberService; - - @DisplayName("프로필 배너 삭제 테스트") - @Test - void delete_profile_banner() { - Member member = MemberFixture.create(); - doReturn(member).when(memberService).find(member.getId()); - - sut.delete(member.getId()); - - assertThat(member.profileBannerUrl()).isEqualTo("DEFAULT_IMAGE"); - } -} diff --git a/src/test/java/com/gomo/app/core/member/application/usecase/DeleteProfileImageUseCaseTest.java b/src/test/java/com/gomo/app/core/member/application/usecase/DeleteProfileImageUseCaseTest.java deleted file mode 100644 index f0207b83..00000000 --- a/src/test/java/com/gomo/app/core/member/application/usecase/DeleteProfileImageUseCaseTest.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.service.MemberService; -import com.gomo.app.core.member.fixture.MemberFixture; - -@DisplayName("[Application Unit]: 멤버 프로필 이미지 삭제 테스트") -@ExtendWith(MockitoExtension.class) -public class DeleteProfileImageUseCaseTest { - - @InjectMocks - private DeleteProfileImageUseCase sut; - - @Mock - private MemberService memberService; - - @DisplayName("프로필 이미지 삭제 테스트") - @Test - void delete_profile_image() { - Member member = MemberFixture.create(); - doReturn(member).when(memberService).find(member.getId()); - sut.delete(member.getId()); - assertThat(member.profileImageUrl()).isEqualTo("DEFAULT_IMAGE"); - } -} diff --git a/src/test/java/com/gomo/app/core/member/application/usecase/ReadMemberUseCaseTest.java b/src/test/java/com/gomo/app/core/member/application/usecase/ReadMemberUseCaseTest.java deleted file mode 100644 index 4ad5e2cd..00000000 --- a/src/test/java/com/gomo/app/core/member/application/usecase/ReadMemberUseCaseTest.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.member.application.port.dto.MemberDto; -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.service.MemberService; -import com.gomo.app.core.member.fixture.MemberFixture; -import com.gomo.app.core.point.application.port.ReadBalancePortIn; - -@DisplayName("[Application unit]: 멤버 조회 테스트") -@ExtendWith(MockitoExtension.class) -public class ReadMemberUseCaseTest { - - @InjectMocks - private ReadMemberUseCase sut; - - @Mock - private MemberService memberService; - - @Mock - private ReadBalancePortIn readBalancePortIn; - - private static final int BALANCE = 5000; - - @DisplayName("멤버 조회에 성공한다") - @Test - void read_member_successfully() { - Member member = MemberFixture.create(); - MemberDto expected = MemberDto.from(member, BALANCE); - - doReturn(member).when(memberService).find(any()); - doReturn(BALANCE).when(readBalancePortIn).find(any()); - - MemberDto actual = sut.find(member.getId()); - - assertThat(actual).usingRecursiveComparison().isEqualTo(expected); - } -} diff --git a/src/test/java/com/gomo/app/core/member/application/usecase/ReadQuestPropertyUseCaseTest.java b/src/test/java/com/gomo/app/core/member/application/usecase/ReadQuestPropertyUseCaseTest.java deleted file mode 100644 index f6a55a36..00000000 --- a/src/test/java/com/gomo/app/core/member/application/usecase/ReadQuestPropertyUseCaseTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.member.application.port.dto.QuestPropertyDto; -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.service.MemberService; -import com.gomo.app.core.member.fixture.MemberFixture; - -@DisplayName("[Application unit]: 퀘스트 설정 조회 테스트") -@ExtendWith(MockitoExtension.class) -public class ReadQuestPropertyUseCaseTest { - - @InjectMocks - private ReadQuestPropertyUseCase sut; - - @Mock - private MemberService memberService; - - @DisplayName("회원의 퀘스트 설정 정보를 조회한다.") - @Test - void find_quest_property_successfully() { - Member member = MemberFixture.create(3); - QuestPropertyDto expected = QuestPropertyDto.from(member.getQuestProperty()); - doReturn(member).when(memberService).find(member.getId()); - - QuestPropertyDto actual = sut.find(member.getId()); - - assertThat(actual).usingRecursiveComparison().isEqualTo(expected); - } -} diff --git a/src/test/java/com/gomo/app/core/member/application/usecase/ResetPasswordUseCaseTest.java b/src/test/java/com/gomo/app/core/member/application/usecase/ResetPasswordUseCaseTest.java deleted file mode 100644 index 67c7d410..00000000 --- a/src/test/java/com/gomo/app/core/member/application/usecase/ResetPasswordUseCaseTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.common.security.encoder.application.port.EncodePasswordPortIn; -import com.gomo.app.common.security.jwt.application.port.VerifyJwtPortIn; -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.service.MemberService; -import com.gomo.app.core.member.fixture.MemberFixture; - -@DisplayName("[Application unit] : 비밀번호 초기화 테스트") -@ExtendWith(MockitoExtension.class) -class ResetPasswordUseCaseTest { - - @InjectMocks - private ResetPasswordUseCase sut; - - @Mock - private VerifyJwtPortIn verifyJwtPortIn; - - @Mock - private EncodePasswordPortIn encodePasswordPortIn; - - @Mock - private MemberService memberService; - - @DisplayName("비밀번호를 초기화한다.") - @Test - void reset_password() { - Member member = MemberFixture.create(); - String encoded = "encoded_password"; - doReturn(true).when(verifyJwtPortIn).validateToken(any()); - doReturn(member).when(memberService).findByEmail(any()); - doReturn(encoded).when(encodePasswordPortIn).encode(any()); - - sut.reset(member.email(), "New1234@", "temporaryToken"); - - assertThat(member.password()).isEqualTo(encoded); - } - - @DisplayName("임시 코드 검증에 실패한다.") - @Test - void fail_validate_temporary_code() { - Member member = MemberFixture.create(); - doReturn(false).when(verifyJwtPortIn).validateToken(null); - - assertThatThrownBy(() -> sut.reset(member.email(), "New1234@", null)).isInstanceOf(IllegalArgumentException.class); - } -} diff --git a/src/test/java/com/gomo/app/core/member/application/usecase/UpdateHandleUseCaseTest.java b/src/test/java/com/gomo/app/core/member/application/usecase/UpdateHandleUseCaseTest.java deleted file mode 100644 index d695a009..00000000 --- a/src/test/java/com/gomo/app/core/member/application/usecase/UpdateHandleUseCaseTest.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.service.MemberService; -import com.gomo.app.core.member.fixture.MemberFixture; - -@DisplayName("[Application unit]: 핸들 업데이트 테스트") -@ExtendWith(MockitoExtension.class) -public class UpdateHandleUseCaseTest { - - @InjectMocks - private UpdateHandleUseCase sut; - - @Mock - private MemberService memberService; - - private final static String UPDATED_HANDLE = "@updatedhandle"; - - @DisplayName("핸들 업데이트를 성공한다") - @Test - void update_handle_success() { - Member member = MemberFixture.create(); - doReturn(member).when(memberService).find(member.getId()); - sut.update(member.getId(), UPDATED_HANDLE); - assertThat(member.handle()).isEqualTo(UPDATED_HANDLE); - } -} diff --git a/src/test/java/com/gomo/app/core/member/application/usecase/UpdateMemberUseCaseTest.java b/src/test/java/com/gomo/app/core/member/application/usecase/UpdateMemberUseCaseTest.java deleted file mode 100644 index eb40e715..00000000 --- a/src/test/java/com/gomo/app/core/member/application/usecase/UpdateMemberUseCaseTest.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.service.MemberService; -import com.gomo.app.core.member.fixture.MemberFixture; - -@DisplayName("[Application unit]: 멤버 수정(이름, 모토) 테스트") -@ExtendWith(MockitoExtension.class) -public class UpdateMemberUseCaseTest { - - @InjectMocks - private UpdateMemberUseCase sut; - - @Mock - private MemberService memberService; - - @DisplayName("회원 정보(모토, 이름)을 수정한다.") - @Test - void update_member_name_and_motto() { - Member member = MemberFixture.create(); - doReturn(member).when(memberService).find(member.getId()); - sut.update(member.getId(), "NEW_NAME", "NEW_MOTTO"); - assertThat(member.name()).isEqualTo("NEW_NAME"); - assertThat(member.motto()).isEqualTo("NEW_MOTTO"); - } - - // TODO: 회원 수정 로직 보완이 필요합니다. - // @DisplayName("회원 정보(이름)을 수정한다.") - // @Test - // void update_member_name() { - // Member member = MemberFixture.member(); - // UpdateMemberRequest request = UpdateMemberRequest.of("NEW_NAME2", null); - // - // doReturn(member).when(memberService).find(member.getId()); - // - // sut.update(member.uuid(), request); - // - // assertThat(member.getName().getName()).isEqualTo("NEW_NAME2"); - // } - // - // @DisplayName("회원 정보(모토)을 수정한다.") - // @Test - // void update_member_motto() { - // Member member = MemberFixture.member(); - // UpdateMemberRequest request = UpdateMemberRequest.of(null, "NEW_MOTTO_2"); - // - // doReturn(member).when(memberService).find(member.getId()); - // - // sut.update(member.uuid(), request); - // - // assertThat(member.getMotto().getMotto()).isEqualTo("NEW_MOTTO_2"); - // } -} diff --git a/src/test/java/com/gomo/app/core/member/application/usecase/UpdatePasswordUseCaseTest.java b/src/test/java/com/gomo/app/core/member/application/usecase/UpdatePasswordUseCaseTest.java deleted file mode 100644 index c59dd5fd..00000000 --- a/src/test/java/com/gomo/app/core/member/application/usecase/UpdatePasswordUseCaseTest.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import static com.gomo.app.core.member.exception.code.MemberErrorCode.*; -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.common.security.encoder.application.port.EncodePasswordPortIn; -import com.gomo.app.common.security.encoder.application.port.VerifyPasswordPortIn; -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.service.MemberService; -import com.gomo.app.core.member.exception.MemberAuthenticationFailedException; -import com.gomo.app.core.member.fixture.MemberFixture; - -@DisplayName("[Application unit] : 비밀번호 변경 테스트") -@ExtendWith(MockitoExtension.class) -class UpdatePasswordUseCaseTest { - - @InjectMocks - private UpdatePasswordUseCase sut; - - @Mock - private VerifyPasswordPortIn verifyPasswordPortIn; - - @Mock - private EncodePasswordPortIn encodePasswordPortIn; - - @Mock - private MemberService memberService; - - @DisplayName("비밀번호를 변경한다.") - @Test - void update_password() { - Member member = MemberFixture.create(); - String encoded = "encoded_password"; - doReturn(member).when(memberService).find(any()); - doReturn(true).when(verifyPasswordPortIn).matches(any(), any()); - doReturn(encoded).when(encodePasswordPortIn).encode(any()); - - sut.update(member.getId(), "Origin123@", "New1234@"); - - assertThat(member.password()).isEqualTo(encoded); - } - - @DisplayName("기존 비밀번호 불일치로 비밀번호를 변경하지 못한다.") - @Test - void update_password_with_wrong_password() { - Member member = MemberFixture.create(); - doReturn(member).when(memberService).find(any()); - doReturn(false).when(verifyPasswordPortIn).matches(any(), any()); - - assertThatThrownBy(() -> sut.update(member.getId(), "Origin123@", "New1234@")) - .isInstanceOf(MemberAuthenticationFailedException.class) - .hasMessageContaining(AUTHENTICATION_FAILED.getMessage()); - } -} diff --git a/src/test/java/com/gomo/app/core/member/application/usecase/VerifyEmailCodeUseCaseTest.java b/src/test/java/com/gomo/app/core/member/application/usecase/VerifyEmailCodeUseCaseTest.java deleted file mode 100644 index 792e2d50..00000000 --- a/src/test/java/com/gomo/app/core/member/application/usecase/VerifyEmailCodeUseCaseTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.gomo.app.core.member.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.common.security.jwt.application.port.GenerateJwtPortIn; -import com.gomo.app.support.auth.application.port.VerifyAuthCodePortIn; -import com.gomo.app.support.auth.exception.AuthErrorCode; -import com.gomo.app.support.auth.exception.InvalidAuthCodeException; - -@DisplayName("[Application Unit]: Email 인증 검증 기능 테스트") -@ExtendWith(MockitoExtension.class) -public class VerifyEmailCodeUseCaseTest { - - @InjectMocks - private VerifyEmailCodeUseCase sut; - - @Mock - private VerifyAuthCodePortIn verifyAuthCodePortIn; - - @Mock - private GenerateJwtPortIn generateJwtPortIn; - - private static final String AUTH_CODE_STORED = "123456"; - private static final String EMAIL = "test@test.com"; - - @DisplayName("이메일 인증코드 검증에 성공한다") - @Test - void verify_email_auth_code_successfully() { - sut.verify(EMAIL, AUTH_CODE_STORED); - verify(verifyAuthCodePortIn, times(1)).verify(EMAIL, AUTH_CODE_STORED); - verify(generateJwtPortIn, times(1)).generateTemporaryToken(EMAIL, 1800); - } - - @DisplayName("이메일 검증코드가 null이면 검증에 실패한다") - @Test - void verify_email_auth_code_fail_with_null() { - doThrow(new InvalidAuthCodeException(AuthErrorCode.INVALID_AUTH_CODE)).when(verifyAuthCodePortIn).verify(anyString(), any()); - assertThatThrownBy(() -> sut.verify(EMAIL, null)) - .isInstanceOf(InvalidAuthCodeException.class) - .hasMessageContaining(AuthErrorCode.INVALID_AUTH_CODE.getMessage()); - } - - @DisplayName("이메일 검증코드가 저장된 값과 다르면 검증에 실패한다") - @Test - void verify_email_auth_code_fail_with_incorrect_code() { - doThrow(new InvalidAuthCodeException(AuthErrorCode.INVALID_AUTH_CODE)).when(verifyAuthCodePortIn).verify(anyString(), anyString()); - assertThatThrownBy(() -> sut.verify(EMAIL, "111111")) - .isInstanceOf(InvalidAuthCodeException.class) - .hasMessageContaining(AuthErrorCode.INVALID_AUTH_CODE.getMessage()); - } -} diff --git a/src/test/java/com/gomo/app/core/member/domain/model/DailyThresholdTest.java b/src/test/java/com/gomo/app/core/member/domain/model/DailyThresholdTest.java index ba4ca478..28e7d265 100644 --- a/src/test/java/com/gomo/app/core/member/domain/model/DailyThresholdTest.java +++ b/src/test/java/com/gomo/app/core/member/domain/model/DailyThresholdTest.java @@ -5,8 +5,8 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import com.gomo.app.core.member.exception.QuestPropertyConstraintViolationException; -import com.gomo.app.core.member.exception.code.QuestPropertyErrorCode; +import com.gomo.app.core.member.domain.exception.QuestPropertyConstraintViolationException; +import com.gomo.app.core.member.domain.exception.code.QuestPropertyErrorCode; @DisplayName("[Domain unit]: 일일 퀘스트 제한 테스트") public class DailyThresholdTest { diff --git a/src/test/java/com/gomo/app/core/member/domain/model/EmailTest.java b/src/test/java/com/gomo/app/core/member/domain/model/EmailTest.java index 5647d661..17d813d3 100644 --- a/src/test/java/com/gomo/app/core/member/domain/model/EmailTest.java +++ b/src/test/java/com/gomo/app/core/member/domain/model/EmailTest.java @@ -5,8 +5,8 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import com.gomo.app.core.member.exception.EmailConstraintViolationException; -import com.gomo.app.core.member.exception.code.EmailErrorCode; +import com.gomo.app.core.member.domain.exception.EmailConstraintViolationException; +import com.gomo.app.core.member.domain.exception.code.EmailErrorCode; @DisplayName("[Domain unit]: 이메일 생성 테스트") public class EmailTest { diff --git a/src/test/java/com/gomo/app/core/member/domain/model/HandleTest.java b/src/test/java/com/gomo/app/core/member/domain/model/HandleTest.java index b46094c0..c3567c82 100644 --- a/src/test/java/com/gomo/app/core/member/domain/model/HandleTest.java +++ b/src/test/java/com/gomo/app/core/member/domain/model/HandleTest.java @@ -5,8 +5,8 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import com.gomo.app.core.member.exception.HandleConstraintViolationException; -import com.gomo.app.core.member.exception.code.HandleErrorCode; +import com.gomo.app.core.member.domain.exception.HandleConstraintViolationException; +import com.gomo.app.core.member.domain.exception.code.HandleErrorCode; @DisplayName("[Domain unit]: 핸들 생성 및 수정 테스트") public class HandleTest { diff --git a/src/test/java/com/gomo/app/core/member/domain/model/MemberNameTest.java b/src/test/java/com/gomo/app/core/member/domain/model/MemberNameTest.java index fdad7b0b..b1b709fb 100644 --- a/src/test/java/com/gomo/app/core/member/domain/model/MemberNameTest.java +++ b/src/test/java/com/gomo/app/core/member/domain/model/MemberNameTest.java @@ -8,8 +8,8 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import com.gomo.app.core.member.exception.MemberNameConstraintViolationException; -import com.gomo.app.core.member.exception.code.MemberNameErrorCode; +import com.gomo.app.core.member.domain.exception.MemberNameConstraintViolationException; +import com.gomo.app.core.member.domain.exception.code.MemberNameErrorCode; @DisplayName("[Domain unit]: 이름 생성 및 수정 테스트") public class MemberNameTest { diff --git a/src/test/java/com/gomo/app/core/member/domain/model/MemberTest.java b/src/test/java/com/gomo/app/core/member/domain/model/MemberTest.java index 298e976c..e7e83169 100644 --- a/src/test/java/com/gomo/app/core/member/domain/model/MemberTest.java +++ b/src/test/java/com/gomo/app/core/member/domain/model/MemberTest.java @@ -10,8 +10,8 @@ import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; -import com.gomo.app.core.member.exception.ActivateStatusException; -import com.gomo.app.core.member.exception.code.ActivateStatusErrorCode; +import com.gomo.app.core.member.domain.exception.ActivateStatusException; +import com.gomo.app.core.member.domain.exception.code.ActivateStatusErrorCode; import com.gomo.app.core.member.fixture.MemberFixture; @DisplayName("[Domain unit]: 회원 테스트") diff --git a/src/test/java/com/gomo/app/core/member/domain/model/MonthlyThresholdTest.java b/src/test/java/com/gomo/app/core/member/domain/model/MonthlyThresholdTest.java index f4a912b8..fe2c1744 100644 --- a/src/test/java/com/gomo/app/core/member/domain/model/MonthlyThresholdTest.java +++ b/src/test/java/com/gomo/app/core/member/domain/model/MonthlyThresholdTest.java @@ -5,8 +5,8 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import com.gomo.app.core.member.exception.QuestPropertyConstraintViolationException; -import com.gomo.app.core.member.exception.code.QuestPropertyErrorCode; +import com.gomo.app.core.member.domain.exception.QuestPropertyConstraintViolationException; +import com.gomo.app.core.member.domain.exception.code.QuestPropertyErrorCode; @DisplayName("[Domain unit]: 월간 퀘스트 제한 테스트") public class MonthlyThresholdTest { diff --git a/src/test/java/com/gomo/app/core/member/domain/model/MottoTest.java b/src/test/java/com/gomo/app/core/member/domain/model/MottoTest.java index cf8f4afd..69417a22 100644 --- a/src/test/java/com/gomo/app/core/member/domain/model/MottoTest.java +++ b/src/test/java/com/gomo/app/core/member/domain/model/MottoTest.java @@ -8,8 +8,8 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import com.gomo.app.core.member.exception.MottoConstraintViolationException; -import com.gomo.app.core.member.exception.code.MottoErrorCode; +import com.gomo.app.core.member.domain.exception.MottoConstraintViolationException; +import com.gomo.app.core.member.domain.exception.code.MottoErrorCode; @DisplayName("[Domain unit]: 모토 생성 및 수정 테스트") public class MottoTest { diff --git a/src/test/java/com/gomo/app/core/member/domain/model/PasswordTest.java b/src/test/java/com/gomo/app/core/member/domain/model/PasswordTest.java index c1fe1b41..cc43599a 100644 --- a/src/test/java/com/gomo/app/core/member/domain/model/PasswordTest.java +++ b/src/test/java/com/gomo/app/core/member/domain/model/PasswordTest.java @@ -10,8 +10,8 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; -import com.gomo.app.core.member.exception.PasswordConstraintViolationException; -import com.gomo.app.core.member.exception.code.PasswordErrorCode; +import com.gomo.app.core.member.domain.exception.PasswordConstraintViolationException; +import com.gomo.app.core.member.domain.exception.code.PasswordErrorCode; @DisplayName("[Domain Unit]: 비밀번호 생성 및 수정 테스트") @ExtendWith(MockitoExtension.class) diff --git a/src/test/java/com/gomo/app/core/member/domain/model/WeeklyThresholdTest.java b/src/test/java/com/gomo/app/core/member/domain/model/WeeklyThresholdTest.java index ad9bbcad..073ab666 100644 --- a/src/test/java/com/gomo/app/core/member/domain/model/WeeklyThresholdTest.java +++ b/src/test/java/com/gomo/app/core/member/domain/model/WeeklyThresholdTest.java @@ -5,8 +5,8 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import com.gomo.app.core.member.exception.QuestPropertyConstraintViolationException; -import com.gomo.app.core.member.exception.code.QuestPropertyErrorCode; +import com.gomo.app.core.member.domain.exception.QuestPropertyConstraintViolationException; +import com.gomo.app.core.member.domain.exception.code.QuestPropertyErrorCode; @DisplayName("[Domain unit]: 주간 퀘스트 제한 테스트") public class WeeklyThresholdTest { diff --git a/src/test/java/com/gomo/app/core/member/infrastructure/repository/MemberRepositoryTest.java b/src/test/java/com/gomo/app/core/member/domain/repository/MemberRepositoryTest.java similarity index 97% rename from src/test/java/com/gomo/app/core/member/infrastructure/repository/MemberRepositoryTest.java rename to src/test/java/com/gomo/app/core/member/domain/repository/MemberRepositoryTest.java index c10a054b..bca9035a 100644 --- a/src/test/java/com/gomo/app/core/member/infrastructure/repository/MemberRepositoryTest.java +++ b/src/test/java/com/gomo/app/core/member/domain/repository/MemberRepositoryTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.infrastructure.repository; +package com.gomo.app.core.member.domain.repository; import static org.assertj.core.api.Assertions.*; diff --git a/src/test/java/com/gomo/app/core/member/domain/service/MemberServiceTest.java b/src/test/java/com/gomo/app/core/member/domain/service/MemberServiceTest.java deleted file mode 100644 index 788ef008..00000000 --- a/src/test/java/com/gomo/app/core/member/domain/service/MemberServiceTest.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.gomo.app.core.member.domain.service; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -import java.util.Optional; -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.member.domain.model.Email; -import com.gomo.app.core.member.domain.model.Handle; -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.repository.MemberRepository; -import com.gomo.app.core.member.exception.EmailDuplicatedException; -import com.gomo.app.core.member.exception.HandleDuplicatedException; -import com.gomo.app.core.member.exception.MemberNotFoundException; -import com.gomo.app.core.member.exception.code.EmailErrorCode; -import com.gomo.app.core.member.exception.code.HandleErrorCode; -import com.gomo.app.core.member.exception.code.MemberErrorCode; - -@DisplayName("[Domain unit]: MemberService 테스트") -@ExtendWith(MockitoExtension.class) -public class MemberServiceTest { - - @InjectMocks - private MemberService sut; - - @Mock - private MemberRepository memberRepository; - - @DisplayName("회원 엔티티를 조회한다.") - @Test - void find_member() { - doReturn(Optional.of(mock(Member.class))).when(memberRepository).findById(any()); - - Member actual = sut.find(UUID.randomUUID()); - - assertThat(actual).isNotNull(); - } - - @DisplayName("존재하지 않는 회원 엔티티를 조회한다.") - @Test - void find_nonexistent_member() { - doReturn(Optional.empty()).when(memberRepository).findById(any()); - - assertThatThrownBy(() -> sut.find(UUID.randomUUID())) - .isInstanceOf(MemberNotFoundException.class) - .hasMessageContaining(MemberErrorCode.NOT_FOUND.getMessage()); - } - - @DisplayName("이메일로 회원 엔티티를 조회한다.") - @Test - void find_member_by_mail() { - doReturn(Optional.of(mock(Member.class))).when(memberRepository).findByEmail(any(Email.class)); - - Member actual = sut.findByEmail(Email.of("gomo@naver.com")); - - assertThat(actual).isNotNull(); - } - - @DisplayName("이메일로 존재하지 않는 회원 엔티티를 조회한다.") - @Test - void find_nonexistent_member_by_email() { - doReturn(Optional.empty()).when(memberRepository).findByEmail(any(Email.class)); - - assertThatThrownBy(() -> sut.findByEmail(Email.of("nonexistent@naver.com"))) - .isInstanceOf(MemberNotFoundException.class) - .hasMessageContaining(MemberErrorCode.NOT_FOUND.getMessage()); - } - - @DisplayName("이메일이 중복되지 않는다.") - @Test - void check_non_duplicated_email() { - doReturn(Optional.empty()).when(memberRepository).findByEmail(any(Email.class)); - - assertThatCode(() -> sut.checkEmailDuplicated(Email.of("nonexistent@naver.com"))) - .doesNotThrowAnyException(); - } - - @DisplayName("이메일이 중복된다.") - @Test - void check_duplicated_email() { - doReturn(Optional.of(mock(Member.class))).when(memberRepository).findByEmail(any(Email.class)); - - assertThatThrownBy(() -> sut.checkEmailDuplicated(Email.of("gomo@naver.com"))) - .isInstanceOf(EmailDuplicatedException.class) - .hasMessageContaining(EmailErrorCode.DUPLICATED.getMessage()); - } - - @DisplayName("핸들이 중복되지 않는다.") - @Test - void check_non_duplicated_handle() { - doReturn(Optional.empty()).when(memberRepository).findByHandle(any(Handle.class)); - - assertThatCode(() -> sut.checkHandleDuplicated(Handle.of("@nonexistent"))) - .doesNotThrowAnyException(); - } - - @DisplayName("핸들이 중복된다.") - @Test - void check_duplicated_handle() { - doReturn(Optional.of(mock(Member.class))).when(memberRepository).findByHandle(any(Handle.class)); - - assertThatThrownBy(() -> sut.checkHandleDuplicated(Handle.of("@gomo"))) - .isInstanceOf(HandleDuplicatedException.class) - .hasMessageContaining(HandleErrorCode.DUPLICATED.getMessage()); - } -} diff --git a/src/test/java/com/gomo/app/core/member/domain/service/ProfileImageServiceTest.java b/src/test/java/com/gomo/app/core/member/domain/service/ProfileImageServiceTest.java deleted file mode 100644 index a418091f..00000000 --- a/src/test/java/com/gomo/app/core/member/domain/service/ProfileImageServiceTest.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.gomo.app.core.member.domain.service; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.List; -import java.util.Set; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.member.domain.repository.MemberRepository; - -@DisplayName("[Domain unit]: 프로필 이미지 URL 조회 테스트") -@ExtendWith(MockitoExtension.class) -public class ProfileImageServiceTest { - - @InjectMocks - private ProfileImageService sut; - - @Mock - private MemberRepository memberRepository; - - @DisplayName("프로필 이미지 URL을 조회한다.") - @Test - void find_all_profile_image_url() { - doReturn(List.of("profileA", "profileB")).when(memberRepository).findAllByProfileImageUrl(); - - Set actual = sut.getAllProfileImageUrl(); - - assertThat(actual.size()).isEqualTo(2); - } -} diff --git a/src/test/java/com/gomo/app/core/point/presentation/documentation/ListPointDocumentationTest.java b/src/test/java/com/gomo/app/core/point/adapter/in/api/ListPointDocumentationTest.java similarity index 64% rename from src/test/java/com/gomo/app/core/point/presentation/documentation/ListPointDocumentationTest.java rename to src/test/java/com/gomo/app/core/point/adapter/in/api/ListPointDocumentationTest.java index 78f4dc43..fdb2068a 100644 --- a/src/test/java/com/gomo/app/core/point/presentation/documentation/ListPointDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/point/adapter/in/api/ListPointDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.point.presentation.documentation; +package com.gomo.app.core.point.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -6,19 +6,20 @@ import static org.springframework.http.HttpStatus.*; import static org.springframework.http.MediaType.*; +import java.util.List; + import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.point.domain.model.SourceType; -import com.gomo.app.core.point.domain.model.TransactionType; +import com.gomo.app.common.util.UUIDGenerator; +import com.gomo.app.core.point.adapter.in.api.snippet.ListPointSnippet; +import com.gomo.app.core.point.domain.model.Point; import com.gomo.app.core.point.domain.repository.PointRepository; -import com.gomo.app.core.point.domain.service.PointService; -import com.gomo.app.core.point.presentation.documentation.snippet.ListPointSnippet; +import com.gomo.app.core.point.fixture.PointFixture; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 포인트 목록 조회 테스트") @@ -26,19 +27,9 @@ public class ListPointDocumentationTest extends DocumentationTestBase { private final RestDocumentationFilter filter = ListPointSnippet.create(); - @Autowired - private PointService pointService; - @Autowired private PointRepository pointRepository; - @BeforeEach - public void setUp() { - pointService.create(sessionMemberId, SourceType.QUEST, TransactionType.GAIN, 10); - pointService.create(sessionMemberId, SourceType.QUEST, TransactionType.GAIN, 150); - pointService.create(sessionMemberId, SourceType.QUEST, TransactionType.GAIN, 1500); - } - @AfterEach void tearDown() { pointRepository.deleteAllInBatch(); @@ -47,6 +38,11 @@ void tearDown() { @DisplayName("사용자가 포인트 목록을 조회한다.") @Test void history_point() { + Point point1 = PointFixture.create(UUIDGenerator.generate(), sessionMemberId); + Point point2 = PointFixture.create(UUIDGenerator.generate(), sessionMemberId); + Point point3 = PointFixture.create(UUIDGenerator.generate(), sessionMemberId); + pointRepository.saveAll(List.of(point1, point2, point3)); + given(this.specification).filter(filter) .header(CONTENT_TYPE, APPLICATION_JSON_VALUE) .header(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken) diff --git a/src/test/java/com/gomo/app/core/point/presentation/documentation/ReadBalanceDocumentationTest.java b/src/test/java/com/gomo/app/core/point/adapter/in/api/ReadBalanceDocumentationTest.java similarity index 85% rename from src/test/java/com/gomo/app/core/point/presentation/documentation/ReadBalanceDocumentationTest.java rename to src/test/java/com/gomo/app/core/point/adapter/in/api/ReadBalanceDocumentationTest.java index bc4e04fb..1a289e45 100644 --- a/src/test/java/com/gomo/app/core/point/presentation/documentation/ReadBalanceDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/point/adapter/in/api/ReadBalanceDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.point.presentation.documentation; +package com.gomo.app.core.point.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -10,7 +10,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.point.presentation.documentation.snippet.ReadBalanceSnippet; +import com.gomo.app.core.point.adapter.in.api.snippet.ReadBalanceSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 포인트 잔고 조회 테스트") diff --git a/src/test/java/com/gomo/app/core/point/presentation/documentation/snippet/ListPointSnippet.java b/src/test/java/com/gomo/app/core/point/adapter/in/api/snippet/ListPointSnippet.java similarity index 95% rename from src/test/java/com/gomo/app/core/point/presentation/documentation/snippet/ListPointSnippet.java rename to src/test/java/com/gomo/app/core/point/adapter/in/api/snippet/ListPointSnippet.java index 7cc3ef8a..85b1c05e 100644 --- a/src/test/java/com/gomo/app/core/point/presentation/documentation/snippet/ListPointSnippet.java +++ b/src/test/java/com/gomo/app/core/point/adapter/in/api/snippet/ListPointSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.point.presentation.documentation.snippet; +package com.gomo.app.core.point.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/point/presentation/documentation/snippet/ReadBalanceSnippet.java b/src/test/java/com/gomo/app/core/point/adapter/in/api/snippet/ReadBalanceSnippet.java similarity index 92% rename from src/test/java/com/gomo/app/core/point/presentation/documentation/snippet/ReadBalanceSnippet.java rename to src/test/java/com/gomo/app/core/point/adapter/in/api/snippet/ReadBalanceSnippet.java index 858a3c23..cfb9365f 100644 --- a/src/test/java/com/gomo/app/core/point/presentation/documentation/snippet/ReadBalanceSnippet.java +++ b/src/test/java/com/gomo/app/core/point/adapter/in/api/snippet/ReadBalanceSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.point.presentation.documentation.snippet; +package com.gomo.app.core.point.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/point/presentation/consumer/CompleteQuestEventPointConsumerTest.java b/src/test/java/com/gomo/app/core/point/adapter/in/consumer/CompleteQuestEventPointConsumerTest.java similarity index 84% rename from src/test/java/com/gomo/app/core/point/presentation/consumer/CompleteQuestEventPointConsumerTest.java rename to src/test/java/com/gomo/app/core/point/adapter/in/consumer/CompleteQuestEventPointConsumerTest.java index beea1bd3..7ba92467 100644 --- a/src/test/java/com/gomo/app/core/point/presentation/consumer/CompleteQuestEventPointConsumerTest.java +++ b/src/test/java/com/gomo/app/core/point/adapter/in/consumer/CompleteQuestEventPointConsumerTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.point.presentation.consumer; +package com.gomo.app.core.point.adapter.in.consumer; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; @@ -16,8 +16,8 @@ import org.mockito.junit.jupiter.MockitoExtension; import com.gomo.app.common.util.JsonParser; -import com.gomo.app.core.point.application.port.CreatePointPortIn; -import com.gomo.app.core.quest.event.CompleteQuestEvent; +import com.gomo.app.core.point.application.port.in.PointCreator; +import com.gomo.app.core.quest.domain.event.CompleteQuestEvent; import com.gomo.app.support.evententry.domain.model.EventEntry; @DisplayName("[Consumer unit]: 퀘스트 완료(포인트) 이벤트 처리 테스트") @@ -28,7 +28,7 @@ class CompleteQuestEventPointConsumerTest { private CompleteQuestEventPointConsumer sut; @Mock - private CreatePointPortIn createPointPortIn; + private PointCreator pointCreator; @DisplayName("포인트 생성 이벤트를 처리한다.") @Test @@ -41,7 +41,7 @@ void event_process() { sut.handleEvent(eventEntry); - verify(createPointPortIn, times(1)).create(any(), any(), any(), anyInt()); + verify(pointCreator, times(1)).create(any(), any(), any(), anyInt()); } } @@ -50,7 +50,7 @@ void event_process() { void cannot_process_event_by_point() { EventEntry eventEntry = EventEntry.of("CompleteQuestEvent", "payload", 1L); CompleteQuestEvent event = CompleteQuestEvent.of(UUID.randomUUID(), UUID.randomUUID(), "DAILY", 2, 10, LocalDateTime.now(), 1L); - doThrow(new IllegalStateException("Point service failure")).when(createPointPortIn).create(any(), any(), any(), anyInt()); + doThrow(new IllegalStateException("Point service failure")).when(pointCreator).create(any(), any(), any(), anyInt()); try (MockedStatic mockedJsonParser = mockStatic(JsonParser.class)) { mockedJsonParser.when(() -> JsonParser.fromJson(any(), eq(CompleteQuestEvent.class))).thenReturn(event); diff --git a/src/test/java/com/gomo/app/core/point/application/usecase/ReadBalanceUseCaseTest.java b/src/test/java/com/gomo/app/core/point/application/service/BalanceServiceTest.java similarity index 62% rename from src/test/java/com/gomo/app/core/point/application/usecase/ReadBalanceUseCaseTest.java rename to src/test/java/com/gomo/app/core/point/application/service/BalanceServiceTest.java index 3ceae008..4ab1faef 100644 --- a/src/test/java/com/gomo/app/core/point/application/usecase/ReadBalanceUseCaseTest.java +++ b/src/test/java/com/gomo/app/core/point/application/service/BalanceServiceTest.java @@ -1,37 +1,37 @@ -package com.gomo.app.core.point.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.point.domain.model.Balance; -import com.gomo.app.core.point.domain.service.PointWalletService; - -@DisplayName("[Application unit]: 포인트 잔고 조회 테스트") -@ExtendWith(MockitoExtension.class) -public class ReadBalanceUseCaseTest { - - @InjectMocks - private ReadBalanceUseCase sut; - - @Mock - private PointWalletService pointWalletService; - - @DisplayName("사용자의 포인트 잔고를 조회한다.") - @Test - void find_balance_by_transactor_id() { - doReturn(Balance.of(1000)).when(pointWalletService).findBalance(any()); - - int actual = sut.find(UUID.randomUUID()); - - assertThat(actual).isEqualTo(1000); - } -} +package com.gomo.app.core.point.application.service; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.UUID; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.core.point.domain.model.Balance; + +@DisplayName("[Application unit]: 포인트 잔고 서비스 테스트") +@ExtendWith(MockitoExtension.class) +class BalanceServiceTest { + + @InjectMocks + private BalanceService sut; + + @Mock + private PointWalletService pointWalletService; + + @DisplayName("사용자의 포인트 잔고를 조회한다.") + @Test + void find_balance_by_transactor_id() { + doReturn(Balance.of(1000)).when(pointWalletService).readBalance(any()); + + int actual = sut.read(UUID.randomUUID()); + + assertThat(actual).isEqualTo(1000); + } +} diff --git a/src/test/java/com/gomo/app/core/point/application/usecase/ReadPointUseCaseTest.java b/src/test/java/com/gomo/app/core/point/application/service/PointServiceTest.java similarity index 54% rename from src/test/java/com/gomo/app/core/point/application/usecase/ReadPointUseCaseTest.java rename to src/test/java/com/gomo/app/core/point/application/service/PointServiceTest.java index fa189b94..9e86fba0 100644 --- a/src/test/java/com/gomo/app/core/point/application/usecase/ReadPointUseCaseTest.java +++ b/src/test/java/com/gomo/app/core/point/application/service/PointServiceTest.java @@ -1,51 +1,64 @@ -package com.gomo.app.core.point.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.List; -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.common.web.PageRequest; -import com.gomo.app.core.point.application.port.dto.ListPointDto; -import com.gomo.app.core.point.domain.repository.PointRepository; -import com.gomo.app.core.point.fixture.PointFixture; - -@DisplayName("[Application unit]: 포인트 조회 테스트") -@ExtendWith(MockitoExtension.class) -public class ReadPointUseCaseTest { - - @InjectMocks - private ReadPointUseCase sut; - - @Mock - private PointRepository pointRepository; - - @DisplayName("포인트 목록을 조회한다.") - @Test - void find_points() { - doReturn(List.of(PointFixture.create(), PointFixture.create())).when(pointRepository).findAllByTransactorId(any(), any(), eq(10)); - - ListPointDto actual = sut.findAll(UUID.randomUUID(), PageRequest.of(10, null)); - - assertThat(actual.points().size()).isEqualTo(2); - assertThat(actual.lastElementId()).isNotNull(); - } - - @DisplayName("포인트 목록이 없다면, 마지막 원소는 null이 된다.") - @Test - void find_empty_points() { - doReturn(List.of()).when(pointRepository).findAllByTransactorId(any(), any(), eq(10)); - - ListPointDto actual = sut.findAll(UUID.randomUUID(), PageRequest.of(10, null)); - - assertThat(actual.lastElementId()).isNull(); - } -} +package com.gomo.app.core.point.application.service; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.List; +import java.util.UUID; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.common.web.PageRequest; +import com.gomo.app.core.point.application.port.dto.ListPointDto; +import com.gomo.app.core.point.domain.repository.PointRepository; +import com.gomo.app.core.point.fixture.PointFixture; + +@DisplayName("[Application unit]: 포인트 생성 테스트") +@ExtendWith(MockitoExtension.class) +class PointServiceTest { + + @InjectMocks + private PointService sut; + + @Mock + private PointWalletService pointWalletService; + + @Mock + private PointRepository pointRepository; + + @DisplayName("포인트를 생성한다.") + @Test + void create_point() { + doReturn(PointFixture.create()).when(pointRepository).save(any()); + sut.create(UUID.randomUUID(), "QUEST", "GAIN", 10); + verify(pointWalletService, times(1)).adjustPointBalance(any(), any(), eq(10)); + verify(pointRepository, times(1)).save(any()); + } + + @DisplayName("포인트 목록을 조회한다.") + @Test + void read_points() { + doReturn(List.of(PointFixture.create(), PointFixture.create())).when(pointRepository).findAllByTransactorId(any(), any(), any(), eq(10)); + + ListPointDto actual = sut.readAll(UUID.randomUUID(), PageRequest.of(10, null, null)); + + assertThat(actual.points().size()).isEqualTo(2); + assertThat(actual.lastElementId()).isNotNull(); + } + + @DisplayName("포인트 목록이 없다면, 마지막 원소는 null이 된다.") + @Test + void read_empty_points() { + doReturn(List.of()).when(pointRepository).findAllByTransactorId(any(), any(), any(), eq(10)); + + ListPointDto actual = sut.readAll(UUID.randomUUID(), PageRequest.of(10, null, null)); + + assertThat(actual.lastElementId()).isNull(); + } +} diff --git a/src/test/java/com/gomo/app/core/point/domain/service/PointWalletServiceTest.java b/src/test/java/com/gomo/app/core/point/application/service/PointWalletServiceTest.java similarity index 69% rename from src/test/java/com/gomo/app/core/point/domain/service/PointWalletServiceTest.java rename to src/test/java/com/gomo/app/core/point/application/service/PointWalletServiceTest.java index 541707c3..b71fabdb 100644 --- a/src/test/java/com/gomo/app/core/point/domain/service/PointWalletServiceTest.java +++ b/src/test/java/com/gomo/app/core/point/application/service/PointWalletServiceTest.java @@ -1,66 +1,87 @@ -package com.gomo.app.core.point.domain.service; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.Optional; -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.point.domain.model.Balance; -import com.gomo.app.core.point.domain.model.PointWallet; -import com.gomo.app.core.point.domain.model.TransactionType; -import com.gomo.app.core.point.domain.repository.PointWalletRepository; -import com.gomo.app.core.point.fixture.PointWalletFixture; - -@DisplayName("[Domain unit]: 포인트 잔고 조회 및 조정 테스트") -@ExtendWith(MockitoExtension.class) -public class PointWalletServiceTest { - - @InjectMocks - private PointWalletService sut; - - @Mock - private PointWalletRepository pointWalletRepository; - - @DisplayName("사용자의 포인트 잔고를 조회한다.") - @Test - void find_balance() { - PointWallet pointWallet = PointWalletFixture.create(UUID.randomUUID(), 1660); - doReturn(Optional.of((pointWallet))).when(pointWalletRepository).findByTransactorId(any()); - - Balance balance = sut.findBalance(pointWallet.getTransactorId()); - - assertThat(balance.getAmount()).isEqualTo(pointWallet.getBalance().getAmount()); - } - - @DisplayName("사용자 포인트 잔고가 증가한다.") - @Test - void enhance_balance() { - PointWallet pointWallet = PointWalletFixture.create(UUID.randomUUID(), 1660); - doReturn(Optional.of((pointWallet))).when(pointWalletRepository).findByTransactorId(any()); - - sut.adjustPointBalance(pointWallet.getTransactorId(), TransactionType.GAIN, 40); - - PointWallet updatedWallet = pointWalletRepository.findByTransactorId(pointWallet.getTransactorId()).get(); - assertThat(updatedWallet.getBalance().getAmount()).isEqualTo(1700); - } - - @DisplayName("사용자 포인트 잔고가 감소한다.") - @Test - void reduce_balance() { - PointWallet pointWallet = PointWalletFixture.create(UUID.randomUUID(), 1660); - doReturn(Optional.of((pointWallet))).when(pointWalletRepository).findByTransactorId(any()); - - sut.adjustPointBalance(pointWallet.getTransactorId(), TransactionType.GAIN, -60); - - PointWallet updatedWallet = pointWalletRepository.findByTransactorId(pointWallet.getTransactorId()).get(); - assertThat(updatedWallet.getBalance().getAmount()).isEqualTo(1600); - } -} +package com.gomo.app.core.point.application.service; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.Optional; +import java.util.UUID; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.core.point.domain.model.Balance; +import com.gomo.app.core.point.domain.model.PointWallet; +import com.gomo.app.core.point.domain.model.TransactionType; +import com.gomo.app.core.point.domain.repository.PointWalletRepository; +import com.gomo.app.core.point.fixture.PointWalletFixture; + +@DisplayName("[Application unit]: 포인트 지갑 생성 테스트") +@ExtendWith(MockitoExtension.class) +class PointWalletServiceTest { + + @InjectMocks + private PointWalletService sut; + + @Mock + private PointWalletRepository pointWalletRepository; + + @DisplayName("포인트 지갑을 생성한다.") + @Test + void create_point_wallet() { + PointWallet pointWallet = PointWalletFixture.create(); + doReturn(false).when(pointWalletRepository).existsByTransactorId(any()); + doReturn(pointWallet).when(pointWalletRepository).save(any()); + + UUID actual = sut.create(UUID.randomUUID()); + + assertThat(actual).isEqualTo(pointWallet.getId()); + } + + @DisplayName("포인트 지갑을 중복 생성한다.") + @Test + void create_duplicated_point_wallet() { + doReturn(true).when(pointWalletRepository).existsByTransactorId(any()); + + assertThatThrownBy(() -> sut.create(UUID.randomUUID())).isInstanceOf(IllegalStateException.class); + } + + @DisplayName("사용자의 포인트 잔고를 조회한다.") + @Test + void read_balance() { + PointWallet pointWallet = PointWalletFixture.create(UUID.randomUUID(), 1660); + doReturn(Optional.of((pointWallet))).when(pointWalletRepository).findByTransactorId(any()); + + Balance balance = sut.readBalance(pointWallet.getTransactorId()); + + assertThat(balance.getAmount()).isEqualTo(pointWallet.getBalance().getAmount()); + } + + @DisplayName("사용자 포인트 잔고가 증가한다.") + @Test + void enhance_balance() { + PointWallet pointWallet = PointWalletFixture.create(UUID.randomUUID(), 1660); + doReturn(Optional.of((pointWallet))).when(pointWalletRepository).findByTransactorId(any()); + + sut.adjustPointBalance(pointWallet.getTransactorId(), TransactionType.GAIN, 40); + + PointWallet updatedWallet = pointWalletRepository.findByTransactorId(pointWallet.getTransactorId()).get(); + assertThat(updatedWallet.getBalance().getAmount()).isEqualTo(1700); + } + + @DisplayName("사용자 포인트 잔고가 감소한다.") + @Test + void reduce_balance() { + PointWallet pointWallet = PointWalletFixture.create(UUID.randomUUID(), 1660); + doReturn(Optional.of((pointWallet))).when(pointWalletRepository).findByTransactorId(any()); + + sut.adjustPointBalance(pointWallet.getTransactorId(), TransactionType.GAIN, -60); + + PointWallet updatedWallet = pointWalletRepository.findByTransactorId(pointWallet.getTransactorId()).get(); + assertThat(updatedWallet.getBalance().getAmount()).isEqualTo(1600); + } +} diff --git a/src/test/java/com/gomo/app/core/point/application/usecase/CreatePointUseCaseTest.java b/src/test/java/com/gomo/app/core/point/application/usecase/CreatePointUseCaseTest.java deleted file mode 100644 index 68292d69..00000000 --- a/src/test/java/com/gomo/app/core/point/application/usecase/CreatePointUseCaseTest.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.gomo.app.core.point.application.usecase; - -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; -import static org.mockito.Mockito.anyInt; - -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.point.domain.service.PointService; - -@DisplayName("[Application unit]: 포인트 생성 테스트") -@ExtendWith(MockitoExtension.class) -class CreatePointUseCaseTest { - - @InjectMocks - private CreatePointUseCase sut; - - @Mock - private PointService pointService; - - @DisplayName("포인트를 생성한다.") - @Test - void create_point() { - sut.create(UUID.randomUUID(), "QUEST", "GAIN", 10); - verify(pointService, times(1)).create(any(), any(), any(), anyInt()); - } -} diff --git a/src/test/java/com/gomo/app/core/point/application/usecase/CreatePointWalletUseCaseTest.java b/src/test/java/com/gomo/app/core/point/application/usecase/CreatePointWalletUseCaseTest.java deleted file mode 100644 index 13030e62..00000000 --- a/src/test/java/com/gomo/app/core/point/application/usecase/CreatePointWalletUseCaseTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.gomo.app.core.point.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.point.domain.model.PointWallet; -import com.gomo.app.core.point.domain.repository.PointWalletRepository; -import com.gomo.app.core.point.fixture.PointWalletFixture; - -@DisplayName("[Application unit]: 포인트 지갑 생성 테스트") -@ExtendWith(MockitoExtension.class) -class CreatePointWalletUseCaseTest { - - @InjectMocks - private CreatePointWalletUseCase sut; - - @Mock - private PointWalletRepository pointWalletRepository; - - @DisplayName("포인트 지갑을 생성한다.") - @Test - void create_point_wallet() { - PointWallet pointWallet = PointWalletFixture.create(); - doReturn(pointWallet).when(pointWalletRepository).save(any()); - - UUID actual = sut.create(UUID.randomUUID()); - - assertThat(actual).isEqualTo(pointWallet.getId()); - } -} diff --git a/src/test/java/com/gomo/app/core/point/domain/model/BalanceTest.java b/src/test/java/com/gomo/app/core/point/domain/model/BalanceTest.java index b4421f1b..e9a32824 100644 --- a/src/test/java/com/gomo/app/core/point/domain/model/BalanceTest.java +++ b/src/test/java/com/gomo/app/core/point/domain/model/BalanceTest.java @@ -7,7 +7,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import com.gomo.app.core.point.exception.InsufficientBalanceException; +import com.gomo.app.core.point.domain.exception.InsufficientBalanceException; @DisplayName("[Domain unit]: 잔고 생성 및 조정 테스트") public class BalanceTest { diff --git a/src/test/java/com/gomo/app/core/point/domain/model/PointTest.java b/src/test/java/com/gomo/app/core/point/domain/model/PointTest.java index b11e2c5a..b9b7e566 100644 --- a/src/test/java/com/gomo/app/core/point/domain/model/PointTest.java +++ b/src/test/java/com/gomo/app/core/point/domain/model/PointTest.java @@ -10,7 +10,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import com.gomo.app.core.point.exception.PointConstraintViolationException; +import com.gomo.app.core.point.domain.exception.PointConstraintViolationException; @DisplayName("[Domain unit]: 포인트 생성 테스트") public class PointTest { diff --git a/src/test/java/com/gomo/app/core/point/domain/repository/PointRepositoryTest.java b/src/test/java/com/gomo/app/core/point/domain/repository/PointRepositoryTest.java new file mode 100644 index 00000000..13a37faa --- /dev/null +++ b/src/test/java/com/gomo/app/core/point/domain/repository/PointRepositoryTest.java @@ -0,0 +1,125 @@ +package com.gomo.app.core.point.domain.repository; + +import static org.assertj.core.api.Assertions.*; + +import java.util.List; +import java.util.UUID; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; + +import com.gomo.app.common.util.UUIDGenerator; +import com.gomo.app.core.point.domain.model.Point; +import com.gomo.app.core.point.fixture.PointFixture; +import com.gomo.app.test.IntegrationTest; + +@DisplayName("[Domain integration]: 포인트 DB 접근 테스트") +@IntegrationTest +public class PointRepositoryTest { + + @Autowired + private PointRepository sut; + + @Autowired + private PointRepository pointRepository; + + @AfterEach + void tearDown() { + pointRepository.deleteAllInBatch(); + } + + @DisplayName("마지막 아이디 없이 포인트 목록을 조회한다.") + @Test + void find_all_point() { + UUID transactorId = UUIDGenerator.generate(); + Point point1 = PointFixture.create(UUIDGenerator.generate(), transactorId); + Point point2 = PointFixture.create(UUIDGenerator.generate(), transactorId); + pointRepository.saveAll(List.of(point1, point2)); + + List actual = sut.findAllByTransactorId( + String.valueOf(transactorId), + null, + null, + 10 + ); + + assertThat(actual.size()).isEqualTo(2); + } + + @DisplayName("포인트 목록은 거래일자 기준으로 내림차순 조회한다.") + @Test + void find_all_point_transaction_date_desc() { + UUID transactorId = UUIDGenerator.generate(); + Point point1 = PointFixture.create(UUIDGenerator.generate(), transactorId); + Point point2 = PointFixture.create(UUIDGenerator.generate(), transactorId); + Point point3 = PointFixture.create(UUIDGenerator.generate(), transactorId); + pointRepository.saveAll(List.of(point1, point2, point3)); + + List actual = sut.findAllByTransactorId( + String.valueOf(transactorId), + null, + null, + 10 + ); + + assertThat(actual.get(0).getTransactionDateTime()).isAfterOrEqualTo(actual.get(1).getTransactionDateTime()); + assertThat(actual.get(1).getTransactionDateTime()).isAfterOrEqualTo(actual.get(2).getTransactionDateTime()); + } + + @DisplayName("마지막 아이디 없이 제한된 개수만큼 포인트 목록을 조회한다.") + @Test + void find_all_point_with_size() { + UUID transactorId = UUIDGenerator.generate(); + Point point1 = PointFixture.create(UUIDGenerator.generate(), transactorId); + Point point2 = PointFixture.create(UUIDGenerator.generate(), transactorId); + Point point3 = PointFixture.create(UUIDGenerator.generate(), transactorId); + pointRepository.saveAll(List.of(point1, point2, point3)); + + List actual = sut.findAllByTransactorId( + String.valueOf(transactorId), + null, + null, + 2 + ); + + assertThat(actual.size()).isEqualTo(2); + } + + @DisplayName("마지막 아이디와 함께 포인트 목록을 조회한다.") + @Test + void find_history_quests_with_last_element_id() { + UUID transactorId = UUIDGenerator.generate(); + Point point1 = PointFixture.create(UUIDGenerator.generate(), transactorId); + Point point2 = PointFixture.create(UUIDGenerator.generate(), transactorId); + Point point3 = PointFixture.create(UUIDGenerator.generate(), transactorId); + Point point4 = PointFixture.create(UUIDGenerator.generate(), transactorId); + pointRepository.saveAll(List.of(point1, point2, point3, point4)); + + List actual = sut.findAllByTransactorId( + String.valueOf(transactorId), + point3.getTransactionDateTime(), + String.valueOf(point3.getId()), + 5 + ); + + assertThat(actual.size()).isEqualTo(2); + } + + @DisplayName("특정 사용자의 포인트 내역을 삭제한다.") + @Transactional + @Test + void delete_all_points() { + UUID transactorId = UUIDGenerator.generate(); + Point point1 = PointFixture.create(UUIDGenerator.generate(), transactorId); + Point point2 = PointFixture.create(UUIDGenerator.generate(), transactorId); + Point point3 = PointFixture.create(UUIDGenerator.generate(), transactorId); + pointRepository.saveAll(List.of(point1, point2, point3)); + + sut.deleteAllByTransactorId(transactorId); + + assertThat(sut.findAllByTransactorId(String.valueOf(transactorId), null, null, 100).size()).isZero(); + } +} diff --git a/src/test/java/com/gomo/app/core/point/domain/service/PointServiceTest.java b/src/test/java/com/gomo/app/core/point/domain/service/PointServiceTest.java deleted file mode 100644 index e5659cf1..00000000 --- a/src/test/java/com/gomo/app/core/point/domain/service/PointServiceTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.gomo.app.core.point.domain.service; - -import static org.mockito.Mockito.*; - -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.point.domain.model.SourceType; -import com.gomo.app.core.point.domain.model.TransactionType; -import com.gomo.app.core.point.domain.repository.PointRepository; -import com.gomo.app.core.point.fixture.PointFixture; - -@DisplayName("[Domain unit]: 포인트 생성 테스트") -@ExtendWith(MockitoExtension.class) -public class PointServiceTest { - - @InjectMocks - private PointService sut; - - @Mock - private PointWalletService pointWalletService; - - @Mock - private PointRepository pointRepository; - - @DisplayName("포인트를 생성한다.") - @Test - void create_point() { - doReturn(PointFixture.create()).when(pointRepository).save(any()); - sut.create(UUID.randomUUID(), SourceType.QUEST, TransactionType.GAIN, 10); - verify(pointWalletService, times(1)).adjustPointBalance(any(), any(), eq(10)); - verify(pointRepository, times(1)).save(any()); - } -} diff --git a/src/test/java/com/gomo/app/core/point/fixture/PointFixture.java b/src/test/java/com/gomo/app/core/point/fixture/PointFixture.java index 7e7bb43e..50008d0f 100644 --- a/src/test/java/com/gomo/app/core/point/fixture/PointFixture.java +++ b/src/test/java/com/gomo/app/core/point/fixture/PointFixture.java @@ -32,4 +32,16 @@ public static Point create(UUID transactionId) { LocalDateTime.now() ); } + + public static Point create(UUID id, UUID transactionId) { + return Point.of( + id, + transactionId, + SourceType.QUEST, + TransactionType.GAIN, + 10, + SourceType.QUEST.getDescription() + TransactionType.GAIN.getDescription(), + LocalDateTime.now() + ); + } } diff --git a/src/test/java/com/gomo/app/core/point/infrastructure/PointRepositoryTest.java b/src/test/java/com/gomo/app/core/point/infrastructure/PointRepositoryTest.java deleted file mode 100644 index 2c3960b5..00000000 --- a/src/test/java/com/gomo/app/core/point/infrastructure/PointRepositoryTest.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.gomo.app.core.point.infrastructure; - -import static org.assertj.core.api.Assertions.*; - -import java.util.List; -import java.util.UUID; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.transaction.annotation.Transactional; - -import com.gomo.app.core.point.domain.model.Point; -import com.gomo.app.core.point.domain.model.SourceType; -import com.gomo.app.core.point.domain.model.TransactionType; -import com.gomo.app.core.point.domain.repository.PointRepository; -import com.gomo.app.core.point.domain.repository.PointWalletRepository; -import com.gomo.app.core.point.domain.service.PointService; -import com.gomo.app.core.point.fixture.PointWalletFixture; -import com.gomo.app.test.IntegrationTest; - -@DisplayName("[Domain integration]: 포인트 DB 접근 테스트") -@IntegrationTest -public class PointRepositoryTest { - - @Autowired - private PointRepository sut; - - @Autowired - private PointService pointService; - private UUID transactorId; - private UUID offsetId; - - @Autowired - private PointRepository pointRepository; - - @Autowired - private PointWalletRepository pointWalletRepository; - - @BeforeEach - public void setUp() { - transactorId = UUID.randomUUID(); - pointWalletRepository.save(PointWalletFixture.create(transactorId, 1660)); - pointService.create(transactorId, SourceType.QUEST, TransactionType.GAIN, 10); - offsetId = pointService.create(transactorId, SourceType.QUEST, TransactionType.GAIN, 150); - pointService.create(transactorId, SourceType.QUEST, TransactionType.GAIN, 1500); - } - - @AfterEach - void tearDown() { - pointRepository.deleteAllInBatch(); - pointWalletRepository.deleteAllInBatch(); - } - - @DisplayName("마지막 아이디 없이 포인트 목록을 조회한다.") - @Test - void find_all_point() { - List actual = sut.findAllByTransactorId( - String.valueOf(transactorId), - null, - 10 - ); - - assertThat(actual.size()).isEqualTo(3); - } - - @DisplayName("포인트 목록은 거래일자 기준으로 내림차순 조회한다.") - @Test - void find_all_point_transaction_date_desc() { - List actual = sut.findAllByTransactorId( - String.valueOf(transactorId), - null, - 10 - ); - - assertThat(actual.get(0).getTransactionDateTime()).isAfterOrEqualTo(actual.get(1).getTransactionDateTime()); - assertThat(actual.get(1).getTransactionDateTime()).isAfterOrEqualTo(actual.get(2).getTransactionDateTime()); - } - - @DisplayName("마지막 아이디 없이 제한된 개수만큼 포인트 목록을 조회한다.") - @Test - void find_all_point_with_size() { - List actual = sut.findAllByTransactorId( - String.valueOf(transactorId), - null, - 2 - ); - - assertThat(actual.size()).isEqualTo(2); - } - - @DisplayName("마지막 아이디와 함께 포인트 목록을 조회한다.") - @Test - void find_history_quests_with_last_element_id() { - List actual = sut.findAllByTransactorId( - String.valueOf(transactorId), - String.valueOf(offsetId), - 2 - ); - - assertThat(actual.size()).isEqualTo(1); - } - - @DisplayName("특정 사용자의 포인트 내역을 삭제한다.") - @Transactional - @Test - void delete_all_points() { - sut.deleteAllByTransactorId(transactorId); - - assertThat(sut.findAllByTransactorId(String.valueOf(transactorId), null, 100).size()).isZero(); - } -} diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/CalendarAssignQuestDocumentationTest.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/CalendarAssignQuestDocumentationTest.java similarity index 93% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/CalendarAssignQuestDocumentationTest.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/CalendarAssignQuestDocumentationTest.java index 4b73c5b5..21951d17 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/CalendarAssignQuestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/CalendarAssignQuestDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation; +package com.gomo.app.core.quest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -15,7 +15,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.quest.presentation.documentation.snippet.CalendarAssignQuestSnippet; +import com.gomo.app.core.quest.adapter.in.api.snippet.CalendarAssignQuestSnippet; import com.gomo.app.core.quest.domain.model.assign.AssignQuest; import com.gomo.app.core.quest.domain.model.quest.QuestType; import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/CompleteAssignQuestDocumentationTest.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/CompleteAssignQuestDocumentationTest.java similarity index 85% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/CompleteAssignQuestDocumentationTest.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/CompleteAssignQuestDocumentationTest.java index 27e14132..ea75e4f8 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/CompleteAssignQuestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/CompleteAssignQuestDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation; +package com.gomo.app.core.quest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -12,11 +12,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.quest.presentation.documentation.snippet.CompleteAssignQuestSnippet; +import com.gomo.app.core.quest.adapter.in.api.request.CompleteAssignQuestRequest; +import com.gomo.app.core.quest.adapter.in.api.snippet.CompleteAssignQuestSnippet; import com.gomo.app.core.quest.domain.model.assign.AssignQuest; import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; import com.gomo.app.core.quest.fixture.AssignQuestFixture; -import com.gomo.app.core.quest.presentation.api.request.CompleteAssignQuestRequest; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 참여 중인 퀘스트 완료 테스트") diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/ConfirmAssignQuestDocumentationTest.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/ConfirmAssignQuestDocumentationTest.java similarity index 89% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/ConfirmAssignQuestDocumentationTest.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/ConfirmAssignQuestDocumentationTest.java index ef845ea3..c946f7c9 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/ConfirmAssignQuestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/ConfirmAssignQuestDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation; +package com.gomo.app.core.quest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -12,7 +12,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.quest.presentation.documentation.snippet.ConfirmAssignQuestSnippet; +import com.gomo.app.core.quest.adapter.in.api.snippet.ConfirmAssignQuestSnippet; import com.gomo.app.core.quest.domain.model.assign.AssignQuest; import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; import com.gomo.app.core.quest.fixture.AssignQuestFixture; diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/CreateAssignQuestDocumentationTest.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/CreateAssignQuestDocumentationTest.java similarity index 85% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/CreateAssignQuestDocumentationTest.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/CreateAssignQuestDocumentationTest.java index de7a82cc..b5bf4f19 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/CreateAssignQuestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/CreateAssignQuestDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation; +package com.gomo.app.core.quest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -14,14 +14,14 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.member.presentation.QuestPropertyApi; -import com.gomo.app.core.member.presentation.request.UpdateQuestPropertyRequest; -import com.gomo.app.core.quest.presentation.documentation.snippet.CreateAssignQuestSnippet; +import com.gomo.app.core.member.adapter.in.api.QuestPropertyApi; +import com.gomo.app.core.member.adapter.in.api.request.UpdateQuestPropertyRequest; +import com.gomo.app.core.quest.adapter.in.api.request.CreateAssignQuestRequest; +import com.gomo.app.core.quest.adapter.in.api.snippet.CreateAssignQuestSnippet; import com.gomo.app.core.quest.domain.model.quest.QuestType; import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; -import com.gomo.app.core.quest.exception.code.QuestContentErrorCode; -import com.gomo.app.core.quest.exception.code.QuestErrorCode; -import com.gomo.app.core.quest.presentation.api.request.CreateAssignQuestRequest; +import com.gomo.app.core.quest.domain.exception.code.QuestContentErrorCode; +import com.gomo.app.core.quest.domain.exception.code.QuestErrorCode; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 할당 퀘스트 생성 테스트") diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/CreateRepeatQuestDocumentationTest.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/CreateRepeatQuestDocumentationTest.java similarity index 83% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/CreateRepeatQuestDocumentationTest.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/CreateRepeatQuestDocumentationTest.java index af9de5af..fcdf4e93 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/CreateRepeatQuestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/CreateRepeatQuestDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation; +package com.gomo.app.core.quest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -15,17 +15,17 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; +import com.gomo.app.core.interest.adapter.in.api.InterestApi; +import com.gomo.app.core.interest.adapter.in.api.request.CreateInterestRequest; import com.gomo.app.core.interest.domain.repository.InterestRepository; -import com.gomo.app.core.interest.presentation.api.InterestApi; -import com.gomo.app.core.interest.presentation.api.request.CreateInterestRequest; -import com.gomo.app.core.member.presentation.QuestPropertyApi; -import com.gomo.app.core.member.presentation.request.UpdateQuestPropertyRequest; -import com.gomo.app.core.quest.presentation.documentation.snippet.CreateRepeatQuestSnippet; +import com.gomo.app.core.member.adapter.in.api.QuestPropertyApi; +import com.gomo.app.core.member.adapter.in.api.request.UpdateQuestPropertyRequest; +import com.gomo.app.core.quest.adapter.in.api.request.CreateRepeatQuestRequest; +import com.gomo.app.core.quest.adapter.in.api.snippet.CreateRepeatQuestSnippet; import com.gomo.app.core.quest.domain.model.quest.QuestType; import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; -import com.gomo.app.core.quest.exception.code.QuestContentErrorCode; -import com.gomo.app.core.quest.exception.code.QuestErrorCode; -import com.gomo.app.core.quest.presentation.api.request.CreateRepeatQuestRequest; +import com.gomo.app.core.quest.domain.exception.code.QuestContentErrorCode; +import com.gomo.app.core.quest.domain.exception.code.QuestErrorCode; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 반복 퀘스트 생성 테스트") diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/DeleteAssignQuestDocumentationTest.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/DeleteAssignQuestDocumentationTest.java similarity index 89% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/DeleteAssignQuestDocumentationTest.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/DeleteAssignQuestDocumentationTest.java index 95ce1d93..25b1869f 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/DeleteAssignQuestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/DeleteAssignQuestDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation; +package com.gomo.app.core.quest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -12,7 +12,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.quest.presentation.documentation.snippet.DeleteAssignQuestSnippet; +import com.gomo.app.core.quest.adapter.in.api.snippet.DeleteAssignQuestSnippet; import com.gomo.app.core.quest.domain.model.assign.AssignQuest; import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; import com.gomo.app.core.quest.fixture.AssignQuestFixture; diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/DeleteRepeatQuestDocumentationTest.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/DeleteRepeatQuestDocumentationTest.java similarity index 84% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/DeleteRepeatQuestDocumentationTest.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/DeleteRepeatQuestDocumentationTest.java index ee7620c4..a379a682 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/DeleteRepeatQuestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/DeleteRepeatQuestDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation; +package com.gomo.app.core.quest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -15,11 +15,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.quest.presentation.documentation.snippet.DeleteRepeatQuestSnippet; +import com.gomo.app.core.quest.adapter.in.api.request.CreateRepeatQuestRequest; +import com.gomo.app.core.quest.adapter.in.api.snippet.DeleteRepeatQuestSnippet; import com.gomo.app.core.quest.domain.model.quest.QuestType; import com.gomo.app.core.quest.domain.repository.RepeatQuestRepository; -import com.gomo.app.core.quest.presentation.api.RepeatQuestApi; -import com.gomo.app.core.quest.presentation.api.request.CreateRepeatQuestRequest; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 반복 퀘스트 삭제 테스트") diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/ListAssignQuestDocumentationTest.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/ListAssignQuestDocumentationTest.java similarity index 91% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/ListAssignQuestDocumentationTest.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/ListAssignQuestDocumentationTest.java index c5aec0d6..c0076a49 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/ListAssignQuestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/ListAssignQuestDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation; +package com.gomo.app.core.quest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -16,7 +16,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.quest.presentation.documentation.snippet.ListAssignQuestSnippet; +import com.gomo.app.core.quest.adapter.in.api.snippet.ListAssignQuestSnippet; import com.gomo.app.core.quest.domain.model.assign.AssignQuest; import com.gomo.app.core.quest.domain.model.quest.QuestType; import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/ListRepeatQuestDocumentationTest.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/ListRepeatQuestDocumentationTest.java similarity index 86% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/ListRepeatQuestDocumentationTest.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/ListRepeatQuestDocumentationTest.java index 50f7cfc4..beb075a4 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/ListRepeatQuestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/ListRepeatQuestDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation; +package com.gomo.app.core.quest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -16,11 +16,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.quest.presentation.documentation.snippet.ListRepeatQuestSnippet; +import com.gomo.app.core.quest.adapter.in.api.request.CreateRepeatQuestRequest; +import com.gomo.app.core.quest.adapter.in.api.snippet.ListRepeatQuestSnippet; import com.gomo.app.core.quest.domain.model.quest.QuestType; import com.gomo.app.core.quest.domain.repository.RepeatQuestRepository; -import com.gomo.app.core.quest.presentation.api.RepeatQuestApi; -import com.gomo.app.core.quest.presentation.api.request.CreateRepeatQuestRequest; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 반복 퀘스트 조회 테스트") diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/OrderUpdateAssignQuestDocumentationTest.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/OrderUpdateAssignQuestDocumentationTest.java similarity index 88% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/OrderUpdateAssignQuestDocumentationTest.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/OrderUpdateAssignQuestDocumentationTest.java index 4708a3c3..2f501ed4 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/OrderUpdateAssignQuestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/OrderUpdateAssignQuestDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation; +package com.gomo.app.core.quest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -17,12 +17,12 @@ import org.springframework.restdocs.restassured.RestDocumentationFilter; import com.gomo.app.common.displayorder.UpdatedOrderDto; -import com.gomo.app.core.quest.presentation.documentation.snippet.OrderUpdateAssignQuestSnippet; +import com.gomo.app.core.quest.adapter.in.api.request.OrderUpdateAssignQuestRequest; +import com.gomo.app.core.quest.adapter.in.api.snippet.OrderUpdateAssignQuestSnippet; import com.gomo.app.core.quest.domain.model.assign.AssignQuest; import com.gomo.app.core.quest.domain.model.quest.QuestType; import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; import com.gomo.app.core.quest.fixture.AssignQuestFixture; -import com.gomo.app.core.quest.presentation.api.request.OrderUpdateAssignQuestRequest; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 참여 중인 퀘스트 순서 변경 테스트") diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/OrderUpdateRepeatQuestDocumentationTest.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/OrderUpdateRepeatQuestDocumentationTest.java similarity index 87% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/OrderUpdateRepeatQuestDocumentationTest.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/OrderUpdateRepeatQuestDocumentationTest.java index 3ed88de5..7c142809 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/OrderUpdateRepeatQuestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/OrderUpdateRepeatQuestDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation; +package com.gomo.app.core.quest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -16,12 +16,12 @@ import org.springframework.restdocs.restassured.RestDocumentationFilter; import com.gomo.app.common.displayorder.UpdatedOrderDto; -import com.gomo.app.core.quest.presentation.documentation.snippet.OrderUpdateRepeatQuestSnippet; +import com.gomo.app.core.quest.adapter.in.api.request.OrderUpdateRepeatQuestRequest; +import com.gomo.app.core.quest.adapter.in.api.snippet.OrderUpdateRepeatQuestSnippet; import com.gomo.app.core.quest.domain.model.quest.QuestType; import com.gomo.app.core.quest.domain.model.repeat.RepeatQuest; import com.gomo.app.core.quest.domain.repository.RepeatQuestRepository; import com.gomo.app.core.quest.fixture.RepeatQuestFixture; -import com.gomo.app.core.quest.presentation.api.request.OrderUpdateRepeatQuestRequest; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 반복 퀘스트 순서 변경 테스트") diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/ReRollAssignQuestDocumentationTest.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/ReRollAssignQuestDocumentationTest.java similarity index 89% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/ReRollAssignQuestDocumentationTest.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/ReRollAssignQuestDocumentationTest.java index db24c904..3de3ea82 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/ReRollAssignQuestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/ReRollAssignQuestDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation; +package com.gomo.app.core.quest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -15,6 +15,8 @@ import org.springframework.restdocs.restassured.RestDocumentationFilter; import com.gomo.app.common.util.UUIDGenerator; +import com.gomo.app.core.quest.adapter.in.api.request.ReRollAssignQuestRequest; +import com.gomo.app.core.quest.adapter.in.api.snippet.ReRollAssignQuestSnippet; import com.gomo.app.core.quest.domain.model.assign.AssignQuest; import com.gomo.app.core.quest.domain.model.pool.ProcessingStatus; import com.gomo.app.core.quest.domain.model.pool.QuestPool; @@ -24,8 +26,6 @@ import com.gomo.app.core.quest.domain.repository.QuestPoolRepository; import com.gomo.app.core.quest.fixture.AssignQuestFixture; import com.gomo.app.core.quest.fixture.QuestFixture; -import com.gomo.app.core.quest.presentation.api.request.ReRollAssignQuestRequest; -import com.gomo.app.core.quest.presentation.documentation.snippet.ReRollAssignQuestSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 퀘스트 재생성(리롤) 테스트") diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/UpdateAssignQuestDocumentationTest.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/UpdateAssignQuestDocumentationTest.java similarity index 88% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/UpdateAssignQuestDocumentationTest.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/UpdateAssignQuestDocumentationTest.java index 4dcdf23f..c1de653f 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/UpdateAssignQuestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/UpdateAssignQuestDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation; +package com.gomo.app.core.quest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -15,13 +15,13 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.quest.presentation.documentation.snippet.UpdateAssignQuestSnippet; +import com.gomo.app.core.quest.adapter.in.api.request.UpdateAssignQuestRequest; +import com.gomo.app.core.quest.adapter.in.api.snippet.UpdateAssignQuestSnippet; import com.gomo.app.core.quest.domain.model.assign.AssignQuest; import com.gomo.app.core.quest.domain.model.quest.QuestType; import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; -import com.gomo.app.core.quest.exception.code.QuestContentErrorCode; +import com.gomo.app.core.quest.domain.exception.code.QuestContentErrorCode; import com.gomo.app.core.quest.fixture.AssignQuestFixture; -import com.gomo.app.core.quest.presentation.api.request.UpdateAssignQuestRequest; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 참여 중인 퀘스트 수정 테스트") diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/UpdateRepeatQuestDocumentationTest.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/UpdateRepeatQuestDocumentationTest.java similarity index 85% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/UpdateRepeatQuestDocumentationTest.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/UpdateRepeatQuestDocumentationTest.java index d8ac5cd6..df34541b 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/UpdateRepeatQuestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/UpdateRepeatQuestDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation; +package com.gomo.app.core.quest.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -16,13 +16,12 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.quest.presentation.documentation.snippet.UpdateRepeatQuestSnippet; +import com.gomo.app.core.quest.adapter.in.api.request.CreateRepeatQuestRequest; +import com.gomo.app.core.quest.adapter.in.api.request.UpdateRepeatQuestRequest; +import com.gomo.app.core.quest.adapter.in.api.snippet.UpdateRepeatQuestSnippet; import com.gomo.app.core.quest.domain.model.quest.QuestType; import com.gomo.app.core.quest.domain.repository.RepeatQuestRepository; -import com.gomo.app.core.quest.exception.code.QuestContentErrorCode; -import com.gomo.app.core.quest.presentation.api.RepeatQuestApi; -import com.gomo.app.core.quest.presentation.api.request.CreateRepeatQuestRequest; -import com.gomo.app.core.quest.presentation.api.request.UpdateRepeatQuestRequest; +import com.gomo.app.core.quest.domain.exception.code.QuestContentErrorCode; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 반복 퀘스트 수정 테스트") diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/CalendarAssignQuestSnippet.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/CalendarAssignQuestSnippet.java similarity index 95% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/CalendarAssignQuestSnippet.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/CalendarAssignQuestSnippet.java index 85cf3298..b4042ada 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/CalendarAssignQuestSnippet.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/CalendarAssignQuestSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation.snippet; +package com.gomo.app.core.quest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/CompleteAssignQuestSnippet.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/CompleteAssignQuestSnippet.java similarity index 93% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/CompleteAssignQuestSnippet.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/CompleteAssignQuestSnippet.java index 6d3dc3f6..e6465620 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/CompleteAssignQuestSnippet.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/CompleteAssignQuestSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation.snippet; +package com.gomo.app.core.quest.adapter.in.api.snippet; // 1. ePages import 제거, Spring REST Docs 표준 import로 교체 diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/ConfirmAssignQuestSnippet.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/ConfirmAssignQuestSnippet.java similarity index 92% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/ConfirmAssignQuestSnippet.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/ConfirmAssignQuestSnippet.java index 89d5e9d5..890426ee 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/ConfirmAssignQuestSnippet.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/ConfirmAssignQuestSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation.snippet; +package com.gomo.app.core.quest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/CreateAssignQuestSnippet.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/CreateAssignQuestSnippet.java similarity index 94% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/CreateAssignQuestSnippet.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/CreateAssignQuestSnippet.java index 7a719f78..e7a22702 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/CreateAssignQuestSnippet.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/CreateAssignQuestSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation.snippet; +package com.gomo.app.core.quest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/CreateRepeatQuestSnippet.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/CreateRepeatQuestSnippet.java similarity index 94% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/CreateRepeatQuestSnippet.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/CreateRepeatQuestSnippet.java index 3f09c2de..3791052b 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/CreateRepeatQuestSnippet.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/CreateRepeatQuestSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation.snippet; +package com.gomo.app.core.quest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/DeleteAssignQuestSnippet.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/DeleteAssignQuestSnippet.java similarity index 92% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/DeleteAssignQuestSnippet.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/DeleteAssignQuestSnippet.java index 44e0286d..08ef5ef6 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/DeleteAssignQuestSnippet.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/DeleteAssignQuestSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation.snippet; +package com.gomo.app.core.quest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/DeleteRepeatQuestSnippet.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/DeleteRepeatQuestSnippet.java similarity index 92% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/DeleteRepeatQuestSnippet.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/DeleteRepeatQuestSnippet.java index 61fdf4fe..65a2d2f6 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/DeleteRepeatQuestSnippet.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/DeleteRepeatQuestSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation.snippet; +package com.gomo.app.core.quest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/ListAssignQuestSnippet.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/ListAssignQuestSnippet.java similarity index 96% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/ListAssignQuestSnippet.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/ListAssignQuestSnippet.java index 04edb17b..d05b5777 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/ListAssignQuestSnippet.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/ListAssignQuestSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation.snippet; +package com.gomo.app.core.quest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/ListRepeatQuestSnippet.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/ListRepeatQuestSnippet.java similarity index 95% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/ListRepeatQuestSnippet.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/ListRepeatQuestSnippet.java index a9c78686..261b3295 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/ListRepeatQuestSnippet.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/ListRepeatQuestSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation.snippet; +package com.gomo.app.core.quest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/OrderUpdateAssignQuestSnippet.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/OrderUpdateAssignQuestSnippet.java similarity index 94% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/OrderUpdateAssignQuestSnippet.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/OrderUpdateAssignQuestSnippet.java index 8a2381b2..ea7df011 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/OrderUpdateAssignQuestSnippet.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/OrderUpdateAssignQuestSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation.snippet; +package com.gomo.app.core.quest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/OrderUpdateRepeatQuestSnippet.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/OrderUpdateRepeatQuestSnippet.java similarity index 94% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/OrderUpdateRepeatQuestSnippet.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/OrderUpdateRepeatQuestSnippet.java index b11fdc3e..b36539de 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/OrderUpdateRepeatQuestSnippet.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/OrderUpdateRepeatQuestSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation.snippet; +package com.gomo.app.core.quest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/ReRollAssignQuestSnippet.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/ReRollAssignQuestSnippet.java similarity index 95% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/ReRollAssignQuestSnippet.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/ReRollAssignQuestSnippet.java index d8148eb3..5d780f6f 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/ReRollAssignQuestSnippet.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/ReRollAssignQuestSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation.snippet; +package com.gomo.app.core.quest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/UpdateAssignQuestSnippet.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/UpdateAssignQuestSnippet.java similarity index 94% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/UpdateAssignQuestSnippet.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/UpdateAssignQuestSnippet.java index c7f2e5d6..f75eb234 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/UpdateAssignQuestSnippet.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/UpdateAssignQuestSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation.snippet; +package com.gomo.app.core.quest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/UpdateRepeatQuestSnippet.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/UpdateRepeatQuestSnippet.java similarity index 94% rename from src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/UpdateRepeatQuestSnippet.java rename to src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/UpdateRepeatQuestSnippet.java index 58fe8f52..8b023d7e 100644 --- a/src/test/java/com/gomo/app/core/quest/presentation/documentation/snippet/UpdateRepeatQuestSnippet.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/snippet/UpdateRepeatQuestSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.presentation.documentation.snippet; +package com.gomo.app.core.quest.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/quest/infrastructure/adapter/LlmCreateQuestContentAdapterTest.java b/src/test/java/com/gomo/app/core/quest/adapter/out/client/LlmCreateQuestContentAdapterTest.java similarity index 85% rename from src/test/java/com/gomo/app/core/quest/infrastructure/adapter/LlmCreateQuestContentAdapterTest.java rename to src/test/java/com/gomo/app/core/quest/adapter/out/client/LlmCreateQuestContentAdapterTest.java index 3569f35d..3529fd46 100644 --- a/src/test/java/com/gomo/app/core/quest/infrastructure/adapter/LlmCreateQuestContentAdapterTest.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/out/client/LlmCreateQuestContentAdapterTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.infrastructure.adapter; +package com.gomo.app.core.quest.adapter.out.client; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.extension.ExtendWith; diff --git a/src/test/java/com/gomo/app/core/quest/infrastructure/adapter/ReadParticipantAdapterTest.java b/src/test/java/com/gomo/app/core/quest/adapter/out/client/ParticipantClientTest.java similarity index 75% rename from src/test/java/com/gomo/app/core/quest/infrastructure/adapter/ReadParticipantAdapterTest.java rename to src/test/java/com/gomo/app/core/quest/adapter/out/client/ParticipantClientTest.java index e27a96a0..89a76bad 100644 --- a/src/test/java/com/gomo/app/core/quest/infrastructure/adapter/ReadParticipantAdapterTest.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/out/client/ParticipantClientTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.infrastructure.adapter; +package com.gomo.app.core.quest.adapter.out.client; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; @@ -12,26 +12,26 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import com.gomo.app.core.member.application.port.ReadMemberPortIn; import com.gomo.app.core.member.application.port.dto.MemberDto; +import com.gomo.app.core.member.application.port.in.MemberReader; import com.gomo.app.core.member.fixture.MemberFixture; import com.gomo.app.core.quest.application.port.dto.ParticipantDto; @DisplayName("[Infrastructure unit]: MemberDto -> ParticipantDto 전환 테스트") @ExtendWith(MockitoExtension.class) -class ReadParticipantAdapterTest { +class ParticipantClientTest { @InjectMocks - private ReadParticipantAdapter sut; + private ParticipantClient sut; @Mock - private ReadMemberPortIn readMemberPortIn; + private MemberReader memberReader; @DisplayName("회원의 퀘스트 설정에 따라 퀘스트 할당량이 결정된다.") @Test void member_to_participant() { - doReturn(MemberDto.from(MemberFixture.create(5, 6, 7), 1000)).when(readMemberPortIn).find(any()); - ParticipantDto dto = sut.find(UUID.randomUUID()); + doReturn(MemberDto.from(MemberFixture.create(5, 6, 7), 1000)).when(memberReader).read(any()); + ParticipantDto dto = sut.read(UUID.randomUUID()); assertThat(dto) .extracting("dailyQuota", "weeklyQuota", "monthlyQuota") .containsExactly(5, 6, 7); diff --git a/src/test/java/com/gomo/app/core/quest/infrastructure/adapter/ReadSubjectAdapterTest.java b/src/test/java/com/gomo/app/core/quest/adapter/out/client/SubjectClientTest.java similarity index 73% rename from src/test/java/com/gomo/app/core/quest/infrastructure/adapter/ReadSubjectAdapterTest.java rename to src/test/java/com/gomo/app/core/quest/adapter/out/client/SubjectClientTest.java index b245d103..590f8831 100644 --- a/src/test/java/com/gomo/app/core/quest/infrastructure/adapter/ReadSubjectAdapterTest.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/out/client/SubjectClientTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.infrastructure.adapter; +package com.gomo.app.core.quest.adapter.out.client; import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; @@ -15,20 +15,20 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import com.gomo.app.core.interest.application.port.ReadInterestPortIn; import com.gomo.app.core.interest.application.port.dto.InterestDto; +import com.gomo.app.core.interest.application.port.in.InterestReader; import com.gomo.app.core.interest.fixture.InterestFixture; import com.gomo.app.core.quest.application.port.dto.SubjectDto; @DisplayName("[Infrastructure unit]: InterestDto -> SubjectDto 전환 테스트") @ExtendWith(MockitoExtension.class) -class ReadSubjectAdapterTest { +class SubjectClientTest { @InjectMocks - private ReadSubjectAdapter sut; + private SubjectClient sut; @Mock - private ReadInterestPortIn readInterestPortIn; + private InterestReader interestReader; @DisplayName("참여자 식별자로 퀘스트 주제 목록을 조회한다.") @Test @@ -38,9 +38,9 @@ void find_all_by_participant_id() { InterestDto.of(InterestFixture.create(), UUID.randomUUID()), InterestDto.of(InterestFixture.create(), UUID.randomUUID()) ); - doReturn(interestDtos).when(readInterestPortIn).findAll(any()); + doReturn(interestDtos).when(interestReader).readAll(any()); - List actual = sut.findAll(UUID.randomUUID()); + List actual = sut.readAll(UUID.randomUUID()); assertThat(actual.size()).isEqualTo(interestDtos.size()); } @@ -48,9 +48,9 @@ void find_all_by_participant_id() { @DisplayName("참여자 식별자로 조회한 목록이 비었다면 빈 목록을 반환한다.") @Test void find_all_by_participant_id_with_empty_list() { - doReturn(List.of()).when(readInterestPortIn).findAll(any()); + doReturn(List.of()).when(interestReader).readAll(any()); - List actual = sut.findAll(UUID.randomUUID()); + List actual = sut.readAll(UUID.randomUUID()); assertThat(actual.isEmpty()).isTrue(); } @@ -63,9 +63,9 @@ void find_all_by_participant_ids() { InterestDto.of(InterestFixture.create(), UUID.randomUUID()), InterestDto.of(InterestFixture.create(), UUID.randomUUID()) ); - doReturn(interestDtos).when(readInterestPortIn).findAllByRegistrantIds(any()); + doReturn(interestDtos).when(interestReader).readAllByRegistrantIds(any()); - List actual = sut.findAllByParticipantIds(Set.of(UUID.randomUUID(), UUID.randomUUID())); + List actual = sut.readAllByParticipantIds(Set.of(UUID.randomUUID(), UUID.randomUUID())); assertThat(actual.size()).isEqualTo(interestDtos.size()); } @@ -73,9 +73,9 @@ void find_all_by_participant_ids() { @DisplayName("참여자 식별자 목록으로 조회한 목록이 비었다면 빈 목록을 반환한다.") @Test void find_all_by_participant_ids_with_empty_list() { - doReturn(List.of()).when(readInterestPortIn).findAllByRegistrantIds(any()); + doReturn(List.of()).when(interestReader).readAllByRegistrantIds(any()); - List actual = sut.findAllByParticipantIds(Set.of(UUID.randomUUID(), UUID.randomUUID())); + List actual = sut.readAllByParticipantIds(Set.of(UUID.randomUUID(), UUID.randomUUID())); assertThat(actual.isEmpty()).isTrue(); } diff --git a/src/test/java/com/gomo/app/core/quest/infrastructure/repository/AssignQuestRepositoryTest.java b/src/test/java/com/gomo/app/core/quest/adapter/out/persistence/AssignQuestRepositoryTest.java similarity index 96% rename from src/test/java/com/gomo/app/core/quest/infrastructure/repository/AssignQuestRepositoryTest.java rename to src/test/java/com/gomo/app/core/quest/adapter/out/persistence/AssignQuestRepositoryTest.java index 1e9ef10e..7e4a0ef8 100644 --- a/src/test/java/com/gomo/app/core/quest/infrastructure/repository/AssignQuestRepositoryTest.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/out/persistence/AssignQuestRepositoryTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.infrastructure.repository; +package com.gomo.app.core.quest.adapter.out.persistence; import static org.assertj.core.api.Assertions.*; diff --git a/src/test/java/com/gomo/app/core/quest/infrastructure/repository/JdbcBulkAssignQuestRepositoryTest.java b/src/test/java/com/gomo/app/core/quest/adapter/out/persistence/JdbcBulkAssignQuestRepositoryTest.java similarity index 98% rename from src/test/java/com/gomo/app/core/quest/infrastructure/repository/JdbcBulkAssignQuestRepositoryTest.java rename to src/test/java/com/gomo/app/core/quest/adapter/out/persistence/JdbcBulkAssignQuestRepositoryTest.java index 0e27d789..863dd4ef 100644 --- a/src/test/java/com/gomo/app/core/quest/infrastructure/repository/JdbcBulkAssignQuestRepositoryTest.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/out/persistence/JdbcBulkAssignQuestRepositoryTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.infrastructure.repository; +package com.gomo.app.core.quest.adapter.out.persistence; import static org.assertj.core.api.Assertions.*; diff --git a/src/test/java/com/gomo/app/core/quest/infrastructure/repository/RepeatQuestRepositoryTest.java b/src/test/java/com/gomo/app/core/quest/adapter/out/persistence/RepeatQuestRepositoryTest.java similarity index 94% rename from src/test/java/com/gomo/app/core/quest/infrastructure/repository/RepeatQuestRepositoryTest.java rename to src/test/java/com/gomo/app/core/quest/adapter/out/persistence/RepeatQuestRepositoryTest.java index 575c2fc4..c9c032a2 100644 --- a/src/test/java/com/gomo/app/core/quest/infrastructure/repository/RepeatQuestRepositoryTest.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/out/persistence/RepeatQuestRepositoryTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.infrastructure.repository; +package com.gomo.app.core.quest.adapter.out.persistence; import static org.assertj.core.api.Assertions.*; diff --git a/src/test/java/com/gomo/app/core/quest/application/usecase/CompleteAssignQuestUseCaseTest.java b/src/test/java/com/gomo/app/core/quest/application/service/AssignQuestCompleteServiceTest.java similarity index 77% rename from src/test/java/com/gomo/app/core/quest/application/usecase/CompleteAssignQuestUseCaseTest.java rename to src/test/java/com/gomo/app/core/quest/application/service/AssignQuestCompleteServiceTest.java index 11871da5..e391ae90 100644 --- a/src/test/java/com/gomo/app/core/quest/application/usecase/CompleteAssignQuestUseCaseTest.java +++ b/src/test/java/com/gomo/app/core/quest/application/service/AssignQuestCompleteServiceTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.application.usecase; +package com.gomo.app.core.quest.application.service; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; @@ -14,28 +14,27 @@ import org.mockito.junit.jupiter.MockitoExtension; import com.gomo.app.core.quest.application.port.command.CompleteAssignQuestCommand; +import com.gomo.app.core.quest.domain.exception.AssignQuestAccessDeniedException; import com.gomo.app.core.quest.domain.model.assign.AssignQuest; import com.gomo.app.core.quest.domain.model.reward.PointReward; import com.gomo.app.core.quest.domain.model.reward.QuestReward; import com.gomo.app.core.quest.domain.model.reward.ScoreReward; -import com.gomo.app.core.quest.domain.service.AssignQuestService; -import com.gomo.app.core.quest.domain.service.QuestRewardService; -import com.gomo.app.core.quest.exception.AssignQuestAccessDeniedException; +import com.gomo.app.core.quest.domain.service.QuestRewardProvider; import com.gomo.app.core.quest.fixture.AssignQuestFixture; import com.gomo.app.support.evententry.application.port.CreateEventEntryPortIn; @DisplayName("[Application unit]: 할당 퀘스트 완료 테스트") @ExtendWith(MockitoExtension.class) -public class CompleteAssignQuestUseCaseTest { +public class AssignQuestCompleteServiceTest { @InjectMocks - private CompleteAssignQuestUseCase sut; + private AssignQuestCompleteService sut; @Mock private AssignQuestService assignQuestService; @Mock - private QuestRewardService questRewardService; + private QuestRewardProvider questRewardProvider; @Mock private CreateEventEntryPortIn createEventEntryPortIn; @@ -44,8 +43,8 @@ public class CompleteAssignQuestUseCaseTest { @Test void complete_assign_quest() { AssignQuest assignQuest = AssignQuestFixture.create(true); - doReturn(assignQuest).when(assignQuestService).find(any()); - doReturn(QuestReward.of(ScoreReward.of(2), PointReward.of(10))).when(questRewardService).find(any()); + doReturn(assignQuest).when(assignQuestService).readById(any()); + doReturn(QuestReward.of(ScoreReward.of(2), PointReward.of(10))).when(questRewardProvider).provide(any()); LocalDateTime now = LocalDateTime.now(); sut.complete(CompleteAssignQuestCommand.of(assignQuest.participantId(), UUID.randomUUID(), "https://proof", now)); @@ -58,7 +57,7 @@ void complete_assign_quest() { @Test void complete_assign_quest_with_not_participant() { AssignQuest assignQuest = AssignQuestFixture.create(true); - doReturn(assignQuest).when(assignQuestService).find(any()); + doReturn(assignQuest).when(assignQuestService).readById(any()); assertThatThrownBy( () -> sut.complete(CompleteAssignQuestCommand.of(UUID.randomUUID(), UUID.randomUUID(), "https://proof", LocalDateTime.now()))) @@ -70,8 +69,8 @@ void complete_assign_quest_with_not_participant() { @Test void complete_assign_quest_with_event() { AssignQuest assignQuest = AssignQuestFixture.create(true); - doReturn(assignQuest).when(assignQuestService).find(any()); - doReturn(QuestReward.of(ScoreReward.of(2), PointReward.of(10))).when(questRewardService).find(any()); + doReturn(assignQuest).when(assignQuestService).readById(any()); + doReturn(QuestReward.of(ScoreReward.of(2), PointReward.of(10))).when(questRewardProvider).provide(any()); sut.complete(CompleteAssignQuestCommand.of(assignQuest.participantId(), UUID.randomUUID(), "https://proof", LocalDateTime.now())); diff --git a/src/test/java/com/gomo/app/core/quest/application/usecase/CreateAssignQuestUseCaseTest.java b/src/test/java/com/gomo/app/core/quest/application/service/AssignQuestCreateServiceTest.java similarity index 52% rename from src/test/java/com/gomo/app/core/quest/application/usecase/CreateAssignQuestUseCaseTest.java rename to src/test/java/com/gomo/app/core/quest/application/service/AssignQuestCreateServiceTest.java index f792dab0..fe3cb504 100644 --- a/src/test/java/com/gomo/app/core/quest/application/usecase/CreateAssignQuestUseCaseTest.java +++ b/src/test/java/com/gomo/app/core/quest/application/service/AssignQuestCreateServiceTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.application.usecase; +package com.gomo.app.core.quest.application.service; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; @@ -8,43 +8,45 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import com.gomo.app.core.quest.application.port.ReadParticipantPortOut; import com.gomo.app.core.quest.application.port.command.CreateAssignQuestCommand; import com.gomo.app.core.quest.application.port.dto.ParticipantDto; +import com.gomo.app.core.quest.application.port.out.ParticipantReader; import com.gomo.app.core.quest.domain.model.assign.AssignQuest; import com.gomo.app.core.quest.domain.model.quest.QuestType; import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; -import com.gomo.app.core.quest.domain.service.AssignQuestService; import com.gomo.app.core.quest.fixture.AssignQuestFixture; @DisplayName("[Application unit]: 할당 퀘스트 생성 테스트") @ExtendWith(MockitoExtension.class) -public class CreateAssignQuestUseCaseTest { +public class AssignQuestCreateServiceTest { @InjectMocks - private CreateAssignQuestUseCase sut; + private AssignQuestCreateService sut; @Mock - private ReadParticipantPortOut readParticipantPort; - - @Mock - private AssignQuestService assignQuestService; + private ParticipantReader participantReader; @Mock private AssignQuestRepository assignQuestRepository; + @Captor + private ArgumentCaptor assignQuestCaptor; + @DisplayName("할당 퀘스트를 생성한다.") @Test void create_assign_quest() { AssignQuest assignQuest = AssignQuestFixture.create(); ParticipantDto participantDto = ParticipantDto.of(UUID.randomUUID(), 5, 5, 5); - doReturn(participantDto).when(readParticipantPort).find(any()); - doReturn(assignQuest).when(assignQuestService).create(any(), any()); + doReturn(participantDto).when(participantReader).read(any()); doReturn(4L).when(assignQuestRepository).countParticipatingQuestByQuestType(any(), any(), any(), any()); + doReturn(4).when(assignQuestRepository).findMaxDisplayOrderOfParticipatingQuest(any(), any(), any(), any()); + doReturn(assignQuest).when(assignQuestRepository).save(any()); UUID actual = sut.create(CreateAssignQuestCommand.of(UUID.randomUUID(), UUID.randomUUID(), "subject name", QuestType.DAILY.name(), "quest content")); @@ -55,9 +57,26 @@ void create_assign_quest() { @Test void check_quest_quota() { ParticipantDto participantDto = ParticipantDto.of(UUID.randomUUID(), 5, 5, 5); - doReturn(participantDto).when(readParticipantPort).find(any()); + doReturn(participantDto).when(participantReader).read(any()); doReturn(5L).when(assignQuestRepository).countParticipatingQuestByQuestType(any(), any(), any(), any()); assertThatThrownBy(() -> sut.create(CreateAssignQuestCommand.of(UUID.randomUUID(), UUID.randomUUID(), "subject name", QuestType.DAILY.name(), "quest content"))); } + + @DisplayName("새로 생성된 할당 퀘스트의 정렬 순서는 현재 참여중인 퀘스트의 마지막 번호 + 1이다.") + @Test + void create_assign_quest_with_display_order() { + int maxDisplayOrder = 4; + ParticipantDto participantDto = new ParticipantDto(UUID.randomUUID(), 5, 5, 5); + doReturn(participantDto).when(participantReader).read(any()); + doReturn((long)maxDisplayOrder).when(assignQuestRepository).countParticipatingQuestByQuestType(any(), any(), any(), any()); + doReturn(maxDisplayOrder).when(assignQuestRepository).findMaxDisplayOrderOfParticipatingQuest(any(), any(), any(), any()); + doReturn(AssignQuestFixture.create()).when(assignQuestRepository).save(any()); + + sut.create(new CreateAssignQuestCommand(UUID.randomUUID(), UUID.randomUUID(), "subject name", QuestType.DAILY.name(), "quest content")); + + verify(assignQuestRepository).save(assignQuestCaptor.capture()); + AssignQuest actual = assignQuestCaptor.getValue(); + assertThat(actual.getDisplayOrder().getDisplayOrder()).isEqualTo(maxDisplayOrder + 1); + } } diff --git a/src/test/java/com/gomo/app/core/quest/application/usecase/ReRollAssignQuestUseCaseTest.java b/src/test/java/com/gomo/app/core/quest/application/service/AssignQuestReRollServiceTest.java similarity index 78% rename from src/test/java/com/gomo/app/core/quest/application/usecase/ReRollAssignQuestUseCaseTest.java rename to src/test/java/com/gomo/app/core/quest/application/service/AssignQuestReRollServiceTest.java index 4e8833d5..8cbe1bc3 100644 --- a/src/test/java/com/gomo/app/core/quest/application/usecase/ReRollAssignQuestUseCaseTest.java +++ b/src/test/java/com/gomo/app/core/quest/application/service/AssignQuestReRollServiceTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.application.usecase; +package com.gomo.app.core.quest.application.service; import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; @@ -13,24 +13,23 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import com.gomo.app.core.quest.application.port.dto.AssignQuestDto; +import com.gomo.app.core.quest.application.port.dto.AssignQuestDetailDto; +import com.gomo.app.core.quest.domain.exception.QuestPoolNotFoundException; import com.gomo.app.core.quest.domain.model.assign.AssignQuest; import com.gomo.app.core.quest.domain.model.pool.QuestPool; import com.gomo.app.core.quest.domain.model.reward.QuestReward; import com.gomo.app.core.quest.domain.repository.QuestPoolRepository; -import com.gomo.app.core.quest.domain.service.AssignQuestService; -import com.gomo.app.core.quest.domain.service.QuestRewardService; -import com.gomo.app.core.quest.exception.QuestPoolNotFoundException; +import com.gomo.app.core.quest.domain.service.QuestRewardProvider; import com.gomo.app.core.quest.fixture.AssignQuestFixture; import com.gomo.app.core.quest.fixture.QuestPoolFixture; import com.gomo.app.core.quest.fixture.QuestRewardFixture; @DisplayName("[Application unit]: 퀘스트 재생성(리롤) 테스트") @ExtendWith(MockitoExtension.class) -class ReRollAssignQuestUseCaseTest { +class AssignQuestReRollServiceTest { @InjectMocks - private ReRollAssignQuestUseCase sut; + private AssignQuestReRollService sut; @Mock private QuestPoolRepository questPoolRepository; @@ -39,7 +38,7 @@ class ReRollAssignQuestUseCaseTest { private AssignQuestService assignQuestService; @Mock - private QuestRewardService questRewardService; + private QuestRewardProvider questRewardProvider; @DisplayName("퀘스트를 재생성한다.") @Test @@ -47,11 +46,11 @@ void re_roll_assign_quest() { AssignQuest assignQuest = AssignQuestFixture.create(); QuestPool questPool = QuestPoolFixture.create(); QuestReward questReward = QuestRewardFixture.create(); - doReturn(assignQuest).when(assignQuestService).find(any()); + doReturn(assignQuest).when(assignQuestService).readById(any()); doReturn(Optional.of(questPool)).when(questPoolRepository).findFirstByQuestParticipantIdAndQuestTypeAndSourceTypeAndProcessingStatus(any(), any(), any(), any()); - doReturn(questReward).when(questRewardService).find(any()); + doReturn(questReward).when(questRewardProvider).provide(any()); - AssignQuestDto actual = sut.reRoll(assignQuest.participantId(), assignQuest.getId()); + AssignQuestDetailDto actual = sut.reRoll(assignQuest.participantId(), assignQuest.getId()); assertThat(actual.questType()).isEqualTo(assignQuest.questType().name()); assertThat(actual.content()).isEqualTo(questPool.getQuest().getContent().toString()); @@ -62,7 +61,7 @@ void re_roll_assign_quest() { @Test void re_roll_assign_quest_without_quest_pool() { AssignQuest removedAssignQuest = AssignQuestFixture.create(); - doReturn(removedAssignQuest).when(assignQuestService).find(any()); + doReturn(removedAssignQuest).when(assignQuestService).readById(any()); doReturn(Optional.empty()).when(questPoolRepository).findFirstByQuestParticipantIdAndQuestTypeAndSourceTypeAndProcessingStatus(any(), any(), any(), any()); assertThatThrownBy(() -> sut.reRoll(removedAssignQuest.participantId(), removedAssignQuest.getId())) diff --git a/src/test/java/com/gomo/app/core/quest/application/usecase/AutoCreateAssignQuestUseCaseTest.java b/src/test/java/com/gomo/app/core/quest/application/service/AssignQuestRoutineServiceTest.java similarity index 91% rename from src/test/java/com/gomo/app/core/quest/application/usecase/AutoCreateAssignQuestUseCaseTest.java rename to src/test/java/com/gomo/app/core/quest/application/service/AssignQuestRoutineServiceTest.java index 7a099866..4c0ec825 100644 --- a/src/test/java/com/gomo/app/core/quest/application/usecase/AutoCreateAssignQuestUseCaseTest.java +++ b/src/test/java/com/gomo/app/core/quest/application/service/AssignQuestRoutineServiceTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.application.usecase; +package com.gomo.app.core.quest.application.service; import static org.mockito.Mockito.*; @@ -23,10 +23,10 @@ @DisplayName("[Domain integration]: 참여 퀘스트 생성 스케줄링 기능 테스트") @ExtendWith(MockitoExtension.class) -public class AutoCreateAssignQuestUseCaseTest { +public class AssignQuestRoutineServiceTest { @InjectMocks - private AutoCreateAssignQuestUseCase sut; + private AssignQuestRoutineService sut; @Mock private RepeatQuestRepository repeatQuestRepository; diff --git a/src/test/java/com/gomo/app/core/quest/application/service/AssignQuestServiceTest.java b/src/test/java/com/gomo/app/core/quest/application/service/AssignQuestServiceTest.java new file mode 100644 index 00000000..77ccd21c --- /dev/null +++ b/src/test/java/com/gomo/app/core/quest/application/service/AssignQuestServiceTest.java @@ -0,0 +1,366 @@ +package com.gomo.app.core.quest.application.service; + +import static com.gomo.app.core.quest.domain.model.quest.QuestType.*; +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.common.displayorder.OrderChanger; +import com.gomo.app.common.displayorder.UpdatedOrderDto; +import com.gomo.app.core.quest.application.port.command.ListAssignQuestCommand; +import com.gomo.app.core.quest.application.port.command.OrderUpdateAssignQuestCommand; +import com.gomo.app.core.quest.application.port.command.UpdateAssignQuestCommand; +import com.gomo.app.core.quest.application.port.dto.AssignQuestDto; +import com.gomo.app.core.quest.application.port.dto.ListAssignQuestDetailDto; +import com.gomo.app.core.quest.domain.exception.AssignQuestAccessDeniedException; +import com.gomo.app.core.quest.domain.exception.AssignQuestConstraintViolationException; +import com.gomo.app.core.quest.domain.exception.AssignQuestNotFoundException; +import com.gomo.app.core.quest.domain.exception.QuestTypeConstraintViolationException; +import com.gomo.app.core.quest.domain.exception.code.AssignQuestErrorCode; +import com.gomo.app.core.quest.domain.exception.code.QuestTypeErrorCode; +import com.gomo.app.core.quest.domain.model.assign.AssignQuest; +import com.gomo.app.core.quest.domain.model.assign.CompletionProof; +import com.gomo.app.core.quest.domain.model.quest.QuestType; +import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; +import com.gomo.app.core.quest.domain.service.QuestRewardProvider; +import com.gomo.app.core.quest.fixture.AssignQuestFixture; +import com.gomo.app.core.quest.fixture.QuestRewardFixture; + +@DisplayName("[Application unit]: 할당 퀘스트 서비스 테스트") +@ExtendWith(MockitoExtension.class) +public class AssignQuestServiceTest { + + @InjectMocks + private AssignQuestService sut; + + @Mock + private AssignQuestRepository assignQuestRepository; + + @Mock + private QuestRewardProvider questRewardProvider; + + @Nested + @DisplayName("할당 퀘스트 목록 조회") + class ReadAssignQuest { + + @DisplayName("완료한 퀘스트의 한달 이력을 조회한다.") + @Test + void find_All_completed_quest_for_month() { + List calendars = List.of(AssignQuestFixture.create(DAILY), AssignQuestFixture.create(WEEKLY)); + UUID participantId = UUID.randomUUID(); + LocalDateTime start = LocalDateTime.of(2025, 2, 1, 0, 0); + LocalDateTime end = start.plusMonths(1).minusSeconds(1); + doReturn(calendars).when(assignQuestRepository).findByQuestParticipantIdAndCompletedDateTimeBetween( + eq(participantId), + eq(start), + eq(end) + ); + + List actual = sut.readAll(ListAssignQuestCommand.of(participantId, true, start, end)); + + assertThat(actual.size()).isEqualTo(2); + } + + @DisplayName("완료한 퀘스트의 하루 이력을 조회한다.") + @Test + void find_All_completed_quest_for_day() { + List calendars = List.of(AssignQuestFixture.create(DAILY), AssignQuestFixture.create(WEEKLY)); + UUID participantId = UUID.randomUUID(); + LocalDateTime start = LocalDateTime.of(2025, 2, 1, 0, 0); + LocalDateTime end = start.plusDays(1).minusSeconds(1); + doReturn(calendars).when(assignQuestRepository).findByQuestParticipantIdAndCompletedDateTimeBetween( + eq(participantId), + eq(start), + eq(end) + ); + + List actual = sut.readAll(ListAssignQuestCommand.of(participantId, true, start, end)); + + assertThat(actual.size()).isEqualTo(2); + } + + @DisplayName("완료하지 못한 퀘스트의 한달 이력을 조회한다.") + @Test + void find_All_not_completed_quest_for_month() { + List calendars = List.of(AssignQuestFixture.create(DAILY), AssignQuestFixture.create(WEEKLY)); + UUID participantId = UUID.randomUUID(); + LocalDateTime start = LocalDateTime.of(2025, 2, 1, 0, 0); + LocalDateTime end = start.plusMonths(1).minusSeconds(1); + doReturn(calendars).when(assignQuestRepository).findByQuestParticipantIdAndStartDateTimeBetweenAndIsCompletedFalse( + eq(participantId), + eq(start), + eq(end) + ); + + List actual = sut.readAll(ListAssignQuestCommand.of(participantId, false, start, end)); + + assertThat(actual.size()).isEqualTo(2); + } + + @DisplayName("완료하지 못한 퀘스트의 하루 이력을 조회한다.") + @Test + void find_All_not_completed_quest_for_day() { + List calendars = List.of(AssignQuestFixture.create(DAILY), AssignQuestFixture.create(WEEKLY)); + UUID participantId = UUID.randomUUID(); + LocalDateTime start = LocalDateTime.of(2025, 2, 1, 0, 0); + LocalDateTime end = start.plusDays(1).minusSeconds(1); + doReturn(calendars).when(assignQuestRepository).findByQuestParticipantIdAndStartDateTimeBetweenAndIsCompletedFalse( + eq(participantId), + eq(start), + eq(end) + ); + + List actual = sut.readAll(ListAssignQuestCommand.of(participantId, false, start, end)); + + assertThat(actual.size()).isEqualTo(2); + } + } + + @Nested + @DisplayName("할당 퀘스트 상세 목록 조회") + class ReadAssignQuestDetail { + + @DisplayName("현재 참여중인 목록을 조회한다.") + @Test + void find_All() { + List dailyQuests = List.of(AssignQuestFixture.create(QuestType.DAILY), AssignQuestFixture.create(QuestType.DAILY)); + List weeklyQuests = List.of(AssignQuestFixture.create(QuestType.WEEKLY)); + List monthlyQuests = List.of(); + doReturn(QuestRewardFixture.create(1, 10)).when(questRewardProvider).provide(eq(QuestType.DAILY)); + doReturn(QuestRewardFixture.create(2, 20)).when(questRewardProvider).provide(eq(QuestType.WEEKLY)); + doReturn(dailyQuests).when(assignQuestRepository).findParticipatingQuestByQuestType(any(), eq(QuestType.DAILY), any(), any()); + doReturn(weeklyQuests).when(assignQuestRepository).findParticipatingQuestByQuestType(any(), eq(QuestType.WEEKLY), any(), any()); + doReturn(monthlyQuests).when(assignQuestRepository).findParticipatingQuestByQuestType(any(), eq(QuestType.MONTHLY), any(), any()); + + ListAssignQuestDetailDto actual = sut.readAll(UUID.randomUUID()); + + assertThat(actual.dailyQuests().size()).isEqualTo(2); + assertThat(actual.dailyQuests()).extracting("score").containsExactly(1, 1); + assertThat(actual.dailyQuests()).extracting("point").containsExactly(10, 10); + assertThat(actual.weeklyQuests().size()).isEqualTo(1); + assertThat(actual.weeklyQuests()).extracting("score").containsExactly(2); + assertThat(actual.weeklyQuests()).extracting("point").containsExactly(20); + assertThat(actual.monthlyQuests().size()).isEqualTo(0); + } + } + + @Nested + @DisplayName("할당 퀘스트 엔티티 조회") + class ReadAssignQuestEntity { + + @DisplayName("할당 퀘스트를 조회한다.") + @Test + void find_assign_quest() { + AssignQuest assignQuest = AssignQuestFixture.create(); + doReturn(Optional.of(assignQuest)).when(assignQuestRepository).findById(any()); + + AssignQuest actual = sut.readById(assignQuest.getId()); + + assertThat(actual).isEqualTo(assignQuest); + } + + @DisplayName("존재하지 않는 할당 퀘스트를 조회한다.") + @Test + void find_nonexistent_assign_quest() { + doReturn(Optional.empty()).when(assignQuestRepository).findById(any()); + + assertThatThrownBy(() -> sut.readById(UUID.randomUUID())) + .isInstanceOf(AssignQuestNotFoundException.class) + .hasMessageContaining(AssignQuestErrorCode.NOT_FOUND.getMessage()); + } + } + + @Nested + @DisplayName("할당 퀘스트 수정") + class UpdateAssignQuest { + + @DisplayName("할당 퀘스트를 수정한다.") + @Test + void update_assign_quest() { + AssignQuest assignQuest = AssignQuestFixture.create(QuestType.DAILY); + doReturn(Optional.of(assignQuest)).when(assignQuestRepository).findById(any()); + + sut.update(getUpdateAssignQuestCommand(assignQuest.getQuest().getParticipantId(), QuestType.DAILY.name())); + + assertThat(assignQuest.getQuest().getSubjectName().toString()).isEqualTo("updated subject name"); + } + + @DisplayName("퀘스트 참여자가 아니면 할당 퀘스트를 수정할 수 없다.") + @Test + void update_assign_quest_with_not_participant() { + AssignQuest assignQuest = AssignQuestFixture.create(QuestType.DAILY); + doReturn(Optional.of(assignQuest)).when(assignQuestRepository).findById(any()); + + assertThatThrownBy(() -> sut.update(getUpdateAssignQuestCommand(UUID.randomUUID(), QuestType.WEEKLY.name()))) + .isInstanceOf(AssignQuestAccessDeniedException.class) + .hasMessageContaining("Access denied for the assign quest"); + } + + @DisplayName("할당 퀘스트를 다른 퀘스트 타입으로 수정할 수 없다.") + @Test + void update_assign_quest_with_different_type() { + AssignQuest assignQuest = AssignQuestFixture.create(QuestType.DAILY); + doReturn(Optional.of(assignQuest)).when(assignQuestRepository).findById(any()); + + assertThatThrownBy(() -> sut.update(getUpdateAssignQuestCommand(assignQuest.getQuest().getParticipantId(), QuestType.WEEKLY.name()))) + .isInstanceOf(QuestTypeConstraintViolationException.class) + .hasMessageContaining(QuestTypeErrorCode.MISMATCHED.getMessage()); + } + + @DisplayName("이미 확정한 할당 퀘스트는 수정할 수 없다.") + @Test + void update_confirmed_assign_quest() { + AssignQuest assignQuest = AssignQuestFixture.create(true); + doReturn(Optional.of(assignQuest)).when(assignQuestRepository).findById(any()); + + assertThatThrownBy(() -> sut.update(getUpdateAssignQuestCommand(assignQuest.getQuest().getParticipantId(), QuestType.DAILY.name()))) + .isInstanceOf(AssignQuestConstraintViolationException.class) + .hasMessageContaining(AssignQuestErrorCode.ALREADY_CONFIRMED.getMessage()); + } + + @DisplayName("이미 완료한 할당 퀘스트는 수정할 수 없다.") + @Test + void update_completed_assign_quest() { + AssignQuest assignQuest = AssignQuestFixture.create(false, true, CompletionProof.createDefault()); + doReturn(Optional.of(assignQuest)).when(assignQuestRepository).findById(any()); + + assertThatThrownBy(() -> sut.update(getUpdateAssignQuestCommand(assignQuest.getQuest().getParticipantId(), QuestType.DAILY.name()))) + .isInstanceOf(AssignQuestConstraintViolationException.class) + .hasMessageContaining(AssignQuestErrorCode.ALREADY_COMPLETED.getMessage()); + } + + private static @NotNull UpdateAssignQuestCommand getUpdateAssignQuestCommand(UUID participantId, String questType) { + return UpdateAssignQuestCommand.of(participantId, UUID.randomUUID(), UUID.randomUUID(), "updated subject name", questType, "updated quest content"); + } + } + + @Nested + @DisplayName("할당 퀘스트 전시 순서 수정") + class UpdateAssignQuestOrder { + + @DisplayName("참여 중인 퀘스트의 전시 순서를 변경한다.") + @Test + void update_participating_quest_display_order() { + doReturn(getParticipatingQuests()).when(assignQuestRepository).findParticipatingQuestByQuestTypeWithoutCompleted(any(), any(), any(), any()); + + try (MockedStatic mockedOrderChanger = mockStatic(OrderChanger.class)) { + sut.update( + OrderUpdateAssignQuestCommand.of( + UUID.randomUUID(), + QuestType.DAILY.name(), + List.of( + UpdatedOrderDto.of(UUID.randomUUID(), 1), + UpdatedOrderDto.of(UUID.randomUUID(), 2), + UpdatedOrderDto.of(UUID.randomUUID(), 3) + ) + ) + ); + + verify(assignQuestRepository, times(1)).findParticipatingQuestByQuestTypeWithoutCompleted(any(), any(), any(), any()); + mockedOrderChanger.verify(() -> OrderChanger.change(any()), times(1)); + } + } + + private @NotNull List getParticipatingQuests() { + return List.of( + AssignQuestFixture.create(1), + AssignQuestFixture.create(2), + AssignQuestFixture.create(3) + ); + } + } + + @Nested + @DisplayName("할당 퀘스트 확정") + class ConfirmAssignQuest { + + @DisplayName("할당 퀘스트를 확정한다.") + @Test + void confirm_assign_quest() { + AssignQuest assignQuest = AssignQuestFixture.create(QuestType.DAILY); + doReturn(Optional.of(assignQuest)).when(assignQuestRepository).findById(any()); + + sut.confirm(assignQuest.getQuest().getParticipantId(), UUID.randomUUID()); + + assertThat(assignQuest.isConfirmed()).isTrue(); + } + + @DisplayName("퀘스트 참여자가 아니면 할당 퀘스트를 확정할 수 없다.") + @Test + void confirm_assign_quest_with_not_participant() { + AssignQuest assignQuest = AssignQuestFixture.create(QuestType.DAILY); + doReturn(Optional.of(assignQuest)).when(assignQuestRepository).findById(any()); + + assertThatThrownBy( + () -> sut.confirm(UUID.randomUUID(), UUID.randomUUID())) + .isInstanceOf(AssignQuestAccessDeniedException.class) + .hasMessageContaining(AssignQuestErrorCode.ACCESS_DENIED.getMessage()); + } + } + + @Nested + @DisplayName("할당 퀘스트 삭제") + class DeleteAssignQuest { + + @DisplayName("할당 퀘스트를 삭제한다.") + @Test + void delete_assign_quest() { + AssignQuest assignQuest = AssignQuestFixture.create(); + doReturn(Optional.of(assignQuest)).when(assignQuestRepository).findById(any()); + + sut.delete(assignQuest.getQuest().getParticipantId(), UUID.randomUUID()); + + verify(assignQuestRepository, times(1)).delete(any(AssignQuest.class)); + } + + @DisplayName("퀘스트 참여자가 아니면 할당 퀘스트를 삭제할 수 없다.") + @Test + void delete_assign_quest_by_not_participant() { + AssignQuest assignQuest = AssignQuestFixture.create(); + doReturn(Optional.of(assignQuest)).when(assignQuestRepository).findById(any()); + + assertThatThrownBy( + () -> sut.delete(UUID.randomUUID(), UUID.randomUUID())) + .isInstanceOf(AssignQuestAccessDeniedException.class) + .hasMessageContaining(AssignQuestErrorCode.ACCESS_DENIED.getMessage()); + } + + @DisplayName("이미 확정한 할당 퀘스트는 삭제할 수 없다.") + @Test + void delete_confirmed_assign_quest() { + AssignQuest assignQuest = AssignQuestFixture.create(true); + doReturn(Optional.of(assignQuest)).when(assignQuestRepository).findById(any()); + + assertThatThrownBy( + () -> sut.delete(assignQuest.getQuest().getParticipantId(), UUID.randomUUID())) + .isInstanceOf(AssignQuestConstraintViolationException.class) + .hasMessageContaining(AssignQuestErrorCode.ALREADY_CONFIRMED.getMessage()); + } + + @DisplayName("이미 완료한 할당 퀘스트는 삭제할 수 없다.") + @Test + void delete_completed_assign_quest() { + AssignQuest assignQuest = AssignQuestFixture.create(false, true, CompletionProof.createDefault()); + doReturn(Optional.of(assignQuest)).when(assignQuestRepository).findById(any()); + + assertThatThrownBy( + () -> sut.delete(assignQuest.getQuest().getParticipantId(), UUID.randomUUID())) + .isInstanceOf(AssignQuestConstraintViolationException.class) + .hasMessageContaining(AssignQuestErrorCode.ALREADY_COMPLETED.getMessage()); + } + } +} diff --git a/src/test/java/com/gomo/app/core/quest/application/usecase/CreateQuestPoolUseCaseTest.java b/src/test/java/com/gomo/app/core/quest/application/service/QuestPoolCreateServiceTest.java similarity index 89% rename from src/test/java/com/gomo/app/core/quest/application/usecase/CreateQuestPoolUseCaseTest.java rename to src/test/java/com/gomo/app/core/quest/application/service/QuestPoolCreateServiceTest.java index 5220b5e6..ed9473c1 100644 --- a/src/test/java/com/gomo/app/core/quest/application/usecase/CreateQuestPoolUseCaseTest.java +++ b/src/test/java/com/gomo/app/core/quest/application/service/QuestPoolCreateServiceTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.quest.application.usecase; +package com.gomo.app.core.quest.application.service; import static org.mockito.Mockito.*; @@ -12,20 +12,20 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import com.gomo.app.core.quest.application.port.CreateQuestContentPortOut; import com.gomo.app.core.quest.application.port.command.CreateQuestPoolCommand; import com.gomo.app.core.quest.application.port.dto.QuestContentDto; +import com.gomo.app.core.quest.application.port.out.QuestContentCreator; import com.gomo.app.core.quest.domain.repository.QuestPoolRepository; @DisplayName("[Application unit]: 퀘스트 풀 생성 테스트") @ExtendWith(MockitoExtension.class) -public class CreateQuestPoolUseCaseTest { +public class QuestPoolCreateServiceTest { @InjectMocks - private CreateQuestPoolUseCase sut; + private QuestPoolCreateService sut; @Mock - private CreateQuestContentPortOut createQuestContentPortOut; + private QuestContentCreator questContentCreator; @Mock private QuestPoolRepository questPoolRepository; @@ -39,7 +39,7 @@ void create_quest_pool() { QuestContentDto.of(UUID.randomUUID(), UUID.randomUUID(), "name3", "DAILY", "content3") ); doReturn(10L).when(questPoolRepository).countByQuestParticipantIdAndQuestTypeAndProcessingStatus(any(), any(), any()); - doReturn(questContents).when(createQuestContentPortOut).create(any()); + doReturn(questContents).when(questContentCreator).create(any()); CreateQuestPoolCommand createQuestPoolCommand = CreateQuestPoolCommand.of( UUID.randomUUID(), List.of( @@ -95,7 +95,7 @@ void already_over_quest_pools() { @Test void no_create_quest_pool_for_participant() { doReturn(10L).when(questPoolRepository).countByQuestParticipantIdAndQuestTypeAndProcessingStatus(any(), any(), any()); - doReturn(List.of()).when(createQuestContentPortOut).create(any()); + doReturn(List.of()).when(questContentCreator).create(any()); CreateQuestPoolCommand createQuestPoolCommand = CreateQuestPoolCommand.of( UUID.randomUUID(), List.of( diff --git a/src/test/java/com/gomo/app/core/quest/application/service/RepeatQuestCreateServiceTest.java b/src/test/java/com/gomo/app/core/quest/application/service/RepeatQuestCreateServiceTest.java new file mode 100644 index 00000000..8864ca2b --- /dev/null +++ b/src/test/java/com/gomo/app/core/quest/application/service/RepeatQuestCreateServiceTest.java @@ -0,0 +1,84 @@ +package com.gomo.app.core.quest.application.service; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.UUID; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.core.quest.application.port.command.CreateRepeatQuestCommand; +import com.gomo.app.core.quest.application.port.dto.ParticipantDto; +import com.gomo.app.core.quest.application.port.out.ParticipantReader; +import com.gomo.app.core.quest.domain.model.quest.QuestType; +import com.gomo.app.core.quest.domain.model.repeat.RepeatQuest; +import com.gomo.app.core.quest.domain.repository.RepeatQuestRepository; +import com.gomo.app.core.quest.fixture.RepeatQuestFixture; + +@DisplayName("[Application unit]: 반복 퀘스트 생성 테스트") +@ExtendWith(MockitoExtension.class) +public class RepeatQuestCreateServiceTest { + + @InjectMocks + private RepeatQuestCreateService sut; + + @Mock + private ParticipantReader participantReader; + + @Mock + private RepeatQuestRepository repeatQuestRepository; + + @Captor + private ArgumentCaptor repeatQuestCaptor; + + @DisplayName("반복 퀘스트를 생성한다.") + @Test + void create_repeat_quest() { + int maxDisplayOrder = 4; + RepeatQuest repeatQuest = RepeatQuestFixture.create(); + ParticipantDto participantDto = ParticipantDto.of(UUID.randomUUID(), 5, 5, 5); + doReturn(participantDto).when(participantReader).read(any()); + doReturn((long)maxDisplayOrder).when(repeatQuestRepository).countByQuestParticipantIdAndQuestType(any(), any()); + doReturn(maxDisplayOrder).when(repeatQuestRepository).findMaxDisplayOrderByQuestType(any(), any()); + doReturn(repeatQuest).when(repeatQuestRepository).save(any()); + + UUID actual = sut.create(CreateRepeatQuestCommand.of(UUID.randomUUID(), UUID.randomUUID(), "subject name", QuestType.DAILY.name(), "quest content")); + + assertThat(actual).isEqualTo(repeatQuest.getId()); + } + + @DisplayName("할당량을 초과하면 반복 퀘스트를 생성할 수 없다.") + @Test + void check_quest_quota() { + ParticipantDto participantDto = ParticipantDto.of(UUID.randomUUID(), 5, 5, 5); + doReturn(participantDto).when(participantReader).read(any()); + doReturn(5L).when(repeatQuestRepository).countByQuestParticipantIdAndQuestType(any(), any()); + + assertThatThrownBy(() -> sut.create(CreateRepeatQuestCommand.of(UUID.randomUUID(), UUID.randomUUID(), "subject name", QuestType.DAILY.name(), "quest content"))); + } + + @DisplayName("새로 생성된 반복 퀘스트의 정렬 순서는 현재 등록된 반복 퀘스트의 마지막 번호 + 1이다.") + @Test + void create_repeat_quest_with_display_order() { + int maxDisplayOrder = 4; + ParticipantDto participantDto = new ParticipantDto(UUID.randomUUID(), 5, 5, 5); + RepeatQuest savedQuest = RepeatQuest.of(UUID.randomUUID(), null, null); + doReturn(participantDto).when(participantReader).read(any()); + doReturn((long)maxDisplayOrder).when(repeatQuestRepository).countByQuestParticipantIdAndQuestType(any(), any()); + doReturn(maxDisplayOrder).when(repeatQuestRepository).findMaxDisplayOrderByQuestType(any(), any()); + doReturn(savedQuest).when(repeatQuestRepository).save(any()); + + sut.create(CreateRepeatQuestCommand.of(UUID.randomUUID(), UUID.randomUUID(), "subject name", QuestType.DAILY.name(), "quest content")); + + verify(repeatQuestRepository).save(repeatQuestCaptor.capture()); + RepeatQuest actual = repeatQuestCaptor.getValue(); + assertThat(actual.getDisplayOrder().getDisplayOrder()).isEqualTo(maxDisplayOrder + 1); + } +} diff --git a/src/test/java/com/gomo/app/core/quest/application/service/RepeatQuestServiceTest.java b/src/test/java/com/gomo/app/core/quest/application/service/RepeatQuestServiceTest.java new file mode 100644 index 00000000..389936e7 --- /dev/null +++ b/src/test/java/com/gomo/app/core/quest/application/service/RepeatQuestServiceTest.java @@ -0,0 +1,198 @@ +package com.gomo.app.core.quest.application.service; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.common.displayorder.OrderChanger; +import com.gomo.app.common.displayorder.UpdatedOrderDto; +import com.gomo.app.core.quest.application.port.command.OrderUpdateRepeatQuestCommand; +import com.gomo.app.core.quest.application.port.command.UpdateRepeatQuestCommand; +import com.gomo.app.core.quest.application.port.dto.ListRepeatQuestDto; +import com.gomo.app.core.quest.domain.exception.QuestTypeConstraintViolationException; +import com.gomo.app.core.quest.domain.exception.RepeatQuestAccessDeniedException; +import com.gomo.app.core.quest.domain.exception.RepeatQuestNotFoundException; +import com.gomo.app.core.quest.domain.exception.code.QuestTypeErrorCode; +import com.gomo.app.core.quest.domain.exception.code.RepeatQuestErrorCode; +import com.gomo.app.core.quest.domain.model.quest.QuestType; +import com.gomo.app.core.quest.domain.model.repeat.RepeatQuest; +import com.gomo.app.core.quest.domain.repository.RepeatQuestRepository; +import com.gomo.app.core.quest.domain.service.QuestRewardProvider; +import com.gomo.app.core.quest.fixture.QuestRewardFixture; +import com.gomo.app.core.quest.fixture.RepeatQuestFixture; + +@DisplayName("[Application unit]: 반복 퀘스트 서비스 테스트") +@ExtendWith(MockitoExtension.class) +public class RepeatQuestServiceTest { + + @InjectMocks + private RepeatQuestService sut; + + @Mock + private RepeatQuestRepository repeatQuestRepository; + + @Mock + private QuestRewardProvider questRewardProvider; + + @Nested + @DisplayName("반복 퀘스트 조회 테스트") + class ReadRepeatQuest { + + @DisplayName("반복 퀘스트 엔티티를 조회한다.") + @Test + void find_repeat_quest_entity() { + RepeatQuest repeatQuest = RepeatQuestFixture.create(); + doReturn(Optional.of(repeatQuest)).when(repeatQuestRepository).findById(any()); + + RepeatQuest actual = sut.readById(repeatQuest.getId()); + + assertThat(actual).isEqualTo(repeatQuest); + } + + @DisplayName("존재하지 않는 반복 퀘스트 엔티티를 조회한다.") + @Test + void find_repeat_quest_with_nonexistent_id() { + doReturn(Optional.empty()).when(repeatQuestRepository).findById(any()); + + assertThatThrownBy(() -> sut.readById(UUID.randomUUID())).isExactlyInstanceOf(RepeatQuestNotFoundException.class); + } + + @DisplayName("반복 퀘스트 목록을 조회한다.") + @Test + void find_All() { + List dailyQuests = List.of(RepeatQuestFixture.create(QuestType.DAILY), RepeatQuestFixture.create(QuestType.DAILY)); + List weeklyQuests = List.of(RepeatQuestFixture.create(QuestType.WEEKLY)); + List monthlyQuests = List.of(); + doReturn(QuestRewardFixture.create(1, 10)).when(questRewardProvider).provide(eq(QuestType.DAILY)); + doReturn(QuestRewardFixture.create(2, 20)).when(questRewardProvider).provide(eq(QuestType.WEEKLY)); + doReturn(dailyQuests).when(repeatQuestRepository).findRepeatQuestsByQuestType(any(), eq(QuestType.DAILY)); + doReturn(weeklyQuests).when(repeatQuestRepository).findRepeatQuestsByQuestType(any(), eq(QuestType.WEEKLY)); + doReturn(monthlyQuests).when(repeatQuestRepository).findRepeatQuestsByQuestType(any(), eq(QuestType.MONTHLY)); + + ListRepeatQuestDto actual = sut.readAll(UUID.randomUUID()); + + assertThat(actual.dailyQuests().size()).isEqualTo(2); + assertThat(actual.dailyQuests()).extracting("score").containsExactly(1, 1); + assertThat(actual.dailyQuests()).extracting("point").containsExactly(10, 10); + assertThat(actual.weeklyQuests().size()).isEqualTo(1); + assertThat(actual.weeklyQuests()).extracting("score").containsExactly(2); + assertThat(actual.weeklyQuests()).extracting("point").containsExactly(20); + assertThat(actual.monthlyQuests().size()).isEqualTo(0); + } + } + + @Nested + @DisplayName("반복 퀘스트 수정 테스트") + class UpdateRepeatQuest { + + @DisplayName("반복 퀘스트를 수정한다.") + @Test + void update_repeat_quest() { + RepeatQuest repeatQuest = RepeatQuestFixture.create(QuestType.DAILY); + doReturn(Optional.of(repeatQuest)).when(repeatQuestRepository).findById(any()); + sut.update(getUpdateRepeatQuestCommand(repeatQuest.getQuest().getParticipantId(), QuestType.DAILY.name())); + assertThat(repeatQuest.getQuest().getSubjectName().toString()).isEqualTo("updated subject name"); + } + + @DisplayName("퀘스트 참여자가 아니면 할당 퀘스트를 수정할 수 없다.") + @Test + void update_repeat_quest_with_not_participant() { + RepeatQuest repeatQuest = RepeatQuestFixture.create(QuestType.DAILY); + doReturn(Optional.of(repeatQuest)).when(repeatQuestRepository).findById(any()); + assertThatThrownBy(() -> sut.update(getUpdateRepeatQuestCommand(UUID.randomUUID(), QuestType.WEEKLY.name()))) + .isInstanceOf(RepeatQuestAccessDeniedException.class) + .hasMessageContaining(RepeatQuestErrorCode.ACCESS_DENIED.getMessage()); + } + + @DisplayName("반복 퀘스트를 다른 퀘스트 타입으로 수정할 수 없다.") + @Test + void update_repeat_quest_with_different_type() { + RepeatQuest repeatQuest = RepeatQuestFixture.create(QuestType.DAILY); + doReturn(Optional.of(repeatQuest)).when(repeatQuestRepository).findById(any()); + assertThatThrownBy(() -> sut.update(getUpdateRepeatQuestCommand(repeatQuest.getQuest().getParticipantId(), QuestType.WEEKLY.name()))) + .isInstanceOf(QuestTypeConstraintViolationException.class) + .hasMessageContaining(QuestTypeErrorCode.MISMATCHED.getMessage()); + } + + private static @NotNull UpdateRepeatQuestCommand getUpdateRepeatQuestCommand(UUID participantId, String questType) { + return UpdateRepeatQuestCommand.of(participantId, UUID.randomUUID(), UUID.randomUUID(), "updated subject name", questType, "updated quest content"); + } + } + + @Nested + @DisplayName("반복 퀘스트 전시 순서 변경 테스트") + class UpdateRepeatQuestOrder { + + @DisplayName("반복 퀘스트의 전시 순서를 변경한다.") + @Test + void update_repeat_quest_display_order() { + doReturn(getRepeatQuests()).when(repeatQuestRepository).findRepeatQuestsByQuestType(any(), any()); + + try (MockedStatic mockedOrderChanger = mockStatic(OrderChanger.class)) { + sut.update( + OrderUpdateRepeatQuestCommand.of( + UUID.randomUUID(), + QuestType.DAILY.name(), + List.of( + UpdatedOrderDto.of(UUID.randomUUID(), 1), + UpdatedOrderDto.of(UUID.randomUUID(), 2), + UpdatedOrderDto.of(UUID.randomUUID(), 3) + ) + ) + ); + + verify(repeatQuestRepository, times(1)).findRepeatQuestsByQuestType(any(), any()); + mockedOrderChanger.verify(() -> OrderChanger.change(any()), times(1)); + } + } + + private static @NotNull List getRepeatQuests() { + return List.of( + RepeatQuestFixture.create(1), + RepeatQuestFixture.create(2), + RepeatQuestFixture.create(3) + ); + } + } + + @Nested + @DisplayName("반복 퀘스트 삭제 테스트") + class DeleteRepeatQuest { + + @DisplayName("반복 퀘스트를 삭제한다.") + @Test + void delete_repeat_quest() { + RepeatQuest repeatQuest = RepeatQuestFixture.create(); + doReturn(Optional.of(repeatQuest)).when(repeatQuestRepository).findById(any()); + + sut.delete(repeatQuest.getQuest().getParticipantId(), UUID.randomUUID()); + + verify(repeatQuestRepository, times(1)).delete(any()); + } + + @DisplayName("퀘스트 참여자가 아니면 반복 퀘스트를 삭제할 수 없다.") + @Test + void delete_repeat_quest_by_not_participant() { + RepeatQuest repeatQuest = RepeatQuestFixture.create(); + doReturn(Optional.of(repeatQuest)).when(repeatQuestRepository).findById(any()); + + assertThatThrownBy( + () -> sut.delete(UUID.randomUUID(), UUID.randomUUID())) + .isInstanceOf(RepeatQuestAccessDeniedException.class) + .hasMessageContaining(RepeatQuestErrorCode.ACCESS_DENIED.getMessage()); + } + } +} diff --git a/src/test/java/com/gomo/app/core/quest/application/usecase/CalendarAssignQuestUseCaseTest.java b/src/test/java/com/gomo/app/core/quest/application/usecase/CalendarAssignQuestUseCaseTest.java deleted file mode 100644 index 38f3a5d5..00000000 --- a/src/test/java/com/gomo/app/core/quest/application/usecase/CalendarAssignQuestUseCaseTest.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.gomo.app.core.quest.application.usecase; - -import static com.gomo.app.core.quest.domain.model.quest.QuestType.*; -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.time.LocalDateTime; -import java.util.List; -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.quest.application.port.command.CalendarAssignQuestCommand; -import com.gomo.app.core.quest.application.port.dto.CalendarAssignQuestDto; -import com.gomo.app.core.quest.domain.model.assign.AssignQuest; -import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; -import com.gomo.app.core.quest.fixture.AssignQuestFixture; - -@DisplayName("[Application unit]: 할당 퀘스트 과거 이력 조회 테스트") -@ExtendWith(MockitoExtension.class) -public class CalendarAssignQuestUseCaseTest { - - @InjectMocks - private CalendarAssignQuestUseCase sut; - - @Mock - private AssignQuestRepository assignQuestRepository; - - @DisplayName("완료한 퀘스트의 한달 이력을 조회한다.") - @Test - void find_completed_quest_for_month() { - List calendars = List.of(AssignQuestFixture.create(DAILY), AssignQuestFixture.create(WEEKLY)); - UUID participantId = UUID.randomUUID(); - LocalDateTime start = LocalDateTime.of(2025, 2, 1, 0, 0); - LocalDateTime end = start.plusMonths(1).minusSeconds(1); - doReturn(calendars).when(assignQuestRepository).findByQuestParticipantIdAndCompletedDateTimeBetween( - eq(participantId), - eq(start), - eq(end) - ); - - List actual = sut.find(CalendarAssignQuestCommand.of(participantId, true, start, end)); - - assertThat(actual.size()).isEqualTo(2); - } - - @DisplayName("완료한 퀘스트의 하루 이력을 조회한다.") - @Test - void find_completed_quest_for_day() { - List calendars = List.of(AssignQuestFixture.create(DAILY), AssignQuestFixture.create(WEEKLY)); - UUID participantId = UUID.randomUUID(); - LocalDateTime start = LocalDateTime.of(2025, 2, 1, 0, 0); - LocalDateTime end = start.plusDays(1).minusSeconds(1); - doReturn(calendars).when(assignQuestRepository).findByQuestParticipantIdAndCompletedDateTimeBetween( - eq(participantId), - eq(start), - eq(end) - ); - - List actual = sut.find(CalendarAssignQuestCommand.of(participantId, true, start, end)); - - assertThat(actual.size()).isEqualTo(2); - } - - @DisplayName("완료하지 못한 퀘스트의 한달 이력을 조회한다.") - @Test - void find_not_completed_quest_for_month() { - List calendars = List.of(AssignQuestFixture.create(DAILY), AssignQuestFixture.create(WEEKLY)); - UUID participantId = UUID.randomUUID(); - LocalDateTime start = LocalDateTime.of(2025, 2, 1, 0, 0); - LocalDateTime end = start.plusMonths(1).minusSeconds(1); - doReturn(calendars).when(assignQuestRepository).findByQuestParticipantIdAndStartDateTimeBetweenAndIsCompletedFalse( - eq(participantId), - eq(start), - eq(end) - ); - - List actual = sut.find(CalendarAssignQuestCommand.of(participantId, false, start, end)); - - assertThat(actual.size()).isEqualTo(2); - } - - @DisplayName("완료하지 못한 퀘스트의 하루 이력을 조회한다.") - @Test - void find_not_completed_quest_for_day() { - List calendars = List.of(AssignQuestFixture.create(DAILY), AssignQuestFixture.create(WEEKLY)); - UUID participantId = UUID.randomUUID(); - LocalDateTime start = LocalDateTime.of(2025, 2, 1, 0, 0); - LocalDateTime end = start.plusDays(1).minusSeconds(1); - doReturn(calendars).when(assignQuestRepository).findByQuestParticipantIdAndStartDateTimeBetweenAndIsCompletedFalse( - eq(participantId), - eq(start), - eq(end) - ); - - List actual = sut.find(CalendarAssignQuestCommand.of(participantId, false, start, end)); - - assertThat(actual.size()).isEqualTo(2); - } -} diff --git a/src/test/java/com/gomo/app/core/quest/application/usecase/ConfirmAssignQuestUseCaseTest.java b/src/test/java/com/gomo/app/core/quest/application/usecase/ConfirmAssignQuestUseCaseTest.java deleted file mode 100644 index 91f4c614..00000000 --- a/src/test/java/com/gomo/app/core/quest/application/usecase/ConfirmAssignQuestUseCaseTest.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.gomo.app.core.quest.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.quest.domain.model.assign.AssignQuest; -import com.gomo.app.core.quest.domain.model.quest.QuestType; -import com.gomo.app.core.quest.domain.service.AssignQuestService; -import com.gomo.app.core.quest.exception.AssignQuestAccessDeniedException; -import com.gomo.app.core.quest.exception.code.AssignQuestErrorCode; -import com.gomo.app.core.quest.fixture.AssignQuestFixture; - -@DisplayName("[Application unit]: 할당 퀘스트 확정 테스트") -@ExtendWith(MockitoExtension.class) -public class ConfirmAssignQuestUseCaseTest { - - @InjectMocks - private ConfirmAssignQuestUseCase sut; - - @Mock - private AssignQuestService assignQuestService; - - @DisplayName("할당 퀘스트를 확정한다.") - @Test - void confirm_assign_quest() { - AssignQuest assignQuest = AssignQuestFixture.create(QuestType.DAILY); - doReturn(assignQuest).when(assignQuestService).find(any()); - - sut.confirm(assignQuest.getQuest().getParticipantId(), UUID.randomUUID()); - - assertThat(assignQuest.isConfirmed()).isTrue(); - } - - @DisplayName("퀘스트 참여자가 아니면 할당 퀘스트를 확정할 수 없다.") - @Test - void confirm_assign_quest_with_not_participant() { - AssignQuest assignQuest = AssignQuestFixture.create(QuestType.DAILY); - doReturn(assignQuest).when(assignQuestService).find(any()); - - assertThatThrownBy( - () -> sut.confirm(UUID.randomUUID(), UUID.randomUUID())) - .isInstanceOf(AssignQuestAccessDeniedException.class) - .hasMessageContaining(AssignQuestErrorCode.ACCESS_DENIED.getMessage()); - } -} diff --git a/src/test/java/com/gomo/app/core/quest/application/usecase/CreateRepeatQuestUseCaseTest.java b/src/test/java/com/gomo/app/core/quest/application/usecase/CreateRepeatQuestUseCaseTest.java deleted file mode 100644 index 262e8694..00000000 --- a/src/test/java/com/gomo/app/core/quest/application/usecase/CreateRepeatQuestUseCaseTest.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.gomo.app.core.quest.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.quest.application.port.ReadParticipantPortOut; -import com.gomo.app.core.quest.application.port.command.CreateRepeatQuestCommand; -import com.gomo.app.core.quest.application.port.dto.ParticipantDto; -import com.gomo.app.core.quest.domain.model.quest.QuestType; -import com.gomo.app.core.quest.domain.model.repeat.RepeatQuest; -import com.gomo.app.core.quest.domain.repository.RepeatQuestRepository; -import com.gomo.app.core.quest.domain.service.RepeatQuestService; -import com.gomo.app.core.quest.fixture.RepeatQuestFixture; - -@DisplayName("[Application unit]: 반복 퀘스트 생성 테스트") -@ExtendWith(MockitoExtension.class) -public class CreateRepeatQuestUseCaseTest { - - @InjectMocks - private CreateRepeatQuestUseCase sut; - - @Mock - private ReadParticipantPortOut readParticipantPort; - - @Mock - private RepeatQuestService repeatQuestService; - - @Mock - private RepeatQuestRepository repeatQuestRepository; - - @DisplayName("반복 퀘스트를 생성한다.") - @Test - void create_repeat_quest() { - RepeatQuest repeatQuest = RepeatQuestFixture.create(); - ParticipantDto participantDto = ParticipantDto.of(UUID.randomUUID(), 5, 5, 5); - doReturn(participantDto).when(readParticipantPort).find(any()); - doReturn(repeatQuest).when(repeatQuestService).create(any(), any()); - doReturn(4L).when(repeatQuestRepository).countByQuestParticipantIdAndQuestType(any(), any()); - - UUID actual = sut.create(CreateRepeatQuestCommand.of(UUID.randomUUID(), UUID.randomUUID(), "subject name", QuestType.DAILY.name(), "quest content")); - - assertThat(actual).isEqualTo(repeatQuest.getId()); - } - - @DisplayName("할당량을 초과하면 반복 퀘스트를 생성할 수 없다.") - @Test - void check_quest_quota() { - ParticipantDto participantDto = ParticipantDto.of(UUID.randomUUID(), 5, 5, 5); - doReturn(participantDto).when(readParticipantPort).find(any()); - doReturn(5L).when(repeatQuestRepository).countByQuestParticipantIdAndQuestType(any(), any()); - - assertThatThrownBy(() -> sut.create(CreateRepeatQuestCommand.of(UUID.randomUUID(), UUID.randomUUID(), "subject name", QuestType.DAILY.name(), "quest content"))); - } -} diff --git a/src/test/java/com/gomo/app/core/quest/application/usecase/DeleteAssignQuestUseCaseTest.java b/src/test/java/com/gomo/app/core/quest/application/usecase/DeleteAssignQuestUseCaseTest.java deleted file mode 100644 index 98f17473..00000000 --- a/src/test/java/com/gomo/app/core/quest/application/usecase/DeleteAssignQuestUseCaseTest.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.gomo.app.core.quest.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.quest.domain.model.assign.AssignQuest; -import com.gomo.app.core.quest.domain.model.assign.CompletionProof; -import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; -import com.gomo.app.core.quest.domain.service.AssignQuestService; -import com.gomo.app.core.quest.exception.AssignQuestAccessDeniedException; -import com.gomo.app.core.quest.exception.AssignQuestConstraintViolationException; -import com.gomo.app.core.quest.exception.code.AssignQuestErrorCode; -import com.gomo.app.core.quest.fixture.AssignQuestFixture; - -@DisplayName("[Application unit]: 할당 퀘스트 삭제 테스트") -@ExtendWith(MockitoExtension.class) -public class DeleteAssignQuestUseCaseTest { - - @InjectMocks - private DeleteAssignQuestUseCase sut; - - @Mock - private AssignQuestService assignQuestService; - - @Mock - private AssignQuestRepository assignQuestRepository; - - @DisplayName("할당 퀘스트를 삭제한다.") - @Test - void delete_assign_quest() { - AssignQuest assignQuest = AssignQuestFixture.create(); - doReturn(assignQuest).when(assignQuestService).find(any()); - - sut.delete(assignQuest.getQuest().getParticipantId(), UUID.randomUUID()); - - verify(assignQuestRepository, times(1)).delete(any(AssignQuest.class)); - } - - @DisplayName("퀘스트 참여자가 아니면 할당 퀘스트를 삭제할 수 없다.") - @Test - void delete_assign_quest_by_not_participant() { - AssignQuest assignQuest = AssignQuestFixture.create(); - doReturn(assignQuest).when(assignQuestService).find(any()); - - assertThatThrownBy( - () -> sut.delete(UUID.randomUUID(), UUID.randomUUID())) - .isInstanceOf(AssignQuestAccessDeniedException.class) - .hasMessageContaining(AssignQuestErrorCode.ACCESS_DENIED.getMessage()); - } - - @DisplayName("이미 확정한 할당 퀘스트는 삭제할 수 없다.") - @Test - void delete_confirmed_assign_quest() { - AssignQuest assignQuest = AssignQuestFixture.create(true); - doReturn(assignQuest).when(assignQuestService).find(any()); - - assertThatThrownBy( - () -> sut.delete(assignQuest.getQuest().getParticipantId(), UUID.randomUUID())) - .isInstanceOf(AssignQuestConstraintViolationException.class) - .hasMessageContaining(AssignQuestErrorCode.ALREADY_CONFIRMED.getMessage()); - } - - @DisplayName("이미 완료한 할당 퀘스트는 삭제할 수 없다.") - @Test - void delete_completed_assign_quest() { - AssignQuest assignQuest = AssignQuestFixture.create(false, true, CompletionProof.createDefault()); - doReturn(assignQuest).when(assignQuestService).find(any()); - - assertThatThrownBy( - () -> sut.delete(assignQuest.getQuest().getParticipantId(), UUID.randomUUID())) - .isInstanceOf(AssignQuestConstraintViolationException.class) - .hasMessageContaining(AssignQuestErrorCode.ALREADY_COMPLETED.getMessage()); - } -} diff --git a/src/test/java/com/gomo/app/core/quest/application/usecase/DeleteRepeatQuestUseCaseTest.java b/src/test/java/com/gomo/app/core/quest/application/usecase/DeleteRepeatQuestUseCaseTest.java deleted file mode 100644 index ade4f0ba..00000000 --- a/src/test/java/com/gomo/app/core/quest/application/usecase/DeleteRepeatQuestUseCaseTest.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.gomo.app.core.quest.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.quest.domain.model.repeat.RepeatQuest; -import com.gomo.app.core.quest.domain.repository.RepeatQuestRepository; -import com.gomo.app.core.quest.domain.service.RepeatQuestService; -import com.gomo.app.core.quest.exception.RepeatQuestAccessDeniedException; -import com.gomo.app.core.quest.exception.code.RepeatQuestErrorCode; -import com.gomo.app.core.quest.fixture.RepeatQuestFixture; - -@DisplayName("[Application unit]: 반복 퀘스트 삭제 테스트") -@ExtendWith(MockitoExtension.class) -public class DeleteRepeatQuestUseCaseTest { - - @InjectMocks - private DeleteRepeatQuestUseCase sut; - - @Mock - private RepeatQuestService repeatQuestService; - - @Mock - private RepeatQuestRepository repeatQuestRepository; - - @DisplayName("반복 퀘스트를 삭제한다.") - @Test - void delete_repeat_quest() { - RepeatQuest repeatQuest = RepeatQuestFixture.create(); - doReturn(repeatQuest).when(repeatQuestService).find(any()); - - sut.delete(repeatQuest.getQuest().getParticipantId(), UUID.randomUUID()); - - verify(repeatQuestRepository, times(1)).delete(any()); - } - - @DisplayName("퀘스트 참여자가 아니면 반복 퀘스트를 삭제할 수 없다.") - @Test - void delete_repeat_quest_by_not_participant() { - RepeatQuest repeatQuest = RepeatQuestFixture.create(); - doReturn(repeatQuest).when(repeatQuestService).find(any()); - - assertThatThrownBy( - () -> sut.delete(UUID.randomUUID(), UUID.randomUUID())) - .isInstanceOf(RepeatQuestAccessDeniedException.class) - .hasMessageContaining(RepeatQuestErrorCode.ACCESS_DENIED.getMessage()); - } -} diff --git a/src/test/java/com/gomo/app/core/quest/application/usecase/OrderUpdateAssignQuestUseCaseTest.java b/src/test/java/com/gomo/app/core/quest/application/usecase/OrderUpdateAssignQuestUseCaseTest.java deleted file mode 100644 index 5d7bcc5c..00000000 --- a/src/test/java/com/gomo/app/core/quest/application/usecase/OrderUpdateAssignQuestUseCaseTest.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.gomo.app.core.quest.application.usecase; - -import static org.mockito.Mockito.*; - -import java.util.List; -import java.util.UUID; - -import org.jetbrains.annotations.NotNull; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockedStatic; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.common.displayorder.OrderChanger; -import com.gomo.app.common.displayorder.UpdatedOrderDto; -import com.gomo.app.core.quest.application.port.command.OrderUpdateAssignQuestCommand; -import com.gomo.app.core.quest.domain.model.assign.AssignQuest; -import com.gomo.app.core.quest.domain.model.quest.QuestType; -import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; -import com.gomo.app.core.quest.fixture.AssignQuestFixture; - -@DisplayName("[Application unit]: 참여 중인 퀘스트 정렬 순서 변경 테스트") -@ExtendWith(MockitoExtension.class) -public class OrderUpdateAssignQuestUseCaseTest { - - @InjectMocks - private OrderUpdateAssignQuestUseCase sut; - - @Mock - private AssignQuestRepository assignQuestRepository; - - @DisplayName("참여 중인 퀘스트의 정렬 순서를 변경한다.") - @Test - void update_participating_quest_display_order() { - doReturn(getParticipatingQuests()).when(assignQuestRepository).findParticipatingQuestByQuestTypeWithoutCompleted(any(), any(), any(), any()); - - try (MockedStatic mockedOrderChanger = mockStatic(OrderChanger.class)) { - sut.update( - OrderUpdateAssignQuestCommand.of( - UUID.randomUUID(), - QuestType.DAILY.name(), - List.of( - UpdatedOrderDto.of(UUID.randomUUID(), 1), - UpdatedOrderDto.of(UUID.randomUUID(), 2), - UpdatedOrderDto.of(UUID.randomUUID(), 3) - ) - ) - ); - - verify(assignQuestRepository, times(1)).findParticipatingQuestByQuestTypeWithoutCompleted(any(), any(), any(), any()); - mockedOrderChanger.verify(() -> OrderChanger.change(any()), times(1)); - } - } - - private @NotNull List getParticipatingQuests() { - return List.of( - AssignQuestFixture.create(1), - AssignQuestFixture.create(2), - AssignQuestFixture.create(3) - ); - } -} diff --git a/src/test/java/com/gomo/app/core/quest/application/usecase/OrderUpdateRepeatQuestUseCaseTest.java b/src/test/java/com/gomo/app/core/quest/application/usecase/OrderUpdateRepeatQuestUseCaseTest.java deleted file mode 100644 index 36243180..00000000 --- a/src/test/java/com/gomo/app/core/quest/application/usecase/OrderUpdateRepeatQuestUseCaseTest.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.gomo.app.core.quest.application.usecase; - -import static org.mockito.Mockito.*; - -import java.util.List; -import java.util.UUID; - -import org.jetbrains.annotations.NotNull; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockedStatic; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.common.displayorder.OrderChanger; -import com.gomo.app.common.displayorder.UpdatedOrderDto; -import com.gomo.app.core.quest.application.port.command.OrderUpdateRepeatQuestCommand; -import com.gomo.app.core.quest.domain.model.quest.QuestType; -import com.gomo.app.core.quest.domain.model.repeat.RepeatQuest; -import com.gomo.app.core.quest.domain.repository.RepeatQuestRepository; -import com.gomo.app.core.quest.fixture.RepeatQuestFixture; - -@DisplayName("[Application unit]: 반복 퀘스트 정렬 순서 변경 테스트") -@ExtendWith(MockitoExtension.class) -public class OrderUpdateRepeatQuestUseCaseTest { - - @InjectMocks - private OrderUpdateRepeatQuestUseCase sut; - - @Mock - private RepeatQuestRepository repeatQuestRepository; - - @DisplayName("반복 퀘스트의 정렬 순서를 변경한다.") - @Test - void update_repeat_quest_display_order() { - doReturn(getRepeatQuests()).when(repeatQuestRepository).findRepeatQuestsByQuestType(any(), any()); - - try (MockedStatic mockedOrderChanger = mockStatic(OrderChanger.class)) { - sut.update( - OrderUpdateRepeatQuestCommand.of( - UUID.randomUUID(), - QuestType.DAILY.name(), - List.of( - UpdatedOrderDto.of(UUID.randomUUID(), 1), - UpdatedOrderDto.of(UUID.randomUUID(), 2), - UpdatedOrderDto.of(UUID.randomUUID(), 3) - ) - ) - ); - - verify(repeatQuestRepository, times(1)).findRepeatQuestsByQuestType(any(), any()); - mockedOrderChanger.verify(() -> OrderChanger.change(any()), times(1)); - } - } - - private static @NotNull List getRepeatQuests() { - return List.of( - RepeatQuestFixture.create(1), - RepeatQuestFixture.create(2), - RepeatQuestFixture.create(3) - ); - } -} diff --git a/src/test/java/com/gomo/app/core/quest/application/usecase/ReadAssignQuestUseCaseTest.java b/src/test/java/com/gomo/app/core/quest/application/usecase/ReadAssignQuestUseCaseTest.java deleted file mode 100644 index efad79f1..00000000 --- a/src/test/java/com/gomo/app/core/quest/application/usecase/ReadAssignQuestUseCaseTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.gomo.app.core.quest.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.List; -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.quest.application.port.dto.ListAssignQuestDto; -import com.gomo.app.core.quest.domain.model.assign.AssignQuest; -import com.gomo.app.core.quest.domain.model.quest.QuestType; -import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; -import com.gomo.app.core.quest.domain.service.QuestRewardService; -import com.gomo.app.core.quest.fixture.AssignQuestFixture; -import com.gomo.app.core.quest.fixture.QuestRewardFixture; - -@DisplayName("[Application unit]: 현재 참여중인 퀘스트 조회 테스트") -@ExtendWith(MockitoExtension.class) -public class ReadAssignQuestUseCaseTest { - - @InjectMocks - private ReadAssignQuestUseCase sut; - - @Mock - private AssignQuestRepository assignQuestRepository; - - @Mock - private QuestRewardService questRewardService; - - @DisplayName("현재 참여중인 목록을 조회한다.") - @Test - void find_All() { - List dailyQuests = List.of(AssignQuestFixture.create(QuestType.DAILY), AssignQuestFixture.create(QuestType.DAILY)); - List weeklyQuests = List.of(AssignQuestFixture.create(QuestType.WEEKLY)); - List monthlyQuests = List.of(); - doReturn(QuestRewardFixture.create(1, 10)).when(questRewardService).find(eq(QuestType.DAILY)); - doReturn(QuestRewardFixture.create(2, 20)).when(questRewardService).find(eq(QuestType.WEEKLY)); - doReturn(dailyQuests).when(assignQuestRepository).findParticipatingQuestByQuestType(any(), eq(QuestType.DAILY), any(), any()); - doReturn(weeklyQuests).when(assignQuestRepository).findParticipatingQuestByQuestType(any(), eq(QuestType.WEEKLY), any(), any()); - doReturn(monthlyQuests).when(assignQuestRepository).findParticipatingQuestByQuestType(any(), eq(QuestType.MONTHLY), any(), any()); - - ListAssignQuestDto actual = sut.findAll(UUID.randomUUID()); - - assertThat(actual.dailyQuests().size()).isEqualTo(2); - assertThat(actual.dailyQuests()).extracting("score").containsExactly(1, 1); - assertThat(actual.dailyQuests()).extracting("point").containsExactly(10, 10); - assertThat(actual.weeklyQuests().size()).isEqualTo(1); - assertThat(actual.weeklyQuests()).extracting("score").containsExactly(2); - assertThat(actual.weeklyQuests()).extracting("point").containsExactly(20); - assertThat(actual.monthlyQuests().size()).isEqualTo(0); - } -} diff --git a/src/test/java/com/gomo/app/core/quest/application/usecase/ReadRepeatQuestUseCaseTest.java b/src/test/java/com/gomo/app/core/quest/application/usecase/ReadRepeatQuestUseCaseTest.java deleted file mode 100644 index e789554b..00000000 --- a/src/test/java/com/gomo/app/core/quest/application/usecase/ReadRepeatQuestUseCaseTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.gomo.app.core.quest.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.List; -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.quest.application.port.dto.ListRepeatQuestDto; -import com.gomo.app.core.quest.domain.model.quest.QuestType; -import com.gomo.app.core.quest.domain.model.repeat.RepeatQuest; -import com.gomo.app.core.quest.domain.repository.RepeatQuestRepository; -import com.gomo.app.core.quest.domain.service.QuestRewardService; -import com.gomo.app.core.quest.fixture.QuestRewardFixture; -import com.gomo.app.core.quest.fixture.RepeatQuestFixture; - -@DisplayName("[Application unit]: 반복 퀘스트 조회 테스트") -@ExtendWith(MockitoExtension.class) -public class ReadRepeatQuestUseCaseTest { - - @InjectMocks - private ReadRepeatQuestUseCase sut; - - @Mock - private RepeatQuestRepository repeatQuestRepository; - - @Mock - private QuestRewardService questRewardService; - - @DisplayName("반복 퀘스트 목록을 조회한다.") - @Test - void find_All() { - List dailyQuests = List.of(RepeatQuestFixture.create(QuestType.DAILY), RepeatQuestFixture.create(QuestType.DAILY)); - List weeklyQuests = List.of(RepeatQuestFixture.create(QuestType.WEEKLY)); - List monthlyQuests = List.of(); - doReturn(QuestRewardFixture.create(1, 10)).when(questRewardService).find(eq(QuestType.DAILY)); - doReturn(QuestRewardFixture.create(2, 20)).when(questRewardService).find(eq(QuestType.WEEKLY)); - doReturn(dailyQuests).when(repeatQuestRepository).findRepeatQuestsByQuestType(any(), eq(QuestType.DAILY)); - doReturn(weeklyQuests).when(repeatQuestRepository).findRepeatQuestsByQuestType(any(), eq(QuestType.WEEKLY)); - doReturn(monthlyQuests).when(repeatQuestRepository).findRepeatQuestsByQuestType(any(), eq(QuestType.MONTHLY)); - - ListRepeatQuestDto actual = sut.findAll(UUID.randomUUID()); - - assertThat(actual.dailyQuests().size()).isEqualTo(2); - assertThat(actual.dailyQuests()).extracting("score").containsExactly(1, 1); - assertThat(actual.dailyQuests()).extracting("point").containsExactly(10, 10); - assertThat(actual.weeklyQuests().size()).isEqualTo(1); - assertThat(actual.weeklyQuests()).extracting("score").containsExactly(2); - assertThat(actual.weeklyQuests()).extracting("point").containsExactly(20); - assertThat(actual.monthlyQuests().size()).isEqualTo(0); - } -} diff --git a/src/test/java/com/gomo/app/core/quest/application/usecase/UpdateAssignQuestUseCaseTest.java b/src/test/java/com/gomo/app/core/quest/application/usecase/UpdateAssignQuestUseCaseTest.java deleted file mode 100644 index ae3ea5ed..00000000 --- a/src/test/java/com/gomo/app/core/quest/application/usecase/UpdateAssignQuestUseCaseTest.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.gomo.app.core.quest.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.UUID; - -import org.jetbrains.annotations.NotNull; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.quest.application.port.command.UpdateAssignQuestCommand; -import com.gomo.app.core.quest.domain.model.assign.AssignQuest; -import com.gomo.app.core.quest.domain.model.assign.CompletionProof; -import com.gomo.app.core.quest.domain.model.quest.QuestType; -import com.gomo.app.core.quest.domain.service.AssignQuestService; -import com.gomo.app.core.quest.exception.AssignQuestAccessDeniedException; -import com.gomo.app.core.quest.exception.AssignQuestConstraintViolationException; -import com.gomo.app.core.quest.exception.QuestTypeConstraintViolationException; -import com.gomo.app.core.quest.exception.code.AssignQuestErrorCode; -import com.gomo.app.core.quest.exception.code.QuestTypeErrorCode; -import com.gomo.app.core.quest.fixture.AssignQuestFixture; - -@DisplayName("[Application unit]: 할당 퀘스트 수정 테스트") -@ExtendWith(MockitoExtension.class) -public class UpdateAssignQuestUseCaseTest { - - @InjectMocks - private UpdateAssignQuestUseCase sut; - - @Mock - private AssignQuestService assignQuestService; - - @DisplayName("할당 퀘스트를 수정한다.") - @Test - void update_assign_quest() { - AssignQuest assignQuest = AssignQuestFixture.create(QuestType.DAILY); - doReturn(assignQuest).when(assignQuestService).find(any()); - sut.update(getUpdateAssignQuestCommand(assignQuest.getQuest().getParticipantId(), QuestType.DAILY.name())); - assertThat(assignQuest.getQuest().getSubjectName().toString()).isEqualTo("updated subject name"); - } - - @DisplayName("퀘스트 참여자가 아니면 할당 퀘스트를 수정할 수 없다.") - @Test - void update_assign_quest_with_not_participant() { - AssignQuest assignQuest = AssignQuestFixture.create(QuestType.DAILY); - doReturn(assignQuest).when(assignQuestService).find(any()); - - assertThatThrownBy(() -> sut.update(getUpdateAssignQuestCommand(UUID.randomUUID(), QuestType.WEEKLY.name()))) - .isInstanceOf(AssignQuestAccessDeniedException.class) - .hasMessageContaining("Access denied for the assign quest"); - } - - @DisplayName("할당 퀘스트를 다른 퀘스트 타입으로 수정할 수 없다.") - @Test - void update_assign_quest_with_different_type() { - AssignQuest assignQuest = AssignQuestFixture.create(QuestType.DAILY); - doReturn(assignQuest).when(assignQuestService).find(any()); - - assertThatThrownBy(() -> sut.update(getUpdateAssignQuestCommand(assignQuest.getQuest().getParticipantId(), QuestType.WEEKLY.name()))) - .isInstanceOf(QuestTypeConstraintViolationException.class) - .hasMessageContaining(QuestTypeErrorCode.MISMATCHED.getMessage()); - } - - @DisplayName("이미 확정한 할당 퀘스트는 수정할 수 없다.") - @Test - void update_confirmed_assign_quest() { - AssignQuest assignQuest = AssignQuestFixture.create(true); - doReturn(assignQuest).when(assignQuestService).find(any()); - - assertThatThrownBy(() -> sut.update(getUpdateAssignQuestCommand(assignQuest.getQuest().getParticipantId(), QuestType.DAILY.name()))) - .isInstanceOf(AssignQuestConstraintViolationException.class) - .hasMessageContaining(AssignQuestErrorCode.ALREADY_CONFIRMED.getMessage()); - } - - @DisplayName("이미 완료한 할당 퀘스트는 수정할 수 없다.") - @Test - void update_completed_assign_quest() { - AssignQuest assignQuest = AssignQuestFixture.create(false, true, CompletionProof.createDefault()); - doReturn(assignQuest).when(assignQuestService).find(any()); - - assertThatThrownBy(() -> sut.update(getUpdateAssignQuestCommand(assignQuest.getQuest().getParticipantId(), QuestType.DAILY.name()))) - .isInstanceOf(AssignQuestConstraintViolationException.class) - .hasMessageContaining(AssignQuestErrorCode.ALREADY_COMPLETED.getMessage()); - } - - private static @NotNull UpdateAssignQuestCommand getUpdateAssignQuestCommand(UUID participantId, String questType) { - return UpdateAssignQuestCommand.of(participantId, UUID.randomUUID(), UUID.randomUUID(), "updated subject name", questType, "updated quest content"); - } -} diff --git a/src/test/java/com/gomo/app/core/quest/application/usecase/UpdateRepeatQuestUseCaseTest.java b/src/test/java/com/gomo/app/core/quest/application/usecase/UpdateRepeatQuestUseCaseTest.java deleted file mode 100644 index eebbc815..00000000 --- a/src/test/java/com/gomo/app/core/quest/application/usecase/UpdateRepeatQuestUseCaseTest.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.gomo.app.core.quest.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.UUID; - -import org.jetbrains.annotations.NotNull; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.quest.application.port.command.UpdateRepeatQuestCommand; -import com.gomo.app.core.quest.domain.model.quest.QuestType; -import com.gomo.app.core.quest.domain.model.repeat.RepeatQuest; -import com.gomo.app.core.quest.domain.service.RepeatQuestService; -import com.gomo.app.core.quest.exception.QuestTypeConstraintViolationException; -import com.gomo.app.core.quest.exception.RepeatQuestAccessDeniedException; -import com.gomo.app.core.quest.exception.code.QuestTypeErrorCode; -import com.gomo.app.core.quest.exception.code.RepeatQuestErrorCode; -import com.gomo.app.core.quest.fixture.RepeatQuestFixture; - -@DisplayName("[Application unit]: 반복 퀘스트 수정 테스트") -@ExtendWith(MockitoExtension.class) -public class UpdateRepeatQuestUseCaseTest { - - @InjectMocks - private UpdateRepeatQuestUseCase sut; - - @Mock - private RepeatQuestService repeatQuestService; - - @DisplayName("반복 퀘스트를 수정한다.") - @Test - void update_repeat_quest() { - RepeatQuest repeatQuest = RepeatQuestFixture.create(QuestType.DAILY); - doReturn(repeatQuest).when(repeatQuestService).find(any()); - sut.update(getUpdateRepeatQuestCommand(repeatQuest.getQuest().getParticipantId(), QuestType.DAILY.name())); - assertThat(repeatQuest.getQuest().getSubjectName().toString()).isEqualTo("updated subject name"); - } - - @DisplayName("퀘스트 참여자가 아니면 할당 퀘스트를 수정할 수 없다.") - @Test - void update_repeat_quest_with_not_participant() { - RepeatQuest repeatQuest = RepeatQuestFixture.create(QuestType.DAILY); - doReturn(repeatQuest).when(repeatQuestService).find(any()); - assertThatThrownBy(() -> sut.update(getUpdateRepeatQuestCommand(UUID.randomUUID(), QuestType.WEEKLY.name()))) - .isInstanceOf(RepeatQuestAccessDeniedException.class) - .hasMessageContaining(RepeatQuestErrorCode.ACCESS_DENIED.getMessage()); - } - - @DisplayName("반복 퀘스트를 다른 퀘스트 타입으로 수정할 수 없다.") - @Test - void update_repeat_quest_with_different_type() { - RepeatQuest repeatQuest = RepeatQuestFixture.create(QuestType.DAILY); - doReturn(repeatQuest).when(repeatQuestService).find(any()); - assertThatThrownBy(() -> sut.update(getUpdateRepeatQuestCommand(repeatQuest.getQuest().getParticipantId(), QuestType.WEEKLY.name()))) - .isInstanceOf(QuestTypeConstraintViolationException.class) - .hasMessageContaining(QuestTypeErrorCode.MISMATCHED.getMessage()); - } - - private static @NotNull UpdateRepeatQuestCommand getUpdateRepeatQuestCommand(UUID participantId, String questType) { - return UpdateRepeatQuestCommand.of(participantId, UUID.randomUUID(), UUID.randomUUID(), "updated subject name", questType, "updated quest content"); - } -} diff --git a/src/test/java/com/gomo/app/core/quest/domain/model/assign/AssignQuestTest.java b/src/test/java/com/gomo/app/core/quest/domain/model/assign/AssignQuestTest.java index 86179054..103cd3d5 100644 --- a/src/test/java/com/gomo/app/core/quest/domain/model/assign/AssignQuestTest.java +++ b/src/test/java/com/gomo/app/core/quest/domain/model/assign/AssignQuestTest.java @@ -14,11 +14,11 @@ import com.gomo.app.core.quest.domain.model.quest.QuestContent; import com.gomo.app.core.quest.domain.model.quest.QuestType; import com.gomo.app.core.quest.domain.model.subject.SubjectName; -import com.gomo.app.core.quest.exception.AssignQuestAccessDeniedException; -import com.gomo.app.core.quest.exception.AssignQuestConstraintViolationException; -import com.gomo.app.core.quest.exception.QuestTypeConstraintViolationException; -import com.gomo.app.core.quest.exception.code.AssignQuestErrorCode; -import com.gomo.app.core.quest.exception.code.QuestTypeErrorCode; +import com.gomo.app.core.quest.domain.exception.AssignQuestAccessDeniedException; +import com.gomo.app.core.quest.domain.exception.AssignQuestConstraintViolationException; +import com.gomo.app.core.quest.domain.exception.QuestTypeConstraintViolationException; +import com.gomo.app.core.quest.domain.exception.code.AssignQuestErrorCode; +import com.gomo.app.core.quest.domain.exception.code.QuestTypeErrorCode; @DisplayName("[Domain unit]: 할당 퀘스트 생성 및 수정 테스트") public class AssignQuestTest { diff --git a/src/test/java/com/gomo/app/core/quest/domain/model/assign/CompletionProofTest.java b/src/test/java/com/gomo/app/core/quest/domain/model/assign/CompletionProofTest.java index 34723bdc..645ccd61 100644 --- a/src/test/java/com/gomo/app/core/quest/domain/model/assign/CompletionProofTest.java +++ b/src/test/java/com/gomo/app/core/quest/domain/model/assign/CompletionProofTest.java @@ -8,8 +8,8 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import com.gomo.app.core.quest.exception.CompletionProofConstraintViolationException; -import com.gomo.app.core.quest.exception.code.CompletionProofErrorCode; +import com.gomo.app.core.quest.domain.exception.CompletionProofConstraintViolationException; +import com.gomo.app.core.quest.domain.exception.code.CompletionProofErrorCode; @DisplayName("[Domain unit]: 퀘스트 증명 생성 및 수정 테스트") public class CompletionProofTest { diff --git a/src/test/java/com/gomo/app/core/quest/domain/model/participant/ParticipantTest.java b/src/test/java/com/gomo/app/core/quest/domain/model/participant/ParticipantTest.java index 2fcfaf79..d8242386 100644 --- a/src/test/java/com/gomo/app/core/quest/domain/model/participant/ParticipantTest.java +++ b/src/test/java/com/gomo/app/core/quest/domain/model/participant/ParticipantTest.java @@ -8,8 +8,8 @@ import org.junit.jupiter.api.Test; import com.gomo.app.core.quest.domain.model.quest.QuestType; -import com.gomo.app.core.quest.exception.QuestConstraintViolationException; -import com.gomo.app.core.quest.exception.code.QuestErrorCode; +import com.gomo.app.core.quest.domain.exception.QuestConstraintViolationException; +import com.gomo.app.core.quest.domain.exception.code.QuestErrorCode; @DisplayName("[Domain unit]: 퀘스트 참여자 엔티티 테스트") public class ParticipantTest { diff --git a/src/test/java/com/gomo/app/core/quest/domain/model/pool/QuestPoolTest.java b/src/test/java/com/gomo/app/core/quest/domain/model/pool/QuestPoolTest.java index 3a3da747..0a8a602d 100644 --- a/src/test/java/com/gomo/app/core/quest/domain/model/pool/QuestPoolTest.java +++ b/src/test/java/com/gomo/app/core/quest/domain/model/pool/QuestPoolTest.java @@ -8,7 +8,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import com.gomo.app.core.quest.exception.QuestAccessDeniedException; +import com.gomo.app.core.quest.domain.exception.QuestAccessDeniedException; import com.gomo.app.core.quest.fixture.QuestFixture; @DisplayName("[Domain unit]: 퀘스트 풀 생성 및 수정 테스트") diff --git a/src/test/java/com/gomo/app/core/quest/domain/model/quest/QuestContentTest.java b/src/test/java/com/gomo/app/core/quest/domain/model/quest/QuestContentTest.java index 2f4bf929..1c9bbefa 100644 --- a/src/test/java/com/gomo/app/core/quest/domain/model/quest/QuestContentTest.java +++ b/src/test/java/com/gomo/app/core/quest/domain/model/quest/QuestContentTest.java @@ -8,8 +8,8 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import com.gomo.app.core.quest.exception.QuestContentConstraintViolationException; -import com.gomo.app.core.quest.exception.code.QuestContentErrorCode; +import com.gomo.app.core.quest.domain.exception.QuestContentConstraintViolationException; +import com.gomo.app.core.quest.domain.exception.code.QuestContentErrorCode; @DisplayName("[Domain unit]: 퀘스트 내용 생성 및 수정 테스트") public class QuestContentTest { diff --git a/src/test/java/com/gomo/app/core/quest/domain/model/repeat/RepeatQuestTest.java b/src/test/java/com/gomo/app/core/quest/domain/model/repeat/RepeatQuestTest.java index 0f7ef171..52cf2824 100644 --- a/src/test/java/com/gomo/app/core/quest/domain/model/repeat/RepeatQuestTest.java +++ b/src/test/java/com/gomo/app/core/quest/domain/model/repeat/RepeatQuestTest.java @@ -15,7 +15,7 @@ import com.gomo.app.core.quest.domain.model.quest.QuestContent; import com.gomo.app.core.quest.domain.model.quest.QuestType; import com.gomo.app.core.quest.domain.model.subject.SubjectName; -import com.gomo.app.core.quest.exception.RepeatQuestAccessDeniedException; +import com.gomo.app.core.quest.domain.exception.RepeatQuestAccessDeniedException; @DisplayName("[Domain unit]: 반복 퀘스트 생성 및 수정 테스트") public class RepeatQuestTest { diff --git a/src/test/java/com/gomo/app/core/quest/domain/service/AssignQuestServiceTest.java b/src/test/java/com/gomo/app/core/quest/domain/service/AssignQuestServiceTest.java deleted file mode 100644 index de008b78..00000000 --- a/src/test/java/com/gomo/app/core/quest/domain/service/AssignQuestServiceTest.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.gomo.app.core.quest.domain.service; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -import java.util.Optional; -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.quest.domain.model.assign.AssignQuest; -import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; -import com.gomo.app.core.quest.exception.AssignQuestNotFoundException; -import com.gomo.app.core.quest.exception.code.AssignQuestErrorCode; -import com.gomo.app.core.quest.fixture.AssignQuestFixture; -import com.gomo.app.core.quest.fixture.QuestFixture; - -@DisplayName("[Domain unit]: 할당 퀘스트 생성 테스트") -@ExtendWith(MockitoExtension.class) -public class AssignQuestServiceTest { - - @InjectMocks - private AssignQuestService sut; - - @Mock - private AssignQuestRepository assignQuestRepository; - - @DisplayName("할당 퀘스트를 생성한다.") - @Test - void create_assign_quest() { - AssignQuest assignQuest = AssignQuestFixture.create(); - - doReturn(4).when(assignQuestRepository).findMaxDisplayOrderOfParticipatingQuest(any(), any(), any(), any()); - doReturn(assignQuest).when(assignQuestRepository).save(any()); - - AssignQuest actual = sut.create(UUID.randomUUID(), QuestFixture.create()); - - assertThat(actual.getId()).isEqualTo(assignQuest.getId()); - } - - @DisplayName("새로 생성된 할당 퀘스트의 정렬 순서는 현재 참여중인 퀘스트의 마지막 번호 + 1이다.") - @Test - void create_assign_quest_with_display_order() { - doReturn(4).when(assignQuestRepository).findMaxDisplayOrderOfParticipatingQuest(any(), any(), any(), any()); - doReturn(AssignQuestFixture.create(4 + 1)).when(assignQuestRepository).save(any()); - - AssignQuest actual = sut.create(UUID.randomUUID(), QuestFixture.create()); - - assertThat(actual.getDisplayOrder().getDisplayOrder()).isEqualTo(4 + 1); - } - - @DisplayName("할당 퀘스트를 조회한다.") - @Test - void find_assign_quest() { - AssignQuest assignQuest = AssignQuestFixture.create(); - doReturn(Optional.of(assignQuest)).when(assignQuestRepository).findById(any()); - - AssignQuest actual = sut.find(assignQuest.getId()); - - assertThat(actual).isEqualTo(assignQuest); - } - - @DisplayName("존재하지 않는 할당 퀘스트를 조회한다.") - @Test - void find_nonexistent_assign_quest() { - doReturn(Optional.empty()).when(assignQuestRepository).findById(any()); - - assertThatThrownBy(() -> sut.find(UUID.randomUUID())) - .isInstanceOf(AssignQuestNotFoundException.class) - .hasMessageContaining(AssignQuestErrorCode.NOT_FOUND.getMessage()); - } -} diff --git a/src/test/java/com/gomo/app/core/quest/domain/service/QuestRewardServiceTest.java b/src/test/java/com/gomo/app/core/quest/domain/service/QuestRewardProviderTest.java similarity index 87% rename from src/test/java/com/gomo/app/core/quest/domain/service/QuestRewardServiceTest.java rename to src/test/java/com/gomo/app/core/quest/domain/service/QuestRewardProviderTest.java index 19120cf3..37ec771a 100644 --- a/src/test/java/com/gomo/app/core/quest/domain/service/QuestRewardServiceTest.java +++ b/src/test/java/com/gomo/app/core/quest/domain/service/QuestRewardProviderTest.java @@ -21,17 +21,17 @@ @DisplayName("[Domain integration]: 퀘스트 보상 생성 테스트") @ExtendWith(MockitoExtension.class) -public class QuestRewardServiceTest { +public class QuestRewardProviderTest { @InjectMocks - private QuestRewardService sut; + private QuestRewardProvider sut; @Mock private QuestRewardPolicyRepository questRewardPolicyRepository; @DisplayName("퀘스트 타입에 맞는 보상을 조회한다.") @Test - void find_daily_quest_reward() { + void provide_daily_quest_reward() { List questRewardPolicies = List.of( QuestRewardPolicy.of( QuestType.DAILY, @@ -45,7 +45,7 @@ void find_daily_quest_reward() { doReturn(questRewardPolicies).when(questRewardPolicyRepository).findAll(); sut.initializeCaches(); - QuestReward questReward = sut.find(QuestType.DAILY); + QuestReward questReward = sut.provide(QuestType.DAILY); assertThat(questReward.scoreValue()).isEqualTo(1); assertThat(questReward.pointValue()).isEqualTo(10); diff --git a/src/test/java/com/gomo/app/core/quest/domain/service/RepeatQuestServiceTest.java b/src/test/java/com/gomo/app/core/quest/domain/service/RepeatQuestServiceTest.java deleted file mode 100644 index 0bb07c34..00000000 --- a/src/test/java/com/gomo/app/core/quest/domain/service/RepeatQuestServiceTest.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.gomo.app.core.quest.domain.service; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.quest.domain.model.repeat.RepeatQuest; -import com.gomo.app.core.quest.domain.repository.RepeatQuestRepository; -import com.gomo.app.core.quest.fixture.QuestFixture; -import com.gomo.app.core.quest.fixture.RepeatQuestFixture; - -@DisplayName("[Domain unit]: 반복 퀘스트 생성 테스트") -@ExtendWith(MockitoExtension.class) -public class RepeatQuestServiceTest { - - @InjectMocks - private RepeatQuestService sut; - - @Mock - private RepeatQuestRepository repeatQuestRepository; - - @DisplayName("반복 퀘스트를 생성한다.") - @Test - void create_repeat_quest() { - RepeatQuest repeatQuest = RepeatQuestFixture.create(); - doReturn(4).when(repeatQuestRepository).findMaxDisplayOrderByQuestType(any(), any()); - doReturn(repeatQuest).when(repeatQuestRepository).save(any()); - - RepeatQuest actual = sut.create(UUID.randomUUID(), QuestFixture.create()); - - assertThat(actual.getId()).isEqualTo(repeatQuest.getId()); - } - - @DisplayName("새로 생성된 반복 퀘스트의 정렬 순서는 현재 등록된 반복 퀘스트의 마지막 번호 + 1이다.") - @Test - void create_repeat_quest_with_display_order() { - doReturn(4).when(repeatQuestRepository).findMaxDisplayOrderByQuestType(any(), any()); - doReturn(RepeatQuestFixture.create(4 + 1)).when(repeatQuestRepository).save(any()); - - RepeatQuest actual = sut.create(UUID.randomUUID(), QuestFixture.create()); - - assertThat(actual.getDisplayOrder().getDisplayOrder()).isEqualTo(4 + 1); - } -} diff --git a/src/test/java/com/gomo/app/core/streak/presentation/documentation/ListStreakDocumentationTest.java b/src/test/java/com/gomo/app/core/streak/adapter/in/api/ListStreakDocumentationTest.java similarity index 91% rename from src/test/java/com/gomo/app/core/streak/presentation/documentation/ListStreakDocumentationTest.java rename to src/test/java/com/gomo/app/core/streak/adapter/in/api/ListStreakDocumentationTest.java index 95a62ddf..4353f966 100644 --- a/src/test/java/com/gomo/app/core/streak/presentation/documentation/ListStreakDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/streak/adapter/in/api/ListStreakDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.streak.presentation.documentation; +package com.gomo.app.core.streak.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -16,11 +16,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; +import com.gomo.app.core.streak.adapter.in.api.snippet.ListStreakSnippet; import com.gomo.app.core.streak.domain.model.Streak; import com.gomo.app.core.streak.domain.model.StreakType; import com.gomo.app.core.streak.domain.repository.StreakRepository; import com.gomo.app.core.streak.fixture.StreakFixture; -import com.gomo.app.core.streak.presentation.documentation.snippet.ListStreakSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 스트릭 목록 조회 테스트") diff --git a/src/test/java/com/gomo/app/core/streak/presentation/documentation/ReadAchieverDocumentationTest.java b/src/test/java/com/gomo/app/core/streak/adapter/in/api/ReadAchieverDocumentationTest.java similarity index 89% rename from src/test/java/com/gomo/app/core/streak/presentation/documentation/ReadAchieverDocumentationTest.java rename to src/test/java/com/gomo/app/core/streak/adapter/in/api/ReadAchieverDocumentationTest.java index 1e677082..7402bd88 100644 --- a/src/test/java/com/gomo/app/core/streak/presentation/documentation/ReadAchieverDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/streak/adapter/in/api/ReadAchieverDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.streak.presentation.documentation; +package com.gomo.app.core.streak.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -13,10 +13,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; +import com.gomo.app.core.streak.adapter.in.api.snippet.ReadAchieverSnippet; import com.gomo.app.core.streak.domain.model.Achiever; import com.gomo.app.core.streak.domain.repository.AchieverRepository; import com.gomo.app.core.streak.fixture.AchieverFixture; -import com.gomo.app.core.streak.presentation.documentation.snippet.ReadAchieverSnippet; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 성취자 조회 테스트") diff --git a/src/test/java/com/gomo/app/core/streak/presentation/documentation/snippet/ListStreakSnippet.java b/src/test/java/com/gomo/app/core/streak/adapter/in/api/snippet/ListStreakSnippet.java similarity index 95% rename from src/test/java/com/gomo/app/core/streak/presentation/documentation/snippet/ListStreakSnippet.java rename to src/test/java/com/gomo/app/core/streak/adapter/in/api/snippet/ListStreakSnippet.java index 1fdc0d8e..f4da38b4 100644 --- a/src/test/java/com/gomo/app/core/streak/presentation/documentation/snippet/ListStreakSnippet.java +++ b/src/test/java/com/gomo/app/core/streak/adapter/in/api/snippet/ListStreakSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.streak.presentation.documentation.snippet; +package com.gomo.app.core.streak.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/streak/presentation/documentation/snippet/ReadAchieverSnippet.java b/src/test/java/com/gomo/app/core/streak/adapter/in/api/snippet/ReadAchieverSnippet.java similarity index 93% rename from src/test/java/com/gomo/app/core/streak/presentation/documentation/snippet/ReadAchieverSnippet.java rename to src/test/java/com/gomo/app/core/streak/adapter/in/api/snippet/ReadAchieverSnippet.java index 7ab256d6..c2b0baad 100644 --- a/src/test/java/com/gomo/app/core/streak/presentation/documentation/snippet/ReadAchieverSnippet.java +++ b/src/test/java/com/gomo/app/core/streak/adapter/in/api/snippet/ReadAchieverSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.streak.presentation.documentation.snippet; +package com.gomo.app.core.streak.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/streak/presentation/consumer/CompleteQuestEventStreakConsumerTest.java b/src/test/java/com/gomo/app/core/streak/adapter/in/consumer/CompleteQuestEventStreakConsumerTest.java similarity index 84% rename from src/test/java/com/gomo/app/core/streak/presentation/consumer/CompleteQuestEventStreakConsumerTest.java rename to src/test/java/com/gomo/app/core/streak/adapter/in/consumer/CompleteQuestEventStreakConsumerTest.java index 184a0506..6d90fc29 100644 --- a/src/test/java/com/gomo/app/core/streak/presentation/consumer/CompleteQuestEventStreakConsumerTest.java +++ b/src/test/java/com/gomo/app/core/streak/adapter/in/consumer/CompleteQuestEventStreakConsumerTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.streak.presentation.consumer; +package com.gomo.app.core.streak.adapter.in.consumer; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; @@ -16,8 +16,8 @@ import org.mockito.junit.jupiter.MockitoExtension; import com.gomo.app.common.util.JsonParser; -import com.gomo.app.core.quest.event.CompleteQuestEvent; -import com.gomo.app.core.streak.application.port.CreateStreakPortIn; +import com.gomo.app.core.quest.domain.event.CompleteQuestEvent; +import com.gomo.app.core.streak.application.port.in.StreakCreator; import com.gomo.app.support.evententry.domain.model.EventEntry; @DisplayName("[Consumer unit]: 퀘스트 완료(스트릭) 이벤트 처리 테스트") @@ -28,7 +28,7 @@ class CompleteQuestEventStreakConsumerTest { private CompleteQuestEventStreakConsumer sut; @Mock - private CreateStreakPortIn createStreakPortIn; + private StreakCreator streakCreator; @DisplayName("숙련도 향상 이벤트를 처리한다.") @Test @@ -41,7 +41,7 @@ void event_process() { sut.handleEvent(eventEntry); - verify(createStreakPortIn, times(1)).create(any(), anyString(), any()); + verify(streakCreator, times(1)).create(any(), anyString(), any()); } } @@ -50,7 +50,7 @@ void event_process() { void cannot_process_event_by_streak() { EventEntry eventEntry = EventEntry.of("CompleteQuestEvent", "payload", 1L); CompleteQuestEvent event = CompleteQuestEvent.of(UUID.randomUUID(), UUID.randomUUID(), "DAILY", 2, 10, LocalDateTime.now(), 1L); - doThrow(new IllegalStateException("Streak service failure")).when(createStreakPortIn).create(any(), anyString(), any()); + doThrow(new IllegalStateException("Streak service failure")).when(streakCreator).create(any(), anyString(), any()); try (MockedStatic mockedJsonParser = mockStatic(JsonParser.class)) { mockedJsonParser.when(() -> JsonParser.fromJson(any(), eq(CompleteQuestEvent.class))).thenReturn(event); diff --git a/src/test/java/com/gomo/app/core/streak/application/service/AchieverServiceTest.java b/src/test/java/com/gomo/app/core/streak/application/service/AchieverServiceTest.java new file mode 100644 index 00000000..9d4e66d2 --- /dev/null +++ b/src/test/java/com/gomo/app/core/streak/application/service/AchieverServiceTest.java @@ -0,0 +1,74 @@ +package com.gomo.app.core.streak.application.service; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.Optional; +import java.util.UUID; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.core.streak.application.port.dto.AchieverDto; +import com.gomo.app.core.streak.domain.model.Achiever; +import com.gomo.app.core.streak.domain.repository.AchieverRepository; +import com.gomo.app.core.streak.fixture.AchieverFixture; + +@DisplayName("[Application unit]: 성취자 생성 테스트") +@ExtendWith(MockitoExtension.class) +class AchieverServiceTest { + + @InjectMocks + private AchieverService sut; + + @Mock + private AchieverRepository achieverRepository; + + @DisplayName("성취자를 생성한다.") + @Test + void create_achiever() { + doReturn(false).when(achieverRepository).existsById(any()); + doReturn(AchieverFixture.create()).when(achieverRepository).save(any()); + + UUID actual = sut.create(UUID.randomUUID()); + + assertThat(actual).isNotNull(); + } + + @DisplayName("성취자를 중복 생성한다.") + @Test + void create_duplicated_achiever() { + doReturn(true).when(achieverRepository).existsById(any()); + + assertThatThrownBy(() -> sut.create(UUID.randomUUID())).isInstanceOf(IllegalStateException.class); + } + + @DisplayName("성취자를 조회한다.") + @Test + void read_achiever() { + Achiever achiever = AchieverFixture.create(); + doReturn(Optional.of(achiever)).when(achieverRepository).findById(any()); + + AchieverDto actual = sut.read(UUID.randomUUID()); + + assertThat(actual).extracting("id", "longestStreakDays", "currentStreakDays") + .containsExactly(achiever.getId(), achiever.getLongestStreakDays(), achiever.getCurrentStreakDays()); + } + + @DisplayName("성취자를 조회한다.") + @Test + void read_achiever_by_id() { + Achiever achiever = AchieverFixture.create(3, 5); + doReturn(Optional.of(achiever)).when(achieverRepository).findById(any()); + + Achiever actual = sut.findById(achiever.getId()); + + assertThat(actual.getCurrentStreakDays()).isEqualTo(3); + assertThat(actual.getLongestStreakDays()).isEqualTo(5); + } +} diff --git a/src/test/java/com/gomo/app/core/streak/application/service/StreakServiceTest.java b/src/test/java/com/gomo/app/core/streak/application/service/StreakServiceTest.java new file mode 100644 index 00000000..43d957e3 --- /dev/null +++ b/src/test/java/com/gomo/app/core/streak/application/service/StreakServiceTest.java @@ -0,0 +1,114 @@ +package com.gomo.app.core.streak.application.service; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.time.LocalDate; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.gomo.app.core.streak.application.port.dto.ListStreakDto; +import com.gomo.app.core.streak.domain.model.Achiever; +import com.gomo.app.core.streak.domain.model.Streak; +import com.gomo.app.core.streak.domain.model.StreakType; +import com.gomo.app.core.streak.domain.repository.StreakRepository; +import com.gomo.app.core.streak.fixture.AchieverFixture; +import com.gomo.app.core.streak.fixture.StreakFixture; + +@DisplayName("[Application unit]: 스트릭 생성 테스트") +@ExtendWith(MockitoExtension.class) +class StreakServiceTest { + + @InjectMocks + private StreakService sut; + + @Mock + private AchieverService achieverService; + + @Mock + private StreakRepository streakRepository; + + @DisplayName("스트릭이 없다면, 최초 스트릭을 생성한다.") + @Test + void create_initial_streak() { + Achiever achiever = AchieverFixture.create(); + Streak streak = Streak.of(UUID.randomUUID(), UUID.randomUUID(), StreakType.DAILY, LocalDate.of(2025, 2, 5), 1); + doReturn(achiever).when(achieverService).findById(any()); + doReturn(List.of()).when(streakRepository).findByAchieverIdAndFilledDate(any(), any()); + doReturn(Optional.empty()).when(streakRepository).findByAchieverIdAndStreakTypeAndFilledDate(any(), any(), any()); + doReturn(streak).when(streakRepository).save(any()); + + sut.create(achiever.getId(), streak.getStreakType().name(), streak.getFilledDate()); + + verify(streakRepository, times(1)).save(any()); + } + + @DisplayName("이미 스트릭이 있다면, 기존 스트릭의 완료 퀘스트 개수를 증가시킨다.") + @Test + void update_exist_streak() { + Achiever achiever = AchieverFixture.create(); + Streak streak = Streak.of(UUID.randomUUID(), UUID.randomUUID(), StreakType.DAILY, LocalDate.now(), 2); + doReturn(achiever).when(achieverService).findById(any()); + doReturn(List.of()).when(streakRepository).findByAchieverIdAndFilledDate(any(), any()); + doReturn(Optional.of(streak)).when(streakRepository).findByAchieverIdAndStreakTypeAndFilledDate(any(), any(), any()); + + sut.create(achiever.getId(), streak.getStreakType().name(), streak.getFilledDate()); + + assertThat(streak.getCompletedQuestCount()).isEqualTo(3); + } + + @DisplayName("전날 어떠한 스트릭(DAILY, WEEKLY, MONTHLY)도 채우지 않았다면, 연속일수를 초기화한다.") + @Test + void initialize_streak_days() { + Achiever achiever = Mockito.mock(Achiever.class); + doReturn(achiever).when(achieverService).findById(any()); + doReturn(List.of()).when(streakRepository).findByAchieverIdAndFilledDate(any(), any()); + doReturn(Optional.empty()).when(streakRepository).findByAchieverIdAndStreakTypeAndFilledDate(any(), any(), any()); + + sut.create(achiever.getId(), StreakType.DAILY.name(), LocalDate.now()); + + verify(achiever, times(1)).updateStreakDays(eq(false)); + } + + @DisplayName("전날 스트릭(DAILY, WEEKLY, MONTHLY)을 하나라도 채웠다면, 연속일수를 갱신한다.") + @Test + void update_streak_days() { + Achiever achiever = Mockito.mock(Achiever.class); + Streak streak = Streak.of(UUID.randomUUID(), UUID.randomUUID(), StreakType.DAILY, LocalDate.now(), 2); + doReturn(achiever).when(achieverService).findById(any()); + doReturn(List.of(streak)).when(streakRepository).findByAchieverIdAndFilledDate(any(), any()); + doReturn(Optional.empty()).when(streakRepository).findByAchieverIdAndStreakTypeAndFilledDate(any(), any(), any()); + + sut.create(achiever.getId(), StreakType.DAILY.name(), LocalDate.now()); + + verify(achiever, times(1)).updateStreakDays(eq(true)); + } + + @DisplayName("스트릭 목록을 조회한다.") + @Test + void find_All() { + List dailyStreaks = List.of(StreakFixture.create(StreakType.DAILY), StreakFixture.create(StreakType.DAILY)); + List weeklyStreaks = List.of(StreakFixture.create(StreakType.WEEKLY)); + List monthlyStreaks = List.of(); + + doReturn(dailyStreaks).when(streakRepository).findByAchieverIdAndStreakTypeAndFilledDateBetween(any(), eq(StreakType.DAILY), any(), any()); + doReturn(weeklyStreaks).when(streakRepository).findByAchieverIdAndStreakTypeAndFilledDateBetween(any(), eq(StreakType.WEEKLY), any(), any()); + doReturn(monthlyStreaks).when(streakRepository).findByAchieverIdAndStreakTypeAndFilledDateBetween(any(), eq(StreakType.MONTHLY), any(), any()); + + ListStreakDto actual = sut.findAll(UUID.randomUUID(), LocalDate.of(2025, 2, 6), LocalDate.of(2025, 2, 7)); + + assertThat(actual.dailyStreaks().size()).isEqualTo(2); + assertThat(actual.weeklyStreaks().size()).isEqualTo(1); + assertThat(actual.monthlyStreaks().size()).isEqualTo(0); + } +} diff --git a/src/test/java/com/gomo/app/core/streak/application/usecase/CreateAchieverUseCaseTest.java b/src/test/java/com/gomo/app/core/streak/application/usecase/CreateAchieverUseCaseTest.java deleted file mode 100644 index 92873a71..00000000 --- a/src/test/java/com/gomo/app/core/streak/application/usecase/CreateAchieverUseCaseTest.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.gomo.app.core.streak.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.streak.domain.repository.AchieverRepository; -import com.gomo.app.core.streak.fixture.AchieverFixture; - -@DisplayName("[Application unit]: 성취자 생성 테스트") -@ExtendWith(MockitoExtension.class) -class CreateAchieverUseCaseTest { - - @InjectMocks - private CreateAchieverUseCase sut; - - @Mock - private AchieverRepository achieverRepository; - - @DisplayName("성취자를 생성한다.") - @Test - void create_achiever() { - doReturn(AchieverFixture.create()).when(achieverRepository).save(any()); - UUID actual = sut.create(UUID.randomUUID()); - assertThat(actual).isNotNull(); - } -} diff --git a/src/test/java/com/gomo/app/core/streak/application/usecase/CreateStreakUseCaseTest.java b/src/test/java/com/gomo/app/core/streak/application/usecase/CreateStreakUseCaseTest.java deleted file mode 100644 index 34158d14..00000000 --- a/src/test/java/com/gomo/app/core/streak/application/usecase/CreateStreakUseCaseTest.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.gomo.app.core.streak.application.usecase; - -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -import java.time.LocalDate; -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.quest.domain.model.quest.QuestType; -import com.gomo.app.core.streak.domain.model.Streak; -import com.gomo.app.core.streak.domain.service.StreakService; - -@DisplayName("[Application unit]: 스트릭 생성 테스트") -@ExtendWith(MockitoExtension.class) -class CreateStreakUseCaseTest { - - @InjectMocks - private CreateStreakUseCase sut; - - @Mock - private StreakService streakService; - - @DisplayName("스트릭을 생성한다.") - @Test - void create_streak() { - sut.create(UUID.randomUUID(), QuestType.DAILY.name(), LocalDate.now()); - verify(streakService, times(1)).fill(any(Streak.class)); - } -} diff --git a/src/test/java/com/gomo/app/core/streak/application/usecase/ReadAchieverUseCaseTest.java b/src/test/java/com/gomo/app/core/streak/application/usecase/ReadAchieverUseCaseTest.java deleted file mode 100644 index 2341c838..00000000 --- a/src/test/java/com/gomo/app/core/streak/application/usecase/ReadAchieverUseCaseTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.gomo.app.core.streak.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.streak.application.port.dto.AchieverDto; -import com.gomo.app.core.streak.domain.model.Achiever; -import com.gomo.app.core.streak.domain.service.AchieverService; -import com.gomo.app.core.streak.fixture.AchieverFixture; - -@DisplayName("[Application unit]: 성취자 조회 테스트") -@ExtendWith(MockitoExtension.class) -public class ReadAchieverUseCaseTest { - - @InjectMocks - private ReadAchieverUseCase sut; - - @Mock - private AchieverService achieverService; - - @DisplayName("성취자를 조회한다.") - @Test - void create_achiever() { - Achiever achiever = AchieverFixture.create(); - doReturn(achiever).when(achieverService).find(any()); - AchieverDto actual = sut.find(UUID.randomUUID()); - assertThat(actual).extracting("id", "longestStreakDays", "currentStreakDays") - .containsExactly(achiever.getId(), achiever.getLongestStreakDays(), achiever.getCurrentStreakDays()); - } -} diff --git a/src/test/java/com/gomo/app/core/streak/application/usecase/ReadStreakUseCaseTest.java b/src/test/java/com/gomo/app/core/streak/application/usecase/ReadStreakUseCaseTest.java deleted file mode 100644 index 00c4c979..00000000 --- a/src/test/java/com/gomo/app/core/streak/application/usecase/ReadStreakUseCaseTest.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.gomo.app.core.streak.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.time.LocalDate; -import java.util.List; -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.streak.application.port.dto.ListStreakDto; -import com.gomo.app.core.streak.domain.model.Streak; -import com.gomo.app.core.streak.domain.model.StreakType; -import com.gomo.app.core.streak.domain.service.StreakService; -import com.gomo.app.core.streak.fixture.StreakFixture; - -@DisplayName("[Application unit]: 스트릭 조회 테스트") -@ExtendWith(MockitoExtension.class) -public class ReadStreakUseCaseTest { - - @InjectMocks - private ReadStreakUseCase sut; - - @Mock - private StreakService streakService; - - @DisplayName("스트릭 목록을 조회한다.") - @Test - void find_All() { - List dailyStreaks = List.of(StreakFixture.create(StreakType.DAILY), StreakFixture.create(StreakType.DAILY)); - List weeklyStreaks = List.of(StreakFixture.create(StreakType.WEEKLY)); - List monthlyStreaks = List.of(); - - doReturn(dailyStreaks).when(streakService).findAllByStreakType(any(), eq(StreakType.DAILY), any(), any()); - doReturn(weeklyStreaks).when(streakService).findAllByStreakType(any(), eq(StreakType.WEEKLY), any(), any()); - doReturn(monthlyStreaks).when(streakService).findAllByStreakType(any(), eq(StreakType.MONTHLY), any(), any()); - - ListStreakDto actual = sut.findAll(UUID.randomUUID(), LocalDate.of(2025, 2, 6), LocalDate.of(2025, 2, 7)); - - assertThat(actual.dailyStreaks().size()).isEqualTo(2); - assertThat(actual.weeklyStreaks().size()).isEqualTo(1); - assertThat(actual.monthlyStreaks().size()).isEqualTo(0); - } -} diff --git a/src/test/java/com/gomo/app/core/streak/domain/service/AchieverServiceTest.java b/src/test/java/com/gomo/app/core/streak/domain/service/AchieverServiceTest.java deleted file mode 100644 index 8f7dcd2d..00000000 --- a/src/test/java/com/gomo/app/core/streak/domain/service/AchieverServiceTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.gomo.app.core.streak.domain.service; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.Optional; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.streak.domain.model.Achiever; -import com.gomo.app.core.streak.domain.repository.AchieverRepository; -import com.gomo.app.core.streak.fixture.AchieverFixture; - -@DisplayName("[Domain unit]: 성취자 서비스 테스트") -@ExtendWith(MockitoExtension.class) -public class AchieverServiceTest { - - @InjectMocks - private AchieverService sut; - - @Mock - private AchieverRepository achieverRepository; - - @DisplayName("성취자를 조회한다.") - @Test - void find_achiever() { - Achiever achiever = AchieverFixture.create(3, 5); - doReturn(Optional.of(achiever)).when(achieverRepository).findById(any()); - - Achiever actual = sut.find(achiever.getId()); - - assertThat(actual.getCurrentStreakDays()).isEqualTo(3); - assertThat(actual.getLongestStreakDays()).isEqualTo(5); - } -} diff --git a/src/test/java/com/gomo/app/core/streak/domain/service/StreakServiceTest.java b/src/test/java/com/gomo/app/core/streak/domain/service/StreakServiceTest.java deleted file mode 100644 index d8165a4a..00000000 --- a/src/test/java/com/gomo/app/core/streak/domain/service/StreakServiceTest.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.gomo.app.core.streak.domain.service; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.time.LocalDate; -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.streak.domain.model.Achiever; -import com.gomo.app.core.streak.domain.model.Streak; -import com.gomo.app.core.streak.domain.model.StreakType; -import com.gomo.app.core.streak.domain.repository.StreakRepository; -import com.gomo.app.core.streak.fixture.AchieverFixture; -import com.gomo.app.core.streak.fixture.StreakFixture; - -@DisplayName("[Domain unit]: 스트릭 생성 및 조회 테스트") -@ExtendWith(MockitoExtension.class) -public class StreakServiceTest { - - @InjectMocks - private StreakService sut; - - @Mock - private AchieverService achieverService; - - @Mock - private StreakRepository streakRepository; - - @DisplayName("스트릭이 없다면, 최초 스트릭을 생성한다.") - @Test - void create_initial_streak() { - Streak streak = Streak.of(UUID.randomUUID(), UUID.randomUUID(), StreakType.DAILY, LocalDate.of(2025, 2, 5), 1); - doReturn(AchieverFixture.create()).when(achieverService).find(any()); - doReturn(List.of()).when(streakRepository).findByAchieverIdAndFilledDate(any(), any()); - doReturn(Optional.empty()).when(streakRepository).findByAchieverIdAndStreakTypeAndFilledDate(any(), any(), any()); - doReturn(streak).when(streakRepository).save(any()); - - Streak actual = sut.fill(streak); - - verify(streakRepository, times(1)).save(any()); - assertThat(actual.getCompletedQuestCount()).isEqualTo(1); - } - - @DisplayName("이미 스트릭이 있다면, 기존 스트릭의 완료 퀘스트 개수를 증가시킨다.") - @Test - void update_exist_streak() { - Streak streak = Streak.of(UUID.randomUUID(), UUID.randomUUID(), StreakType.DAILY, LocalDate.now(), 1); - doReturn(AchieverFixture.create()).when(achieverService).find(any()); - doReturn(List.of()).when(streakRepository).findByAchieverIdAndFilledDate(any(), any()); - doReturn(Optional.of(StreakFixture.create(5))).when(streakRepository).findByAchieverIdAndStreakTypeAndFilledDate(any(), any(), any()); - - Streak actual = sut.fill(streak); - - assertThat(actual.getCompletedQuestCount()).isEqualTo(6); - } - - @DisplayName("전날 스트릭 존재 여부에 따라 연속 유지 일수도 함께 조정한다.") - @Test - void adjust_streak_days() { - Achiever achiever = Mockito.mock(Achiever.class); - doReturn(achiever).when(achieverService).find(any()); - doReturn(List.of()).when(streakRepository).findByAchieverIdAndFilledDate(any(), any()); - doReturn(Optional.empty()).when(streakRepository).findByAchieverIdAndStreakTypeAndFilledDate(any(), any(), any()); - - sut.fill(StreakFixture.create()); - - verify(achiever, times(1)).updateStreakDays(eq(false)); - } - - @DisplayName("타입, 날짜 별 스트릭 목록을 조회한다.") - @Test - void find_streaks_by_type() { - sut.findAllByStreakType(UUID.randomUUID(), StreakType.DAILY, LocalDate.now(), LocalDate.now()); - verify(streakRepository, times(1)).findByAchieverIdAndStreakTypeAndFilledDateBetween(any(), any(), any(), any()); - } -} diff --git a/src/test/java/com/gomo/app/core/survey/documentation/CreateSurveyAnswerDocumentationTest.java b/src/test/java/com/gomo/app/core/survey/adapter/in/api/CreateSurveyAnswerDocumentationTest.java similarity index 87% rename from src/test/java/com/gomo/app/core/survey/documentation/CreateSurveyAnswerDocumentationTest.java rename to src/test/java/com/gomo/app/core/survey/adapter/in/api/CreateSurveyAnswerDocumentationTest.java index 33d95f9c..156887be 100644 --- a/src/test/java/com/gomo/app/core/survey/documentation/CreateSurveyAnswerDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/survey/adapter/in/api/CreateSurveyAnswerDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.survey.documentation; +package com.gomo.app.core.survey.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -15,15 +15,15 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.survey.documentation.snippet.CreateSurveyAnswerSnippet; +import com.gomo.app.core.survey.adapter.in.api.snippet.CreateSurveyAnswerSnippet; import com.gomo.app.core.survey.domain.model.SurveyItem; import com.gomo.app.core.survey.domain.model.SurveyQuestion; import com.gomo.app.core.survey.domain.repository.SurveyItemRepository; import com.gomo.app.core.survey.domain.repository.SurveyQuestionRepository; import com.gomo.app.core.survey.fixture.SurveyItemFixture; import com.gomo.app.core.survey.fixture.SurveyQuestionFixture; -import com.gomo.app.core.survey.presentation.request.CreateSurveyResultRequest; -import com.gomo.app.core.survey.presentation.request.SelectedSurveyItemRequest; +import com.gomo.app.core.survey.adapter.in.api.request.CreateSurveyResultRequest; +import com.gomo.app.core.survey.adapter.in.api.request.SelectedSurveyItemRequest; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 설문 결과 생성 테스트") diff --git a/src/test/java/com/gomo/app/core/survey/documentation/ListSurveyDocumentationTest.java b/src/test/java/com/gomo/app/core/survey/adapter/in/api/ListSurveyDocumentationTest.java similarity index 92% rename from src/test/java/com/gomo/app/core/survey/documentation/ListSurveyDocumentationTest.java rename to src/test/java/com/gomo/app/core/survey/adapter/in/api/ListSurveyDocumentationTest.java index 7e78a87d..e90b41fa 100644 --- a/src/test/java/com/gomo/app/core/survey/documentation/ListSurveyDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/survey/adapter/in/api/ListSurveyDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.survey.documentation; +package com.gomo.app.core.survey.adapter.in.api; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; @@ -15,7 +15,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.survey.documentation.snippet.ListSurveySnippet; +import com.gomo.app.core.survey.adapter.in.api.snippet.ListSurveySnippet; import com.gomo.app.core.survey.domain.model.SurveyItem; import com.gomo.app.core.survey.domain.model.SurveyQuestion; import com.gomo.app.core.survey.domain.repository.SurveyItemRepository; diff --git a/src/test/java/com/gomo/app/core/survey/documentation/snippet/CreateSurveyAnswerSnippet.java b/src/test/java/com/gomo/app/core/survey/adapter/in/api/snippet/CreateSurveyAnswerSnippet.java similarity index 95% rename from src/test/java/com/gomo/app/core/survey/documentation/snippet/CreateSurveyAnswerSnippet.java rename to src/test/java/com/gomo/app/core/survey/adapter/in/api/snippet/CreateSurveyAnswerSnippet.java index ecf6413f..bdd344b1 100644 --- a/src/test/java/com/gomo/app/core/survey/documentation/snippet/CreateSurveyAnswerSnippet.java +++ b/src/test/java/com/gomo/app/core/survey/adapter/in/api/snippet/CreateSurveyAnswerSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.survey.documentation.snippet; +package com.gomo.app.core.survey.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/survey/documentation/snippet/ListSurveySnippet.java b/src/test/java/com/gomo/app/core/survey/adapter/in/api/snippet/ListSurveySnippet.java similarity index 95% rename from src/test/java/com/gomo/app/core/survey/documentation/snippet/ListSurveySnippet.java rename to src/test/java/com/gomo/app/core/survey/adapter/in/api/snippet/ListSurveySnippet.java index c473ea87..b0508a39 100644 --- a/src/test/java/com/gomo/app/core/survey/documentation/snippet/ListSurveySnippet.java +++ b/src/test/java/com/gomo/app/core/survey/adapter/in/api/snippet/ListSurveySnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.survey.documentation.snippet; +package com.gomo.app.core.survey.adapter.in.api.snippet; import static org.springframework.http.HttpHeaders.*; import static org.springframework.restdocs.headers.HeaderDocumentation.*; diff --git a/src/test/java/com/gomo/app/core/survey/integration/SurveyResultRepositoryTest.java b/src/test/java/com/gomo/app/core/survey/adapter/out/persistence/SurveyResultRepositoryTest.java similarity index 94% rename from src/test/java/com/gomo/app/core/survey/integration/SurveyResultRepositoryTest.java rename to src/test/java/com/gomo/app/core/survey/adapter/out/persistence/SurveyResultRepositoryTest.java index 0db5e7ed..7c74749e 100644 --- a/src/test/java/com/gomo/app/core/survey/integration/SurveyResultRepositoryTest.java +++ b/src/test/java/com/gomo/app/core/survey/adapter/out/persistence/SurveyResultRepositoryTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.survey.integration; +package com.gomo.app.core.survey.adapter.out.persistence; import static org.assertj.core.api.Assertions.*; diff --git a/src/test/java/com/gomo/app/core/survey/unit/usecase/ReadSurveyResultUseCaseTest.java b/src/test/java/com/gomo/app/core/survey/application/service/ReadSurveyResultUseCaseTest.java similarity index 83% rename from src/test/java/com/gomo/app/core/survey/unit/usecase/ReadSurveyResultUseCaseTest.java rename to src/test/java/com/gomo/app/core/survey/application/service/ReadSurveyResultUseCaseTest.java index 43c821a1..94d48b35 100644 --- a/src/test/java/com/gomo/app/core/survey/unit/usecase/ReadSurveyResultUseCaseTest.java +++ b/src/test/java/com/gomo/app/core/survey/application/service/ReadSurveyResultUseCaseTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.survey.unit.usecase; +package com.gomo.app.core.survey.application.service; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; @@ -12,8 +12,7 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import com.gomo.app.core.survey.application.ReadSurveyQuestionUseCase; -import com.gomo.app.core.survey.application.SurveyQuestionDto; +import com.gomo.app.core.survey.application.dto.SurveyQuestionDto; import com.gomo.app.core.survey.domain.repository.SurveyItemRepository; import com.gomo.app.core.survey.domain.repository.SurveyQuestionRepository; import com.gomo.app.core.survey.fixture.SurveyItemFixture; @@ -24,7 +23,7 @@ public class ReadSurveyResultUseCaseTest { @InjectMocks - private ReadSurveyQuestionUseCase sut; + private SurveyQuestionService sut; @Mock private SurveyQuestionRepository surveyQuestionRepository; diff --git a/src/test/java/com/gomo/app/core/survey/unit/usecase/CreateSurveyResultUseCaseTest.java b/src/test/java/com/gomo/app/core/survey/application/service/SurveyResultServiceTest.java similarity index 75% rename from src/test/java/com/gomo/app/core/survey/unit/usecase/CreateSurveyResultUseCaseTest.java rename to src/test/java/com/gomo/app/core/survey/application/service/SurveyResultServiceTest.java index 69b1fb04..7add2ccd 100644 --- a/src/test/java/com/gomo/app/core/survey/unit/usecase/CreateSurveyResultUseCaseTest.java +++ b/src/test/java/com/gomo/app/core/survey/application/service/SurveyResultServiceTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.survey.unit.usecase; +package com.gomo.app.core.survey.application.service; import static org.mockito.Mockito.*; @@ -13,17 +13,16 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import com.gomo.app.core.survey.application.CreateSurveyResultCommand; -import com.gomo.app.core.survey.application.CreateSurveyResultUseCase; -import com.gomo.app.core.survey.application.SurveyItemDto; +import com.gomo.app.core.survey.application.command.CreateSurveyResultCommand; +import com.gomo.app.core.survey.application.dto.SurveyItemDto; import com.gomo.app.core.survey.domain.repository.SurveyResultRepository; @DisplayName("[Application unit]: 설문 결과 생성 테스트") @ExtendWith(MockitoExtension.class) -public class CreateSurveyResultUseCaseTest { +public class SurveyResultServiceTest { @InjectMocks - private CreateSurveyResultUseCase sut; + private SurveyResultService sut; @Mock private SurveyResultRepository surveyResultRepository; diff --git a/src/test/java/com/gomo/app/core/survey/unit/domain/SurveyResultTest.java b/src/test/java/com/gomo/app/core/survey/domain/SurveyResultTest.java similarity index 92% rename from src/test/java/com/gomo/app/core/survey/unit/domain/SurveyResultTest.java rename to src/test/java/com/gomo/app/core/survey/domain/SurveyResultTest.java index a8daab90..f04cfc01 100644 --- a/src/test/java/com/gomo/app/core/survey/unit/domain/SurveyResultTest.java +++ b/src/test/java/com/gomo/app/core/survey/domain/SurveyResultTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.survey.unit.domain; +package com.gomo.app.core.survey.domain; import static org.assertj.core.api.Assertions.*; @@ -10,8 +10,8 @@ import org.junit.jupiter.api.Test; import com.gomo.app.core.survey.domain.model.SurveyResult; -import com.gomo.app.core.survey.exception.SurveyResultConstraintViolationException; -import com.gomo.app.core.survey.exception.SurveyResultErrorCode; +import com.gomo.app.core.survey.domain.exception.SurveyResultConstraintViolationException; +import com.gomo.app.core.survey.domain.exception.SurveyResultErrorCode; @DisplayName("[Domain unit]: 설문 결과 생성 테스트") public class SurveyResultTest { diff --git a/src/test/java/com/gomo/app/support/auth/application/usecase/AuthenticateUseCaseTest.java b/src/test/java/com/gomo/app/support/auth/application/usecase/AuthenticateUseCaseTest.java deleted file mode 100644 index 854b25cc..00000000 --- a/src/test/java/com/gomo/app/support/auth/application/usecase/AuthenticateUseCaseTest.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.gomo.app.support.auth.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.common.security.jwt.application.port.VerifyJwtPortIn; -import com.gomo.app.core.member.application.port.LoginMemberPortIn; -import com.gomo.app.core.member.domain.model.ActivateStatus; -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.fixture.MemberFixture; -import com.gomo.app.support.auth.application.port.dto.AuthTokenDto; -import com.gomo.app.support.auth.domain.model.AuthToken; - -@DisplayName("[Application Unit]: 사용자 로그인 테스트") -@ExtendWith(MockitoExtension.class) -public class AuthenticateUseCaseTest { - - @InjectMocks - private AuthenticateUseCase sut; - - @Mock - private LoginMemberPortIn loginMemberPortIn; - - @Mock - private VerifyJwtPortIn verifyJwtPortIn; - - @Mock - private CreateAuthTokenInternalService createAuthTokenInternalService; - - @DisplayName("사용자가 로그인에 성공한다.") - @Test - void authenticate_success() { - Member member = MemberFixture.create(ActivateStatus.ACTIVE); - AuthToken authToken = AuthToken.of("access", "refresh"); - AuthTokenDto expected = AuthTokenDto.of(member.getId(), authToken.getAccessToken(), authToken.getRefreshToken(), 1L); - doReturn(member.getId()).when(loginMemberPortIn).authenticate(anyString(), anyString()); - doReturn(authToken).when(createAuthTokenInternalService).create(any()); - doReturn(1L).when(verifyJwtPortIn).extractExpirationTime(anyString()); - - AuthTokenDto actual = sut.authenticate(member.email(), member.password()); - - assertThat(actual).usingRecursiveComparison().isEqualTo(expected); - } -} diff --git a/src/test/java/com/gomo/app/support/auth/application/usecase/CreateAuthCodeUseCaseTest.java b/src/test/java/com/gomo/app/support/auth/application/usecase/CreateAuthCodeUseCaseTest.java deleted file mode 100644 index 3e1d2121..00000000 --- a/src/test/java/com/gomo/app/support/auth/application/usecase/CreateAuthCodeUseCaseTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.gomo.app.support.auth.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.support.auth.application.port.SendAuthCodePortOut; -import com.gomo.app.support.auth.domain.repository.AuthCodeRepository; - -@DisplayName("[Application Unit]: 인증 코드 생성 테스트") -@ExtendWith(MockitoExtension.class) -class CreateAuthCodeUseCaseTest { - - @InjectMocks - private CreateAuthCodeUseCase sut; - - @Mock - private SendAuthCodePortOut sendAuthCodePortOut; - - @Mock - private AuthCodeRepository authCodeRepository; - - @DisplayName("인증 코드를 생성한다.") - @Test - void create_auth_code() { - String actual = sut.sendToEmail("email@gmail.com"); - - assertThat(actual).isNotBlank(); - verify(authCodeRepository, times(1)).save(any(), any()); - verify(sendAuthCodePortOut, times(1)).toEmail(any(), any()); - } -} diff --git a/src/test/java/com/gomo/app/support/auth/application/usecase/CreateAuthTokenInternalServiceTest.java b/src/test/java/com/gomo/app/support/auth/application/usecase/CreateAuthTokenInternalServiceTest.java deleted file mode 100644 index b42f1a36..00000000 --- a/src/test/java/com/gomo/app/support/auth/application/usecase/CreateAuthTokenInternalServiceTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.gomo.app.support.auth.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.common.security.jwt.application.port.GenerateJwtPortIn; -import com.gomo.app.support.auth.domain.model.AuthToken; -import com.gomo.app.support.auth.domain.repository.AuthTokenRepository; - -@DisplayName("[Application Unit]: 인증 토큰 발급 테스트") -@ExtendWith(MockitoExtension.class) -public class CreateAuthTokenInternalServiceTest { - - @InjectMocks - private CreateAuthTokenInternalService sut; - - @Mock - private GenerateJwtPortIn generateJwtPortIn; - - @Mock - private AuthTokenRepository authTokenRepository; - - @DisplayName("인증토큰 발급에 성공한다.") - @Test - void create_auth_token_success() { - AuthToken expected = AuthToken.of("access", "refresh"); - - doReturn("access").when(generateJwtPortIn).generateAccessToken(any()); - doReturn("refresh").when(generateJwtPortIn).generateRefreshToken(any()); - doNothing().when(authTokenRepository).setRefreshToken(any(), anyString()); - - AuthToken actual = sut.create(UUID.randomUUID()); - - assertThat(actual).usingRecursiveComparison().isEqualTo(expected); - } -} diff --git a/src/test/java/com/gomo/app/support/auth/application/usecase/UpdateRefreshTokenUseCaseTest.java b/src/test/java/com/gomo/app/support/auth/application/usecase/UpdateRefreshTokenUseCaseTest.java deleted file mode 100644 index 0d23ef8c..00000000 --- a/src/test/java/com/gomo/app/support/auth/application/usecase/UpdateRefreshTokenUseCaseTest.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.gomo.app.support.auth.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.common.security.jwt.application.port.VerifyJwtPortIn; -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.fixture.MemberFixture; -import com.gomo.app.support.auth.application.port.dto.AuthTokenDto; -import com.gomo.app.support.auth.domain.model.AuthToken; -import com.gomo.app.support.auth.domain.repository.AuthTokenRepository; -import com.gomo.app.support.auth.exception.AuthErrorCode; -import com.gomo.app.support.auth.exception.AuthenticationFailException; - -@DisplayName("[Application Unit]: Refresh 토큰 재발급 테스트") -@ExtendWith(MockitoExtension.class) -public class UpdateRefreshTokenUseCaseTest { - - @InjectMocks - private UpdateRefreshTokenUseCase sut; - - @Mock - private CreateAuthTokenInternalService createAuthTokenInternalService; - - @Mock - private VerifyJwtPortIn verifyJwtPortIn; - - @Mock - private AuthTokenRepository authTokenRepository; - - private static final String REFRESH_TOKEN = "REFRESH_TOKEN"; - private static final String REFRESH_TOKEN_WRONG = "WRONG_TOKEN"; - - @DisplayName("Refresh 토큰 재발급에 성공한다.") - @Test - void renew_refresh_token_successfully() { - Member member = MemberFixture.create(); - AuthToken authToken = AuthToken.of("access", "refresh"); - AuthTokenDto expected = AuthTokenDto.of(member.getId(), authToken.getAccessToken(), authToken.getRefreshToken(), 1L); - - doReturn(member.getId().toString()).when(verifyJwtPortIn).extractSubject(anyString()); - doReturn(REFRESH_TOKEN).when(authTokenRepository).getRefreshToken(member.getId()); - doReturn(authToken).when(createAuthTokenInternalService).create(member.getId()); - doReturn(1L).when(verifyJwtPortIn).extractExpirationTime(anyString()); - - AuthTokenDto actual = sut.update(REFRESH_TOKEN); - - assertThat(actual).usingRecursiveComparison().isEqualTo(expected); - } - - @DisplayName("Refresh 토큰이 null로 들어올 경우 재발급에 실패한다.") - @Test - void renew_refresh_token_with_null() { - assertThatThrownBy(() -> sut.update(null)) - .isInstanceOf(AuthenticationFailException.class) - .hasMessageContaining(AuthErrorCode.MISSING_REFRESH_TOKEN.getMessage()); - } - - @DisplayName("Refresh 토큰이 저장된 값과 다를 경우 재발급에 실패한다.") - @Test - void renew_refresh_token_with_wrong_token() { - Member member = MemberFixture.create(); - doReturn(member.getId().toString()).when(verifyJwtPortIn).extractSubject(anyString()); - doReturn(REFRESH_TOKEN_WRONG).when(authTokenRepository).getRefreshToken(member.getId()); - - assertThatThrownBy(() -> sut.update(REFRESH_TOKEN)) - .isInstanceOf(AuthenticationFailException.class) - .hasMessageContaining(AuthErrorCode.INVALID_REFRESH_TOKEN.getMessage()); - } -} diff --git a/src/test/java/com/gomo/app/support/image/infrastructure/MinioImageAdapterTest.java b/src/test/java/com/gomo/app/support/image/adapter/out/client/MinioImageClientTest.java similarity index 81% rename from src/test/java/com/gomo/app/support/image/infrastructure/MinioImageAdapterTest.java rename to src/test/java/com/gomo/app/support/image/adapter/out/client/MinioImageClientTest.java index f563a7cb..c8d71aa1 100644 --- a/src/test/java/com/gomo/app/support/image/infrastructure/MinioImageAdapterTest.java +++ b/src/test/java/com/gomo/app/support/image/adapter/out/client/MinioImageClientTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.image.infrastructure; +package com.gomo.app.support.image.adapter.out.client; import static com.gomo.app.test.container.MinioContainerInitializer.*; import static org.assertj.core.api.Assertions.*; @@ -21,10 +21,10 @@ @DisplayName("[Infrastructure integration]: minio 시나리오 테스트") @IntegrationTest @WithMinio -class MinioImageAdapterTest { +class MinioImageClientTest { @Autowired - private MinioImageAdapter minioImageAdapter; + private MinioImageClient minioImageClient; private String uploadedImageUrl; @DisplayName("시나리오: 이미지 업로드, 조회, 삭제") @@ -34,7 +34,7 @@ Collection imageManagementDynamicScenario() { return List.of( dynamicTest("1단계: 새로운 이미지를 업로드한다", () -> { - String imageUrl = minioImageAdapter.save(mockFile); + String imageUrl = minioImageClient.save(mockFile); assertThat(imageUrl).isNotNull(); assertThat(imageUrl).contains(TEST_BUCKET_NAME, ".png"); @@ -45,7 +45,7 @@ Collection imageManagementDynamicScenario() { dynamicTest("2단계: 업로드된 이미지가 전체 목록에서 조회된다", () -> { assertThat(this.uploadedImageUrl).as("1단계(업로드)가 먼저 성공해야 한다.").isNotNull(); - Set allImageUrls = minioImageAdapter.findAllImageUrls(); + Set allImageUrls = minioImageClient.findAllImageUrls(); assertThat(allImageUrls).hasSize(1).contains(this.uploadedImageUrl); }), @@ -53,9 +53,9 @@ Collection imageManagementDynamicScenario() { dynamicTest("3단계: 이미지를 삭제하고, 목록에서 사라졌는지 확인한다", () -> { assertThat(this.uploadedImageUrl).as("1단계(업로드)가 먼저 성공해야 한다.").isNotNull(); - assertDoesNotThrow(() -> minioImageAdapter.delete(this.uploadedImageUrl)); + assertDoesNotThrow(() -> minioImageClient.delete(this.uploadedImageUrl)); - Set urlsAfterDeletion = minioImageAdapter.findAllImageUrls(); + Set urlsAfterDeletion = minioImageClient.findAllImageUrls(); assertThat(urlsAfterDeletion).isEmpty(); }) ); diff --git a/src/test/java/com/gomo/app/support/image/application/usecase/UploadImageUseCaseTest.java b/src/test/java/com/gomo/app/support/image/application/service/ImageServiceTest.java similarity index 56% rename from src/test/java/com/gomo/app/support/image/application/usecase/UploadImageUseCaseTest.java rename to src/test/java/com/gomo/app/support/image/application/service/ImageServiceTest.java index 513ed315..ed6ecaea 100644 --- a/src/test/java/com/gomo/app/support/image/application/usecase/UploadImageUseCaseTest.java +++ b/src/test/java/com/gomo/app/support/image/application/service/ImageServiceTest.java @@ -1,9 +1,10 @@ -package com.gomo.app.support.image.application.usecase; +package com.gomo.app.support.image.application.service; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; import java.util.Optional; +import java.util.Set; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -13,24 +14,34 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.mock.web.MockMultipartFile; -import com.gomo.app.support.image.application.port.ManageImagePortOut; +import com.gomo.app.support.image.application.port.out.ImageStore; -@DisplayName("[Application Unit]: 이미지 파일 업로드 테스트") +@DisplayName("[Application Unit]: 이미지 파일 조회 테스트") @ExtendWith(MockitoExtension.class) -class UploadImageUseCaseTest { +class ImageServiceTest { @InjectMocks - private UploadImageUseCase sut; + private ImageService sut; @Mock - private ManageImagePortOut manageImagePortOut; + private ImageStore imageStore; + + @DisplayName("이미지 목록을 조회한다.") + @Test + void read_images() { + doReturn(Set.of("urlA", "urlB")).when(imageStore).findAllImageUrls(); + + Set actual = sut.readAllImages(); + + assertThat(actual.size()).isEqualTo(2); + } @DisplayName("이미지를 업로드한다.") @Test void upload_image() { MockMultipartFile file = new MockMultipartFile("file", "image.jpg", "image/jpeg", "image/jpeg".getBytes()); String imageUrl = "imageUrl"; - doReturn(imageUrl).when(manageImagePortOut).save(any()); + doReturn(imageUrl).when(imageStore).save(any()); Optional actual = sut.upload(file); @@ -45,4 +56,12 @@ void upload_empty_file() { assertThat(actual).isEmpty(); } + + @DisplayName("이미지 파일을 삭제한다.") + @Test + void delete_image() { + sut.delete("imageUrl"); + + verify(imageStore, times(1)).delete(anyString()); + } } diff --git a/src/test/java/com/gomo/app/support/image/application/usecase/DeleteImageUseCaseTest.java b/src/test/java/com/gomo/app/support/image/application/usecase/DeleteImageUseCaseTest.java deleted file mode 100644 index 20b91057..00000000 --- a/src/test/java/com/gomo/app/support/image/application/usecase/DeleteImageUseCaseTest.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.gomo.app.support.image.application.usecase; - -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.support.image.application.port.ManageImagePortOut; - -@DisplayName("[Application Unit]: 이미지 파일 삭제 테스트") -@ExtendWith(MockitoExtension.class) -class DeleteImageUseCaseTest { - - @InjectMocks - private DeleteImageUseCase sut; - - @Mock - private ManageImagePortOut manageImagePortOut; - - @DisplayName("이미지 파일을 삭제한다.") - @Test - void delete_image() { - sut.delete("imageUrl"); - - verify(manageImagePortOut, times(1)).delete(anyString()); - } -} diff --git a/src/test/java/com/gomo/app/support/image/application/usecase/ReadImageUseCaseTest.java b/src/test/java/com/gomo/app/support/image/application/usecase/ReadImageUseCaseTest.java deleted file mode 100644 index 575a6f9f..00000000 --- a/src/test/java/com/gomo/app/support/image/application/usecase/ReadImageUseCaseTest.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.gomo.app.support.image.application.usecase; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.Set; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.support.image.application.port.ManageImagePortOut; - -@DisplayName("[Application Unit]: 이미지 파일 조회 테스트") -@ExtendWith(MockitoExtension.class) -class ReadImageUseCaseTest { - - @InjectMocks - private ReadImageUseCase sut; - - @Mock - private ManageImagePortOut manageImagePortOut; - - @DisplayName("이미지 목록을 조회한다.") - @Test - void read_images() { - doReturn(Set.of("urlA", "urlB")).when(manageImagePortOut).findAllImageUrls(); - - Set actual = sut.readAllImages(); - - assertThat(actual.size()).isEqualTo(2); - } -} diff --git a/src/test/java/com/gomo/app/support/messagebroker/infrastructure/adapter/RabbitMQClientTest.java b/src/test/java/com/gomo/app/support/messagebroker/adapter/out/client/RabbitMQClientTest.java similarity index 95% rename from src/test/java/com/gomo/app/support/messagebroker/infrastructure/adapter/RabbitMQClientTest.java rename to src/test/java/com/gomo/app/support/messagebroker/adapter/out/client/RabbitMQClientTest.java index ba3f97c7..99c0275b 100644 --- a/src/test/java/com/gomo/app/support/messagebroker/infrastructure/adapter/RabbitMQClientTest.java +++ b/src/test/java/com/gomo/app/support/messagebroker/adapter/out/client/RabbitMQClientTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.messagebroker.infrastructure.adapter; +package com.gomo.app.support.messagebroker.adapter.out.client; import static com.gomo.app.test.config.RabbitMQConfig.*; import static org.assertj.core.api.Assertions.*; diff --git a/src/test/java/com/gomo/app/support/messagebroker/infrastructure/adapter/JdbcProcessedDirectEventRepositoryTest.java b/src/test/java/com/gomo/app/support/messagebroker/adapter/out/repository/JdbcProcessedDirectEventRepositoryTest.java similarity index 94% rename from src/test/java/com/gomo/app/support/messagebroker/infrastructure/adapter/JdbcProcessedDirectEventRepositoryTest.java rename to src/test/java/com/gomo/app/support/messagebroker/adapter/out/repository/JdbcProcessedDirectEventRepositoryTest.java index 6b80fe28..ac640a88 100644 --- a/src/test/java/com/gomo/app/support/messagebroker/infrastructure/adapter/JdbcProcessedDirectEventRepositoryTest.java +++ b/src/test/java/com/gomo/app/support/messagebroker/adapter/out/repository/JdbcProcessedDirectEventRepositoryTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.messagebroker.infrastructure.adapter; +package com.gomo.app.support.messagebroker.adapter.out.repository; import static org.assertj.core.api.Assertions.*; diff --git a/src/test/java/com/gomo/app/support/messagebroker/infrastructure/aspect/IdempotentDirectEventConsumerAspectTest.java b/src/test/java/com/gomo/app/support/messagebroker/application/service/IdempotentDirectEventConsumerAspectTest.java similarity index 96% rename from src/test/java/com/gomo/app/support/messagebroker/infrastructure/aspect/IdempotentDirectEventConsumerAspectTest.java rename to src/test/java/com/gomo/app/support/messagebroker/application/service/IdempotentDirectEventConsumerAspectTest.java index d8ed6649..22bc5eb8 100644 --- a/src/test/java/com/gomo/app/support/messagebroker/infrastructure/aspect/IdempotentDirectEventConsumerAspectTest.java +++ b/src/test/java/com/gomo/app/support/messagebroker/application/service/IdempotentDirectEventConsumerAspectTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.messagebroker.infrastructure.aspect; +package com.gomo.app.support.messagebroker.application.service; import static org.assertj.core.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*; @@ -19,7 +19,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionTemplate; -import com.gomo.app.support.messagebroker.application.port.IdempotentDirectEventConsumer; +import com.gomo.app.support.messagebroker.application.port.in.IdempotentDirectEventConsumer; import com.gomo.app.support.messagebroker.domain.model.DirectEvent; import com.gomo.app.support.messagebroker.domain.repository.ProcessedDirectEventRepository; import com.gomo.app.test.IntegrationTest; diff --git a/src/test/java/com/gomo/app/support/messagebroker/application/PublishMessageUseCaseTest.java b/src/test/java/com/gomo/app/support/messagebroker/application/service/MessagePublishServiceTest.java similarity index 60% rename from src/test/java/com/gomo/app/support/messagebroker/application/PublishMessageUseCaseTest.java rename to src/test/java/com/gomo/app/support/messagebroker/application/service/MessagePublishServiceTest.java index 4e6f2e4c..b160bbf8 100644 --- a/src/test/java/com/gomo/app/support/messagebroker/application/PublishMessageUseCaseTest.java +++ b/src/test/java/com/gomo/app/support/messagebroker/application/service/MessagePublishServiceTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.messagebroker.application; +package com.gomo.app.support.messagebroker.application.service; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; @@ -10,22 +10,22 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import com.gomo.app.support.messagebroker.application.port.MessageBrokerClientPortOut; +import com.gomo.app.support.messagebroker.application.port.out.MessageBrokerManager; @DisplayName("[Application Unit]: 메시지 발행 테스트") @ExtendWith(MockitoExtension.class) -class PublishMessageUseCaseTest { +class MessagePublishServiceTest { @InjectMocks - private PublishMessageUseCase sut; + private MessagePublishService sut; @Mock - private MessageBrokerClientPortOut messageBrokerClientPortOut; + private MessageBrokerManager messageBrokerManager; @DisplayName("이벤트를 발행한다.") @Test void process_event_entry() { sut.send("destination", "key", "message"); - verify(messageBrokerClientPortOut, times(1)).send(anyString(), anyString(), anyString()); + verify(messageBrokerManager, times(1)).send(anyString(), anyString(), anyString()); } } diff --git a/src/test/java/com/gomo/app/test/DocumentationTestBase.java b/src/test/java/com/gomo/app/test/DocumentationTestBase.java index b405d1b2..94bad9a4 100644 --- a/src/test/java/com/gomo/app/test/DocumentationTestBase.java +++ b/src/test/java/com/gomo/app/test/DocumentationTestBase.java @@ -17,15 +17,14 @@ import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; -import com.gomo.app.common.security.jwt.application.port.GenerateJwtPortIn; import com.gomo.app.core.member.domain.model.LoginProvider; import com.gomo.app.core.member.domain.repository.MemberRepository; -import com.gomo.app.core.member.presentation.MemberApi; -import com.gomo.app.core.member.presentation.request.CreateMemberRequest; -import com.gomo.app.support.auth.presentation.api.AuthApi; -import com.gomo.app.support.auth.presentation.request.LoginRequest; -import com.gomo.app.support.auth.presentation.response.AccessTokenResponse; -import com.gomo.app.support.auth.presentation.security.AuthInfo; +import com.gomo.app.core.auth.adapter.in.api.AuthApi; +import com.gomo.app.core.auth.adapter.in.api.request.CreatePrincipalRequest; +import com.gomo.app.core.auth.adapter.in.api.request.LoginRequest; +import com.gomo.app.core.auth.adapter.in.api.response.AccessTokenResponse; +import com.gomo.app.core.auth.adapter.in.security.AuthInfo; +import com.gomo.app.core.auth.application.port.out.JwtCreator; import com.google.common.net.HttpHeaders; import io.restassured.builder.RequestSpecBuilder; @@ -41,10 +40,7 @@ public abstract class DocumentationTestBase { protected RequestSpecification specification; @Autowired - protected MemberApi memberApi; - - @Autowired - protected GenerateJwtPortIn generateJwtPortIn; + protected JwtCreator jwtCreator; @Autowired protected AuthApi authApi; @@ -81,8 +77,8 @@ void tearDown() { } protected void signup(String email, String password, String handle) { - String temporaryToken = generateJwtPortIn.generateTemporaryToken(email, 300); - memberApi.create(CreateMemberRequest.of(email, password, handle, "testname", "testmotto", LoginProvider.EMAIL.name(), temporaryToken)); + String temporaryToken = jwtCreator.createTemporaryToken(email, 300); + authApi.signup(CreatePrincipalRequest.of(email, password, handle, "testname", "testmotto", LoginProvider.EMAIL.name(), temporaryToken)); } protected ResponseEntity login(String email, String password) { From 2e3e5e48eda868961a1ff84fe4fe4784441adb20 Mon Sep 17 00:00:00 2001 From: Junhyeok Lee Date: Tue, 4 Nov 2025 13:45:32 +0900 Subject: [PATCH 12/16] =?UTF-8?q?[GOMO-239]=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=EC=A3=BC=EC=9E=85=20=EB=B0=A9=EC=8B=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#102)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AuthInfo를 SessionInfo로 변경 - 인증 정보를 주입하는 resolver를 공통 세션 모듈로 이전 --- .../Auth.java => common/session/Session.java} | 4 ++-- .../session/SessionArgumentResolver.java} | 20 +++++++++--------- .../gomo/app/common/session/SessionInfo.java | 21 +++++++++++++++++++ .../FilterRegistrationConfiguration.java | 2 +- .../com/gomo/app/config/WebConfiguration.java | 6 +++--- .../app/core/auth/adapter/in/api/AuthApi.java | 8 +++---- .../AuthenticationFilter.java | 11 +++++----- .../auth/adapter/in/security/AuthInfo.java | 19 ----------------- .../interest/adapter/in/api/InterestApi.java | 20 +++++++++--------- .../adapter/in/api/InterestNetworkApi.java | 16 +++++++------- .../adapter/in/api/MajorInterestApi.java | 16 +++++++------- .../in/api/OrderUpdateMajorInterestApi.java | 8 +++---- .../core/member/adapter/in/api/HandleApi.java | 8 +++---- .../core/member/adapter/in/api/MemberApi.java | 16 +++++++------- .../member/adapter/in/api/PasswordApi.java | 8 +++---- .../adapter/in/api/ProfileBannerApi.java | 12 +++++------ .../adapter/in/api/ProfileImageApi.java | 12 +++++------ .../adapter/in/api/QuestPropertyApi.java | 12 +++++------ .../core/member/adapter/in/api/WidgetApi.java | 8 +++---- .../core/point/adapter/in/api/PointApi.java | 12 +++++------ .../quest/adapter/in/api/AssignQuestApi.java | 20 +++++++++--------- .../in/api/CalendarAssignQuestApi.java | 8 +++---- .../in/api/CompleteAssignQuestApi.java | 8 +++---- .../adapter/in/api/ConfirmAssignQuestApi.java | 8 +++---- .../in/api/OrderUpdateAssignQuestApi.java | 8 +++---- .../in/api/OrderUpdateRepeatQuestApi.java | 8 +++---- .../adapter/in/api/ReRollAssignQuestApi.java | 8 +++---- .../quest/adapter/in/api/RepeatQuestApi.java | 20 +++++++++--------- .../streak/adapter/in/api/AchieverApi.java | 8 +++---- .../core/streak/adapter/in/api/StreakApi.java | 8 +++---- .../core/survey/adapter/in/api/SurveyApi.java | 8 +++---- .../web/ApplicationExceptionAdviceTest.java | 2 +- ...eateInterestRelationDocumentationTest.java | 2 +- .../CreateMajorInterestDocumentationTest.java | 4 ++-- .../api/DeleteInterestDocumentationTest.java | 2 +- ...leteInterestRelationDocumentationTest.java | 4 ++-- .../DeleteMajorInterestDocumentationTest.java | 4 ++-- .../api/InterestNetworkDocumentationTest.java | 4 ++-- .../in/api/ListInterestDocumentationTest.java | 2 +- .../ListMajorInterestDocumentationTest.java | 4 ++-- ...rUpdateMajorInterestDocumentationTest.java | 4 ++-- .../in/api/ReadInterestDocumentationTest.java | 2 +- .../api/UpdateInterestDocumentationTest.java | 2 +- .../UpdateInterestLogoDocumentationTest.java | 2 +- .../CreateAssignQuestDocumentationTest.java | 6 +++--- .../CreateRepeatQuestDocumentationTest.java | 8 +++---- .../DeleteRepeatQuestDocumentationTest.java | 2 +- .../api/ListRepeatQuestDocumentationTest.java | 6 +++--- .../UpdateRepeatQuestDocumentationTest.java | 4 ++-- .../gomo/app/test/DocumentationTestBase.java | 10 ++++----- 50 files changed, 214 insertions(+), 211 deletions(-) rename src/main/java/com/gomo/app/{core/auth/adapter/in/security/Auth.java => common/session/Session.java} (75%) rename src/main/java/com/gomo/app/{core/auth/adapter/in/security/AuthArgumentResolver.java => common/session/SessionArgumentResolver.java} (56%) create mode 100644 src/main/java/com/gomo/app/common/session/SessionInfo.java rename src/main/java/com/gomo/app/core/auth/adapter/in/{security => filter}/AuthenticationFilter.java (82%) delete mode 100644 src/main/java/com/gomo/app/core/auth/adapter/in/security/AuthInfo.java diff --git a/src/main/java/com/gomo/app/core/auth/adapter/in/security/Auth.java b/src/main/java/com/gomo/app/common/session/Session.java similarity index 75% rename from src/main/java/com/gomo/app/core/auth/adapter/in/security/Auth.java rename to src/main/java/com/gomo/app/common/session/Session.java index 40055c24..73898a70 100644 --- a/src/main/java/com/gomo/app/core/auth/adapter/in/security/Auth.java +++ b/src/main/java/com/gomo/app/common/session/Session.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.auth.adapter.in.security; +package com.gomo.app.common.session; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -7,5 +7,5 @@ @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) -public @interface Auth { +public @interface Session { } diff --git a/src/main/java/com/gomo/app/core/auth/adapter/in/security/AuthArgumentResolver.java b/src/main/java/com/gomo/app/common/session/SessionArgumentResolver.java similarity index 56% rename from src/main/java/com/gomo/app/core/auth/adapter/in/security/AuthArgumentResolver.java rename to src/main/java/com/gomo/app/common/session/SessionArgumentResolver.java index 27d27be3..8c129369 100644 --- a/src/main/java/com/gomo/app/core/auth/adapter/in/security/AuthArgumentResolver.java +++ b/src/main/java/com/gomo/app/common/session/SessionArgumentResolver.java @@ -1,6 +1,8 @@ -package com.gomo.app.core.auth.adapter.in.security; +package com.gomo.app.common.session; -import jakarta.servlet.http.HttpServletRequest; +import static com.gomo.app.common.session.SessionInfo.*; + +import java.util.UUID; import org.springframework.core.MethodParameter; import org.springframework.stereotype.Component; @@ -9,21 +11,19 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; -import java.util.UUID; +import jakarta.servlet.http.HttpServletRequest; @Component -public class AuthArgumentResolver implements HandlerMethodArgumentResolver { +public class SessionArgumentResolver implements HandlerMethodArgumentResolver { + @Override public boolean supportsParameter(MethodParameter parameter) { - return parameter.hasParameterAnnotation(Auth.class); + return parameter.hasParameterAnnotation(Session.class); } @Override - public Object resolveArgument(MethodParameter parameter, - ModelAndViewContainer mavContainer, - NativeWebRequest webRequest, - WebDataBinderFactory binderFactory) { + public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) { HttpServletRequest request = (HttpServletRequest)webRequest.getNativeRequest(); - return AuthInfo.of(UUID.fromString((String)request.getAttribute("memberId"))); + return SessionInfo.of(UUID.fromString((String)request.getAttribute(SESSION_PRINCIPAL_ID))); } } diff --git a/src/main/java/com/gomo/app/common/session/SessionInfo.java b/src/main/java/com/gomo/app/common/session/SessionInfo.java new file mode 100644 index 00000000..d6c0f8fd --- /dev/null +++ b/src/main/java/com/gomo/app/common/session/SessionInfo.java @@ -0,0 +1,21 @@ +package com.gomo.app.common.session; + +import java.util.UUID; + +import lombok.Getter; + +@Getter +public class SessionInfo { + + public static final String SESSION_PRINCIPAL_ID = "principalId"; + + private UUID principalId; + + private SessionInfo(UUID principalId) { + this.principalId = principalId; + } + + public static SessionInfo of(UUID principalId) { + return new SessionInfo(principalId); + } +} diff --git a/src/main/java/com/gomo/app/config/FilterRegistrationConfiguration.java b/src/main/java/com/gomo/app/config/FilterRegistrationConfiguration.java index faec657b..96de7988 100644 --- a/src/main/java/com/gomo/app/config/FilterRegistrationConfiguration.java +++ b/src/main/java/com/gomo/app/config/FilterRegistrationConfiguration.java @@ -10,7 +10,7 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; -import com.gomo.app.core.auth.adapter.in.security.AuthenticationFilter; +import com.gomo.app.core.auth.adapter.in.filter.AuthenticationFilter; import com.gomo.app.support.logging.LoggingFilter; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/com/gomo/app/config/WebConfiguration.java b/src/main/java/com/gomo/app/config/WebConfiguration.java index b02bb4fc..41d36129 100644 --- a/src/main/java/com/gomo/app/config/WebConfiguration.java +++ b/src/main/java/com/gomo/app/config/WebConfiguration.java @@ -7,8 +7,8 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import com.gomo.app.common.session.SessionArgumentResolver; import com.gomo.app.common.web.OctetStreamReadMsgConverter; -import com.gomo.app.core.auth.adapter.in.security.AuthArgumentResolver; import lombok.RequiredArgsConstructor; @@ -16,12 +16,12 @@ @RequiredArgsConstructor public class WebConfiguration implements WebMvcConfigurer { - private final AuthArgumentResolver authArgumentResolver; + private final SessionArgumentResolver sessionArgumentResolver; private final OctetStreamReadMsgConverter octetStreamReadMsgConverter; @Override public void addArgumentResolvers(List resolvers) { - resolvers.add(authArgumentResolver); + resolvers.add(sessionArgumentResolver); } @Override diff --git a/src/main/java/com/gomo/app/core/auth/adapter/in/api/AuthApi.java b/src/main/java/com/gomo/app/core/auth/adapter/in/api/AuthApi.java index 17fec369..235ad35d 100644 --- a/src/main/java/com/gomo/app/core/auth/adapter/in/api/AuthApi.java +++ b/src/main/java/com/gomo/app/core/auth/adapter/in/api/AuthApi.java @@ -16,12 +16,12 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.common.session.Session; +import com.gomo.app.common.session.SessionInfo; import com.gomo.app.core.auth.adapter.in.api.request.CreatePrincipalRequest; import com.gomo.app.core.auth.adapter.in.api.request.LoginRequest; import com.gomo.app.core.auth.adapter.in.api.response.AccessTokenResponse; import com.gomo.app.core.auth.adapter.in.api.response.CreatePrincipalResponse; -import com.gomo.app.core.auth.adapter.in.security.Auth; -import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import com.gomo.app.core.auth.application.port.dto.AuthTokenDto; import com.gomo.app.core.auth.application.port.in.LoginProcessor; import com.gomo.app.core.auth.application.port.in.RefreshTokenDeleter; @@ -63,8 +63,8 @@ public ResponseEntity refresh(@CookieValue(name = "refreshT } @GetMapping("/logout") - public ResponseEntity logout(@Auth AuthInfo authInfo) { - refreshTokenDeleter.delete(authInfo.getPrincipalId()); + public ResponseEntity logout(@Session SessionInfo sessionInfo) { + refreshTokenDeleter.delete(sessionInfo.getPrincipalId()); ResponseCookie cookie = createResponseCookie("", 0); return ResponseEntity.ok().header(HttpHeaders.SET_COOKIE, cookie.toString()).build(); } diff --git a/src/main/java/com/gomo/app/core/auth/adapter/in/security/AuthenticationFilter.java b/src/main/java/com/gomo/app/core/auth/adapter/in/filter/AuthenticationFilter.java similarity index 82% rename from src/main/java/com/gomo/app/core/auth/adapter/in/security/AuthenticationFilter.java rename to src/main/java/com/gomo/app/core/auth/adapter/in/filter/AuthenticationFilter.java index 84d004a4..a9ea646c 100644 --- a/src/main/java/com/gomo/app/core/auth/adapter/in/security/AuthenticationFilter.java +++ b/src/main/java/com/gomo/app/core/auth/adapter/in/filter/AuthenticationFilter.java @@ -1,5 +1,6 @@ -package com.gomo.app.core.auth.adapter.in.security; +package com.gomo.app.core.auth.adapter.in.filter; +import static com.gomo.app.common.session.SessionInfo.*; import static com.gomo.app.support.logging.MDC.*; import java.io.IOException; @@ -55,10 +56,10 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse } try { token = token.substring(BEARER_TOKEN.length()); - String memberId = jwtVerifier.extractSubject(token); - MDC.put(MEMBER_ID.name(), memberId); - log.info("action=MEMBER_AUTHENTICATION, status=success, memberId={}", memberId); - request.setAttribute("memberId", memberId); + String principalId = jwtVerifier.extractSubject(token); + MDC.put(MEMBER_ID.name(), principalId); + log.info("action=PRINCIPAL_AUTHENTICATION, status=success, principalId={}", principalId); + request.setAttribute(SESSION_PRINCIPAL_ID, principalId); } catch (JwtException e) { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.getWriter().write("Invalid or Expired JWT Token"); diff --git a/src/main/java/com/gomo/app/core/auth/adapter/in/security/AuthInfo.java b/src/main/java/com/gomo/app/core/auth/adapter/in/security/AuthInfo.java deleted file mode 100644 index fca7ec61..00000000 --- a/src/main/java/com/gomo/app/core/auth/adapter/in/security/AuthInfo.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.gomo.app.core.auth.adapter.in.security; - -import java.util.UUID; - -import lombok.Getter; - -@Getter -public class AuthInfo { - - private UUID principalId; - - private AuthInfo(UUID principalId) { - this.principalId = principalId; - } - - public static AuthInfo of(UUID principalId) { - return new AuthInfo(principalId); - } -} diff --git a/src/main/java/com/gomo/app/core/interest/adapter/in/api/InterestApi.java b/src/main/java/com/gomo/app/core/interest/adapter/in/api/InterestApi.java index 744f77d1..6879073b 100644 --- a/src/main/java/com/gomo/app/core/interest/adapter/in/api/InterestApi.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/InterestApi.java @@ -17,6 +17,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.common.session.Session; +import com.gomo.app.common.session.SessionInfo; import com.gomo.app.core.interest.adapter.in.api.request.CreateInterestRequest; import com.gomo.app.core.interest.adapter.in.api.request.UpdateInterestRequest; import com.gomo.app.core.interest.adapter.in.api.response.CreateInterestResponse; @@ -27,8 +29,6 @@ import com.gomo.app.core.interest.application.port.in.InterestDeleter; import com.gomo.app.core.interest.application.port.in.InterestReader; import com.gomo.app.core.interest.application.port.in.InterestUpdater; -import com.gomo.app.core.auth.adapter.in.security.Auth; -import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -43,8 +43,8 @@ public class InterestApi { private final InterestDeleter interestDeleter; @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public ResponseEntity create(@Auth AuthInfo authInfo, @ModelAttribute CreateInterestRequest request) { - UUID interestId = interestCreator.create(request.toCommand(authInfo.getPrincipalId())); + public ResponseEntity create(@Session SessionInfo sessionInfo, @ModelAttribute CreateInterestRequest request) { + UUID interestId = interestCreator.create(request.toCommand(sessionInfo.getPrincipalId())); return ResponseEntity.status(CREATED).body(CreateInterestResponse.of(interestId)); } @@ -55,22 +55,22 @@ public ResponseEntity find(@PathVariable("id") UUID intere } @GetMapping - public ResponseEntity list(@Auth AuthInfo authInfo) { - List responses = interestReader.readAll(authInfo.getPrincipalId()).stream() + public ResponseEntity list(@Session SessionInfo sessionInfo) { + List responses = interestReader.readAll(sessionInfo.getPrincipalId()).stream() .map(ReadInterestResponse::from) .toList(); return ResponseEntity.status(OK).body(ListInterestResponse.of(responses)); } @PutMapping("/{id}") - public ResponseEntity update(@Auth AuthInfo authInfo, @PathVariable("id") UUID interestId, @RequestBody UpdateInterestRequest request) { - interestUpdater.update(request.toCommand(authInfo.getPrincipalId(), interestId)); + public ResponseEntity update(@Session SessionInfo sessionInfo, @PathVariable("id") UUID interestId, @RequestBody UpdateInterestRequest request) { + interestUpdater.update(request.toCommand(sessionInfo.getPrincipalId(), interestId)); return ResponseEntity.noContent().build(); } @DeleteMapping("/{id}") - public ResponseEntity delete(@Auth AuthInfo authInfo, @PathVariable("id") UUID interestId) { - interestDeleter.delete(authInfo.getPrincipalId(), interestId); + public ResponseEntity delete(@Session SessionInfo sessionInfo, @PathVariable("id") UUID interestId) { + interestDeleter.delete(sessionInfo.getPrincipalId(), interestId); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/interest/adapter/in/api/InterestNetworkApi.java b/src/main/java/com/gomo/app/core/interest/adapter/in/api/InterestNetworkApi.java index ae0394c3..e4899efc 100644 --- a/src/main/java/com/gomo/app/core/interest/adapter/in/api/InterestNetworkApi.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/InterestNetworkApi.java @@ -13,6 +13,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.common.session.Session; +import com.gomo.app.common.session.SessionInfo; import com.gomo.app.core.interest.adapter.in.api.request.CreateInterestRelationRequest; import com.gomo.app.core.interest.adapter.in.api.response.CreateInterestRelationResponse; import com.gomo.app.core.interest.adapter.in.api.response.InterestNetworkResponse; @@ -20,8 +22,6 @@ import com.gomo.app.core.interest.application.port.in.InterestNetworkReader; import com.gomo.app.core.interest.application.port.in.InterestRelationCreator; import com.gomo.app.core.interest.application.port.in.InterestRelationDeleter; -import com.gomo.app.core.auth.adapter.in.security.Auth; -import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -35,20 +35,20 @@ public class InterestNetworkApi { private final InterestRelationDeleter interestRelationDeleter; @PostMapping("/relations") - public ResponseEntity createRelation(@Auth AuthInfo authInfo, @RequestBody CreateInterestRelationRequest request) { - UUID relationId = interestRelationCreator.create(authInfo.getPrincipalId(), request.getParentInterestId(), request.getChildInterestId()); + public ResponseEntity createRelation(@Session SessionInfo sessionInfo, @RequestBody CreateInterestRelationRequest request) { + UUID relationId = interestRelationCreator.create(sessionInfo.getPrincipalId(), request.getParentInterestId(), request.getChildInterestId()); return ResponseEntity.status(CREATED).body(CreateInterestRelationResponse.of(relationId)); } @GetMapping - public ResponseEntity find(@Auth AuthInfo authInfo) { - InterestNetworkDto interestNetworkDto = interestNetworkReader.read(authInfo.getPrincipalId()); + public ResponseEntity find(@Session SessionInfo sessionInfo) { + InterestNetworkDto interestNetworkDto = interestNetworkReader.read(sessionInfo.getPrincipalId()); return ResponseEntity.ok(InterestNetworkResponse.from(interestNetworkDto)); } @DeleteMapping("/relations/{id}") - public ResponseEntity deleteRelation(@Auth AuthInfo authInfo, @PathVariable("id") UUID interestRelationId) { - interestRelationDeleter.delete(authInfo.getPrincipalId(), interestRelationId); + public ResponseEntity deleteRelation(@Session SessionInfo sessionInfo, @PathVariable("id") UUID interestRelationId) { + interestRelationDeleter.delete(sessionInfo.getPrincipalId(), interestRelationId); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/interest/adapter/in/api/MajorInterestApi.java b/src/main/java/com/gomo/app/core/interest/adapter/in/api/MajorInterestApi.java index 7807ddb5..7aafff1e 100644 --- a/src/main/java/com/gomo/app/core/interest/adapter/in/api/MajorInterestApi.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/MajorInterestApi.java @@ -13,14 +13,14 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.common.session.Session; +import com.gomo.app.common.session.SessionInfo; import com.gomo.app.core.interest.adapter.in.api.response.CreateMajorInterestResponse; import com.gomo.app.core.interest.adapter.in.api.response.ListMajorInterestResponse; import com.gomo.app.core.interest.application.port.dto.MajorInterestDto; import com.gomo.app.core.interest.application.port.in.MajorInterestCreator; import com.gomo.app.core.interest.application.port.in.MajorInterestDeleter; import com.gomo.app.core.interest.application.port.in.MajorInterestReader; -import com.gomo.app.core.auth.adapter.in.security.Auth; -import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -34,20 +34,20 @@ public class MajorInterestApi { private final MajorInterestDeleter majorInterestDeleter; @PostMapping("/{id}/majors") - public ResponseEntity create(@Auth AuthInfo authInfo, @PathVariable("id") UUID interestId) { - UUID majorInterestId = majorInterestCreator.create(authInfo.getPrincipalId(), interestId); + public ResponseEntity create(@Session SessionInfo sessionInfo, @PathVariable("id") UUID interestId) { + UUID majorInterestId = majorInterestCreator.create(sessionInfo.getPrincipalId(), interestId); return ResponseEntity.status(CREATED).body(CreateMajorInterestResponse.of(majorInterestId)); } @GetMapping("/majors") - public ResponseEntity findAll(@Auth AuthInfo authInfo) { - List dtos = majorInterestReader.readAll(authInfo.getPrincipalId()); + public ResponseEntity findAll(@Session SessionInfo sessionInfo) { + List dtos = majorInterestReader.readAll(sessionInfo.getPrincipalId()); return ResponseEntity.ok(ListMajorInterestResponse.of(dtos)); } @DeleteMapping("/majors/{id}") - public ResponseEntity delete(@Auth AuthInfo authInfo, @PathVariable("id") UUID majorInterestId) { - majorInterestDeleter.delete(authInfo.getPrincipalId(), majorInterestId); + public ResponseEntity delete(@Session SessionInfo sessionInfo, @PathVariable("id") UUID majorInterestId) { + majorInterestDeleter.delete(sessionInfo.getPrincipalId(), majorInterestId); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/interest/adapter/in/api/OrderUpdateMajorInterestApi.java b/src/main/java/com/gomo/app/core/interest/adapter/in/api/OrderUpdateMajorInterestApi.java index c3adf122..91ce5cdf 100644 --- a/src/main/java/com/gomo/app/core/interest/adapter/in/api/OrderUpdateMajorInterestApi.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/OrderUpdateMajorInterestApi.java @@ -6,10 +6,10 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.common.session.Session; +import com.gomo.app.common.session.SessionInfo; import com.gomo.app.core.interest.adapter.in.api.request.OrderUpdateMajorInterestRequest; import com.gomo.app.core.interest.application.port.in.MajorInterestOrderUpdater; -import com.gomo.app.core.auth.adapter.in.security.Auth; -import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -21,8 +21,8 @@ public class OrderUpdateMajorInterestApi { private final MajorInterestOrderUpdater majorInterestOrderUpdater; @PutMapping - public ResponseEntity update(@Auth AuthInfo authInfo, @RequestBody OrderUpdateMajorInterestRequest request) { - majorInterestOrderUpdater.update(request.toCommand(authInfo.getPrincipalId())); + public ResponseEntity update(@Session SessionInfo sessionInfo, @RequestBody OrderUpdateMajorInterestRequest request) { + majorInterestOrderUpdater.update(request.toCommand(sessionInfo.getPrincipalId())); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/member/adapter/in/api/HandleApi.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/HandleApi.java index 2e27104f..96e67110 100644 --- a/src/main/java/com/gomo/app/core/member/adapter/in/api/HandleApi.java +++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/HandleApi.java @@ -8,11 +8,11 @@ import org.springframework.web.bind.annotation.RequestParam; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.common.session.Session; +import com.gomo.app.common.session.SessionInfo; import com.gomo.app.core.member.adapter.in.api.request.UpdateHandleRequest; import com.gomo.app.core.member.application.port.in.HandleUpdater; import com.gomo.app.core.member.application.port.in.HandleValidator; -import com.gomo.app.core.auth.adapter.in.security.Auth; -import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -31,8 +31,8 @@ public ResponseEntity checkHandleDuplicated(@RequestParam String handle) { } @PutMapping - public ResponseEntity update(@Auth AuthInfo authInfo, @RequestBody UpdateHandleRequest request) { - handleUpdater.update(authInfo.getPrincipalId(), request.getHandle()); + public ResponseEntity update(@Session SessionInfo sessionInfo, @RequestBody UpdateHandleRequest request) { + handleUpdater.update(sessionInfo.getPrincipalId(), request.getHandle()); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/member/adapter/in/api/MemberApi.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/MemberApi.java index 028eb6be..64483db3 100644 --- a/src/main/java/com/gomo/app/core/member/adapter/in/api/MemberApi.java +++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/MemberApi.java @@ -8,14 +8,14 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.common.session.Session; +import com.gomo.app.common.session.SessionInfo; import com.gomo.app.core.member.adapter.in.api.request.UpdateMemberRequest; import com.gomo.app.core.member.adapter.in.api.response.ReadMemberResponse; import com.gomo.app.core.member.application.port.dto.MemberDto; import com.gomo.app.core.member.application.port.in.MemberDeleter; import com.gomo.app.core.member.application.port.in.MemberReader; import com.gomo.app.core.member.application.port.in.MemberUpdater; -import com.gomo.app.core.auth.adapter.in.security.Auth; -import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -29,20 +29,20 @@ public class MemberApi { private final MemberDeleter memberDeleter; @GetMapping - public ResponseEntity read(@Auth AuthInfo authInfo) { - MemberDto dto = memberReader.read(authInfo.getPrincipalId()); + public ResponseEntity read(@Session SessionInfo sessionInfo) { + MemberDto dto = memberReader.read(sessionInfo.getPrincipalId()); return ResponseEntity.ok(ReadMemberResponse.of(dto)); } @PutMapping - public ResponseEntity update(@Auth AuthInfo authInfo, @RequestBody UpdateMemberRequest request) { - memberUpdater.update(authInfo.getPrincipalId(), request.getName(), request.getMotto()); + public ResponseEntity update(@Session SessionInfo sessionInfo, @RequestBody UpdateMemberRequest request) { + memberUpdater.update(sessionInfo.getPrincipalId(), request.getName(), request.getMotto()); return ResponseEntity.noContent().build(); } @DeleteMapping - public ResponseEntity delete(@Auth AuthInfo authInfo) { - memberDeleter.delete(authInfo.getPrincipalId()); + public ResponseEntity delete(@Session SessionInfo sessionInfo) { + memberDeleter.delete(sessionInfo.getPrincipalId()); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/member/adapter/in/api/PasswordApi.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/PasswordApi.java index fe7cbb01..31603d95 100644 --- a/src/main/java/com/gomo/app/core/member/adapter/in/api/PasswordApi.java +++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/PasswordApi.java @@ -6,12 +6,12 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.common.session.Session; +import com.gomo.app.common.session.SessionInfo; import com.gomo.app.core.member.adapter.in.api.request.ResetPasswordRequest; import com.gomo.app.core.member.adapter.in.api.request.UpdatePasswordRequest; import com.gomo.app.core.member.application.port.in.PasswordResetter; import com.gomo.app.core.member.application.port.in.PasswordUpdater; -import com.gomo.app.core.auth.adapter.in.security.Auth; -import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -24,8 +24,8 @@ public class PasswordApi { private final PasswordResetter passwordResetter; @PutMapping - public ResponseEntity update(@Auth AuthInfo authInfo, @RequestBody UpdatePasswordRequest request) { - passwordUpdater.update(authInfo.getPrincipalId(), request.getOriginPassword(), request.getNewPassword()); + public ResponseEntity update(@Session SessionInfo sessionInfo, @RequestBody UpdatePasswordRequest request) { + passwordUpdater.update(sessionInfo.getPrincipalId(), request.getOriginPassword(), request.getNewPassword()); return ResponseEntity.noContent().build(); } diff --git a/src/main/java/com/gomo/app/core/member/adapter/in/api/ProfileBannerApi.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/ProfileBannerApi.java index 9ff540fe..76e7a1e1 100644 --- a/src/main/java/com/gomo/app/core/member/adapter/in/api/ProfileBannerApi.java +++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/ProfileBannerApi.java @@ -8,11 +8,11 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.common.session.Session; +import com.gomo.app.common.session.SessionInfo; import com.gomo.app.core.member.adapter.in.api.request.UpdateProfileBannerRequest; import com.gomo.app.core.member.application.port.in.ProfileBannerDeleter; import com.gomo.app.core.member.application.port.in.ProfileBannerUpdater; -import com.gomo.app.core.auth.adapter.in.security.Auth; -import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -25,14 +25,14 @@ public class ProfileBannerApi { private final ProfileBannerDeleter profileBannerDeleter; @PutMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public ResponseEntity update(@Auth AuthInfo authInfo, @ModelAttribute UpdateProfileBannerRequest request) { - profileBannerUpdater.update(authInfo.getPrincipalId(), request.getProfileBanner()); + public ResponseEntity update(@Session SessionInfo sessionInfo, @ModelAttribute UpdateProfileBannerRequest request) { + profileBannerUpdater.update(sessionInfo.getPrincipalId(), request.getProfileBanner()); return ResponseEntity.noContent().build(); } @DeleteMapping - public ResponseEntity delete(@Auth AuthInfo authInfo) { - profileBannerDeleter.delete(authInfo.getPrincipalId()); + public ResponseEntity delete(@Session SessionInfo sessionInfo) { + profileBannerDeleter.delete(sessionInfo.getPrincipalId()); return ResponseEntity.ok().build(); } } diff --git a/src/main/java/com/gomo/app/core/member/adapter/in/api/ProfileImageApi.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/ProfileImageApi.java index cc673a20..78f3068f 100644 --- a/src/main/java/com/gomo/app/core/member/adapter/in/api/ProfileImageApi.java +++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/ProfileImageApi.java @@ -8,11 +8,11 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.common.session.Session; +import com.gomo.app.common.session.SessionInfo; import com.gomo.app.core.member.adapter.in.api.request.UpdateProfileImageRequest; import com.gomo.app.core.member.application.port.in.ProfileImageDeleter; import com.gomo.app.core.member.application.port.in.ProfileImageUpdater; -import com.gomo.app.core.auth.adapter.in.security.Auth; -import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -25,14 +25,14 @@ public class ProfileImageApi { private final ProfileImageDeleter profileImageDeleter; @PutMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public ResponseEntity update(@Auth AuthInfo authInfo, @ModelAttribute UpdateProfileImageRequest request) { - profileImageUpdater.update(authInfo.getPrincipalId(), request.getProfileImage()); + public ResponseEntity update(@Session SessionInfo sessionInfo, @ModelAttribute UpdateProfileImageRequest request) { + profileImageUpdater.update(sessionInfo.getPrincipalId(), request.getProfileImage()); return ResponseEntity.noContent().build(); } @DeleteMapping - public ResponseEntity delete(@Auth AuthInfo authInfo) { - profileImageDeleter.delete(authInfo.getPrincipalId()); + public ResponseEntity delete(@Session SessionInfo sessionInfo) { + profileImageDeleter.delete(sessionInfo.getPrincipalId()); return ResponseEntity.ok().build(); } } diff --git a/src/main/java/com/gomo/app/core/member/adapter/in/api/QuestPropertyApi.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/QuestPropertyApi.java index f9019c49..2dbf945a 100644 --- a/src/main/java/com/gomo/app/core/member/adapter/in/api/QuestPropertyApi.java +++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/QuestPropertyApi.java @@ -7,13 +7,13 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.common.session.Session; +import com.gomo.app.common.session.SessionInfo; import com.gomo.app.core.member.adapter.in.api.request.UpdateQuestPropertyRequest; import com.gomo.app.core.member.adapter.in.api.response.ReadQuestPropertyResponse; import com.gomo.app.core.member.application.port.dto.QuestPropertyDto; import com.gomo.app.core.member.application.port.in.QuestPropertyReader; import com.gomo.app.core.member.application.port.in.QuestPropertyUpdater; -import com.gomo.app.core.auth.adapter.in.security.Auth; -import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -26,14 +26,14 @@ public class QuestPropertyApi { private final QuestPropertyUpdater questPropertyUpdater; @GetMapping - public ResponseEntity find(@Auth AuthInfo authInfo) { - QuestPropertyDto dto = questPropertyReader.read(authInfo.getPrincipalId()); + public ResponseEntity find(@Session SessionInfo sessionInfo) { + QuestPropertyDto dto = questPropertyReader.read(sessionInfo.getPrincipalId()); return ResponseEntity.ok(ReadQuestPropertyResponse.of(dto)); } @PutMapping - public ResponseEntity update(@Auth AuthInfo authInfo, @RequestBody UpdateQuestPropertyRequest request) { - questPropertyUpdater.update(request.toCommand(authInfo.getPrincipalId())); + public ResponseEntity update(@Session SessionInfo sessionInfo, @RequestBody UpdateQuestPropertyRequest request) { + questPropertyUpdater.update(request.toCommand(sessionInfo.getPrincipalId())); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/member/adapter/in/api/WidgetApi.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/WidgetApi.java index ecb23dbc..6e1f7857 100644 --- a/src/main/java/com/gomo/app/core/member/adapter/in/api/WidgetApi.java +++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/WidgetApi.java @@ -6,10 +6,10 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.common.session.Session; +import com.gomo.app.common.session.SessionInfo; import com.gomo.app.core.member.adapter.in.api.request.UpdateWidgetRequest; import com.gomo.app.core.member.application.port.in.WidgetUpdater; -import com.gomo.app.core.auth.adapter.in.security.Auth; -import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -21,8 +21,8 @@ public class WidgetApi { private final WidgetUpdater widgetUpdater; @PutMapping - public ResponseEntity update(@Auth AuthInfo authInfo, @RequestBody UpdateWidgetRequest request) { - widgetUpdater.update(authInfo.getPrincipalId(), request.getSnapshot()); + public ResponseEntity update(@Session SessionInfo sessionInfo, @RequestBody UpdateWidgetRequest request) { + widgetUpdater.update(sessionInfo.getPrincipalId(), request.getSnapshot()); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/point/adapter/in/api/PointApi.java b/src/main/java/com/gomo/app/core/point/adapter/in/api/PointApi.java index 9345b926..d0184804 100644 --- a/src/main/java/com/gomo/app/core/point/adapter/in/api/PointApi.java +++ b/src/main/java/com/gomo/app/core/point/adapter/in/api/PointApi.java @@ -6,14 +6,14 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.common.session.Session; +import com.gomo.app.common.session.SessionInfo; import com.gomo.app.common.web.PageRequest; import com.gomo.app.core.point.adapter.in.api.response.ListPointResponse; import com.gomo.app.core.point.adapter.in.api.response.ReadBalanceResponse; import com.gomo.app.core.point.application.port.dto.ListPointDto; import com.gomo.app.core.point.application.port.in.BalanceReader; import com.gomo.app.core.point.application.port.in.PointReader; -import com.gomo.app.core.auth.adapter.in.security.Auth; -import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -26,14 +26,14 @@ public class PointApi { private final BalanceReader balanceReader; @GetMapping - public ResponseEntity findAll(@Auth AuthInfo authInfo, @ModelAttribute PageRequest pageRequest) { - ListPointDto dto = pointReader.readAll(authInfo.getPrincipalId(), pageRequest); + public ResponseEntity findAll(@Session SessionInfo sessionInfo, @ModelAttribute PageRequest pageRequest) { + ListPointDto dto = pointReader.readAll(sessionInfo.getPrincipalId(), pageRequest); return ResponseEntity.ok(ListPointResponse.from(dto)); } @GetMapping("/balances") - public ResponseEntity findBalance(@Auth AuthInfo authInfo) { - int balance = balanceReader.read(authInfo.getPrincipalId()); + public ResponseEntity findBalance(@Session SessionInfo sessionInfo) { + int balance = balanceReader.read(sessionInfo.getPrincipalId()); return ResponseEntity.ok(ReadBalanceResponse.of(balance)); } } diff --git a/src/main/java/com/gomo/app/core/quest/adapter/in/api/AssignQuestApi.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/AssignQuestApi.java index 479c82fb..d6444737 100644 --- a/src/main/java/com/gomo/app/core/quest/adapter/in/api/AssignQuestApi.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/AssignQuestApi.java @@ -14,6 +14,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.common.session.Session; +import com.gomo.app.common.session.SessionInfo; import com.gomo.app.core.quest.adapter.in.api.request.CreateAssignQuestRequest; import com.gomo.app.core.quest.adapter.in.api.request.UpdateAssignQuestRequest; import com.gomo.app.core.quest.adapter.in.api.response.CreateAssignQuestResponse; @@ -23,8 +25,6 @@ import com.gomo.app.core.quest.application.port.in.AssignQuestDeleter; import com.gomo.app.core.quest.application.port.in.AssignQuestDetailReader; import com.gomo.app.core.quest.application.port.in.AssignQuestUpdater; -import com.gomo.app.core.auth.adapter.in.security.Auth; -import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -39,26 +39,26 @@ public class AssignQuestApi { private final AssignQuestDeleter assignQuestDeleter; @PostMapping - public ResponseEntity create(@Auth AuthInfo authInfo, @RequestBody CreateAssignQuestRequest request) { - UUID assignQuestId = assignQuestCreator.create(request.toCommand(authInfo.getPrincipalId())); + public ResponseEntity create(@Session SessionInfo sessionInfo, @RequestBody CreateAssignQuestRequest request) { + UUID assignQuestId = assignQuestCreator.create(request.toCommand(sessionInfo.getPrincipalId())); return ResponseEntity.status(CREATED).body(CreateAssignQuestResponse.of(assignQuestId)); } @GetMapping - public ResponseEntity findAll(@Auth AuthInfo authInfo) { - ListAssignQuestDetailDto dto = assignQuestDetailReader.readAll(authInfo.getPrincipalId()); + public ResponseEntity findAll(@Session SessionInfo sessionInfo) { + ListAssignQuestDetailDto dto = assignQuestDetailReader.readAll(sessionInfo.getPrincipalId()); return ResponseEntity.ok(ListAssignQuestDetailResponse.from(dto)); } @PutMapping("/{id}") - public ResponseEntity update(@Auth AuthInfo authInfo, @PathVariable("id") UUID assignQuestId, @RequestBody UpdateAssignQuestRequest request) { - assignQuestUpdater.update(request.toCommand(authInfo.getPrincipalId(), assignQuestId)); + public ResponseEntity update(@Session SessionInfo sessionInfo, @PathVariable("id") UUID assignQuestId, @RequestBody UpdateAssignQuestRequest request) { + assignQuestUpdater.update(request.toCommand(sessionInfo.getPrincipalId(), assignQuestId)); return ResponseEntity.noContent().build(); } @DeleteMapping("/{id}") - public ResponseEntity delete(@Auth AuthInfo authInfo, @PathVariable("id") UUID assignQuestId) { - assignQuestDeleter.delete(authInfo.getPrincipalId(), assignQuestId); + public ResponseEntity delete(@Session SessionInfo sessionInfo, @PathVariable("id") UUID assignQuestId) { + assignQuestDeleter.delete(sessionInfo.getPrincipalId(), assignQuestId); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/quest/adapter/in/api/CalendarAssignQuestApi.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/CalendarAssignQuestApi.java index 2300ae06..244cab60 100644 --- a/src/main/java/com/gomo/app/core/quest/adapter/in/api/CalendarAssignQuestApi.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/CalendarAssignQuestApi.java @@ -9,13 +9,13 @@ import org.springframework.web.bind.annotation.RequestParam; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.common.session.Session; +import com.gomo.app.common.session.SessionInfo; import com.gomo.app.core.quest.adapter.in.api.response.ListAssignQuestResponse; import com.gomo.app.core.quest.adapter.in.api.response.ReadAssignQuestResponse; import com.gomo.app.core.quest.application.port.command.ListAssignQuestCommand; import com.gomo.app.core.quest.application.port.dto.AssignQuestDto; import com.gomo.app.core.quest.application.port.in.AssignQuestReader; -import com.gomo.app.core.auth.adapter.in.security.Auth; -import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -27,9 +27,9 @@ public class CalendarAssignQuestApi { private final AssignQuestReader assignQuestReader; @GetMapping - public ResponseEntity find(@Auth AuthInfo authInfo, @RequestParam boolean isCompleted, + public ResponseEntity find(@Session SessionInfo sessionInfo, @RequestParam boolean isCompleted, @RequestParam LocalDateTime startDateTime, @RequestParam LocalDateTime endDateTime) { - ListAssignQuestCommand command = ListAssignQuestCommand.of(authInfo.getPrincipalId(), isCompleted, startDateTime, endDateTime); + ListAssignQuestCommand command = ListAssignQuestCommand.of(sessionInfo.getPrincipalId(), isCompleted, startDateTime, endDateTime); List calendarDtos = assignQuestReader.readAll(command); return ResponseEntity.ok(ListAssignQuestResponse.of(calendarDtos.stream().map(ReadAssignQuestResponse::from).toList())); } diff --git a/src/main/java/com/gomo/app/core/quest/adapter/in/api/CompleteAssignQuestApi.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/CompleteAssignQuestApi.java index 3ceb0bd6..48f83d60 100644 --- a/src/main/java/com/gomo/app/core/quest/adapter/in/api/CompleteAssignQuestApi.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/CompleteAssignQuestApi.java @@ -10,10 +10,10 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.common.session.Session; +import com.gomo.app.common.session.SessionInfo; import com.gomo.app.core.quest.adapter.in.api.request.CompleteAssignQuestRequest; import com.gomo.app.core.quest.application.port.in.AssignQuestCompleter; -import com.gomo.app.core.auth.adapter.in.security.Auth; -import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -25,8 +25,8 @@ public class CompleteAssignQuestApi { private final AssignQuestCompleter assignQuestCompleter; @PutMapping - public ResponseEntity complete(@Auth AuthInfo authInfo, @PathVariable("id") UUID assignQuestId, @RequestBody CompleteAssignQuestRequest request) { - assignQuestCompleter.complete(request.toCommand(authInfo.getPrincipalId(), assignQuestId, LocalDateTime.now())); + public ResponseEntity complete(@Session SessionInfo sessionInfo, @PathVariable("id") UUID assignQuestId, @RequestBody CompleteAssignQuestRequest request) { + assignQuestCompleter.complete(request.toCommand(sessionInfo.getPrincipalId(), assignQuestId, LocalDateTime.now())); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/quest/adapter/in/api/ConfirmAssignQuestApi.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/ConfirmAssignQuestApi.java index 50583c20..be0f9fc9 100644 --- a/src/main/java/com/gomo/app/core/quest/adapter/in/api/ConfirmAssignQuestApi.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/ConfirmAssignQuestApi.java @@ -8,9 +8,9 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.common.session.Session; +import com.gomo.app.common.session.SessionInfo; import com.gomo.app.core.quest.application.port.in.AssignQuestConfirmer; -import com.gomo.app.core.auth.adapter.in.security.Auth; -import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -22,8 +22,8 @@ public class ConfirmAssignQuestApi { private final AssignQuestConfirmer assignQuestConfirmer; @PutMapping - public ResponseEntity confirm(@Auth AuthInfo authInfo, @PathVariable("id") UUID assignQuestId) { - assignQuestConfirmer.confirm(authInfo.getPrincipalId(), assignQuestId); + public ResponseEntity confirm(@Session SessionInfo sessionInfo, @PathVariable("id") UUID assignQuestId) { + assignQuestConfirmer.confirm(sessionInfo.getPrincipalId(), assignQuestId); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/quest/adapter/in/api/OrderUpdateAssignQuestApi.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/OrderUpdateAssignQuestApi.java index e9dd13c3..12c0f961 100644 --- a/src/main/java/com/gomo/app/core/quest/adapter/in/api/OrderUpdateAssignQuestApi.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/OrderUpdateAssignQuestApi.java @@ -6,10 +6,10 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.common.session.Session; +import com.gomo.app.common.session.SessionInfo; import com.gomo.app.core.quest.adapter.in.api.request.OrderUpdateAssignQuestRequest; import com.gomo.app.core.quest.application.port.in.AssignQuestOrderUpdater; -import com.gomo.app.core.auth.adapter.in.security.Auth; -import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -21,8 +21,8 @@ public class OrderUpdateAssignQuestApi { private final AssignQuestOrderUpdater assignQuestOrderUpdater; @PutMapping - public ResponseEntity update(@Auth AuthInfo authInfo, @RequestBody OrderUpdateAssignQuestRequest request) { - assignQuestOrderUpdater.update(request.toCommand(authInfo.getPrincipalId())); + public ResponseEntity update(@Session SessionInfo sessionInfo, @RequestBody OrderUpdateAssignQuestRequest request) { + assignQuestOrderUpdater.update(request.toCommand(sessionInfo.getPrincipalId())); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/quest/adapter/in/api/OrderUpdateRepeatQuestApi.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/OrderUpdateRepeatQuestApi.java index cfad5d5e..21a2d321 100644 --- a/src/main/java/com/gomo/app/core/quest/adapter/in/api/OrderUpdateRepeatQuestApi.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/OrderUpdateRepeatQuestApi.java @@ -6,10 +6,10 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.common.session.Session; +import com.gomo.app.common.session.SessionInfo; import com.gomo.app.core.quest.adapter.in.api.request.OrderUpdateRepeatQuestRequest; import com.gomo.app.core.quest.application.port.in.RepeatQuestOrderUpdater; -import com.gomo.app.core.auth.adapter.in.security.Auth; -import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -21,8 +21,8 @@ public class OrderUpdateRepeatQuestApi { private final RepeatQuestOrderUpdater repeatQuestOrderUpdater; @PutMapping - public ResponseEntity update(@Auth AuthInfo authInfo, @RequestBody OrderUpdateRepeatQuestRequest request) { - repeatQuestOrderUpdater.update(request.toCommand(authInfo.getPrincipalId())); + public ResponseEntity update(@Session SessionInfo sessionInfo, @RequestBody OrderUpdateRepeatQuestRequest request) { + repeatQuestOrderUpdater.update(request.toCommand(sessionInfo.getPrincipalId())); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/quest/adapter/in/api/ReRollAssignQuestApi.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/ReRollAssignQuestApi.java index a0bac53d..1648f74e 100644 --- a/src/main/java/com/gomo/app/core/quest/adapter/in/api/ReRollAssignQuestApi.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/ReRollAssignQuestApi.java @@ -8,12 +8,12 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.common.session.Session; +import com.gomo.app.common.session.SessionInfo; import com.gomo.app.core.quest.adapter.in.api.request.ReRollAssignQuestRequest; import com.gomo.app.core.quest.adapter.in.api.response.ReadAssignQuestDetailResponse; import com.gomo.app.core.quest.application.port.dto.AssignQuestDetailDto; import com.gomo.app.core.quest.application.port.in.AssignQuestReRoller; -import com.gomo.app.core.auth.adapter.in.security.Auth; -import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -25,8 +25,8 @@ public class ReRollAssignQuestApi { private final AssignQuestReRoller assignQuestReRoller; @PostMapping - public ResponseEntity reRoll(@Auth AuthInfo authInfo, @RequestBody ReRollAssignQuestRequest request) { - AssignQuestDetailDto assignQuestDetailDto = assignQuestReRoller.reRoll(authInfo.getPrincipalId(), request.getAssignQuestId()); + public ResponseEntity reRoll(@Session SessionInfo sessionInfo, @RequestBody ReRollAssignQuestRequest request) { + AssignQuestDetailDto assignQuestDetailDto = assignQuestReRoller.reRoll(sessionInfo.getPrincipalId(), request.getAssignQuestId()); return ResponseEntity.status(CREATED).body(ReadAssignQuestDetailResponse.from(assignQuestDetailDto)); } } diff --git a/src/main/java/com/gomo/app/core/quest/adapter/in/api/RepeatQuestApi.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/RepeatQuestApi.java index 9ab4876e..ad9cb92d 100644 --- a/src/main/java/com/gomo/app/core/quest/adapter/in/api/RepeatQuestApi.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/RepeatQuestApi.java @@ -14,6 +14,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.common.session.Session; +import com.gomo.app.common.session.SessionInfo; import com.gomo.app.core.quest.adapter.in.api.request.CreateRepeatQuestRequest; import com.gomo.app.core.quest.adapter.in.api.request.UpdateRepeatQuestRequest; import com.gomo.app.core.quest.adapter.in.api.response.CreateRepeatQuestResponse; @@ -23,8 +25,6 @@ import com.gomo.app.core.quest.application.port.in.RepeatQuestDeleter; import com.gomo.app.core.quest.application.port.in.RepeatQuestReader; import com.gomo.app.core.quest.application.port.in.RepeatQuestUpdater; -import com.gomo.app.core.auth.adapter.in.security.Auth; -import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -39,26 +39,26 @@ public class RepeatQuestApi { private final RepeatQuestDeleter repeatQuestDeleter; @PostMapping - public ResponseEntity create(@Auth AuthInfo authInfo, @RequestBody CreateRepeatQuestRequest request) { - UUID repeatQuestId = repeatQuestCreator.create(request.toCommand(authInfo.getPrincipalId())); + public ResponseEntity create(@Session SessionInfo sessionInfo, @RequestBody CreateRepeatQuestRequest request) { + UUID repeatQuestId = repeatQuestCreator.create(request.toCommand(sessionInfo.getPrincipalId())); return ResponseEntity.status(CREATED).body(CreateRepeatQuestResponse.of(repeatQuestId)); } @GetMapping - public ResponseEntity findAll(@Auth AuthInfo authInfo) { - ListRepeatQuestDto dto = repeatQuestReader.readAll(authInfo.getPrincipalId()); + public ResponseEntity findAll(@Session SessionInfo sessionInfo) { + ListRepeatQuestDto dto = repeatQuestReader.readAll(sessionInfo.getPrincipalId()); return ResponseEntity.ok(ListRepeatQuestResponse.from(dto)); } @PutMapping("/{id}") - public ResponseEntity update(@Auth AuthInfo authInfo, @PathVariable("id") UUID repeatQuestId, @RequestBody UpdateRepeatQuestRequest request) { - repeatQuestUpdater.update(request.toCommand(authInfo.getPrincipalId(), repeatQuestId)); + public ResponseEntity update(@Session SessionInfo sessionInfo, @PathVariable("id") UUID repeatQuestId, @RequestBody UpdateRepeatQuestRequest request) { + repeatQuestUpdater.update(request.toCommand(sessionInfo.getPrincipalId(), repeatQuestId)); return ResponseEntity.noContent().build(); } @DeleteMapping("/{id}") - public ResponseEntity delete(@Auth AuthInfo authInfo, @PathVariable("id") UUID repeatQuestId) { - repeatQuestDeleter.delete(authInfo.getPrincipalId(), repeatQuestId); + public ResponseEntity delete(@Session SessionInfo sessionInfo, @PathVariable("id") UUID repeatQuestId) { + repeatQuestDeleter.delete(sessionInfo.getPrincipalId(), repeatQuestId); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/gomo/app/core/streak/adapter/in/api/AchieverApi.java b/src/main/java/com/gomo/app/core/streak/adapter/in/api/AchieverApi.java index b2859241..b7749f8c 100644 --- a/src/main/java/com/gomo/app/core/streak/adapter/in/api/AchieverApi.java +++ b/src/main/java/com/gomo/app/core/streak/adapter/in/api/AchieverApi.java @@ -5,11 +5,11 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.common.session.Session; +import com.gomo.app.common.session.SessionInfo; import com.gomo.app.core.streak.adapter.in.api.response.ReadAchieverResponse; import com.gomo.app.core.streak.application.port.dto.AchieverDto; import com.gomo.app.core.streak.application.port.in.AchieverReader; -import com.gomo.app.core.auth.adapter.in.security.Auth; -import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -21,8 +21,8 @@ public class AchieverApi { private final AchieverReader achieverReader; @GetMapping - public ResponseEntity find(@Auth AuthInfo authInfo) { - AchieverDto achieverDto = achieverReader.read(authInfo.getPrincipalId()); + public ResponseEntity find(@Session SessionInfo sessionInfo) { + AchieverDto achieverDto = achieverReader.read(sessionInfo.getPrincipalId()); return ResponseEntity.ok(ReadAchieverResponse.from(achieverDto)); } } diff --git a/src/main/java/com/gomo/app/core/streak/adapter/in/api/StreakApi.java b/src/main/java/com/gomo/app/core/streak/adapter/in/api/StreakApi.java index 69756237..12e67207 100644 --- a/src/main/java/com/gomo/app/core/streak/adapter/in/api/StreakApi.java +++ b/src/main/java/com/gomo/app/core/streak/adapter/in/api/StreakApi.java @@ -8,11 +8,11 @@ import org.springframework.web.bind.annotation.RequestParam; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.common.session.Session; +import com.gomo.app.common.session.SessionInfo; import com.gomo.app.core.streak.adapter.in.api.response.ListStreakResponse; import com.gomo.app.core.streak.application.port.dto.ListStreakDto; import com.gomo.app.core.streak.application.port.in.StreakReader; -import com.gomo.app.core.auth.adapter.in.security.Auth; -import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -24,8 +24,8 @@ public class StreakApi { private final StreakReader streakReader; @GetMapping - public ResponseEntity findAllByStreakType(@Auth AuthInfo authInfo, @RequestParam LocalDate startDate, @RequestParam LocalDate endDate) { - ListStreakDto dto = streakReader.findAll(authInfo.getPrincipalId(), startDate, endDate); + public ResponseEntity findAllByStreakType(@Session SessionInfo sessionInfo, @RequestParam LocalDate startDate, @RequestParam LocalDate endDate) { + ListStreakDto dto = streakReader.findAll(sessionInfo.getPrincipalId(), startDate, endDate); return ResponseEntity.ok(ListStreakResponse.from(dto)); } } diff --git a/src/main/java/com/gomo/app/core/survey/adapter/in/api/SurveyApi.java b/src/main/java/com/gomo/app/core/survey/adapter/in/api/SurveyApi.java index b1be8d6d..72c2e76e 100644 --- a/src/main/java/com/gomo/app/core/survey/adapter/in/api/SurveyApi.java +++ b/src/main/java/com/gomo/app/core/survey/adapter/in/api/SurveyApi.java @@ -11,13 +11,13 @@ import org.springframework.web.bind.annotation.RequestMapping; import com.gomo.app.common.arch.CoreApi; +import com.gomo.app.common.session.Session; +import com.gomo.app.common.session.SessionInfo; import com.gomo.app.core.survey.adapter.in.api.request.CreateSurveyResultRequest; import com.gomo.app.core.survey.adapter.in.api.response.ListSurveyQuestionResponse; import com.gomo.app.core.survey.application.dto.SurveyQuestionDto; import com.gomo.app.core.survey.application.service.SurveyQuestionService; import com.gomo.app.core.survey.application.service.SurveyResultService; -import com.gomo.app.core.auth.adapter.in.security.Auth; -import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import lombok.RequiredArgsConstructor; @@ -30,8 +30,8 @@ public class SurveyApi { private final SurveyQuestionService surveyQuestionService; @PostMapping - public ResponseEntity createSurveyResult(@Auth AuthInfo authInfo, @RequestBody CreateSurveyResultRequest request) { - surveyResultService.create(request.toCommand(authInfo.getPrincipalId())); + public ResponseEntity createSurveyResult(@Session SessionInfo sessionInfo, @RequestBody CreateSurveyResultRequest request) { + surveyResultService.create(request.toCommand(sessionInfo.getPrincipalId())); return ResponseEntity.status(CREATED).build(); } diff --git a/src/test/java/com/gomo/app/common/web/ApplicationExceptionAdviceTest.java b/src/test/java/com/gomo/app/common/web/ApplicationExceptionAdviceTest.java index b234cfcf..d4e7b172 100644 --- a/src/test/java/com/gomo/app/common/web/ApplicationExceptionAdviceTest.java +++ b/src/test/java/com/gomo/app/common/web/ApplicationExceptionAdviceTest.java @@ -17,7 +17,7 @@ import org.springframework.web.multipart.MaxUploadSizeExceededException; import com.gomo.app.common.exception.ApplicationException; -import com.gomo.app.core.auth.adapter.in.security.AuthenticationFilter; +import com.gomo.app.core.auth.adapter.in.filter.AuthenticationFilter; @WebMvcTest( controllers = ApplicationExceptionAdvice.class, diff --git a/src/test/java/com/gomo/app/core/interest/adapter/in/api/CreateInterestRelationDocumentationTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/CreateInterestRelationDocumentationTest.java index 9a6fbc29..23f9573b 100644 --- a/src/test/java/com/gomo/app/core/interest/adapter/in/api/CreateInterestRelationDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/CreateInterestRelationDocumentationTest.java @@ -66,6 +66,6 @@ void create_interest_relation() { } private UUID createInterest(String name) { - return interestApi.create(super.authInfo, CreateInterestRequest.of(name, "#FF0000", null)).getBody().getId(); + return interestApi.create(super.sessionInfo, CreateInterestRequest.of(name, "#FF0000", null)).getBody().getId(); } } diff --git a/src/test/java/com/gomo/app/core/interest/adapter/in/api/CreateMajorInterestDocumentationTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/CreateMajorInterestDocumentationTest.java index c2b42add..1fcfbff3 100644 --- a/src/test/java/com/gomo/app/core/interest/adapter/in/api/CreateMajorInterestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/CreateMajorInterestDocumentationTest.java @@ -70,7 +70,7 @@ void create_major_interest() { @DisplayName("이미 등록된 주요 관심사를 중복 등록한다.") @Test void create_already_major_interest() { - majorInterestApi.create(super.authInfo, interestId); + majorInterestApi.create(super.sessionInfo, interestId); given(this.specification) .filter(errorFilter) @@ -88,6 +88,6 @@ void create_already_major_interest() { } private UUID createInterest(String name) { - return interestApi.create(super.authInfo, CreateInterestRequest.of(name, "#FF0000", null)).getBody().getId(); + return interestApi.create(super.sessionInfo, CreateInterestRequest.of(name, "#FF0000", null)).getBody().getId(); } } diff --git a/src/test/java/com/gomo/app/core/interest/adapter/in/api/DeleteInterestDocumentationTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/DeleteInterestDocumentationTest.java index db0bbb5a..434449c9 100644 --- a/src/test/java/com/gomo/app/core/interest/adapter/in/api/DeleteInterestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/DeleteInterestDocumentationTest.java @@ -55,6 +55,6 @@ void delete_interest() { } private UUID createInterest(String name) { - return interestApi.create(super.authInfo, CreateInterestRequest.of(name, "#FF0000", null)).getBody().getId(); + return interestApi.create(super.sessionInfo, CreateInterestRequest.of(name, "#FF0000", null)).getBody().getId(); } } diff --git a/src/test/java/com/gomo/app/core/interest/adapter/in/api/DeleteInterestRelationDocumentationTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/DeleteInterestRelationDocumentationTest.java index a6b62793..69176f85 100644 --- a/src/test/java/com/gomo/app/core/interest/adapter/in/api/DeleteInterestRelationDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/DeleteInterestRelationDocumentationTest.java @@ -67,10 +67,10 @@ void delete_interest_relation() { } private UUID createInterest(String name) { - return interestApi.create(super.authInfo, CreateInterestRequest.of(name, "#FF0000", null)).getBody().getId(); + return interestApi.create(super.sessionInfo, CreateInterestRequest.of(name, "#FF0000", null)).getBody().getId(); } private UUID createInterestRelation(UUID depth1Id, UUID depth2Id) { - return interestNetworkApi.createRelation(this.authInfo, CreateInterestRelationRequest.of(depth1Id, depth2Id)).getBody().getId(); + return interestNetworkApi.createRelation(this.sessionInfo, CreateInterestRelationRequest.of(depth1Id, depth2Id)).getBody().getId(); } } diff --git a/src/test/java/com/gomo/app/core/interest/adapter/in/api/DeleteMajorInterestDocumentationTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/DeleteMajorInterestDocumentationTest.java index 34829d57..8227730c 100644 --- a/src/test/java/com/gomo/app/core/interest/adapter/in/api/DeleteMajorInterestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/DeleteMajorInterestDocumentationTest.java @@ -64,10 +64,10 @@ void delete_major_interest() { } private UUID createMajorInterest(UUID interestId) { - return majorInterestApi.create(this.authInfo, interestId).getBody().getId(); + return majorInterestApi.create(this.sessionInfo, interestId).getBody().getId(); } private UUID createInterest(String name) { - return interestApi.create(super.authInfo, CreateInterestRequest.of(name, "#FF0000", null)).getBody().getId(); + return interestApi.create(super.sessionInfo, CreateInterestRequest.of(name, "#FF0000", null)).getBody().getId(); } } diff --git a/src/test/java/com/gomo/app/core/interest/adapter/in/api/InterestNetworkDocumentationTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/InterestNetworkDocumentationTest.java index 6081a7c1..b1b5020c 100644 --- a/src/test/java/com/gomo/app/core/interest/adapter/in/api/InterestNetworkDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/InterestNetworkDocumentationTest.java @@ -68,10 +68,10 @@ void read_interest_network() { } private UUID createInterest(String name) { - return interestApi.create(super.authInfo, CreateInterestRequest.of(name, "#FF0000", null)).getBody().getId(); + return interestApi.create(super.sessionInfo, CreateInterestRequest.of(name, "#FF0000", null)).getBody().getId(); } private void createInterestRelation(UUID depth1Id, UUID depth2Id) { - interestNetworkApi.createRelation(this.authInfo, CreateInterestRelationRequest.of(depth1Id, depth2Id)); + interestNetworkApi.createRelation(this.sessionInfo, CreateInterestRelationRequest.of(depth1Id, depth2Id)); } } diff --git a/src/test/java/com/gomo/app/core/interest/adapter/in/api/ListInterestDocumentationTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/ListInterestDocumentationTest.java index 98343991..56349331 100644 --- a/src/test/java/com/gomo/app/core/interest/adapter/in/api/ListInterestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/ListInterestDocumentationTest.java @@ -55,6 +55,6 @@ void list_interest() { } private void createInterest(String name) { - interestApi.create(super.authInfo, CreateInterestRequest.of(name, "#FF0000", null)); + interestApi.create(super.sessionInfo, CreateInterestRequest.of(name, "#FF0000", null)); } } diff --git a/src/test/java/com/gomo/app/core/interest/adapter/in/api/ListMajorInterestDocumentationTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/ListMajorInterestDocumentationTest.java index d7d33ad2..e67dc6b6 100644 --- a/src/test/java/com/gomo/app/core/interest/adapter/in/api/ListMajorInterestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/ListMajorInterestDocumentationTest.java @@ -66,10 +66,10 @@ void list_major_interest() { } private void createMajorInterest(UUID interestId) { - majorInterestApi.create(this.authInfo, interestId); + majorInterestApi.create(this.sessionInfo, interestId); } private UUID createInterest(String name) { - return interestApi.create(super.authInfo, CreateInterestRequest.of(name, "#FF0000", null)).getBody().getId(); + return interestApi.create(super.sessionInfo, CreateInterestRequest.of(name, "#FF0000", null)).getBody().getId(); } } diff --git a/src/test/java/com/gomo/app/core/interest/adapter/in/api/OrderUpdateMajorInterestDocumentationTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/OrderUpdateMajorInterestDocumentationTest.java index d3c5ee08..e8a5db85 100644 --- a/src/test/java/com/gomo/app/core/interest/adapter/in/api/OrderUpdateMajorInterestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/OrderUpdateMajorInterestDocumentationTest.java @@ -81,10 +81,10 @@ void update_major_interest_order() { } private UUID createMajorInterest(UUID interestId) { - return majorInterestApi.create(this.authInfo, interestId).getBody().getId(); + return majorInterestApi.create(this.sessionInfo, interestId).getBody().getId(); } private UUID createInterest(String name) { - return interestApi.create(super.authInfo, CreateInterestRequest.of(name, "#FF0000", null)).getBody().getId(); + return interestApi.create(super.sessionInfo, CreateInterestRequest.of(name, "#FF0000", null)).getBody().getId(); } } diff --git a/src/test/java/com/gomo/app/core/interest/adapter/in/api/ReadInterestDocumentationTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/ReadInterestDocumentationTest.java index 86fe6801..95991b74 100644 --- a/src/test/java/com/gomo/app/core/interest/adapter/in/api/ReadInterestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/ReadInterestDocumentationTest.java @@ -55,6 +55,6 @@ void read_interest() { } private UUID createInterest(String name) { - return interestApi.create(super.authInfo, CreateInterestRequest.of(name, "#FF0000", null)).getBody().getId(); + return interestApi.create(super.sessionInfo, CreateInterestRequest.of(name, "#FF0000", null)).getBody().getId(); } } diff --git a/src/test/java/com/gomo/app/core/interest/adapter/in/api/UpdateInterestDocumentationTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/UpdateInterestDocumentationTest.java index 1c385d35..0a9ffc43 100644 --- a/src/test/java/com/gomo/app/core/interest/adapter/in/api/UpdateInterestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/UpdateInterestDocumentationTest.java @@ -78,6 +78,6 @@ void update_interest_with_forbidden_name() { } private UUID createInterest(String name) { - return interestApi.create(super.authInfo, CreateInterestRequest.of(name, "#FF0000", null)).getBody().getId(); + return interestApi.create(super.sessionInfo, CreateInterestRequest.of(name, "#FF0000", null)).getBody().getId(); } } diff --git a/src/test/java/com/gomo/app/core/interest/adapter/in/api/UpdateInterestLogoDocumentationTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/api/UpdateInterestLogoDocumentationTest.java index 607f9c0a..a2424521 100644 --- a/src/test/java/com/gomo/app/core/interest/adapter/in/api/UpdateInterestLogoDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/api/UpdateInterestLogoDocumentationTest.java @@ -87,6 +87,6 @@ private static File getImageFile(String imageName) throws IOException { } private UUID createInterest(String name) { - return interestApi.create(super.authInfo, CreateInterestRequest.of(name, "#FF0000", null)).getBody().getId(); + return interestApi.create(super.sessionInfo, CreateInterestRequest.of(name, "#FF0000", null)).getBody().getId(); } } diff --git a/src/test/java/com/gomo/app/core/quest/adapter/in/api/CreateAssignQuestDocumentationTest.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/CreateAssignQuestDocumentationTest.java index b5bf4f19..14b076aa 100644 --- a/src/test/java/com/gomo/app/core/quest/adapter/in/api/CreateAssignQuestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/CreateAssignQuestDocumentationTest.java @@ -18,10 +18,10 @@ import com.gomo.app.core.member.adapter.in.api.request.UpdateQuestPropertyRequest; import com.gomo.app.core.quest.adapter.in.api.request.CreateAssignQuestRequest; import com.gomo.app.core.quest.adapter.in.api.snippet.CreateAssignQuestSnippet; -import com.gomo.app.core.quest.domain.model.quest.QuestType; -import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; import com.gomo.app.core.quest.domain.exception.code.QuestContentErrorCode; import com.gomo.app.core.quest.domain.exception.code.QuestErrorCode; +import com.gomo.app.core.quest.domain.model.quest.QuestType; +import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 할당 퀘스트 생성 테스트") @@ -85,7 +85,7 @@ void create_assign_quest_invalid_quest_content() { @DisplayName("사용자가 퀘스트 제한 개수를 초과하는 할당 퀘스트를 생성한다.") @Test void create_assign_quest_exceeding_threshold() { - questPropertyApi.update(super.authInfo, UpdateQuestPropertyRequest.of(0, 0, 0)); + questPropertyApi.update(super.sessionInfo, UpdateQuestPropertyRequest.of(0, 0, 0)); given(this.specification).filter(errorFilter) .header(CONTENT_TYPE, APPLICATION_JSON_VALUE) .header(AUTHORIZATION, "Bearer " + accessToken) diff --git a/src/test/java/com/gomo/app/core/quest/adapter/in/api/CreateRepeatQuestDocumentationTest.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/CreateRepeatQuestDocumentationTest.java index fcdf4e93..05649f4e 100644 --- a/src/test/java/com/gomo/app/core/quest/adapter/in/api/CreateRepeatQuestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/CreateRepeatQuestDocumentationTest.java @@ -22,10 +22,10 @@ import com.gomo.app.core.member.adapter.in.api.request.UpdateQuestPropertyRequest; import com.gomo.app.core.quest.adapter.in.api.request.CreateRepeatQuestRequest; import com.gomo.app.core.quest.adapter.in.api.snippet.CreateRepeatQuestSnippet; -import com.gomo.app.core.quest.domain.model.quest.QuestType; -import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; import com.gomo.app.core.quest.domain.exception.code.QuestContentErrorCode; import com.gomo.app.core.quest.domain.exception.code.QuestErrorCode; +import com.gomo.app.core.quest.domain.model.quest.QuestType; +import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 반복 퀘스트 생성 테스트") @@ -44,7 +44,7 @@ public class CreateRepeatQuestDocumentationTest extends DocumentationTestBase { @BeforeEach public void setUp() { - subjectId = interestApi.create(super.authInfo, CreateInterestRequest.of("name", "#FF0000", null)) + subjectId = interestApi.create(super.sessionInfo, CreateInterestRequest.of("name", "#FF0000", null)) .getBody() .getId(); } @@ -104,7 +104,7 @@ void create_repeat_quest_invalid_quest_content() { @DisplayName("사용자가 퀘스트 제한 개수를 초과하는 반복 퀘스트를 생성한다.") @Test void create_repeat_quest_exceeding_threshold() { - questPropertyApi.update(super.authInfo, UpdateQuestPropertyRequest.of(0, 0, 0)); + questPropertyApi.update(super.sessionInfo, UpdateQuestPropertyRequest.of(0, 0, 0)); given(this.specification).filter(errorFilter) .header(CONTENT_TYPE, APPLICATION_JSON_VALUE) .header(AUTHORIZATION, "Bearer " + accessToken) diff --git a/src/test/java/com/gomo/app/core/quest/adapter/in/api/DeleteRepeatQuestDocumentationTest.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/DeleteRepeatQuestDocumentationTest.java index a379a682..1e111312 100644 --- a/src/test/java/com/gomo/app/core/quest/adapter/in/api/DeleteRepeatQuestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/DeleteRepeatQuestDocumentationTest.java @@ -35,7 +35,7 @@ public class DeleteRepeatQuestDocumentationTest extends DocumentationTestBase { @BeforeEach public void setUp() { - repeatQuestId = repeatQuestApi.create(super.authInfo, getCreateRepeatQuestRequest()).getBody().getId(); + repeatQuestId = repeatQuestApi.create(super.sessionInfo, getCreateRepeatQuestRequest()).getBody().getId(); } @AfterEach diff --git a/src/test/java/com/gomo/app/core/quest/adapter/in/api/ListRepeatQuestDocumentationTest.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/ListRepeatQuestDocumentationTest.java index beb075a4..df88ba76 100644 --- a/src/test/java/com/gomo/app/core/quest/adapter/in/api/ListRepeatQuestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/ListRepeatQuestDocumentationTest.java @@ -35,9 +35,9 @@ public class ListRepeatQuestDocumentationTest extends DocumentationTestBase { @BeforeEach public void setUp() { - repeatQuestApi.create(super.authInfo, getCreateRepeatQuestRequest(QuestType.DAILY.name())).getBody().getId(); - repeatQuestApi.create(super.authInfo, getCreateRepeatQuestRequest(QuestType.WEEKLY.name())).getBody().getId(); - repeatQuestApi.create(super.authInfo, getCreateRepeatQuestRequest(QuestType.MONTHLY.name())).getBody().getId(); + repeatQuestApi.create(super.sessionInfo, getCreateRepeatQuestRequest(QuestType.DAILY.name())).getBody().getId(); + repeatQuestApi.create(super.sessionInfo, getCreateRepeatQuestRequest(QuestType.WEEKLY.name())).getBody().getId(); + repeatQuestApi.create(super.sessionInfo, getCreateRepeatQuestRequest(QuestType.MONTHLY.name())).getBody().getId(); } @AfterEach diff --git a/src/test/java/com/gomo/app/core/quest/adapter/in/api/UpdateRepeatQuestDocumentationTest.java b/src/test/java/com/gomo/app/core/quest/adapter/in/api/UpdateRepeatQuestDocumentationTest.java index df34541b..2e2350f2 100644 --- a/src/test/java/com/gomo/app/core/quest/adapter/in/api/UpdateRepeatQuestDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/quest/adapter/in/api/UpdateRepeatQuestDocumentationTest.java @@ -19,9 +19,9 @@ import com.gomo.app.core.quest.adapter.in.api.request.CreateRepeatQuestRequest; import com.gomo.app.core.quest.adapter.in.api.request.UpdateRepeatQuestRequest; import com.gomo.app.core.quest.adapter.in.api.snippet.UpdateRepeatQuestSnippet; +import com.gomo.app.core.quest.domain.exception.code.QuestContentErrorCode; import com.gomo.app.core.quest.domain.model.quest.QuestType; import com.gomo.app.core.quest.domain.repository.RepeatQuestRepository; -import com.gomo.app.core.quest.domain.exception.code.QuestContentErrorCode; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 반복 퀘스트 수정 테스트") @@ -39,7 +39,7 @@ public class UpdateRepeatQuestDocumentationTest extends DocumentationTestBase { @BeforeEach public void setUp() { - repeatQuestId = repeatQuestApi.create(super.authInfo, getCreateRepeatQuestRequest()).getBody().getId(); + repeatQuestId = repeatQuestApi.create(super.sessionInfo, getCreateRepeatQuestRequest()).getBody().getId(); } @AfterEach diff --git a/src/test/java/com/gomo/app/test/DocumentationTestBase.java b/src/test/java/com/gomo/app/test/DocumentationTestBase.java index 94bad9a4..914aad1a 100644 --- a/src/test/java/com/gomo/app/test/DocumentationTestBase.java +++ b/src/test/java/com/gomo/app/test/DocumentationTestBase.java @@ -17,14 +17,14 @@ import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; -import com.gomo.app.core.member.domain.model.LoginProvider; -import com.gomo.app.core.member.domain.repository.MemberRepository; +import com.gomo.app.common.session.SessionInfo; import com.gomo.app.core.auth.adapter.in.api.AuthApi; import com.gomo.app.core.auth.adapter.in.api.request.CreatePrincipalRequest; import com.gomo.app.core.auth.adapter.in.api.request.LoginRequest; import com.gomo.app.core.auth.adapter.in.api.response.AccessTokenResponse; -import com.gomo.app.core.auth.adapter.in.security.AuthInfo; import com.gomo.app.core.auth.application.port.out.JwtCreator; +import com.gomo.app.core.member.domain.model.LoginProvider; +import com.gomo.app.core.member.domain.repository.MemberRepository; import com.google.common.net.HttpHeaders; import io.restassured.builder.RequestSpecBuilder; @@ -48,7 +48,7 @@ public abstract class DocumentationTestBase { @Autowired private MemberRepository memberRepository; - protected AuthInfo authInfo; + protected SessionInfo sessionInfo; protected UUID sessionMemberId; protected String accessToken; protected String refreshToken; @@ -89,7 +89,7 @@ protected void sessionInit(ResponseEntity responseEntity) { AccessTokenResponse responseBody = responseEntity.getBody(); List cookies = responseEntity.getHeaders().get(HttpHeaders.SET_COOKIE); this.sessionMemberId = responseBody.getPrincipalId(); - this.authInfo = AuthInfo.of(sessionMemberId); + this.sessionInfo = SessionInfo.of(sessionMemberId); this.accessToken = responseBody.getAccessToken(); this.refreshToken = extractTokenFromCookie(cookies); } From 81f4f88a7d770e4f2ddf017243d37badaca4790a Mon Sep 17 00:00:00 2001 From: Junhyeok Lee Date: Thu, 6 Nov 2025 09:21:11 +0900 Subject: [PATCH 13/16] =?UTF-8?q?[GOMO-232]=20=EC=8A=A4=ED=94=84=EB=A7=81?= =?UTF-8?q?=20=EB=AA=A8=EB=93=88=EB=A6=AC=EC=8A=A4=20=EB=8F=84=EC=9E=85=20?= =?UTF-8?q?(#103)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 비밀번호 초기화 기능 수정 - 임시 토큰 검증에 대한 책임은 인증 모듈로 이동 - 인증 모듈과 회원 모듈 간 순환 의존 제거 * feat: 스프링 모듈리스 도입 - 모듈간 순환 의존성 검증 자동화 - 모듈간 의존 방향 문서화 * docs: 문서 제목 수정 * fix: support-logging 모듈 패키지 공개 타입 수정 --- build.gradle | 17 ++- src/docs/asciidoc/apis/auth-api.adoc | 20 +++ src/docs/asciidoc/apis/member-api.adoc | 24 --- src/docs/asciidoc/index.adoc | 4 +- src/docs/asciidoc/modulith-index.adoc | 67 +++++++++ .../app/batch/MemberCleanupScheduler.java | 138 ++++++++---------- .../arch/SpringModulithPackageInfo.java | 12 ++ .../config/SpringModulithPackageInfo.java | 12 ++ .../{ => common}/config/WebConfiguration.java | 2 +- .../SpringModulithPackageInfo.java | 12 ++ .../event/CompleteQuestEvent.java | 4 +- .../event/CreateQuestPoolEvent.java | 4 +- .../event/SpringModulithPackageInfo.java | 12 ++ .../exception/SpringModulithPackageInfo.java | 12 ++ .../common/jpa/SpringModulithPackageInfo.java | 12 ++ .../logging/SpringModulithPackageInfo.java | 12 ++ .../session/SpringModulithPackageInfo.java | 12 ++ .../util/SpringModulithPackageInfo.java | 12 ++ .../common/web/SpringModulithPackageInfo.java | 12 ++ .../core/auth/SpringModulithPackageInfo.java | 22 +++ .../app/core/auth/adapter/in/api/AuthApi.java | 10 ++ .../in/api/request/ResetPasswordRequest.java | 21 +++ .../auth/adapter/out/client/MemberClient.java | 18 ++- .../port/in/PasswordResetProcessor.java | 17 +++ .../port/in/SpringModulithPackageInfo.java | 9 ++ .../port/out/PrincipalPasswordResetter.java | 6 + .../auth/application/service/AuthService.java | 15 +- .../FilterRegistrationConfiguration.java | 2 +- .../auth/domain/exception/AuthErrorCode.java | 1 - .../interest/SpringModulithPackageInfo.java | 26 ++++ .../CompleteQuestEventScoreConsumer.java | 2 +- .../port/dto/SpringModulithPackageInfo.java | 9 ++ .../port/in/SpringModulithPackageInfo.java | 9 ++ .../member/SpringModulithPackageInfo.java | 24 +++ .../member/adapter/in/api/PasswordApi.java | 9 -- .../adapter/out/client/EmailTokenClient.java | 24 --- .../command/SpringModulithPackageInfo.java | 9 ++ .../port/dto/SpringModulithPackageInfo.java | 9 ++ .../application/port/in/PasswordResetter.java | 6 +- .../port/in/SpringModulithPackageInfo.java | 9 ++ .../port/out/EmailTokenVerifier.java | 14 -- .../application/service/PasswordService.java | 6 +- .../exception/code/MemberErrorCode.java | 3 +- .../app/core/member/domain/model/Member.java | 6 +- .../model/SpringModulithPackageInfo.java | 9 ++ .../core/point/SpringModulithPackageInfo.java | 24 +++ .../CompleteQuestEventPointConsumer.java | 2 +- .../port/in/SpringModulithPackageInfo.java | 9 ++ .../core/quest/SpringModulithPackageInfo.java | 30 ++++ .../consumer/FillQuestPoolEventConsumer.java | 2 +- .../service/AssignQuestCompleteService.java | 2 +- .../service/QuestPoolEventService.java | 2 +- .../streak/SpringModulithPackageInfo.java | 24 +++ .../CompleteQuestEventStreakConsumer.java | 2 +- .../port/in/SpringModulithPackageInfo.java | 9 ++ .../survey/SpringModulithPackageInfo.java | 12 ++ .../LogSimulator.java | 2 +- .../diagnostic/SpringModulithPackageInfo.java | 12 ++ .../evententry/SpringModulithPackageInfo.java | 18 +++ .../port/SpringModulithPackageInfo.java | 9 ++ .../model/SpringModulithPackageInfo.java | 9 ++ .../image/SpringModulithPackageInfo.java | 16 ++ .../port/in/SpringModulithPackageInfo.java | 9 ++ .../llm/SpringModulithPackageInfo.java | 12 ++ .../SpringModulithPackageInfo.java | 9 ++ .../logging/SpringModulithPackageInfo.java | 12 ++ .../SpringModulithPackageInfo.java | 12 ++ .../port/in/SpringModulithPackageInfo.java | 9 ++ .../model/SpringModulithPackageInfo.java | 9 ++ .../api/ResetPasswordDocumentationTest.java | 12 +- .../in/api/snippet/ResetPasswordSnippet.java | 4 +- .../application/service/AuthServiceTest.java | 24 +++ .../CompleteQuestEventScoreConsumerTest.java | 2 +- .../in/api/DeleteMemberDocumentationTest.java | 6 + .../out/client/TemporaryTokenClientTest.java | 43 ------ .../service/PasswordServiceTest.java | 7 +- .../CompleteQuestEventPointConsumerTest.java | 2 +- .../CompleteQuestEventStreakConsumerTest.java | 2 +- ...nnotationBasedModuleDetectionStrategy.java | 15 ++ .../gomo/app/modulith/ModularityTests.java | 31 ++++ src/test/resources/META-INF/spring.factories | 2 + 81 files changed, 851 insertions(+), 250 deletions(-) create mode 100644 src/docs/asciidoc/modulith-index.adoc create mode 100644 src/main/java/com/gomo/app/common/arch/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/common/config/SpringModulithPackageInfo.java rename src/main/java/com/gomo/app/{ => common}/config/WebConfiguration.java (93%) create mode 100644 src/main/java/com/gomo/app/common/displayorder/SpringModulithPackageInfo.java rename src/main/java/com/gomo/app/{core/quest/domain => common}/event/CompleteQuestEvent.java (90%) rename src/main/java/com/gomo/app/{core/quest/domain => common}/event/CreateQuestPoolEvent.java (90%) create mode 100644 src/main/java/com/gomo/app/common/event/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/common/exception/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/common/jpa/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/common/logging/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/common/session/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/common/util/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/common/web/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/core/auth/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/core/auth/adapter/in/api/request/ResetPasswordRequest.java create mode 100644 src/main/java/com/gomo/app/core/auth/application/port/in/PasswordResetProcessor.java create mode 100644 src/main/java/com/gomo/app/core/auth/application/port/in/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/core/auth/application/port/out/PrincipalPasswordResetter.java rename src/main/java/com/gomo/app/{ => core/auth}/config/FilterRegistrationConfiguration.java (98%) create mode 100644 src/main/java/com/gomo/app/core/interest/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/core/interest/application/port/dto/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/core/interest/application/port/in/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/core/member/SpringModulithPackageInfo.java delete mode 100644 src/main/java/com/gomo/app/core/member/adapter/out/client/EmailTokenClient.java create mode 100644 src/main/java/com/gomo/app/core/member/application/port/command/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/core/member/application/port/dto/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/core/member/application/port/in/SpringModulithPackageInfo.java delete mode 100644 src/main/java/com/gomo/app/core/member/application/port/out/EmailTokenVerifier.java create mode 100644 src/main/java/com/gomo/app/core/member/domain/model/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/core/point/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/core/point/application/port/in/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/core/quest/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/core/streak/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/core/streak/application/port/in/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/core/survey/SpringModulithPackageInfo.java rename src/main/java/com/gomo/app/support/{diagnositc => diagnostic}/LogSimulator.java (98%) create mode 100644 src/main/java/com/gomo/app/support/diagnostic/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/support/evententry/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/support/evententry/application/port/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/support/evententry/domain/model/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/support/image/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/support/image/application/port/in/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/support/llm/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/support/llm/application/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/support/logging/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/support/messagebroker/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/support/messagebroker/application/port/in/SpringModulithPackageInfo.java create mode 100644 src/main/java/com/gomo/app/support/messagebroker/domain/model/SpringModulithPackageInfo.java rename src/test/java/com/gomo/app/core/{member => auth}/adapter/in/api/ResetPasswordDocumentationTest.java (80%) rename src/test/java/com/gomo/app/core/{member => auth}/adapter/in/api/snippet/ResetPasswordSnippet.java (93%) delete mode 100644 src/test/java/com/gomo/app/core/member/adapter/out/client/TemporaryTokenClientTest.java create mode 100644 src/test/java/com/gomo/app/modulith/AnnotationBasedModuleDetectionStrategy.java create mode 100644 src/test/java/com/gomo/app/modulith/ModularityTests.java create mode 100644 src/test/resources/META-INF/spring.factories diff --git a/build.gradle b/build.gradle index c7854e63..307e2020 100644 --- a/build.gradle +++ b/build.gradle @@ -35,6 +35,11 @@ repositories { mavenCentral() } +ext { + set('springModulithVersion', "1.4.4") + snippetsDir = file('build/generated-snippets') +} + dependencies { // web implementation 'org.springframework.boot:spring-boot-starter-web' @@ -91,10 +96,14 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-actuator' runtimeOnly 'io.micrometer:micrometer-registry-prometheus' - // batch + // spring batch implementation("org.springframework.boot:spring-boot-starter-batch") implementation("org.springframework.boot:spring-boot-starter-quartz") + // spring modulith + implementation 'org.springframework.modulith:spring-modulith-starter-jpa' + testImplementation 'org.springframework.modulith:spring-modulith-starter-test' + // test testRuntimeOnly "org.junit.platform:junit-platform-launcher" testImplementation "org.springframework.boot:spring-boot-starter-test" @@ -110,8 +119,10 @@ dependencies { testImplementation "org.testcontainers:minio" } -ext { - snippetsDir = file('build/generated-snippets') +dependencyManagement { + imports { + mavenBom "org.springframework.modulith:spring-modulith-bom:${springModulithVersion}" + } } tasks.named('test') { diff --git a/src/docs/asciidoc/apis/auth-api.adoc b/src/docs/asciidoc/apis/auth-api.adoc index ba4fe7aa..8a4ac6af 100644 --- a/src/docs/asciidoc/apis/auth-api.adoc +++ b/src/docs/asciidoc/apis/auth-api.adoc @@ -18,6 +18,26 @@ operation::auth-signup[snippets='http-response,response-fields'] ''' +=== 비밀번호 초기화 (찾기) + +`PUT /auth/passwords/reset` + +이메일 인증 등을 통해 본인인증이 완료된 사용자가 비밀번호를 새로 설정합니다. + +==== 요청 헤더 + +operation::auth-password-reset[snippets='request-headers'] + +==== 요청 본문 (JSON) + +operation::auth-password-reset[snippets='http-request,request-fields'] + +==== 성공 응답 + +성공 시 `204 No Content` 상태 코드와 함께 빈 응답 본문을 반환합니다. + +''' + === 로그인 `POST /auth/login` diff --git a/src/docs/asciidoc/apis/member-api.adoc b/src/docs/asciidoc/apis/member-api.adoc index 0fb6cb74..41e4aea5 100644 --- a/src/docs/asciidoc/apis/member-api.adoc +++ b/src/docs/asciidoc/apis/member-api.adoc @@ -153,30 +153,6 @@ operation::member-quest-property-read-error[snippets='http-response,response-fie ''' -=== 비밀번호 초기화 (찾기) - -`PUT /members/passwords/reset` - -이메일 인증 등을 통해 본인인증이 완료된 사용자가 비밀번호를 새로 설정합니다. - -==== 요청 헤더 - -operation::member-password-reset[snippets='request-headers'] - -==== 요청 본문 (JSON) - -operation::member-password-reset[snippets='http-request,request-fields'] - -==== 성공 응답 - -성공 시 `204 No Content` 상태 코드와 함께 빈 응답 본문을 반환합니다. - -==== 에러 응답 - -operation::member-password-reset-error[snippets='http-response,response-fields'] - -''' - === 핸들 수정 `PUT /members/handles` diff --git a/src/docs/asciidoc/index.adoc b/src/docs/asciidoc/index.adoc index 0c6e1d1f..f4919476 100644 --- a/src/docs/asciidoc/index.adoc +++ b/src/docs/asciidoc/index.adoc @@ -1,4 +1,4 @@ -= gomo api docs += GOMO Docs - API :doctype: book :source-highlighter: highlightjs :toc: left @@ -15,7 +15,6 @@ include::apis/auth-api.adoc[] `AUT-ROO-001`: Auth code is incorrect + `AUT-ROO-002`: Refresh token not found + `AUT-ROO-003`: Refresh token is incorrect + -`AUT-ROO-004`: OAuth member cannot login with password + `AUT-ROO-005`: Principal already exists + `AUT-ROO-006`: Principal not found + `AUT-ROO-007`: Verified email token is incorrect + @@ -30,6 +29,7 @@ include::apis/member-api.adoc[] `MEM-ROO-001`: Member not found + `MEM-ROO-002`: Access denied for the member + `MEM-ROO-003`: Member Authentication fail + +`MEM-ROO-004`: OAuth member cannot login with password + `MEM-EMA-001`: Email must not be blank + `MEM-EMA-002`: Email must be at least 10 characters + diff --git a/src/docs/asciidoc/modulith-index.adoc b/src/docs/asciidoc/modulith-index.adoc new file mode 100644 index 00000000..14f667af --- /dev/null +++ b/src/docs/asciidoc/modulith-index.adoc @@ -0,0 +1,67 @@ += GOMO Docs - Module +:modulith-docs: ../../../build/spring-modulith-docs + +== core-auth + +plantuml::{modulith-docs}/module-core-auth.puml[format="svg"] +include::{modulith-docs}/module-core-auth.adoc[] + +== core-member + +plantuml::{modulith-docs}/module-core-member.puml[format="svg"] +include::{modulith-docs}/module-core-member.adoc[] + +== core-interest + +plantuml::{modulith-docs}/module-core-interest.puml[format="svg"] +include::{modulith-docs}/module-core-interest.adoc[] + +== core-quest + +plantuml::{modulith-docs}/module-core-quest.puml[format="svg"] +include::{modulith-docs}/module-core-quest.adoc[] + +== core-streak + +plantuml::{modulith-docs}/module-core-streak.puml[format="svg"] +include::{modulith-docs}/module-core-streak.adoc[] + +== core-point + +plantuml::{modulith-docs}/module-core-point.puml[format="svg"] +include::{modulith-docs}/module-core-point.adoc[] + +== core-survey + +plantuml::{modulith-docs}/module-core-survey.puml[format="svg"] +include::{modulith-docs}/module-core-survey.adoc[] + +== support-image + +plantuml::{modulith-docs}/module-support-image.puml[format="svg"] +include::{modulith-docs}/module-support-image.adoc[] + +== support-messagebroker + +plantuml::{modulith-docs}/module-support-messagebroker.puml[format="svg"] +include::{modulith-docs}/module-support-messagebroker.adoc[] + +== support-logging + +plantuml::{modulith-docs}/module-support-logging.puml[format="svg"] +include::{modulith-docs}/module-support-logging.adoc[] + +== support-evententry + +plantuml::{modulith-docs}/module-support-evententry.puml[format="svg"] +include::{modulith-docs}/module-support-evententry.adoc[] + +== support-llm + +plantuml::{modulith-docs}/module-support-llm.puml[format="svg"] +include::{modulith-docs}/module-support-llm.adoc[] + +== support-diagnostic + +plantuml::{modulith-docs}/module-support-diagnostic.puml[format="svg"] +include::{modulith-docs}/module-support-diagnostic.adoc[] diff --git a/src/main/java/com/gomo/app/batch/MemberCleanupScheduler.java b/src/main/java/com/gomo/app/batch/MemberCleanupScheduler.java index df267ac4..45e6c32a 100644 --- a/src/main/java/com/gomo/app/batch/MemberCleanupScheduler.java +++ b/src/main/java/com/gomo/app/batch/MemberCleanupScheduler.java @@ -1,90 +1,70 @@ package com.gomo.app.batch; -import java.time.LocalDateTime; -import java.util.List; -import java.util.concurrent.CompletableFuture; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.scheduling.annotation.Async; -import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; -import com.gomo.app.core.interest.domain.repository.InterestRelationRepository; -import com.gomo.app.core.interest.domain.repository.InterestRepository; -import com.gomo.app.core.interest.domain.repository.MajorInterestRepository; -import com.gomo.app.core.member.domain.model.Member; -import com.gomo.app.core.member.domain.repository.MemberRepository; -import com.gomo.app.core.point.domain.repository.PointRepository; -import com.gomo.app.core.point.domain.repository.PointWalletRepository; -import com.gomo.app.core.quest.domain.repository.AssignQuestRepository; -import com.gomo.app.core.quest.domain.repository.RepeatQuestRepository; -import com.gomo.app.core.streak.domain.repository.AchieverRepository; -import com.gomo.app.core.streak.domain.repository.StreakRepository; -import com.gomo.app.support.image.application.port.in.ImageDeleter; - import lombok.RequiredArgsConstructor; @Component @RequiredArgsConstructor public class MemberCleanupScheduler { - private final ImageDeleter imageDeleter; - private final PointRepository pointRepository; - private final PointWalletRepository pointWalletRepository; - private final AssignQuestRepository assignQuestRepository; - private final RepeatQuestRepository repeatQuestRepository; - private final InterestRelationRepository interestRelationRepository; - private final MajorInterestRepository majorInterestRepository; - private final InterestRepository interestRepository; - private final StreakRepository streakRepository; - private final AchieverRepository achieverRepository; - private final MemberRepository memberRepository; - - @Value("${app.members.retentionDays}") - private long retentionDays; - - @Scheduled(cron = "0 0 2 * * *") - public void memberDataCleanUp() { - List deletedMembers = memberRepository.findByDeletedAtBefore(LocalDateTime.now().minusDays(retentionDays)); - - for (Member member : deletedMembers) { - cleanupMemberDataAsync(member); - } - } - - @Async("memberCleanupExecutor") - public CompletableFuture cleanupMemberDataAsync(Member member) { - try { - deleteMemberAndRelatedData(member); - return CompletableFuture.completedFuture(null); - } catch (Exception e) { - return CompletableFuture.failedFuture(e); - } - } - - private void deleteMemberAndRelatedData(Member member) { - // Quest 관련 데이터 삭제 - assignQuestRepository.deleteAllByParticipantId(member.getId()); - repeatQuestRepository.deleteAllByParticipantId(member.getId()); - - // Interest 관련 데이터 삭제 - interestRelationRepository.deleteAllByRegistrantId(member.getId()); - majorInterestRepository.deleteAllByRegistrantId(member.getId()); - interestRepository.deleteAllByRegistrantId(member.getId()); - - // Point 관련 데이터 삭제 - pointRepository.deleteAllByTransactorId(member.getId()); - pointWalletRepository.deletePointWalletByTransactorId(member.getId()); - - // Streak 관련 데이터 삭제 - streakRepository.deleteAllByAchieverId(member.getId()); - achieverRepository.deleteByAchieverId(member.getId()); - - // 이미지 파일 삭제 - imageDeleter.delete(member.profileImageUrl()); - imageDeleter.delete(member.profileBannerUrl()); - - // member 최종 삭제 - memberRepository.deleteById(member.getId()); - } + // private final ImageDeleter imageDeleter; + // private final PointRepository pointRepository; + // private final PointWalletRepository pointWalletRepository; + // private final AssignQuestRepository assignQuestRepository; + // private final RepeatQuestRepository repeatQuestRepository; + // private final InterestRelationRepository interestRelationRepository; + // private final MajorInterestRepository majorInterestRepository; + // private final InterestRepository interestRepository; + // private final StreakRepository streakRepository; + // private final AchieverRepository achieverRepository; + // private final MemberRepository memberRepository; + // + // @Value("${app.members.retentionDays}") + // private long retentionDays; + // + // @Scheduled(cron = "0 0 2 * * *") + // public void memberDataCleanUp() { + // List deletedMembers = memberRepository.findByDeletedAtBefore(LocalDateTime.now().minusDays(retentionDays)); + // + // for (Member member : deletedMembers) { + // cleanupMemberDataAsync(member); + // } + // } + // + // @Async("memberCleanupExecutor") + // public CompletableFuture cleanupMemberDataAsync(Member member) { + // try { + // deleteMemberAndRelatedData(member); + // return CompletableFuture.completedFuture(null); + // } catch (Exception e) { + // return CompletableFuture.failedFuture(e); + // } + // } + // + // private void deleteMemberAndRelatedData(Member member) { + // // Quest 관련 데이터 삭제 + // assignQuestRepository.deleteAllByParticipantId(member.getId()); + // repeatQuestRepository.deleteAllByParticipantId(member.getId()); + // + // // Interest 관련 데이터 삭제 + // interestRelationRepository.deleteAllByRegistrantId(member.getId()); + // majorInterestRepository.deleteAllByRegistrantId(member.getId()); + // interestRepository.deleteAllByRegistrantId(member.getId()); + // + // // Point 관련 데이터 삭제 + // pointRepository.deleteAllByTransactorId(member.getId()); + // pointWalletRepository.deletePointWalletByTransactorId(member.getId()); + // + // // Streak 관련 데이터 삭제 + // streakRepository.deleteAllByAchieverId(member.getId()); + // achieverRepository.deleteByAchieverId(member.getId()); + // + // // 이미지 파일 삭제 + // imageDeleter.delete(member.profileImageUrl()); + // imageDeleter.delete(member.profileBannerUrl()); + // + // // member 최종 삭제 + // memberRepository.deleteById(member.getId()); + // } } diff --git a/src/main/java/com/gomo/app/common/arch/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/common/arch/SpringModulithPackageInfo.java new file mode 100644 index 00000000..81f0ddbf --- /dev/null +++ b/src/main/java/com/gomo/app/common/arch/SpringModulithPackageInfo.java @@ -0,0 +1,12 @@ +package com.gomo.app.common.arch; + +import org.springframework.modulith.ApplicationModule; +import org.springframework.modulith.PackageInfo; + +@ApplicationModule( + id = "common-arch", + displayName = "common-arch" +) +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/common/config/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/common/config/SpringModulithPackageInfo.java new file mode 100644 index 00000000..c727a026 --- /dev/null +++ b/src/main/java/com/gomo/app/common/config/SpringModulithPackageInfo.java @@ -0,0 +1,12 @@ +package com.gomo.app.common.config; + +import org.springframework.modulith.ApplicationModule; +import org.springframework.modulith.PackageInfo; + +@ApplicationModule( + id = "common-config", + displayName = "common-config" +) +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/config/WebConfiguration.java b/src/main/java/com/gomo/app/common/config/WebConfiguration.java similarity index 93% rename from src/main/java/com/gomo/app/config/WebConfiguration.java rename to src/main/java/com/gomo/app/common/config/WebConfiguration.java index 41d36129..0aabf3d7 100644 --- a/src/main/java/com/gomo/app/config/WebConfiguration.java +++ b/src/main/java/com/gomo/app/common/config/WebConfiguration.java @@ -1,4 +1,4 @@ -package com.gomo.app.config; +package com.gomo.app.common.config; import java.util.List; diff --git a/src/main/java/com/gomo/app/common/displayorder/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/common/displayorder/SpringModulithPackageInfo.java new file mode 100644 index 00000000..dde4a767 --- /dev/null +++ b/src/main/java/com/gomo/app/common/displayorder/SpringModulithPackageInfo.java @@ -0,0 +1,12 @@ +package com.gomo.app.common.displayorder; + +import org.springframework.modulith.ApplicationModule; +import org.springframework.modulith.PackageInfo; + +@ApplicationModule( + id = "common-displayorder", + displayName = "common-displayorder" +) +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/core/quest/domain/event/CompleteQuestEvent.java b/src/main/java/com/gomo/app/common/event/CompleteQuestEvent.java similarity index 90% rename from src/main/java/com/gomo/app/core/quest/domain/event/CompleteQuestEvent.java rename to src/main/java/com/gomo/app/common/event/CompleteQuestEvent.java index f664e21d..d9759722 100644 --- a/src/main/java/com/gomo/app/core/quest/domain/event/CompleteQuestEvent.java +++ b/src/main/java/com/gomo/app/common/event/CompleteQuestEvent.java @@ -1,10 +1,8 @@ -package com.gomo.app.core.quest.domain.event; +package com.gomo.app.common.event; import java.time.LocalDateTime; import java.util.UUID; -import com.gomo.app.common.event.Event; -import com.gomo.app.common.event.EventRouting; import com.gomo.app.core.quest.domain.model.quest.QuestType; import lombok.AccessLevel; diff --git a/src/main/java/com/gomo/app/core/quest/domain/event/CreateQuestPoolEvent.java b/src/main/java/com/gomo/app/common/event/CreateQuestPoolEvent.java similarity index 90% rename from src/main/java/com/gomo/app/core/quest/domain/event/CreateQuestPoolEvent.java rename to src/main/java/com/gomo/app/common/event/CreateQuestPoolEvent.java index 9aedd81d..667a2184 100644 --- a/src/main/java/com/gomo/app/core/quest/domain/event/CreateQuestPoolEvent.java +++ b/src/main/java/com/gomo/app/common/event/CreateQuestPoolEvent.java @@ -1,10 +1,8 @@ -package com.gomo.app.core.quest.domain.event; +package com.gomo.app.common.event; import java.util.List; import java.util.UUID; -import com.gomo.app.common.event.Event; -import com.gomo.app.common.event.EventRouting; import com.gomo.app.core.quest.domain.model.quest.QuestType; import lombok.AccessLevel; diff --git a/src/main/java/com/gomo/app/common/event/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/common/event/SpringModulithPackageInfo.java new file mode 100644 index 00000000..43178487 --- /dev/null +++ b/src/main/java/com/gomo/app/common/event/SpringModulithPackageInfo.java @@ -0,0 +1,12 @@ +package com.gomo.app.common.event; + +import org.springframework.modulith.ApplicationModule; +import org.springframework.modulith.PackageInfo; + +@ApplicationModule( + id = "common-event", + displayName = "common-event" +) +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/common/exception/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/common/exception/SpringModulithPackageInfo.java new file mode 100644 index 00000000..e07b99d2 --- /dev/null +++ b/src/main/java/com/gomo/app/common/exception/SpringModulithPackageInfo.java @@ -0,0 +1,12 @@ +package com.gomo.app.common.exception; + +import org.springframework.modulith.ApplicationModule; +import org.springframework.modulith.PackageInfo; + +@ApplicationModule( + id = "common-exception", + displayName = "common-exception" +) +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/common/jpa/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/common/jpa/SpringModulithPackageInfo.java new file mode 100644 index 00000000..559106ce --- /dev/null +++ b/src/main/java/com/gomo/app/common/jpa/SpringModulithPackageInfo.java @@ -0,0 +1,12 @@ +package com.gomo.app.common.jpa; + +import org.springframework.modulith.ApplicationModule; +import org.springframework.modulith.PackageInfo; + +@ApplicationModule( + id = "common-jpa", + displayName = "common-jpa" +) +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/common/logging/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/common/logging/SpringModulithPackageInfo.java new file mode 100644 index 00000000..c3b2bfea --- /dev/null +++ b/src/main/java/com/gomo/app/common/logging/SpringModulithPackageInfo.java @@ -0,0 +1,12 @@ +package com.gomo.app.common.logging; + +import org.springframework.modulith.ApplicationModule; +import org.springframework.modulith.PackageInfo; + +@ApplicationModule( + id = "common-logging", + displayName = "common-logging" +) +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/common/session/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/common/session/SpringModulithPackageInfo.java new file mode 100644 index 00000000..2a5417a7 --- /dev/null +++ b/src/main/java/com/gomo/app/common/session/SpringModulithPackageInfo.java @@ -0,0 +1,12 @@ +package com.gomo.app.common.session; + +import org.springframework.modulith.ApplicationModule; +import org.springframework.modulith.PackageInfo; + +@ApplicationModule( + id = "common-session", + displayName = "common-session" +) +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/common/util/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/common/util/SpringModulithPackageInfo.java new file mode 100644 index 00000000..6ca019c8 --- /dev/null +++ b/src/main/java/com/gomo/app/common/util/SpringModulithPackageInfo.java @@ -0,0 +1,12 @@ +package com.gomo.app.common.util; + +import org.springframework.modulith.ApplicationModule; +import org.springframework.modulith.PackageInfo; + +@ApplicationModule( + id = "common-util", + displayName = "common-util" +) +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/common/web/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/common/web/SpringModulithPackageInfo.java new file mode 100644 index 00000000..c829b60b --- /dev/null +++ b/src/main/java/com/gomo/app/common/web/SpringModulithPackageInfo.java @@ -0,0 +1,12 @@ +package com.gomo.app.common.web; + +import org.springframework.modulith.ApplicationModule; +import org.springframework.modulith.PackageInfo; + +@ApplicationModule( + id = "common-web", + displayName = "common-web" +) +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/core/auth/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/core/auth/SpringModulithPackageInfo.java new file mode 100644 index 00000000..0928c382 --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/SpringModulithPackageInfo.java @@ -0,0 +1,22 @@ +package com.gomo.app.core.auth; + +import org.springframework.modulith.ApplicationModule; +import org.springframework.modulith.PackageInfo; + +@ApplicationModule( + id = "core-auth", + displayName = "core-auth", + allowedDependencies = { + "common-arch", + "common-exception", + "common-logging", + "common-session", + "core-member::in", + "core-member::model", + "core-member::command", + "support-logging" + } +) +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/core/auth/adapter/in/api/AuthApi.java b/src/main/java/com/gomo/app/core/auth/adapter/in/api/AuthApi.java index 235ad35d..6b408103 100644 --- a/src/main/java/com/gomo/app/core/auth/adapter/in/api/AuthApi.java +++ b/src/main/java/com/gomo/app/core/auth/adapter/in/api/AuthApi.java @@ -12,6 +12,7 @@ import org.springframework.web.bind.annotation.CookieValue; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -20,10 +21,12 @@ import com.gomo.app.common.session.SessionInfo; import com.gomo.app.core.auth.adapter.in.api.request.CreatePrincipalRequest; import com.gomo.app.core.auth.adapter.in.api.request.LoginRequest; +import com.gomo.app.core.auth.adapter.in.api.request.ResetPasswordRequest; import com.gomo.app.core.auth.adapter.in.api.response.AccessTokenResponse; import com.gomo.app.core.auth.adapter.in.api.response.CreatePrincipalResponse; import com.gomo.app.core.auth.application.port.dto.AuthTokenDto; import com.gomo.app.core.auth.application.port.in.LoginProcessor; +import com.gomo.app.core.auth.application.port.in.PasswordResetProcessor; import com.gomo.app.core.auth.application.port.in.RefreshTokenDeleter; import com.gomo.app.core.auth.application.port.in.RefreshTokenUpdater; import com.gomo.app.core.auth.application.port.in.SignupProcessor; @@ -36,6 +39,7 @@ public class AuthApi { private final SignupProcessor signupProcessor; + private final PasswordResetProcessor passwordResetProcessor; private final LoginProcessor loginProcessor; private final RefreshTokenUpdater refreshTokenUpdater; private final RefreshTokenDeleter refreshTokenDeleter; @@ -46,6 +50,12 @@ public ResponseEntity signup(@RequestBody CreatePrincip return ResponseEntity.status(HttpStatus.CREATED).body(CreatePrincipalResponse.of(principalId)); } + @PutMapping("/passwords/reset") + public ResponseEntity reset(@RequestBody ResetPasswordRequest request) { + passwordResetProcessor.reset(request.getEmail(), request.getNewPassword(), request.getTemporaryToken()); + return ResponseEntity.noContent().build(); + } + @PostMapping("/login") public ResponseEntity login(@RequestBody LoginRequest request) { AuthTokenDto authTokenDto = loginProcessor.login(request.getEmail(), request.getPassword()); diff --git a/src/main/java/com/gomo/app/core/auth/adapter/in/api/request/ResetPasswordRequest.java b/src/main/java/com/gomo/app/core/auth/adapter/in/api/request/ResetPasswordRequest.java new file mode 100644 index 00000000..e0262e5e --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/adapter/in/api/request/ResetPasswordRequest.java @@ -0,0 +1,21 @@ +package com.gomo.app.core.auth.adapter.in.api.request; + +import lombok.Getter; + +@Getter +public class ResetPasswordRequest { + + private final String email; + private final String newPassword; + private final String temporaryToken; + + private ResetPasswordRequest(String email, String newPassword, String temporaryToken) { + this.email = email; + this.newPassword = newPassword; + this.temporaryToken = temporaryToken; + } + + public static ResetPasswordRequest of(String email, String newPassword, String temporaryToken) { + return new ResetPasswordRequest(email, newPassword, temporaryToken); + } +} diff --git a/src/main/java/com/gomo/app/core/auth/adapter/out/client/MemberClient.java b/src/main/java/com/gomo/app/core/auth/adapter/out/client/MemberClient.java index 85f614e4..8e237441 100644 --- a/src/main/java/com/gomo/app/core/auth/adapter/out/client/MemberClient.java +++ b/src/main/java/com/gomo/app/core/auth/adapter/out/client/MemberClient.java @@ -4,26 +4,29 @@ import java.util.UUID; import com.gomo.app.common.arch.Adapter; -import com.gomo.app.core.member.application.port.in.EmailChecker; -import com.gomo.app.core.member.application.port.in.MemberCreator; -import com.gomo.app.core.member.application.port.in.MemberLoginProcessor; -import com.gomo.app.core.member.application.port.in.MemberOAuthLoginProcessor; import com.gomo.app.core.auth.application.port.command.CreatePrincipalCommand; import com.gomo.app.core.auth.application.port.out.PrincipalCreator; import com.gomo.app.core.auth.application.port.out.PrincipalEmailChecker; import com.gomo.app.core.auth.application.port.out.PrincipalLoginProcessor; import com.gomo.app.core.auth.application.port.out.PrincipalOAuthLoginProcessor; +import com.gomo.app.core.auth.application.port.out.PrincipalPasswordResetter; +import com.gomo.app.core.member.application.port.in.EmailChecker; +import com.gomo.app.core.member.application.port.in.MemberCreator; +import com.gomo.app.core.member.application.port.in.MemberLoginProcessor; +import com.gomo.app.core.member.application.port.in.MemberOAuthLoginProcessor; +import com.gomo.app.core.member.application.port.in.PasswordResetter; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @Adapter -class MemberClient implements PrincipalCreator, PrincipalEmailChecker, PrincipalLoginProcessor, PrincipalOAuthLoginProcessor { +class MemberClient implements PrincipalCreator, PrincipalEmailChecker, PrincipalLoginProcessor, PrincipalOAuthLoginProcessor, PrincipalPasswordResetter { private final MemberCreator memberCreator; private final EmailChecker emailChecker; private final MemberLoginProcessor memberLoginProcessor; private final MemberOAuthLoginProcessor memberOAuthLoginProcessor; + private final PasswordResetter passwordResetter; @Override public UUID create(CreatePrincipalCommand command) { @@ -44,4 +47,9 @@ public UUID login(String email, String password) { public Optional login(String email) { return memberOAuthLoginProcessor.login(email); } + + @Override + public void reset(String email, String newPassword) { + passwordResetter.reset(email, newPassword); + } } diff --git a/src/main/java/com/gomo/app/core/auth/application/port/in/PasswordResetProcessor.java b/src/main/java/com/gomo/app/core/auth/application/port/in/PasswordResetProcessor.java new file mode 100644 index 00000000..d175b401 --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/application/port/in/PasswordResetProcessor.java @@ -0,0 +1,17 @@ +package com.gomo.app.core.auth.application.port.in; + +import com.gomo.app.core.member.domain.exception.MemberNotFoundException; + +public interface PasswordResetProcessor { + + /** + * Resets the password for a member after validating a temporary token. + * + * @param email The email address of the member for whom the password reset is being performed. + * @param newPassword The new raw password to be set. + * @param temporaryToken The verification token required to authorize the password change. + * @throws MemberNotFoundException if no member is found with the specified email address. + * @throws IllegalArgumentException if the provided temporary token is invalid. + */ + void reset(String email, String newPassword, String temporaryToken); +} diff --git a/src/main/java/com/gomo/app/core/auth/application/port/in/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/core/auth/application/port/in/SpringModulithPackageInfo.java new file mode 100644 index 00000000..c835079f --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/application/port/in/SpringModulithPackageInfo.java @@ -0,0 +1,9 @@ +package com.gomo.app.core.auth.application.port.in; + +import org.springframework.modulith.NamedInterface; +import org.springframework.modulith.PackageInfo; + +@NamedInterface("in") +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/core/auth/application/port/out/PrincipalPasswordResetter.java b/src/main/java/com/gomo/app/core/auth/application/port/out/PrincipalPasswordResetter.java new file mode 100644 index 00000000..8f062f2b --- /dev/null +++ b/src/main/java/com/gomo/app/core/auth/application/port/out/PrincipalPasswordResetter.java @@ -0,0 +1,6 @@ +package com.gomo.app.core.auth.application.port.out; + +public interface PrincipalPasswordResetter { + + void reset(String email, String newPassword); +} diff --git a/src/main/java/com/gomo/app/core/auth/application/service/AuthService.java b/src/main/java/com/gomo/app/core/auth/application/service/AuthService.java index 517a3371..70865882 100644 --- a/src/main/java/com/gomo/app/core/auth/application/service/AuthService.java +++ b/src/main/java/com/gomo/app/core/auth/application/service/AuthService.java @@ -9,10 +9,12 @@ import com.gomo.app.core.auth.application.port.command.CreatePrincipalCommand; import com.gomo.app.core.auth.application.port.dto.AuthTokenDto; import com.gomo.app.core.auth.application.port.in.LoginProcessor; +import com.gomo.app.core.auth.application.port.in.PasswordResetProcessor; import com.gomo.app.core.auth.application.port.in.SignupProcessor; import com.gomo.app.core.auth.application.port.out.JwtVerifier; import com.gomo.app.core.auth.application.port.out.PrincipalCreator; import com.gomo.app.core.auth.application.port.out.PrincipalLoginProcessor; +import com.gomo.app.core.auth.application.port.out.PrincipalPasswordResetter; import com.gomo.app.core.auth.domain.exception.AuthenticationFailException; import com.gomo.app.core.auth.domain.model.AuthToken; import com.gomo.app.core.member.domain.model.LoginProvider; @@ -21,12 +23,13 @@ @RequiredArgsConstructor @ApplicationService -class AuthService implements SignupProcessor, LoginProcessor { +class AuthService implements SignupProcessor, LoginProcessor, PasswordResetProcessor { private final PrincipalCreator principalCreator; private final JwtVerifier jwtVerifier; private final PrincipalLoginProcessor principalLoginProcessor; private final AuthTokenService authTokenService; + private final PrincipalPasswordResetter principalPasswordResetter; @Override @AuditLog(action = "SIGNUP") @@ -46,4 +49,14 @@ public AuthTokenDto login(String email, String password) { long expirationTime = jwtVerifier.extractExpirationTime(authToken.getRefreshToken()); return AuthTokenDto.of(principalId, authToken.getAccessToken(), authToken.getRefreshToken(), expirationTime); } + + @Override + @AuditLog(action = "TOKEN_VERIFY_AND_PASSWORD_RESET") + public void reset(String email, String newPassword, String temporaryToken) { + // TODO [2025-11-04] jhl221123 : 토큰 내부 이메일이 동일한지 확인하는 jwt 기능이 추가되어야 합니다. + if (!jwtVerifier.verify(temporaryToken)) { + throw new AuthenticationFailException(INVALID_VERIFIED_EMAIL_TOKEN); + } + principalPasswordResetter.reset(email, newPassword); + } } diff --git a/src/main/java/com/gomo/app/config/FilterRegistrationConfiguration.java b/src/main/java/com/gomo/app/core/auth/config/FilterRegistrationConfiguration.java similarity index 98% rename from src/main/java/com/gomo/app/config/FilterRegistrationConfiguration.java rename to src/main/java/com/gomo/app/core/auth/config/FilterRegistrationConfiguration.java index 96de7988..2a2b4ea7 100644 --- a/src/main/java/com/gomo/app/config/FilterRegistrationConfiguration.java +++ b/src/main/java/com/gomo/app/core/auth/config/FilterRegistrationConfiguration.java @@ -1,4 +1,4 @@ -package com.gomo.app.config; +package com.gomo.app.core.auth.config; import java.util.Arrays; diff --git a/src/main/java/com/gomo/app/core/auth/domain/exception/AuthErrorCode.java b/src/main/java/com/gomo/app/core/auth/domain/exception/AuthErrorCode.java index 65ccc08e..c6f17c8b 100644 --- a/src/main/java/com/gomo/app/core/auth/domain/exception/AuthErrorCode.java +++ b/src/main/java/com/gomo/app/core/auth/domain/exception/AuthErrorCode.java @@ -8,7 +8,6 @@ public enum AuthErrorCode { INVALID_AUTH_CODE(401, "AUT-ROO-001", "Auth code is incorrect"), MISSING_REFRESH_TOKEN(401, "AUT-ROO-002", "Refresh token not found"), INVALID_REFRESH_TOKEN(401, "AUT-ROO-003", "Refresh token is incorrect"), - UNSUPPORTED_LOGIN_METHOD(401, "AUT-ROO-004", "OAuth member cannot login with password"), PRINCIPAL_DUPLICATED(409, "AUT-ROO-005", "Principal already exists"), PRINCIPAL_NOT_FOUND(404, "AUT-ROO-006", "Principal not found"), INVALID_VERIFIED_EMAIL_TOKEN(401, "AUT-ROO-007", "Verified email token is incorrect"); diff --git a/src/main/java/com/gomo/app/core/interest/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/core/interest/SpringModulithPackageInfo.java new file mode 100644 index 00000000..b93e6dc7 --- /dev/null +++ b/src/main/java/com/gomo/app/core/interest/SpringModulithPackageInfo.java @@ -0,0 +1,26 @@ +package com.gomo.app.core.interest; + +import org.springframework.modulith.ApplicationModule; + +@ApplicationModule( + id = "core-interest", + displayName = "core-interest", + allowedDependencies = { + "common-arch", + "common-displayorder", + "common-event", + "common-exception", + "common-jpa", + "common-logging", + "common-session", + "common-util", + "core-member::in", + "core-member::dto", + "support-evententry::in", + "support-evententry::model", + "support-image::in" + } +) +@org.springframework.modulith.PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/core/interest/adapter/in/consumer/CompleteQuestEventScoreConsumer.java b/src/main/java/com/gomo/app/core/interest/adapter/in/consumer/CompleteQuestEventScoreConsumer.java index 8cd7c5d3..a33acd72 100644 --- a/src/main/java/com/gomo/app/core/interest/adapter/in/consumer/CompleteQuestEventScoreConsumer.java +++ b/src/main/java/com/gomo/app/core/interest/adapter/in/consumer/CompleteQuestEventScoreConsumer.java @@ -3,9 +3,9 @@ import org.springframework.amqp.rabbit.annotation.RabbitListener; import com.gomo.app.common.arch.EventConsumer; +import com.gomo.app.common.event.CompleteQuestEvent; import com.gomo.app.common.util.JsonParser; import com.gomo.app.core.interest.application.port.in.ProficiencyPropagator; -import com.gomo.app.core.quest.domain.event.CompleteQuestEvent; import com.gomo.app.support.evententry.application.port.IdempotentEventEntryConsumer; import com.gomo.app.support.evententry.domain.model.EventEntry; diff --git a/src/main/java/com/gomo/app/core/interest/application/port/dto/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/core/interest/application/port/dto/SpringModulithPackageInfo.java new file mode 100644 index 00000000..90f60f6f --- /dev/null +++ b/src/main/java/com/gomo/app/core/interest/application/port/dto/SpringModulithPackageInfo.java @@ -0,0 +1,9 @@ +package com.gomo.app.core.interest.application.port.dto; + +import org.springframework.modulith.NamedInterface; +import org.springframework.modulith.PackageInfo; + +@NamedInterface("dto") +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/core/interest/application/port/in/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/core/interest/application/port/in/SpringModulithPackageInfo.java new file mode 100644 index 00000000..97f553cd --- /dev/null +++ b/src/main/java/com/gomo/app/core/interest/application/port/in/SpringModulithPackageInfo.java @@ -0,0 +1,9 @@ +package com.gomo.app.core.interest.application.port.in; + +import org.springframework.modulith.NamedInterface; +import org.springframework.modulith.PackageInfo; + +@NamedInterface("in") +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/core/member/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/core/member/SpringModulithPackageInfo.java new file mode 100644 index 00000000..085373aa --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/SpringModulithPackageInfo.java @@ -0,0 +1,24 @@ +package com.gomo.app.core.member; + +import org.springframework.modulith.ApplicationModule; +import org.springframework.modulith.PackageInfo; + +@ApplicationModule( + id = "core-member", + displayName = "core-member", + allowedDependencies = { + "common-arch", + "common-exception", + "common-jpa", + "common-logging", + "common-session", + "common-util", + "core-point::in", + "core-streak::in", + "support-logging", + "support-image::in" + } +) +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/core/member/adapter/in/api/PasswordApi.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/PasswordApi.java index 31603d95..92b99574 100644 --- a/src/main/java/com/gomo/app/core/member/adapter/in/api/PasswordApi.java +++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/PasswordApi.java @@ -8,9 +8,7 @@ import com.gomo.app.common.arch.CoreApi; import com.gomo.app.common.session.Session; import com.gomo.app.common.session.SessionInfo; -import com.gomo.app.core.member.adapter.in.api.request.ResetPasswordRequest; import com.gomo.app.core.member.adapter.in.api.request.UpdatePasswordRequest; -import com.gomo.app.core.member.application.port.in.PasswordResetter; import com.gomo.app.core.member.application.port.in.PasswordUpdater; import lombok.RequiredArgsConstructor; @@ -21,17 +19,10 @@ public class PasswordApi { private final PasswordUpdater passwordUpdater; - private final PasswordResetter passwordResetter; @PutMapping public ResponseEntity update(@Session SessionInfo sessionInfo, @RequestBody UpdatePasswordRequest request) { passwordUpdater.update(sessionInfo.getPrincipalId(), request.getOriginPassword(), request.getNewPassword()); return ResponseEntity.noContent().build(); } - - @PutMapping("/reset") - public ResponseEntity reset(@RequestBody ResetPasswordRequest request) { - passwordResetter.reset(request.getEmail(), request.getNewPassword(), request.getTemporaryToken()); - return ResponseEntity.noContent().build(); - } } diff --git a/src/main/java/com/gomo/app/core/member/adapter/out/client/EmailTokenClient.java b/src/main/java/com/gomo/app/core/member/adapter/out/client/EmailTokenClient.java deleted file mode 100644 index 39ddf001..00000000 --- a/src/main/java/com/gomo/app/core/member/adapter/out/client/EmailTokenClient.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.gomo.app.core.member.adapter.out.client; - -import com.gomo.app.common.arch.Adapter; -import com.gomo.app.core.member.application.port.out.EmailTokenVerifier; -import com.gomo.app.core.auth.application.port.out.JwtVerifier; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Adapter -class EmailTokenClient implements EmailTokenVerifier { - - private final JwtVerifier jwtVerifier; - - // TODO [2025-11-02] jhl221123 : 인증 모듈의 책임입니다. - @Override - public void verify(String temporaryToken) { - // TODO [2025-10-18] jhl221123 : jwt 형식 뿐 아니라 내부 이메일이 요청한 이메일과 같은지 검증이 필요합니다. - // TODO [2025-10-19] jhl221123 : 커스텀 예외를 반환하도록 수정해야합니다. - if (!jwtVerifier.verify(temporaryToken)) { - throw new IllegalArgumentException("Invalid temporary token"); - } - } -} diff --git a/src/main/java/com/gomo/app/core/member/application/port/command/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/core/member/application/port/command/SpringModulithPackageInfo.java new file mode 100644 index 00000000..4149cfd0 --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/port/command/SpringModulithPackageInfo.java @@ -0,0 +1,9 @@ +package com.gomo.app.core.member.application.port.command; + +import org.springframework.modulith.NamedInterface; +import org.springframework.modulith.PackageInfo; + +@NamedInterface("command") +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/core/member/application/port/dto/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/core/member/application/port/dto/SpringModulithPackageInfo.java new file mode 100644 index 00000000..070ca5e7 --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/port/dto/SpringModulithPackageInfo.java @@ -0,0 +1,9 @@ +package com.gomo.app.core.member.application.port.dto; + +import org.springframework.modulith.NamedInterface; +import org.springframework.modulith.PackageInfo; + +@NamedInterface("dto") +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/core/member/application/port/in/PasswordResetter.java b/src/main/java/com/gomo/app/core/member/application/port/in/PasswordResetter.java index f69e19b2..4b4253a0 100644 --- a/src/main/java/com/gomo/app/core/member/application/port/in/PasswordResetter.java +++ b/src/main/java/com/gomo/app/core/member/application/port/in/PasswordResetter.java @@ -5,13 +5,11 @@ public interface PasswordResetter { /** - * Resets the password for a member after validating a temporary token. + * Resets the password for a member. * * @param email The email address of the member for whom the password reset is being performed. * @param newPassword The new raw password to be set. - * @param temporaryToken The verification token required to authorize the password change. * @throws MemberNotFoundException if no member is found with the specified email address. - * @throws IllegalArgumentException if the provided temporary token is invalid. */ - void reset(String email, String newPassword, String temporaryToken); + void reset(String email, String newPassword); } diff --git a/src/main/java/com/gomo/app/core/member/application/port/in/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/core/member/application/port/in/SpringModulithPackageInfo.java new file mode 100644 index 00000000..8d155660 --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/application/port/in/SpringModulithPackageInfo.java @@ -0,0 +1,9 @@ +package com.gomo.app.core.member.application.port.in; + +import org.springframework.modulith.NamedInterface; +import org.springframework.modulith.PackageInfo; + +@NamedInterface("in") +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/core/member/application/port/out/EmailTokenVerifier.java b/src/main/java/com/gomo/app/core/member/application/port/out/EmailTokenVerifier.java deleted file mode 100644 index d699a6db..00000000 --- a/src/main/java/com/gomo/app/core/member/application/port/out/EmailTokenVerifier.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.gomo.app.core.member.application.port.out; - -public interface EmailTokenVerifier { - - // TODO [2025-11-02] jhl221123 : 인증 모듈의 책임입니다. - - /** - * Verifies the validity of a temporary token, typically used for processes like email verification. - * - * @param temporaryToken The temporary token string to be validated. - * @throws IllegalArgumentException if the token is invalid, expired, or malformed. - */ - void verify(String temporaryToken); -} diff --git a/src/main/java/com/gomo/app/core/member/application/service/PasswordService.java b/src/main/java/com/gomo/app/core/member/application/service/PasswordService.java index 6a1fb59e..0ee8f9b1 100644 --- a/src/main/java/com/gomo/app/core/member/application/service/PasswordService.java +++ b/src/main/java/com/gomo/app/core/member/application/service/PasswordService.java @@ -8,7 +8,6 @@ import com.gomo.app.common.logging.AuditLog; import com.gomo.app.core.member.application.port.in.PasswordResetter; import com.gomo.app.core.member.application.port.in.PasswordUpdater; -import com.gomo.app.core.member.application.port.out.EmailTokenVerifier; import com.gomo.app.core.member.application.port.out.PasswordEncodeManager; import com.gomo.app.core.member.domain.exception.MemberAuthenticationFailedException; import com.gomo.app.core.member.domain.model.LoginProvider; @@ -23,15 +22,12 @@ @ApplicationService class PasswordService implements PasswordResetter, PasswordUpdater { - private final EmailTokenVerifier emailTokenVerifier; private final PasswordEncodeManager passwordEncodeManager; private final MemberService memberService; @Override @AuditLog(action = "PASSWORD_RESET") - public void reset(String email, String newPassword, String temporaryToken) { - emailTokenVerifier.verify(temporaryToken); - + public void reset(String email, String newPassword) { Member member = memberService.findByEmail(email); String encoded = passwordEncodeManager.encode(Password.ofRaw(newPassword).getPassword()); member.updatePassword(Password.ofEncoded(encoded)); diff --git a/src/main/java/com/gomo/app/core/member/domain/exception/code/MemberErrorCode.java b/src/main/java/com/gomo/app/core/member/domain/exception/code/MemberErrorCode.java index eedd4a67..ed3c6209 100644 --- a/src/main/java/com/gomo/app/core/member/domain/exception/code/MemberErrorCode.java +++ b/src/main/java/com/gomo/app/core/member/domain/exception/code/MemberErrorCode.java @@ -7,7 +7,8 @@ public enum MemberErrorCode { NOT_FOUND(404, "MEM-ROO-001", "Member not found"), ACCESS_DENIED(403, "MEM-ROO-002", "Access denied for the member"), - AUTHENTICATION_FAILED(401, "MEM-ROO-003", "Member Authentication fail"); + AUTHENTICATION_FAILED(401, "MEM-ROO-003", "Member Authentication fail"), + UNSUPPORTED_LOGIN(401, "MEM-ROO-004", "OAuth member cannot login with password"); private final int httpStatus; private final String errorCode; diff --git a/src/main/java/com/gomo/app/core/member/domain/model/Member.java b/src/main/java/com/gomo/app/core/member/domain/model/Member.java index 8cd6453e..e977b4f9 100644 --- a/src/main/java/com/gomo/app/core/member/domain/model/Member.java +++ b/src/main/java/com/gomo/app/core/member/domain/model/Member.java @@ -5,9 +5,9 @@ import com.gomo.app.common.jpa.LogicalDeleteBaseAudit; import com.gomo.app.core.member.domain.exception.ActivateStatusException; +import com.gomo.app.core.member.domain.exception.MemberAuthenticationFailedException; import com.gomo.app.core.member.domain.exception.code.ActivateStatusErrorCode; -import com.gomo.app.core.auth.domain.exception.AuthErrorCode; -import com.gomo.app.core.auth.domain.exception.AuthenticationFailException; +import com.gomo.app.core.member.domain.exception.code.MemberErrorCode; import jakarta.persistence.AttributeOverride; import jakarta.persistence.AttributeOverrides; @@ -193,7 +193,7 @@ public void validateActive() { public void validateLoginProviderIsEmail() { if (this.loginProvider != LoginProvider.EMAIL) { - throw new AuthenticationFailException(AuthErrorCode.UNSUPPORTED_LOGIN_METHOD); + throw new MemberAuthenticationFailedException(MemberErrorCode.UNSUPPORTED_LOGIN); } } diff --git a/src/main/java/com/gomo/app/core/member/domain/model/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/core/member/domain/model/SpringModulithPackageInfo.java new file mode 100644 index 00000000..63fce320 --- /dev/null +++ b/src/main/java/com/gomo/app/core/member/domain/model/SpringModulithPackageInfo.java @@ -0,0 +1,9 @@ +package com.gomo.app.core.member.domain.model; + +import org.springframework.modulith.NamedInterface; +import org.springframework.modulith.PackageInfo; + +@NamedInterface("model") +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/core/point/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/core/point/SpringModulithPackageInfo.java new file mode 100644 index 00000000..48b7ed65 --- /dev/null +++ b/src/main/java/com/gomo/app/core/point/SpringModulithPackageInfo.java @@ -0,0 +1,24 @@ +package com.gomo.app.core.point; + +import org.springframework.modulith.ApplicationModule; +import org.springframework.modulith.PackageInfo; + +@ApplicationModule( + id = "core-point", + displayName = "core-point", + allowedDependencies = { + "common-arch", + "common-event", + "common-exception", + "common-jpa", + "common-logging", + "common-session", + "common-util", + "common-web", + "support-evententry::in", + "support-evententry::model", + } +) +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/core/point/adapter/in/consumer/CompleteQuestEventPointConsumer.java b/src/main/java/com/gomo/app/core/point/adapter/in/consumer/CompleteQuestEventPointConsumer.java index 5e6cd85e..854a4394 100644 --- a/src/main/java/com/gomo/app/core/point/adapter/in/consumer/CompleteQuestEventPointConsumer.java +++ b/src/main/java/com/gomo/app/core/point/adapter/in/consumer/CompleteQuestEventPointConsumer.java @@ -3,9 +3,9 @@ import org.springframework.amqp.rabbit.annotation.RabbitListener; import com.gomo.app.common.arch.EventConsumer; +import com.gomo.app.common.event.CompleteQuestEvent; import com.gomo.app.common.util.JsonParser; import com.gomo.app.core.point.application.port.in.PointCreator; -import com.gomo.app.core.quest.domain.event.CompleteQuestEvent; import com.gomo.app.support.evententry.application.port.IdempotentEventEntryConsumer; import com.gomo.app.support.evententry.domain.model.EventEntry; diff --git a/src/main/java/com/gomo/app/core/point/application/port/in/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/core/point/application/port/in/SpringModulithPackageInfo.java new file mode 100644 index 00000000..083fb1da --- /dev/null +++ b/src/main/java/com/gomo/app/core/point/application/port/in/SpringModulithPackageInfo.java @@ -0,0 +1,9 @@ +package com.gomo.app.core.point.application.port.in; + +import org.springframework.modulith.NamedInterface; +import org.springframework.modulith.PackageInfo; + +@NamedInterface("in") +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/core/quest/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/core/quest/SpringModulithPackageInfo.java new file mode 100644 index 00000000..104fc2e4 --- /dev/null +++ b/src/main/java/com/gomo/app/core/quest/SpringModulithPackageInfo.java @@ -0,0 +1,30 @@ +package com.gomo.app.core.quest; + +import org.springframework.modulith.ApplicationModule; +import org.springframework.modulith.PackageInfo; + +@ApplicationModule( + id = "core-quest", + displayName = "core-quest", + allowedDependencies = { + "common-arch", + "common-displayorder", + "common-event", + "common-exception", + "common-jpa", + "common-logging", + "common-session", + "common-util", + "core-member::in", + "core-member::dto", + "core-interest::in", + "core-interest::dto", + "support-llm::in", + "support-evententry::in", + "support-messagebroker::in", + "support-messagebroker::model", + } +) +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/core/quest/adapter/in/consumer/FillQuestPoolEventConsumer.java b/src/main/java/com/gomo/app/core/quest/adapter/in/consumer/FillQuestPoolEventConsumer.java index 6a6f0705..3e1ab3a7 100644 --- a/src/main/java/com/gomo/app/core/quest/adapter/in/consumer/FillQuestPoolEventConsumer.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/in/consumer/FillQuestPoolEventConsumer.java @@ -3,10 +3,10 @@ import org.springframework.amqp.rabbit.annotation.RabbitListener; import com.gomo.app.common.arch.EventConsumer; +import com.gomo.app.common.event.CreateQuestPoolEvent; import com.gomo.app.common.util.JsonParser; import com.gomo.app.core.quest.application.port.command.CreateQuestPoolCommand; import com.gomo.app.core.quest.application.port.in.QuestPoolCreator; -import com.gomo.app.core.quest.domain.event.CreateQuestPoolEvent; import com.gomo.app.support.messagebroker.application.port.in.IdempotentDirectEventConsumer; import com.gomo.app.support.messagebroker.domain.model.DirectEvent; diff --git a/src/main/java/com/gomo/app/core/quest/application/service/AssignQuestCompleteService.java b/src/main/java/com/gomo/app/core/quest/application/service/AssignQuestCompleteService.java index 068fa2fd..16fb73ba 100644 --- a/src/main/java/com/gomo/app/core/quest/application/service/AssignQuestCompleteService.java +++ b/src/main/java/com/gomo/app/core/quest/application/service/AssignQuestCompleteService.java @@ -5,12 +5,12 @@ import org.springframework.transaction.annotation.Transactional; import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.event.CompleteQuestEvent; import com.gomo.app.common.logging.AuditLog; import com.gomo.app.common.util.JsonParser; import com.gomo.app.common.util.TimestampGenerator; import com.gomo.app.core.quest.application.port.command.CompleteAssignQuestCommand; import com.gomo.app.core.quest.application.port.in.AssignQuestCompleter; -import com.gomo.app.core.quest.domain.event.CompleteQuestEvent; import com.gomo.app.core.quest.domain.model.assign.AssignQuest; import com.gomo.app.core.quest.domain.model.assign.CompletionProof; import com.gomo.app.core.quest.domain.model.reward.QuestReward; diff --git a/src/main/java/com/gomo/app/core/quest/application/service/QuestPoolEventService.java b/src/main/java/com/gomo/app/core/quest/application/service/QuestPoolEventService.java index 5baa9aee..9daeb9e2 100644 --- a/src/main/java/com/gomo/app/core/quest/application/service/QuestPoolEventService.java +++ b/src/main/java/com/gomo/app/core/quest/application/service/QuestPoolEventService.java @@ -7,6 +7,7 @@ import java.util.stream.Collectors; import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.common.event.CreateQuestPoolEvent; import com.gomo.app.common.event.EventRouter; import com.gomo.app.common.logging.AuditLog; import com.gomo.app.common.util.JsonParser; @@ -16,7 +17,6 @@ import com.gomo.app.core.quest.application.port.dto.SubjectDto; import com.gomo.app.core.quest.application.port.in.QuestPoolEventPublisher; import com.gomo.app.core.quest.application.port.out.SubjectReader; -import com.gomo.app.core.quest.domain.event.CreateQuestPoolEvent; import com.gomo.app.core.quest.domain.model.participant.Participant; import com.gomo.app.support.messagebroker.application.port.in.MessagePublisher; import com.gomo.app.support.messagebroker.domain.model.DirectEvent; diff --git a/src/main/java/com/gomo/app/core/streak/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/core/streak/SpringModulithPackageInfo.java new file mode 100644 index 00000000..affae844 --- /dev/null +++ b/src/main/java/com/gomo/app/core/streak/SpringModulithPackageInfo.java @@ -0,0 +1,24 @@ +package com.gomo.app.core.streak; + +import org.springframework.modulith.ApplicationModule; +import org.springframework.modulith.PackageInfo; + +@ApplicationModule( + id = "core-streak", + displayName = "core-streak", + allowedDependencies = { + "common-arch", + "common-event", + "common-exception", + "common-jpa", + "common-logging", + "common-session", + "common-util", + "common-web", + "support-evententry::in", + "support-evententry::model", + } +) +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/core/streak/adapter/in/consumer/CompleteQuestEventStreakConsumer.java b/src/main/java/com/gomo/app/core/streak/adapter/in/consumer/CompleteQuestEventStreakConsumer.java index 286d1a30..b79f50fc 100644 --- a/src/main/java/com/gomo/app/core/streak/adapter/in/consumer/CompleteQuestEventStreakConsumer.java +++ b/src/main/java/com/gomo/app/core/streak/adapter/in/consumer/CompleteQuestEventStreakConsumer.java @@ -3,8 +3,8 @@ import org.springframework.amqp.rabbit.annotation.RabbitListener; import com.gomo.app.common.arch.EventConsumer; +import com.gomo.app.common.event.CompleteQuestEvent; import com.gomo.app.common.util.JsonParser; -import com.gomo.app.core.quest.domain.event.CompleteQuestEvent; import com.gomo.app.core.streak.application.port.in.StreakCreator; import com.gomo.app.support.evententry.application.port.IdempotentEventEntryConsumer; import com.gomo.app.support.evententry.domain.model.EventEntry; diff --git a/src/main/java/com/gomo/app/core/streak/application/port/in/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/core/streak/application/port/in/SpringModulithPackageInfo.java new file mode 100644 index 00000000..258e4650 --- /dev/null +++ b/src/main/java/com/gomo/app/core/streak/application/port/in/SpringModulithPackageInfo.java @@ -0,0 +1,9 @@ +package com.gomo.app.core.streak.application.port.in; + +import org.springframework.modulith.NamedInterface; +import org.springframework.modulith.PackageInfo; + +@NamedInterface("in") +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/core/survey/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/core/survey/SpringModulithPackageInfo.java new file mode 100644 index 00000000..3319ef3a --- /dev/null +++ b/src/main/java/com/gomo/app/core/survey/SpringModulithPackageInfo.java @@ -0,0 +1,12 @@ +package com.gomo.app.core.survey; + +import org.springframework.modulith.ApplicationModule; +import org.springframework.modulith.PackageInfo; + +@ApplicationModule( + id = "core-survey", + displayName = "core-survey" +) +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/support/diagnositc/LogSimulator.java b/src/main/java/com/gomo/app/support/diagnostic/LogSimulator.java similarity index 98% rename from src/main/java/com/gomo/app/support/diagnositc/LogSimulator.java rename to src/main/java/com/gomo/app/support/diagnostic/LogSimulator.java index e4cbcfd7..0650cad8 100644 --- a/src/main/java/com/gomo/app/support/diagnositc/LogSimulator.java +++ b/src/main/java/com/gomo/app/support/diagnostic/LogSimulator.java @@ -1,4 +1,4 @@ -package com.gomo.app.support.diagnositc; +package com.gomo.app.support.diagnostic; import org.springframework.context.annotation.Profile; import org.springframework.web.bind.annotation.PostMapping; diff --git a/src/main/java/com/gomo/app/support/diagnostic/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/support/diagnostic/SpringModulithPackageInfo.java new file mode 100644 index 00000000..90a75a24 --- /dev/null +++ b/src/main/java/com/gomo/app/support/diagnostic/SpringModulithPackageInfo.java @@ -0,0 +1,12 @@ +package com.gomo.app.support.diagnostic; + +import org.springframework.modulith.ApplicationModule; +import org.springframework.modulith.PackageInfo; + +@ApplicationModule( + id = "support-diagnostic", + displayName = "support-diagnostic" +) +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/support/evententry/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/support/evententry/SpringModulithPackageInfo.java new file mode 100644 index 00000000..e86d4194 --- /dev/null +++ b/src/main/java/com/gomo/app/support/evententry/SpringModulithPackageInfo.java @@ -0,0 +1,18 @@ +package com.gomo.app.support.evententry; + +import org.springframework.modulith.ApplicationModule; +import org.springframework.modulith.PackageInfo; + +@ApplicationModule( + id = "support-evententry", + displayName = "support-evententry", + allowedDependencies = { + "common-arch", + "common-event", + "common-util", + "support-messagebroker::in" + } +) +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/support/evententry/application/port/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/support/evententry/application/port/SpringModulithPackageInfo.java new file mode 100644 index 00000000..bf913a16 --- /dev/null +++ b/src/main/java/com/gomo/app/support/evententry/application/port/SpringModulithPackageInfo.java @@ -0,0 +1,9 @@ +package com.gomo.app.support.evententry.application.port; + +import org.springframework.modulith.NamedInterface; +import org.springframework.modulith.PackageInfo; + +@NamedInterface("in") +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/support/evententry/domain/model/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/support/evententry/domain/model/SpringModulithPackageInfo.java new file mode 100644 index 00000000..a0a72881 --- /dev/null +++ b/src/main/java/com/gomo/app/support/evententry/domain/model/SpringModulithPackageInfo.java @@ -0,0 +1,9 @@ +package com.gomo.app.support.evententry.domain.model; + +import org.springframework.modulith.NamedInterface; +import org.springframework.modulith.PackageInfo; + +@NamedInterface("model") +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/support/image/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/support/image/SpringModulithPackageInfo.java new file mode 100644 index 00000000..d08f387b --- /dev/null +++ b/src/main/java/com/gomo/app/support/image/SpringModulithPackageInfo.java @@ -0,0 +1,16 @@ +package com.gomo.app.support.image; + +import org.springframework.modulith.ApplicationModule; +import org.springframework.modulith.PackageInfo; + +@ApplicationModule( + id = "support-image", + displayName = "support-image", + allowedDependencies = { + "common-arch", + "common-exception" + } +) +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/support/image/application/port/in/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/support/image/application/port/in/SpringModulithPackageInfo.java new file mode 100644 index 00000000..b5909842 --- /dev/null +++ b/src/main/java/com/gomo/app/support/image/application/port/in/SpringModulithPackageInfo.java @@ -0,0 +1,9 @@ +package com.gomo.app.support.image.application.port.in; + +import org.springframework.modulith.NamedInterface; +import org.springframework.modulith.PackageInfo; + +@NamedInterface("in") +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/support/llm/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/support/llm/SpringModulithPackageInfo.java new file mode 100644 index 00000000..3e477016 --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/SpringModulithPackageInfo.java @@ -0,0 +1,12 @@ +package com.gomo.app.support.llm; + +import org.springframework.modulith.ApplicationModule; +import org.springframework.modulith.PackageInfo; + +@ApplicationModule( + id = "support-llm", + displayName = "support-llm" +) +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/support/llm/application/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/support/llm/application/SpringModulithPackageInfo.java new file mode 100644 index 00000000..435f2af5 --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/application/SpringModulithPackageInfo.java @@ -0,0 +1,9 @@ +package com.gomo.app.support.llm.application; + +import org.springframework.modulith.NamedInterface; +import org.springframework.modulith.PackageInfo; + +@NamedInterface("in") +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/support/logging/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/support/logging/SpringModulithPackageInfo.java new file mode 100644 index 00000000..63b45a4f --- /dev/null +++ b/src/main/java/com/gomo/app/support/logging/SpringModulithPackageInfo.java @@ -0,0 +1,12 @@ +package com.gomo.app.support.logging; + +import org.springframework.modulith.ApplicationModule; +import org.springframework.modulith.PackageInfo; + +@ApplicationModule( + id = "support-logging", + displayName = "support-logging" +) +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/support/messagebroker/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/support/messagebroker/SpringModulithPackageInfo.java new file mode 100644 index 00000000..ec5d326a --- /dev/null +++ b/src/main/java/com/gomo/app/support/messagebroker/SpringModulithPackageInfo.java @@ -0,0 +1,12 @@ +package com.gomo.app.support.messagebroker; + +import org.springframework.modulith.ApplicationModule; +import org.springframework.modulith.PackageInfo; + +@ApplicationModule( + id = "support-messagebroker", + displayName = "support-messagebroker" +) +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/support/messagebroker/application/port/in/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/support/messagebroker/application/port/in/SpringModulithPackageInfo.java new file mode 100644 index 00000000..ac12084d --- /dev/null +++ b/src/main/java/com/gomo/app/support/messagebroker/application/port/in/SpringModulithPackageInfo.java @@ -0,0 +1,9 @@ +package com.gomo.app.support.messagebroker.application.port.in; + +import org.springframework.modulith.NamedInterface; +import org.springframework.modulith.PackageInfo; + +@NamedInterface("in") +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/main/java/com/gomo/app/support/messagebroker/domain/model/SpringModulithPackageInfo.java b/src/main/java/com/gomo/app/support/messagebroker/domain/model/SpringModulithPackageInfo.java new file mode 100644 index 00000000..55dd0a75 --- /dev/null +++ b/src/main/java/com/gomo/app/support/messagebroker/domain/model/SpringModulithPackageInfo.java @@ -0,0 +1,9 @@ +package com.gomo.app.support.messagebroker.domain.model; + +import org.springframework.modulith.NamedInterface; +import org.springframework.modulith.PackageInfo; + +@NamedInterface("model") +@PackageInfo +class SpringModulithPackageInfo { +} diff --git a/src/test/java/com/gomo/app/core/member/adapter/in/api/ResetPasswordDocumentationTest.java b/src/test/java/com/gomo/app/core/auth/adapter/in/api/ResetPasswordDocumentationTest.java similarity index 80% rename from src/test/java/com/gomo/app/core/member/adapter/in/api/ResetPasswordDocumentationTest.java rename to src/test/java/com/gomo/app/core/auth/adapter/in/api/ResetPasswordDocumentationTest.java index 5094d2c7..1f08a24a 100644 --- a/src/test/java/com/gomo/app/core/member/adapter/in/api/ResetPasswordDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/auth/adapter/in/api/ResetPasswordDocumentationTest.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.adapter.in.api; +package com.gomo.app.core.auth.adapter.in.api; import static io.restassured.RestAssured.*; import static org.springframework.http.HttpHeaders.*; @@ -11,15 +11,15 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; -import com.gomo.app.core.member.adapter.in.api.request.ResetPasswordRequest; -import com.gomo.app.core.member.adapter.in.api.snippet.ResetPasswordSnippet; +import com.gomo.app.core.auth.adapter.in.api.request.ResetPasswordRequest; +import com.gomo.app.core.auth.adapter.in.api.snippet.ResetPasswordSnippet; import com.gomo.app.core.member.domain.repository.MemberRepository; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation Documentation]: 비밀번호 초기화 테스트") public class ResetPasswordDocumentationTest extends DocumentationTestBase { - private static final String RESET_PASSWORD_URL = "/members/passwords/reset"; + private static final String URL = "/auth/passwords/reset"; private final RestDocumentationFilter filter = ResetPasswordSnippet.create(); private final RestDocumentationFilter errorFilter = ResetPasswordSnippet.createError(); @@ -34,14 +34,14 @@ void tearDown() { @DisplayName("비밀번호를 초기화 한다.") @Test - void update_password() { + void reset_password() { String email = "testmember@naver.com"; String temporaryToken = jwtCreator.createTemporaryToken(email, 300); given(this.specification).filter(filter) .header(CONTENT_TYPE, APPLICATION_JSON_VALUE) .body(ResetPasswordRequest.of(email, "Test1234!", temporaryToken)) .when() - .put(RESET_PASSWORD_URL) + .put(URL) .then() .statusCode(NO_CONTENT.value()); } diff --git a/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/ResetPasswordSnippet.java b/src/test/java/com/gomo/app/core/auth/adapter/in/api/snippet/ResetPasswordSnippet.java similarity index 93% rename from src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/ResetPasswordSnippet.java rename to src/test/java/com/gomo/app/core/auth/adapter/in/api/snippet/ResetPasswordSnippet.java index 16499bea..34b49331 100644 --- a/src/test/java/com/gomo/app/core/member/adapter/in/api/snippet/ResetPasswordSnippet.java +++ b/src/test/java/com/gomo/app/core/auth/adapter/in/api/snippet/ResetPasswordSnippet.java @@ -1,4 +1,4 @@ -package com.gomo.app.core.member.adapter.in.api.snippet; +package com.gomo.app.core.auth.adapter.in.api.snippet; import static com.gomo.app.test.ErrorResponseFields.*; import static org.springframework.http.HttpHeaders.*; @@ -12,7 +12,7 @@ import org.springframework.restdocs.snippet.Snippet; public class ResetPasswordSnippet { - private static final String IDENTIFIER = "member-password-reset"; + private static final String IDENTIFIER = "auth-password-reset"; private static final Snippet REQUEST_HEADERS = requestHeaders( headerWithName(CONTENT_TYPE).description("Content-Type: `application/json`") diff --git a/src/test/java/com/gomo/app/core/auth/application/service/AuthServiceTest.java b/src/test/java/com/gomo/app/core/auth/application/service/AuthServiceTest.java index e48cf0d0..3963301e 100644 --- a/src/test/java/com/gomo/app/core/auth/application/service/AuthServiceTest.java +++ b/src/test/java/com/gomo/app/core/auth/application/service/AuthServiceTest.java @@ -21,6 +21,7 @@ import com.gomo.app.core.auth.application.port.out.JwtVerifier; import com.gomo.app.core.auth.application.port.out.PrincipalCreator; import com.gomo.app.core.auth.application.port.out.PrincipalLoginProcessor; +import com.gomo.app.core.auth.application.port.out.PrincipalPasswordResetter; import com.gomo.app.core.auth.domain.exception.AuthenticationFailException; import com.gomo.app.core.auth.domain.model.AuthToken; import com.gomo.app.core.member.domain.model.LoginProvider; @@ -44,6 +45,9 @@ public class AuthServiceTest { @Mock private AuthTokenService authTokenService; + @Mock + private PrincipalPasswordResetter principalPasswordResetter; + @DisplayName("이메일로 회원 가입한다.") @Test void email_signup() { @@ -95,4 +99,24 @@ void login() { assertThat(actual).usingRecursiveComparison().isEqualTo(expected); } + + @DisplayName("사용자 비밀번호 초기화 요청을 처리한다.") + @Test + void reset_password() { + doReturn(true).when(jwtVerifier).verify(anyString()); + + sut.reset("email@email.com", "Gomo123@", "token"); + + verify(principalPasswordResetter, times(1)).reset(anyString(), anyString()); + } + + @DisplayName("사용자 비밀번호 초기화 요청을 처리한다.") + @Test + void reset_password_with_invalid_token() { + doReturn(false).when(jwtVerifier).verify(anyString()); + + assertThatThrownBy(() -> sut.reset("email@email.com", "Gomo123@", "token")) + .isInstanceOf(AuthenticationFailException.class) + .hasMessageContaining(INVALID_VERIFIED_EMAIL_TOKEN.getMessage()); + } } diff --git a/src/test/java/com/gomo/app/core/interest/adapter/in/consumer/CompleteQuestEventScoreConsumerTest.java b/src/test/java/com/gomo/app/core/interest/adapter/in/consumer/CompleteQuestEventScoreConsumerTest.java index f651a000..bc662c25 100644 --- a/src/test/java/com/gomo/app/core/interest/adapter/in/consumer/CompleteQuestEventScoreConsumerTest.java +++ b/src/test/java/com/gomo/app/core/interest/adapter/in/consumer/CompleteQuestEventScoreConsumerTest.java @@ -15,9 +15,9 @@ import org.mockito.MockedStatic; import org.mockito.junit.jupiter.MockitoExtension; +import com.gomo.app.common.event.CompleteQuestEvent; import com.gomo.app.common.util.JsonParser; import com.gomo.app.core.interest.application.port.in.ProficiencyPropagator; -import com.gomo.app.core.quest.domain.event.CompleteQuestEvent; import com.gomo.app.support.evententry.domain.model.EventEntry; @DisplayName("[Consumer unit]: 퀘스트 완료(점수) 이벤트 처리 테스트") diff --git a/src/test/java/com/gomo/app/core/member/adapter/in/api/DeleteMemberDocumentationTest.java b/src/test/java/com/gomo/app/core/member/adapter/in/api/DeleteMemberDocumentationTest.java index 31b1c31d..cff1168c 100644 --- a/src/test/java/com/gomo/app/core/member/adapter/in/api/DeleteMemberDocumentationTest.java +++ b/src/test/java/com/gomo/app/core/member/adapter/in/api/DeleteMemberDocumentationTest.java @@ -9,9 +9,11 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.restdocs.restassured.RestDocumentationFilter; import com.gomo.app.core.member.adapter.in.api.snippet.DeleteMemberSnippet; +import com.gomo.app.core.member.domain.repository.MemberRepository; import com.gomo.app.test.DocumentationTestBase; @DisplayName("[Presentation documentation]: 회원 탈퇴 테스트") @@ -22,6 +24,9 @@ public class DeleteMemberDocumentationTest extends DocumentationTestBase { private final RestDocumentationFilter filter = DeleteMemberSnippet.create(); private final RestDocumentationFilter errorFilter = DeleteMemberSnippet.createError(); + @Autowired + private MemberRepository memberRepository; + @BeforeEach void setSessionToTestPrincipal() { String email = "test@naver.com"; @@ -33,6 +38,7 @@ void setSessionToTestPrincipal() { @AfterEach void setSessionToOriginalPrincipal() { sessionInit(login(sessionEmail, sessionPassword)); + memberRepository.deleteAllInBatch(); } @DisplayName("사용자가 회원 탈퇴를 요청한다.") diff --git a/src/test/java/com/gomo/app/core/member/adapter/out/client/TemporaryTokenClientTest.java b/src/test/java/com/gomo/app/core/member/adapter/out/client/TemporaryTokenClientTest.java deleted file mode 100644 index 1922ee2b..00000000 --- a/src/test/java/com/gomo/app/core/member/adapter/out/client/TemporaryTokenClientTest.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.gomo.app.core.member.adapter.out.client; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.gomo.app.core.auth.application.port.out.JwtVerifier; - -@DisplayName("[Adapter Unit]: 임시토큰 요청 테스트") -@ExtendWith(MockitoExtension.class) -class TemporaryTokenClientTest { - - @InjectMocks - private EmailTokenClient sut; - - @Mock - private JwtVerifier jwtVerifier; - - @DisplayName("임시토큰을 검증한다.") - @Test - void verify_temporary_token() { - doReturn(true).when(jwtVerifier).verify(any()); - - assertThatCode(() -> sut.verify("temporaryToken")).doesNotThrowAnyException(); - verify(jwtVerifier, times(1)).verify(any()); - } - - @DisplayName("유효하지 않은 임시토큰으로 검증한다.") - @Test - void verify_invalid_temporary_token() { - doReturn(false).when(jwtVerifier).verify(any()); - - assertThatThrownBy(() -> sut.verify("temporaryToken")).isExactlyInstanceOf(IllegalArgumentException.class); - verify(jwtVerifier, times(1)).verify(any()); - } -} diff --git a/src/test/java/com/gomo/app/core/member/application/service/PasswordServiceTest.java b/src/test/java/com/gomo/app/core/member/application/service/PasswordServiceTest.java index f837822b..35ae2c7b 100644 --- a/src/test/java/com/gomo/app/core/member/application/service/PasswordServiceTest.java +++ b/src/test/java/com/gomo/app/core/member/application/service/PasswordServiceTest.java @@ -14,7 +14,6 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import com.gomo.app.core.member.application.port.out.EmailTokenVerifier; import com.gomo.app.core.member.application.port.out.PasswordEncodeManager; import com.gomo.app.core.member.domain.exception.MemberAuthenticationFailedException; import com.gomo.app.core.member.domain.model.LoginProvider; @@ -29,9 +28,6 @@ class PasswordServiceTest { @InjectMocks private PasswordService sut; - @Mock - private EmailTokenVerifier emailTokenVerifier; - @Mock private PasswordEncodeManager passwordEncodeManager; @@ -46,10 +42,9 @@ void reset_password() { doReturn(member).when(memberService).findByEmail(any()); doReturn(encoded).when(passwordEncodeManager).encode(any()); - sut.reset(member.email(), "New1234@", "temporaryToken"); + sut.reset(member.email(), "New1234@"); assertThat(member.password()).isEqualTo(encoded); - verify(emailTokenVerifier, times(1)).verify(any()); } @DisplayName("비밀번호를 변경한다.") diff --git a/src/test/java/com/gomo/app/core/point/adapter/in/consumer/CompleteQuestEventPointConsumerTest.java b/src/test/java/com/gomo/app/core/point/adapter/in/consumer/CompleteQuestEventPointConsumerTest.java index 7ba92467..c58a02ff 100644 --- a/src/test/java/com/gomo/app/core/point/adapter/in/consumer/CompleteQuestEventPointConsumerTest.java +++ b/src/test/java/com/gomo/app/core/point/adapter/in/consumer/CompleteQuestEventPointConsumerTest.java @@ -15,9 +15,9 @@ import org.mockito.MockedStatic; import org.mockito.junit.jupiter.MockitoExtension; +import com.gomo.app.common.event.CompleteQuestEvent; import com.gomo.app.common.util.JsonParser; import com.gomo.app.core.point.application.port.in.PointCreator; -import com.gomo.app.core.quest.domain.event.CompleteQuestEvent; import com.gomo.app.support.evententry.domain.model.EventEntry; @DisplayName("[Consumer unit]: 퀘스트 완료(포인트) 이벤트 처리 테스트") diff --git a/src/test/java/com/gomo/app/core/streak/adapter/in/consumer/CompleteQuestEventStreakConsumerTest.java b/src/test/java/com/gomo/app/core/streak/adapter/in/consumer/CompleteQuestEventStreakConsumerTest.java index 6d90fc29..fb729755 100644 --- a/src/test/java/com/gomo/app/core/streak/adapter/in/consumer/CompleteQuestEventStreakConsumerTest.java +++ b/src/test/java/com/gomo/app/core/streak/adapter/in/consumer/CompleteQuestEventStreakConsumerTest.java @@ -15,8 +15,8 @@ import org.mockito.MockedStatic; import org.mockito.junit.jupiter.MockitoExtension; +import com.gomo.app.common.event.CompleteQuestEvent; import com.gomo.app.common.util.JsonParser; -import com.gomo.app.core.quest.domain.event.CompleteQuestEvent; import com.gomo.app.core.streak.application.port.in.StreakCreator; import com.gomo.app.support.evententry.domain.model.EventEntry; diff --git a/src/test/java/com/gomo/app/modulith/AnnotationBasedModuleDetectionStrategy.java b/src/test/java/com/gomo/app/modulith/AnnotationBasedModuleDetectionStrategy.java new file mode 100644 index 00000000..2326fecb --- /dev/null +++ b/src/test/java/com/gomo/app/modulith/AnnotationBasedModuleDetectionStrategy.java @@ -0,0 +1,15 @@ +package com.gomo.app.modulith; + +import java.util.stream.Stream; + +import org.springframework.modulith.ApplicationModule; +import org.springframework.modulith.core.ApplicationModuleDetectionStrategy; +import org.springframework.modulith.core.JavaPackage; + +public class AnnotationBasedModuleDetectionStrategy implements ApplicationModuleDetectionStrategy { + + @Override + public Stream getModuleBasePackages(JavaPackage basePackage) { + return basePackage.getSubPackagesAnnotatedWith(ApplicationModule.class); + } +} diff --git a/src/test/java/com/gomo/app/modulith/ModularityTests.java b/src/test/java/com/gomo/app/modulith/ModularityTests.java new file mode 100644 index 00000000..45ea7948 --- /dev/null +++ b/src/test/java/com/gomo/app/modulith/ModularityTests.java @@ -0,0 +1,31 @@ +package com.gomo.app.modulith; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.modulith.core.ApplicationModules; +import org.springframework.modulith.docs.Documenter; + +import com.gomo.app.GomoApplication; + +/** + * Tests to verify the modular structure and generate documentation for the modules. + */ +public class ModularityTests { + + ApplicationModules modules = ApplicationModules.of(GomoApplication.class); + + @DisplayName("모듈간 순환 의존성은 존재하지 않는다.") + @Test + void verifies_modular_structure() { + modules.verify(); + } + + @DisplayName("모듈 문서를 생성한다.") + @Test + void create_module_documentation() { + new Documenter(modules) + .writeModulesAsPlantUml() + .writeIndividualModulesAsPlantUml() + .writeModuleCanvases(); + } +} diff --git a/src/test/resources/META-INF/spring.factories b/src/test/resources/META-INF/spring.factories new file mode 100644 index 00000000..7f20010c --- /dev/null +++ b/src/test/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.modulith.core.ApplicationModuleDetectionStrategy=\ + com.gomo.app.modulith.AnnotationBasedModuleDetectionStrategy From b4f3ee8a6dd315b66243de7800c521700c66c579 Mon Sep 17 00:00:00 2001 From: nurdy-kim Date: Mon, 13 Oct 2025 14:59:06 +0900 Subject: [PATCH 14/16] =?UTF-8?q?feat:=20=ED=80=98=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20LLM=20=EB=A7=88=EC=9D=B4=EA=B7=B8=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../llm/application/GenerateTextDto.java | 7 +-- .../llm/exception/GenerateQuestErrorCode.java | 21 +++++++ .../llm/infrastructure/GeminiApiAdapter.java | 59 ++++--------------- .../llm/infrastructure/GeminiRequest.java | 39 +++++++++--- 4 files changed, 67 insertions(+), 59 deletions(-) create mode 100644 src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java diff --git a/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java b/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java index ee99b748..21098463 100644 --- a/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java +++ b/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java @@ -1,7 +1,4 @@ package com.gomo.app.support.llm.application; -import java.util.List; -import java.util.Map; - -public record GenerateTextDto(Map> generatedText) {} - +public record GenerateTextDto(String generatedText) { +} diff --git a/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java new file mode 100644 index 00000000..9cdf3167 --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java @@ -0,0 +1,21 @@ +package com.gomo.app.support.llm.exception; + +import lombok.Getter; + +@Getter +public enum GenerateQuestErrorCode { + GEMINI_API_ERROR(500, "QUE-GEN-001", "An error occurred while call GeminiAPI"), + EMPTY_RESPONSE(500, "QUE-GEN-002", "Gemini API response blank"), + INVALID_RESPONSE_FORMAT(500, "QUE-GEN-003", "Gemini Response format is invalid") + ; + + private final int httpStatus; + private final String errorCode; + private final String message; + + GenerateQuestErrorCode(int httpStatus, String errorCode, String message) { + this.httpStatus = httpStatus; + this.errorCode = errorCode; + this.message = message; + } +} diff --git a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java index 86440dca..f325f9d4 100644 --- a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java +++ b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java @@ -1,30 +1,22 @@ package com.gomo.app.support.llm.infrastructure; -import java.util.List; -import java.util.Map; - import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.web.client.RestClient; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import com.gomo.app.common.arch.Adapter; import com.gomo.app.support.llm.application.GenerateTextCommand; import com.gomo.app.support.llm.application.GenerateTextDto; -import com.gomo.app.support.llm.application.LlmClientPortOut; -import com.gomo.app.support.llm.exception.LlmErrorCode; -import com.gomo.app.support.llm.exception.LlmException; -import com.gomo.app.support.llm.util.PromptLoader; +import com.gomo.app.support.llm.exception.GenerateQuestException; +import com.gomo.app.support.llm.exception.GenerateQuestErrorCode; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @RequiredArgsConstructor -@Slf4j @Adapter -class GeminiApiAdapter implements LlmClientPortOut { +@Slf4j +public class GeminiApiAdapter { private final RestClient restClient; @Value("${spring.ai.openai.api-key}") @@ -33,12 +25,10 @@ class GeminiApiAdapter implements LlmClientPortOut { @Value("${spring.ai.openai.chat.options.model}") private String model; - private PromptLoader promptLoader; - private static final String GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions"; - public GenerateTextDto generate(GenerateTextCommand command) { - try { + public GenerateTextDto generate(GenerateTextCommand command){ + try{ String apiKey = "Bearer " + this.apiKey; GeminiRequest request = createGeminiRequest(command); @@ -57,41 +47,16 @@ public GenerateTextDto generate(GenerateTextCommand command) { } } - private GeminiRequest createGeminiRequest(GenerateTextCommand command) { - return GeminiRequest.createPrompt(command.interests(), command.questType(), command.amount(), promptLoader); + private GeminiRequest createGeminiRequest(GenerateTextCommand command){ + return GeminiRequest.createPrompt(command.interests(), command.questType(), command.amount()); } - private GenerateTextDto convertToGenerateTextDto(GeminiResponse response) { - if (response.choices() == null || response.choices().isEmpty()) { - throw new LlmException(LlmErrorCode.EMPTY_RESPONSE); + private GenerateTextDto convertToGenerateTextDto(GeminiResponse response){ + if (response.choices() == null || response.choices().isEmpty()){ + throw new GenerateQuestException(GenerateQuestErrorCode.EMPTY_RESPONSE); } String generatedText = response.choices().get(0).message().content(); - return new GenerateTextDto(parseDtofromText(generatedText)); - } - - private Map> parseDtofromText(String text) { - try { - String cleanText = text.trim(); - - if (cleanText.startsWith("```json")) { - cleanText = cleanText.substring(7); - } - - if (cleanText.endsWith("```")) { - cleanText = cleanText.substring(0, cleanText.length() - 3); - } - - cleanText = cleanText.trim(); - ObjectMapper objectMapper = new ObjectMapper(); - TypeReference>> typeRef = new TypeReference>>() { - }; - - return objectMapper.readValue(cleanText, typeRef); - } catch (JsonProcessingException e) { - throw new LlmException(LlmErrorCode.INVALID_JSON_FORMAT); - } catch (Exception e) { - throw new LlmException(LlmErrorCode.PARSING_ERROR); - } + return new GenerateTextDto(generatedText); } } diff --git a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java index 30a17b24..86938e19 100644 --- a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java +++ b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java @@ -4,7 +4,6 @@ import java.util.Map; import java.util.stream.Collectors; -import com.gomo.app.support.llm.util.PromptLoader; import com.gomo.app.core.quest.domain.model.quest.QuestType; public record GeminiRequest( @@ -12,9 +11,30 @@ public record GeminiRequest( String reasoning_effort, List messages ) { - private static Prompt createSystemPrompt(PromptLoader promptLoader){ - String content = promptLoader.loadPrompt("quest/system-prompt.txt"); - return new Prompt("system", content); + private static Prompt createSystemPrompt(){ + return new Prompt("system", """ + 당신은 개인 맞춤형 도전 과제를 생성하는 전문가 입니다. 아래 가이드라인을 준수하여 도전 과제를 생성하세요. + + **도전 과제 생성 가이드라인** + #1. 아래 주어지는 ‘개인 정보’를 바탕으로 ‘도전 과제’를 생성합니다. + #1-1. ‘개인 정보’의 숙련도와 퀘스트 타입으로 ‘도전 과제’의 ‘소요 시간(분)’을 결정합니다. + #1-1-1. 숙련도는 0 - 100 사이의 정수입니다. + #1-1-2. 퀘스트 타입은 각각 Daily(30 - 90), Weekly(300 - 900), Monthly(1000 - 1500) 사이의 무작위 정수입니다. + #1-1-3. ‘도전 과제’의 ‘소요 시간(분)’은 연산식(숙련도 * 0.1 + 퀘스트 타입) 결과로 0 - 1510 사이의 정수입니다. + #1-2. ‘도전 과제’의 content는 ‘개인 정보’의 관심사와 연관된 목표입니다. + #1-2-1. content는 명확하고 구조적인 행동을 제시합니다. + #1-2-1-1. 문장 형식은 “진행합니다.” 가 아닌 “진행”과 같이 짧게 끝맺음한다. + #1-2-2. content는 실질적으로 ‘소요 시간(분)’ 이내에 달성 가능해야 합니다. + #1-2-2-1. 30 - 100 ex) “알고리즘 1문제 풀이”, “TIL 작성”, “기술 블로그 하나 정독” + #1-2-2-2. 300 - 910 ex) “기술 블로그 하나 작성”, “개인 프로젝트 pr 하나 작업”, “개인 프로젝트 로깅 시스템 점검” + #1-2-2-3. 1000 - 1510 ex) “서킷 브레이커 학습 후, 개인 프로젝트에 적용하기”, “오픈 소스 1회 기여하기”, “멀티 모듈 학습하고 토이 프로젝트 진행하기” + #2. ‘도전 과제’의 응답 형식은 반드시 JSON으로 작성해주세요. + #2-1. 생성된 도전과제는 30자 이내의 동사형으로 제시해주세요. + #2-2. 응답 형식 예시: { + ["관심사명" : [{ “content” : “[생성된 도전 과제]” }, ...],]} + #2-3. 이전 수행 퀘스트를 참고하여, 중복이 발생하지 않도록 제시해주세요. + #2-4. 각 관심사 별 퀘스트 수를 동일한 비율로 생성해 주세요. + """); } private static Prompt createUserPrompt(Map interests, QuestType questType, int amount){ @@ -23,14 +43,19 @@ private static Prompt createUserPrompt(Map interests, QuestType qu .collect(Collectors.joining(", ")); String promptText = String.format( - "**개인 정보**\n- 관심사: %s \n- 퀘스트 타입: %s \n- 퀘스트 수: %s", interestsText, questType.name(), amount + """ + **개인 정보** + - 관심사: %s + - 퀘스트 타입: %s + - 퀘스트 수: %s + """, interestsText, questType.name(), amount ); return new Prompt("user", promptText); } - public static GeminiRequest createPrompt(Map interests, QuestType questType, int amount, PromptLoader promptLoader){ - Prompt system = createSystemPrompt(promptLoader); + public static GeminiRequest createPrompt(Map interests, QuestType questType, int amount){ + Prompt system = createSystemPrompt(); Prompt user = createUserPrompt(interests, questType, amount); return new GeminiRequest("gemini-2.5-flash", "none", List.of(system, user)); } From 18c0ca4e2f284daf2ff9156c345dfedc636e2009 Mon Sep 17 00:00:00 2001 From: nurdy-kim Date: Mon, 20 Oct 2025 13:12:20 +0900 Subject: [PATCH 15/16] =?UTF-8?q?feat:=20=EB=A6=AC=EB=B7=B0=20=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EB=B0=98=EC=98=81(prompt=20=EB=B3=84=EB=8F=84=20te?= =?UTF-8?q?xt=20=ED=8C=8C=EC=9D=BC,=20LlmClientPortOut=20interface=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1,=20Style=20=EC=98=A4=EB=A5=98=20=EB=93=B1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../llm/application/GenerateTextDto.java | 7 ++- .../llm/exception/GenerateQuestErrorCode.java | 5 ++- .../llm/infrastructure/GeminiApiAdapter.java | 43 +++++++++++++++++-- .../llm/infrastructure/GeminiRequest.java | 39 +++-------------- 4 files changed, 55 insertions(+), 39 deletions(-) diff --git a/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java b/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java index 21098463..ee99b748 100644 --- a/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java +++ b/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java @@ -1,4 +1,7 @@ package com.gomo.app.support.llm.application; -public record GenerateTextDto(String generatedText) { -} +import java.util.List; +import java.util.Map; + +public record GenerateTextDto(Map> generatedText) {} + diff --git a/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java index 9cdf3167..9bcc020d 100644 --- a/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java +++ b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java @@ -6,8 +6,9 @@ public enum GenerateQuestErrorCode { GEMINI_API_ERROR(500, "QUE-GEN-001", "An error occurred while call GeminiAPI"), EMPTY_RESPONSE(500, "QUE-GEN-002", "Gemini API response blank"), - INVALID_RESPONSE_FORMAT(500, "QUE-GEN-003", "Gemini Response format is invalid") - ; + INVALID_RESPONSE_FORMAT(500, "QUE-GEN-003", "Gemini Response format is invalid"), + INVALID_JSON_FORMAT(500, "QUE-GEN-004", "Gemini Response JSON format is invalid"), + PARSING_ERROR(500, "QUE-GEN-005", "An error occurred while parse data String to Map"); private final int httpStatus; private final String errorCode; diff --git a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java index f325f9d4..0dc93c20 100644 --- a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java +++ b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java @@ -1,12 +1,23 @@ package com.gomo.app.support.llm.infrastructure; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.web.client.RestClient; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import com.gomo.app.common.arch.Adapter; +import com.gomo.app.common.util.PromptLoader; import com.gomo.app.support.llm.application.GenerateTextCommand; import com.gomo.app.support.llm.application.GenerateTextDto; +import com.gomo.app.support.llm.application.LlmClientPortOut; import com.gomo.app.support.llm.exception.GenerateQuestException; import com.gomo.app.support.llm.exception.GenerateQuestErrorCode; @@ -16,7 +27,7 @@ @RequiredArgsConstructor @Adapter @Slf4j -public class GeminiApiAdapter { +public class GeminiApiAdapter implements LlmClientPortOut { private final RestClient restClient; @Value("${spring.ai.openai.api-key}") @@ -25,6 +36,8 @@ public class GeminiApiAdapter { @Value("${spring.ai.openai.chat.options.model}") private String model; + private PromptLoader promptLoader; + private static final String GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions"; public GenerateTextDto generate(GenerateTextCommand command){ @@ -48,7 +61,7 @@ public GenerateTextDto generate(GenerateTextCommand command){ } private GeminiRequest createGeminiRequest(GenerateTextCommand command){ - return GeminiRequest.createPrompt(command.interests(), command.questType(), command.amount()); + return GeminiRequest.createPrompt(command.interests(), command.questType(), command.amount(), promptLoader); } private GenerateTextDto convertToGenerateTextDto(GeminiResponse response){ @@ -57,6 +70,30 @@ private GenerateTextDto convertToGenerateTextDto(GeminiResponse response){ } String generatedText = response.choices().get(0).message().content(); - return new GenerateTextDto(generatedText); + return new GenerateTextDto(parseDtofromText(generatedText)); + } + + private Map> parseDtofromText(String text){ + try{ + String cleanText = text.trim(); + + if (cleanText.startsWith("```json")) { + cleanText = cleanText.substring(7); + } + + if (cleanText.endsWith("```")){ + cleanText = cleanText.substring(0, cleanText.length()-3); + } + + cleanText = cleanText.trim(); + ObjectMapper objectMapper = new ObjectMapper(); + TypeReference>> typeRef = new TypeReference>>() {}; + + return objectMapper.readValue(cleanText, typeRef); + } catch (JsonProcessingException e){ + throw new GenerateQuestException(GenerateQuestErrorCode.INVALID_JSON_FORMAT); + } catch (Exception e){ + throw new GenerateQuestException(GenerateQuestErrorCode.PARSING_ERROR); + } } } diff --git a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java index 86938e19..68cfcae5 100644 --- a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java +++ b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java @@ -4,6 +4,7 @@ import java.util.Map; import java.util.stream.Collectors; +import com.gomo.app.common.util.PromptLoader; import com.gomo.app.core.quest.domain.model.quest.QuestType; public record GeminiRequest( @@ -11,30 +12,9 @@ public record GeminiRequest( String reasoning_effort, List messages ) { - private static Prompt createSystemPrompt(){ - return new Prompt("system", """ - 당신은 개인 맞춤형 도전 과제를 생성하는 전문가 입니다. 아래 가이드라인을 준수하여 도전 과제를 생성하세요. - - **도전 과제 생성 가이드라인** - #1. 아래 주어지는 ‘개인 정보’를 바탕으로 ‘도전 과제’를 생성합니다. - #1-1. ‘개인 정보’의 숙련도와 퀘스트 타입으로 ‘도전 과제’의 ‘소요 시간(분)’을 결정합니다. - #1-1-1. 숙련도는 0 - 100 사이의 정수입니다. - #1-1-2. 퀘스트 타입은 각각 Daily(30 - 90), Weekly(300 - 900), Monthly(1000 - 1500) 사이의 무작위 정수입니다. - #1-1-3. ‘도전 과제’의 ‘소요 시간(분)’은 연산식(숙련도 * 0.1 + 퀘스트 타입) 결과로 0 - 1510 사이의 정수입니다. - #1-2. ‘도전 과제’의 content는 ‘개인 정보’의 관심사와 연관된 목표입니다. - #1-2-1. content는 명확하고 구조적인 행동을 제시합니다. - #1-2-1-1. 문장 형식은 “진행합니다.” 가 아닌 “진행”과 같이 짧게 끝맺음한다. - #1-2-2. content는 실질적으로 ‘소요 시간(분)’ 이내에 달성 가능해야 합니다. - #1-2-2-1. 30 - 100 ex) “알고리즘 1문제 풀이”, “TIL 작성”, “기술 블로그 하나 정독” - #1-2-2-2. 300 - 910 ex) “기술 블로그 하나 작성”, “개인 프로젝트 pr 하나 작업”, “개인 프로젝트 로깅 시스템 점검” - #1-2-2-3. 1000 - 1510 ex) “서킷 브레이커 학습 후, 개인 프로젝트에 적용하기”, “오픈 소스 1회 기여하기”, “멀티 모듈 학습하고 토이 프로젝트 진행하기” - #2. ‘도전 과제’의 응답 형식은 반드시 JSON으로 작성해주세요. - #2-1. 생성된 도전과제는 30자 이내의 동사형으로 제시해주세요. - #2-2. 응답 형식 예시: { - ["관심사명" : [{ “content” : “[생성된 도전 과제]” }, ...],]} - #2-3. 이전 수행 퀘스트를 참고하여, 중복이 발생하지 않도록 제시해주세요. - #2-4. 각 관심사 별 퀘스트 수를 동일한 비율로 생성해 주세요. - """); + private static Prompt createSystemPrompt(PromptLoader promptLoader){ + String content = promptLoader.loadPrompt("quest/system-prompt.txt"); + return new Prompt("system", content); } private static Prompt createUserPrompt(Map interests, QuestType questType, int amount){ @@ -43,19 +23,14 @@ private static Prompt createUserPrompt(Map interests, QuestType qu .collect(Collectors.joining(", ")); String promptText = String.format( - """ - **개인 정보** - - 관심사: %s - - 퀘스트 타입: %s - - 퀘스트 수: %s - """, interestsText, questType.name(), amount + "**개인 정보**\n- 관심사: %s \n- 퀘스트 타입: %s \n- 퀘스트 수: %s", interestsText, questType.name(), amount ); return new Prompt("user", promptText); } - public static GeminiRequest createPrompt(Map interests, QuestType questType, int amount){ - Prompt system = createSystemPrompt(); + public static GeminiRequest createPrompt(Map interests, QuestType questType, int amount, PromptLoader promptLoader){ + Prompt system = createSystemPrompt(promptLoader); Prompt user = createUserPrompt(interests, questType, amount); return new GeminiRequest("gemini-2.5-flash", "none", List.of(system, user)); } From bd36080c93a9fa0e0990ce07eef8a05f2b156daf Mon Sep 17 00:00:00 2001 From: nurdykim Date: Sun, 14 Dec 2025 23:45:40 +0900 Subject: [PATCH 16/16] =?UTF-8?q?feat:=20LLM=20Refactoring=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20review=20=EC=82=AC=ED=95=AD=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../out/client/LlmQuestContentClient.java | 1 - .../GeminiGenerateTextUseCase.java | 17 --- .../llm/application/GenerateTextCommand.java | 11 -- .../llm/application/GenerateTextDto.java | 7 -- .../llm/application/GenerateTextPortIn.java | 6 - .../llm/application/LlmClientPortOut.java | 14 --- .../application/port/dto/GenerateTextDto.java | 11 ++ .../llm/application/port/dto/LlmRequest.java | 7 ++ .../llm/application/port/dto/LlmResponse.java | 7 ++ .../port/in/GenerateQuestTextCommand.java | 19 ++++ .../port/in/GenerateQuestTextPortIn.java | 11 ++ .../port/out/LlmClientPortOut.java | 19 ++++ .../usecase/GeminiGenerateTextUseCase.java | 87 +++++++++++++++ .../llm/exception/GenerateQuestErrorCode.java | 22 ---- .../llm/infrastructure/GeminiApiAdapter.java | 105 +++++++++--------- .../llm/infrastructure/GeminiRequest.java | 39 ------- .../llm/infrastructure/GeminiResponse.java | 49 -------- .../app/support/llm/util/PromptLoader.java | 9 ++ 18 files changed, 221 insertions(+), 220 deletions(-) delete mode 100644 src/main/java/com/gomo/app/support/llm/application/GeminiGenerateTextUseCase.java delete mode 100644 src/main/java/com/gomo/app/support/llm/application/GenerateTextCommand.java delete mode 100644 src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java delete mode 100644 src/main/java/com/gomo/app/support/llm/application/GenerateTextPortIn.java delete mode 100644 src/main/java/com/gomo/app/support/llm/application/LlmClientPortOut.java create mode 100644 src/main/java/com/gomo/app/support/llm/application/port/dto/GenerateTextDto.java create mode 100644 src/main/java/com/gomo/app/support/llm/application/port/dto/LlmRequest.java create mode 100644 src/main/java/com/gomo/app/support/llm/application/port/dto/LlmResponse.java create mode 100644 src/main/java/com/gomo/app/support/llm/application/port/in/GenerateQuestTextCommand.java create mode 100644 src/main/java/com/gomo/app/support/llm/application/port/in/GenerateQuestTextPortIn.java create mode 100644 src/main/java/com/gomo/app/support/llm/application/port/out/LlmClientPortOut.java create mode 100644 src/main/java/com/gomo/app/support/llm/application/usecase/GeminiGenerateTextUseCase.java delete mode 100644 src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java delete mode 100644 src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java delete mode 100644 src/main/java/com/gomo/app/support/llm/infrastructure/GeminiResponse.java diff --git a/src/main/java/com/gomo/app/core/quest/adapter/out/client/LlmQuestContentClient.java b/src/main/java/com/gomo/app/core/quest/adapter/out/client/LlmQuestContentClient.java index e3777377..17847cec 100644 --- a/src/main/java/com/gomo/app/core/quest/adapter/out/client/LlmQuestContentClient.java +++ b/src/main/java/com/gomo/app/core/quest/adapter/out/client/LlmQuestContentClient.java @@ -7,7 +7,6 @@ import com.gomo.app.core.quest.application.port.command.CreateQuestContentCommand; import com.gomo.app.core.quest.application.port.dto.QuestContentDto; import com.gomo.app.core.quest.application.port.out.QuestContentCreator; -import com.gomo.app.support.llm.application.GenerateTextPortIn; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/src/main/java/com/gomo/app/support/llm/application/GeminiGenerateTextUseCase.java b/src/main/java/com/gomo/app/support/llm/application/GeminiGenerateTextUseCase.java deleted file mode 100644 index 9f711d31..00000000 --- a/src/main/java/com/gomo/app/support/llm/application/GeminiGenerateTextUseCase.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.gomo.app.support.llm.application; - -import com.gomo.app.common.arch.ApplicationService; - -import lombok.RequiredArgsConstructor; - -@ApplicationService -@RequiredArgsConstructor -class GeminiGenerateTextUseCase implements GenerateTextPortIn { - - private final LlmClientPortOut llmClientPortOut; - - @Override - public GenerateTextDto generate(GenerateTextCommand command) { - return llmClientPortOut.generate(command); - } -} diff --git a/src/main/java/com/gomo/app/support/llm/application/GenerateTextCommand.java b/src/main/java/com/gomo/app/support/llm/application/GenerateTextCommand.java deleted file mode 100644 index baff3404..00000000 --- a/src/main/java/com/gomo/app/support/llm/application/GenerateTextCommand.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.gomo.app.support.llm.application; - -import java.util.Map; - -import com.gomo.app.core.quest.domain.model.quest.QuestType; - -public record GenerateTextCommand(Map interests, QuestType questType, int amount) { - public static GenerateTextCommand of(Map interests, QuestType questType, int amount) { - return new GenerateTextCommand(interests, questType, amount); - } -} diff --git a/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java b/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java deleted file mode 100644 index ee99b748..00000000 --- a/src/main/java/com/gomo/app/support/llm/application/GenerateTextDto.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.gomo.app.support.llm.application; - -import java.util.List; -import java.util.Map; - -public record GenerateTextDto(Map> generatedText) {} - diff --git a/src/main/java/com/gomo/app/support/llm/application/GenerateTextPortIn.java b/src/main/java/com/gomo/app/support/llm/application/GenerateTextPortIn.java deleted file mode 100644 index d55084e9..00000000 --- a/src/main/java/com/gomo/app/support/llm/application/GenerateTextPortIn.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.gomo.app.support.llm.application; - -public interface GenerateTextPortIn { - - GenerateTextDto generate(GenerateTextCommand command); -} diff --git a/src/main/java/com/gomo/app/support/llm/application/LlmClientPortOut.java b/src/main/java/com/gomo/app/support/llm/application/LlmClientPortOut.java deleted file mode 100644 index c72d513d..00000000 --- a/src/main/java/com/gomo/app/support/llm/application/LlmClientPortOut.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.gomo.app.support.llm.application; - -import com.gomo.app.core.interest.application.port.dto.RegistrantDto; - -public interface LlmClientPortOut { - - /** - * Retrieves the essential details of a single registrant by id. - * - * @param {@link GenerateTextCommand} The information to generate Quests with LLM. - * @return A {@link GenerateTextDto} containing the GeneratedText data. - */ - GenerateTextDto generate(GenerateTextCommand command); -} diff --git a/src/main/java/com/gomo/app/support/llm/application/port/dto/GenerateTextDto.java b/src/main/java/com/gomo/app/support/llm/application/port/dto/GenerateTextDto.java new file mode 100644 index 00000000..faae81c4 --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/application/port/dto/GenerateTextDto.java @@ -0,0 +1,11 @@ +package com.gomo.app.support.llm.application.port.dto; + +import java.util.List; +import java.util.Map; + +public record GenerateTextDto(Map> questsByType) { + public static GenerateTextDto of(Map> questsByType) { + return new GenerateTextDto(questsByType); + } +} + diff --git a/src/main/java/com/gomo/app/support/llm/application/port/dto/LlmRequest.java b/src/main/java/com/gomo/app/support/llm/application/port/dto/LlmRequest.java new file mode 100644 index 00000000..715cb906 --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/application/port/dto/LlmRequest.java @@ -0,0 +1,7 @@ +package com.gomo.app.support.llm.application.port.dto; + +public record LlmRequest(String prompt) { + public static LlmRequest of(String prompt) { + return new LlmRequest(prompt); + } +} diff --git a/src/main/java/com/gomo/app/support/llm/application/port/dto/LlmResponse.java b/src/main/java/com/gomo/app/support/llm/application/port/dto/LlmResponse.java new file mode 100644 index 00000000..911bc28d --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/application/port/dto/LlmResponse.java @@ -0,0 +1,7 @@ +package com.gomo.app.support.llm.application.port.dto; + +public record LlmResponse(String generatedText) { + public static LlmResponse of(String generatedText) { + return new LlmResponse(generatedText); + } +} diff --git a/src/main/java/com/gomo/app/support/llm/application/port/in/GenerateQuestTextCommand.java b/src/main/java/com/gomo/app/support/llm/application/port/in/GenerateQuestTextCommand.java new file mode 100644 index 00000000..9b2af8c3 --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/application/port/in/GenerateQuestTextCommand.java @@ -0,0 +1,19 @@ +package com.gomo.app.support.llm.application.port.in; + +import java.util.Map; + +import com.gomo.app.core.quest.domain.model.quest.QuestType; + +public record GenerateQuestTextCommand( + Map interests, + QuestType questType, + int amount +) { + public static GenerateQuestTextCommand of( + Map interests, + QuestType questType, + int amount + ) { + return new GenerateQuestTextCommand(interests, questType, amount); + } +} diff --git a/src/main/java/com/gomo/app/support/llm/application/port/in/GenerateQuestTextPortIn.java b/src/main/java/com/gomo/app/support/llm/application/port/in/GenerateQuestTextPortIn.java new file mode 100644 index 00000000..39669d0d --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/application/port/in/GenerateQuestTextPortIn.java @@ -0,0 +1,11 @@ +package com.gomo.app.support.llm.application.port.in; + +import com.gomo.app.support.llm.application.port.dto.GenerateTextDto; + +/** + * Quest generate Port (Driving port) + * For generate LLM Quest text for Quest Domain + */ +public interface GenerateQuestTextPortIn { + GenerateTextDto generate(GenerateQuestTextCommand command); +} diff --git a/src/main/java/com/gomo/app/support/llm/application/port/out/LlmClientPortOut.java b/src/main/java/com/gomo/app/support/llm/application/port/out/LlmClientPortOut.java new file mode 100644 index 00000000..63b95b83 --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/application/port/out/LlmClientPortOut.java @@ -0,0 +1,19 @@ +package com.gomo.app.support.llm.application.port.out; + +import com.gomo.app.support.llm.application.port.dto.LlmRequest; +import com.gomo.app.support.llm.application.port.dto.LlmResponse; + +/** + * LLM Client Port (Driven Port) + * Only + */ +public interface LlmClientPortOut { + + /** + * Generate Text from given Prompt + * + * @param {@link LlmRequest} The prompt for generate text. + * @return A {@link LlmResponse} LLM created raw text. + */ + LlmResponse generateText(LlmRequest request); +} diff --git a/src/main/java/com/gomo/app/support/llm/application/usecase/GeminiGenerateTextUseCase.java b/src/main/java/com/gomo/app/support/llm/application/usecase/GeminiGenerateTextUseCase.java new file mode 100644 index 00000000..86924caf --- /dev/null +++ b/src/main/java/com/gomo/app/support/llm/application/usecase/GeminiGenerateTextUseCase.java @@ -0,0 +1,87 @@ +package com.gomo.app.support.llm.application.usecase; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.gomo.app.common.arch.ApplicationService; +import com.gomo.app.support.llm.application.port.dto.GenerateTextDto; +import com.gomo.app.support.llm.application.port.dto.LlmRequest; +import com.gomo.app.support.llm.application.port.dto.LlmResponse; +import com.gomo.app.support.llm.application.port.in.GenerateQuestTextCommand; +import com.gomo.app.support.llm.application.port.in.GenerateQuestTextPortIn; +import com.gomo.app.support.llm.application.port.out.LlmClientPortOut; +import com.gomo.app.support.llm.exception.LlmErrorCode; +import com.gomo.app.support.llm.exception.LlmException; +import com.gomo.app.support.llm.util.PromptLoader; + +import lombok.RequiredArgsConstructor; + +@ApplicationService +@RequiredArgsConstructor +class GeminiGenerateTextUseCase implements GenerateQuestTextPortIn { + + private final LlmClientPortOut llmClient; + private final PromptLoader promptLoader; + private final ObjectMapper objectMapper; + + @Override + public GenerateTextDto generate(GenerateQuestTextCommand command) { + String prompt = buildQuestPrompt(command); + LlmResponse response = llmClient.generateText(LlmRequest.of(prompt)); + Map> questsByType = parseQuestJson(response.generatedText()); + + return GenerateTextDto.of(questsByType); + } + + private String buildQuestPrompt(GenerateQuestTextCommand command) { + String systemPrompt = promptLoader.loadPrompt("quest/system-prompt.txt"); + String userPrompt = buildUserPrompt(command); + + return systemPrompt + "\n\n" + userPrompt; + } + + private String buildUserPrompt(GenerateQuestTextCommand command) { + String interestsText = command.interests().entrySet().stream() + .map(entry -> entry.getKey() + "(숙련도: " + entry.getValue() + ")") + .collect(Collectors.joining(", ")); + return String.format( + "**개인 정보**\n- 관심사: %s\n- 퀘스트타입: %s\n-퀘스트 수: %d", + interestsText, + command.questType().name(), + command.amount() + ); + } + + private Map> parseQuestJson(String rawText) { + try { + String cleanedJson = cleanMarkdownCodeBlock(rawText); + TypeReference>> typeRef = new TypeReference>>() { + }; + return objectMapper.readValue(cleanedJson, typeRef); + } catch (JsonProcessingException e) { + throw new LlmException(LlmErrorCode.INVALID_JSON_FORMAT, e); + } catch (Exception e) { + throw new LlmException(LlmErrorCode.PARSING_ERROR, e); + } + } + + private String cleanMarkdownCodeBlock(String rawText) { + String cleaned = rawText.trim(); + + if (cleaned.startsWith("```json")) { + cleaned = cleaned.substring(7); + } else if (cleaned.startsWith("```")) { + cleaned = cleaned.substring(3); + } + + if (cleaned.endsWith("```")) { + cleaned = cleaned.substring(0, cleaned.length() - 3); + } + + return cleaned.trim(); + } +} diff --git a/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java b/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java deleted file mode 100644 index 9bcc020d..00000000 --- a/src/main/java/com/gomo/app/support/llm/exception/GenerateQuestErrorCode.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.gomo.app.support.llm.exception; - -import lombok.Getter; - -@Getter -public enum GenerateQuestErrorCode { - GEMINI_API_ERROR(500, "QUE-GEN-001", "An error occurred while call GeminiAPI"), - EMPTY_RESPONSE(500, "QUE-GEN-002", "Gemini API response blank"), - INVALID_RESPONSE_FORMAT(500, "QUE-GEN-003", "Gemini Response format is invalid"), - INVALID_JSON_FORMAT(500, "QUE-GEN-004", "Gemini Response JSON format is invalid"), - PARSING_ERROR(500, "QUE-GEN-005", "An error occurred while parse data String to Map"); - - private final int httpStatus; - private final String errorCode; - private final String message; - - GenerateQuestErrorCode(int httpStatus, String errorCode, String message) { - this.httpStatus = httpStatus; - this.errorCode = errorCode; - this.message = message; - } -} diff --git a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java index 0dc93c20..a1a775ed 100644 --- a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java +++ b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiApiAdapter.java @@ -1,25 +1,17 @@ package com.gomo.app.support.llm.infrastructure; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.web.client.RestClient; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import com.gomo.app.common.arch.Adapter; -import com.gomo.app.common.util.PromptLoader; -import com.gomo.app.support.llm.application.GenerateTextCommand; -import com.gomo.app.support.llm.application.GenerateTextDto; -import com.gomo.app.support.llm.application.LlmClientPortOut; -import com.gomo.app.support.llm.exception.GenerateQuestException; -import com.gomo.app.support.llm.exception.GenerateQuestErrorCode; +import com.gomo.app.support.llm.application.port.dto.LlmRequest; +import com.gomo.app.support.llm.application.port.dto.LlmResponse; +import com.gomo.app.support.llm.application.port.out.LlmClientPortOut; +import com.gomo.app.support.llm.exception.LlmErrorCode; +import com.gomo.app.support.llm.exception.LlmException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -28,6 +20,8 @@ @Adapter @Slf4j public class GeminiApiAdapter implements LlmClientPortOut { + private static final String GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions"; + private final RestClient restClient; @Value("${spring.ai.openai.api-key}") @@ -36,64 +30,67 @@ public class GeminiApiAdapter implements LlmClientPortOut { @Value("${spring.ai.openai.chat.options.model}") private String model; - private PromptLoader promptLoader; - - private static final String GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions"; + @Override + public LlmResponse generateText(LlmRequest request) { + try { + ApiRequest apiRequest = new ApiRequest( + model, + "none", + List.of(new ApiRequest.Message("user", request.prompt())) + ); - public GenerateTextDto generate(GenerateTextCommand command){ - try{ - String apiKey = "Bearer " + this.apiKey; - GeminiRequest request = createGeminiRequest(command); - - GeminiResponse response = restClient.post() + ApiResponse response = restClient.post() .uri(GEMINI_API_URL) - .header("Authorization", apiKey) + .header("Authorization", "Bearer " + apiKey) .contentType(MediaType.APPLICATION_JSON) - .body(request) + .body(apiRequest) .retrieve() - .body(GeminiResponse.class); + .body(ApiResponse.class); + + validateResponse(response); + String generatedText = extractGeneratedText(response); - return convertToGenerateTextDto(response); + return LlmResponse.of(generatedText); + } catch (LlmException e) { + // todo to : custom exception 추가 필요 + throw e; } catch (Exception e) { + // todo to : custom exception 추가 필요2 log.error("Failed to generate text with Gemini API", e); - throw new RuntimeException("Gemini API 호출 중 오류가 발생 했습니다.", e); + throw e; } } - private GeminiRequest createGeminiRequest(GenerateTextCommand command){ - return GeminiRequest.createPrompt(command.interests(), command.questType(), command.amount(), promptLoader); - } - - private GenerateTextDto convertToGenerateTextDto(GeminiResponse response){ - if (response.choices() == null || response.choices().isEmpty()){ - throw new GenerateQuestException(GenerateQuestErrorCode.EMPTY_RESPONSE); + private void validateResponse(ApiResponse response) { + if (response == null || response.choices() == null || response.choices().isEmpty()) { + throw new LlmException(LlmErrorCode.EMPTY_RESPONSE); } - - String generatedText = response.choices().get(0).message().content(); - return new GenerateTextDto(parseDtofromText(generatedText)); } - private Map> parseDtofromText(String text){ - try{ - String cleanText = text.trim(); + private String extractGeneratedText(ApiResponse response) { + return response.choices().getFirst().message().content(); + } - if (cleanText.startsWith("```json")) { - cleanText = cleanText.substring(7); - } + private record ApiRequest(String model, String reasoning_effort, List messages) { + record Message(String role, String content) { + } + } - if (cleanText.endsWith("```")){ - cleanText = cleanText.substring(0, cleanText.length()-3); - } + private record ApiResponse( + List choices, + int created, + String id, + String model, + String object, + Usage usage + ) { + record Choice(String finish_reason, int index, Message message) { + } - cleanText = cleanText.trim(); - ObjectMapper objectMapper = new ObjectMapper(); - TypeReference>> typeRef = new TypeReference>>() {}; + record Message(String content, String role) { + } - return objectMapper.readValue(cleanText, typeRef); - } catch (JsonProcessingException e){ - throw new GenerateQuestException(GenerateQuestErrorCode.INVALID_JSON_FORMAT); - } catch (Exception e){ - throw new GenerateQuestException(GenerateQuestErrorCode.PARSING_ERROR); + record Usage(int completion_tokens, int prompt_tokens, int total_tokens) { } } } diff --git a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java deleted file mode 100644 index 68cfcae5..00000000 --- a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiRequest.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.gomo.app.support.llm.infrastructure; - -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import com.gomo.app.common.util.PromptLoader; -import com.gomo.app.core.quest.domain.model.quest.QuestType; - -public record GeminiRequest( - String model, - String reasoning_effort, - List messages -) { - private static Prompt createSystemPrompt(PromptLoader promptLoader){ - String content = promptLoader.loadPrompt("quest/system-prompt.txt"); - return new Prompt("system", content); - } - - private static Prompt createUserPrompt(Map interests, QuestType questType, int amount){ - String interestsText = interests.entrySet().stream() - .map(entry -> entry.getKey() + "(숙련도 : " + entry.getValue() + ")") - .collect(Collectors.joining(", ")); - - String promptText = String.format( - "**개인 정보**\n- 관심사: %s \n- 퀘스트 타입: %s \n- 퀘스트 수: %s", interestsText, questType.name(), amount - ); - - return new Prompt("user", promptText); - } - - public static GeminiRequest createPrompt(Map interests, QuestType questType, int amount, PromptLoader promptLoader){ - Prompt system = createSystemPrompt(promptLoader); - Prompt user = createUserPrompt(interests, questType, amount); - return new GeminiRequest("gemini-2.5-flash", "none", List.of(system, user)); - } - - public record Prompt(String role, String content){} -} \ No newline at end of file diff --git a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiResponse.java b/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiResponse.java deleted file mode 100644 index 4c6da3db..00000000 --- a/src/main/java/com/gomo/app/support/llm/infrastructure/GeminiResponse.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.gomo.app.support.llm.infrastructure; - -import java.util.List; - -/** - * - * @param choices: a list of generated contents. normally returns 1 content. - * @param created: response created time. (Unix timestamp, unit: s) - * @param id: Unique ID. - * @param model: Gemini Model name who create response( normally: gemini-2.5-flash ) - * @param object: API response object specification string( normally: "chat.completion") - * @param usage: Total Usage. - */ -public record GeminiResponse( - List choices, - int created, - String id, - String model, - String object, - GeminiUsage usage -) { - /** - * - * @param finish_reason: reason which stopped model( ex: "stop", "length") - * @param index: index of Choice array. - * @param message: information of generated model (response and role) - */ - public record Choice(String finish_reason, int index, Message message) { - } - - /** - * - * @param content: generated text contents(in this project. generated quest) - * @param role: role ("user", "assistant") - */ - public record Message(String content, String role) { - } - - /** - * - * @param completion_tokens : Total usage to Response Token. - * @param prompt_tokens : Total usage to Prompt Token. - * @param total_tokens : Total usage of Token. - */ - public record GeminiUsage(int completion_tokens, int prompt_tokens, int total_tokens) { - } -} - - diff --git a/src/main/java/com/gomo/app/support/llm/util/PromptLoader.java b/src/main/java/com/gomo/app/support/llm/util/PromptLoader.java index 9fd32f0e..6594876a 100644 --- a/src/main/java/com/gomo/app/support/llm/util/PromptLoader.java +++ b/src/main/java/com/gomo/app/support/llm/util/PromptLoader.java @@ -3,13 +3,22 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Component; @Component public class PromptLoader { + + private final Map promptCache = new ConcurrentHashMap<>(); + public String loadPrompt(String promptPath) { + return promptCache.computeIfAbsent(promptPath, this::loadFromFile); + } + + public String loadFromFile(String promptPath) { try { ClassPathResource resource = new ClassPathResource("prompts/" + promptPath); return Files.readString(resource.getFile().toPath(), StandardCharsets.UTF_8);