Skip to content

대시보드_최근_목록_클릭_기능_추가#555

Open
Cassiiopeia wants to merge 2 commits intomainfrom
20260227_#552_대시보드_최근_목록_클릭_기능_추가

Hidden character warning

The head ref may contain hidden characters: "20260227_#552_\ub300\uc2dc\ubcf4\ub4dc_\ucd5c\uadfc_\ubaa9\ub85d_\ud074\ub9ad_\uae30\ub2a5_\ucd94\uac00"
Open

대시보드_최근_목록_클릭_기능_추가#555
Cassiiopeia wants to merge 2 commits intomainfrom
20260227_#552_대시보드_최근_목록_클릭_기능_추가

Conversation

@Cassiiopeia
Copy link
Member

@Cassiiopeia Cassiiopeia commented Feb 27, 2026

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 관리자용 항목 상세 조회 및 회원 상세 조회 API 추가
    • 관리자 응답에 단일 항목/회원 및 회원 상태 정보 포함
    • 항목 조회 시 상세연결 데이터 조회 경로 추가
    • 관리자 대시보드·목록 페이징 총계 계산 개선
    • 로그인/로그아웃 시 토큰·쿠키 처리 및 만료 처리 강화
  • 문서

    • 전체 API 규약, Admin API 인터페이스 문서화 및 작성 가이드 추가

@coderabbitai
Copy link

coderabbitai bot commented Feb 27, 2026

Walkthrough

관리자 API 문서화 인터페이스와 엔드포인트가 추가되고, AdminResponse DTO에 단일 Item/Member 필드가 도입되며, 서비스·레포지토리에 관리자용 상세 조회 메서드가 추가되었습니다.

Changes

Cohort / File(s) Summary
API 컨벤션 & Docs
CLAUDE.md, RomRom-Web/src/main/java/com/romrom/web/controller/api/AdminApiControllerDocs.java
API 문서·컨벤션 추가 및 AdminApiControllerDocs 인터페이스(11개 관리자 엔드포인트, Operation/ApiChangeLog 주석 포함) 신규 도입.
컨트롤러 구현
RomRom-Web/src/main/java/com/romrom/web/controller/api/AdminApiController.java
AdminApiController가 AdminApiControllerDocs를 구현하도록 변경. 로그인/로그아웃 쿠키 처리 개선과 POST /items/detail, POST /members/detail 엔드포인트 추가(각각 AdminResponse 반환). 기존 엔드포인트들은 @Override로 정렬.
DTO 확장
RomRom-Common/src/main/java/com/romrom/common/dto/AdminResponse.java
AdminResponse에 itemmember 단일 엔티티 필드 추가; AdminMemberDto에 accountStatus 필드 추가. AdminItemDto의 정적 팩토리 메서드 제거.
서비스 레이어
RomRom-Domain-Item/.../ItemService.java, RomRom-Domain-Member/.../MemberService.java
관리자용 상세 조회 메서드 추가: getItemDetailForAdmin(AdminRequest)getMemberDetailForAdmin(AdminRequest)(readOnly 트랜잭션, 존재하지 않으면 예외 처리). 총계 계산을 page.getTotalElements()로 변경.
레포지토리
RomRom-Domain-Item/src/main/java/com/romrom/item/repository/postgres/ItemRepository.java
아이템 상세 조회용 Optional<Item> findByItemIdWithDetails(UUID) 메서드 추가(LEFT JOIN FETCH로 Member 및 itemImages 포함).

Sequence Diagram(s)

