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/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 0c37c6de..8a4ac6af 100644
--- a/src/docs/asciidoc/apis/auth-api.adoc
+++ b/src/docs/asciidoc/apis/auth-api.adoc
@@ -1,3 +1,43 @@
+=== 회원 가입
+
+`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']
+
+'''
+
+=== 비밀번호 초기화 (찾기)
+
+`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`
@@ -16,10 +56,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 +72,6 @@ operation::auth-logout[snippets='request-headers']
성공 시 `204 No Content` 상태 코드와 함께 빈 응답 본문을 반환합니다.
-// ==== 에러 응답
-//
-// operation::member-logout-error[snippets='http-response,response-fields']
-
'''
=== Refresh Token 재발급
@@ -60,25 +92,21 @@ 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 /members/emails/codes/signup`
+`POST /auth/codes/emails/signup`
회원가입에 사용할 이메일 인증 코드를 요청한 이메일 주소로 발송합니다.
==== 요청 헤더
-operation::member-email-auth-code-create[snippets='request-headers']
+operation::auth-code-for-sign-up-create[snippets='request-headers']
==== 요청 본문 (JSON)
-operation::member-email-auth-code-create[snippets='http-request,request-fields']
+operation::auth-code-for-sign-up-create[snippets='http-request,request-fields']
==== 성공 응답
@@ -86,23 +114,23 @@ operation::member-email-auth-code-create[snippets='http-request,request-fields']
==== 에러 응답 (이미 가입된 이메일)
-operation::member-email-auth-code-create-error[snippets='http-response,response-fields']
+operation::auth-code-for-sign-up-create-error[snippets='http-response,response-fields']
'''
=== 이메일 인증 코드 발송 (비밀번호 변경 시)
-`POST /members/passwords/reset`
+`POST /auth/codes/emails/passwords/reset`
비밀번호 찾기에 사용할 이메일 인증 코드를 요청한 이메일 주소로 발송합니다.
==== 요청 헤더
-operation::member-password-auth-code-create[snippets='request-headers']
+operation::auth-code-for-password-reset-create[snippets='request-headers']
==== 요청 본문 (JSON)
-operation::member-password-auth-code-create[snippets='http-request,request-fields']
+operation::auth-code-for-password-reset-create[snippets='http-request,request-fields']
==== 성공 응답
@@ -110,19 +138,19 @@ operation::member-password-auth-code-create[snippets='http-request,request-field
==== 에러 응답 (이미 가입된 이메일)
-operation::member-password-auth-code-create-error[snippets='http-response,response-fields']
+operation::auth-code-for-password-reset-create-error[snippets='http-response,response-fields']
'''
=== 이메일 인증 코드 검증
-`GET /members/emails/codes/verify`
+`GET /auth/codes/emails/verify`
이메일로 발송된 인증 코드가 올바른지 검증합니다.
==== 쿼리 파라미터
-operation::member-email-auth-code-verify[snippets='query-parameters']
+operation::auth-code-verify[snippets='query-parameters']
==== 성공 응답
@@ -130,4 +158,4 @@ operation::member-email-auth-code-verify[snippets='query-parameters']
==== 에러 응답 (잘못된 인증 코드)
-operation::member-email-auth-code-verify-error[snippets='http-response,response-fields']
+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 77c6b3c4..41e4aea5 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']
-
'''
=== 프로필 이미지 삭제
@@ -189,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`
@@ -255,10 +195,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 +215,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 +235,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,7 +252,3 @@ operation::member-widget-update[snippets='http-request,request-fields']
==== 성공 응답
성공 시 `204 No Content` 상태 코드와 함께 빈 응답 본문을 반환합니다.
-
-// ==== 에러 응답
-//
-// operation::member-quest-property-update-error[snippets='http-response,response-fields']
diff --git a/src/docs/asciidoc/index.adoc b/src/docs/asciidoc/index.adoc
index b5486973..f4919476 100644
--- a/src/docs/asciidoc/index.adoc
+++ b/src/docs/asciidoc/index.adoc
@@ -1,14 +1,27 @@
-= gomo api docs
+= GOMO Docs - API
:doctype: book
:source-highlighter: highlightjs
:toc: left
: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-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[]
==== 에러 코드
@@ -16,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 +
@@ -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/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/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..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.DeleteImagePortIn;
-
import lombok.RequiredArgsConstructor;
@Component
@RequiredArgsConstructor
public class MemberCleanupScheduler {
- private final DeleteImagePortIn deleteImagePortIn;
- 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());
-
- // 이미지 파일 삭제
- deleteImagePortIn.delete(member.profileImageUrl());
- deleteImagePortIn.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/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/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 77%
rename from src/main/java/com/gomo/app/config/WebConfiguration.java
rename to src/main/java/com/gomo/app/common/config/WebConfiguration.java
index 61229c50..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;
@@ -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.support.auth.presentation.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/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/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/event/CompleteQuestEvent.java
rename to src/main/java/com/gomo/app/common/event/CompleteQuestEvent.java
index 72212308..d9759722 100644
--- a/src/main/java/com/gomo/app/core/quest/event/CompleteQuestEvent.java
+++ b/src/main/java/com/gomo/app/common/event/CompleteQuestEvent.java
@@ -1,10 +1,8 @@
-package com.gomo.app.core.quest.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/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/event/CreateQuestPoolEvent.java
rename to src/main/java/com/gomo/app/common/event/CreateQuestPoolEvent.java
index 8f1602c2..667a2184 100644
--- a/src/main/java/com/gomo/app/core/quest/event/CreateQuestPoolEvent.java
+++ b/src/main/java/com/gomo/app/common/event/CreateQuestPoolEvent.java
@@ -1,10 +1,8 @@
-package com.gomo.app.core.quest.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/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/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/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/support/auth/presentation/security/Auth.java b/src/main/java/com/gomo/app/common/session/Session.java
similarity index 73%
rename from src/main/java/com/gomo/app/support/auth/presentation/security/Auth.java
rename to src/main/java/com/gomo/app/common/session/Session.java
index 02b3ae6d..73898a70 100644
--- a/src/main/java/com/gomo/app/support/auth/presentation/security/Auth.java
+++ b/src/main/java/com/gomo/app/common/session/Session.java
@@ -1,4 +1,4 @@
-package com.gomo.app.support.auth.presentation.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/support/auth/presentation/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/support/auth/presentation/security/AuthArgumentResolver.java
rename to src/main/java/com/gomo/app/common/session/SessionArgumentResolver.java
index 987866a5..8c129369 100644
--- a/src/main/java/com/gomo/app/support/auth/presentation/security/AuthArgumentResolver.java
+++ b/src/main/java/com/gomo/app/common/session/SessionArgumentResolver.java
@@ -1,6 +1,8 @@
-package com.gomo.app.support.auth.presentation.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/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/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/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
new file mode 100644
index 00000000..6b408103
--- /dev/null
+++ b/src/main/java/com/gomo/app/core/auth/adapter/in/api/AuthApi.java
@@ -0,0 +1,90 @@
+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;
+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.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.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;
+
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@RequestMapping("/auth")
+@CoreApi
+public class AuthApi {
+
+ private final SignupProcessor signupProcessor;
+ private final PasswordResetProcessor passwordResetProcessor;
+ 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));
+ }
+
+ @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());
+ 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);
+ }
+
+ @PostMapping("/refresh")
+ public ResponseEntity refresh(@CookieValue(name = "refreshToken", required = false) String 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()));
+ }
+
+ @GetMapping("/logout")
+ public ResponseEntity logout(@Session SessionInfo sessionInfo) {
+ refreshTokenDeleter.delete(sessionInfo.getPrincipalId());
+ ResponseCookie cookie = createResponseCookie("", 0);
+ return ResponseEntity.ok().header(HttpHeaders.SET_COOKIE, cookie.toString()).build();
+ }
+
+ private ResponseCookie createResponseCookie(String refreshToken, long expiresIn) {
+ return ResponseCookie.from("refreshToken", refreshToken)
+ .httpOnly(true)
+ .secure(true)
+ .path("/")
+ .maxAge(Duration.ofMillis(expiresIn))
+ .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/ResetPasswordRequest.java b/src/main/java/com/gomo/app/core/auth/adapter/in/api/request/ResetPasswordRequest.java
similarity index 73%
rename from src/main/java/com/gomo/app/core/member/presentation/request/ResetPasswordRequest.java
rename to src/main/java/com/gomo/app/core/auth/adapter/in/api/request/ResetPasswordRequest.java
index c565638f..e0262e5e 100644
--- a/src/main/java/com/gomo/app/core/member/presentation/request/ResetPasswordRequest.java
+++ b/src/main/java/com/gomo/app/core/auth/adapter/in/api/request/ResetPasswordRequest.java
@@ -1,13 +1,13 @@
-package com.gomo.app.core.member.presentation.request;
+package com.gomo.app.core.auth.adapter.in.api.request;
import lombok.Getter;
@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/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/AuthenticationFilter.java b/src/main/java/com/gomo/app/core/auth/adapter/in/filter/AuthenticationFilter.java
similarity index 77%
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/filter/AuthenticationFilter.java
index 978fe082..a9ea646c 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/filter/AuthenticationFilter.java
@@ -1,5 +1,6 @@
-package com.gomo.app.support.auth.presentation.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;
@@ -8,8 +9,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 +29,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,10 +56,10 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
}
try {
token = token.substring(BEARER_TOKEN.length());
- String memberId = verifyJwtPortIn.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/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..8e237441
--- /dev/null
+++ b/src/main/java/com/gomo/app/core/auth/adapter/out/client/MemberClient.java
@@ -0,0 +1,55 @@
+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.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, 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) {
+ 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);
+ }
+
+ @Override
+ public void reset(String email, String newPassword) {
+ passwordResetter.reset(email, newPassword);
+ }
+}
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/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/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/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/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/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/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..70865882
--- /dev/null
+++ b/src/main/java/com/gomo/app/core/auth/application/service/AuthService.java
@@ -0,0 +1,62 @@
+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.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;
+
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@ApplicationService
+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")
+ 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);
+ }
+
+ @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/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/config/FilterRegistrationConfiguration.java b/src/main/java/com/gomo/app/core/auth/config/FilterRegistrationConfiguration.java
similarity index 95%
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 c0775457..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;
@@ -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.filter.AuthenticationFilter;
import com.gomo.app.support.logging.LoggingFilter;
import lombok.RequiredArgsConstructor;
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..c6f17c8b 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,9 @@ 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");
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/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/api/InterestApi.java b/src/main/java/com/gomo/app/core/interest/adapter/in/api/InterestApi.java
new file mode 100644
index 00000000..6879073b
--- /dev/null
+++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/InterestApi.java
@@ -0,0 +1,76 @@
+package com.gomo.app.core.interest.adapter.in.api;
+
+import static org.springframework.http.HttpStatus.*;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.springframework.http.MediaType;
+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.ModelAttribute;
+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.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;
+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.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 lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@RequestMapping("/interests")
+@CoreApi
+public class InterestApi {
+
+ 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(@Session SessionInfo sessionInfo, @ModelAttribute CreateInterestRequest request) {
+ UUID interestId = interestCreator.create(request.toCommand(sessionInfo.getPrincipalId()));
+ return ResponseEntity.status(CREATED).body(CreateInterestResponse.of(interestId));
+ }
+
+ @GetMapping("/{id}")
+ public ResponseEntity find(@PathVariable("id") UUID interestId) {
+ InterestDto dto = interestReader.read(interestId);
+ return ResponseEntity.status(OK).body(ReadInterestResponse.from(dto));
+ }
+
+ @GetMapping
+ 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(@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(@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/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/adapter/in/api/InterestNetworkApi.java b/src/main/java/com/gomo/app/core/interest/adapter/in/api/InterestNetworkApi.java
new file mode 100644
index 00000000..e4899efc
--- /dev/null
+++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/InterestNetworkApi.java
@@ -0,0 +1,54 @@
+package com.gomo.app.core.interest.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.RequestBody;
+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;
+import com.gomo.app.core.interest.application.port.dto.InterestNetworkDto;
+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 lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@RequestMapping("/interests/networks")
+@CoreApi
+public class InterestNetworkApi {
+
+ private final InterestRelationCreator interestRelationCreator;
+ private final InterestNetworkReader interestNetworkReader;
+ private final InterestRelationDeleter interestRelationDeleter;
+
+ @PostMapping("/relations")
+ 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(@Session SessionInfo sessionInfo) {
+ InterestNetworkDto interestNetworkDto = interestNetworkReader.read(sessionInfo.getPrincipalId());
+ return ResponseEntity.ok(InterestNetworkResponse.from(interestNetworkDto));
+ }
+
+ @DeleteMapping("/relations/{id}")
+ 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
new file mode 100644
index 00000000..7aafff1e
--- /dev/null
+++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/MajorInterestApi.java
@@ -0,0 +1,53 @@
+package com.gomo.app.core.interest.adapter.in.api;
+
+import static org.springframework.http.HttpStatus.*;
+
+import java.util.List;
+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.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 lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@RequestMapping("/interests")
+@CoreApi
+public class MajorInterestApi {
+
+ private final MajorInterestCreator majorInterestCreator;
+ private final MajorInterestReader majorInterestReader;
+ private final MajorInterestDeleter majorInterestDeleter;
+
+ @PostMapping("/{id}/majors")
+ 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(@Session SessionInfo sessionInfo) {
+ List dtos = majorInterestReader.readAll(sessionInfo.getPrincipalId());
+ return ResponseEntity.ok(ListMajorInterestResponse.of(dtos));
+ }
+
+ @DeleteMapping("/majors/{id}")
+ 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
new file mode 100644
index 00000000..91ce5cdf
--- /dev/null
+++ b/src/main/java/com/gomo/app/core/interest/adapter/in/api/OrderUpdateMajorInterestApi.java
@@ -0,0 +1,28 @@
+package com.gomo.app.core.interest.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.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 lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@RequestMapping("/interests/majors/orders")
+@CoreApi
+public class OrderUpdateMajorInterestApi {
+
+ private final MajorInterestOrderUpdater majorInterestOrderUpdater;
+
+ @PutMapping
+ 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/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..a33acd72 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.event.CompleteQuestEvent;
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.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/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/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/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/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/interest/presentation/api/InterestApi.java b/src/main/java/com/gomo/app/core/interest/presentation/api/InterestApi.java
deleted file mode 100644
index f530b604..00000000
--- a/src/main/java/com/gomo/app/core/interest/presentation/api/InterestApi.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.gomo.app.core.interest.presentation.api;
-
-import static org.springframework.http.HttpStatus.*;
-
-import java.util.List;
-import java.util.UUID;
-
-import org.springframework.http.MediaType;
-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.ModelAttribute;
-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.interest.application.port.ReadInterestPortIn;
-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 lombok.RequiredArgsConstructor;
-
-@RequiredArgsConstructor
-@RequestMapping("/interests")
-@CoreApi
-public class InterestApi {
-
- private final CreateInterestUseCase createInterestUseCase;
- private final ReadInterestPortIn readInterestPortIn;
- private final UpdateInterestUseCase updateInterestUseCase;
- private final DeleteInterestUseCase deleteInterestUseCase;
-
- @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
- public ResponseEntity create(@Auth AuthInfo authInfo, @ModelAttribute CreateInterestRequest request) {
- UUID interestId = createInterestUseCase.create(request.toCommand(authInfo.getMemberId()));
- return ResponseEntity.status(CREATED).body(CreateInterestResponse.of(interestId));
- }
-
- @GetMapping("/{id}")
- public ResponseEntity find(@PathVariable("id") UUID interestId) {
- InterestDto dto = readInterestPortIn.find(interestId);
- return ResponseEntity.status(OK).body(ReadInterestResponse.from(dto));
- }
-
- @GetMapping
- public ResponseEntity list(@Auth AuthInfo authInfo) {
- List responses = readInterestPortIn.findAll(authInfo.getMemberId()).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) {
- updateInterestUseCase.update(request.toCommand(authInfo.getMemberId(), interestId));
- return ResponseEntity.noContent().build();
- }
-
- @DeleteMapping("/{id}")
- public ResponseEntity delete(@Auth AuthInfo authInfo, @PathVariable("id") UUID interestId) {
- deleteInterestUseCase.delete(authInfo.getMemberId(), interestId);
- 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/presentation/api/InterestNetworkApi.java
deleted file mode 100644
index 669ab61c..00000000
--- a/src/main/java/com/gomo/app/core/interest/presentation/api/InterestNetworkApi.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.gomo.app.core.interest.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.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-
-import com.gomo.app.common.arch.CoreApi;
-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 lombok.RequiredArgsConstructor;
-
-@RequiredArgsConstructor
-@RequestMapping("/interests/networks")
-@CoreApi
-public class InterestNetworkApi {
-
- private final CreateInterestRelationUseCase createInterestRelationUseCase;
- private final ReadInterestNetworkUseCase readInterestNetworkUseCase;
- private final DeleteInterestRelationUseCase deleteInterestRelationUseCase;
-
- @PostMapping("/relations")
- public ResponseEntity createRelation(@Auth AuthInfo authInfo, @RequestBody CreateInterestRelationRequest request) {
- UUID relationId = createInterestRelationUseCase.create(authInfo.getMemberId(), 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());
- return ResponseEntity.ok(InterestNetworkResponse.from(interestNetworkDto));
- }
-
- @DeleteMapping("/relations/{id}")
- public ResponseEntity deleteRelation(@Auth AuthInfo authInfo, @PathVariable("id") UUID interestRelationId) {
- deleteInterestRelationUseCase.delete(authInfo.getMemberId(), 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/presentation/api/MajorInterestApi.java
deleted file mode 100644
index b41903a9..00000000
--- a/src/main/java/com/gomo/app/core/interest/presentation/api/MajorInterestApi.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.gomo.app.core.interest.presentation.api;
-
-import static org.springframework.http.HttpStatus.*;
-
-import java.util.List;
-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.RequestMapping;
-
-import com.gomo.app.common.arch.CoreApi;
-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 lombok.RequiredArgsConstructor;
-
-@RequiredArgsConstructor
-@RequestMapping("/interests")
-@CoreApi
-public class MajorInterestApi {
-
- private final CreateMajorInterestUseCase createMajorInterestUseCase;
- private final ReadMajorInterestUseCase readMajorInterestUseCase;
- private final DeleteMajorInterestUseCase deleteMajorInterestUseCase;
-
- @PostMapping("/{id}/majors")
- public ResponseEntity create(@Auth AuthInfo authInfo, @PathVariable("id") UUID interestId) {
- UUID majorInterestId = createMajorInterestUseCase.create(authInfo.getMemberId(), interestId);
- return ResponseEntity.status(CREATED).body(CreateMajorInterestResponse.of(majorInterestId));
- }
-
- @GetMapping("/majors")
- public ResponseEntity findAll(@Auth AuthInfo authInfo) {
- List dtos = readMajorInterestUseCase.findAll(authInfo.getMemberId());
- return ResponseEntity.ok(ListMajorInterestResponse.of(dtos));
- }
-
- @DeleteMapping("/majors/{id}")
- public ResponseEntity delete(@Auth AuthInfo authInfo, @PathVariable("id") UUID majorInterestId) {
- deleteMajorInterestUseCase.delete(authInfo.getMemberId(), 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/presentation/api/OrderUpdateMajorInterestApi.java
deleted file mode 100644
index 3e29ed5e..00000000
--- a/src/main/java/com/gomo/app/core/interest/presentation/api/OrderUpdateMajorInterestApi.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.gomo.app.core.interest.presentation.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.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 lombok.RequiredArgsConstructor;
-
-@RequiredArgsConstructor
-@RequestMapping("/interests/majors/orders")
-@CoreApi
-public class OrderUpdateMajorInterestApi {
-
- private final OrderUpdateMajorInterestUseCase orderUpdateMajorInterestUseCase;
-
- @PutMapping
- public ResponseEntity update(@Auth AuthInfo authInfo, @RequestBody OrderUpdateMajorInterestRequest request) {
- orderUpdateMajorInterestUseCase.update(request.toCommand(authInfo.getMemberId()));
- return ResponseEntity.noContent().build();
- }
-}
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/HandleApi.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/HandleApi.java
new file mode 100644
index 00000000..96e67110
--- /dev/null
+++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/HandleApi.java
@@ -0,0 +1,38 @@
+package com.gomo.app.core.member.adapter.in.api;
+
+import org.springframework.http.ResponseEntity;
+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 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 lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@RequestMapping("/members/handles")
+@CoreApi
+public class HandleApi {
+
+ private final HandleValidator handleValidator;
+ private final HandleUpdater handleUpdater;
+
+ @GetMapping("/duplicate")
+ public ResponseEntity checkHandleDuplicated(@RequestParam String handle) {
+ handleValidator.validateDuplicated(handle);
+ return ResponseEntity.ok().build();
+ }
+
+ @PutMapping
+ 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
new file mode 100644
index 00000000..64483db3
--- /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.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 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(@Session SessionInfo sessionInfo) {
+ MemberDto dto = memberReader.read(sessionInfo.getPrincipalId());
+ return ResponseEntity.ok(ReadMemberResponse.of(dto));
+ }
+
+ @PutMapping
+ 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(@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
new file mode 100644
index 00000000..92b99574
--- /dev/null
+++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/PasswordApi.java
@@ -0,0 +1,28 @@
+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.common.session.Session;
+import com.gomo.app.common.session.SessionInfo;
+import com.gomo.app.core.member.adapter.in.api.request.UpdatePasswordRequest;
+import com.gomo.app.core.member.application.port.in.PasswordUpdater;
+
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@RequestMapping("/members/passwords")
+@CoreApi
+public class PasswordApi {
+
+ private final PasswordUpdater passwordUpdater;
+
+ @PutMapping
+ 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
new file mode 100644
index 00000000..76e7a1e1
--- /dev/null
+++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/ProfileBannerApi.java
@@ -0,0 +1,38 @@
+package com.gomo.app.core.member.adapter.in.api;
+
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PutMapping;
+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 lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@RequestMapping("/members/images/banners")
+@CoreApi
+public class ProfileBannerApi {
+
+ private final ProfileBannerUpdater profileBannerUpdater;
+ private final ProfileBannerDeleter profileBannerDeleter;
+
+ @PutMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+ public ResponseEntity update(@Session SessionInfo sessionInfo, @ModelAttribute UpdateProfileBannerRequest request) {
+ profileBannerUpdater.update(sessionInfo.getPrincipalId(), request.getProfileBanner());
+ return ResponseEntity.noContent().build();
+ }
+
+ @DeleteMapping
+ 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
new file mode 100644
index 00000000..78f3068f
--- /dev/null
+++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/ProfileImageApi.java
@@ -0,0 +1,38 @@
+package com.gomo.app.core.member.adapter.in.api;
+
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PutMapping;
+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 lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@RequestMapping("/members/images/profiles")
+@CoreApi
+public class ProfileImageApi {
+
+ private final ProfileImageUpdater profileImageUpdater;
+ private final ProfileImageDeleter profileImageDeleter;
+
+ @PutMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+ public ResponseEntity update(@Session SessionInfo sessionInfo, @ModelAttribute UpdateProfileImageRequest request) {
+ profileImageUpdater.update(sessionInfo.getPrincipalId(), request.getProfileImage());
+ return ResponseEntity.noContent().build();
+ }
+
+ @DeleteMapping
+ 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
new file mode 100644
index 00000000..2dbf945a
--- /dev/null
+++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/QuestPropertyApi.java
@@ -0,0 +1,39 @@
+package com.gomo.app.core.member.adapter.in.api;
+
+import org.springframework.http.ResponseEntity;
+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.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 lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@RequestMapping("/members/properties/quests")
+@CoreApi
+public class QuestPropertyApi {
+
+ private final QuestPropertyReader questPropertyReader;
+ private final QuestPropertyUpdater questPropertyUpdater;
+
+ @GetMapping
+ public ResponseEntity find(@Session SessionInfo sessionInfo) {
+ QuestPropertyDto dto = questPropertyReader.read(sessionInfo.getPrincipalId());
+ return ResponseEntity.ok(ReadQuestPropertyResponse.of(dto));
+ }
+
+ @PutMapping
+ 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
new file mode 100644
index 00000000..6e1f7857
--- /dev/null
+++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/WidgetApi.java
@@ -0,0 +1,28 @@
+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.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 lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@RequestMapping("/members/widgets")
+@CoreApi
+public class WidgetApi {
+
+ private final WidgetUpdater widgetUpdater;
+
+ @PutMapping
+ 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/member/adapter/in/api/request/ResetPasswordRequest.java b/src/main/java/com/gomo/app/core/member/adapter/in/api/request/ResetPasswordRequest.java
new file mode 100644
index 00000000..8ced64cc
--- /dev/null
+++ b/src/main/java/com/gomo/app/core/member/adapter/in/api/request/ResetPasswordRequest.java
@@ -0,0 +1,21 @@
+package com.gomo.app.core.member.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/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 83%
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 4253f2bc..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;
@@ -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/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/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/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/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/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/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..4b4253a0
--- /dev/null
+++ b/src/main/java/com/gomo/app/core/member/application/port/in/PasswordResetter.java
@@ -0,0 +1,15 @@
+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.
+ *
+ * @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.
+ * @throws MemberNotFoundException if no member is found with the specified email address.
+ */
+ void reset(String email, String newPassword);
+}
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/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/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/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..0ee8f9b1
--- /dev/null
+++ b/src/main/java/com/gomo/app/core/member/application/service/PasswordService.java
@@ -0,0 +1,55 @@
+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.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 PasswordEncodeManager passwordEncodeManager;
+ private final MemberService memberService;
+
+ @Override
+ @AuditLog(action = "PASSWORD_RESET")
+ 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));
+ }
+
+ @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 74%
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..ed3c6209 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;
@@ -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/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..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
@@ -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.MemberAuthenticationFailedException;
+import com.gomo.app.core.member.domain.exception.code.ActivateStatusErrorCode;
+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/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/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/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 a2339140..00000000
--- a/src/main/java/com/gomo/app/core/member/presentation/EmailCodeApi.java
+++ /dev/null
@@ -1,46 +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.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;
-
-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));
- }
-
- @GetMapping("/verify")
- public ResponseEntity verify(@ModelAttribute 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/HandleApi.java b/src/main/java/com/gomo/app/core/member/presentation/HandleApi.java
deleted file mode 100644
index 16f9ff11..00000000
--- a/src/main/java/com/gomo/app/core/member/presentation/HandleApi.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.gomo.app.core.member.presentation;
-
-import org.springframework.http.ResponseEntity;
-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 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 lombok.RequiredArgsConstructor;
-
-@RequiredArgsConstructor
-@RequestMapping("/members/handles")
-@CoreApi
-public class HandleApi {
-
- private final CheckHandleUseCase checkHandleUseCase;
- private final UpdateHandleUseCase updateHandleUseCase;
-
- @GetMapping("/duplicate")
- public ResponseEntity checkHandleDuplicated(@RequestParam String handle) {
- checkHandleUseCase.checkHandleDuplicated(handle);
- return ResponseEntity.ok().build();
- }
-
- @PutMapping
- public ResponseEntity update(@Auth AuthInfo authInfo, @RequestBody UpdateHandleRequest request) {
- updateHandleUseCase.update(authInfo.getMemberId(), request.getHandle());
- return ResponseEntity.noContent().build();
- }
-}
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/ProfileBannerApi.java b/src/main/java/com/gomo/app/core/member/presentation/ProfileBannerApi.java
deleted file mode 100644
index d638edb0..00000000
--- a/src/main/java/com/gomo/app/core/member/presentation/ProfileBannerApi.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.gomo.app.core.member.presentation;
-
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.ModelAttribute;
-import org.springframework.web.bind.annotation.PutMapping;
-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 lombok.RequiredArgsConstructor;
-
-@RequiredArgsConstructor
-@RequestMapping("/members/images/banners")
-@CoreApi
-public class ProfileBannerApi {
-
- private final UpdateProfileBannerUseCase updateProfileBannerUseCase;
- private final DeleteProfileBannerUseCase deleteProfileBannerUseCase;
-
- @PutMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
- public ResponseEntity update(@Auth AuthInfo authInfo, @ModelAttribute UpdateProfileBannerRequest request) {
- updateProfileBannerUseCase.update(authInfo.getMemberId(), request.getProfileBanner());
- return ResponseEntity.noContent().build();
- }
-
- @DeleteMapping
- public ResponseEntity delete(@Auth AuthInfo authInfo) {
- deleteProfileBannerUseCase.delete(authInfo.getMemberId());
- 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/presentation/ProfileImageApi.java
deleted file mode 100644
index e86a70c3..00000000
--- a/src/main/java/com/gomo/app/core/member/presentation/ProfileImageApi.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.gomo.app.core.member.presentation;
-
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.ModelAttribute;
-import org.springframework.web.bind.annotation.PutMapping;
-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 lombok.RequiredArgsConstructor;
-
-@RequiredArgsConstructor
-@RequestMapping("/members/images/profiles")
-@CoreApi
-public class ProfileImageApi {
-
- private final UpdateProfileImageUseCase updateProfileImageUseCase;
- private final DeleteProfileImageUseCase deleteProfileImageUseCase;
-
- @PutMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
- public ResponseEntity update(@Auth AuthInfo authInfo, @ModelAttribute UpdateProfileImageRequest request) {
- updateProfileImageUseCase.update(authInfo.getMemberId(), request.getProfileImage());
- return ResponseEntity.noContent().build();
- }
-
- @DeleteMapping
- public ResponseEntity delete(@Auth AuthInfo authInfo) {
- deleteProfileImageUseCase.delete(authInfo.getMemberId());
- 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/presentation/QuestPropertyApi.java
deleted file mode 100644
index de43a640..00000000
--- a/src/main/java/com/gomo/app/core/member/presentation/QuestPropertyApi.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.gomo.app.core.member.presentation;
-
-import org.springframework.http.ResponseEntity;
-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.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 lombok.RequiredArgsConstructor;
-
-@RequiredArgsConstructor
-@RequestMapping("/members/properties/quests")
-@CoreApi
-public class QuestPropertyApi {
-
- private final ReadQuestPropertyUseCase readQuestPropertyUseCase;
- private final UpdateQuestPropertyUseCase updateQuestPropertyUseCase;
-
- @GetMapping
- public ResponseEntity find(@Auth AuthInfo authInfo) {
- QuestPropertyDto dto = readQuestPropertyUseCase.find(authInfo.getMemberId());
- return ResponseEntity.ok(ReadQuestPropertyResponse.of(dto));
- }
-
- @PutMapping
- public ResponseEntity update(@Auth AuthInfo authInfo, @RequestBody UpdateQuestPropertyRequest request) {
- updateQuestPropertyUseCase.update(request.toCommand(authInfo.getMemberId()));
- 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/presentation/WidgetApi.java
deleted file mode 100644
index dddacec6..00000000
--- a/src/main/java/com/gomo/app/core/member/presentation/WidgetApi.java
+++ /dev/null
@@ -1,28 +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.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 lombok.RequiredArgsConstructor;
-
-@RequiredArgsConstructor
-@RequestMapping("/members/widgets")
-@CoreApi
-public class WidgetApi {
-
- private final UpdateWidgetUseCase updateWidgetUseCase;
-
- @PutMapping
- public ResponseEntity update(@Auth AuthInfo authInfo, @RequestBody UpdateWidgetRequest request) {
- updateWidgetUseCase.update(authInfo.getMemberId(), request.getSnapshot());
- 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/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/api/PointApi.java b/src/main/java/com/gomo/app/core/point/adapter/in/api/PointApi.java
new file mode 100644
index 00000000..d0184804
--- /dev/null
+++ b/src/main/java/com/gomo/app/core/point/adapter/in/api/PointApi.java
@@ -0,0 +1,39 @@
+package com.gomo.app.core.point.adapter.in.api;
+
+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.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 lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@RequestMapping("/points")
+@CoreApi
+public class PointApi {
+
+ private final PointReader pointReader;
+ private final BalanceReader balanceReader;
+
+ @GetMapping
+ 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(@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/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..854a4394 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.event.CompleteQuestEvent;
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.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/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/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/point/presentation/api/PointApi.java b/src/main/java/com/gomo/app/core/point/presentation/api/PointApi.java
deleted file mode 100644
index fa53f4eb..00000000
--- a/src/main/java/com/gomo/app/core/point/presentation/api/PointApi.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.gomo.app.core.point.presentation.api;
-
-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.RequestMapping;
-
-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.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 lombok.RequiredArgsConstructor;
-
-@RequiredArgsConstructor
-@RequestMapping("/points")
-@CoreApi
-public class PointApi {
-
- private final ReadPointUseCase readPointUseCase;
- private final ReadBalancePortIn readBalancePortIn;
-
- @GetMapping
- public ResponseEntity findAll(@Auth AuthInfo authInfo, @ModelAttribute PageRequest pageRequest) {
- ListPointDto dto = readPointUseCase.findAll(authInfo.getMemberId(), pageRequest);
- return ResponseEntity.ok(ListPointResponse.from(dto));
- }
-
- @GetMapping("/balances")
- public ResponseEntity findBalance(@Auth AuthInfo authInfo) {
- int balance = readBalancePortIn.find(authInfo.getMemberId());
- return ResponseEntity.ok(ReadBalanceResponse.of(balance));
- }
-}
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/api/AssignQuestApi.java b/src/main/java/com/gomo/app/core/quest/adapter/in/api/AssignQuestApi.java
new file mode 100644
index 00000000..d6444737
--- /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.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;
+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 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(@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(@Session SessionInfo sessionInfo) {
+ ListAssignQuestDetailDto dto = assignQuestDetailReader.readAll(sessionInfo.getPrincipalId());
+ return ResponseEntity.ok(ListAssignQuestDetailResponse.from(dto));
+ }
+
+ @PutMapping("/{id}")
+ 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(@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
new file mode 100644
index 00000000..244cab60
--- /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.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 lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@RequestMapping("/quests/assigns/calendars")
+@CoreApi
+public class CalendarAssignQuestApi {
+
+ private final AssignQuestReader assignQuestReader;
+
+ @GetMapping
+ public ResponseEntity find(@Session SessionInfo sessionInfo, @RequestParam boolean isCompleted,
+ @RequestParam LocalDateTime startDateTime, @RequestParam LocalDateTime 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
new file mode 100644
index 00000000..48f83d60
--- /dev/null
+++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/CompleteAssignQuestApi.java
@@ -0,0 +1,32 @@
+package com.gomo.app.core.quest.adapter.in.api;
+
+import java.time.LocalDateTime;
+import java.util.UUID;
+
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PathVariable;
+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.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 lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@RequestMapping("/quests/assigns/{id}/complete")
+@CoreApi
+public class CompleteAssignQuestApi {
+
+ private final AssignQuestCompleter assignQuestCompleter;
+
+ @PutMapping
+ 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
new file mode 100644
index 00000000..be0f9fc9
--- /dev/null
+++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/ConfirmAssignQuestApi.java
@@ -0,0 +1,29 @@
+package com.gomo.app.core.quest.adapter.in.api;
+
+import java.util.UUID;
+
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PutMapping;
+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 lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@RequestMapping("/quests/assigns/{id}/confirm")
+@CoreApi
+public class ConfirmAssignQuestApi {
+
+ private final AssignQuestConfirmer assignQuestConfirmer;
+
+ @PutMapping
+ 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
new file mode 100644
index 00000000..12c0f961
--- /dev/null
+++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/OrderUpdateAssignQuestApi.java
@@ -0,0 +1,28 @@
+package com.gomo.app.core.quest.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.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 lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@RequestMapping("/quests/assigns/orders")
+@CoreApi
+public class OrderUpdateAssignQuestApi {
+
+ private final AssignQuestOrderUpdater assignQuestOrderUpdater;
+
+ @PutMapping
+ 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
new file mode 100644
index 00000000..21a2d321
--- /dev/null
+++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/OrderUpdateRepeatQuestApi.java
@@ -0,0 +1,28 @@
+package com.gomo.app.core.quest.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.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 lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@RequestMapping("/quests/repeats/orders")
+@CoreApi
+public class OrderUpdateRepeatQuestApi {
+
+ private final RepeatQuestOrderUpdater repeatQuestOrderUpdater;
+
+ @PutMapping
+ 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
new file mode 100644
index 00000000..1648f74e
--- /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.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 lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@RequestMapping("/quests/assigns/re-roll")
+@CoreApi
+public class ReRollAssignQuestApi {
+
+ private final AssignQuestReRoller assignQuestReRoller;
+
+ @PostMapping
+ 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
new file mode 100644
index 00000000..ad9cb92d
--- /dev/null
+++ b/src/main/java/com/gomo/app/core/quest/adapter/in/api/RepeatQuestApi.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.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;
+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.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 lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@RequestMapping("/quests/repeats")
+@CoreApi
+public class RepeatQuestApi {
+
+ private final RepeatQuestCreator repeatQuestCreator;
+ private final RepeatQuestReader repeatQuestReader;
+ private final RepeatQuestUpdater repeatQuestUpdater;
+ private final RepeatQuestDeleter repeatQuestDeleter;
+
+ @PostMapping
+ 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(@Session SessionInfo sessionInfo) {
+ ListRepeatQuestDto dto = repeatQuestReader.readAll(sessionInfo.getPrincipalId());
+ return ResponseEntity.ok(ListRepeatQuestResponse.from(dto));
+ }
+
+ @PutMapping("/{id}")
+ 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(@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/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..3e1ab3a7 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.event.CreateQuestPoolEvent;
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.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 80%
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..17847cec 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,13 +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.support.llm.application.GenerateTextPortIn;
+import com.gomo.app.core.quest.application.port.out.QuestContentCreator;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -15,7 +14,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