Skip to content

Feat: [FN-327] 그룹 권한 추가 API #15

Merged
stoneTiger0912 merged 6 commits intomainfrom
feat/add-down-permission
Mar 1, 2026
Merged

Feat: [FN-327] 그룹 권한 추가 API #15
stoneTiger0912 merged 6 commits intomainfrom
feat/add-down-permission

Conversation

@stoneTiger0912
Copy link
Member

@stoneTiger0912 stoneTiger0912 commented Mar 1, 2026

Summary by CodeRabbit

릴리스 노트

  • 새 기능
    • 그룹 역할에 대한 권한 추가 기능 제공
    • 역할 계층 구조 도입으로 체계적인 권한 관리 지원
    • 권한 중복 추가 방지 및 역할 우선순위 검증 강화

@stoneTiger0912 stoneTiger0912 self-assigned this Mar 1, 2026
@coderabbitai
Copy link

coderabbitai bot commented Mar 1, 2026

Warning

Rate limit exceeded

@stoneTiger0912 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 3 minutes and 27 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 84fc87d and b6483bf.

📒 Files selected for processing (2)
  • src/main/java/flipnote/group/adapter/out/persistence/GroupRoleRepositoryAdapter.java
  • src/main/java/flipnote/group/infrastructure/persistence/jpa/GroupRoleRepository.java

개요

이 PR은 그룹 내 권한 관리 기능을 추가합니다. 새로운 REST 엔드포인트를 통해 사용자가 특정 역할에 권한을 추가할 수 있으며, 역할 계층 구조 검증 및 권한 중복 확인을 포함합니다. 도메인 모델에 우선순위 기반 역할 비교 시스템도 도입됩니다.

변경사항

Cohort / File(s) 요약
Web Controller 계층
MemberController.java, PermissionController.java
MemberController에 DeleteMapping, PatchMapping 주석 추가. PermissionController 신규 생성으로 POST /v1/groups/{groupId}/permissions 엔드포인트 추가 및 권한 추가 처리.
Request/Response DTO
AddPermissionRequestDto.java, AddPermissionResponseDto.java
권한 추가 요청/응답을 위한 신규 레코드 클래스 추가. ResponseDto는 AddPermissionResult를 변환하는 정적 팩토리 메서드 포함.
Use Case & 명령/결과
AddPermissionUseCase.java, AddPermissionCommand.java, AddPermissionResult.java
권한 추가 기능의 포트-어댑터 패턴 구현. Command는 userId, groupId, 역할, 권한 정보 전달. Result는 권한 목록과 역할 정보 반환.
Service 구현
AddPermissionService.java
AddPermissionUseCase 구현. 사용자 역할 조회, 권한 보유 확인, 역할 계층 검증, 중복 권한 확인 후 권한 추가 처리 (@Transactional).
Repository Port
GroupRoleRepositoryPort.java
addPermission, existPermission, findRole 메서드 신규 추가로 권한 관리 및 역할 조회 인터페이스 확장.
Repository Adapter & JPA
GroupRoleRepositoryAdapter.java, GroupMemberRepository.java, GroupRolePermissionRepository.java
GroupRoleRepositoryAdapter에서 권한 추가/확인 로직 구현. JPA Repository에 권한 존재 여부 및 역할별 권한 목록 조회 메서드 추가.
Domain Model
GroupMemberRole.java
OWNER(4), HEAD_MANAGER(3), MANAGER(2), MEMBER(1)의 우선순위 필드 추가. isHigherThan(), isAtLeast() 메서드로 역할 계층 비교 기능 제공.

Sequence Diagram

