Skip to content

Conversation

@stoneTiger0912
Copy link
Member

@stoneTiger0912 stoneTiger0912 commented Feb 11, 2026

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능
    • 그룹 삭제 기능이 추가되었습니다. 사용자는 이제 자신의 그룹을 삭제할 수 있습니다.

@stoneTiger0912 stoneTiger0912 self-assigned this Feb 11, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 11, 2026

개요

그룹 삭제 기능이 구현되었습니다. 클린 아키텍처의 각 계층을 따라 DeleteGroupUseCase 인터페이스, DeleteGroupCommand 레코드, DeleteGroupService 구현, 그리고 GroupController의 새로운 엔드포인트가 추가되었으며, 저장소 포트와 어댑터도 확장되었습니다.

변경 사항

Cohort / File(s) 요약
API 엔드포인트
src/main/java/flipnote/group/adapter/in/web/GroupController.java
새로운 deleteGroup 엔드포인트 추가 (@DeleteMapping("/{groupId}")). 헤더에서 사용자 ID, 경로에서 그룹 ID를 받아 DeleteGroupCommand를 구성하고 사용 사례를 호출한 후 HTTP 204를 반환합니다.
컨트롤러 스텁
src/main/java/flipnote/group/adapter/in/web/MemberController.java
멤버 관리 작업을 위한 플레이스홀더 TODO 주석이 포함된 새로운 공개 클래스 추가 (아직 구현되지 않음).
사용 사례 및 커맨드 정의
src/main/java/flipnote/group/application/port/in/DeleteGroupUseCase.java, src/main/java/flipnote/group/application/port/in/command/DeleteGroupCommand.java
DeleteGroupUseCase 인터페이스와 DeleteGroupCommand 레코드 추가. 커맨드는 userIdgroupId 필드를 정의합니다.
애플리케이션 서비스 구현
src/main/java/flipnote/group/application/service/DeleteGroupService.java
DeleteGroupUseCase를 구현하는 새로운 서비스 클래스. GroupRepositoryPort에 위임하여 삭제 로직을 처리합니다.
저장소 포트 및 어댑터
src/main/java/flipnote/group/application/port/out/GroupRepositoryPort.java, src/main/java/flipnote/group/adapter/out/persistence/GroupRepositoryAdapter.java
GroupRepositoryPort 인터페이스에 void delete(Long id) 메서드 추가. GroupRepositoryAdapter에서 이를 구현하여 groupRepository.deleteById(groupId)로 위임합니다.

예상 코드 검토 시간

🎯 3 (Moderate) | ⏱️ ~20 minutes

관련 가능성 있는 PR

  • Feat: [FN-297] 그룹 조회 API 구현  #2: 이 PR과 동일하게 GroupControllerGroupRepositoryPort/GroupRepositoryAdapter 클래스를 수정하여 새로운 그룹 생명주기 작업(이 PR은 삭제, 다른 PR은 조회/변경)을 추가하므로 동일한 클래스 및 저장소 포트/어댑터 인터페이스를 건드립니다.

🐰 그룹을 지우는 길, 깔끔하게 뚫렸네,
아키텍처 계층마다 한 걸음씩,
포트와 어댑터가 춤을 추고,
서비스가 커맨드를 받아 처리하니,
삭제의 우아함, DELETE 한 줄로 완성! 🗑️

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% 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 구현이라는 목표가 제목에 잘 드러나 있습니다.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/delete-group

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

🤖 Fix all issues with AI agents
In `@src/main/java/flipnote/group/adapter/in/web/GroupController.java`:
- Around line 118-136: Fix the typo in the TODO comment inside GroupController
(in the deleteGroup method of class GroupController): change both occurrences of
"권환" to "권한" so the TODO reads correctly (e.g., "추후 권한 체크 후 권한 확인 후 삭제"),
preserving the comment structure and spacing.

