Skip to content

[FEAT] 모임 취소 구현 #55

Merged
LimdaeIl merged 2 commits intomainfrom
feat/group-left
Dec 9, 2025
Merged

[FEAT] 모임 취소 구현 #55
LimdaeIl merged 2 commits intomainfrom
feat/group-left

Conversation

@LimdaeIl
Copy link
Collaborator

@LimdaeIl LimdaeIl commented Dec 9, 2025

📝 Pull Request

📌 PR 종류

해당하는 항목에 체크해주세요.

  • 기능 추가 (Feature)
  • 버그 수정 (Fix)
  • 문서 수정 (Docs)
  • 코드 리팩터링 (Refactor)
  • 테스트 추가 (Test)
  • 기타 변경 (Chore)

✨ 변경 내용

모임 참여 취소를 구현합니다.

🔍 관련 이슈

🧪 테스트

변경된 기능에 대한 테스트 범위 또는 테스트 결과를 작성해주세요.

  • 유닛 테스트 추가 / 수정
  • 통합 테스트 검증
  • 수동 테스트 완료

🚨 확인해야 할 사항 (Checklist)

PR을 제출하기 전에 아래 항목들을 확인해주세요.

  • 코드 포매팅 완료
  • 불필요한 파일/코드 제거
  • 로직 검증 완료
  • 프로젝트 빌드 성공
  • 린트/정적 분석 통과 (해당 시)

🙋 기타 참고 사항

리뷰어가 참고하면 좋을 만한 추가 설명이 있다면 적어주세요.

Summary by CodeRabbit

릴리스 노트

  • New Features
    • 그룹 참여 취소 기능 추가: 사용자가 참여 중인 그룹에서 나갈 수 있습니다.
    • 호스트 보호: 그룹 호스트는 자신의 그룹에서 나갈 수 없습니다.
    • 참여 상태 검증: 이미 나간 회원이나 참여하지 않은 회원의 취소 요청을 방지합니다.

✏️ Tip: You can customize this high-level summary in your review settings.

@LimdaeIl LimdaeIl self-assigned this Dec 9, 2025
Copilot AI review requested due to automatic review settings December 9, 2025 14:38
@LimdaeIl LimdaeIl added the ✨enhancement New feature or request label Dec 9, 2025
@coderabbitai
Copy link

coderabbitai bot commented Dec 9, 2025

Walkthrough

그룹 참석 취소 기능을 구현합니다. GroupService에 cancelAttendGroup 메서드를 추가하고, 호스트 탈퇴 금지 및 미참석 회원 검증 에러코드 2개를 등록합니다. 컨트롤러 엔드포인트와 통합 테스트 시나리오를 함께 추가합니다.

Changes

Cohort / File(s) Change Summary
참석 취소 핵심 로직
src/main/java/team/wego/wegobackend/group/application/service/GroupService.java
cancelAttendGroup(groupId, memberId) 메서드 추가: 그룹 및 회원 검증, GroupUser 관계 조회, 호스트 탈퇴 금지 검증, 미참석 상태 검증, leave() 수행 후 응답 반환
도메인 에러 처리
src/main/java/team/wego/wegobackend/group/domain/exception/GroupErrorCode.java
NOT_ATTEND_GROUP(참여 없음 또는 이미 나감), HOST_CANNOT_LEAVE_OWN_GROUP(호스트 탈퇴 금지) 에러코드 추가; GROUP_CAPACITY_EXCEEDED 뒤에 쉼표 추가
API 엔드포인트
src/main/java/team/wego/wegobackend/group/presentation/GroupController.java
POST /api/v1/groups/{groupId}/cancel 엔드포인트 추가; cancelAttendGroup(groupId, userId) 호출 및 ApiResponse 반환; attendGroup 반환문 서식 조정
통합 테스트 시나리오
src/test/http/group/cancel.http
회원가입(HOST) → 로그인 → 이미지 업로드 → 그룹 생성 → 추가 회원 가입/로그인 → 그룹 참석 → 참석 취소 흐름의 멀티스텝 HTTP 테스트 스크립트

Sequence Diagram