sequenceDiagram
    participant Client
    participant PermissionController
    participant AddPermissionService
    participant GroupRoleRepositoryPort
    participant Database

    Client->>PermissionController: POST /v1/groups/{groupId}/permissions<br/>(userId, groupId, changeRole, permission)
    
    PermissionController->>AddPermissionService: addPermission(AddPermissionCommand)
    
    AddPermissionService->>GroupRoleRepositoryPort: findRole(userId, groupId)
    GroupRoleRepositoryPort->>Database: SELECT user role
    Database-->>GroupRoleRepositoryPort: GroupMemberRole
    GroupRoleRepositoryPort-->>AddPermissionService: role
    
    AddPermissionService->>GroupRoleRepositoryPort: checkPermission(userId, groupId, permission)
    GroupRoleRepositoryPort->>Database: SELECT user permission
    Database-->>GroupRoleRepositoryPort: permission exists
    GroupRoleRepositoryPort-->>AddPermissionService: validated
    
    AddPermissionService->>AddPermissionService: role.isHigherThan(changeRole)
    
    AddPermissionService->>GroupRoleRepositoryPort: existPermission(changeRole, groupId, permission)
    GroupRoleRepositoryPort->>Database: SELECT target permission
    Database-->>GroupRoleRepositoryPort: permission exists?
    GroupRoleRepositoryPort-->>AddPermissionService: false (not exists)
    
    AddPermissionService->>GroupRoleRepositoryPort: addPermission(groupId, changeRole, permission)
    GroupRoleRepositoryPort->>Database: INSERT permission
    Database-->>GroupRoleRepositoryPort: List<GroupPermission>
    GroupRoleRepositoryPort-->>AddPermissionService: permissions
    
    AddPermissionService-->>PermissionController: AddPermissionResult
    
    PermissionController->>PermissionController: AddPermissionResponseDto.from(result)
    PermissionController-->>Client: 200 OK + AddPermissionResponseDto
Loading

코드 리뷰 예상 난이도

🎯 3 (중간) | ⏱️ ~20분

관련 PR

🐰 권한 시스템을 짜고 짰네요,
역할 계층을 우선순위로 쌓고,
검증 로직 촘촘하게 짜서,
중복 없이 깔끔하게 담았어요!
다채로운 권한 관리의 시작이라네요~✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% 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 제목이 변경 사항의 주요 내용을 명확하게 설명하고 있습니다. 그룹 권한 추가 API 기능 구현이 이 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 feat/add-down-permission

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

🧹 Nitpick comments (7)
src/main/java/flipnote/group/infrastructure/persistence/jpa/GroupMemberRepository.java (1)

26-26: 매개변수 이름 id가 메서드명과 일치하지 않습니다.

메서드명이 existsByUserIdAndRole_Id인데, 두 번째 매개변수가 id로 되어 있어 혼란을 줄 수 있습니다. roleId로 변경하면 메서드의 의도가 더 명확해집니다.

♻️ 매개변수명 수정 제안
-	boolean existsByUserIdAndRole_Id(Long userId, Long id);
+	boolean existsByUserIdAndRole_Id(Long userId, Long roleId);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/flipnote/group/infrastructure/persistence/jpa/GroupMemberRepository.java`
at line 26, 메서드 existsByUserIdAndRole_Id의 두 번째 매개변수명이 현재 id로 되어 있어 메서드명과 불일치하므로,
메서드 서명을 boolean existsByUserIdAndRole_Id(Long userId, Long roleId)로 변경해 의도를 명확히
하고 관련 호출부(이 리포지토리 메서드를 사용하는 서비스/테스트 코드)에서 매개변수 이름을 roleId로 맞춰 수정하세요.
src/main/java/flipnote/group/application/port/in/command/AddPermissionCommand.java (1)

6-11: 입력 유효성 검증 추가를 고려해보세요.

Command 객체에 null 또는 잘못된 값이 전달될 경우를 대비하여, Bean Validation 어노테이션(@NotNull, @Positive 등)을 추가하거나 compact constructor에서 유효성 검증을 수행하는 것을 권장합니다.

♻️ 선택적 유효성 검증 추가 예시
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Positive;
+
 public record AddPermissionCommand(
-	Long userId,
-	Long groupId,
-	GroupMemberRole changeRole,
-	GroupPermission permission) {
+	`@NotNull` `@Positive` Long userId,
+	`@NotNull` `@Positive` Long groupId,
+	`@NotNull` GroupMemberRole changeRole,
+	`@NotNull` GroupPermission permission) {
 
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/flipnote/group/application/port/in/command/AddPermissionCommand.java`
around lines 6 - 11, AddPermissionCommand 레코드의 입력에 대한 유효성 검증이 빠져 있어 null 또는 부적절한
값이 들어올 수 있으니, AddPermissionCommand의 필드(userId, groupId, changeRole, permission)에
대해 `@NotNull` 및 아이디에 대해 `@Positive` 같은 Bean Validation 어노테이션을 추가하거나
AddPermissionCommand의 compact constructor를 구현해 userId와 groupId가 null 또는 <=0 이
아닌지, changeRole와 permission이 null이 아닌지 검사하고 유효하지 않으면 IllegalArgumentException을
던지도록 변경하세요.
src/main/java/flipnote/group/api/dto/request/AddPermissionRequestDto.java (1)

