diff --git a/src/main/java/org/sopt/seonyakServer/SeonyakServerApplication.java b/src/main/java/org/sopt/seonyakServer/SeonyakServerApplication.java index cd4ad2d..c602143 100644 --- a/src/main/java/org/sopt/seonyakServer/SeonyakServerApplication.java +++ b/src/main/java/org/sopt/seonyakServer/SeonyakServerApplication.java @@ -2,8 +2,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication +@EnableScheduling public class SeonyakServerApplication { public static void main(String[] args) { diff --git a/src/main/java/org/sopt/seonyakServer/domain/member/repository/MemberRepository.java b/src/main/java/org/sopt/seonyakServer/domain/member/repository/MemberRepository.java index faf0c70..5781d45 100644 --- a/src/main/java/org/sopt/seonyakServer/domain/member/repository/MemberRepository.java +++ b/src/main/java/org/sopt/seonyakServer/domain/member/repository/MemberRepository.java @@ -1,5 +1,6 @@ package org.sopt.seonyakServer.domain.member.repository; +import java.time.LocalDateTime; import java.util.Optional; import org.sopt.seonyakServer.domain.member.model.Member; import org.sopt.seonyakServer.domain.member.model.SocialType; @@ -21,4 +22,7 @@ default Member findMemberByIdOrThrow(Long id) { return findMemberById(id) .orElseThrow(() -> new CustomException(ErrorType.NOT_FOUND_MEMBER_ERROR)); } + + // phoneNumber가 null이고 updatedAt 시간이 time만큼 보다 더 이전인 모든 Member 엔티티를 삭제 + void deleteByPhoneNumberIsNullAndUpdatedAtBefore(LocalDateTime time); } diff --git a/src/main/java/org/sopt/seonyakServer/domain/member/service/MemberService.java b/src/main/java/org/sopt/seonyakServer/domain/member/service/MemberService.java index 6a17345..0062fb3 100644 --- a/src/main/java/org/sopt/seonyakServer/domain/member/service/MemberService.java +++ b/src/main/java/org/sopt/seonyakServer/domain/member/service/MemberService.java @@ -1,6 +1,7 @@ package org.sopt.seonyakServer.domain.member.service; import jakarta.annotation.PostConstruct; +import java.time.LocalDateTime; import java.util.Random; import lombok.RequiredArgsConstructor; import net.nurigo.sdk.NurigoApp; @@ -28,6 +29,7 @@ import org.sopt.seonyakServer.global.exception.model.CustomException; import org.springframework.beans.factory.annotation.Value; import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -61,6 +63,7 @@ public void init() { } // JWT Access Token 생성 + @Transactional public LoginSuccessResponse create( final String authorizationCode, final MemberLoginRequest loginRequest @@ -71,7 +74,7 @@ public LoginSuccessResponse create( } // 소셜 플랫폼으로부터 해당 유저 정보를 받아옴 - public MemberInfoResponse getMemberInfoResponse( + private MemberInfoResponse getMemberInfoResponse( final String authorizationCode, final MemberLoginRequest loginRequest ) { @@ -104,14 +107,14 @@ private LoginSuccessResponse getTokenDto(final MemberInfoResponse memberInfoResp } } - public boolean isExistingMember( + private boolean isExistingMember( final SocialType socialType, final String socialId ) { return memberRepository.findBySocialTypeAndSocialId(socialType, socialId).isPresent(); } - public Long getMemberIdBySocialId( + private Long getMemberIdBySocialId( final SocialType socialType, final String socialId ) { @@ -122,13 +125,14 @@ public Long getMemberIdBySocialId( return member.getId(); } - public LoginSuccessResponse getTokenByMemberId(final Long id) { + private LoginSuccessResponse getTokenByMemberId(final Long id) { MemberAuthentication memberAuthentication = new MemberAuthentication(id, null, null); return LoginSuccessResponse.of(jwtTokenProvider.issueAccessToken(memberAuthentication)); } // 닉네임 유효성 검증 + @Transactional(readOnly = true) public void validNickname(final NicknameRequest nicknameRequest) { if (!nicknameRequest.nickname().matches(NICKNAME_PATTERN)) { // 형식 체크 throw new CustomException(ErrorType.INVALID_NICKNAME_ERROR); @@ -166,6 +170,7 @@ public MemberJoinResponse patchMemberJoin(MemberJoinRequest memberJoinRequest) { ); } + @Transactional public void sendMessage(SendCodeRequest sendCodeRequest) { Message message = new Message(); @@ -196,6 +201,7 @@ private String generateRandomNumber(int digitCount) { } // 인증번호 일치 여부 확인 + @Transactional public void verifyCode(VerifyCodeRequest verifyCodeRequest) { String number = verifyCodeRequest.phoneNumber().replaceAll("-", ""); @@ -214,4 +220,11 @@ private void validPhoneNumberDuplication(String phoneNumber) { throw new CustomException(ErrorType.PHONE_NUMBER_DUP_ERROR); } } + + @Scheduled(fixedRate = 43200000) // 12시간마다 실행 (43200000 밀리초) + @Transactional + public void deleteMembersWithNullPhoneNumber() { + LocalDateTime oneHourAgo = LocalDateTime.now().minusMinutes(60); + memberRepository.deleteByPhoneNumberIsNullAndUpdatedAtBefore(oneHourAgo); + } } diff --git a/src/main/java/org/sopt/seonyakServer/global/auth/redis/service/CodeService.java b/src/main/java/org/sopt/seonyakServer/global/auth/redis/service/CodeService.java index dcf8ae8..174cd31 100644 --- a/src/main/java/org/sopt/seonyakServer/global/auth/redis/service/CodeService.java +++ b/src/main/java/org/sopt/seonyakServer/global/auth/redis/service/CodeService.java @@ -14,7 +14,6 @@ public class CodeService { private final CodeRepository codeRepository; - @Transactional public void saveVerificationCode( final String phoneNumber, final String verificationCode @@ -27,7 +26,6 @@ public void saveVerificationCode( ); } - @Transactional(readOnly = true) public String findCodeByPhoneNumber(final String phoneNumber) { Code code = codeRepository.findByPhoneNumber(phoneNumber).orElseThrow( () -> new CustomException(ErrorType.NO_VERIFICATION_REQUEST_HISTORY)