Skip to content

Conversation

@kamillcream
Copy link
Contributor

@kamillcream kamillcream commented Jan 16, 2026

📌 PR 개요

  • User 도메인 회원가입 구현 및 테스트 검증

✅ 변경사항

  • 회원가입에 필요한 내용 구현
  • 서비스, 영속성, 컨트롤러 계층에서의 성공, 실패 테스트 구현

🔍 체크리스트

  • PR 제목은 명확한가요?
  • 관련 이슈가 있다면 연결했나요?
  • 로컬 테스트는 통과했나요?
  • 코드에 불필요한 부분은 없나요?

📎 관련 이슈

Closes #3


💬 기타 참고사항

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 사용자 가입 API 및 이메일 중복 확인 API 추가
    • 표준화된 API 응답 포맷과 중앙 예외 처리 도입
    • JPA 기반 사용자 도메인, 영속화 흐름 및 매퍼/레포지토리 등록
    • 보안 설정(BCrypt 비밀번호 인코더 제공) 및 JPA 감사(created/updated) 추가
  • 테스트

    • 서비스·컨트롤러·퍼시스턴스 단위 테스트 추가
  • Chores

    • 빌드 구성 업데이트: Lombok·MapStruct·트랜잭션 설정 추가, 불필요한 모듈 제거