6-10: API 요청 DTO에 유효성 검증 어노테이션 추가를 권장합니다.

REST API 요청 바인딩에 사용되는 DTO이므로, @NotNull 등의 Bean Validation 어노테이션을 추가하여 잘못된 요청을 조기에 차단하는 것이 좋습니다.

♻️ 유효성 검증 추가 제안
+import jakarta.validation.constraints.NotNull;
+
 public record AddPermissionRequestDto(
-	GroupMemberRole changeRole,
-	GroupPermission permission
+	`@NotNull` GroupMemberRole changeRole,
+	`@NotNull` GroupPermission permission
 ) {
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/flipnote/group/api/dto/request/AddPermissionRequestDto.java`
around lines 6 - 10, Add Bean Validation annotations to the
AddPermissionRequestDto record by marking its components (changeRole and
permission) with `@NotNull` so invalid requests are rejected early; update the
record declaration in AddPermissionRequestDto to annotate the components, add
the corresponding import (javax.validation.constraints.NotNull) and ensure
controllers that accept this DTO have validation enabled (e.g., `@Valid` on the
parameter) so the annotations are enforced.
src/main/java/flipnote/group/infrastructure/persistence/jpa/GroupRolePermissionRepository.java (1)

13-15: 매개변수 이름을 명확하게 변경하는 것을 권장합니다.

id 매개변수는 다소 모호합니다. Spring Data JPA 메서드명에서 GroupRoleId를 참조하므로, 일관성을 위해 매개변수 이름을 groupRoleId로 변경하면 가독성이 향상됩니다.

♻️ 매개변수명 변경 제안
-	boolean existsByGroupRoleIdAndPermission(Long id, GroupPermission permission);
+	boolean existsByGroupRoleIdAndPermission(Long groupRoleId, GroupPermission permission);
 
-	List<PermissionEntity> findAllByGroupRoleId(Long id);
+	List<PermissionEntity> findAllByGroupRoleId(Long groupRoleId);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/flipnote/group/infrastructure/persistence/jpa/GroupRolePermissionRepository.java`
around lines 13 - 15, Rename the ambiguous parameter name `id` to `groupRoleId`
in the GroupRolePermissionRepository method signatures — specifically change the
parameter in existsByGroupRoleIdAndPermission(Long id, GroupPermission
permission) and findAllByGroupRoleId(Long id) to `groupRoleId`, and update any
call sites or references accordingly so method signatures and usage are
consistent with the Spring Data JPA property name.
src/main/java/flipnote/group/application/port/out/GroupRoleRepositoryPort.java (1)

18-18: 파라미터 이름 aLong이 명확하지 않음

aLong은 의미가 불분명합니다. 구현체(GroupRoleRepositoryAdapter)에서는 groupId로 사용하고 있으므로 인터페이스에서도 일관성 있게 groupId로 명명해주세요.

♻️ 파라미터 이름 수정 제안
-boolean existPermission(GroupMemberRole groupMemberRole, Long aLong, GroupPermission permission);
+boolean existPermission(GroupMemberRole groupMemberRole, Long groupId, GroupPermission permission);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/flipnote/group/application/port/out/GroupRoleRepositoryPort.java`
at line 18, Rename the ambiguous parameter aLong to groupId in the interface
method existPermission within GroupRoleRepositoryPort so it matches the meaning
used in the implementation; update the method signature boolean
existPermission(GroupMemberRole groupMemberRole, Long groupId, GroupPermission
permission) and ensure implementing class GroupRoleRepositoryAdapter (and any
other implementations) use the same parameter name to keep signatures
consistent.
src/main/java/flipnote/group/adapter/in/web/PermissionController.java (1)

4-4: 사용되지 않는 import 제거 필요

DeleteMapping이 import되어 있지만 현재 코드에서 사용되지 않습니다. 불필요한 import는 제거해주세요.

🧹 사용되지 않는 import 제거
 import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.PathVariable;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/flipnote/group/adapter/in/web/PermissionController.java` at
line 4, Remove the unused import of DeleteMapping in PermissionController.java:
locate the import line "import
org.springframework.web.bind.annotation.DeleteMapping;" and delete it so only
used imports remain (ensure compilation still passes and run the IDE/static
analyzer to confirm no other unused imports remain).
src/main/java/flipnote/group/application/service/AddPermissionService.java (1)

36-49: 예외 타입 세분화 고려

현재 모든 비즈니스 검증 실패 시 IllegalArgumentException을 사용하고 있습니다. 클라이언트가 오류 유형을 구분하기 어려울 수 있으므로, 향후 커스텀 예외(예: PermissionDeniedException, DuplicatePermissionException)로 세분화하는 것을 고려해보세요.

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

In `@src/main/java/flipnote/group/application/service/AddPermissionService.java`
around lines 36 - 49, Replace the generic IllegalArgumentException usages in
AddPermissionService with specific custom exceptions so clients can distinguish
error types: create (unchecked) exceptions like HostPermissionNotFoundException
and throw it when !existHostPermission, PermissionDeniedException and throw it
when !role.isHigherThan(cmd.changeRole()), and DuplicatePermissionException and
throw it when groupRoleRepository.existPermission(...) returns true; update any
method signatures or exception handling paths that expect
IllegalArgumentException and adjust unit/integration tests to assert the new
exception types (refer to symbols existHostPermission, role.isHigherThan,
groupRoleRepository.existPermission, and AddPermissionService).
🤖 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/flipnote/group/adapter/out/persistence/GroupRoleRepositoryAdapter.java`:
- Around line 140-146: In GroupRoleRepositoryAdapter.existPermission, the call
to groupRoleRepository.findByGroupIdAndRole can return null and is not
null-checked; update existPermission to mirror addPermission by checking the
returned RoleEntity (from findByGroupIdAndRole) and throw the same exception (or
handle identically) when null before calling
groupRolePermissionRepository.existsByGroupRoleIdAndPermission with
roleEntity.getId(); reference existPermission, findByGroupIdAndRole, RoleEntity,
addPermission, and
groupRolePermissionRepository.existsByGroupRoleIdAndPermission to locate and
apply the fix.
- Around line 115-131: In addPermission, guard against a null return from
groupRoleRepository.findByGroupIdAndRole by checking roleEntity for null before
using roleEntity.getId(); if null, throw a clear domain exception (or
IllegalArgumentException/NoSuchElementException) indicating the role for the
given groupId and GroupMemberRole was not found so you avoid the NPE in
PermissionEntity.builder and subsequent groupRolePermissionRepository calls;
update the method to validate roleEntity, throw the chosen exception with
context, and only proceed to build/save PermissionEntity and fetch permissions
when roleEntity is non-null.

---

Nitpick comments:
In `@src/main/java/flipnote/group/adapter/in/web/PermissionController.java`:
- Line 4: Remove the unused import of DeleteMapping in
PermissionController.java: locate the import line "import
org.springframework.web.bind.annotation.DeleteMapping;" and delete it so only
used imports remain (ensure compilation still passes and run the IDE/static
analyzer to confirm no other unused imports remain).

In `@src/main/java/flipnote/group/api/dto/request/AddPermissionRequestDto.java`:
- Around line 6-10: Add Bean Validation annotations to the
AddPermissionRequestDto record by marking its components (changeRole and
permission) with `@NotNull` so invalid requests are rejected early; update the
record declaration in AddPermissionRequestDto to annotate the components, add
the corresponding import (javax.validation.constraints.NotNull) and ensure
controllers that accept this DTO have validation enabled (e.g., `@Valid` on the
parameter) so the annotations are enforced.

In
`@src/main/java/flipnote/group/application/port/in/command/AddPermissionCommand.java`:
- Around line 6-11: AddPermissionCommand 레코드의 입력에 대한 유효성 검증이 빠져 있어 null 또는 부적절한
값이 들어올 수 있으니, AddPermissionCommand의 필드(userId, groupId, changeRole, permission)에
대해 `@NotNull` 및 아이디에 대해 `@Positive` 같은 Bean Validation 어노테이션을 추가하거나
AddPermissionCommand의 compact constructor를 구현해 userId와 groupId가 null 또는 <=0 이
아닌지, changeRole와 permission이 null이 아닌지 검사하고 유효하지 않으면 IllegalArgumentException을
던지도록 변경하세요.

In
`@src/main/java/flipnote/group/application/port/out/GroupRoleRepositoryPort.java`:
- Line 18: Rename the ambiguous parameter aLong to groupId in the interface
method existPermission within GroupRoleRepositoryPort so it matches the meaning
used in the implementation; update the method signature boolean
existPermission(GroupMemberRole groupMemberRole, Long groupId, GroupPermission
permission) and ensure implementing class GroupRoleRepositoryAdapter (and any
other implementations) use the same parameter name to keep signatures
consistent.

In `@src/main/java/flipnote/group/application/service/AddPermissionService.java`:
- Around line 36-49: Replace the generic IllegalArgumentException usages in
AddPermissionService with specific custom exceptions so clients can distinguish
error types: create (unchecked) exceptions like HostPermissionNotFoundException
and throw it when !existHostPermission, PermissionDeniedException and throw it
when !role.isHigherThan(cmd.changeRole()), and DuplicatePermissionException and
throw it when groupRoleRepository.existPermission(...) returns true; update any
method signatures or exception handling paths that expect
IllegalArgumentException and adjust unit/integration tests to assert the new
exception types (refer to symbols existHostPermission, role.isHigherThan,
groupRoleRepository.existPermission, and AddPermissionService).

In
`@src/main/java/flipnote/group/infrastructure/persistence/jpa/GroupMemberRepository.java`:
- Line 26: 메서드 existsByUserIdAndRole_Id의 두 번째 매개변수명이 현재 id로 되어 있어 메서드명과 불일치하므로,
메서드 서명을 boolean existsByUserIdAndRole_Id(Long userId, Long roleId)로 변경해 의도를 명확히
하고 관련 호출부(이 리포지토리 메서드를 사용하는 서비스/테스트 코드)에서 매개변수 이름을 roleId로 맞춰 수정하세요.

In
`@src/main/java/flipnote/group/infrastructure/persistence/jpa/GroupRolePermissionRepository.java`:
- Around line 13-15: Rename the ambiguous parameter name `id` to `groupRoleId`
in the GroupRolePermissionRepository method signatures — specifically change the
parameter in existsByGroupRoleIdAndPermission(Long id, GroupPermission
permission) and findAllByGroupRoleId(Long id) to `groupRoleId`, and update any
call sites or references accordingly so method signatures and usage are
consistent with the Spring Data JPA property name.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 490d2d5 and 84fc87d.

📒 Files selected for processing (13)
  • src/main/java/flipnote/group/adapter/in/web/MemberController.java
  • src/main/java/flipnote/group/adapter/in/web/PermissionController.java
  • src/main/java/flipnote/group/adapter/out/persistence/GroupRoleRepositoryAdapter.java
  • src/main/java/flipnote/group/api/dto/request/AddPermissionRequestDto.java
  • src/main/java/flipnote/group/api/dto/response/AddPermissionResponseDto.java
  • src/main/java/flipnote/group/application/port/in/AddPermissionUseCase.java
  • src/main/java/flipnote/group/application/port/in/command/AddPermissionCommand.java
  • src/main/java/flipnote/group/application/port/in/result/AddPermissionResult.java
  • src/main/java/flipnote/group/application/port/out/GroupRoleRepositoryPort.java
  • src/main/java/flipnote/group/application/service/AddPermissionService.java
  • src/main/java/flipnote/group/domain/model/member/GroupMemberRole.java
  • src/main/java/flipnote/group/infrastructure/persistence/jpa/GroupMemberRepository.java
  • src/main/java/flipnote/group/infrastructure/persistence/jpa/GroupRolePermissionRepository.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