From b09b73f62740905a4fc144ab394ba94716f57f84 Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Sun, 8 Nov 2026 22:15:24 +0900 Subject: [PATCH 01/10] =?UTF-8?q?feat:=20MemberRepository=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framey/member/domain/repository/MemberRepository.java | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 framey-application/member-service/src/main/java/framey/member/domain/repository/MemberRepository.java diff --git a/framey-application/member-service/src/main/java/framey/member/domain/repository/MemberRepository.java b/framey-application/member-service/src/main/java/framey/member/domain/repository/MemberRepository.java new file mode 100644 index 0000000..b57ba32 --- /dev/null +++ b/framey-application/member-service/src/main/java/framey/member/domain/repository/MemberRepository.java @@ -0,0 +1,8 @@ +package framey.member.domain.repository; + +import framey.member.domain.model.Member; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MemberRepository extends JpaRepository { + boolean existsByNickname(String nickname); +} From 90a35e6c76ee7a7848718384acd6739437286974 Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Sun, 8 Nov 2026 22:24:14 +0900 Subject: [PATCH 02/10] =?UTF-8?q?feat:=20MemberService=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/application/service/MemberService.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 framey-application/member-service/src/main/java/framey/member/application/service/MemberService.java diff --git a/framey-application/member-service/src/main/java/framey/member/application/service/MemberService.java b/framey-application/member-service/src/main/java/framey/member/application/service/MemberService.java new file mode 100644 index 0000000..fb6127b --- /dev/null +++ b/framey-application/member-service/src/main/java/framey/member/application/service/MemberService.java @@ -0,0 +1,13 @@ +package framey.member.application.service; + +import framey.member.domain.repository.MemberRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class MemberService { + private final MemberRepository memberRepository; +} From 4ee39ba8ab49168103f050ed4ab772622bfe07ae Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Mon, 9 Nov 2026 10:58:52 +0900 Subject: [PATCH 03/10] =?UTF-8?q?feat:=20=EC=84=9C=EB=B9=84=EC=8A=A4=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=EC=97=90=20nickname=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/application/dto/CreateMember.java | 17 ++++++++ .../application/service/MemberService.java | 39 +++++++++++++++++++ .../domain/constant/NicknameConstant.java | 1 + .../domain/exception/MemberErrorCode.java | 3 +- .../domain/model/NicknameGenerator.java | 1 - .../domain/repository/MemberRepository.java | 2 +- 6 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 framey-application/member-service/src/main/java/framey/member/application/dto/CreateMember.java diff --git a/framey-application/member-service/src/main/java/framey/member/application/dto/CreateMember.java b/framey-application/member-service/src/main/java/framey/member/application/dto/CreateMember.java new file mode 100644 index 0000000..e82f600 --- /dev/null +++ b/framey-application/member-service/src/main/java/framey/member/application/dto/CreateMember.java @@ -0,0 +1,17 @@ +package framey.member.application.dto; + +import framey.member.domain.model.Member; + +public record CreateMember( + String nickname, + String email, + String profileImageUrl +) { + public static CreateMember from(final Member member) { + return new CreateMember( + member.getNickname(), + member.getEmail(), + member.getProfileImageUrl() + ); + } +} diff --git a/framey-application/member-service/src/main/java/framey/member/application/service/MemberService.java b/framey-application/member-service/src/main/java/framey/member/application/service/MemberService.java index fb6127b..390e2d5 100644 --- a/framey-application/member-service/src/main/java/framey/member/application/service/MemberService.java +++ b/framey-application/member-service/src/main/java/framey/member/application/service/MemberService.java @@ -1,5 +1,12 @@ package framey.member.application.service; +import framey.common.exception.BusinessException; +import framey.member.application.dto.CreateMember; +import framey.member.domain.constant.NicknameConstant; +import framey.member.domain.constant.Provider; +import framey.member.domain.exception.MemberErrorCode; +import framey.member.domain.model.Member; +import framey.member.domain.model.NicknameGenerator; import framey.member.domain.repository.MemberRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -10,4 +17,36 @@ @Transactional(readOnly = true) public class MemberService { private final MemberRepository memberRepository; + + @Transactional + public Member createMember(CreateMember createMember) { + // TODO: provider 및 providerId 검증 + Member member = Member.signUp( + createMember.email(), + resolveNickname(createMember.nickname()), + createMember.profileImageUrl(), + "123", // TODO: 임시 providerId + Provider.GOOGLE // TODO: 임시 provider + ); + + return memberRepository.save(member); + } + + private String resolveNickname(String nickname) { + String baseNickname = NicknameGenerator.normalize(nickname); + + if (!baseNickname.equals(NicknameConstant.BASE_NICKNAME) && !memberRepository.existsByNickname(baseNickname)) { + return baseNickname; + } + + for (int i = 0; i < NicknameConstant.MAX_RETRY_COUNT; i++) { + String generatedNickname = NicknameGenerator.appendSuffix(baseNickname); + + if (!memberRepository.existsByNickname(generatedNickname)) { + return generatedNickname; + } + } + + throw new BusinessException(MemberErrorCode.NICKNAME_GENERATION_FAILED); + } } diff --git a/framey-application/member-service/src/main/java/framey/member/domain/constant/NicknameConstant.java b/framey-application/member-service/src/main/java/framey/member/domain/constant/NicknameConstant.java index e397788..67c2be2 100644 --- a/framey-application/member-service/src/main/java/framey/member/domain/constant/NicknameConstant.java +++ b/framey-application/member-service/src/main/java/framey/member/domain/constant/NicknameConstant.java @@ -13,4 +13,5 @@ public final class NicknameConstant { ); public static final String BASE_NICKNAME = "framey"; public static final int SUFFIX_DIGITS = 4; + public static final int MAX_RETRY_COUNT = 5; } diff --git a/framey-application/member-service/src/main/java/framey/member/domain/exception/MemberErrorCode.java b/framey-application/member-service/src/main/java/framey/member/domain/exception/MemberErrorCode.java index af570d8..3a85999 100644 --- a/framey-application/member-service/src/main/java/framey/member/domain/exception/MemberErrorCode.java +++ b/framey-application/member-service/src/main/java/framey/member/domain/exception/MemberErrorCode.java @@ -9,7 +9,8 @@ @RequiredArgsConstructor public enum MemberErrorCode implements ErrorCode { NICKNAME_REQUIRED("MB-001", "닉네임을 입력해 주세요.", HttpStatus.BAD_REQUEST), - MAX_NICKNAME_LENGTH("MB-002", "닉네임은 10자 이내로 입력해 주세요.", HttpStatus.BAD_REQUEST); + MAX_NICKNAME_LENGTH("MB-002", "닉네임은 10자 이내로 입력해 주세요.", HttpStatus.BAD_REQUEST), + NICKNAME_GENERATION_FAILED("MB-003", "닉네임 생성에 실패했습니다. 다시 시도해 주세요.", HttpStatus.INTERNAL_SERVER_ERROR); private final String value; private final String message; diff --git a/framey-application/member-service/src/main/java/framey/member/domain/model/NicknameGenerator.java b/framey-application/member-service/src/main/java/framey/member/domain/model/NicknameGenerator.java index cc20430..634932a 100644 --- a/framey-application/member-service/src/main/java/framey/member/domain/model/NicknameGenerator.java +++ b/framey-application/member-service/src/main/java/framey/member/domain/model/NicknameGenerator.java @@ -3,7 +3,6 @@ import lombok.AccessLevel; import lombok.NoArgsConstructor; -import java.util.Random; import java.util.concurrent.ThreadLocalRandom; import static framey.member.domain.constant.NicknameConstant.BASE_NICKNAME; diff --git a/framey-application/member-service/src/main/java/framey/member/domain/repository/MemberRepository.java b/framey-application/member-service/src/main/java/framey/member/domain/repository/MemberRepository.java index b57ba32..b26cf60 100644 --- a/framey-application/member-service/src/main/java/framey/member/domain/repository/MemberRepository.java +++ b/framey-application/member-service/src/main/java/framey/member/domain/repository/MemberRepository.java @@ -3,6 +3,6 @@ import framey.member.domain.model.Member; import org.springframework.data.jpa.repository.JpaRepository; -public interface MemberRepository extends JpaRepository { +public interface MemberRepository extends JpaRepository { boolean existsByNickname(String nickname); } From 3423e369de179bcb5dc3b2acb4101e93329c5ae5 Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Mon, 9 Nov 2026 11:05:09 +0900 Subject: [PATCH 04/10] =?UTF-8?q?docs:=20=ED=8A=B8=EB=9E=9C=EC=9E=AD?= =?UTF-8?q?=EC=85=98=20=EC=9E=AC=EC=8B=9C=EB=8F=84=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?TODO=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/framey/member/application/service/MemberService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/framey-application/member-service/src/main/java/framey/member/application/service/MemberService.java b/framey-application/member-service/src/main/java/framey/member/application/service/MemberService.java index 390e2d5..443ff16 100644 --- a/framey-application/member-service/src/main/java/framey/member/application/service/MemberService.java +++ b/framey-application/member-service/src/main/java/framey/member/application/service/MemberService.java @@ -20,7 +20,8 @@ public class MemberService { @Transactional public Member createMember(CreateMember createMember) { - // TODO: provider 및 providerId 검증 + // TODO: 추후 AuthService와 같은 createMember를 처리하는 쪽에서 Transaction 재시도 로직 추가 + Member member = Member.signUp( createMember.email(), resolveNickname(createMember.nickname()), From 40fc767d41a8c6c685c847a6801e0d3ac0d069c7 Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Mon, 9 Nov 2026 14:53:33 +0900 Subject: [PATCH 05/10] =?UTF-8?q?test:=20MemberService=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/MemberServiceTest.java | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 framey-application/member-service/src/test/java/framey/member/application/service/MemberServiceTest.java diff --git a/framey-application/member-service/src/test/java/framey/member/application/service/MemberServiceTest.java b/framey-application/member-service/src/test/java/framey/member/application/service/MemberServiceTest.java new file mode 100644 index 0000000..b27db03 --- /dev/null +++ b/framey-application/member-service/src/test/java/framey/member/application/service/MemberServiceTest.java @@ -0,0 +1,117 @@ +package framey.member.application.service; + +import framey.common.exception.BusinessException; +import framey.member.application.dto.CreateMember; +import framey.member.domain.constant.NicknameConstant; +import framey.member.domain.exception.MemberErrorCode; +import framey.member.domain.model.Member; +import framey.member.domain.repository.MemberRepository; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.then; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; + +@ExtendWith(MockitoExtension.class) +class MemberServiceTest { + @Mock + private MemberRepository memberRepository; + + @InjectMocks + private MemberService memberService; + + @Test + @DisplayName("소셜 닉네임이 사용 중이 아니면 해당 닉네임을 그대로 사용한다") + void useSocialNicknameWhenNotDuplicated() { + given(memberRepository.existsByNickname("프레이미")).willReturn(false); + given(memberRepository.save(any(Member.class))).willAnswer(inv -> inv.getArgument(0)); + + CreateMember member = new CreateMember("프레이미", "framey@exam.com", ""); + + Member newMember = memberService.createMember(member); + + Assertions.assertThat(newMember.getNickname()).isEqualTo("프레이미"); + } + + @Test + @DisplayName("소셜 닉네임이 사용 중이라면, 기존 닉네임 뒤에 10자리를 맞춰 임의 숫자를 넣어 사용한다") + void useAppendSuffixNicknameWhenDuplicated() { + given(memberRepository.existsByNickname("프레이미")).willReturn(true); + given(memberRepository.save(any(Member.class))).willAnswer(inv -> inv.getArgument(0)); + + CreateMember member = new CreateMember("프레이미", "framey@exam.com", ""); + + Member newMember = memberService.createMember(member); + + Assertions.assertThat(newMember.getNickname()).matches("^프레이미\\d{6}"); + } + + @Test + @DisplayName("소셜 닉네임이 기본 닉네임과 같으면 뒤에 임의 숫자를 붙인다") + void appendSuffixWhenNicknameEqualsBaseNickname() { + given(memberRepository.save(any(Member.class))).willAnswer(inv -> inv.getArgument(0)); + + CreateMember member = new CreateMember("framey", "framey@exam.com", ""); + + Member newMember = memberService.createMember(member); + + Assertions.assertThat(newMember.getNickname()).matches("^framey\\d{4}"); + then(memberRepository).should(never()).existsByNickname("framey"); + } + + @ParameterizedTest + @ValueSource(strings = {" ", "\u3000", "\u00A0"}) + @NullAndEmptySource + @DisplayName("소셜 닉네임이 없으면 기본 닉네임에 임의 숫자를 붙인다") + void useBaseNicknameWithSuffixWhenNicknameIsBlank(String nickname) { + given(memberRepository.save(any(Member.class))).willAnswer(inv -> inv.getArgument(0)); + CreateMember member = new CreateMember(nickname, "framey@exam.com", ""); + + Member newMember = memberService.createMember(member); + + Assertions.assertThat(newMember.getNickname()).matches("^framey\\d{4}"); + then(memberRepository).should(never()).existsByNickname("framey"); + } + + @Test + @DisplayName("임의 숫자를 붙인 닉네임도 모두 사용 중이면 닉네임 생성에 실패한다") + void failWhenAllGeneratedNicknamesAreDuplicated() { + given(memberRepository.existsByNickname(anyString())).willReturn(true); + + CreateMember member = new CreateMember("프레이미", "framey@exam.com", ""); + + Assertions.assertThatThrownBy(() -> memberService.createMember(member)) + .isInstanceOf(BusinessException.class) + .extracting("errorCode") + .isEqualTo(MemberErrorCode.NICKNAME_GENERATION_FAILED); + + then(memberRepository).should(never()).save(any()); + then(memberRepository).should(times(1 + NicknameConstant.MAX_RETRY_COUNT)).existsByNickname(anyString()); + } + + @Test + @DisplayName("임의 숫자를 붙인 닉네임도 사용 중이라면 새 숫자를 붙여 다시 시도한다") + void retryWithNewSuffixWhenGeneratedNicknameIsDuplicated() { + given(memberRepository.existsByNickname(anyString())).willReturn(true, true, false); + given(memberRepository.save(any(Member.class))).willAnswer(inv -> inv.getArgument(0)); + + CreateMember member = new CreateMember("프레이미", "framey@exam.com", ""); + + Member newMember = memberService.createMember(member); + + Assertions.assertThat(newMember.getNickname()).matches("^프레이미\\d{6}"); + then(memberRepository).should(times(3)).existsByNickname(anyString()); + } +} From 55723e52d4c4930036064cf86abc9b518d34b366 Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Mon, 9 Nov 2026 17:43:19 +0900 Subject: [PATCH 06/10] =?UTF-8?q?test:=20NicknameGenertator=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EB=B3=B4=EC=99=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/NicknameGeneratorTest.java | 59 ++++++++++++++++++- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/framey-application/member-service/src/test/java/framey/member/domain/member/NicknameGeneratorTest.java b/framey-application/member-service/src/test/java/framey/member/domain/member/NicknameGeneratorTest.java index af8052f..d9c16a3 100644 --- a/framey-application/member-service/src/test/java/framey/member/domain/member/NicknameGeneratorTest.java +++ b/framey-application/member-service/src/test/java/framey/member/domain/member/NicknameGeneratorTest.java @@ -2,6 +2,7 @@ import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.NullAndEmptySource; import org.junit.jupiter.params.provider.ValueSource; @@ -17,18 +18,70 @@ class NicknameGeneratorTest { void useDefaultNicknameWhenNicknameIsBlank(String nickname) { String generatedNickname = appendSuffix(normalize(nickname)); - Assertions.assertThat(generatedNickname).isNotBlank(); Assertions.assertThat(generatedNickname).matches("^framey\\d{4}$"); } @ParameterizedTest @ValueSource(strings = { " 프레이미 ", " 프레이미", "프레이미 ", "\u3000프레이미\u3000"}) - @DisplayName("닉네임의 공백을 제거한다.") + @DisplayName("닉네임의 앞 뒤 공백을 제거한다.") void stripsNicknameWhiteSpaces(String nickname) { String generatedNickname = normalize(nickname); - Assertions.assertThat(generatedNickname).isNotBlank(); Assertions.assertThat(generatedNickname).isEqualTo("프레이미"); } + @Test + @DisplayName("닉네임이 10자를 넘어가면 10자에 맞게 자른다") + void truncateNicknameWhenLengthOver10() { + String nickname = "가나다라마바사아자차카타파"; + String generatedNickname = normalize(nickname); + + Assertions.assertThat(generatedNickname.codePointCount(0, generatedNickname.length())).isEqualTo(10); + } + + @Test + @DisplayName("중복 방지용 임의 숫자를 붙일 때, 닉네임이 길면 앞부분을 잘라 최소 4자리를 확보한다") + void truncateBaseToKeepMinimumSuffixDigits() { + String nickname = "가나다라마바사아자차"; + String result = appendSuffix(normalize(nickname)); + + Assertions.assertThat(result).matches("^가나다라마바\\d{4}"); + } + + @Test + @DisplayName("짧은 닉네임은 전체 10자가 되도록 숫자를 채운다") + void fillSuffixToMaxLengthWhenBaseIsShort() { + String nickname = "가나"; + String result = appendSuffix(normalize(nickname)); + + Assertions.assertThat(result).matches("^가나\\d{8}"); + } + + @Test + @DisplayName("이모지가 포함된 닉네임은 깨지지 않도록 코드 포인트 기준으로 10자까지 자른다") + void truncateNicknameByCodePoint() { + String nickname = "🙂🙂🙂🙂🙂🙂🙂🙂🙂🙂🙂"; + String result = normalize(nickname); + + Assertions.assertThat(result).isEqualTo("🙂🙂🙂🙂🙂🙂🙂🙂🙂🙂"); + Assertions.assertThat(result.codePointCount(0, result.length())).isEqualTo(10); + } + + @Test + @DisplayName("이모지 닉네임에 숫자를 붙일 때 깨지지 않도록 앞부분을 자른다") + void truncateEmojiBaseByCodePointWhenAppendingSuffix() { + String nickname = "🙂🙂🙂🙂🙂🙂🙂🙂🙂🙂"; + String result = appendSuffix(normalize(nickname)); + + Assertions.assertThat(result).matches("^🙂🙂🙂🙂🙂🙂\\d{4}"); + } + + @Test + @DisplayName("닉네임 중간의 공백은 제거하지 않는다") + void keepWhitespaceInsideNickname() { + String nickname = "프 레 이 미"; + String result = normalize(nickname); + + Assertions.assertThat(result).isEqualTo("프 레 이 미"); + } } From e661fdd8e47f3350640f41744f718f7e1f543c1b Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Mon, 9 Nov 2026 17:44:31 +0900 Subject: [PATCH 07/10] =?UTF-8?q?refactor:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=BD=94=EB=93=9C=20=ED=8F=B4=EB=8D=94=EB=A7=81=20=EB=A7=9E?= =?UTF-8?q?=EC=B6=94=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framey/member/domain/{ => model}/member/MemberTest.java | 2 +- .../member/domain/{ => model}/member/NicknameGeneratorTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename framey-application/member-service/src/test/java/framey/member/domain/{ => model}/member/MemberTest.java (98%) rename framey-application/member-service/src/test/java/framey/member/domain/{ => model}/member/NicknameGeneratorTest.java (98%) diff --git a/framey-application/member-service/src/test/java/framey/member/domain/member/MemberTest.java b/framey-application/member-service/src/test/java/framey/member/domain/model/member/MemberTest.java similarity index 98% rename from framey-application/member-service/src/test/java/framey/member/domain/member/MemberTest.java rename to framey-application/member-service/src/test/java/framey/member/domain/model/member/MemberTest.java index 64ae982..8dbb709 100644 --- a/framey-application/member-service/src/test/java/framey/member/domain/member/MemberTest.java +++ b/framey-application/member-service/src/test/java/framey/member/domain/model/member/MemberTest.java @@ -1,4 +1,4 @@ -package framey.member.domain.member; +package framey.member.domain.model.member; import framey.common.exception.BusinessException; import framey.member.domain.constant.Provider; diff --git a/framey-application/member-service/src/test/java/framey/member/domain/member/NicknameGeneratorTest.java b/framey-application/member-service/src/test/java/framey/member/domain/model/member/NicknameGeneratorTest.java similarity index 98% rename from framey-application/member-service/src/test/java/framey/member/domain/member/NicknameGeneratorTest.java rename to framey-application/member-service/src/test/java/framey/member/domain/model/member/NicknameGeneratorTest.java index d9c16a3..6a2e81d 100644 --- a/framey-application/member-service/src/test/java/framey/member/domain/member/NicknameGeneratorTest.java +++ b/framey-application/member-service/src/test/java/framey/member/domain/model/member/NicknameGeneratorTest.java @@ -1,4 +1,4 @@ -package framey.member.domain.member; +package framey.member.domain.model.member; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; From 7a53e7268488040b1869ef3705339b9bff0c69d8 Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Tue, 10 Nov 2026 10:46:29 +0900 Subject: [PATCH 08/10] =?UTF-8?q?chore:=20=EC=9E=84=EC=8B=9C=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=ED=95=84=20=EA=B8=B0=EB=B3=B8=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application-dev.yaml | 3 +++ .../src/main/resources/application.yaml | 2 ++ .../static/assets/default-profile-image.png | Bin 0 -> 11391 bytes 3 files changed, 5 insertions(+) create mode 100644 framey-application/member-service/src/main/resources/static/assets/default-profile-image.png diff --git a/framey-application/member-service/src/main/resources/application-dev.yaml b/framey-application/member-service/src/main/resources/application-dev.yaml index e6eaa41..4e07fc7 100644 --- a/framey-application/member-service/src/main/resources/application-dev.yaml +++ b/framey-application/member-service/src/main/resources/application-dev.yaml @@ -31,3 +31,6 @@ management: health: probes: enabled: true + +member: + default-profile-image-url: http://dev-swagger.framey.kr/assets/default-profile-image.png diff --git a/framey-application/member-service/src/main/resources/application.yaml b/framey-application/member-service/src/main/resources/application.yaml index 383a600..3b42f4a 100644 --- a/framey-application/member-service/src/main/resources/application.yaml +++ b/framey-application/member-service/src/main/resources/application.yaml @@ -9,3 +9,5 @@ server: springdoc: api-docs: enabled: true +member: + default-profile-image-url: http://localhost:8081/assets/default-profile-image.png diff --git a/framey-application/member-service/src/main/resources/static/assets/default-profile-image.png b/framey-application/member-service/src/main/resources/static/assets/default-profile-image.png new file mode 100644 index 0000000000000000000000000000000000000000..bcddb9641cce43869b8da58b0b70bd1a34bd9f56 GIT binary patch literal 11391 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 BRA&GH literal 0 HcmV?d00001 From 5bec1910f31dc6f5ee9ba27f434e1c6b66f490a4 Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Tue, 10 Nov 2026 11:13:05 +0900 Subject: [PATCH 09/10] =?UTF-8?q?feat:=20=EA=B8=B0=EB=B3=B8=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=ED=95=84=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/service/MemberService.java | 12 +++++- .../member/config/MemberProperties.java | 7 ++++ .../src/main/resources/application-dev.yaml | 2 +- .../service/MemberServiceTest.java | 39 ++++++++++++++++++- 4 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 framey-application/member-service/src/main/java/framey/member/config/MemberProperties.java diff --git a/framey-application/member-service/src/main/java/framey/member/application/service/MemberService.java b/framey-application/member-service/src/main/java/framey/member/application/service/MemberService.java index 443ff16..da25d4a 100644 --- a/framey-application/member-service/src/main/java/framey/member/application/service/MemberService.java +++ b/framey-application/member-service/src/main/java/framey/member/application/service/MemberService.java @@ -2,6 +2,7 @@ import framey.common.exception.BusinessException; import framey.member.application.dto.CreateMember; +import framey.member.config.MemberProperties; import framey.member.domain.constant.NicknameConstant; import framey.member.domain.constant.Provider; import framey.member.domain.exception.MemberErrorCode; @@ -17,6 +18,7 @@ @Transactional(readOnly = true) public class MemberService { private final MemberRepository memberRepository; + private final MemberProperties memberProperties; @Transactional public Member createMember(CreateMember createMember) { @@ -25,7 +27,7 @@ public Member createMember(CreateMember createMember) { Member member = Member.signUp( createMember.email(), resolveNickname(createMember.nickname()), - createMember.profileImageUrl(), + resolveProfileImageUrl(createMember.profileImageUrl()), "123", // TODO: 임시 providerId Provider.GOOGLE // TODO: 임시 provider ); @@ -50,4 +52,12 @@ private String resolveNickname(String nickname) { throw new BusinessException(MemberErrorCode.NICKNAME_GENERATION_FAILED); } + + private String resolveProfileImageUrl(String profileImageUrl) { + if (profileImageUrl == null || profileImageUrl.isBlank()) { + return memberProperties.defaultProfileImageUrl(); + } + + return profileImageUrl; + } } diff --git a/framey-application/member-service/src/main/java/framey/member/config/MemberProperties.java b/framey-application/member-service/src/main/java/framey/member/config/MemberProperties.java new file mode 100644 index 0000000..a4faf71 --- /dev/null +++ b/framey-application/member-service/src/main/java/framey/member/config/MemberProperties.java @@ -0,0 +1,7 @@ +package framey.member.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties(prefix = "member") +public record MemberProperties(String defaultProfileImageUrl) { +} diff --git a/framey-application/member-service/src/main/resources/application-dev.yaml b/framey-application/member-service/src/main/resources/application-dev.yaml index 4e07fc7..05df9c2 100644 --- a/framey-application/member-service/src/main/resources/application-dev.yaml +++ b/framey-application/member-service/src/main/resources/application-dev.yaml @@ -33,4 +33,4 @@ management: enabled: true member: - default-profile-image-url: http://dev-swagger.framey.kr/assets/default-profile-image.png + default-profile-image-url: https://dev-swagger.framey.kr/assets/default-profile-image.png diff --git a/framey-application/member-service/src/test/java/framey/member/application/service/MemberServiceTest.java b/framey-application/member-service/src/test/java/framey/member/application/service/MemberServiceTest.java index b27db03..14cdd31 100644 --- a/framey-application/member-service/src/test/java/framey/member/application/service/MemberServiceTest.java +++ b/framey-application/member-service/src/test/java/framey/member/application/service/MemberServiceTest.java @@ -2,18 +2,19 @@ import framey.common.exception.BusinessException; import framey.member.application.dto.CreateMember; +import framey.member.config.MemberProperties; import framey.member.domain.constant.NicknameConstant; import framey.member.domain.exception.MemberErrorCode; import framey.member.domain.model.Member; import framey.member.domain.repository.MemberRepository; import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.NullAndEmptySource; import org.junit.jupiter.params.provider.ValueSource; -import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @@ -26,12 +27,18 @@ @ExtendWith(MockitoExtension.class) class MemberServiceTest { + private static final String DEFAULT_PROFILE_IMAGE_URL = "https://test.framey/default-profile-image.png"; + @Mock private MemberRepository memberRepository; - @InjectMocks private MemberService memberService; + @BeforeEach + void setUp() { + memberService = new MemberService(memberRepository, new MemberProperties(DEFAULT_PROFILE_IMAGE_URL)); + } + @Test @DisplayName("소셜 닉네임이 사용 중이 아니면 해당 닉네임을 그대로 사용한다") void useSocialNicknameWhenNotDuplicated() { @@ -114,4 +121,32 @@ void retryWithNewSuffixWhenGeneratedNicknameIsDuplicated() { Assertions.assertThat(newMember.getNickname()).matches("^프레이미\\d{6}"); then(memberRepository).should(times(3)).existsByNickname(anyString()); } + + @ParameterizedTest + @ValueSource(strings = " ") + @NullAndEmptySource + @DisplayName("프로필 이미지가 없으면 기본 프로필 이미지를 사용한다") + void useDefaultProfileImageWhenProfileImageIsBlank(String profileImageUrl) { + given(memberRepository.save(any(Member.class))).willAnswer(inv -> inv.getArgument(0)); + + CreateMember member = new CreateMember("프레이미", "framey@exam.com", profileImageUrl); + + Member newMember = memberService.createMember(member); + + Assertions.assertThat(newMember.getProfileImageUrl()).isEqualTo(DEFAULT_PROFILE_IMAGE_URL); + } + + @Test + @DisplayName("프로필 이미지가 있으면 그대로 사용한다") + void useSocialProfileImageWhenPresent() { + given(memberRepository.save(any(Member.class))).willAnswer(inv -> inv.getArgument(0)); + + String profileImageUrl = "https://test.framey/profile.png"; + + CreateMember member = new CreateMember("프레이미", "framey@exam.com", profileImageUrl); + + Member newMember = memberService.createMember(member); + + Assertions.assertThat(newMember.getProfileImageUrl()).isEqualTo(profileImageUrl); + } } From 4b6b2f093a9edfb552d0200ee147705131ad5db7 Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Tue, 10 Nov 2026 11:32:23 +0900 Subject: [PATCH 10/10] =?UTF-8?q?chore:=20Member=20=EA=B8=B0=EB=B3=B8=20?= =?UTF-8?q?=ED=94=84=EB=A1=9C=ED=95=84=20=EA=B2=BD=EB=A1=9C=20=ED=94=84?= =?UTF-8?q?=EB=A1=9D=EC=8B=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application-dev.yaml | 2 +- .../src/main/resources/application.yaml | 2 +- .../assets/{ => members}/default-profile-image.png | Bin framey-infrastructure/nginx/dev/default.conf | 10 ++++++++++ 4 files changed, 12 insertions(+), 2 deletions(-) rename framey-application/member-service/src/main/resources/static/assets/{ => members}/default-profile-image.png (100%) diff --git a/framey-application/member-service/src/main/resources/application-dev.yaml b/framey-application/member-service/src/main/resources/application-dev.yaml index 05df9c2..091fa2d 100644 --- a/framey-application/member-service/src/main/resources/application-dev.yaml +++ b/framey-application/member-service/src/main/resources/application-dev.yaml @@ -33,4 +33,4 @@ management: enabled: true member: - default-profile-image-url: https://dev-swagger.framey.kr/assets/default-profile-image.png + default-profile-image-url: https://dev-swagger.framey.kr/assets/members/default-profile-image.png diff --git a/framey-application/member-service/src/main/resources/application.yaml b/framey-application/member-service/src/main/resources/application.yaml index 3b42f4a..8249f25 100644 --- a/framey-application/member-service/src/main/resources/application.yaml +++ b/framey-application/member-service/src/main/resources/application.yaml @@ -10,4 +10,4 @@ springdoc: api-docs: enabled: true member: - default-profile-image-url: http://localhost:8081/assets/default-profile-image.png + default-profile-image-url: http://localhost:8081/assets/members/default-profile-image.png diff --git a/framey-application/member-service/src/main/resources/static/assets/default-profile-image.png b/framey-application/member-service/src/main/resources/static/assets/members/default-profile-image.png similarity index 100% rename from framey-application/member-service/src/main/resources/static/assets/default-profile-image.png rename to framey-application/member-service/src/main/resources/static/assets/members/default-profile-image.png diff --git a/framey-infrastructure/nginx/dev/default.conf b/framey-infrastructure/nginx/dev/default.conf index 534e17b..29e3098 100644 --- a/framey-infrastructure/nginx/dev/default.conf +++ b/framey-infrastructure/nginx/dev/default.conf @@ -67,6 +67,16 @@ server { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } + # ========================= + # Member Static Assets + # ========================= + location ^~ /assets/members/ { + proxy_pass http://member-dev:8081; + + proxy_set_header Host $host; + proxy_set_header X-Forwarded-Proto $scheme; + } + # ========================= # Collage Service # =========================