sequenceDiagram
    participant Admin as Admin User
    participant Ctrl as AdminApiController
    participant Docs as AdminApiControllerDocs
    participant SvcItem as ItemService
    participant SvcMember as MemberService
    participant Repo as ItemRepository
    participant DB as Database
    participant Resp as AdminResponse

    Admin->>Ctrl: POST /items/detail (AdminRequest)
    Ctrl->>Docs: (Docs interface metadata) 
    Ctrl->>SvcItem: getItemDetailForAdmin(request)
    SvcItem->>Repo: findByItemIdWithDetails(itemId)
    Repo->>DB: SELECT with LEFT JOIN FETCH
    DB-->>Repo: Item + Member + Images
    Repo-->>SvcItem: Optional<Item>
    SvcItem->>Resp: build AdminResponse with item
    Resp-->>Ctrl: AdminResponse
    Ctrl-->>Admin: 200 ResponseEntity<AdminResponse>

    Admin->>Ctrl: POST /members/detail (AdminRequest)
    Ctrl->>SvcMember: getMemberDetailForAdmin(request)
    SvcMember->>DB: Query member by ID
    DB-->>SvcMember: Member
    SvcMember->>Resp: build AdminResponse with member
    Resp-->>Ctrl: AdminResponse
    Ctrl-->>Admin: 200 ResponseEntity<AdminResponse>
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • Chuseok22
  • discipline24
  • nayoung04
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 46.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 변경 사항의 주요 내용과 일치합니다. 대시보드 최근 목록 클릭 기능 추가라는 제목이 추가된 새로운 엔드포인트들(getItemDetail, getMemberDetail)과 관련된 기능을 정확하게 반영합니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 20260227_#552_대시보드_최근_목록_클릭_기능_추가

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
RomRom-Web/src/main/java/com/romrom/web/controller/api/AdminApiController.java (3)

109-119: ⚠️ Potential issue | 🟠 Major

대시보드 통계: totalMembers/totalItems에 “active count”를 넣는지 확인이 필요합니다.

getDashboardStats()에서 dashboardStats.totalMembersmemberService.countActiveMembers()(Line 115)를, dashboardStats.totalItemsitemService.countActiveItems()(Line 116)를 세팅하고 있습니다. 이름 그대로라면 “전체”와 “활성”이 섞여 보이므로, 의도한 지표가 무엇인지 맞춰주는 게 좋겠습니다(필드명을 activeMembers/activeItems로 쓰거나, 서비스 메서드/리포지토리 쿼리를 total 기준으로 맞추거나).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@RomRom-Web/src/main/java/com/romrom/web/controller/api/AdminApiController.java`
around lines 109 - 119, The dashboard stats currently assign active counts to
fields named totalMembers and totalItems in getDashboardStats
(AdminResponse.AdminDashboardStats), causing a naming/semantic mismatch; either
change the fields to activeMembers/activeItems in
AdminResponse.AdminDashboardStats and the builder calls in getDashboardStats, or
call total-count service methods (e.g.,
memberService.countAllMembers()/itemService.countAllItems) so
totalMembers/totalItems truly represent totals—update the builder usage in
getDashboardStats and the AdminResponse model consistently to resolve the
mismatch.

75-105: ⚠️ Potential issue | 🟡 Minor

/logoutconsumes=MULTIPART_FORM_DATA는 빈 바디 요청에서 415 오류를 유발합니다.

/logout 엔드포인트(Line 76)는 @PostMapping(..., consumes = MediaType.MULTIPART_FORM_DATA_VALUE)로 지정되어 있지만, 요청 바디가 없습니다. 표준 클라이언트는 보통 logout을 빈 바디로 호출하므로, Content-Type이 multipart가 아니면 Spring이 415를 반환합니다. /login과 달리 logout은 @ModelAttribute 같은 바디 파라미터가 없어서 consumes 제약이 불필요합니다.

  • consumes를 제거하거나 클라이언트가 항상 multipart로 호출하도록 강제하는 중 하나로 정리하세요.
  • 추가로 adminAuthService.logout(...)이 실패해도 쿠키 삭제는 계속 진행되는 것이 UX상 좋으므로, try/finally 처리를 검토하세요.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@RomRom-Web/src/main/java/com/romrom/web/controller/api/AdminApiController.java`
