Skip to content

fix: 운영진 이상 조회 시 동아리 멤버 학번 마스킹을 해제#344

Open
dh2906 wants to merge 4 commits intodevelopfrom
fix/club-manager-member-student-number
Open

fix: 운영진 이상 조회 시 동아리 멤버 학번 마스킹을 해제#344
dh2906 wants to merge 4 commits intodevelopfrom
fix/club-manager-member-student-number

Conversation

@dh2906
Copy link
Contributor

@dh2906 dh2906 commented Mar 4, 2026

🔍 개요

  • close #이슈번호

🚀 주요 변경 내용


💬 참고 사항


✅ Checklist (완료 조건)

  • 코드 스타일 가이드 준수
  • 테스트 코드 포함됨
  • Reviewers / Assignees / Labels 지정 완료
  • 보안 및 민감 정보 검증 (API 키, 환경 변수, 개인정보 등)

@dh2906 dh2906 self-assigned this Mar 4, 2026
@coderabbitai
Copy link

coderabbitai bot commented Mar 4, 2026

Warning

Rate limit exceeded

@dh2906 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 14 minutes and 42 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 09102e10-a3e0-4ec5-b462-58f80c04cdb1

📥 Commits

Reviewing files that changed from the base of the PR and between 45ffd4d and 3b1b308.

📒 Files selected for processing (2)
  • src/main/java/gg/agit/konect/domain/club/dto/ClubMembersResponse.java
  • src/main/java/gg/agit/konect/domain/club/service/ClubService.java
📝 Walkthrough

Walkthrough

ClubService의 getClubMembers에서 요청자의 권한(관리자 여부 및 클럽 내 포지션)을 검사해 학생번호 노출 가능 여부를 결정하고, 해당 플래그를 ClubMembersResponse로 전달하도록 변경되었습니다. DTO(InnerClubMember.from)는 마스킹 여부 플래그를 받아 학생번호를 조건부로 마스킹합니다.

Changes

Cohort / File(s) Summary
학생 번호 마스킹 응답 DTO
src/main/java/gg/agit/konect/domain/club/dto/ClubMembersResponse.java
InnerClubMember.from(ClubMember, boolean) 추가 및 기존 from(ClubMember)from(ClubMember, boolean) 변경. ClubMembersResponse.from(List<ClubMember>, boolean) 오버로드 추가, 기본 from(List<ClubMember>)는 true(마스킹)로 위임. 맵핑 시 마스킹 플래그 전달로 변경.
조건부 권한 검증 서비스
src/main/java/gg/agit/konect/domain/club/service/ClubService.java
getClubMembers()에서 관리자 여부와 요청자의 클럽 포지션(MANAGERS 포함)을 검사해 canViewUnmaskedStudentNumber 결정. ClubMembersResponse 생성 시 마스킹 플래그(!canViewUnmaskedStudentNumber) 전달로 변경.
API 설명 주석/문구
src/main/java/gg/agit/konect/domain/club/controller/ClubBasicApi.java
getClubMembers API 설명에 학생번호가 접근 수준에 따라 마스킹될 수 있음을 명시하는 문장 추가.

Sequence Diagram(s)

sequenceDiagram
    participant Client as "Client\n(요청자)"
    participant Service as "ClubService"
    participant Repo as "ClubMemberRepo"
    participant DTO as "ClubMembersResponse / InnerClubMember"

    Client->>Service: getClubMembers(clubId, requester)
    Service->>Repo: findAllByClubId(clubId)
    Repo-->>Service: List<ClubMember>
    Service->>Repo: findByClubIdAndUserId(clubId, requester) (권한확인)
    Repo-->>Service: Optional<ClubMember> (요청자 포지션)
    Service->>Service: canViewUnmaskedStudentNumber 결정 (admin || MANAGERS)
    Service->>DTO: ClubMembersResponse.from(members, !canViewUnmaskedStudentNumber)
    DTO->>DTO: InnerClubMember.from(member, shouldMaskStudentNumber) 각각 호출
    DTO-->>Client: ClubMembersResponse (학생번호는 플래그에 따라 마스킹)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

버그

Poem

🐰 학생번호 살짝 숨기네,
요청자 보이면 움찔, 아니면 깜짝 숨겨요.
서비스가 묻고 DTO가 가려주니,
당근은 맛있고 권한은 깔끔하네요. 🥕✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive PR 설명이 템플릿 형식으로만 구성되어 있으며, 구체적인 변경사항에 대한 설명이 거의 없습니다. 체크리스트만 포함되어 있고 주요 변경 내용 섹션이 비어있어 의미 있는 정보를 전달하지 못합니다. PR 설명의 '주요 변경 내용' 섹션에 구현 세부사항, 마스킹 로직 변경 방식, 영향 범위 등을 구체적으로 작성해주시기 바랍니다.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 변경사항의 핵심을 명확하게 설명하고 있습니다. 운영진 이상 권한으로 조회할 때 학번 마스킹을 해제하는 것이 주요 변경 내용이며, 제목이 이를 정확히 반영합니다.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/club-manager-member-student-number

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

