feat: 어드민 유저 관리 기능 추가#686
Conversation
- 차단 기능 rebase 및 충돌 해결
- University -> HostUniversity 변경
Walkthrough
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (8)
src/main/java/com/example/solidconnection/admin/dto/RestrictedUserSearchResponse.java (1)
6-12:reportedInfoResponse의null가능성을 타입 수준에서 표현해 주세요.
- 현재 상태
BannedInfoResponse는isBanned = false형태로 항상 존재할 수 있지만,reportedInfoResponse는 차단만 된 사용자(신고 이력 없음)에게null일 수 있습니다.- 제안 사항
- 두 필드에
@Nullable어노테이션으로 의도를 명시하면, 서비스·리포지터리 레이어에서 null 처리를 명확히 할 수 있습니다:+import org.springframework.lang.Nullable; public record RestrictedUserSearchResponse( String nickname, Role role, UserStatus userStatus, + `@Nullable` ReportedInfoResponse reportedInfoResponse, + `@Nullable` BannedInfoResponse bannedInfoResponse ) {}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/com/example/solidconnection/admin/dto/RestrictedUserSearchResponse.java` around lines 6 - 12, The record component reportedInfoResponse in RestrictedUserSearchResponse can be null but this isn't expressed in the type; annotate the component with a `@Nullable` annotation (e.g., org.springframework.lang.Nullable or javax.annotation.Nullable) on the reportedInfoResponse component in the RestrictedUserSearchResponse record declaration so callers and static tools know it may be null, and add the corresponding import; leave BannedInfoResponse unchanged.src/main/java/com/example/solidconnection/admin/dto/BannedInfoResponse.java (1)
7-7:duration은isBanned = false일 때 의미가 없는 필드입니다.
- 현재 상태
- 차단되지 않은 경우(
isBanned = false),duration은null이 될 수 있으나 이에 대한 안내가 없습니다.- 제안 사항
- 최소한
@Nullable어노테이션으로 의도를 명시하거나 Javadoc으로 보완하면 소비하는 쪽에서 NPE를 예방할 수 있습니다.+import org.springframework.lang.Nullable; public record BannedInfoResponse( boolean isBanned, + `@Nullable` UserBanDuration duration ) {}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/com/example/solidconnection/admin/dto/BannedInfoResponse.java` at line 7, The duration field in BannedInfoResponse (UserBanDuration duration) can be null when isBanned == false; annotate the field (and its getter/constructor parameter if present) with a `@Nullable` annotation (e.g., org.jetbrains.annotations.Nullable or javax.annotation.Nullable used in the project) and/or add a one-line Javadoc on the duration field explaining "nullable when isBanned is false" so callers know to null-check; update imports and any serialization/deserialization hints (e.g., Jackson) if needed to preserve nullability.src/main/java/com/example/solidconnection/admin/dto/MentorApplicationHistoryInfoResponse.java (1)
6-10: 기존MentorApplicationHistoryResponse와의 네이밍 유사성을 확인해주세요.기존 코드에 이미
MentorApplicationHistoryResponse가 존재하며, 이 새 레코드는id와applicationOrder를 제외한 부분집합입니다.
- 현재 네이밍:
MentorApplicationHistoryInfoResponse—Info접미사만으로 구분됩니다.- 혼동 가능성: 두 DTO가 유사한 이름을 가져 개발자가 실수로 잘못된 타입을 사용할 수 있습니다.
대안으로
MentorApplicationHistorySummaryResponse같은 이름이 용도 차이를 더 명확히 드러낼 수 있으나, 프로젝트 전체 네이밍 컨벤션에 맞추시는 것이 우선입니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/com/example/solidconnection/admin/dto/MentorApplicationHistoryInfoResponse.java` around lines 6 - 10, Rename the DTO class MentorApplicationHistoryInfoResponse to a clearer, non-ambiguous name (e.g., MentorApplicationHistorySummaryResponse) to avoid confusion with the existing MentorApplicationHistoryResponse; update all references/usages of MentorApplicationHistoryInfoResponse (constructors, imports, tests, serializers) accordingly and ensure the new name matches the project's DTO naming conventions.src/main/java/com/example/solidconnection/admin/dto/UserInfoDetailResponse.java (1)
5-9: Nullable 필드에 대한@Nullable어노테이션 추가를 권장드립니다.현재 주석으로 null 가능성을 잘 설명해주셨지만,
@Nullable어노테이션을 함께 사용하면 다음과 같은 장점이 있습니다:
- 정적 분석 도구가 null 안전성을 자동으로 검증할 수 있습니다.
- API 문서 생성 시 nullable 여부가 자동 반영됩니다.
- JSON 직렬화 라이브러리(Jackson 등)와의 연동에도 명확한 시그널을 줍니다.
♻️ 참고 예시
+import org.springframework.lang.Nullable; + public record UserInfoDetailResponse( - MentorInfoResponse mentorInfoResponse, // 멘티일 경우 null - MenteeInfoResponse menteeInfoResponse, // 멘토일 경우 null + `@Nullable` MentorInfoResponse mentorInfoResponse, // 멘티일 경우 null + `@Nullable` MenteeInfoResponse menteeInfoResponse, // 멘토일 경우 null List<ReportedHistoryResponse> reportedHistoryResponses ) {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/com/example/solidconnection/admin/dto/UserInfoDetailResponse.java` around lines 5 - 9, Add nullable annotations to the record components in UserInfoDetailResponse: annotate MentorInfoResponse mentorInfoResponse and MenteeInfoResponse menteeInfoResponse (and optionally List<ReportedHistoryResponse> reportedHistoryResponses if it can be null) with `@Nullable` (e.g., org.springframework.lang.Nullable) and add the corresponding import; this makes nullability explicit for static analysis, docs and serializers while leaving the record signature otherwise unchanged.src/main/java/com/example/solidconnection/admin/service/AdminUserService.java (1)
38-50:siteUser.getId()대신userId를 바로 전달해도 됩니다.
findById(userId)로 존재 여부를 검증하는 것은 좋습니다.- 하지만 검증 후
siteUser.getId()를 호출하는 것은 입력받은userId와 동일한 값이므로 불필요한 참조입니다.userId를 직접 전달하면 의도가 더 명확해집니다.♻️ 제안된 수정
`@Transactional`(readOnly = true) public UserInfoDetailResponse getUserInfoDetail(long userId) { - SiteUser siteUser = siteUserRepository.findById(userId) + siteUserRepository.findById(userId) .orElseThrow(() -> new CustomException(USER_NOT_FOUND)); - return siteUserFilterRepository.getUserInfoDetailByUserId(siteUser.getId()); + return siteUserFilterRepository.getUserInfoDetailByUserId(userId); } `@Transactional`(readOnly = true) public RestrictedUserInfoDetailResponse getRestrictedUserInfoDetail(long userId) { - SiteUser siteUser = siteUserRepository.findById(userId) + siteUserRepository.findById(userId) .orElseThrow(() -> new CustomException(USER_NOT_FOUND)); - return siteUserFilterRepository.getRestrictedUserInfoDetail(siteUser.getId()); + return siteUserFilterRepository.getRestrictedUserInfoDetail(userId); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/com/example/solidconnection/admin/service/AdminUserService.java` around lines 38 - 50, The existence check using siteUserRepository.findById(userId) is fine but calling siteUser.getId() afterward is redundant; in both getUserInfoDetail and getRestrictedUserInfoDetail replace the siteUser.getId() argument passed to siteUserFilterRepository.getUserInfoDetailByUserId and getRestrictedUserInfoDetail respectively with the original userId parameter to make the intent clearer and avoid unnecessary object access while keeping the same validation via siteUserRepository.src/test/java/com/example/solidconnection/admin/service/AdminUserServiceTest.java (1)
276-277:@DisplayName어노테이션이 일부@Nested클래스에 누락되어 있습니다.
전체_유저_검색(Line 93)과유저_상세_정보_조회(Line 178) 클래스에는@DisplayName이 있습니다.- 그런데
신고_차단된_유저_검색(Line 277)과신고_차단된_유저_상세_정보_조회(Line 362)에는 빠져 있어 테스트 리포트에서 일관성이 깨집니다.Also applies to: 361-362
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/test/java/com/example/solidconnection/admin/service/AdminUserServiceTest.java` around lines 276 - 277, Add missing `@DisplayName` annotations to the nested test classes 신고_차단된_유저_검색 and 신고_차단된_유저_상세_정보_조회 so test reports match the style used for 전체_유저_검색 and 유저_상세_정보_조회; locate the `@Nested` class declarations for 신고_차단된_유저_검색 and 신고_차단된_유저_상세_정보_조회 and add a `@DisplayName` with an appropriate Korean description (e.g., matching the wording pattern used in 전체_유저_검색 / 유저_상세_정보_조회) directly above each class declaration.src/main/java/com/example/solidconnection/siteuser/repository/custom/SiteUserFilterRepositoryImpl.java (1)
290-316: 멘토 상세 조회 시 여러 번의 개별 쿼리가 실행됩니다.
fetchMentorInfo내에서 멘토 ID 조회 → 멘티 정보 조회 → 멘토 신청 이력 조회로 최대 3회의 쿼리가 실행됩니다.fetchMenteeInfo도 유사하게 여러 쿼리를 수행합니다.- 단일 유저 상세 조회이므로 현재로서는 큰 성능 이슈는 아니지만, 향후 배치 조회 등으로 확장될 경우 단일 쿼리로 최적화하는 것을 고려해 주세요.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/com/example/solidconnection/siteuser/repository/custom/SiteUserFilterRepositoryImpl.java` around lines 290 - 316, fetchMentorInfo currently issues up to three separate queries (select mentor.id, fetch menteeInfos, fetch mentorApplicationHistory); consolidate into a single query to avoid N+1/extra roundtrips by using left joins or subqueries in one query with queryFactory: join siteUser -> leftJoin(mentor) -> leftJoin(mentoring).on(mentoring.mentorId.eq(mentor.id)) and leftJoin(mentorApplication).on(mentorApplication.siteUserId.eq(siteUser.id)), select and map MATCHED_INFO_RESPONSE_PROJECTION and MENTOR_APPLICATION_HISTORY_RESPONSE_PROJECTION (or use grouping/transformers) so MentorInfoResponse is constructed from a single fetch; apply the same approach to fetchMenteeInfo to eliminate its multiple queries.src/main/java/com/example/solidconnection/siteuser/repository/custom/SiteUserFilterRepository.java (1)
1-21:siteuser.repository패키지에서admin.dto에 직접 의존하고 있습니다.
SiteUserFilterRepository는 도메인/인프라 계층에 위치하지만, 반환 타입이 모두admin.dto패키지의 DTO입니다.- 이렇게 되면 도메인 레이어가 특정 표현 계층(admin)에 결합됩니다.
- 당장은 문제가 없지만, 추후 다른 컨텍스트에서 동일한 쿼리를 재사용해야 할 때 리팩토링이 필요해질 수 있습니다.
- 대안으로, 이 인터페이스와 구현체를
admin패키지 하위로 이동하거나, 도메인 중립적인 projection을 반환한 뒤 서비스 계층에서 변환하는 방법이 있습니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/com/example/solidconnection/siteuser/repository/custom/SiteUserFilterRepository.java` around lines 1 - 21, SiteUserFilterRepository currently depends on admin.dto types (UserSearchResponse, RestrictedUserSearchResponse, UserInfoDetailResponse, RestrictedUserInfoDetailResponse) which couples the domain/infra layer to the admin presentation layer; either move the interface and its implementation into the admin package (so symbols SiteUserFilterRepository and its methods searchAllUsers, searchRestrictedUsers, getUserInfoDetailByUserId, getRestrictedUserInfoDetail live under com.example.solidconnection.admin.*) or change the repository API to return domain-neutral projections/DTOs (e.g., UserSearchProjection, RestrictedUserSearchProjection, UserInfoProjection) defined in a domain- or repository-level package and perform mapping to admin.dto types in the admin service layer; update the implementation and callers accordingly to use the chosen projection types or new package location.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/main/java/com/example/solidconnection/admin/dto/BannedInfoResponse.java`:
- Around line 5-8: The boolean record component is serialized as "banned"
because Jackson strips the "is" prefix; update the BannedInfoResponse record to
explicitly name the JSON property by annotating the boolean component with
`@JsonProperty`("isBanned") (i.e., add import
com.fasterxml.jackson.annotation.JsonProperty and annotate the component
declaration `@JsonProperty("isBanned") boolean isBanned`) so the generated JSON
key matches the expected "isBanned".
In `@src/main/java/com/example/solidconnection/admin/dto/MenteeInfoResponse.java`:
- Around line 5-8: Rename the record component univApplyInfos to univApplyInfo
in the MenteeInfoResponse record to match its single-object type
UnivApplyInfoResponse (leave mentorInfos as-is); update all references/usages of
MenteeInfoResponse.univApplyInfos to MenteeInfoResponse.univApplyInfo and adjust
any constructors, mappers or serializers that reference the old name.
In
`@src/main/java/com/example/solidconnection/siteuser/repository/custom/SiteUserFilterRepositoryImpl.java`:
- Around line 75-83: RESTRICTED_USER_SEARCH_RESPONSE_PROJECTION currently omits
the user ID; add siteUser.id to the Projections.constructor argument list
(matching the same position/ordering used in USER_SEARCH_RESPONSE_PROJECTION) so
RestrictedUserSearchResponse receives the ID for links to /restricted/{user-id};
if necessary, update RestrictedUserSearchResponse's constructor to accept the id
parameter to match the new projection signature.
- Around line 68-73: BANNED_INFO_RESPONSE_PROJECTION currently mixes
siteUser.userStatus and userBan.duration which can produce inconsistent results;
change the projection so both fields are derived from the userBan join (e.g.,
compute "isBanned" from whether userBan is present/active and use
userBan.duration for duration) and update the corresponding
projection/constructor usage for BannedInfoResponse; apply the same fix to the
other projection(s) around the block that constructs BannedInfoResponse (the
later projection in the file) so both status and duration come from userBan
rather than siteUser.userStatus.
- Around line 240-262: Change getUserInfoDetailByUserId to accept a SiteUser
instead of re-querying: update the interface signature to UserInfoDetailResponse
getUserInfoDetailByUserId(SiteUser user) and in SiteUserFilterRepositoryImpl
remove the queryFactory.selectFrom(...).fetchOne() call; use the passed-in
SiteUser (user) for status/role checks and call
fetchReportedHistories(user.getId()), fetchMentorInfo(user.getId()), and
fetchMenteeInfo(user.getId()) as before. Also update all callers to pass the
already-loaded SiteUser (or, if callers may pass null, validate the parameter at
the start of getUserInfoDetailByUserId and throw a meaningful exception). Ensure
you keep references to UserInfoDetailResponse, fetchReportedHistories,
fetchMentorInfo, fetchMenteeInfo, and SiteUser to locate the changes.
- Around line 51-58: The UserSearchResponse DTO is missing the user ID needed
for navigation; update the UserSearchResponse record/class to include an id
field (matching the type used by siteUser.getId()), then update the
USER_SEARCH_RESPONSE_PROJECTION constant (the Projections.constructor call in
SiteUserFilterRepositoryImpl) to include siteUser.id as the first/appropriate
constructor argument so the projection parameters and the DTO constructor
parameter order match.
In
`@src/test/java/com/example/solidconnection/admin/service/AdminUserServiceTest.java`:
- Line 5: In AdminUserServiceTest replace the incorrect import for
assertThatCode (currently from org.assertj.core.api.AssertionsForClassTypes)
with the standard AssertJ import org.assertj.core.api.Assertions so the test
uses Assertions.assertThatCode; update the import line where assertThatCode is
referenced and run the tests to verify compilation.
---
Nitpick comments:
In `@src/main/java/com/example/solidconnection/admin/dto/BannedInfoResponse.java`:
- Line 7: The duration field in BannedInfoResponse (UserBanDuration duration)
can be null when isBanned == false; annotate the field (and its
getter/constructor parameter if present) with a `@Nullable` annotation (e.g.,
org.jetbrains.annotations.Nullable or javax.annotation.Nullable used in the
project) and/or add a one-line Javadoc on the duration field explaining
"nullable when isBanned is false" so callers know to null-check; update imports
and any serialization/deserialization hints (e.g., Jackson) if needed to
preserve nullability.
In
`@src/main/java/com/example/solidconnection/admin/dto/MentorApplicationHistoryInfoResponse.java`:
- Around line 6-10: Rename the DTO class MentorApplicationHistoryInfoResponse to
a clearer, non-ambiguous name (e.g., MentorApplicationHistorySummaryResponse) to
avoid confusion with the existing MentorApplicationHistoryResponse; update all
references/usages of MentorApplicationHistoryInfoResponse (constructors,
imports, tests, serializers) accordingly and ensure the new name matches the
project's DTO naming conventions.
In
`@src/main/java/com/example/solidconnection/admin/dto/RestrictedUserSearchResponse.java`:
- Around line 6-12: The record component reportedInfoResponse in
RestrictedUserSearchResponse can be null but this isn't expressed in the type;
annotate the component with a `@Nullable` annotation (e.g.,
org.springframework.lang.Nullable or javax.annotation.Nullable) on the
reportedInfoResponse component in the RestrictedUserSearchResponse record
declaration so callers and static tools know it may be null, and add the
corresponding import; leave BannedInfoResponse unchanged.
In
`@src/main/java/com/example/solidconnection/admin/dto/UserInfoDetailResponse.java`:
- Around line 5-9: Add nullable annotations to the record components in
UserInfoDetailResponse: annotate MentorInfoResponse mentorInfoResponse and
MenteeInfoResponse menteeInfoResponse (and optionally
List<ReportedHistoryResponse> reportedHistoryResponses if it can be null) with
`@Nullable` (e.g., org.springframework.lang.Nullable) and add the corresponding
import; this makes nullability explicit for static analysis, docs and
serializers while leaving the record signature otherwise unchanged.
In
`@src/main/java/com/example/solidconnection/admin/service/AdminUserService.java`:
- Around line 38-50: The existence check using
siteUserRepository.findById(userId) is fine but calling siteUser.getId()
afterward is redundant; in both getUserInfoDetail and
getRestrictedUserInfoDetail replace the siteUser.getId() argument passed to
siteUserFilterRepository.getUserInfoDetailByUserId and
getRestrictedUserInfoDetail respectively with the original userId parameter to
make the intent clearer and avoid unnecessary object access while keeping the
same validation via siteUserRepository.
In
`@src/main/java/com/example/solidconnection/siteuser/repository/custom/SiteUserFilterRepository.java`:
- Around line 1-21: SiteUserFilterRepository currently depends on admin.dto
types (UserSearchResponse, RestrictedUserSearchResponse, UserInfoDetailResponse,
RestrictedUserInfoDetailResponse) which couples the domain/infra layer to the
admin presentation layer; either move the interface and its implementation into
the admin package (so symbols SiteUserFilterRepository and its methods
searchAllUsers, searchRestrictedUsers, getUserInfoDetailByUserId,
getRestrictedUserInfoDetail live under com.example.solidconnection.admin.*) or
change the repository API to return domain-neutral projections/DTOs (e.g.,
UserSearchProjection, RestrictedUserSearchProjection, UserInfoProjection)
defined in a domain- or repository-level package and perform mapping to
admin.dto types in the admin service layer; update the implementation and
callers accordingly to use the chosen projection types or new package location.
In
`@src/main/java/com/example/solidconnection/siteuser/repository/custom/SiteUserFilterRepositoryImpl.java`:
- Around line 290-316: fetchMentorInfo currently issues up to three separate
queries (select mentor.id, fetch menteeInfos, fetch mentorApplicationHistory);
consolidate into a single query to avoid N+1/extra roundtrips by using left
joins or subqueries in one query with queryFactory: join siteUser ->
leftJoin(mentor) -> leftJoin(mentoring).on(mentoring.mentorId.eq(mentor.id)) and
leftJoin(mentorApplication).on(mentorApplication.siteUserId.eq(siteUser.id)),
select and map MATCHED_INFO_RESPONSE_PROJECTION and
MENTOR_APPLICATION_HISTORY_RESPONSE_PROJECTION (or use grouping/transformers) so
MentorInfoResponse is constructed from a single fetch; apply the same approach
to fetchMenteeInfo to eliminate its multiple queries.
In
`@src/test/java/com/example/solidconnection/admin/service/AdminUserServiceTest.java`:
- Around line 276-277: Add missing `@DisplayName` annotations to the nested test
classes 신고_차단된_유저_검색 and 신고_차단된_유저_상세_정보_조회 so test reports match the style used
for 전체_유저_검색 and 유저_상세_정보_조회; locate the `@Nested` class declarations for
신고_차단된_유저_검색 and 신고_차단된_유저_상세_정보_조회 and add a `@DisplayName` with an appropriate
Korean description (e.g., matching the wording pattern used in 전체_유저_검색 /
유저_상세_정보_조회) directly above each class declaration.
src/main/java/com/example/solidconnection/admin/dto/BannedInfoResponse.java
Show resolved
Hide resolved
src/main/java/com/example/solidconnection/admin/dto/MenteeInfoResponse.java
Show resolved
Hide resolved
| private static final ConstructorExpression<UserSearchResponse> USER_SEARCH_RESPONSE_PROJECTION = | ||
| Projections.constructor( | ||
| UserSearchResponse.class, | ||
| siteUser.nickname, | ||
| siteUser.email, | ||
| siteUser.role, | ||
| siteUser.userStatus | ||
| ); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# UserSearchResponse와 RestrictedUserSearchResponse DTO 파일 찾기
echo "=== UserSearchResponse 파일 검색 ==="
fd 'UserSearchResponse' --type f 2>/dev/null | head -20
echo ""
echo "=== RestrictedUserSearchResponse 파일 검색 ==="
fd 'RestrictedUserSearchResponse' --type f 2>/dev/null | head -20Repository: solid-connection/solid-connect-server
Length of output: 405
🏁 Script executed:
#!/bin/bash
# UserSearchResponse 클래스 정의 확인
find . -name 'UserSearchResponse.java' -type f | xargs cat 2>/dev/null
echo ""
echo "=== RestrictedUserSearchResponse 클래스 정의 ==="
find . -name 'RestrictedUserSearchResponse.java' -type f | xargs cat 2>/dev/nullRepository: solid-connection/solid-connect-server
Length of output: 760
🏁 Script executed:
#!/bin/bash
# SiteUserFilterRepositoryImpl 전체 내용 확인
find . -name 'SiteUserFilterRepositoryImpl.java' -type f | xargs cat 2>/dev/nullRepository: solid-connection/solid-connect-server
Length of output: 15239
UserSearchResponse DTO에 유저 ID 필드 추가가 필요합니다.
검색 결과에서 사용자 상세 조회 페이지로 네비게이션하려면 유저 ID가 필수입니다. 현재 프로젝션의 구성을 정리하면 다음과 같습니다:
-
현재 포함 필드: nickname, email, role, userStatus만 포함되어 있어 프론트엔드에서 개별 사용자의 상세 정보 조회 요청 시 식별자가 부족합니다.
-
필요한 수정 사항:
UserSearchResponse 레코드 수정
public record UserSearchResponse( + Long id, String nickname, String email, Role role, UserStatus userStatus ) { } -
프로젝션 업데이트:
USER_SEARCH_RESPONSE_PROJECTION 수정
private static final ConstructorExpression<UserSearchResponse> USER_SEARCH_RESPONSE_PROJECTION = Projections.constructor( UserSearchResponse.class, + siteUser.id, siteUser.nickname, siteUser.email, siteUser.role, siteUser.userStatus );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@src/main/java/com/example/solidconnection/siteuser/repository/custom/SiteUserFilterRepositoryImpl.java`
around lines 51 - 58, The UserSearchResponse DTO is missing the user ID needed
for navigation; update the UserSearchResponse record/class to include an id
field (matching the type used by siteUser.getId()), then update the
USER_SEARCH_RESPONSE_PROJECTION constant (the Projections.constructor call in
SiteUserFilterRepositoryImpl) to include siteUser.id as the first/appropriate
constructor argument so the projection parameters and the DTO constructor
parameter order match.
| private static final ConstructorExpression<BannedInfoResponse> BANNED_INFO_RESPONSE_PROJECTION = | ||
| Projections.constructor( | ||
| BannedInfoResponse.class, | ||
| siteUser.userStatus.eq(UserStatus.BANNED), | ||
| userBan.duration | ||
| ); |
There was a problem hiding this comment.
BANNED_INFO_RESPONSE_PROJECTION에서 userStatus와 실제 차단 레코드 간 불일치 가능성이 있습니다.
- Line 71:
siteUser.userStatus.eq(UserStatus.BANNED)는 유저 상태 필드 기반으로 "현재 차단 여부"를 판단합니다. - Line 72:
userBan.duration은 left join된 차단 레코드에서 가져옵니다. - 차단 레코드가 만료되었거나 조건에 맞지 않아 join 결과가 없으면,
userStatus는 BANNED이지만duration은null이 될 수 있습니다. - 반대로
userStatus가 아직 BANNED로 업데이트되지 않았는데 차단 레코드가 존재하는 경우도 불일치가 발생할 수 있습니다. - 이 두 값의 소스를 통일하는 것이 안전합니다 (예: 둘 다
userBan레코드 기반으로 판단).
Also applies to: 160-202
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@src/main/java/com/example/solidconnection/siteuser/repository/custom/SiteUserFilterRepositoryImpl.java`
around lines 68 - 73, BANNED_INFO_RESPONSE_PROJECTION currently mixes
siteUser.userStatus and userBan.duration which can produce inconsistent results;
change the projection so both fields are derived from the userBan join (e.g.,
compute "isBanned" from whether userBan is present/active and use
userBan.duration for duration) and update the corresponding
projection/constructor usage for BannedInfoResponse; apply the same fix to the
other projection(s) around the block that constructs BannedInfoResponse (the
later projection in the file) so both status and duration come from userBan
rather than siteUser.userStatus.
...ava/com/example/solidconnection/siteuser/repository/custom/SiteUserFilterRepositoryImpl.java
Show resolved
Hide resolved
...ava/com/example/solidconnection/siteuser/repository/custom/SiteUserFilterRepositoryImpl.java
Show resolved
Hide resolved
src/test/java/com/example/solidconnection/admin/service/AdminUserServiceTest.java
Outdated
Show resolved
Hide resolved
whqtker
left a comment
There was a problem hiding this comment.
동작은 큰 문제 없어 보이고, 컨벤션 관련만 코멘트 남겼습니다
고생하셨어요 ~!
src/test/java/com/example/solidconnection/admin/service/AdminUserServiceTest.java
Outdated
Show resolved
Hide resolved
src/test/java/com/example/solidconnection/admin/service/AdminUserServiceTest.java
Outdated
Show resolved
Hide resolved
src/main/java/com/example/solidconnection/admin/service/AdminUserService.java
Outdated
Show resolved
Hide resolved
src/main/java/com/example/solidconnection/admin/service/AdminUserService.java
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/main/java/com/example/solidconnection/siteuser/repository/custom/SiteUserFilterRepositoryImpl.java (1)
69-74:⚠️ Potential issue | 🟠 Major2) 차단 정보 계산 기준을 한 소스로 맞춰주세요.
- 현재isBanned는 유저 상태 기반,duration은 차단 조인 기반이라 조합이 어긋날 수 있습니다.
- 활성 차단 레코드 기준으로 둘 다 계산하면 응답 해석이 일관됩니다.수정 예시
private static final ConstructorExpression<BannedInfoResponse> BANNED_INFO_RESPONSE_PROJECTION = Projections.constructor( BannedInfoResponse.class, - siteUser.userStatus.eq(UserStatus.BANNED), + userBan.id.isNotNull(), userBan.duration );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/com/example/solidconnection/siteuser/repository/custom/SiteUserFilterRepositoryImpl.java` around lines 69 - 74, The projection BANNED_INFO_RESPONSE_PROJECTION currently mixes siteUser.userStatus (isBanned) with userBan.duration which can mismatch; update BANNED_INFO_RESPONSE_PROJECTION so both fields derive from the same active ban join: compute isBanned based on the active userBan presence/flag (e.g., userBan.id.isNotNull() or userBan.isActive expression) and use userBan.duration for duration (or null if no active ban), ensuring the constructor projection passes the active-ban boolean and its duration together instead of siteUser.userStatus and userBan.duration.
🧹 Nitpick comments (1)
src/main/java/com/example/solidconnection/siteuser/repository/custom/SiteUserFilterRepository.java (1)
19-19: 1) 메서드명만 조금 다듬으면 읽기가 더 좋아집니다.
-getUserInfoDetailByUserId(SiteUser user)는 이름은...ByUserId인데 인자는 객체라,getUserInfoDetailByUser(...)처럼 맞춰주면 의도가 더 선명해집니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/com/example/solidconnection/siteuser/repository/custom/SiteUserFilterRepository.java` at line 19, 메서드명 getUserInfoDetailByUserId(SiteUser user)가 인자로 SiteUser 객체를 받는 반면 이름은 Id를 가리켜 혼동을 유발하므로, 인터페이스 SiteUserFilterRepository의 메서드명을 getUserInfoDetailByUser로 변경하고 해당 시그니처(UserInfoDetailResponse getUserInfoDetailByUser(SiteUser user))로 통일하세요; 변경 후 동일한 이름을 참조하는 구현체와 호출부들을 모두 찾아(getUserInfoDetailByUserId → getUserInfoDetailByUser) 수정하여 컴파일 오류가 없도록 합니다.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@src/main/java/com/example/solidconnection/siteuser/repository/custom/SiteUserFilterRepositoryImpl.java`:
- Around line 235-239: The keywordContains method currently only searches
nickname; change it to OR-match nickname, email and id so user management
searches cover name/email/ID. In keywordContains(String keyword) (which returns
BooleanExpression and currently references siteUser.nickname), keep the hasText
check, then return a combined expression like
siteUser.nickname.containsIgnoreCase(keyword).or(siteUser.email.containsIgnoreCase(keyword)).or(siteUser.id.containsIgnoreCase(keyword))
(use the actual email/id property names in your entity if they differ) so all
three fields are searched.
---
Duplicate comments:
In
`@src/main/java/com/example/solidconnection/siteuser/repository/custom/SiteUserFilterRepositoryImpl.java`:
- Around line 69-74: The projection BANNED_INFO_RESPONSE_PROJECTION currently
mixes siteUser.userStatus (isBanned) with userBan.duration which can mismatch;
update BANNED_INFO_RESPONSE_PROJECTION so both fields derive from the same
active ban join: compute isBanned based on the active userBan presence/flag
(e.g., userBan.id.isNotNull() or userBan.isActive expression) and use
userBan.duration for duration (or null if no active ban), ensuring the
constructor projection passes the active-ban boolean and its duration together
instead of siteUser.userStatus and userBan.duration.
---
Nitpick comments:
In
`@src/main/java/com/example/solidconnection/siteuser/repository/custom/SiteUserFilterRepository.java`:
- Line 19: 메서드명 getUserInfoDetailByUserId(SiteUser user)가 인자로 SiteUser 객체를 받는 반면
이름은 Id를 가리켜 혼동을 유발하므로, 인터페이스 SiteUserFilterRepository의 메서드명을
getUserInfoDetailByUser로 변경하고 해당 시그니처(UserInfoDetailResponse
getUserInfoDetailByUser(SiteUser user))로 통일하세요; 변경 후 동일한 이름을 참조하는 구현체와 호출부들을 모두
찾아(getUserInfoDetailByUserId → getUserInfoDetailByUser) 수정하여 컴파일 오류가 없도록 합니다.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: dd1b11e7-4dda-4865-8666-286f1fe9afda
📒 Files selected for processing (9)
src/main/java/com/example/solidconnection/admin/dto/BannedInfoResponse.javasrc/main/java/com/example/solidconnection/admin/dto/MenteeInfoResponse.javasrc/main/java/com/example/solidconnection/admin/dto/RestrictedUserSearchResponse.javasrc/main/java/com/example/solidconnection/admin/dto/UserSearchResponse.javasrc/main/java/com/example/solidconnection/admin/service/AdminUserService.javasrc/main/java/com/example/solidconnection/siteuser/repository/SiteUserRepository.javasrc/main/java/com/example/solidconnection/siteuser/repository/custom/SiteUserFilterRepository.javasrc/main/java/com/example/solidconnection/siteuser/repository/custom/SiteUserFilterRepositoryImpl.javasrc/test/java/com/example/solidconnection/admin/service/AdminUserServiceTest.java
🚧 Files skipped from review as they are similar to previous changes (3)
- src/test/java/com/example/solidconnection/admin/service/AdminUserServiceTest.java
- src/main/java/com/example/solidconnection/admin/dto/UserSearchResponse.java
- src/main/java/com/example/solidconnection/admin/dto/MenteeInfoResponse.java
관련 이슈
작업 내용
유저 관리 페이지에 필요한 기능 추가
특이 사항
리뷰 요구사항 (선택)