around lines 75 - 105, Remove the unnecessary consumes constraint from the
`@PostMapping` on AdminApiController.logout (i.e., delete the consumes =
MediaType.MULTIPART_FORM_DATA_VALUE) so the endpoint accepts empty-body
requests; then wrap the call to adminAuthService.logout(refreshTokenFromCookie)
in a try/finally so that the cookie deletion logic (creating/setting
accessToken, refreshToken, authStatus cookies with path "/" and maxAge 0 and
adding them to the response) always runs even if adminAuthService.logout throws.

33-73: ⚠️ Potential issue | 🟠 Major

관리자 로그인: 토큰 쿠키의 Secure=false 고정 + SameSite 미설정은 운영 보안 리스크입니다.

현재 access/refresh token 쿠키에 setSecure(false)가 하드코딩되어 있습니다(45, 53줄). 운영 환경이 HTTPS라면 네트워크 상에서 토큰이 평문으로 노출될 수 있습니다. 또한 SameSite 속성이 명시되지 않아 CSRF 관점에서 브라우저 기본값에 의존하게 됩니다(관리자 기능은 영향이 큼).

  • 환경별로 secure 값을 true/false로 주입(프로파일/설정값)하고, SameSite도 명시해야 합니다.
  • Spring 3.4.1은 ResponseCookie를 지원하므로 이를 활용하면 SameSite까지 함께 안전하게 설정할 수 있습니다.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@RomRom-Web/src/main/java/com/romrom/web/controller/api/AdminApiController.java`
around lines 33 - 73, The login method currently hardcodes cookie secure flags
and omits SameSite, which is unsafe; modify AdminApiController.login to read an
injected config/property (e.g., a boolean like cookieSecure or
environment/profile flag) and use Spring's ResponseCookie builder instead of
java.net.Cookie to set accessToken, refreshToken and authStatus cookies so you
can call .secure(cookieSecure).sameSite("Strict" or "Lax" as appropriate) and
other attributes (path, httpOnly, maxAge) before adding them to the
HttpServletResponse (use response.addHeader("Set-Cookie",
responseCookie.toString()) or ResponseCookie.toString()); remove the hardcoded
setSecure(false) calls on accessTokenCookie/refreshTokenCookie/authStatusCookie
and ensure adminAuthService.authenticateWithJwt still supplies tokens unchanged.
RomRom-Common/src/main/java/com/romrom/common/dto/AdminResponse.java (1)

16-53: ⚠️ Potential issue | 🟠 Major

클래스 레벨 @ToString으로 인한 토큰/민감 정보 로그 노출 위험

AdminResponse@ToString 어노테이션(16줄)이 accessToken, refreshToken, item, member 필드를 포함하여 문자열화합니다. 이 객체를 로그로 출력하면 인증 토큰과 사용자 PII가 그대로 노출됩니다. 내부 클래스인 AdminItemDto, AdminMemberDto, AdminDashboardStats도 동일하게 @ToString이 적용되어 있어 연쇄 노출 위험이 있습니다.

민감 필드에 @ToString.Exclude를 추가하여 로그에서 제외하세요:

  • accessToken, refreshToken
  • item, member (엔티티 필드는 ID나 기본 정보만 필요한 경우가 많음)
예시 적용
+import lombok.ToString;

 `@ToString`
 public class AdminResponse {
     
+    `@ToString.Exclude`
     private String accessToken;

+    `@ToString.Exclude`
     private String refreshToken;

+    `@ToString.Exclude`
     private Item item;

+    `@ToString.Exclude`
     private Member member;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@RomRom-Common/src/main/java/com/romrom/common/dto/AdminResponse.java` around
lines 16 - 53, The class-level `@ToString` on AdminResponse causes sensitive data
exposure; remove or limit it by adding Lombok `@ToString.Exclude` to the sensitive
fields accessToken, refreshToken, item, and member in AdminResponse (or replace
the class-level `@ToString` with a safe, custom toString), and apply the same
treatment to nested DTOs AdminItemDto, AdminMemberDto, and AdminDashboardStats
(either remove their `@ToString` or add `@ToString.Exclude` to fields containing
PII/tokens) so tokens and personal data are excluded from logged string
representations.
RomRom-Web/src/main/java/com/romrom/web/controller/api/AdminApiControllerDocs.java (1)

