-
Notifications
You must be signed in to change notification settings - Fork 44
[volume-1] 회원가입, 내 정보 조회, 비밀번호 변경 기능 구현 #49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| --- | ||
| name: requirements-analysis | ||
| description: | ||
| 제공된 요구사항을 분석하고, 개발자와의 질문/대답을 통해 애매한 요구사항을 명확히 하여 정리합니다. | ||
| 모든 정리가 끝나면, 시퀀스 다이어그램, 클래스 다이어그램, ERD 등을 Mermaid 문법으로 작성한다. | ||
| 요구사항이 제공되었을 때, 코드를 작성하기 전 이를 명확히 하는 데에 사용합니다. | ||
| --- | ||
| 요구사항을 분석할 때 반드시 다음 흐름을 따른다. | ||
| ### 1️⃣ 요구사항을 그대로 믿지 말고, 문제 상황으로 다시 설명한다. | ||
| - 요구사항 문장을 정리하는 데서 끝내지 않는다. | ||
| - "무엇을 만들까?"가 아니라 "지금 어떤 문제가 있고, 그걸 왜 해결하려는가?" 로 재해석한다. | ||
| - 다음 관점을 분리해서 정리한다: | ||
| - 사용자 관점 | ||
| - 비즈니스 관점 | ||
| - 시스템 관점 | ||
| > 예시 | ||
| > "주문 실패 시 결제를 취소한다" → "결제 성공/실패와 주문 상태가 어긋나지 않도록 일관성을 유지하려는 문제" | ||
| ### 2️⃣ 애매한 요구사항을 숨기지 말고 드러낸다 | ||
| - 추측하거나 알아서 결정하지 않는다. | ||
| - 요구사항에서 결정되지 않은 부분을 명시적으로 나열한다. | ||
| **다음 유형의 질문을 반드시 포함한다:** | ||
| - 정책 질문: 기준 시점, 성공/실패 조건, 예외 처리 규칙 | ||
| - 경계 질문: 어디까지가 한 책임인가, 어디서 분리되는가 | ||
| - 확장 질문: 나중에 바뀔 가능성이 있는가 | ||
|
|
||
| ### 3️⃣ 요구사항 명확화를 위한 질문을 개발자 답변이 쉬운 형태로 제시한다 | ||
| - 질문은 우선순위를 가진다 (중요한 것부터). | ||
| - 선택지가 있는 경우, 옵션 + 영향도를 함께 제시한다. | ||
| > 형식 예시: | ||
| - 선택지 A: 하나의 트랜잭션으로 처리 → 구현 단순, 확장성 낮음 | ||
| - 선택지 B: 단계별 분리 → 구조 복잡, 확장/보상 처리 유리 | ||
|
|
||
| ### 4️⃣ 합의된 내용을 바탕으로 개념 모델부터 잡는다 | ||
| - 바로 코드나 기술 얘기로 들어가지 않는다. | ||
| - 먼저 다음을 정의한다: | ||
| - 액터 (사용자, 외부 시스템) | ||
| - 핵심 도메인 | ||
| - 보조/외부 시스템 | ||
| - 이 단계는 “구현”이 아니라 설계 사고 정렬이 목적이다. | ||
|
|
||
| ### 5️⃣ 다이어그램은 항상 이유 → 다이어그램 → 해석 순서로 제시한다 | ||
| **다이어그램을 그리기 전에 반드시 설명한다** | ||
| - 왜 이 다이어그램이 필요한지 | ||
| - 이 다이어그램으로 무엇을 검증하려는지 | ||
|
|
||
| **다이어그램은 Mermaid 문법으로 작성한다** | ||
| 사용 기준: | ||
| - **시퀀스 다이어그램** | ||
| - 책임 분리 | ||
| - 호출 순서 | ||
| - 트랜잭션 경계 확인 | ||
| - **클래스 다이어그램** | ||
| - 도메인 책임 | ||
| - 의존 방향 | ||
| - 응집도 확인 | ||
| - **ERD** | ||
| - 영속성 구조 | ||
| - 관계의 주인 | ||
| - 정규화 여부 | ||
|
|
||
| ### 6️⃣ 다이어그램을 던지고 끝내지 말고 읽는 법을 짚어준다 | ||
| - "이 구조에서 특히 봐야 할 포인트"를 2~3줄로 설명한다. | ||
| - 설계 의도가 드러나도록 해석을 붙인다. | ||
|
|
||
| ### 7️⃣ 설계의 잠재 리스크를 반드시 언급한다 | ||
| - 현재 설계가 가질 수 있는 위험을 숨기지 않는다. | ||
| - 트랜잭션 비대화 | ||
| - 도메인 간 결합도 증가 | ||
| - 정책 변경 시 영향 범위 확대 | ||
| - 해결책은 정답처럼 말하지 않고 선택지로 제시한다. | ||
|
|
||
| ### 톤 & 스타일 가이드 | ||
| - 강의처럼 설명하지 말고 설계 리뷰 톤을 유지한다 | ||
| - 정답이라고 제시하기보다, 다른 선택지가 있다면 이를 제공하도록 한다. | ||
| - 코드보다 의도, 책임, 경계를 더 중요하게 다룬다 | ||
| - 구현 전에 생각해야 할 것을 끌어내는 데 집중한다 |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| package com.loopers.config; | ||
|
|
||
| import org.springframework.context.annotation.Bean; | ||
| import org.springframework.context.annotation.Configuration; | ||
| import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; | ||
| import org.springframework.security.crypto.password.PasswordEncoder; | ||
|
|
||
| @Configuration | ||
| public class SecurityConfig { | ||
|
|
||
| @Bean | ||
| public PasswordEncoder passwordEncoder() { | ||
| return new BCryptPasswordEncoder(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| package com.loopers.user.controller; | ||
|
|
||
| import com.loopers.user.domain.User; | ||
| import com.loopers.user.dto.ChangePasswordRequest; | ||
| import com.loopers.user.dto.CreateUserRequest; | ||
| import com.loopers.user.dto.CreateUserResponse; | ||
| import com.loopers.user.dto.GetMyInfoResponse; | ||
| import com.loopers.user.service.UserService; | ||
| import jakarta.validation.Valid; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.http.HttpStatus; | ||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.web.bind.annotation.*; | ||
|
|
||
| @RequiredArgsConstructor | ||
| @RestController | ||
| @RequestMapping("/api/v1/users") | ||
| public class UserController { | ||
|
|
||
| public static final String LOGIN_ID_HEADER = "X-Loopers-LoginId"; | ||
| public static final String LOGIN_PW_HEADER = "X-Loopers-LoginPw"; | ||
|
|
||
| private final UserService userService; | ||
|
|
||
| @PostMapping | ||
| public ResponseEntity<CreateUserResponse> createUser(@Valid @RequestBody CreateUserRequest request) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: find apps/commerce-api -name "UserController.java" -type fRepository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 164 🏁 Script executed: find apps/commerce-api -name "*ApiControllerAdvice*" -o -name "*ControllerAdvice*" | head -20Repository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 168 🏁 Script executed: find apps/commerce-api -path "*/config/*" -name "*.java" | grep -i adviceRepository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 67 🏁 Script executed: cat -n apps/commerce-api/src/main/java/com/loopers/user/controller/UserController.javaRepository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 2195 🏁 Script executed: cat -n apps/commerce-api/src/main/java/com/loopers/interfaces/api/ApiControllerAdvice.javaRepository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 6820 🏁 Script executed: find apps/commerce-api -name "CreateUserRequest.java" -o -name "ChangePasswordRequest.java"Repository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 240 🏁 Script executed: find apps/commerce-api -path "*/test/*" -name "*UserController*Test*.java"Repository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 168 🏁 Script executed: cat -n apps/commerce-api/src/main/java/com/loopers/user/dto/CreateUserRequest.javaRepository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 765 🏁 Script executed: cat -n apps/commerce-api/src/main/java/com/loopers/user/dto/ChangePasswordRequest.javaRepository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 315 🏁 Script executed: cat -n apps/commerce-api/src/test/java/com/loopers/user/controller/UserControllerTest.javaRepository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 5536 🏁 Script executed: find apps/commerce-api -name "GlobalExceptionHandler.java"Repository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 171 🏁 Script executed: cat -n apps/commerce-api/src/main/java/com/loopers/user/exception/GlobalExceptionHandler.javaRepository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 2606 🏁 Script executed: find apps/commerce-api -name "pom.xml" -o -name "build.gradle" -o -name "build.gradle.kts" | head -1 | xargs cat | grep -A 5 -B 5 "spring-boot\|spring-webmvc" | head -40Repository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 606 🏁 Script executed: rg "MethodArgumentNotValidException" apps/commerce-apiRepository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 576 @Valid 제거하고 응답 포맷 일관성 확보 필요
또한 비밀번호를 X-Loopers-LoginPw 헤더로 전달하면 로그, 프록시, APM에서 민감정보가 노출될 수 있으므로 요청 본문으로 이동하는 것이 필요하다. 수정 제안-import jakarta.validation.Valid;
@@
- public ResponseEntity<CreateUserResponse> createUser(`@Valid` `@RequestBody` CreateUserRequest request) {
+ public ResponseEntity<CreateUserResponse> createUser(`@RequestBody` CreateUserRequest request) {
@@
- public ResponseEntity<Void> changePassword(
+ public ResponseEntity<Void> changePassword(
`@RequestHeader`(LOGIN_ID_HEADER) String loginId,
- `@RequestHeader`(LOGIN_PW_HEADER) String currentPassword,
- `@Valid` `@RequestBody` ChangePasswordRequest request
+ `@RequestBody` ChangePasswordRequest request
) {
- userService.changePassword(loginId, currentPassword, request.newPassword());
+ userService.changePassword(loginId, request.currentPassword(), request.newPassword()); |
||
| User user = userService.createUser(request); | ||
| return ResponseEntity.status(HttpStatus.CREATED).body(CreateUserResponse.from(user)); | ||
| } | ||
|
|
||
| @GetMapping("/me") | ||
| public ResponseEntity<GetMyInfoResponse> getMyInfo( | ||
| @RequestHeader(LOGIN_ID_HEADER) String loginId | ||
| ) { | ||
| GetMyInfoResponse response = userService.getMyInfo(loginId); | ||
| return ResponseEntity.ok(response); | ||
| } | ||
|
|
||
| @PatchMapping("/password") | ||
| public ResponseEntity<Void> changePassword( | ||
| @RequestHeader(LOGIN_ID_HEADER) String loginId, | ||
| @RequestHeader(LOGIN_PW_HEADER) String currentPassword, | ||
| @Valid @RequestBody ChangePasswordRequest request | ||
|
Comment on lines
+41
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 비밀번호를 헤더로 전달하면 노출 위험이 큼 수정 제안- public ResponseEntity<Void> changePassword(
- `@RequestHeader`(LOGIN_ID_HEADER) String loginId,
- `@RequestHeader`(LOGIN_PW_HEADER) String currentPassword,
- `@RequestBody` ChangePasswordRequest request
- ) {
- userService.changePassword(loginId, currentPassword, request.newPassword());
+ public ResponseEntity<Void> changePassword(
+ `@RequestHeader`(LOGIN_ID_HEADER) String loginId,
+ `@RequestBody` ChangePasswordRequest request
+ ) {
+ userService.changePassword(loginId, request.currentPassword(), request.newPassword());
return ResponseEntity.ok().build();
}As per coding guidelines '로깅 시 민감정보 노출 가능성을 점검한다.'를 따랐다. 🤖 Prompt for AI Agents |
||
| ) { | ||
| userService.changePassword(loginId, currentPassword, request.newPassword()); | ||
| return ResponseEntity.ok().build(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| package com.loopers.user.domain; | ||
|
|
||
| import com.loopers.domain.BaseEntity; | ||
| import jakarta.persistence.*; | ||
| import org.springframework.util.Assert; | ||
| import lombok.AccessLevel; | ||
| import lombok.Builder; | ||
| import lombok.Getter; | ||
| import lombok.NoArgsConstructor; | ||
|
|
||
| @Entity | ||
| @Table(name = "users") | ||
| @Getter | ||
| @NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
| public class User extends BaseEntity { | ||
|
|
||
| @Column(nullable = false, length = 10, unique = true) | ||
| private String loginId; | ||
|
|
||
| @Column(nullable = false) | ||
| private String password; | ||
|
|
||
| @Column(nullable = false) | ||
| private String name; | ||
|
|
||
| @Column(nullable = false) | ||
| private String birthDate; | ||
|
|
||
| @Column(nullable = false) | ||
| private String email; | ||
|
|
||
| @Builder | ||
| public User(String loginId, String password, String name, String birthDate, String email) { | ||
| validateRequired(loginId, password, name, birthDate, email); | ||
|
|
||
| this.loginId = loginId; | ||
| this.password = password; | ||
| this.name = name; | ||
| this.birthDate = birthDate; | ||
| this.email = email; | ||
| } | ||
|
|
||
| private void validateRequired(String loginId, String password, String name, String birthDate, String email) { | ||
| Assert.hasText(loginId, "loginId는 필수입니다"); | ||
| Assert.hasText(password, "password는 필수입니다"); | ||
| Assert.hasText(name, "name은 필수입니다"); | ||
| Assert.hasText(birthDate, "birthDate는 필수입니다"); | ||
| Assert.hasText(email, "email은 필수입니다"); | ||
| } | ||
|
|
||
| public String getMaskedName() { | ||
| if (name.length() == 1) { | ||
| return "*"; | ||
| } | ||
| return name.substring(0, name.length() - 1) + "*"; | ||
| } | ||
|
|
||
| public void changePassword(String newPassword) { | ||
| Assert.hasText(newPassword, "새 비밀번호는 필수입니다"); | ||
| this.password = newPassword; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| package com.loopers.user.dto; | ||
|
|
||
| import jakarta.validation.constraints.NotBlank; | ||
|
|
||
| public record ChangePasswordRequest( | ||
| @NotBlank | ||
| String newPassword | ||
|
Comment on lines
+3
to
+7
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# 1. ChangePasswordRequest 파일 확인
find . -name "ChangePasswordRequest.java" -type f | head -5Repository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 166 🏁 Script executed: #!/bin/bash
# 2. 프로젝트 전체 DTO의 Bean Validation 사용 패턴 확인
rg -n '@NotBlank|@Email|@Pattern|@Valid|jakarta\.validation' -g '*.java' -A 2 -B 2 | head -100Repository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 6330 🏁 Script executed: #!/bin/bash
# 3. 프로젝트 구조와 User 관련 서비스/도메인 파일 확인
find . -path '*/user/*' -name '*.java' -type f | grep -E '(Service|Domain|Policy)' | head -20Repository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 331 🏁 Script executed: #!/bin/bash
# 4. UserService의 changePassword 메서드 확인
cat -n ./apps/commerce-api/src/main/java/com/loopers/user/service/UserService.javaRepository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 3194 🏁 Script executed: #!/bin/bash
# 5. PasswordPolicy 파일 찾기 및 내용 확인
find . -name "*PasswordPolicy*" -type fRepository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 67 🏁 Script executed: #!/bin/bash
# 6. 에러 핸들링 구조 확인 - CoreException과 ApiControllerAdvice 패턴
find . -name "*ControllerAdvice*" -o -name "*CoreException*" | head -10Repository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 332 🏁 Script executed: #!/bin/bash
# 7. ApiControllerAdvice 확인 - MethodArgumentNotValidException 핸들링 여부
cat -n ./apps/commerce-api/src/main/java/com/loopers/interfaces/api/ApiControllerAdvice.javaRepository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 6820 🏁 Script executed: #!/bin/bash
# 8. PasswordValidator 확인
find . -name "PasswordValidator.java" -type f | xargs cat -nRepository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 1039 ChangePasswordRequest의
수정안으로 다음 항목이 필요하다:
추가 테스트로 newPassword가 null/blank/정책 위배인 경우 각각 BAD_REQUEST 상태 코드와 통일된 ApiResponse 형식으로 응답되는지 검증해야 한다. 🤖 Prompt for AI Agents |
||
| ) { | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| package com.loopers.user.dto; | ||
|
|
||
| import jakarta.validation.constraints.Email; | ||
| import jakarta.validation.constraints.NotBlank; | ||
| import jakarta.validation.constraints.Pattern; | ||
|
|
||
| public record CreateUserRequest( | ||
| @NotBlank | ||
| @Pattern(regexp = "^[a-zA-Z0-9]+$") | ||
| String loginId, | ||
| @NotBlank | ||
| String password, | ||
| @NotBlank | ||
| String name, | ||
| @NotBlank | ||
| @Pattern(regexp = "\\d{4}-\\d{2}-\\d{2}") | ||
| String birthDate, | ||
| @NotBlank | ||
| String email | ||
|
Comment on lines
+3
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # User 엔티티 찾기
fd -e java User | grep -E '(entity|domain)' | head -20Repository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 220 🏁 Script executed: # CreateUserRequest 파일 확인
fd CreateUserRequest -e javaRepository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 257 🏁 Script executed: # UserService 찾기
fd UserService -e javaRepository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 325 🏁 Script executed: # 프로젝트의 Bean Validation 사용 현황 전체 파악
rg 'jakarta\.validation|@NotBlank|@Email|@Pattern' -g '*.java' -A 2 -B 2 | head -80Repository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 4839 🏁 Script executed: # 다른 DTO들의 검증 패턴 확인
fd -e java -path '*/dto/*' | head -20Repository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 253 🏁 Script executed: cat -n apps/commerce-api/src/main/java/com/loopers/user/domain/User.javaRepository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 2253 🏁 Script executed: cat -n apps/commerce-api/src/main/java/com/loopers/user/service/UserService.javaRepository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 3194 🏁 Script executed: cat -n apps/commerce-api/src/test/java/com/loopers/user/controller/CreateUserRequestValidationTest.javaRepository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 5154 🏁 Script executed: fd PasswordValidator -e javaRepository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 252 🏁 Script executed: cat -n apps/commerce-api/src/main/java/com/loopers/user/validator/PasswordValidator.javaRepository: Loopers-dev-lab/loop-pack-be-l2-vol3-java Length of output: 1039 DTO의 Bean Validation 어노테이션을 제거하고 도메인 레이어 검증으로 일원화해야 한다 현재 수정안으로 다음을 진행해야 한다:
🛠️ 수정 예시-import jakarta.validation.constraints.Email;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.Pattern;
-
public record CreateUserRequest(
- `@NotBlank`
- `@Pattern`(regexp = "^[a-zA-Z0-9]+$")
String loginId,
- `@NotBlank`
String password,
- `@NotBlank`
String name,
- `@NotBlank`
- `@Pattern`(regexp = "\\d{4}-\\d{2}-\\d{2}")
String birthDate,
- `@Email`
- `@NotBlank`
String email
) {
}UserService.createUser()에 검증 로직 추가: public User createUser(CreateUserRequest request) {
LoginIdValidator.validate(request.loginId()); // 추가
BirthDateValidator.validate(request.birthDate()); // 추가
EmailValidator.validate(request.email()); // 추가
if(userRepository.existsByLoginId(request.loginId())){
throw new DuplicateLoginIdException();
}
PasswordValidator.validate(request.password(), request.birthDate());
// ...
}🤖 Prompt for AI Agents |
||
| ) { | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| package com.loopers.user.dto; | ||
|
|
||
| import com.loopers.user.domain.User; | ||
|
|
||
| public record CreateUserResponse( | ||
| Long id, | ||
| String loginId, | ||
| String name, | ||
| String email, | ||
| String birthDate | ||
| ) { | ||
| public static CreateUserResponse from(User user) { | ||
| return new CreateUserResponse( | ||
| user.getId(), | ||
| user.getLoginId(), | ||
| user.getName(), | ||
| user.getEmail(), | ||
| user.getBirthDate() | ||
| ); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| package com.loopers.user.dto; | ||
|
|
||
| import com.loopers.user.domain.User; | ||
|
|
||
| public record GetMyInfoResponse( | ||
| String loginId, | ||
| String name, | ||
| String birthDate, | ||
| String email | ||
| ) { | ||
| public static GetMyInfoResponse from(User user) { | ||
| return new GetMyInfoResponse( | ||
| user.getLoginId(), | ||
| user.getMaskedName(), | ||
| user.getBirthDate(), | ||
| user.getEmail() | ||
| ); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| package com.loopers.user.exception; | ||
|
|
||
| public class DuplicateLoginIdException extends RuntimeException { | ||
|
|
||
| private static final String DEFAULT_MESSAGE = "이미 사용 중인 로그인 ID입니다."; | ||
|
|
||
| public DuplicateLoginIdException() { | ||
| super(DEFAULT_MESSAGE); | ||
| } | ||
|
|
||
| public DuplicateLoginIdException(String message) { | ||
| super(message); | ||
| } | ||
|
Comment on lines
+3
to
+13
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CoreException 경로로 통일해 예외 응답 포맷을 보장해야 한다 Based on learnings: In the loop-pack-be-l2-vol3-java project, enforce unified error handling by routing errors through CoreException to ApiControllerAdvice to ensure a consistent response format. Do not introduce MethodArgumentNotValidException handlers or Bean Validation handling, as that would create inconsistent error handling patterns. This guidance applies to all Java files under the commerce-api module (source code under apps/commerce-api/src/main/java/). 🤖 Prompt for AI Agents |
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: Loopers-dev-lab/loop-pack-be-l2-vol3-java
Length of output: 429
🏁 Script executed:
Repository: Loopers-dev-lab/loop-pack-be-l2-vol3-java
Length of output: 314
🏁 Script executed:
Repository: Loopers-dev-lab/loop-pack-be-l2-vol3-java
Length of output: 4538
🏁 Script executed:
Repository: Loopers-dev-lab/loop-pack-be-l2-vol3-java
Length of output: 126
🏁 Script executed:
# gradle.properties 확인 cat -n gradle.propertiesRepository: Loopers-dev-lab/loop-pack-be-l2-vol3-java
Length of output: 747
🏁 Script executed:
# apps/commerce-api/build.gradle.kts 전체 내용 확인 cat -n apps/commerce-api/build.gradle.ktsRepository: Loopers-dev-lab/loop-pack-be-l2-vol3-java
Length of output: 1269
🏁 Script executed:
# settings.gradle.kts 확인 cat -n settings.gradle.ktsRepository: Loopers-dev-lab/loop-pack-be-l2-vol3-java
Length of output: 1230
🏁 Script executed:
Repository: Loopers-dev-lab/loop-pack-be-l2-vol3-java
Length of output: 67
🏁 Script executed:
Repository: Loopers-dev-lab/loop-pack-be-l2-vol3-java
Length of output: 110
🏁 Script executed:
Repository: Loopers-dev-lab/loop-pack-be-l2-vol3-java
Length of output: 67
🏁 Script executed:
Repository: Loopers-dev-lab/loop-pack-be-l2-vol3-java
Length of output: 129
🏁 Script executed:
Repository: Loopers-dev-lab/loop-pack-be-l2-vol3-java
Length of output: 67
🏁 Script executed:
Repository: Loopers-dev-lab/loop-pack-be-l2-vol3-java
Length of output: 121
🏁 Script executed:
Repository: Loopers-dev-lab/loop-pack-be-l2-vol3-java
Length of output: 141
명시적 버전 관리와 보안 검증 프로세스 추가
spring-security-crypto는 Spring Boot BOM을 통해 관리되는 표준 방식이나, 실제 해석되는 버전을 추적하고 보안 패치 적용을 보증하기 위해 다음을 수행해야 한다.
🤖 Prompt for AI Agents