Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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"
Expand All @@ -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') {
Expand Down
20 changes: 20 additions & 0 deletions src/docs/asciidoc/apis/auth-api.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,26 @@ operation::auth-signup[snippets='http-response,response-fields']

'''

=== 비밀번호 초기화 (찾기)

`PUT /auth/passwords/reset`

이메일 인증 등을 통해 본인인증이 완료된 사용자가 비밀번호를 새로 설정합니다.

==== 요청 헤더

operation::auth-password-reset[snippets='request-headers']

==== 요청 본문 (JSON)

operation::auth-password-reset[snippets='http-request,request-fields']

==== 성공 응답

성공 시 `204 No Content` 상태 코드와 함께 빈 응답 본문을 반환합니다.

'''

=== 로그인

`POST /auth/login`
Expand Down
24 changes: 0 additions & 24 deletions src/docs/asciidoc/apis/member-api.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -153,30 +153,6 @@ operation::member-quest-property-read-error[snippets='http-response,response-fie

'''

=== 비밀번호 초기화 (찾기)

`PUT /members/passwords/reset`

이메일 인증 등을 통해 본인인증이 완료된 사용자가 비밀번호를 새로 설정합니다.

==== 요청 헤더

operation::member-password-reset[snippets='request-headers']

==== 요청 본문 (JSON)

operation::member-password-reset[snippets='http-request,request-fields']

==== 성공 응답

성공 시 `204 No Content` 상태 코드와 함께 빈 응답 본문을 반환합니다.

==== 에러 응답

operation::member-password-reset-error[snippets='http-response,response-fields']

'''

=== 핸들 수정

`PUT /members/handles`
Expand Down
4 changes: 2 additions & 2 deletions src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
= gomo api docs
= GOMO Docs - API
:doctype: book
:source-highlighter: highlightjs
:toc: left
Expand All @@ -15,7 +15,6 @@ include::apis/auth-api.adoc[]
`AUT-ROO-001`: Auth code is incorrect +
`AUT-ROO-002`: Refresh token not found +
`AUT-ROO-003`: Refresh token is incorrect +
`AUT-ROO-004`: OAuth member cannot login with password +
`AUT-ROO-005`: Principal already exists +
`AUT-ROO-006`: Principal not found +
`AUT-ROO-007`: Verified email token is incorrect +
Expand All @@ -30,6 +29,7 @@ include::apis/member-api.adoc[]
`MEM-ROO-001`: Member not found +
`MEM-ROO-002`: Access denied for the member +
`MEM-ROO-003`: Member Authentication fail +
`MEM-ROO-004`: OAuth member cannot login with password +

`MEM-EMA-001`: Email must not be blank +
`MEM-EMA-002`: Email must be at least 10 characters +
Expand Down
67 changes: 67 additions & 0 deletions src/docs/asciidoc/modulith-index.adoc
Original file line number Diff line number Diff line change
@@ -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[]
138 changes: 59 additions & 79 deletions src/main/java/com/gomo/app/batch/MemberCleanupScheduler.java
Original file line number Diff line number Diff line change
@@ -1,90 +1,70 @@
package com.gomo.app.batch;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.CompletableFuture;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.gomo.app.core.interest.domain.repository.InterestRelationRepository;
import com.gomo.app.core.interest.domain.repository.InterestRepository;
import com.gomo.app.core.interest.domain.repository.MajorInterestRepository;
import com.gomo.app.core.member.domain.model.Member;
import com.gomo.app.core.member.domain.repository.MemberRepository;
import com.gomo.app.core.point.domain.repository.PointRepository;
import com.gomo.app.core.point.domain.repository.PointWalletRepository;
import com.gomo.app.core.quest.domain.repository.AssignQuestRepository;
import com.gomo.app.core.quest.domain.repository.RepeatQuestRepository;
import com.gomo.app.core.streak.domain.repository.AchieverRepository;
import com.gomo.app.core.streak.domain.repository.StreakRepository;
import com.gomo.app.support.image.application.port.in.ImageDeleter;

import lombok.RequiredArgsConstructor;

@Component
@RequiredArgsConstructor
public class MemberCleanupScheduler {

private final ImageDeleter imageDeleter;
private final PointRepository pointRepository;
private final PointWalletRepository pointWalletRepository;
private final AssignQuestRepository assignQuestRepository;
private final RepeatQuestRepository repeatQuestRepository;
private final InterestRelationRepository interestRelationRepository;
private final MajorInterestRepository majorInterestRepository;
private final InterestRepository interestRepository;
private final StreakRepository streakRepository;
private final AchieverRepository achieverRepository;
private final MemberRepository memberRepository;

@Value("${app.members.retentionDays}")
private long retentionDays;

@Scheduled(cron = "0 0 2 * * *")
public void memberDataCleanUp() {
List<Member> deletedMembers = memberRepository.findByDeletedAtBefore(LocalDateTime.now().minusDays(retentionDays));

for (Member member : deletedMembers) {
cleanupMemberDataAsync(member);
}
}

@Async("memberCleanupExecutor")
public CompletableFuture<Void> cleanupMemberDataAsync(Member member) {
try {
deleteMemberAndRelatedData(member);
return CompletableFuture.completedFuture(null);
} catch (Exception e) {
return CompletableFuture.failedFuture(e);
}
}

private void deleteMemberAndRelatedData(Member member) {
// Quest 관련 데이터 삭제
assignQuestRepository.deleteAllByParticipantId(member.getId());
repeatQuestRepository.deleteAllByParticipantId(member.getId());

// Interest 관련 데이터 삭제
interestRelationRepository.deleteAllByRegistrantId(member.getId());
majorInterestRepository.deleteAllByRegistrantId(member.getId());
interestRepository.deleteAllByRegistrantId(member.getId());

// Point 관련 데이터 삭제
pointRepository.deleteAllByTransactorId(member.getId());
pointWalletRepository.deletePointWalletByTransactorId(member.getId());

// Streak 관련 데이터 삭제
streakRepository.deleteAllByAchieverId(member.getId());
achieverRepository.deleteByAchieverId(member.getId());

// 이미지 파일 삭제
imageDeleter.delete(member.profileImageUrl());
imageDeleter.delete(member.profileBannerUrl());

// member 최종 삭제
memberRepository.deleteById(member.getId());
}
// private final ImageDeleter imageDeleter;
// private final PointRepository pointRepository;
// private final PointWalletRepository pointWalletRepository;
// private final AssignQuestRepository assignQuestRepository;
// private final RepeatQuestRepository repeatQuestRepository;
// private final InterestRelationRepository interestRelationRepository;
// private final MajorInterestRepository majorInterestRepository;
// private final InterestRepository interestRepository;
// private final StreakRepository streakRepository;
// private final AchieverRepository achieverRepository;
// private final MemberRepository memberRepository;
//
// @Value("${app.members.retentionDays}")
// private long retentionDays;
//
// @Scheduled(cron = "0 0 2 * * *")
// public void memberDataCleanUp() {
// List<Member> deletedMembers = memberRepository.findByDeletedAtBefore(LocalDateTime.now().minusDays(retentionDays));
//
// for (Member member : deletedMembers) {
// cleanupMemberDataAsync(member);
// }
// }
//
// @Async("memberCleanupExecutor")
// public CompletableFuture<Void> 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());
// }
}
Original file line number Diff line number Diff line change
@@ -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 {
}
Original file line number Diff line number Diff line change
@@ -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 {
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.gomo.app.config;
package com.gomo.app.common.config;

import java.util.List;

Expand Down
Original file line number Diff line number Diff line change
@@ -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 {
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package com.gomo.app.core.quest.domain.event;
package com.gomo.app.common.event;

import java.time.LocalDateTime;
import java.util.UUID;

import com.gomo.app.common.event.Event;
import com.gomo.app.common.event.EventRouting;
import com.gomo.app.core.quest.domain.model.quest.QuestType;

import lombok.AccessLevel;
Expand Down
Loading