17-295: ⚠️ Potential issue | 🟡 Minor

문서 컨벤션(issueNumber) 정리와 login 에러 응답 형식을 맞춰주세요.

  • issueNumber = 0이 여러 곳에 들어가 있는데(Line 23, 47, 67, 82, 104, 164, 193, 249, 273), PR #552 패턴처럼 GitHub Issue 번호를 쓸지 결정 필요합니다.
  • login 문서에서 INVALID_CREDENTIALS 에러코드를 명시했으나(Line 40-42), 실제 구현은 실패 시 HTTP 400 + 빈 바디만 반환합니다(AdminApiController 69-71줄). 문서를 "400 + 빈 바디"로 수정하거나 컨트롤러가 표준 에러 응답을 내려주도록 변경하세요.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@RomRom-Web/src/main/java/com/romrom/web/controller/api/AdminApiControllerDocs.java`
around lines 17 - 295, The documentation has inconsistent issueNumber usage and
a mismatch between the login docs and the controller behavior; update
AdminApiControllerDocs and/or the controller to make them consistent: (1)
Replace repeated ApiChangeLog(issueNumber = 0) entries in AdminApiControllerDocs
with the correct PR/issue number (e.g., 552) for the entries that correspond to
PR `#552` (refer to the ApiChangeLog annotations in AdminApiControllerDocs) or
decide a consistent convention and apply it across all ApiChangeLog annotations;
(2) For the login mismatch, either update the login Operation description in
AdminApiControllerDocs to state the actual behavior ("returns HTTP 400 with
empty body on invalid credentials") or change the AdminApiController.login
implementation to return a standard error response containing the
INVALID_CREDENTIALS error payload (make the controller return the structured
error instead of plain 400 empty body) so that AdminApiControllerDocs.login and
AdminApiController.login are aligned.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@CLAUDE.md`:
- Around line 16-26: Update the "POST API 패턴 (전체 공통)" section to explicitly
state exceptions (e.g., read-only endpoints using GET and destructive endpoints
using DELETE) and mention that controllers like AdminApiController expose GET
/dashboard/*, GET /items, GET /members and DELETE /items/{itemId} as allowed
deviations from the POST+multipart+@ModelAttribute rule; also fix the missing
fenced-code-block language by adding the appropriate language tag (e.g., ```md)
to the fenced block in the documentation so markdownlint MD040 is satisfied.

In
`@RomRom-Domain-Member/src/main/java/com/romrom/member/service/MemberService.java`:
- Around line 311-326: Ensure AdminRequest.memberId is validated and remove
duplicate lookup: add a `@NotNull` on AdminRequest.memberId and make the
controller getMemberDetail endpoint use `@Valid` or `@Validated` so null memberId
yields a 400; then change MemberService.getMemberDetailForAdmin(AdminRequest) to
call the existing findMemberById(UUID memberId) helper (or explicitly null-check
request.getMemberId() and throw a 400-mapped CustomException) instead of calling
memberRepository.findById(...) inline, reusing the centralized error handling in
findMemberById and eliminating the duplicated lookup/logging.

---

Outside diff comments:
In `@RomRom-Common/src/main/java/com/romrom/common/dto/AdminResponse.java`:
- Around line 16-53: The class-level `@ToString` on AdminResponse causes sensitive
data exposure; remove or limit it by adding Lombok `@ToString.Exclude` to the
sensitive fields accessToken, refreshToken, item, and member in AdminResponse
(or replace the class-level `@ToString` with a safe, custom toString), and apply
the same treatment to nested DTOs AdminItemDto, AdminMemberDto, and
AdminDashboardStats (either remove their `@ToString` or add `@ToString.Exclude` to
fields containing PII/tokens) so tokens and personal data are excluded from
logged string representations.