In
`@src/main/java/flipnote/group/adapter/out/persistence/GroupRepositoryAdapter.java`:
- Around line 39-42: The delete method in GroupRepositoryAdapter currently calls
groupRepository.deleteById(groupId) without checking existence, which is
inconsistent with findById's behavior; update GroupRepositoryAdapter.delete(Long
groupId) to first verify the group exists (e.g., use
groupRepository.existsById(groupId) or reuse findById logic) and if not present
throw the same IllegalArgumentException used elsewhere, otherwise call
groupRepository.deleteById(groupId) to perform the deletion so behavior and
client responses remain consistent.

In `@src/main/java/flipnote/group/application/service/DeleteGroupService.java`:
- Around line 10-19: Add transactional and ownership checks to
DeleteGroupService: annotate the class or deleteGroup method with
`@Transactional`, load the group via GroupRepositoryPort (e.g., findById or
getById) inside deleteGroup(DeleteGroupCommand cmd), verify that the fetched
group's ownerId equals cmd.userId, and if not throw an appropriate
access/authorization exception; only call groupRepository.delete(cmd.groupId())
after the existence and ownership checks succeed (and handle group-not-found by
throwing a not-found exception).
🧹 Nitpick comments (2)
src/main/java/flipnote/group/adapter/in/web/MemberController.java (1)

1-18: 스캐폴딩 전용 컨트롤러가 메인 브랜치에 병합됩니다.

이 파일은 구현이 전혀 없이 TODO 주석만 포함된 빈 클래스입니다. 그룹 삭제 API PR의 범위에 포함될 필요가 없어 보이며, 해당 기능을 실제 구현할 때 추가하는 것이 더 적절합니다.

만약 의도적으로 포함시킨 것이라면, 최소한 @RestController@RequestMapping 어노테이션을 미리 추가하는 것을 권장합니다.

src/main/java/flipnote/group/application/service/DeleteGroupService.java (1)

17-18: 소프트 삭제(Soft Delete) 고려 필요

현재 물리적 삭제(deleteById)를 수행하고 있습니다. 그룹에 속한 멤버, 노트 등 연관 데이터가 있을 경우 데이터 정합성 문제가 발생할 수 있습니다. 소프트 삭제(deleted 플래그 또는 deletedAt 타임스탬프) 도입을 검토해 보세요. 당장이 아니더라도 아키텍처 방향 결정이 필요한 사항입니다.

Comment on lines +118 to +136
/**
* 그룹 삭제
* todo 추후 권환 체크 후 권환 확인 후 삭제
* @param userId
* @param groupId
* @return
*/
@DeleteMapping("/{groupId}")
public ResponseEntity<Void> deleteGroup(
@RequestHeader("X-USER-ID") Long userId,
@PathVariable("groupId") Long groupId
) {

DeleteGroupCommand cmd = new DeleteGroupCommand(userId, groupId);

deleteGroupUseCase.deleteGroup(cmd);

return ResponseEntity.noContent().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 | 🟡 Minor

엔드포인트 구조는 적절합니다. TODO 코멘트에 오타가 있습니다.

Line 120: 권환권한 (2회 반복). 사소하지만 나중에 TODO를 검색할 때 혼동을 줄 수 있습니다.

-	 * todo 추후 권환 체크 후 권환 확인 후 삭제
+	 * todo 추후 권한 체크 후 권한 확인 후 삭제
🤖 Prompt for AI Agents
In `@src/main/java/flipnote/group/adapter/in/web/GroupController.java` around
lines 118 - 136, Fix the typo in the TODO comment inside GroupController (in the
deleteGroup method of class GroupController): change both occurrences of "권환" to
"권한" so the TODO reads correctly (e.g., "추후 권한 체크 후 권한 확인 후 삭제"), preserving the
comment structure and spacing.

Comment on lines +39 to +42
@Override
public void delete(Long groupId) {
groupRepository.deleteById(groupId);
}
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

존재하지 않는 그룹 삭제 시 예외 처리 부재

Spring Data JPA 3.x의 deleteById는 해당 ID의 엔티티가 존재하지 않아도 예외 없이 무시됩니다. 같은 클래스의 findById는 존재하지 않을 때 IllegalArgumentException을 던지므로 동작이 일관되지 않습니다. 존재하지 않는 그룹에 대해 204를 반환하면 클라이언트에게 잘못된 성공 신호를 줄 수 있습니다.

🔧 존재 확인 후 삭제하는 방식 제안
 `@Override`
 public void delete(Long groupId) {
-    groupRepository.deleteById(groupId);
+    if (!groupRepository.existsById(groupId)) {
+        throw new IllegalArgumentException("Group not Exist");
+    }
+    groupRepository.deleteById(groupId);
 }
📝 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
@Override
public void delete(Long groupId) {
groupRepository.deleteById(groupId);
}
`@Override`
public void delete(Long groupId) {
if (!groupRepository.existsById(groupId)) {
throw new IllegalArgumentException("Group not Exist");
}
groupRepository.deleteById(groupId);
}
🤖 Prompt for AI Agents
In
`@src/main/java/flipnote/group/adapter/out/persistence/GroupRepositoryAdapter.java`
around lines 39 - 42, The delete method in GroupRepositoryAdapter currently
calls groupRepository.deleteById(groupId) without checking existence, which is
inconsistent with findById's behavior; update GroupRepositoryAdapter.delete(Long
groupId) to first verify the group exists (e.g., use
groupRepository.existsById(groupId) or reuse findById logic) and if not present
throw the same IllegalArgumentException used elsewhere, otherwise call
groupRepository.deleteById(groupId) to perform the deletion so behavior and
client responses remain consistent.