✏️ Tip: You can customize this high-level summary in your review settings.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@main-modules/user/infrastructure/src/main/java/com/sidework/user/persistence/entity/UserEntity.java`:
- Around line 9-10: The `@Table`(name = "user") mapping in the UserEntity class
uses a reserved word; update the mapping to a safe identifier (e.g., change
`@Table`(name = "users")) or apply proper quoting/identifier strategy so the table
name is escaped by the JPA provider; modify the UserEntity annotation and any
related repository or schema DDL references to use the new identifier
(UserEntity, `@Table`) and ensure tests/migrations reflect the change.
♻️ Duplicate comments (1)
main-modules/user/infrastructure/src/main/java/com/sidework/user/persistence/entity/UserEntity.java (1)

21-22: 이메일 길이 100은 여전히 짧을 수 있음
RFC 기준 최대 254자까지 가능하므로 100은 합법적인 주소를 자를 수 있습니다. 254(또는 255)로 확장 검토를 권장합니다.

🛠️ 변경 예시
-@Column(name = "email", nullable = false, length = 100)
+@Column(name = "email", nullable = false, length = 255)
🧹 Nitpick comments (7)
main-modules/common/src/main/java/com/sidework/common/response/exception/ExceptionAdvice.java (4)

97-100: 스택 트레이스 검증 개선 확인.

이전 리뷰에서 지적된 ArrayIndexOutOfBoundsException 가능성이 수정되었습니다. null과 빈 배열을 모두 체크하는 것이 올바릅니다.

다만, Line 100에서 이미 추출한 stackTrace 변수 대신 e.getStackTrace()[0]를 다시 호출하고 있습니다. 일관성을 위해 stackTrace[0]를 사용하는 것이 좋습니다.

♻️ 수정 제안
         StackTraceElement[] stackTrace = e.getStackTrace();
         String errorPoint = (stackTrace == null || stackTrace.length == 0)
                 ? "No Stack Trace Error."
-                : e.getStackTrace()[0].toString();
+                : stackTrace[0].toString();

148-164: 에러 코드 상수 사용 일관성 개선 권장.

handleHttpMessageNotReadable(Line 77)에서는 ErrorStatus.BAD_REQUEST.getCode()를 사용하지만, 여기서는 "COMMON_400"을 하드코딩하고 있습니다. 유지보수성을 위해 ErrorStatus 상수를 일관되게 사용하는 것이 좋습니다.

♻️ 수정 제안
         return ResponseEntity.badRequest().body(
                 ApiResponse.onFailure(
-                        "COMMON_400",
+                        ErrorStatus.BAD_REQUEST.getCode(),
                         "잘못된 요청입니다.",
                         message,
                         path
                 )
         );

166-190: 동일한 에러 코드 상수 일관성 문제.

Line 184에서도 "COMMON_400"을 하드코딩하고 있습니다. 위의 handleTypeMismatch와 동일하게 ErrorStatus.BAD_REQUEST.getCode()를 사용하는 것이 좋습니다.

♻️ 수정 제안
         return ResponseEntity.badRequest().body(
                 ApiResponse.onFailure(
-                        "COMMON_400",
+                        ErrorStatus.BAD_REQUEST.getCode(),
                         errorMessage,
                         null,
                         path
                 )
         );

196-215: 내부 서버 오류 시 전체 스택 트레이스 로깅 권장.

Line 213에서 errorPoint 문자열만 로깅하고 있어 500 에러 발생 시 디버깅에 필요한 전체 스택 트레이스가 손실됩니다. 운영 환경에서 문제 추적을 위해 예외 객체 자체를 함께 로깅하는 것이 좋습니다.

♻️ 수정 제안
-        log.error(errorPoint);
+        log.error("Internal Server Error at {}: {}", path, errorPoint, e);
main-modules/user/infrastructure/src/main/java/com/sidework/user/persistence/entity/UserEntity.java (1)

32-34: columnDefinition = "TEXT"는 DB 의존적
DB마다 타입명이 달라 이식성이 떨어집니다. JPA 표준 @Lob 사용을 권장합니다.

♻️ 변경 예시
-@Column(name = "password", nullable = false, columnDefinition = "TEXT")
+@Lob
+@Column(name = "password", nullable = false)
main-modules/user/infrastructure/src/test/java/com/sidework/user/persistence/UserPersistenceAdapterTest.java (1)

37-42: save 테스트에서 매핑 결과도 검증하면 안정성이 올라갑니다.

현재는 호출 여부만 확인하므로 매핑 오류를 놓칠 수 있습니다. 캡처한 엔티티의 핵심 필드를 검증하는 방식이 좋습니다(필드 접근자는 실제 모델에 맞게 조정).

♻️ 예시 개선
@@
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.*;
+import org.mockito.ArgumentCaptor;
@@
     void save는_도메인_객체를_영속성_객체로_변환해_저장한다() {
         User domain = createUser(createCommand());
         adapter.save(domain);
-        verify(repo).save(any(UserEntity.class));
+        ArgumentCaptor<UserEntity> captor = ArgumentCaptor.forClass(UserEntity.class);
+        verify(repo).save(captor.capture());
+        UserEntity saved = captor.getValue();
+        assertAll(
+                () -> assertEquals(domain.getEmail(), saved.getEmail()),
+                () -> assertEquals(domain.getName(), saved.getName()),
+                () -> assertEquals(domain.getNickname(), saved.getNickname())
+        );
     }
main-modules/common/src/main/java/com/sidework/common/response/status/ErrorStatus.java (1)

22-25: USER_NOT_FOUND의 HTTP 상태코드는 404가 더 자연스럽습니다.

리소스 미존재는 NOT_FOUND가 표준적이라, 클라이언트 처리 일관성이 좋아집니다. 팀의 에러 정책과 맞는지 확인해 주세요.

♻️ 제안 변경
-    USER_NOT_FOUND(HttpStatus.BAD_REQUEST, "USER_002", "해당 사용자를 찾을 수 없습니다."),
+    USER_NOT_FOUND(HttpStatus.NOT_FOUND, "USER_002", "해당 사용자를 찾을 수 없습니다."),
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a27e72a and 456a6d2.

📒 Files selected for processing (8)
  • gradle/libs.versions.toml
  • main-modules/common/src/main/java/com/sidework/common/response/exception/ExceptionAdvice.java
  • main-modules/common/src/main/java/com/sidework/common/response/status/ErrorStatus.java
  • main-modules/user/application/src/test/java/com/sidework/user/application/UserQueryServiceTest.java
  • main-modules/user/infrastructure/src/main/java/com/sidework/user/persistence/adapter/UserPersistenceAdapter.java
  • main-modules/user/infrastructure/src/main/java/com/sidework/user/persistence/entity/UserEntity.java
  • main-modules/user/infrastructure/src/main/java/com/sidework/user/persistence/exception/UserNotFoundException.java
  • main-modules/user/infrastructure/src/test/java/com/sidework/user/persistence/UserPersistenceAdapterTest.java
🚧 Files skipped from review as they are similar to previous changes (2)
  • gradle/libs.versions.toml
  • main-modules/user/application/src/test/java/com/sidework/user/application/UserQueryServiceTest.java
🧰 Additional context used
🧬 Code graph analysis (3)
main-modules/user/infrastructure/src/test/java/com/sidework/user/persistence/UserPersistenceAdapterTest.java (2)
main-modules/user/application/src/main/java/com/sidework/user/application/exception/InvalidCommandException.java (1)
  • InvalidCommandException (6-10)
main-modules/user/infrastructure/src/main/java/com/sidework/user/persistence/exception/UserNotFoundException.java (1)
  • UserNotFoundException (6-10)
main-modules/common/src/main/java/com/sidework/common/response/exception/ExceptionAdvice.java (1)
main-modules/user/application/src/main/java/com/sidework/user/application/adapter/UserController.java (1)
  • RestController (12-30)
main-modules/user/infrastructure/src/main/java/com/sidework/user/persistence/adapter/UserPersistenceAdapter.java (1)
main-modules/user/infrastructure/src/main/java/com/sidework/user/persistence/exception/UserNotFoundException.java (1)
  • UserNotFoundException (6-10)
🔇 Additional comments (15)
main-modules/common/src/main/java/com/sidework/common/response/exception/ExceptionAdvice.java (5)

30-33: LGTM!

클래스 구조가 Spring 예외 처리 베스트 프랙티스를 잘 따르고 있습니다. @RestControllerAdviceResponseEntityExceptionHandler 확장을 적절히 활용하고 있습니다.


35-62: LGTM!

ConstraintViolationException 핸들러가 위반 정보를 명확하게 추출하고 있습니다. 방어적 예외 처리도 적절합니다.


64-90: LGTM!

HTTP 메시지 파싱 오류를 적절히 처리하고 있습니다. getMostSpecificCause()를 활용하여 가장 구체적인 오류 메시지를 추출하는 방식이 좋습니다.


112-127: LGTM!

GlobalException 핸들러가 ErrorDetail을 활용하여 일관된 응답을 생성하고 있습니다. 구현이 깔끔합니다.


129-146: LGTM!

HTTP 메서드 미지원 예외 처리가 ErrorStatus 상수를 일관되게 사용하고 있습니다.

main-modules/user/infrastructure/src/test/java/com/sidework/user/persistence/UserPersistenceAdapterTest.java (5)

32-35: 초기화 구성은 깔끔합니다.

테스트 대상과 의존성 주입 흐름이 명확합니다.


44-59: 중복 이메일 조회 테스트 구성이 명확합니다.

성공/실패 케이스가 모두 커버됩니다.


61-73: 정상 조회 테스트 OK.

도메인 변환과 기본 값 검증이 적절합니다.


75-81: 미존재 사용자 예외 테스트 OK.

예외 타입과 호출 검증이 일관됩니다.


83-115: 테스트 데이터 팩토리 구성이 일관적입니다.

재사용성과 가독성이 좋습니다.

main-modules/user/infrastructure/src/main/java/com/sidework/user/persistence/exception/UserNotFoundException.java (1)

6-9: 예외 메시지에 식별자 컨텍스트를 넣은 점이 좋습니다.

진단과 로깅에 유리합니다.

main-modules/common/src/main/java/com/sidework/common/response/status/ErrorStatus.java (1)

53-69: withDetail 확장 방식이 유연합니다.

공통 코드/상태를 유지하면서 상세 메시지 분리를 잘 지원합니다.

main-modules/user/infrastructure/src/main/java/com/sidework/user/persistence/adapter/UserPersistenceAdapter.java (3)

18-21: 저장 로직 단순하고 명확합니다.

매핑 → 저장 흐름이 깔끔합니다.


23-26: 중복 이메일 조회 위임 OK.

리포지토리 역할 분리도 적절합니다.


28-32: 미존재 사용자 예외 처리까지 포함되어 좋습니다.

도메인 예외로 매핑하는 흐름이 안정적입니다.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@main-modules/bootstrap/src/main/java/com/sidework/config/SecurityConfig.java`:
- Around line 8-14: Add a SecurityFilterChain bean to SecurityConfig so
anonymous access is allowed for signup/login: create a method named
securityFilterChain(HttpSecurity http) that configures HttpSecurity to
permitAll() for "/signup" and "/login", require authentication for anyRequest(),
disables CSRF (or configures it appropriately for your API), and returns
http.build(); keep the existing passwordEncoder() bean intact and ensure the new
bean is annotated with `@Bean` and throws Exception.
♻️ Duplicate comments (2)
main-modules/user/application/src/main/java/com/sidework/user/application/adapter/UserController.java (1)