sequenceDiagram
    participant Client
    participant Controller as GroupController
    participant Service as GroupService
    participant Repo as Repository<br/>(Group, GroupUser)
    participant DB as Database

    Client->>Controller: POST /cancel<br/>groupId, userId
    Controller->>Service: cancelAttendGroup(groupId, userId)
    
    Service->>Repo: loadGroup(groupId)<br/>excludeSoftDeleted
    Repo->>DB: Query Group
    DB-->>Repo: Group Entity
    Repo-->>Service: Group
    
    Service->>Repo: loadMember(memberId)
    Repo->>DB: Query Member
    DB-->>Repo: Member Entity
    Repo-->>Service: Member
    
    Service->>Repo: findGroupUser(group, member)
    Repo->>DB: Query GroupUser
    DB-->>Repo: GroupUser
    Repo-->>Service: GroupUser
    
    Note over Service: Validate:<br/>1. Not HOST<br/>2. Status ≠ LEFT
    
    alt Validation Fails
        Service-->>Controller: Throw Exception<br/>(HOST_CANNOT_LEAVE_OWN_GROUP<br/>or NOT_ATTEND_GROUP)
        Controller-->>Client: 400 Bad Request
    else Validation Passes
        Service->>Repo: leave() on GroupUser
        Repo->>DB: Update GroupUser Status
        DB-->>Repo: Success
        
        Service->>Repo: buildGetGroupResponse(group)
        Repo-->>Service: GetGroupResponse
        
        Service-->>Controller: GetGroupResponse
        Controller-->>Client: 200 OK<br/>+ GetGroupResponse
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • 검증 로직: 호스트 탈퇴 금지, 미참석 상태 검증 등 여러 조건 확인 필요
  • 상태 전환: attendGroup과 유사하면서도 반대 로직으로 동작하므로 일관성 검증 필요
  • 에러 코드: 새로운 에러 처리 경로 2개 추가로 기존 흐름과의 통합 확인
  • 테스트 시나리오: 전체 워크플로우 검증으로 정상 동작 확인

추가 주의사항:

  • cancelAttendGroup에서 상태 전환 로직이 leave() 메서드에 올바르게 구현되었는지 확인
  • 호스트 검증 순서와 에러 우선순위 확인 (호스트 먼저 검증하는지, 미참석 상태 검증이 맞는지)
  • HTTP 테스트에서 토큰 및 userId 재사용이 올바르게 수행되는지 검증

Possibly related PRs

  • [FEAT] 모임 상세 조회 구현 #50: attendGroup 메서드와 GroupUser 상태 전환 로직을 정의하였으며, cancelAttendGroup은 이를 반대로 처리하는 보완 기능으로 동일한 도메인 흐름 내에서 일관성 있는 구현 필요

Poem

🐰 모임을 나가는 길도 들어가는 길처럼,
정중히 호스트만 남겨두고,
검증은 철저하게, 응답은 명확하게—
참석 취소의 춤이 흐르네! 🎭✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목은 '모임 취소 구현'으로 주요 변경사항인 모임 참여 취소 기능 추가를 명확하게 요약합니다.
Linked Issues check ✅ Passed 변경사항이 #52 요구사항을 충족합니다. cancelAttendGroup API가 구현되었고, 참여 취소 기능을 제공하며, 에러 처리와 일관된 응답 생성이 포함되어 있습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 #52의 모임 취소 기능 범위 내에 있습니다. 추가적인 범위 외 변경사항은 없습니다.
✨ 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/group-left

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

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements group attendance cancellation functionality, allowing members to leave groups they have joined. The implementation includes proper validation to prevent hosts from leaving their own groups and ensures members can only cancel if they are currently attending.

  • Added cancelAttendGroup endpoint and service method with business rule validation
  • Introduced two new error codes for handling cancellation edge cases
  • Created HTTP test file for manual testing of the cancellation flow

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
src/main/java/team/wego/wegobackend/group/presentation/GroupController.java Added /cancel POST endpoint to handle group attendance cancellation requests
src/main/java/team/wego/wegobackend/group/application/service/GroupService.java Implemented cancelAttendGroup method with validation for HOST restriction and attendance status
src/main/java/team/wego/wegobackend/group/domain/exception/GroupErrorCode.java Added error codes for non-attending members and HOST leave prevention
src/test/http/group/cancel.http Added manual test scenarios for the cancellation feature with member registration and login flows

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