Caution

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

⚠️ Outside diff range comments (1)
src/main/java/gg/agit/konect/domain/club/dto/ClubMembersResponse.java (1)

26-27: ⚠️ Potential issue | 🟡 Minor

[LEVEL: low] studentNumber API 설명이 실제 응답 동작과 불일치합니다.
문제는 studentNumber 스키마가 “마스킹된 학번”으로 고정되어 있는데, 현재 구현은 관리자/운영진 조회 시 원본 학번을 반환한다는 점입니다.
영향은 Swagger 기반 클라이언트가 응답 계약을 잘못 해석해 권한별 개인정보 처리 로직을 오구현할 수 있으며, 운영진/관리자 계정으로 조회하면 재현됩니다.
제안은 필드 설명을 “권한에 따라 마스킹될 수 있음”으로 수정하고 예시도 마스킹/비마스킹 케이스를 모두 반영하는 것입니다.

Also applies to: 41-43

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

In `@src/main/java/gg/agit/konect/domain/club/dto/ClubMembersResponse.java` around
lines 26 - 27, Update the `@Schema` annotation for the studentNumber field in
ClubMembersResponse to reflect conditional masking (e.g., change description to
"권한에 따라 마스킹될 수 있음") and replace the single masked example with a value that
demonstrates both cases or an explicit note (e.g., example showing masked and
unmasked forms or a combined example string). Apply the same change to the other
occurrence referenced (lines 41-43) so both schema entries accurately indicate
that the actual response may be masked or unmasked depending on caller
permissions.
🤖 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/gg/agit/konect/domain/club/service/ClubService.java`:
- Around line 213-219: The code currently calls
clubMemberRepository.existsByClubIdAndUserId(...) and then
clubMemberRepository.getByClubIdAndUserId(...), causing a TOCTOU race and extra
DB roundtrip; replace both calls with a single findByClubIdAndUserId(clubId,
userId).orElseThrow(() -> CustomException.of(FORBIDDEN_CLUB_MEMBER_ACCESS)) to
obtain the ClubMember once, then compute canViewUnmaskedStudentNumber =
MANAGERS.contains(requesterClubMember.getClubPosition()); this removes the
duplicate existence check, avoids returning NOT_FOUND_CLUB_MEMBER on a race, and
reduces database calls.

---

Outside diff comments:
In `@src/main/java/gg/agit/konect/domain/club/dto/ClubMembersResponse.java`:
- Around line 26-27: Update the `@Schema` annotation for the studentNumber field
in ClubMembersResponse to reflect conditional masking (e.g., change description
to "권한에 따라 마스킹될 수 있음") and replace the single masked example with a value that
demonstrates both cases or an explicit note (e.g., example showing masked and
unmasked forms or a combined example string). Apply the same change to the other
occurrence referenced (lines 41-43) so both schema entries accurately indicate
that the actual response may be masked or unmasked depending on caller
permissions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 88fac209-07bd-4489-91ad-1041f176a8dd

📥 Commits

Reviewing files that changed from the base of the PR and between eb371e0 and e064667.

📒 Files selected for processing (2)
  • src/main/java/gg/agit/konect/domain/club/dto/ClubMembersResponse.java
  • src/main/java/gg/agit/konect/domain/club/service/ClubService.java
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
src/main/java/**/*.java

⚙️ CodeRabbit configuration file

src/main/java/**/*.java: 아래 원칙으로 리뷰 코멘트를 작성한다.

  • 코멘트는 반드시 한국어로 작성한다.
  • 반드시 수정이 필요한 항목만 코멘트로 남기고, 단순 취향 차이는 지적하지 않는다.
  • 각 코멘트 첫 줄에 심각도를 [LEVEL: high|medium|low] 형식으로 반드시 표기한다.
  • 심각도 기준: high=운영 장애 가능, medium=품질 저하, low=개선 권고.
  • 각 코멘트는 "문제 -> 영향 -> 제안" 순서로 3문장 이내로 간결하게 작성한다.
  • 가능하면 재현 조건 및 실패 시나리오도 포함한다.
  • 제안은 현재 코드베이스(Spring Boot + JPA + Flyway) 패턴과 일치해야 한다.
  • 보안, 트랜잭션 경계, 예외 처리, N+1, 성능 회귀 가능성을 우선 점검한다.
  • 가독성: 변수/메서드 이름이 의도를 바로 드러내는지, 중첩과 메서드 길이가 과도하지 않은지 점검한다.
  • 단순화: 불필요한 추상화, 중복 로직, 과한 방어 코드가 있으면 더 단순한 대안을 제시한다.
  • 확장성: 새 요구사항 추가 시 변경 범위가 최소화되는 구조인지(하드코딩 분기/값 여부 포함) 점검한다.

Files:

  • src/main/java/gg/agit/konect/domain/club/service/ClubService.java
  • src/main/java/gg/agit/konect/domain/club/dto/ClubMembersResponse.java
**/*

⚙️ CodeRabbit configuration file

**/*: 공통 리뷰 톤 가이드:

  • 모든 코멘트는 첫 줄에 [LEVEL: ...] 태그를 포함한다.
  • 과장된 표현 없이 사실 기반으로 작성한다.
  • 한 코멘트에는 하나의 이슈만 다룬다.
  • 코드 예시가 필요하면 최소 수정 예시를 제시한다.
  • 가독성/단순화/확장성 이슈를 발견하면 우선순위를 높여 코멘트한다.

Files:

  • src/main/java/gg/agit/konect/domain/club/service/ClubService.java
  • src/main/java/gg/agit/konect/domain/club/dto/ClubMembersResponse.java

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

🤖 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/gg/agit/konect/domain/club/dto/ClubMembersResponse.java`:
- Around line 38-47: The current InnerClubMember.from(ClubMember clubMember,
boolean shouldMaskStudentNumber) is ambiguous and error-prone; replace the
boolean flag with a clear MaskingPolicy enum (e.g., MASKED, UNMASKED) or add two
explicit factory methods like InnerClubMember.fromMasked(ClubMember) and
InnerClubMember.fromUnmasked(ClubMember), change uses of maskStudentNumber(...)
call inside those factories accordingly, and update all call sites (including
the other occurrence around the second block) to use the enum or the new named
factories so the masking intent is explicit and cannot be inverted by mistake.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: c2bc3b0b-26cb-4a58-98f6-51b8466cbd22

