From e6effac8b9efff3bc2ca726e8f37c58de416c4ec Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Tue, 3 Nov 2026 14:43:03 +0900 Subject: [PATCH 01/19] =?UTF-8?q?feat:=20Member=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framey/member/domain/member/Gender.java | 6 ++ .../framey/member/domain/member/Member.java | 83 +++++++++++++++++++ .../framey/member/domain/member/Provider.java | 7 ++ 3 files changed, 96 insertions(+) create mode 100644 framey-application/member-service/src/main/java/framey/member/domain/member/Gender.java create mode 100644 framey-application/member-service/src/main/java/framey/member/domain/member/Member.java create mode 100644 framey-application/member-service/src/main/java/framey/member/domain/member/Provider.java diff --git a/framey-application/member-service/src/main/java/framey/member/domain/member/Gender.java b/framey-application/member-service/src/main/java/framey/member/domain/member/Gender.java new file mode 100644 index 0000000..49ca811 --- /dev/null +++ b/framey-application/member-service/src/main/java/framey/member/domain/member/Gender.java @@ -0,0 +1,6 @@ +package framey.member.domain.member; + +public enum Gender { + MALE, + FEMALE, +} diff --git a/framey-application/member-service/src/main/java/framey/member/domain/member/Member.java b/framey-application/member-service/src/main/java/framey/member/domain/member/Member.java new file mode 100644 index 0000000..b12ff9e --- /dev/null +++ b/framey-application/member-service/src/main/java/framey/member/domain/member/Member.java @@ -0,0 +1,83 @@ +package framey.member.domain.member; + +import framey.common.jpa.BaseEntity; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Column; +import jakarta.persistence.Enumerated; +import jakarta.persistence.EnumType; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.time.LocalDate; +import java.util.UUID; + +@Entity +@Table( + uniqueConstraints = { + @UniqueConstraint(name = "uk_member_provider", columnNames = {"provider", "provider_id"}), + @UniqueConstraint(name = "uk_member_nickname", columnNames = {"nickname"}), + @UniqueConstraint(name = "uk_member_email", columnNames = {"email"}), + } +) +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class Member extends BaseEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long memberId; + + @Column(updatable = false, nullable = false) + private String email; + + @Column(length = 10, nullable = false) + private String nickname; + + @Column(updatable = false, unique = true, nullable = false) + private UUID entityId; + + @Column(length = 2048, nullable = false) + private String profileImageUrl; + + @Column(updatable = false, nullable = false) + private String providerId; + + @Enumerated(EnumType.STRING) + @Column(updatable = false, nullable = false) + private Provider provider; + + private LocalDate birthDate; + + @Enumerated(EnumType.STRING) + private Gender gender; + + public static Member signUp( + String email, + String nickname, + String profileImageUrl, + String providerId, + Provider provider, + LocalDate birthDate, + Gender gender + ) { + Member member = new Member(); + member.email = email; + member.nickname = normalizeNickname(nickname); + member.profileImageUrl = profileImageUrl; + member.providerId = providerId; + member.provider = provider; + member.entityId = UUID.randomUUID(); + member.birthDate = birthDate; + member.gender = gender; + + return member; + } + + private static String normalizeNickname(String nickname) { + // TODO: normalizing + return nickname; + } +} diff --git a/framey-application/member-service/src/main/java/framey/member/domain/member/Provider.java b/framey-application/member-service/src/main/java/framey/member/domain/member/Provider.java new file mode 100644 index 0000000..d09581f --- /dev/null +++ b/framey-application/member-service/src/main/java/framey/member/domain/member/Provider.java @@ -0,0 +1,7 @@ +package framey.member.domain.member; + +public enum Provider { + GOOGLE, + KAKAO, + APPLE +} From 27b65998ccd828293bcc44df1d005940e1717a89 Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Tue, 3 Nov 2026 14:59:54 +0900 Subject: [PATCH 02/19] =?UTF-8?q?feat:=20nickname=20=EA=B2=80=EC=A6=9D=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 --- .../framey/member/domain/member/Member.java | 24 +++++++++++++++---- .../member/exception/MemberErrorCode.java | 17 +++++++++++++ 2 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 framey-application/member-service/src/main/java/framey/member/exception/MemberErrorCode.java diff --git a/framey-application/member-service/src/main/java/framey/member/domain/member/Member.java b/framey-application/member-service/src/main/java/framey/member/domain/member/Member.java index b12ff9e..3861c13 100644 --- a/framey-application/member-service/src/main/java/framey/member/domain/member/Member.java +++ b/framey-application/member-service/src/main/java/framey/member/domain/member/Member.java @@ -1,6 +1,8 @@ package framey.member.domain.member; +import framey.common.exception.BusinessException; import framey.common.jpa.BaseEntity; +import framey.member.exception.MemberErrorCode; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; @@ -26,6 +28,8 @@ ) @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Member extends BaseEntity { + private static final int MAX_NICKNAME_LENGTH = 10; + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long memberId; @@ -33,7 +37,7 @@ public class Member extends BaseEntity { @Column(updatable = false, nullable = false) private String email; - @Column(length = 10, nullable = false) + @Column(length = MAX_NICKNAME_LENGTH, nullable = false) private String nickname; @Column(updatable = false, unique = true, nullable = false) @@ -65,7 +69,7 @@ public static Member signUp( ) { Member member = new Member(); member.email = email; - member.nickname = normalizeNickname(nickname); + member.nickname = validateNickname(nickname); member.profileImageUrl = profileImageUrl; member.providerId = providerId; member.provider = provider; @@ -76,8 +80,18 @@ public static Member signUp( return member; } - private static String normalizeNickname(String nickname) { - // TODO: normalizing - return nickname; + private static String validateNickname(String nickname) { + if (nickname == null || nickname.isBlank()) { + throw new BusinessException(MemberErrorCode.NICKNAME_REQUIRED); + } + + String stripedNickname = nickname.strip(); + + // NOTE: 이모지를 1글자로 처리하기 위해 codePointCount 사용 + if (stripedNickname.codePointCount(0, stripedNickname.length()) > MAX_NICKNAME_LENGTH) { + throw new BusinessException(MemberErrorCode.MAX_NICKNAME_LENGTH); + } + + return stripedNickname; } } diff --git a/framey-application/member-service/src/main/java/framey/member/exception/MemberErrorCode.java b/framey-application/member-service/src/main/java/framey/member/exception/MemberErrorCode.java new file mode 100644 index 0000000..d40795b --- /dev/null +++ b/framey-application/member-service/src/main/java/framey/member/exception/MemberErrorCode.java @@ -0,0 +1,17 @@ +package framey.member.exception; + +import framey.common.response.ErrorCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; + +@Getter +@RequiredArgsConstructor +public enum MemberErrorCode implements ErrorCode { + NICKNAME_REQUIRED("MB-001", "닉네임을 입력해 주세요.", HttpStatus.BAD_REQUEST), + MAX_NICKNAME_LENGTH("MB-002", "닉네임은 10자 이내로 입력해 주세요.", HttpStatus.BAD_REQUEST); + + private final String value; + private final String message; + private final HttpStatus httpStatus; +} From 911736497c2ec76a3c0a117b5792a9d7b103e8fc Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Tue, 3 Nov 2026 16:32:39 +0900 Subject: [PATCH 03/19] =?UTF-8?q?test:=20Member=20=EB=8B=89=EB=84=A4?= =?UTF-8?q?=EC=9E=84=20=EA=B4=80=EB=A0=A8=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framey/member/domain/member/Member.java | 2 + .../member/domain/member/MemberTest.java | 73 +++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 framey-application/member-service/src/test/java/framey/member/domain/member/MemberTest.java diff --git a/framey-application/member-service/src/main/java/framey/member/domain/member/Member.java b/framey-application/member-service/src/main/java/framey/member/domain/member/Member.java index 3861c13..ac02d5f 100644 --- a/framey-application/member-service/src/main/java/framey/member/domain/member/Member.java +++ b/framey-application/member-service/src/main/java/framey/member/domain/member/Member.java @@ -13,6 +13,7 @@ import jakarta.persistence.Table; import jakarta.persistence.UniqueConstraint; import lombok.AccessLevel; +import lombok.Getter; import lombok.NoArgsConstructor; import java.time.LocalDate; @@ -27,6 +28,7 @@ } ) @NoArgsConstructor(access = AccessLevel.PROTECTED) +@Getter public class Member extends BaseEntity { private static final int MAX_NICKNAME_LENGTH = 10; 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/member/MemberTest.java new file mode 100644 index 0000000..1eb0710 --- /dev/null +++ b/framey-application/member-service/src/test/java/framey/member/domain/member/MemberTest.java @@ -0,0 +1,73 @@ +package framey.member.domain.member; + +import framey.common.exception.BusinessException; +import framey.member.exception.MemberErrorCode; +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; + +class MemberTest { + + @ParameterizedTest + @ValueSource(strings = {" ", " ", "\u3000"}) + @NullAndEmptySource + @DisplayName("닉네임이 비어 있거나 null이면 가입할 수 없다") + void signUpFailWhenNicknameIsBlank(String nickname) { + Assertions.assertThatThrownBy(() -> + Member.signUp("framey@test.com", nickname, "", "test-1", Provider.GOOGLE, null, Gender.MALE) + ) + .isInstanceOf(BusinessException.class) + .extracting("errorCode") + .isEqualTo(MemberErrorCode.NICKNAME_REQUIRED); + } + + @ParameterizedTest + @ValueSource(strings = {" Framey ", "\u3000Framey\u3000"}) + @DisplayName("닉네임에 공백(유니코드 공백 포함)이 있으면 제거된다") + void signUpStripsNicknameWhitespace(String nickname) { + Member member = Member.signUp("framey@test.com", nickname, "", "test-1", Provider.GOOGLE, null, Gender.MALE); + + Assertions.assertThat(member.getEntityId()).isNotNull(); + Assertions.assertThat(member.getNickname()).isEqualTo(nickname.strip()); + } + + @Test + @DisplayName("닉네임이 10자 이내면 가입할 수 있다") + void signUpSuccessWhenNicknameIsWithinMaxLength() { + String nickname = "0123456789"; + Member member = Member.signUp("framey@test.com", nickname, "", "test-1", Provider.GOOGLE, null, Gender.MALE); + + Assertions.assertThat(nickname.length()).isEqualTo(10); + Assertions.assertThat(member.getNickname()).isEqualTo(nickname); + Assertions.assertThat(member.getNickname()).isEqualTo(nickname); + Assertions.assertThat(member.getEntityId()).isNotNull(); + } + + @Test + @DisplayName("닉네임의 이모지는 1글자로 센다") + void signUpCountsEmojiAsOneChar() { + String nickname = "🙂🙂🙂🙂🙂🙂🙂🙂🙂🙂"; + Member member = Member.signUp("framey@test.com", nickname, "", "test-1", Provider.GOOGLE, null, Gender.MALE); + + Assertions.assertThat(nickname.codePointCount(0, nickname.length())).isEqualTo(10); + Assertions.assertThat(member.getNickname()).isEqualTo(nickname); + Assertions.assertThat(member.getNickname()).isEqualTo(nickname); + Assertions.assertThat(member.getEntityId()).isNotNull(); + } + + @ParameterizedTest + @ValueSource(strings = {"01234567890", "🙂🙂🙂🙂🙂🙂🙂🙂🙂🙂🙂"}) + @DisplayName("닉네임 길이는 10자를 초과할 수 없다") + void signUpFailWhenNicknameOverMaxLength(String nickname) { + Assertions.assertThat(nickname.codePointCount(0, nickname.length())).isEqualTo(11); + Assertions.assertThatThrownBy(() -> + Member.signUp("framey@test.com", nickname, "", "test-1", Provider.GOOGLE, null, Gender.MALE) + ) + .isInstanceOf(BusinessException.class) + .extracting("errorCode") + .isEqualTo(MemberErrorCode.MAX_NICKNAME_LENGTH); + } +} From 33dac5efcef6459f0eea595a372306a42f44e145 Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Wed, 4 Nov 2026 10:02:35 +0900 Subject: [PATCH 04/19] =?UTF-8?q?refactor:=20=EC=84=B1=EB=B3=84,=20?= =?UTF-8?q?=EC=83=9D=EC=9D=BC=20=EC=A0=95=EB=B3=B4=20=EC=A0=9C=EC=99=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/framey/member/domain/member/Gender.java | 6 ------ .../main/java/framey/member/domain/member/Member.java | 11 +---------- .../java/framey/member/domain/member/MemberTest.java | 10 +++++----- 3 files changed, 6 insertions(+), 21 deletions(-) delete mode 100644 framey-application/member-service/src/main/java/framey/member/domain/member/Gender.java diff --git a/framey-application/member-service/src/main/java/framey/member/domain/member/Gender.java b/framey-application/member-service/src/main/java/framey/member/domain/member/Gender.java deleted file mode 100644 index 49ca811..0000000 --- a/framey-application/member-service/src/main/java/framey/member/domain/member/Gender.java +++ /dev/null @@ -1,6 +0,0 @@ -package framey.member.domain.member; - -public enum Gender { - MALE, - FEMALE, -} diff --git a/framey-application/member-service/src/main/java/framey/member/domain/member/Member.java b/framey-application/member-service/src/main/java/framey/member/domain/member/Member.java index ac02d5f..b1a6c69 100644 --- a/framey-application/member-service/src/main/java/framey/member/domain/member/Member.java +++ b/framey-application/member-service/src/main/java/framey/member/domain/member/Member.java @@ -55,19 +55,12 @@ public class Member extends BaseEntity { @Column(updatable = false, nullable = false) private Provider provider; - private LocalDate birthDate; - - @Enumerated(EnumType.STRING) - private Gender gender; - public static Member signUp( String email, String nickname, String profileImageUrl, String providerId, - Provider provider, - LocalDate birthDate, - Gender gender + Provider provider ) { Member member = new Member(); member.email = email; @@ -76,8 +69,6 @@ public static Member signUp( member.providerId = providerId; member.provider = provider; member.entityId = UUID.randomUUID(); - member.birthDate = birthDate; - member.gender = gender; return member; } 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/member/MemberTest.java index 1eb0710..08dd8ad 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/member/MemberTest.java @@ -17,7 +17,7 @@ class MemberTest { @DisplayName("닉네임이 비어 있거나 null이면 가입할 수 없다") void signUpFailWhenNicknameIsBlank(String nickname) { Assertions.assertThatThrownBy(() -> - Member.signUp("framey@test.com", nickname, "", "test-1", Provider.GOOGLE, null, Gender.MALE) + Member.signUp("framey@test.com", nickname, "", "test-1", Provider.GOOGLE) ) .isInstanceOf(BusinessException.class) .extracting("errorCode") @@ -28,7 +28,7 @@ void signUpFailWhenNicknameIsBlank(String nickname) { @ValueSource(strings = {" Framey ", "\u3000Framey\u3000"}) @DisplayName("닉네임에 공백(유니코드 공백 포함)이 있으면 제거된다") void signUpStripsNicknameWhitespace(String nickname) { - Member member = Member.signUp("framey@test.com", nickname, "", "test-1", Provider.GOOGLE, null, Gender.MALE); + Member member = Member.signUp("framey@test.com", nickname, "", "test-1", Provider.GOOGLE); Assertions.assertThat(member.getEntityId()).isNotNull(); Assertions.assertThat(member.getNickname()).isEqualTo(nickname.strip()); @@ -38,7 +38,7 @@ void signUpStripsNicknameWhitespace(String nickname) { @DisplayName("닉네임이 10자 이내면 가입할 수 있다") void signUpSuccessWhenNicknameIsWithinMaxLength() { String nickname = "0123456789"; - Member member = Member.signUp("framey@test.com", nickname, "", "test-1", Provider.GOOGLE, null, Gender.MALE); + Member member = Member.signUp("framey@test.com", nickname, "", "test-1", Provider.GOOGLE); Assertions.assertThat(nickname.length()).isEqualTo(10); Assertions.assertThat(member.getNickname()).isEqualTo(nickname); @@ -50,7 +50,7 @@ void signUpSuccessWhenNicknameIsWithinMaxLength() { @DisplayName("닉네임의 이모지는 1글자로 센다") void signUpCountsEmojiAsOneChar() { String nickname = "🙂🙂🙂🙂🙂🙂🙂🙂🙂🙂"; - Member member = Member.signUp("framey@test.com", nickname, "", "test-1", Provider.GOOGLE, null, Gender.MALE); + Member member = Member.signUp("framey@test.com", nickname, "", "test-1", Provider.GOOGLE); Assertions.assertThat(nickname.codePointCount(0, nickname.length())).isEqualTo(10); Assertions.assertThat(member.getNickname()).isEqualTo(nickname); @@ -64,7 +64,7 @@ void signUpCountsEmojiAsOneChar() { void signUpFailWhenNicknameOverMaxLength(String nickname) { Assertions.assertThat(nickname.codePointCount(0, nickname.length())).isEqualTo(11); Assertions.assertThatThrownBy(() -> - Member.signUp("framey@test.com", nickname, "", "test-1", Provider.GOOGLE, null, Gender.MALE) + Member.signUp("framey@test.com", nickname, "", "test-1", Provider.GOOGLE) ) .isInstanceOf(BusinessException.class) .extracting("errorCode") From f805181da680be0b6bb33b0f05e1d764925ebd31 Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Sat, 7 Nov 2026 13:53:36 +0900 Subject: [PATCH 05/19] =?UTF-8?q?feat:=20=EB=8B=89=EB=84=A4=EC=9E=84=20?= =?UTF-8?q?=EC=A4=91=EB=B3=B5=20=EC=8B=9C=20=EC=82=AC=EC=9A=A9=ED=95=A0=20?= =?UTF-8?q?generator=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framey/member/domain/member/Member.java | 3 +- .../domain/member/NicknameGenerator.java | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 framey-application/member-service/src/main/java/framey/member/domain/member/NicknameGenerator.java diff --git a/framey-application/member-service/src/main/java/framey/member/domain/member/Member.java b/framey-application/member-service/src/main/java/framey/member/domain/member/Member.java index b1a6c69..ddfda24 100644 --- a/framey-application/member-service/src/main/java/framey/member/domain/member/Member.java +++ b/framey-application/member-service/src/main/java/framey/member/domain/member/Member.java @@ -16,7 +16,6 @@ import lombok.Getter; import lombok.NoArgsConstructor; -import java.time.LocalDate; import java.util.UUID; @Entity @@ -30,7 +29,7 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) @Getter public class Member extends BaseEntity { - private static final int MAX_NICKNAME_LENGTH = 10; + public static final int MAX_NICKNAME_LENGTH = 10; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/framey-application/member-service/src/main/java/framey/member/domain/member/NicknameGenerator.java b/framey-application/member-service/src/main/java/framey/member/domain/member/NicknameGenerator.java new file mode 100644 index 0000000..1024583 --- /dev/null +++ b/framey-application/member-service/src/main/java/framey/member/domain/member/NicknameGenerator.java @@ -0,0 +1,37 @@ +package framey.member.domain.member; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.Random; + +import static framey.member.domain.member.Member.MAX_NICKNAME_LENGTH; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class NicknameGenerator { + private static final String NICKNAME_BASE = "프레이미"; + private static final int MIN_SUFFIX_DIGITS = 5; + + public static String generate(String nickname) { + boolean hasNickname = nickname != null && !nickname.isBlank(); + + String baseNickname = hasNickname ? nickname.strip() : NICKNAME_BASE; + + int baseLength = baseNickname.codePointCount(0, baseNickname.length()); + int suffixLength = Math.max(MIN_SUFFIX_DIGITS, MAX_NICKNAME_LENGTH - baseLength); + int keepLength = MAX_NICKNAME_LENGTH - suffixLength; + + if (baseLength > keepLength) { + baseNickname = baseNickname.substring(0, baseNickname.offsetByCodePoints(0, keepLength)); + } + + StringBuilder base = new StringBuilder(baseNickname); + + for (int i = 0; i < suffixLength; i++) { + int randomNumber = new Random().nextInt(10); + base.append(randomNumber); + } + + return base.toString(); + } +} From e55cc3d6351f857f285fab6e021c0904142c17d9 Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Sat, 7 Nov 2026 17:06:46 +0900 Subject: [PATCH 06/19] =?UTF-8?q?feat:=20NicknameGenerator=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/NicknameGenerator.java | 35 ++++++++-------- .../domain/member/NicknameGeneratorTest.java | 40 +++++++++++++++++++ 2 files changed, 59 insertions(+), 16 deletions(-) create mode 100644 framey-application/member-service/src/test/java/framey/member/domain/member/NicknameGeneratorTest.java diff --git a/framey-application/member-service/src/main/java/framey/member/domain/member/NicknameGenerator.java b/framey-application/member-service/src/main/java/framey/member/domain/member/NicknameGenerator.java index 1024583..0e8a4df 100644 --- a/framey-application/member-service/src/main/java/framey/member/domain/member/NicknameGenerator.java +++ b/framey-application/member-service/src/main/java/framey/member/domain/member/NicknameGenerator.java @@ -9,29 +9,32 @@ @NoArgsConstructor(access = AccessLevel.PRIVATE) public class NicknameGenerator { - private static final String NICKNAME_BASE = "프레이미"; - private static final int MIN_SUFFIX_DIGITS = 5; + private static final String BASE_NICKNAME = "프레이미"; + private static final int MIN_SUFFIX_DIGITS = 4; - public static String generate(String nickname) { - boolean hasNickname = nickname != null && !nickname.isBlank(); + public static String normalize(String nickname) { + if (nickname == null || nickname.isBlank()) { + return BASE_NICKNAME; + } - String baseNickname = hasNickname ? nickname.strip() : NICKNAME_BASE; + return truncate(nickname.strip(), MAX_NICKNAME_LENGTH); + } - int baseLength = baseNickname.codePointCount(0, baseNickname.length()); + public static String appendSuffix(String base) { + int baseLength = base.codePointCount(0, base.length()); int suffixLength = Math.max(MIN_SUFFIX_DIGITS, MAX_NICKNAME_LENGTH - baseLength); - int keepLength = MAX_NICKNAME_LENGTH - suffixLength; - - if (baseLength > keepLength) { - baseNickname = baseNickname.substring(0, baseNickname.offsetByCodePoints(0, keepLength)); - } - - StringBuilder base = new StringBuilder(baseNickname); + StringBuilder nickname = new StringBuilder(truncate(base, MAX_NICKNAME_LENGTH - suffixLength)); for (int i = 0; i < suffixLength; i++) { - int randomNumber = new Random().nextInt(10); - base.append(randomNumber); + nickname.append(new Random().nextInt(10)); } + return nickname.toString(); + } - return base.toString(); + private static String truncate(String value, int maxLength) { + if (value.codePointCount(0, value.length()) <= maxLength) { + return value; + } + return value.substring(0, value.offsetByCodePoints(0, maxLength)); } } 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 new file mode 100644 index 0000000..3086e39 --- /dev/null +++ b/framey-application/member-service/src/test/java/framey/member/domain/member/NicknameGeneratorTest.java @@ -0,0 +1,40 @@ +package framey.member.domain.member; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.junit.jupiter.params.provider.ValueSource; + +import static framey.member.domain.member.NicknameGenerator.appendSuffix; +import static framey.member.domain.member.NicknameGenerator.normalize; + +class NicknameGeneratorTest { + /** + * - 6자, 11자 → ^가나다라마\d{5}$ + * - 🙂×10 → 🙂×5 + \d{5} + * - 모든 결과의 코드포인트 길이가 10인지 + */ + + @ParameterizedTest + @ValueSource(strings = {" ", "\u3000"}) + @NullAndEmptySource + @DisplayName("닉네임이 비어있을 경우 기본 닉네임을 사용한다") + void useDefaultNicknameWhenNicknameIsBlank(String nickname) { + String generatedNickname = appendSuffix(normalize(nickname)); + + Assertions.assertThat(generatedNickname).isNotBlank(); + Assertions.assertThat(generatedNickname).matches("^프레이미\\d{6}$"); + } + + @ParameterizedTest + @ValueSource(strings = { " 프레이미 ", " 프레이미", "프레이미 ", "\u3000프레이미\u3000"}) + @DisplayName("닉네임의 공백을 제거한다.") + void stripsNicknameWhiteSpaces(String nickname) { + String generatedNickname = normalize(nickname); + + Assertions.assertThat(generatedNickname).isNotBlank(); + Assertions.assertThat(generatedNickname).isEqualTo("프레이미"); + } + +} From 0d8fd23bb5ecb7206b3ad8b0854e74b1a7c56033 Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Sat, 7 Nov 2026 17:07:52 +0900 Subject: [PATCH 07/19] =?UTF-8?q?refactor:=20=ED=8F=B4=EB=8D=94=20?= =?UTF-8?q?=EC=95=84=ED=82=A4=ED=85=8D=EC=B2=98=20=EB=A7=9E=EC=B6=94?= =?UTF-8?q?=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/domain/{member => constant}/Provider.java | 2 +- .../member/{ => domain}/exception/MemberErrorCode.java | 2 +- .../framey/member/domain/{member => model}/Member.java | 5 +++-- .../domain/{member => model}/NicknameGenerator.java | 4 ++-- .../java/framey/member/domain/member/MemberTest.java | 4 +++- .../member/domain/member/NicknameGeneratorTest.java | 10 ++-------- 6 files changed, 12 insertions(+), 15 deletions(-) rename framey-application/member-service/src/main/java/framey/member/domain/{member => constant}/Provider.java (60%) rename framey-application/member-service/src/main/java/framey/member/{ => domain}/exception/MemberErrorCode.java (93%) rename framey-application/member-service/src/main/java/framey/member/domain/{member => model}/Member.java (95%) rename framey-application/member-service/src/main/java/framey/member/domain/{member => model}/NicknameGenerator.java (92%) diff --git a/framey-application/member-service/src/main/java/framey/member/domain/member/Provider.java b/framey-application/member-service/src/main/java/framey/member/domain/constant/Provider.java similarity index 60% rename from framey-application/member-service/src/main/java/framey/member/domain/member/Provider.java rename to framey-application/member-service/src/main/java/framey/member/domain/constant/Provider.java index d09581f..7eedcf5 100644 --- a/framey-application/member-service/src/main/java/framey/member/domain/member/Provider.java +++ b/framey-application/member-service/src/main/java/framey/member/domain/constant/Provider.java @@ -1,4 +1,4 @@ -package framey.member.domain.member; +package framey.member.domain.constant; public enum Provider { GOOGLE, diff --git a/framey-application/member-service/src/main/java/framey/member/exception/MemberErrorCode.java b/framey-application/member-service/src/main/java/framey/member/domain/exception/MemberErrorCode.java similarity index 93% rename from framey-application/member-service/src/main/java/framey/member/exception/MemberErrorCode.java rename to framey-application/member-service/src/main/java/framey/member/domain/exception/MemberErrorCode.java index d40795b..af570d8 100644 --- a/framey-application/member-service/src/main/java/framey/member/exception/MemberErrorCode.java +++ b/framey-application/member-service/src/main/java/framey/member/domain/exception/MemberErrorCode.java @@ -1,4 +1,4 @@ -package framey.member.exception; +package framey.member.domain.exception; import framey.common.response.ErrorCode; import lombok.Getter; diff --git a/framey-application/member-service/src/main/java/framey/member/domain/member/Member.java b/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java similarity index 95% rename from framey-application/member-service/src/main/java/framey/member/domain/member/Member.java rename to framey-application/member-service/src/main/java/framey/member/domain/model/Member.java index ddfda24..753a4cf 100644 --- a/framey-application/member-service/src/main/java/framey/member/domain/member/Member.java +++ b/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java @@ -1,8 +1,9 @@ -package framey.member.domain.member; +package framey.member.domain.model; import framey.common.exception.BusinessException; import framey.common.jpa.BaseEntity; -import framey.member.exception.MemberErrorCode; +import framey.member.domain.constant.Provider; +import framey.member.domain.exception.MemberErrorCode; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; diff --git a/framey-application/member-service/src/main/java/framey/member/domain/member/NicknameGenerator.java b/framey-application/member-service/src/main/java/framey/member/domain/model/NicknameGenerator.java similarity index 92% rename from framey-application/member-service/src/main/java/framey/member/domain/member/NicknameGenerator.java rename to framey-application/member-service/src/main/java/framey/member/domain/model/NicknameGenerator.java index 0e8a4df..1c92a3a 100644 --- a/framey-application/member-service/src/main/java/framey/member/domain/member/NicknameGenerator.java +++ b/framey-application/member-service/src/main/java/framey/member/domain/model/NicknameGenerator.java @@ -1,11 +1,11 @@ -package framey.member.domain.member; +package framey.member.domain.model; import lombok.AccessLevel; import lombok.NoArgsConstructor; import java.util.Random; -import static framey.member.domain.member.Member.MAX_NICKNAME_LENGTH; +import static framey.member.domain.model.Member.MAX_NICKNAME_LENGTH; @NoArgsConstructor(access = AccessLevel.PRIVATE) public class NicknameGenerator { 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/member/MemberTest.java index 08dd8ad..22fb1eb 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/member/MemberTest.java @@ -1,7 +1,9 @@ package framey.member.domain.member; import framey.common.exception.BusinessException; -import framey.member.exception.MemberErrorCode; +import framey.member.domain.constant.Provider; +import framey.member.domain.model.Member; +import framey.member.domain.exception.MemberErrorCode; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; 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 3086e39..d0a3ba4 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 @@ -6,16 +6,10 @@ import org.junit.jupiter.params.provider.NullAndEmptySource; import org.junit.jupiter.params.provider.ValueSource; -import static framey.member.domain.member.NicknameGenerator.appendSuffix; -import static framey.member.domain.member.NicknameGenerator.normalize; +import static framey.member.domain.model.NicknameGenerator.appendSuffix; +import static framey.member.domain.model.NicknameGenerator.normalize; class NicknameGeneratorTest { - /** - * - 6자, 11자 → ^가나다라마\d{5}$ - * - 🙂×10 → 🙂×5 + \d{5} - * - 모든 결과의 코드포인트 길이가 10인지 - */ - @ParameterizedTest @ValueSource(strings = {" ", "\u3000"}) @NullAndEmptySource From a11bae859e000521f6726fa46280f295d4905fec Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Sun, 8 Nov 2026 20:52:12 +0900 Subject: [PATCH 08/19] =?UTF-8?q?feat:=20email,=20providerId,=20provider?= =?UTF-8?q?=20=EC=BB=AC=EB=9F=BC=20NotNull=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/framey/member/domain/model/Member.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java b/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java index 753a4cf..88a9790 100644 --- a/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java +++ b/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java @@ -13,6 +13,7 @@ import jakarta.persistence.EnumType; import jakarta.persistence.Table; import jakarta.persistence.UniqueConstraint; +import jakarta.validation.constraints.NotNull; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @@ -37,6 +38,7 @@ public class Member extends BaseEntity { private Long memberId; @Column(updatable = false, nullable = false) + @NotNull private String email; @Column(length = MAX_NICKNAME_LENGTH, nullable = false) @@ -49,10 +51,12 @@ public class Member extends BaseEntity { private String profileImageUrl; @Column(updatable = false, nullable = false) + @NotNull private String providerId; @Enumerated(EnumType.STRING) @Column(updatable = false, nullable = false) + @NotNull private Provider provider; public static Member signUp( From 4649f5a7e8eef9c6aa010ecbe761629b4590fe42 Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Sun, 8 Nov 2026 21:41:19 +0900 Subject: [PATCH 09/19] =?UTF-8?q?refactor:=20=EB=8B=89=EB=84=A4=EC=9E=84?= =?UTF-8?q?=20=EA=B2=80=EC=A6=9D=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/constant/NicknameConstant.java | 12 ++++++++++++ .../framey/member/domain/model/Member.java | 14 ++++++++++---- .../member/domain/model/NicknameGenerator.java | 18 ++++++++++++------ 3 files changed, 34 insertions(+), 10 deletions(-) create mode 100644 framey-application/member-service/src/main/java/framey/member/domain/constant/NicknameConstant.java 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 new file mode 100644 index 0000000..66e192e --- /dev/null +++ b/framey-application/member-service/src/main/java/framey/member/domain/constant/NicknameConstant.java @@ -0,0 +1,12 @@ +package framey.member.domain.constant; + +import java.util.regex.Pattern; + +public class NicknameConstant { + public static final int MAX_NICKNAME_LENGTH = 10; + public static final Pattern EDGE_WHITESPACE = Pattern.compile( + "^[\\p{javaWhitespace}\\p{Z}]+|[\\p{javaWhitespace}\\p{Z}]+$" + ); + public static final String BASE_NICKNAME = "프레이미"; + public static final int MIN_SUFFIX_DIGITS = 4; +} diff --git a/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java b/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java index 88a9790..26d3995 100644 --- a/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java +++ b/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java @@ -20,6 +20,9 @@ import java.util.UUID; +import static framey.member.domain.constant.NicknameConstant.EDGE_WHITESPACE; +import static framey.member.domain.constant.NicknameConstant.MAX_NICKNAME_LENGTH; + @Entity @Table( uniqueConstraints = { @@ -31,8 +34,6 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) @Getter public class Member extends BaseEntity { - public static final int MAX_NICKNAME_LENGTH = 10; - @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long memberId; @@ -78,11 +79,16 @@ public static Member signUp( } private static String validateNickname(String nickname) { - if (nickname == null || nickname.isBlank()) { + if (nickname == null) { + throw new BusinessException(MemberErrorCode.NICKNAME_REQUIRED); + } + + String stripedNickname = EDGE_WHITESPACE.matcher(nickname).replaceAll(""); + + if (stripedNickname.isEmpty()) { throw new BusinessException(MemberErrorCode.NICKNAME_REQUIRED); } - String stripedNickname = nickname.strip(); // NOTE: 이모지를 1글자로 처리하기 위해 codePointCount 사용 if (stripedNickname.codePointCount(0, stripedNickname.length()) > MAX_NICKNAME_LENGTH) { 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 1c92a3a..4743fa2 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 @@ -5,19 +5,25 @@ import java.util.Random; -import static framey.member.domain.model.Member.MAX_NICKNAME_LENGTH; +import static framey.member.domain.constant.NicknameConstant.BASE_NICKNAME; +import static framey.member.domain.constant.NicknameConstant.EDGE_WHITESPACE; +import static framey.member.domain.constant.NicknameConstant.MAX_NICKNAME_LENGTH; +import static framey.member.domain.constant.NicknameConstant.MIN_SUFFIX_DIGITS; @NoArgsConstructor(access = AccessLevel.PRIVATE) public class NicknameGenerator { - private static final String BASE_NICKNAME = "프레이미"; - private static final int MIN_SUFFIX_DIGITS = 4; - public static String normalize(String nickname) { - if (nickname == null || nickname.isBlank()) { + if (nickname == null) { + return BASE_NICKNAME; + } + + String stripedNickname = EDGE_WHITESPACE.matcher(nickname).replaceAll(""); + + if (stripedNickname.isEmpty()) { return BASE_NICKNAME; } - return truncate(nickname.strip(), MAX_NICKNAME_LENGTH); + return truncate(stripedNickname.strip(), MAX_NICKNAME_LENGTH); } public static String appendSuffix(String base) { From 4cb8a9802958ba6c72caf45b32e30c37a1c41be4 Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Sun, 8 Nov 2026 21:47:38 +0900 Subject: [PATCH 10/19] =?UTF-8?q?refactor:=20unicode=20=EA=B3=B5=EB=B0=B1?= =?UTF-8?q?=20=EC=B2=98=EB=A6=AC=20=ED=8F=AC=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/framey/member/domain/constant/NicknameConstant.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 66e192e..161f1d6 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 @@ -5,7 +5,7 @@ public class NicknameConstant { public static final int MAX_NICKNAME_LENGTH = 10; public static final Pattern EDGE_WHITESPACE = Pattern.compile( - "^[\\p{javaWhitespace}\\p{Z}]+|[\\p{javaWhitespace}\\p{Z}]+$" + "^[\\p{javaWhitespace}\\s]+|[\\p{javaWhitespace}\\s]+$" ); public static final String BASE_NICKNAME = "프레이미"; public static final int MIN_SUFFIX_DIGITS = 4; From 789ab45475f6b9303f3052429c73ce8b06227d3c Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Sun, 8 Nov 2026 21:55:53 +0900 Subject: [PATCH 11/19] =?UTF-8?q?refactor:=20=EC=A4=84=EB=B0=94=EA=BF=88?= =?UTF-8?q?=20=EC=97=86=EB=8A=94=20=EA=B3=B5=EB=B0=B1=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/framey/member/domain/constant/NicknameConstant.java | 2 +- .../java/framey/member/domain/member/NicknameGeneratorTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 161f1d6..6564320 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 @@ -5,7 +5,7 @@ public class NicknameConstant { public static final int MAX_NICKNAME_LENGTH = 10; public static final Pattern EDGE_WHITESPACE = Pattern.compile( - "^[\\p{javaWhitespace}\\s]+|[\\p{javaWhitespace}\\s]+$" + "^[\\p{javaWhitespace}\\p{IsWhite_Space}]+|[\\p{javaWhitespace}\\p{IsWhite_Space}]+$" ); public static final String BASE_NICKNAME = "프레이미"; public static final int MIN_SUFFIX_DIGITS = 4; 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 d0a3ba4..f63ff23 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 @@ -11,7 +11,7 @@ class NicknameGeneratorTest { @ParameterizedTest - @ValueSource(strings = {" ", "\u3000"}) + @ValueSource(strings = {" ", "\u3000", "\u00A0"}) @NullAndEmptySource @DisplayName("닉네임이 비어있을 경우 기본 닉네임을 사용한다") void useDefaultNicknameWhenNicknameIsBlank(String nickname) { From 51d5001045cd321ecb65fd8a8b0ebd6d31764de6 Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Mon, 9 Nov 2026 09:29:35 +0900 Subject: [PATCH 12/19] =?UTF-8?q?refactor:=20normalize=EC=97=90=20?= =?UTF-8?q?=EC=A4=91=EB=B3=B5=20strip()=20=EC=B2=98=EB=A6=AC=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/framey/member/domain/model/NicknameGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 4743fa2..85886ff 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 @@ -23,7 +23,7 @@ public static String normalize(String nickname) { return BASE_NICKNAME; } - return truncate(stripedNickname.strip(), MAX_NICKNAME_LENGTH); + return truncate(stripedNickname, MAX_NICKNAME_LENGTH); } public static String appendSuffix(String base) { From e0be3dc1e82e5c54537c3dc46bae38241b51d3bf Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Mon, 9 Nov 2026 09:30:25 +0900 Subject: [PATCH 13/19] =?UTF-8?q?refactor:=20=EC=9D=B4=EB=AA=A8=EC=A7=80?= =?UTF-8?q?=20=EA=B8=80=EC=9E=90=20=EA=B2=80=EC=A6=9D=20=EC=A3=BC=EC=84=9D?= =?UTF-8?q?=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/framey/member/domain/model/Member.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java b/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java index 26d3995..619099d 100644 --- a/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java +++ b/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java @@ -90,7 +90,7 @@ private static String validateNickname(String nickname) { } - // NOTE: 이모지를 1글자로 처리하기 위해 codePointCount 사용 + // NOTE: 유니코드 코드 포인트 기준으로 길이 검증 if (stripedNickname.codePointCount(0, stripedNickname.length()) > MAX_NICKNAME_LENGTH) { throw new BusinessException(MemberErrorCode.MAX_NICKNAME_LENGTH); } From 106ec7fc809ab8db42ad5e9ee58e3b14426fc201 Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Mon, 9 Nov 2026 09:31:02 +0900 Subject: [PATCH 14/19] =?UTF-8?q?refactor:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=A4=91=EB=B3=B5=20=EA=B2=80=EC=A6=9D=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/test/java/framey/member/domain/member/MemberTest.java | 2 -- 1 file changed, 2 deletions(-) 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/member/MemberTest.java index 22fb1eb..64ae982 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/member/MemberTest.java @@ -44,7 +44,6 @@ void signUpSuccessWhenNicknameIsWithinMaxLength() { Assertions.assertThat(nickname.length()).isEqualTo(10); Assertions.assertThat(member.getNickname()).isEqualTo(nickname); - Assertions.assertThat(member.getNickname()).isEqualTo(nickname); Assertions.assertThat(member.getEntityId()).isNotNull(); } @@ -56,7 +55,6 @@ void signUpCountsEmojiAsOneChar() { Assertions.assertThat(nickname.codePointCount(0, nickname.length())).isEqualTo(10); Assertions.assertThat(member.getNickname()).isEqualTo(nickname); - Assertions.assertThat(member.getNickname()).isEqualTo(nickname); Assertions.assertThat(member.getEntityId()).isNotNull(); } From 79fdbd702c35d828e5b1e37e53a9d68a1a92c220 Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Mon, 9 Nov 2026 09:34:33 +0900 Subject: [PATCH 15/19] =?UTF-8?q?refactor:=20NicknameConstant=20=EC=83=81?= =?UTF-8?q?=EC=86=8D=20=EB=B0=A9=EC=A7=80=20=EB=B0=8F=20=EC=9D=B8=EC=8A=A4?= =?UTF-8?q?=ED=84=B4=EC=8A=A4=20=EC=83=9D=EC=84=B1=20=EC=A0=9C=ED=95=9C,?= =?UTF-8?q?=20=EB=B3=80=EC=88=98=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/domain/constant/NicknameConstant.java | 10 +++++++--- .../framey/member/domain/model/NicknameGenerator.java | 4 ++-- .../member/domain/member/NicknameGeneratorTest.java | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) 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 6564320..e397788 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 @@ -1,12 +1,16 @@ package framey.member.domain.constant; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + import java.util.regex.Pattern; -public class NicknameConstant { +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class NicknameConstant { public static final int MAX_NICKNAME_LENGTH = 10; public static final Pattern EDGE_WHITESPACE = Pattern.compile( "^[\\p{javaWhitespace}\\p{IsWhite_Space}]+|[\\p{javaWhitespace}\\p{IsWhite_Space}]+$" ); - public static final String BASE_NICKNAME = "프레이미"; - public static final int MIN_SUFFIX_DIGITS = 4; + public static final String BASE_NICKNAME = "framey"; + public static final int SUFFIX_DIGITS = 4; } 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 85886ff..087e7b4 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 @@ -8,7 +8,7 @@ import static framey.member.domain.constant.NicknameConstant.BASE_NICKNAME; import static framey.member.domain.constant.NicknameConstant.EDGE_WHITESPACE; import static framey.member.domain.constant.NicknameConstant.MAX_NICKNAME_LENGTH; -import static framey.member.domain.constant.NicknameConstant.MIN_SUFFIX_DIGITS; +import static framey.member.domain.constant.NicknameConstant.SUFFIX_DIGITS; @NoArgsConstructor(access = AccessLevel.PRIVATE) public class NicknameGenerator { @@ -28,7 +28,7 @@ public static String normalize(String nickname) { public static String appendSuffix(String base) { int baseLength = base.codePointCount(0, base.length()); - int suffixLength = Math.max(MIN_SUFFIX_DIGITS, MAX_NICKNAME_LENGTH - baseLength); + int suffixLength = Math.max(SUFFIX_DIGITS, MAX_NICKNAME_LENGTH - baseLength); StringBuilder nickname = new StringBuilder(truncate(base, MAX_NICKNAME_LENGTH - suffixLength)); for (int i = 0; i < suffixLength; i++) { 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 f63ff23..af8052f 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 @@ -18,7 +18,7 @@ void useDefaultNicknameWhenNicknameIsBlank(String nickname) { String generatedNickname = appendSuffix(normalize(nickname)); Assertions.assertThat(generatedNickname).isNotBlank(); - Assertions.assertThat(generatedNickname).matches("^프레이미\\d{6}$"); + Assertions.assertThat(generatedNickname).matches("^framey\\d{4}$"); } @ParameterizedTest From 557e3154726975b4cc09535820290db52496f283 Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Mon, 9 Nov 2026 09:37:16 +0900 Subject: [PATCH 16/19] =?UTF-8?q?refactor:=20ThreadLocalRandom=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=EC=9C=BC=EB=A1=9C=20=EA=B0=9D=EC=B2=B4=20=EB=B0=98?= =?UTF-8?q?=EB=B3=B5=20=EC=83=9D=EC=84=B1=20=EB=B0=A9=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/framey/member/domain/model/NicknameGenerator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 087e7b4..cc20430 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 @@ -4,6 +4,7 @@ import lombok.NoArgsConstructor; import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; import static framey.member.domain.constant.NicknameConstant.BASE_NICKNAME; import static framey.member.domain.constant.NicknameConstant.EDGE_WHITESPACE; @@ -32,7 +33,7 @@ public static String appendSuffix(String base) { StringBuilder nickname = new StringBuilder(truncate(base, MAX_NICKNAME_LENGTH - suffixLength)); for (int i = 0; i < suffixLength; i++) { - nickname.append(new Random().nextInt(10)); + nickname.append(ThreadLocalRandom.current().nextInt(10)); } return nickname.toString(); } From a1ea94ab6f5ca28271af03d58274a35922f568ed Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Mon, 9 Nov 2026 09:56:41 +0900 Subject: [PATCH 17/19] =?UTF-8?q?refactor:=20Member=20entity=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EC=83=9D=EC=84=B1,=20=EC=B4=88=EA=B8=B0=ED=99=94?= =?UTF-8?q?=20=EC=B1=85=EC=9E=84=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framey/member/domain/model/Member.java | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java b/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java index 619099d..e266624 100644 --- a/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java +++ b/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java @@ -60,6 +60,21 @@ public class Member extends BaseEntity { @NotNull private Provider provider; + private Member( + String email, + String nickname, + String profileImageUrl, + String providerId, + Provider provider + ) { + this.email = email; + this.nickname = validateNickname(nickname); + this.profileImageUrl = profileImageUrl; + this.providerId = providerId; + this.provider = provider; + this.entityId = UUID.randomUUID(); + } + public static Member signUp( String email, String nickname, @@ -67,15 +82,7 @@ public static Member signUp( String providerId, Provider provider ) { - Member member = new Member(); - member.email = email; - member.nickname = validateNickname(nickname); - member.profileImageUrl = profileImageUrl; - member.providerId = providerId; - member.provider = provider; - member.entityId = UUID.randomUUID(); - - return member; + return new Member(email, nickname, profileImageUrl, providerId, provider); } private static String validateNickname(String nickname) { From af58c54e687e6d4877554955fd0882471ab3b950 Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Mon, 9 Nov 2026 10:10:48 +0900 Subject: [PATCH 18/19] =?UTF-8?q?refactor:=20@NotBlank=20=EB=B0=8F=20@Emai?= =?UTF-8?q?l=20=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/framey/member/domain/model/Member.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java b/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java index e266624..fd44823 100644 --- a/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java +++ b/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java @@ -13,6 +13,8 @@ import jakarta.persistence.EnumType; import jakarta.persistence.Table; import jakarta.persistence.UniqueConstraint; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.AccessLevel; import lombok.Getter; @@ -39,25 +41,28 @@ public class Member extends BaseEntity { private Long memberId; @Column(updatable = false, nullable = false) - @NotNull + @NotBlank + @Email private String email; @Column(length = MAX_NICKNAME_LENGTH, nullable = false) + @NotBlank private String nickname; @Column(updatable = false, unique = true, nullable = false) private UUID entityId; @Column(length = 2048, nullable = false) + @NotBlank private String profileImageUrl; @Column(updatable = false, nullable = false) - @NotNull + @NotBlank private String providerId; @Enumerated(EnumType.STRING) @Column(updatable = false, nullable = false) - @NotNull + @NotBlank private Provider provider; private Member( From 7a44f99a15969128073b3fb51ff0b8edbf37d9bb Mon Sep 17 00:00:00 2001 From: nimusee1 Date: Mon, 9 Nov 2026 15:26:59 +0900 Subject: [PATCH 19/19] =?UTF-8?q?refactor:=20Provider=20=EC=BB=AC=EB=9F=BC?= =?UTF-8?q?=20@NotNull=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/framey/member/domain/model/Member.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java b/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java index fd44823..0932dbb 100644 --- a/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java +++ b/framey-application/member-service/src/main/java/framey/member/domain/model/Member.java @@ -62,7 +62,7 @@ public class Member extends BaseEntity { @Enumerated(EnumType.STRING) @Column(updatable = false, nullable = false) - @NotBlank + @NotNull private Provider provider; private Member(