Comment on lines +10 to +19
@Service
@RequiredArgsConstructor
public class DeleteGroupService implements DeleteGroupUseCase {

private final GroupRepositoryPort groupRepository;

@Override
public void deleteGroup(DeleteGroupCommand cmd) {
groupRepository.delete(cmd.groupId());
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

@Transactional 누락 및 권한 검증 부재

두 가지 문제가 있습니다:

  1. @Transactional 누락: 삭제는 쓰기 작업이므로 @Transactional 어노테이션이 필요합니다. 향후 삭제 로직이 복잡해지면(연관 데이터 정리 등) 트랜잭션 보장이 필수적입니다.

  2. userId가 사용되지 않음: DeleteGroupCommanduserId가 전달되지만 서비스에서 전혀 참조하지 않습니다. 현재 상태에서는 어떤 사용자든 임의의 그룹을 삭제할 수 있어 보안 위험이 있습니다. TODO로 남겨두셨지만, 최소한 그룹 소유자인지 확인하는 로직은 이 PR에 포함하는 것을 권장합니다.

🔧 `@Transactional` 추가 및 소유자 검증 제안
 package flipnote.group.application.service;

+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.stereotype.Service;

 import flipnote.group.application.port.in.DeleteGroupUseCase;
 import flipnote.group.application.port.in.command.DeleteGroupCommand;
 import flipnote.group.application.port.out.GroupRepositoryPort;
 import lombok.RequiredArgsConstructor;

 `@Service`
 `@RequiredArgsConstructor`
 public class DeleteGroupService implements DeleteGroupUseCase {

 	private final GroupRepositoryPort groupRepository;

 	`@Override`
+	`@Transactional`
 	public void deleteGroup(DeleteGroupCommand cmd) {
+		var group = groupRepository.findById(cmd.groupId());
+		// TODO: group.getOwnerId()와 cmd.userId() 비교하여 권한 검증
 		groupRepository.delete(cmd.groupId());
 	}

 }
🤖 Prompt for AI Agents
In `@src/main/java/flipnote/group/application/service/DeleteGroupService.java`
around lines 10 - 19, Add transactional and ownership checks to
DeleteGroupService: annotate the class or deleteGroup method with
`@Transactional`, load the group via GroupRepositoryPort (e.g., findById or
getById) inside deleteGroup(DeleteGroupCommand cmd), verify that the fetched
group's ownerId equals cmd.userId, and if not throw an appropriate
access/authorization exception; only call groupRepository.delete(cmd.groupId())
after the existence and ownership checks succeed (and handle group-not-found by
throwing a not-found exception).

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