📥 Commits

Reviewing files that changed from the base of the PR and between 4a19da9 and 45ffd4d.

📒 Files selected for processing (2)
  • src/main/java/gg/agit/konect/domain/club/controller/ClubBasicApi.java
  • src/main/java/gg/agit/konect/domain/club/dto/ClubMembersResponse.java
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
src/main/java/**/*.java

⚙️ CodeRabbit configuration file

src/main/java/**/*.java: 아래 원칙으로 리뷰 코멘트를 작성한다.

  • 코멘트는 반드시 한국어로 작성한다.
  • 반드시 수정이 필요한 항목만 코멘트로 남기고, 단순 취향 차이는 지적하지 않는다.
  • 각 코멘트 첫 줄에 심각도를 [LEVEL: high|medium|low] 형식으로 반드시 표기한다.
  • 심각도 기준: high=운영 장애 가능, medium=품질 저하, low=개선 권고.
  • 각 코멘트는 "문제 -> 영향 -> 제안" 순서로 3문장 이내로 간결하게 작성한다.
  • 가능하면 재현 조건 및 실패 시나리오도 포함한다.
  • 제안은 현재 코드베이스(Spring Boot + JPA + Flyway) 패턴과 일치해야 한다.
  • 보안, 트랜잭션 경계, 예외 처리, N+1, 성능 회귀 가능성을 우선 점검한다.
  • 가독성: 변수/메서드 이름이 의도를 바로 드러내는지, 중첩과 메서드 길이가 과도하지 않은지 점검한다.
  • 단순화: 불필요한 추상화, 중복 로직, 과한 방어 코드가 있으면 더 단순한 대안을 제시한다.
  • 확장성: 새 요구사항 추가 시 변경 범위가 최소화되는 구조인지(하드코딩 분기/값 여부 포함) 점검한다.

Files:

  • src/main/java/gg/agit/konect/domain/club/controller/ClubBasicApi.java
  • src/main/java/gg/agit/konect/domain/club/dto/ClubMembersResponse.java
**/*

⚙️ CodeRabbit configuration file

**/*: 공통 리뷰 톤 가이드:

  • 모든 코멘트는 첫 줄에 [LEVEL: ...] 태그를 포함한다.
  • 과장된 표현 없이 사실 기반으로 작성한다.
  • 한 코멘트에는 하나의 이슈만 다룬다.
  • 코드 예시가 필요하면 최소 수정 예시를 제시한다.
  • 가독성/단순화/확장성 이슈를 발견하면 우선순위를 높여 코멘트한다.

Files:

  • src/main/java/gg/agit/konect/domain/club/controller/ClubBasicApi.java
  • src/main/java/gg/agit/konect/domain/club/dto/ClubMembersResponse.java

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