diff --git a/src/main/java/checkmo/authentication/AuthenticationEvent.java b/src/main/java/checkmo/authentication/AuthenticationEvent.java index 0be37ee9..01d615f3 100644 --- a/src/main/java/checkmo/authentication/AuthenticationEvent.java +++ b/src/main/java/checkmo/authentication/AuthenticationEvent.java @@ -1,11 +1,12 @@ package checkmo.authentication; +import java.util.List; import lombok.Builder; public class AuthenticationEvent { @Builder - public record CreateMember(String id, String email) { + public record CreateMember(String id, String email, List agreedTermsIds) { } @Builder diff --git a/src/main/java/checkmo/authentication/internal/service/command/AuthUserCommandService.java b/src/main/java/checkmo/authentication/internal/service/command/AuthUserCommandService.java index 1d8c0ea6..7995fc05 100644 --- a/src/main/java/checkmo/authentication/internal/service/command/AuthUserCommandService.java +++ b/src/main/java/checkmo/authentication/internal/service/command/AuthUserCommandService.java @@ -29,7 +29,6 @@ public class AuthUserCommandService { private final ApplicationEventPublisher eventPublisher; public AuthUser signUp(AuthRequestDTO.SignUp request) { - // TODO: Member 모듈의 API를 통해 필수 약관 동의 여부 체크 // 이메일 중복 확인 if (authRepository.existsByEmail(request.getEmail())) { @@ -54,7 +53,7 @@ public AuthUser signUp(AuthRequestDTO.SignUp request) { AuthenticationEvent.CreateMember.builder() .id(savedUser.getId()) .email(savedUser.getEmail()) - // TODO: 동의한 약관 ID 리스트 보냄 + .agreedTermsIds(request.getAgreedTermsIds()) .build()); return newUser; diff --git a/src/main/java/checkmo/authentication/web/dto/AuthRequestDTO.java b/src/main/java/checkmo/authentication/web/dto/AuthRequestDTO.java index f3b66b07..a12ffd68 100644 --- a/src/main/java/checkmo/authentication/web/dto/AuthRequestDTO.java +++ b/src/main/java/checkmo/authentication/web/dto/AuthRequestDTO.java @@ -3,8 +3,10 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Size; +import java.util.List; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -24,6 +26,9 @@ public static class SignUp { @Pattern(regexp = "^(?=.*[a-zA-Z])(?=.*[!@#$%^&*]).*$", message = "비밀번호는 영어 및 특수문자를 포함해야 합니다") @Schema(description = "비밀번호(영어+특수문자 포함 6~12자", example = "pass123!") private String password; + + @NotEmpty(message = "필수 약관 동의 정보가 필요합니다.") + private List agreedTermsIds; } @Getter diff --git a/src/main/java/checkmo/member/internal/exception/MemberErrorStatus.java b/src/main/java/checkmo/member/internal/exception/MemberErrorStatus.java index ef960c57..6ecc6c95 100644 --- a/src/main/java/checkmo/member/internal/exception/MemberErrorStatus.java +++ b/src/main/java/checkmo/member/internal/exception/MemberErrorStatus.java @@ -24,7 +24,11 @@ public enum MemberErrorStatus implements BaseErrorCode { MULTIPLE_ACCOUNTS_FOUND(HttpStatus.BAD_REQUEST, "MEMBER_409", "해당 정보로 가입된 계정이 여러 개입니다. 관리자에게 문의해주세요."), // 신고 - CANNOT_REPORT_SELF(HttpStatus.BAD_REQUEST, "REPORT_400", "자기 자신을 신고할 수 없습니다."); + CANNOT_REPORT_SELF(HttpStatus.BAD_REQUEST, "REPORT_400", "자기 자신을 신고할 수 없습니다."), + + // 약관 + TERMS_NOT_FOUND(HttpStatus.NOT_FOUND, "TERMS_400", "해당 약관을 찾을 수 없습니다."), + REQUIRED_TERMS_NOT_AGREE(HttpStatus.BAD_REQUEST, "TERMS_401", "필수 약관에 동의해야 회원가입이 가능합니다."); private final HttpStatus httpStatus; private final String code; diff --git a/src/main/java/checkmo/member/internal/listener/MemberEventListener.java b/src/main/java/checkmo/member/internal/listener/MemberEventListener.java index 56be06a2..ff0d8c9e 100644 --- a/src/main/java/checkmo/member/internal/listener/MemberEventListener.java +++ b/src/main/java/checkmo/member/internal/listener/MemberEventListener.java @@ -17,6 +17,6 @@ public class MemberEventListener { @EventListener @Transactional(propagation = Propagation.MANDATORY) public void createMember(AuthenticationEvent.CreateMember event) { - memberCommandService.createMember(event.id(), event.email()); + memberCommandService.createMember(event.id(), event.email(), event.agreedTermsIds()); } } diff --git a/src/main/java/checkmo/member/internal/repository/MemberTermsRepository.java b/src/main/java/checkmo/member/internal/repository/MemberTermsRepository.java new file mode 100644 index 00000000..f61fab47 --- /dev/null +++ b/src/main/java/checkmo/member/internal/repository/MemberTermsRepository.java @@ -0,0 +1,8 @@ +package checkmo.member.internal.repository; + +import checkmo.member.internal.entity.MemberTerms; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MemberTermsRepository extends JpaRepository { + +} diff --git a/src/main/java/checkmo/member/internal/repository/TermsRepository.java b/src/main/java/checkmo/member/internal/repository/TermsRepository.java new file mode 100644 index 00000000..6b1721d7 --- /dev/null +++ b/src/main/java/checkmo/member/internal/repository/TermsRepository.java @@ -0,0 +1,8 @@ +package checkmo.member.internal.repository; + +import checkmo.member.internal.entity.Terms; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface TermsRepository extends JpaRepository { + +} diff --git a/src/main/java/checkmo/member/internal/service/command/MemberCommandService.java b/src/main/java/checkmo/member/internal/service/command/MemberCommandService.java index 9feafbc2..8e5c2e0f 100644 --- a/src/main/java/checkmo/member/internal/service/command/MemberCommandService.java +++ b/src/main/java/checkmo/member/internal/service/command/MemberCommandService.java @@ -4,12 +4,17 @@ import checkmo.member.MemberEvent; import checkmo.member.internal.converter.MemberConverter; import checkmo.member.internal.entity.Member; +import checkmo.member.internal.entity.MemberTerms; +import checkmo.member.internal.entity.Terms; import checkmo.member.internal.exception.MemberErrorStatus; import checkmo.member.internal.exception.MemberException; import checkmo.member.internal.repository.MemberRepository; +import checkmo.member.internal.repository.MemberTermsRepository; +import checkmo.member.internal.repository.TermsRepository; import checkmo.member.web.dto.MemberRequestDTO; import checkmo.member.web.dto.MemberResponseDTO.DetailInfo; import java.util.HashSet; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; @@ -26,7 +31,13 @@ public class MemberCommandService { private final ApplicationEventPublisher eventPublisher; - public void createMember(String memberId, String email) { + private final MemberTermsRepository memberTermsRepository; + + private final TermsRepository termsRepository; + + public void createMember(String memberId, String email, List agreedTermsIds) { + validateRequiredTerms(agreedTermsIds); + Member member = Member.builder() .id(memberId) .email(email) @@ -39,7 +50,30 @@ public void createMember(String memberId, String email) { memberRepository.save(member); - // TODO: 여기서 약관 내역 DB에 저장 (멤버 생성 후) + // 여기서 약관 내역 DB에 저장 (멤버 생성 후) + for (Long termsId : agreedTermsIds) { + Terms terms = termsRepository.findById(termsId) + .orElseThrow(() -> new MemberException(MemberErrorStatus.TERMS_NOT_FOUND)); + + MemberTerms memberTerms = MemberTerms.builder() + .member(member) + .terms(terms) + .isAgreed(true) + .build(); + + memberTermsRepository.save(memberTerms); + } + } + + private void validateRequiredTerms(List agreedTermsIds) { + List requiredTermsIds = termsRepository.findAll().stream() + .filter(Terms::isRequired) + .map(Terms::getId) + .toList(); + + if (agreedTermsIds == null || !agreedTermsIds.containsAll(requiredTermsIds)) { + throw new MemberException(MemberErrorStatus.REQUIRED_TERMS_NOT_AGREE); + } } /** diff --git a/src/main/resources/db/migration/V20260211__insert_default_terms.sql b/src/main/resources/db/migration/V20260211__insert_default_terms.sql new file mode 100644 index 00000000..079f1587 --- /dev/null +++ b/src/main/resources/db/migration/V20260211__insert_default_terms.sql @@ -0,0 +1,4 @@ +INSERT INTO terms (id, term_url, is_required) VALUES + (1, 'https://www.notion.so/2cd7445c73f780dab5c5ccfbf5ce6101', true), -- 서비스 이용을 위한 필수 개인정보 수집 이용 동의(필수) + (2, 'https://www.notion.so/2cd7445c73f780e3a653ead96321331f', false), -- 마케팅 및 이벤트 정보 수신 동의 (선택) + (3, 'https://www.notion.so/3-2cd7445c73f7806f9b37f75eea6acb30', false); -- 개인정보 제3자 제공 동의(선택) \ No newline at end of file