In
`@RomRom-Web/src/main/java/com/romrom/web/controller/api/AdminApiController.java`:
- Around line 109-119: The dashboard stats currently assign active counts to
fields named totalMembers and totalItems in getDashboardStats
(AdminResponse.AdminDashboardStats), causing a naming/semantic mismatch; either
change the fields to activeMembers/activeItems in
AdminResponse.AdminDashboardStats and the builder calls in getDashboardStats, or
call total-count service methods (e.g.,
memberService.countAllMembers()/itemService.countAllItems) so
totalMembers/totalItems truly represent totals—update the builder usage in
getDashboardStats and the AdminResponse model consistently to resolve the
mismatch.
- Around line 75-105: Remove the unnecessary consumes constraint from the
`@PostMapping` on AdminApiController.logout (i.e., delete the consumes =
MediaType.MULTIPART_FORM_DATA_VALUE) so the endpoint accepts empty-body
requests; then wrap the call to adminAuthService.logout(refreshTokenFromCookie)
in a try/finally so that the cookie deletion logic (creating/setting
accessToken, refreshToken, authStatus cookies with path "/" and maxAge 0 and
adding them to the response) always runs even if adminAuthService.logout throws.
- Around line 33-73: The login method currently hardcodes cookie secure flags
and omits SameSite, which is unsafe; modify AdminApiController.login to read an
injected config/property (e.g., a boolean like cookieSecure or
environment/profile flag) and use Spring's ResponseCookie builder instead of
java.net.Cookie to set accessToken, refreshToken and authStatus cookies so you
can call .secure(cookieSecure).sameSite("Strict" or "Lax" as appropriate) and
other attributes (path, httpOnly, maxAge) before adding them to the
HttpServletResponse (use response.addHeader("Set-Cookie",
responseCookie.toString()) or ResponseCookie.toString()); remove the hardcoded
setSecure(false) calls on accessTokenCookie/refreshTokenCookie/authStatusCookie
and ensure adminAuthService.authenticateWithJwt still supplies tokens unchanged.

