Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import team.wego.wegobackend.group.v2.domain.repository.GroupUserV2QueryRepository;
import team.wego.wegobackend.group.v2.domain.repository.GroupUserV2Repository;
import team.wego.wegobackend.group.v2.domain.repository.GroupV2Repository;
import team.wego.wegobackend.user.domain.User;
import team.wego.wegobackend.user.repository.UserRepository;

@Slf4j
Expand All @@ -51,9 +52,8 @@ public class GroupV2AttendanceService {
@Transactional
public AttendanceGroupV2Response attend(Long userId, Long groupId, String message) {
// 회원 체크
if (userId == null) {
throw new GroupException(GroupErrorCode.USER_ID_NULL);
}
User member = userRepository.findById(userId)
.orElseThrow(() -> new GroupException(GroupErrorCode.USER_ID_NULL));
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

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

The error code USER_ID_NULL is being used when a user is not found in the database (via findById), but the error message "모임: 회원 ID가 null 입니다." (The member ID is null) is misleading in this context. The userId parameter is not null - it's being passed to findById. The actual issue is that the user doesn't exist in the database. Consider using a more appropriate error code like GROUP_USER_NOT_FOUND or creating a new error code that accurately reflects that the user doesn't exist.

Suggested change
.orElseThrow(() -> new GroupException(GroupErrorCode.USER_ID_NULL));
.orElseThrow(() -> new GroupException(GroupErrorCode.GROUP_USER_NOT_FOUND));

Copilot uses AI. Check for mistakes.

// 모임 체크: for update로 가져오기
GroupV2 group = groupV2Repository.findByIdForUpdate(groupId)
Expand Down Expand Up @@ -119,7 +119,8 @@ public AttendanceGroupV2Response attend(Long userId, Long groupId, String messag
}

// FULL 자동 전환
long newCount = groupUserV2Repository.countByGroupIdAndStatus(groupId, GroupUserV2Status.ATTEND);
long newCount = groupUserV2Repository.countByGroupIdAndStatus(groupId,
GroupUserV2Status.ATTEND);

if (newCount == group.getMaxParticipants()
&& group.getStatus() == GroupV2Status.RECRUITING) {
Expand All @@ -132,6 +133,8 @@ public AttendanceGroupV2Response attend(Long userId, Long groupId, String messag
eventPublisher.publishEvent(
new GroupJoinedEvent(groupId, group.getHost().getId(), userId));

member.increaseGroupJoinedCount();
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

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

The groupJoinedCount is incremented when a user re-attends a group (after leaving, getting kicked, rejected, or cancelled), but there is no corresponding decrement when the user leaves the group. In the 'left' method at line 173-226, when a user's status changes to LEFT, the counter is not decremented. This will cause the counter to continuously increase even when users leave and re-join the same group multiple times, leading to inaccurate tracking of actual group participation. Consider adding member.decreaseGroupJoinedCount() in the 'left' method when the status changes to LEFT.

Copilot uses AI. Check for mistakes.

return AttendanceGroupV2Response.of(group, newCount, membership);
}

Expand Down Expand Up @@ -298,6 +301,11 @@ public GroupUserV2StatusResponse approve(Long approverUserId, Long groupId,
group.changeStatus(GroupV2Status.FULL);
}

User member = userRepository.findById(targetUserId)
.orElseThrow(() -> new GroupException(GroupErrorCode.USER_ID_NULL, targetUserId));
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

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

The error code USER_ID_NULL is being used when a user is not found in the database (via findById), but the error message "모임: 회원 ID가 null 입니다." (The member ID is null) is misleading in this context. The userId parameter is not null - it's being passed to findById. The actual issue is that the user doesn't exist in the database. Consider using a more appropriate error code like GROUP_USER_NOT_FOUND or creating a new error code that accurately reflects that the user doesn't exist.

Suggested change
.orElseThrow(() -> new GroupException(GroupErrorCode.USER_ID_NULL, targetUserId));
.orElseThrow(() -> new GroupException(GroupErrorCode.GROUP_USER_NOT_FOUND, targetUserId));

Copilot uses AI. Check for mistakes.

member.increaseGroupJoinedCount();
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

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

The groupJoinedCount is incremented when a user is approved to join a group, but similar to the attend method, there is no corresponding decrement when users leave. When a user who was approved later leaves the group (via the 'left' method or gets kicked), their counter should be decremented to maintain accuracy. This same issue affects the kick scenario as well - users who are kicked from a group should have their groupJoinedCount decremented.

Copilot uses AI. Check for mistakes.

eventPublisher.publishEvent(
new GroupJoinApprovedEvent(groupId, approverUserId, targetUserId));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,11 +202,14 @@ public CreateGroupV2Response create(Long userId, CreateGroupV2Request request) {

groupCreateCooldownService.acquireOrThrowWithRollbackRelease(userId, COOL_DOWN_SECONDS);

// 회원 조회
// 회원 조회 후 카운트
User host = userRepository.findById(userId)
.orElseThrow(() -> new GroupException(GroupErrorCode.HOST_USER_NOT_FOUND, userId)
);

Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

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

When a host creates a group, both groupCreatedCount and groupJoinedCount are incremented. While this may be intentional (the host both creates and joins the group), it's worth noting that if the host later deletes the group or leaves (though the code prevents hosts from leaving), there should be corresponding decrements for both counters. Currently, no decrement logic exists for group deletion or other scenarios. Consider documenting this behavior or implementing symmetric decrement logic.

Suggested change
// NOTE:
// - The host both creates and joins the group, so we increment both counters here.
// - These counters are intended as lifetime statistics (total created / total joined)
// and are not decremented on group deletion or when a host leaves.

Copilot uses AI. Check for mistakes.
host.increaseGroupCreatedCount();
host.increaseGroupJoinedCount();

// 모임 주소 생성
GroupV2Address address = GroupV2Address.of(request.location(), request.locationDetail());

Expand Down Expand Up @@ -283,9 +286,15 @@ public GetGroupV2Response getGroup(Long userId, Long groupId) {
.orElseThrow(
() -> new GroupException(GroupErrorCode.GROUP_NOT_FOUND_BY_ID, groupId));

// HOST 여부에 따라 응답 결과를 분기 처리하자.
boolean isHost = group.getHost().getId().equals(userId);

List<GroupUserV2> users = isHost
? groupUserV2Repository.findByGroupIdOrderByJoinedAtAscWithUser(groupId)
: groupUserV2Repository.findAttendByGroupIdOrderByJoinedAtAscWithUser(groupId);

// 컬렉션은 안전하게 따로 보관해서 옮겨야 좋다고 한다.
List<GroupImageV2> images = groupImageV2Repository.findAllByGroupIdWithVariants(groupId);
List<GroupUserV2> users = groupUserV2Repository.findAllByGroupIdWithUser(groupId);

Long chatRoomId = group.getChatRoom() != null ? group.getChatRoom().getId() : null;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,24 @@ List<Long> findUserIdsByGroupIdAndStatuses(
@Modifying(clearAutomatically = true, flushAutomatically = true)
@Query("delete from GroupUserV2 gu where gu.user.id = :userId")
void deleteByUserId(@Param("userId") Long userId);

@Query("""
select gu
from GroupUserV2 gu
join fetch gu.user u
where gu.group.id = :groupId
order by gu.joinedAt asc
""")
List<GroupUserV2> findByGroupIdOrderByJoinedAtAscWithUser(@Param("groupId") Long groupId);
Comment on lines +68 to +75
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

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

The sorting by joinedAt may produce unexpected results when users re-join a group. The joinedAt field is updated to the current time when a user re-attends a group (via reAttend() at line 84 in GroupUserV2.java or requestJoin() at line 164). This means users who leave and re-join will appear at the end of the list, potentially after users who joined later originally. If the intent is to sort by the original join time regardless of re-joins, consider using a separate field for the original join timestamp or clarify the expected behavior in comments.

Copilot uses AI. Check for mistakes.

@Query("""
select gu
from GroupUserV2 gu
join fetch gu.user u
where gu.group.id = :groupId
and gu.status = 'ATTEND'
order by gu.joinedAt asc
""")
List<GroupUserV2> findAttendByGroupIdOrderByJoinedAtAscWithUser(@Param("groupId") Long groupId);
Comment on lines +82 to +85
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

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

Using a hard-coded string literal 'ATTEND' in the JPQL query instead of a parameterized value. This is inconsistent with other queries in this file (like findUserIdsByGroupIdAndStatus at line 37) that use proper parameters for status values. Consider using a parameter for the status value to maintain consistency, improve type safety, and prevent potential typos.

Suggested change
and gu.status = 'ATTEND'
order by gu.joinedAt asc
""")
List<GroupUserV2> findAttendByGroupIdOrderByJoinedAtAscWithUser(@Param("groupId") Long groupId);
and gu.status = :status
order by gu.joinedAt asc
""")
List<GroupUserV2> findAttendByGroupIdOrderByJoinedAtAscWithUser(@Param("groupId") Long groupId,
@Param("status") GroupUserV2Status status);

Copilot uses AI. Check for mistakes.

}
Loading