15-24: @RequestParam 검증이 실제로 동작하지 않을 수 있음
클래스/메서드에 @Validated가 없으면 @Email/@NotNull 검증이 트리거되지 않습니다. @NotBlank로 공백도 차단하는 편이 안전합니다.

🔧 제안 수정안
+@Validated
 `@RestController`
 `@RequestMapping`("/api/v1/users")
 `@RequiredArgsConstructor`
 public class UserController {
@@
-    public ResponseEntity<ApiResponse<Boolean>> getEmailAvailable(`@RequestParam` `@Email` `@NotNull` String email) {
+    public ResponseEntity<ApiResponse<Boolean>> getEmailAvailable(
+            `@RequestParam` `@Email` `@NotBlank` String email
+    ) {
         return ResponseEntity.ok(ApiResponse.onSuccess(queryService.checkEmailExists(email)));
     }
main-modules/user/application/src/main/java/com/sidework/user/application/service/UserCommandService.java (1)

19-31: 중복 이메일 사전 검증이 없습니다

Line 29-31에서 바로 저장되어 동일 이메일 중복 생성이 가능합니다. 저장 전에 existsByEmail로 빠르게 차단하고, DB 레벨 unique 제약도 확인해주세요.

🛡️ 제안 변경
         if(command.email() == null || command.name() == null || command.nickname() == null
         || command.password() == null || command.tel() == null || command.age() == null) {
             throw new InvalidCommandException();
         }
+        if (userRepository.existsByEmail(command.email())) {
+            throw new DuplicateEmailException();
+        }
         User user = User.create(command.email(), command.name(), command.nickname(), encodePassword(command.password())
                 , command.age(), command.tel(), UserType.LOCAL);
         userRepository.save(user);
🧹 Nitpick comments (6)
main-modules/user/application/build.gradle (2)

26-26: 버전 관리 일관성 검토 필요.

다른 의존성들은 버전 카탈로그(libs.xxx)를 사용하고 있으나, jakarta.validation-api는 버전이 하드코딩되어 있습니다. 일관성을 위해 버전 카탈로그로 이동하는 것을 권장합니다.

♻️ 버전 카탈로그 적용 제안

gradle/libs.versions.toml에 버전을 추가하고:

[versions]
jakarta-validation = "3.1.1"

[libraries]
jakarta-validation-api = { module = "jakarta.validation:jakarta.validation-api", version.ref = "jakarta-validation" }

그 후 build.gradle에서:

-    implementation("jakarta.validation:jakarta.validation-api:3.1.1")
+    implementation libs.jakarta.validation.api

27-28: 불필요한 빈 줄 제거 권장.

연속된 빈 줄이 있습니다. 코드 일관성을 위해 하나로 줄이는 것이 좋습니다.

♻️ 빈 줄 정리
     implementation("jakarta.validation:jakarta.validation-api:3.1.1")
-
-
 }
main-modules/user/infrastructure/src/main/java/com/sidework/user/persistence/entity/UserEntity.java (2)

21-22: 이메일 필드에 유니크 제약조건 추가를 권장합니다.

회원가입 기능에서 이메일은 사용자 식별에 핵심적으로 사용됩니다. 데이터베이스 레벨에서 유니크 제약조건을 추가하면 동시 요청 시에도 중복 가입을 방지할 수 있습니다.

♻️ 수정 제안
-    `@Column`(name = "email", nullable = false, length = 100)
+    `@Column`(name = "email", nullable = false, length = 100, unique = true)
     private String email;

36-38: 나이 대신 생년월일 저장을 고려해 보세요.

나이를 정수로 저장하면 시간이 지남에 따라 값이 부정확해집니다. 생년월일(LocalDate birthDate)을 저장하고 필요 시 나이를 계산하는 방식이 데이터 정확성 측면에서 더 적합합니다.

♻️ 수정 제안
-    // 만 나이
-    `@Column`(name = "age", nullable = false)
-    private Integer age;
+    // 생년월일
+    `@Column`(name = "birth_date", nullable = false)
+    private LocalDate birthDate;

java.time.LocalDate import가 필요합니다.

main-modules/user/application/src/main/java/com/sidework/user/application/port/in/SignUpCommand.java (1)

7-13: 문자열 공백/나이 음수 방지 제약 추가 권장
현재 @NotNull만으로는 공백 문자열과 음수/0 나이를 허용합니다. @NotBlank, @Positive(또는 @Min)로 계약을 강화하는 편이 안전합니다.

♻️ 제안 수정안
-import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Positive;
 import jakarta.validation.constraints.Size;

 public record SignUpCommand(
-        `@NotNull` `@Email` String email,
-        `@NotNull` `@Size`(min = 8, message = "비밀번호는 최소 8자 이상이어야 합니다.") String password,
-        `@NotNull` String name,
-        `@NotNull` String nickname,
-        `@NotNull` Integer age,
-        `@NotNull` String tel
+        `@NotBlank` `@Email` String email,
+        `@NotBlank` `@Size`(min = 8, message = "비밀번호는 최소 8자 이상이어야 합니다.") String password,
+        `@NotBlank` String name,
+        `@NotBlank` String nickname,
+        `@NotNull` `@Positive` Integer age,
+        `@NotBlank` String tel
 ) {
 }
main-modules/user/application/src/main/java/com/sidework/user/application/service/UserCommandService.java (1)

10-17: PasswordEncoder 인터페이스로 의존성 역전 권장

Line 16-17에서 BCryptPasswordEncoder에 직접 의존하면 구현체 교체/테스트가 어려워집니다. Spring Security에서는 PasswordEncoder 인터페이스 주입 패턴이 일반적이니 전환을 권장합니다.

♻️ 제안 변경
-import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
@@
-    private final BCryptPasswordEncoder encoder;
+    private final PasswordEncoder encoder;
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 456a6d2 and 6e39453.

📒 Files selected for processing (15)
  • main-modules/bootstrap/build.gradle
  • main-modules/bootstrap/src/main/java/com/sidework/config/SecurityConfig.java
  • main-modules/user/application/build.gradle
  • main-modules/user/application/src/main/java/com/sidework/user/application/adapter/UserController.java
  • main-modules/user/application/src/main/java/com/sidework/user/application/port/in/SignUpCommand.java
  • main-modules/user/application/src/main/java/com/sidework/user/application/port/in/UserCommandUseCase.java
  • main-modules/user/application/src/main/java/com/sidework/user/application/port/in/UserQueryUseCase.java
  • main-modules/user/application/src/main/java/com/sidework/user/application/service/UserCommandService.java
  • main-modules/user/application/src/main/java/com/sidework/user/application/service/UserQueryService.java
  • main-modules/user/application/src/test/java/com/sidework/user/application/UserCommandServiceTest.java
  • main-modules/user/application/src/test/java/com/sidework/user/application/UserControllerTest.java
  • main-modules/user/application/src/test/java/com/sidework/user/application/UserQueryServiceTest.java
  • main-modules/user/infrastructure/build.gradle
  • main-modules/user/infrastructure/src/main/java/com/sidework/user/persistence/entity/UserEntity.java
  • main-modules/user/infrastructure/src/test/java/com/sidework/user/persistence/UserPersistenceAdapterTest.java
💤 Files with no reviewable changes (1)
  • main-modules/bootstrap/build.gradle
🚧 Files skipped from review as they are similar to previous changes (5)
  • main-modules/user/infrastructure/src/test/java/com/sidework/user/persistence/UserPersistenceAdapterTest.java
  • main-modules/user/infrastructure/build.gradle
  • main-modules/user/application/src/main/java/com/sidework/user/application/port/in/UserQueryUseCase.java
  • main-modules/user/application/src/test/java/com/sidework/user/application/UserCommandServiceTest.java
  • main-modules/user/application/src/main/java/com/sidework/user/application/port/in/UserCommandUseCase.java
🧰 Additional context used
🧬 Code graph analysis (1)
main-modules/user/application/src/main/java/com/sidework/user/application/service/UserCommandService.java (1)
main-modules/user/application/src/main/java/com/sidework/user/application/exception/InvalidCommandException.java (1)
  • InvalidCommandException (6-10)
🔇 Additional comments (9)
main-modules/user/application/src/test/java/com/sidework/user/application/UserQueryServiceTest.java (1)

15-32: 위임 검증 테스트가 적절합니다.
UserOutPort를 mock하고 existsByEmail 호출을 검증하는 흐름이 명확합니다.

main-modules/user/application/src/main/java/com/sidework/user/application/service/UserQueryService.java (1)

8-16: 서비스 책임 분리가 깔끔합니다.
use case → out port 위임 구조가 명확합니다.

main-modules/user/application/build.gradle (2)

6-12: LGTM! 멀티 모듈 라이브러리 구성이 올바릅니다.

jar.enabled = truebootJar.enabled = false 설정은 멀티 모듈 Spring Boot 프로젝트에서 라이브러리 모듈에 적합한 구성입니다. 이 모듈은 실행 가능한 JAR가 아닌 일반 JAR로 패키징됩니다.


15-21: LGTM! 회원가입 기능에 필요한 의존성이 적절하게 추가되었습니다.

Spring Security, Web, Lombok 및 테스트 의존성이 올바르게 구성되었습니다.

main-modules/user/infrastructure/src/main/java/com/sidework/user/persistence/entity/UserEntity.java (3)

9-14: LGTM! 엔티티 클래스 구조가 적절합니다.

테이블명이 users로 변경되어 예약어 충돌 문제가 해결되었습니다. BaseEntity를 상속하여 감사(auditing) 필드를 재사용하는 구조도 좋습니다.


44-47: LGTM!

EnumType.STRING을 사용하여 가독성과 마이그레이션 안정성을 확보했습니다. 컬럼 길이 10은 현재 정의된 enum 값들(LOCAL, KAKAO, GITHUB, GOOGLE)을 모두 수용합니다.


49-51: LGTM!

주석이 Boolean 타입과 일치하도록 수정되었습니다.

main-modules/user/application/src/test/java/com/sidework/user/application/UserControllerTest.java (1)

40-55: 핵심 성공 시나리오 테스트가 잘 구성되었습니다.
201 응답과 성공 플래그 검증 흐름이 명확합니다.

main-modules/user/application/src/main/java/com/sidework/user/application/service/UserCommandService.java (1)

34-35: 비밀번호 인코딩 헬퍼 분리 좋습니다

인코딩 로직을 별도 메서드로 분리해 테스트/교체가 쉬워졌습니다.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@main-modules/user/application/src/test/java/com/sidework/user/application/UserCommandServiceTest.java`:
- Around line 27-42: The test uses a mocked BCryptPasswordEncoder so
encoder.encode(...) returns null and the equality assertion is meaningless;
change the test to use a real/spy BCryptPasswordEncoder (replace `@Mock` encoder
with a `@Spy` or instantiate new BCryptPasswordEncoder and ensure the service
under test receives it) and replace the equality assertion with a password-match
check using encoder.matches(command.password(), savedUser.getPassword());
alternatively, if you must keep a mock, stub encoder.encode(...) to return a
deterministic value and assert against that stubbed value, but prefer the
spy/real encoder + encoder.matches(...) in UserCommandServiceTest around
service.signUp, encoder, and the captured User from repo.save.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6e39453 and a9a8725.

📒 Files selected for processing (1)
  • main-modules/user/application/src/test/java/com/sidework/user/application/UserCommandServiceTest.java
🧰 Additional context used
🧬 Code graph analysis (1)
main-modules/user/application/src/test/java/com/sidework/user/application/UserCommandServiceTest.java (1)
main-modules/user/application/src/main/java/com/sidework/user/application/exception/InvalidCommandException.java (1)
  • InvalidCommandException (6-10)

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

private final BCryptPasswordEncoder encoder;

@Override
public void signUp(SignUpCommand command) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

signUp 함수에 @transactional 걸면 좋을 듯

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ㅇㅋㅇㅋ 추가할게

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아키텍처 구조 파악하면서 하나 궁금한게

application에는 domain, common
Infrastructure에는 domain, common, application 의존성 추가하는데

bootstrap에는 implementation project(:main-modules:user:infrastructure) 이거 추가 안 해도 되나?
implementation project(':main-modules:common')은 추가되어 있길래

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아 넣는 게 맞음.
왜 뺐냐면 헥사고날 아키텍쳐에서는 bootstrap에서 컨트롤러도 포함하는데 모듈리스에서는 도메인 별로 모듈을 갖추니까 어댑터의 일종인 컨트롤러를 bootstrap에 넣는 게 모호하더라고. 그래서 도메인 모듈로 뺐는데 넣는 게 맞는 듯.

@kamillcream kamillcream merged commit c6c19c8 into main Jan 17, 2026
1 check was pending
@kamillcream kamillcream deleted the feat/#3-user-signup-login branch January 17, 2026 13:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feat] User 도메인 - 회원가입

3 participants