In
`@RomRom-Web/src/main/java/com/romrom/web/controller/api/AdminApiControllerDocs.java`:
- Around line 17-295: The documentation has inconsistent issueNumber usage and a
mismatch between the login docs and the controller behavior; update
AdminApiControllerDocs and/or the controller to make them consistent: (1)
Replace repeated ApiChangeLog(issueNumber = 0) entries in AdminApiControllerDocs
with the correct PR/issue number (e.g., 552) for the entries that correspond to
PR `#552` (refer to the ApiChangeLog annotations in AdminApiControllerDocs) or
decide a consistent convention and apply it across all ApiChangeLog annotations;
(2) For the login mismatch, either update the login Operation description in
AdminApiControllerDocs to state the actual behavior ("returns HTTP 400 with
empty body on invalid credentials") or change the AdminApiController.login
implementation to return a standard error response containing the
INVALID_CREDENTIALS error payload (make the controller return the structured
error instead of plain 400 empty body) so that AdminApiControllerDocs.login and
AdminApiController.login are aligned.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ebbf906 and bc7beeb.

📒 Files selected for processing (6)
  • CLAUDE.md
  • RomRom-Common/src/main/java/com/romrom/common/dto/AdminResponse.java
  • RomRom-Domain-Item/src/main/java/com/romrom/item/service/ItemService.java
  • RomRom-Domain-Member/src/main/java/com/romrom/member/service/MemberService.java
  • RomRom-Web/src/main/java/com/romrom/web/controller/api/AdminApiController.java
  • RomRom-Web/src/main/java/com/romrom/web/controller/api/AdminApiControllerDocs.java

Comment on lines +16 to +26
### POST API 패턴 (전체 공통)
- **모든 API는 POST + `consumes = MediaType.MULTIPART_FORM_DATA_VALUE` + `@ModelAttribute` 패턴 사용**
- 예시:
```java
@PostMapping(value = "/sign-in", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@LogMonitor
public ResponseEntity<AuthResponse> signIn(@ModelAttribute AuthRequest request) {
return ResponseEntity.ok(authService.signIn(request));
}
```

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

문서 규칙과 실제 구현이 어긋날 수 있어 예외/범위를 명시해두는 게 좋겠습니다.

  • Line 17-25에서 “모든 API는 POST + multipart + @ModelAttribute”를 “전체 공통”으로 선언했는데, 이번 PR의 AdminApiController만 봐도 GET /dashboard/*, GET /items, GET /members, DELETE /items/{itemId}가 존재합니다. “예외 케이스(예: 조회는 GET, 삭제는 DELETE 등)”를 문서에 같이 적어두면 혼선이 줄어들어요.

또한 markdownlint 힌트(MD040)처럼 Line 55의 fenced code block에 언어가 빠져 있습니다.

제안 diff (MD040 해결)
@@
-  ```
+  ```md
   ## 인증(JWT): **필요/불필요**
@@
-  ```
+  ```

Also applies to: 52-66

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CLAUDE.md` around lines 16 - 26, Update the "POST API 패턴 (전체 공통)" section to
explicitly state exceptions (e.g., read-only endpoints using GET and destructive
endpoints using DELETE) and mention that controllers like AdminApiController
expose GET /dashboard/*, GET /items, GET /members and DELETE /items/{itemId} as
allowed deviations from the POST+multipart+@ModelAttribute rule; also fix the
missing fenced-code-block language by adding the appropriate language tag (e.g.,
```md) to the fenced block in the documentation so markdownlint MD040 is
satisfied.

Comment on lines +311 to +326
/**
* 관리자용 회원 단건 조회
*/
@Transactional(readOnly = true)
public AdminResponse getMemberDetailForAdmin(AdminRequest request) {
Member member = memberRepository.findById(request.getMemberId())
.orElseThrow(() -> {
log.error("관리자 회원 단건 조회 실패 - 존재하지 않는 memberId: {}", request.getMemberId());
return new CustomException(ErrorCode.MEMBER_NOT_FOUND);
});

return AdminResponse.builder()
.member(member)
.build();
}

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== 1. AdminRequest 검증 어노테이션 확인 =="
fd -t f 'AdminRequest.java' | head -5 | while read file; do
  echo "--- $file ---"
  cat -n "$file" || true
done

echo
echo "== 2. AdminApiController에서 getMemberDetail 관련 코드 확인 =="
fd -t f 'AdminApiController.java' | head -1 | while read file; do
  echo "--- $file ---"
  cat -n "$file" | grep -A 20 -B 5 "getMemberDetail\|@Valid\|@Validated" || true
done

echo
echo "== 3. MemberService에서 findMemberById 메서드 확인 =="
fd -t f 'MemberService.java' | head -1 | while read file; do
  echo "--- $file ---"
  cat -n "$file" | sed -n '330,345p'
done

echo
echo "== 4. MemberService에서 Admin 관련 메서드 검색 =="
fd -t f 'MemberService.java' | head -1 | while read file; do
  echo "--- $file ---"
  rg -n 'public.*Admin|getMemberDetail' "$file" || true
done

Repository: TEAM-ROMROM/RomRom-BE

Length of output: 5210


관리자 회원 단건 조회: memberId 누락 시 500 가능 + 기존 조회 로직 중복입니다.

  • AdminRequestmemberId 필드(line 76)가 검증 어노테이션 없이 선언되어 있고, 컨트롤러의 getMemberDetail 메서드(line 164)도 @Valid 또는 @Validated가 없어서, null 값이 그대로 memberRepository.findById(null)로 전달되어 Spring Data JPA가 IllegalArgumentException을 던집니다. 이는 500 에러를 발생시키는데, 400 응답이 올바릅니다.

  • 같은 클래스의 findMemberById(UUID memberId) 메서드(line 331~)가 동일한 로직을 처리하고 있어서, getMemberDetailForAdmin에서 이를 재사용하면 중복을 제거할 수 있습니다.

제안 diff (중복 제거 방향)
   `@Transactional`(readOnly = true)
   public AdminResponse getMemberDetailForAdmin(AdminRequest request) {
-    Member member = memberRepository.findById(request.getMemberId())
-        .orElseThrow(() -> {
-          log.error("관리자 회원 단건 조회 실패 - 존재하지 않는 memberId: {}", request.getMemberId());
-          return new CustomException(ErrorCode.MEMBER_NOT_FOUND);
-        });
+    // AdminRequest에 `@NotNull` + 컨트롤러에 `@Valid` 추가 필수
+    Member member = findMemberById(request.getMemberId());

     return AdminResponse.builder()
         .member(member)
         .build();
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@RomRom-Domain-Member/src/main/java/com/romrom/member/service/MemberService.java`
around lines 311 - 326, Ensure AdminRequest.memberId is validated and remove
duplicate lookup: add a `@NotNull` on AdminRequest.memberId and make the
controller getMemberDetail endpoint use `@Valid` or `@Validated` so null memberId
yields a 400; then change MemberService.getMemberDetailForAdmin(AdminRequest) to
call the existing findMemberById(UUID memberId) helper (or explicitly null-check
request.getMemberId() and throw a 400-mapped CustomException) instead of calling
memberRepository.findById(...) inline, reusing the centralized error handling in
findMemberById and eliminating the duplicated lookup/logging.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
RomRom-Common/src/main/java/com/romrom/common/dto/AdminResponse.java (1)

25-41: ⚠️ Potential issue | 🟠 Major

관리자 목록 응답용 페이지 메타 필드를 명시적으로 추가해 주세요.

totalPages, totalElements, currentPage가 DTO 최상위에 없어 목록 응답 계약이 불명확합니다. AdminResponse에 메타 필드를 추가하고 목록 API에서 값을 채우는 것이 맞습니다.

🔧 제안 수정안
 public class AdminResponse {

     `@Schema`(description = "전체 카운트")
     private Long totalCount;
+
+    `@Schema`(description = "전체 페이지 수")
+    private Integer totalPages;
+
+    `@Schema`(description = "전체 요소 수")
+    private Long totalElements;
+
+    `@Schema`(description = "현재 페이지(0-based)")
+    private Integer currentPage;

Based on learnings: Applies to **/AdminResponse.{java,kt} : Admin API 목록 조회 시 Page 정보(totalPages, totalElements, currentPage)를 Response에 포함

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@RomRom-Common/src/main/java/com/romrom/common/dto/AdminResponse.java` around
lines 25 - 41, AdminResponse currently exposes totalCount, items
(Page<AdminItemDto>), and members (Page<AdminMemberDto>) but lacks explicit
pagination meta fields; add Long totalPages, Long totalElements, and Integer
currentPage to AdminResponse and ensure the list endpoints that populate items
or members also set these new fields from the Page object (use
page.getTotalPages(), page.getTotalElements(), page.getNumber() or equivalent)
so the response contract clearly includes pagination metadata.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@RomRom-Domain-Item/src/main/java/com/romrom/item/repository/postgres/ItemRepository.java`:
- Around line 59-60: The JPQL fetch join in the repository method
findByItemIdWithDetails can return duplicate rows (causing
NonUniqueResultException) because of the collection fetch (i.itemImages); update
the query string used by findByItemIdWithDetails to use SELECT DISTINCT i
instead of SELECT i (i.e., "SELECT DISTINCT i FROM Item i LEFT JOIN FETCH
i.member LEFT JOIN FETCH i.itemImages") so the Optional<Item> single-result
retrieval is safe.

---

Outside diff comments:
In `@RomRom-Common/src/main/java/com/romrom/common/dto/AdminResponse.java`:
- Around line 25-41: AdminResponse currently exposes totalCount, items
(Page<AdminItemDto>), and members (Page<AdminMemberDto>) but lacks explicit
pagination meta fields; add Long totalPages, Long totalElements, and Integer
currentPage to AdminResponse and ensure the list endpoints that populate items
or members also set these new fields from the Page object (use
page.getTotalPages(), page.getTotalElements(), page.getNumber() or equivalent)
so the response contract clearly includes pagination metadata.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bc7beeb and ec23bd0.

📒 Files selected for processing (4)
  • RomRom-Common/src/main/java/com/romrom/common/dto/AdminResponse.java
  • RomRom-Domain-Item/src/main/java/com/romrom/item/repository/postgres/ItemRepository.java
  • RomRom-Domain-Item/src/main/java/com/romrom/item/service/ItemService.java
  • RomRom-Domain-Member/src/main/java/com/romrom/member/service/MemberService.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • RomRom-Domain-Member/src/main/java/com/romrom/member/service/MemberService.java

Comment on lines +59 to +60
@Query("SELECT i FROM Item i LEFT JOIN FETCH i.member LEFT JOIN FETCH i.itemImages WHERE i.itemId = :itemId")
Optional<Item> findByItemIdWithDetails(@Param("itemId") UUID itemId);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "ItemRepository.java" | head -5

Repository: TEAM-ROMROM/RomRom-BE

Length of output: 155


🏁 Script executed:

find . -type f -name "Item.java" | head -5

Repository: TEAM-ROMROM/RomRom-BE

Length of output: 141


🏁 Script executed:

fd 'ItemRepository\.java$' -x cat -n {}

Repository: TEAM-ROMROM/RomRom-BE

Length of output: 3095


🏁 Script executed:

fd 'Item\.java$' -x cat -n {}

Repository: TEAM-ROMROM/RomRom-BE

Length of output: 4982


🏁 Script executed:

# Check if there are any tests for this method
fd -type f -name "*Test.java" | xargs rg -l "findByItemIdWithDetails" 2>/dev/null || echo "No tests found for this method"

Repository: TEAM-ROMROM/RomRom-BE

Length of output: 415


🏁 Script executed:

# Search for any other similar patterns to understand if DISTINCT is already used elsewhere
rg "SELECT DISTINCT" RomRom-Domain-Item/src/main/java/com/romrom/item/repository/ 2>/dev/null || echo "No DISTINCT queries found in ItemRepository"

Repository: TEAM-ROMROM/RomRom-BE

Length of output: 198


LEFT JOIN FETCH i.itemImages 단건 조회는 DISTINCT 없으면 중복 결과 예외 위험입니다.

Line 59의 컬렉션 fetch join(@OneToMany)은 행 중복을 생성하여 Optional<Item> 단건 반환에서 NonUniqueResultException을 발생시킬 수 있습니다. SELECT DISTINCT i로 수정이 필요합니다.

수정안
-  `@Query`("SELECT i FROM Item i LEFT JOIN FETCH i.member LEFT JOIN FETCH i.itemImages WHERE i.itemId = :itemId")
+  `@Query`("SELECT DISTINCT i FROM Item i LEFT JOIN FETCH i.member LEFT JOIN FETCH i.itemImages WHERE i.itemId = :itemId")
   Optional<Item> findByItemIdWithDetails(`@Param`("itemId") UUID itemId);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Query("SELECT i FROM Item i LEFT JOIN FETCH i.member LEFT JOIN FETCH i.itemImages WHERE i.itemId = :itemId")
Optional<Item> findByItemIdWithDetails(@Param("itemId") UUID itemId);
`@Query`("SELECT DISTINCT i FROM Item i LEFT JOIN FETCH i.member LEFT JOIN FETCH i.itemImages WHERE i.itemId = :itemId")
Optional<Item> findByItemIdWithDetails(`@Param`("itemId") UUID itemId);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@RomRom-Domain-Item/src/main/java/com/romrom/item/repository/postgres/ItemRepository.java`
around lines 59 - 60, The JPQL fetch join in the repository method
findByItemIdWithDetails can return duplicate rows (causing
NonUniqueResultException) because of the collection fetch (i.itemImages); update
the query string used by findByItemIdWithDetails to use SELECT DISTINCT i
instead of SELECT i (i.e., "SELECT DISTINCT i FROM Item i LEFT JOIN FETCH
i.member LEFT JOIN FETCH i.itemImages") so the Optional<Item> single-result
retrieval is safe.

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.

1 participant