> {%
// 응답 구조에 따라 수정 필요
// 예: { "userId": 1, ... } 라면 아래처럼 유지
client.global.set("memberId1", response.body.data.userId);
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

The variable name should be memberId2 instead of memberId1 for MEMBER 2. This overwrites the previously set memberId1 value from line 109.

Suggested change
client.global.set("memberId1", response.body.data.userId);
client.global.set("memberId2", response.body.data.userId);

Copilot uses AI. Check for mistakes.
Content-Type: application/json

{
"email": "test1@example.com",
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

The login credentials are incorrect. This should use test2@example.com to match the MEMBER 2 account created in line 140, not test1@example.com.

Suggested change
"email": "test1@example.com",
"email": "test2@example.com",

Copilot uses AI. Check for mistakes.
@LimdaeIl LimdaeIl merged commit a686741 into main Dec 9, 2025
6 of 7 checks passed
@github-project-automation github-project-automation bot moved this from Backlog to Done in WeGo-Together Backend Dec 9, 2025
@LimdaeIl LimdaeIl deleted the feat/group-left branch December 9, 2025 14:42
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

🧹 Nitpick comments (2)
src/main/java/team/wego/wegobackend/group/presentation/GroupController.java (1)

50-53: 모임 취소 엔드포인트 구현 방향 적절함

attendGroup와 동일한 패턴으로 cancelAttendGroup을 구성해서 응답 형태와 상태코드가 일관적이고, 서비스 레이어 위임도 명확합니다. 지금은 userId를 쿼리 파라미터로 받되 TODO로 인증 연동을 명시해 둔 것도 괜찮아 보입니다. 추후 인증 정보를 붙일 때에는 토큰의 사용자 ID와 userId 파라미터 불일치에 대한 방어 로직까지 같이 고려해 주시면 좋겠습니다.

Also applies to: 56-68

src/main/java/team/wego/wegobackend/group/application/service/GroupService.java (1)

247-276: 참석 취소 도메인 로직 일관적이며 예외 처리도 적절합니다

모임/회원 조회 → GroupUser 조회 → HOST 방지 → 이미 LEFT 상태 방지 → leave() 후 최신 상세 응답 반환까지 플로우가 attendGroup과 대칭적으로 잘 잡혀 있습니다. 예외 코드도 NOT_ATTEND_GROUP/HOST_CANNOT_LEAVE_OWN_GROUP와 정확히 매핑되어 이해하기 쉽습니다.

추가로, 나중에 정리할 때 attendGroup/cancelAttendGroup에서 공통으로 사용하는 그룹·회원·GroupUser 조회 부분을 private 메서드로 추출하면 중복이 줄어서 유지보수에 더 좋을 것 같습니다.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c789b0a and 68fd54f.

📒 Files selected for processing (4)
  • src/main/java/team/wego/wegobackend/group/application/service/GroupService.java (1 hunks)
  • src/main/java/team/wego/wegobackend/group/domain/exception/GroupErrorCode.java (1 hunks)
  • src/main/java/team/wego/wegobackend/group/presentation/GroupController.java (1 hunks)
  • src/test/http/group/cancel.http (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: CodeQL analysis (java)
  • GitHub Check: Agent
🔇 Additional comments (1)
src/main/java/team/wego/wegobackend/group/domain/exception/GroupErrorCode.java (1)

22-24: 취소 플로우용 에러 코드 정의가 서비스 구현과 잘 맞습니다

NOT_ATTEND_GROUP, HOST_CANNOT_LEAVE_OWN_GROUP 모두 메시지와 포맷 인자(모임 ID, 회원 ID)가 cancelAttendGroup에서 던지는 예외와 정확히 대응하고 있어 도메인 규칙 표현이 명확합니다. 추가 수정 필요 없어 보입니다.

Comment on lines +95 to +183
### 회원가입(MEMBER 1)
POST http://localhost:8080/api/v1/auth/signup
Content-Type: application/json

{
"email": "test1@example.com",
"password": "Test1234!@#",
"nickName": "Heemo",
"phoneNumber": "010-1234-5678"
}

> {%
// 응답 구조에 따라 수정 필요
// 예: { "userId": 1, ... } 라면 아래처럼 유지
client.global.set("memberId1", response.body.data.userId);
%}

### 로그인 (MEMBER 1)
POST http://localhost:8080/api/v1/auth/login
Content-Type: application/json

{
"email": "test1@example.com",
"password": "Test1234!@#"
}

> {%
client.global.set("accessTokenByMember1", response.body.data.accessToken);
%}

### 모임 참여 (MEMBER 1)
POST http://localhost:8080/api/v1/groups/{{groupId_png_jpg}}/attend
?userId=2
Content-Type: application/json
Authorization: Bearer {{accessTokenByMember1}}

{

}

### 회원가입(MEMBER 2)
POST http://localhost:8080/api/v1/auth/signup
Content-Type: application/json

{
"email": "test2@example.com",
"password": "Test1234!@#",
"nickName": "Qeemo",
"phoneNumber": "010-1234-5678"
}

> {%
// 응답 구조에 따라 수정 필요
// 예: { "userId": 1, ... } 라면 아래처럼 유지
client.global.set("memberId1", response.body.data.userId);
%}

### 로그인 (MEMBER 2)
POST http://localhost:8080/api/v1/auth/login
Content-Type: application/json

{
"email": "test1@example.com",
"password": "Test1234!@#"
}

> {%
client.global.set("accessTokenByMember2", response.body.data.accessToken);
%}

### 모임 참여 (MEMBER 2)
POST http://localhost:8080/api/v1/groups/{{groupId_png_jpg}}/attend
?userId=3
Content-Type: application/json
Authorization: Bearer {{accessTokenByMember2}}

{

}

### 모임 취소 (MEMBER 1)
POST http://localhost:8080/api/v1/groups/{{groupId_png_jpg}}/cancel
?userId=2
Content-Type: application/json
Authorization: Bearer {{accessTokenByMember1}}

{

} No newline at end of file
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

MEMBER 1/2 시나리오의 userId 및 로그인 정보 불일치로 테스트가 신뢰하기 어려운 상태입니다

모임 참석/취소 플로우 쪽에 몇 가지 문제가 있습니다.

  • MEMBER 1 참석 요청에서 ?userId=2를 하드코딩하고 있어, 실제로 발급된 memberId1과 DB 상태(선행 데이터)에 따라 불일치할 수 있습니다.
  • MEMBER 2 가입 후에도 전역 변수 이름을 memberId1로 다시 덮어쓰고 있어, MEMBER 1/2 ID가 섞입니다.
  • MEMBER 2 로그인 요청이 email: "test1@example.com"으로 MEMBER 1 계정을 다시 로그인하고 있습니다.
  • MEMBER 2 참석, MEMBER 1 취소 요청의 userId도 각각 3, 2로 하드코딩되어 있어, 실제 응답 값과 동기화되지 않습니다.

지금 상태로는 “어떤 유저가 어떤 토큰과 어떤 userId로 참석/취소하는지”가 꼬일 수 있어서, 새로 구현한 취소 기능을 검증하기 어렵습니다. 아래처럼 응답에서 받은 ID를 실제로 사용하도록 바꾸는 것을 제안드립니다.

### 모임 참여 (MEMBER 1)
POST http://localhost:8080/api/v1/groups/{{groupId_png_jpg}}/attend
-    ?userId=2
+    ?userId={{memberId1}}
 Content-Type: application/json
 Authorization: Bearer {{accessTokenByMember1}}
@@
 ### 회원가입(MEMBER 2)
@@
-  client.global.set("memberId1", response.body.data.userId);
+  client.global.set("memberId2", response.body.data.userId);
@@
 ### 로그인 (MEMBER 2)
@@
 {
-  "email": "test1@example.com",
+  "email": "test2@example.com",
   "password": "Test1234!@#"
 }
@@
 ### 모임 참여 (MEMBER 2)
 POST http://localhost:8080/api/v1/groups/{{groupId_png_jpg}}/attend
-    ?userId=3
+    ?userId={{memberId2}}
@@
 ### 모임 취소 (MEMBER 1)
 POST http://localhost:8080/api/v1/groups/{{groupId_png_jpg}}/cancel
-    ?userId=2
+    ?userId={{memberId1}}
 Content-Type: application/json
 Authorization: Bearer {{accessTokenByMember1}}

이렇게 수정하면 각 요청이 “해당 토큰으로 로그인한 실제 회원 ID”와 일치하게 되어, 참석/취소 로직을 더 정확하게 검증할 수 있습니다.

🤖 Prompt for AI Agents
In src/test/http/group/cancel.http around lines 95-183, the test hardcodes
userId values and reuses/overwrites global variables and login info causing
member IDs and tokens to be mismatched; change the script to store distinct
globals (e.g., memberId1 and memberId2) from each signup response, correct
MEMBER 2 login to use test2@example.com and store its accessToken into
accessTokenByMember2, and replace every hardcoded ?userId=2/3 with the
corresponding saved variable (use the memberIdX globals) so each attend/cancel
request uses the token and userId that were actually returned by the
signup/login responses.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨enhancement New feature or request

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[FEAT] 모임 취소 구현

1 participant