Conversation
# Conflicts: # src/main/java/gg/agit/konect/domain/chat/controller/ChatApi.java # src/main/java/gg/agit/konect/domain/chat/service/ChatService.java
There was a problem hiding this comment.
Pull request overview
동아리(Club) 단위의 단체 채팅을 추가하고, 기존 1:1 채팅과 단체 채팅을 단일 API에서 통합 조회/전송할 수 있도록 채팅 도메인을 direct/group/unified로 재구성한 PR입니다. 또한 메시지 폴링 주기(1초)에 맞춰 접속 상태 TTL을 단축하고, 단체 채팅 푸시 알림 전송 로직을 추가합니다.
Changes:
- 단체 채팅용 DB 테이블/엔티티/레포지토리/서비스 추가 및 동아리 생성 시 단체 채팅방 자동 생성
- 채팅방 목록/메시지 조회/전송 API를 DIRECT/GROUP 타입으로 통합(unified) 제공
- Presence TTL(15s→5s) 조정 및 단체 채팅 푸시 알림 전송 기능 추가
Reviewed changes
Copilot reviewed 42 out of 42 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| src/main/resources/db/migration/V22__add_group_chat_tables.sql | 단체 채팅 테이블 생성 및 기존 동아리/멤버 기반 초기 데이터 삽입 |
| src/main/java/gg/agit/konect/global/code/ApiResponseCode.java | 단체 채팅 접근/채팅방 미존재 응답 코드 추가 |
| src/main/java/gg/agit/konect/domain/user/service/UserService.java | direct 패키지로 이동한 채팅 모델/레포지토리 import 반영 |
| src/main/java/gg/agit/konect/domain/notification/service/NotificationService.java | 단체 채팅 푸시 알림 전송 메서드 추가 및 PresenceService import 경로 변경 |
| src/main/java/gg/agit/konect/domain/club/service/ClubService.java | 동아리 생성 시 GroupChatRoom 자동 생성 |
| src/main/java/gg/agit/konect/domain/club/repository/ClubMemberRepository.java | 동아리 가입시각 조회/동아리 멤버 userId 목록 조회 등 단체 채팅에 필요한 쿼리 추가 |
| src/main/java/gg/agit/konect/domain/chat/unified/service/UnifiedChatService.java | DIRECT/GROUP 채팅방/메시지 API 응답을 통합하여 병합/정렬/변환 |
| src/main/java/gg/agit/konect/domain/chat/unified/service/ChatPresenceService.java | 패키지 이동 및 Presence TTL 5초로 조정 |
| src/main/java/gg/agit/konect/domain/chat/unified/enums/ChatType.java | DIRECT/GROUP 타입 구분 enum 추가 |
| src/main/java/gg/agit/konect/domain/chat/unified/dto/UnifiedChatRoomsResponse.java | 통합 채팅방 리스트 응답 DTO 추가 |
| src/main/java/gg/agit/konect/domain/chat/unified/dto/UnifiedChatRoomResponse.java | 통합 채팅방 항목 DTO 추가 |
| src/main/java/gg/agit/konect/domain/chat/unified/dto/UnifiedChatMessagesResponse.java | 통합 메시지 리스트 응답 DTO 추가 |
| src/main/java/gg/agit/konect/domain/chat/unified/dto/UnifiedChatMessageResponse.java | 통합 메시지 항목 DTO 추가 |
| src/main/java/gg/agit/konect/domain/chat/unified/controller/ChatController.java | 기존 채팅 컨트롤러를 unified로 이동하고 통합 서비스 기반으로 변경 |
| src/main/java/gg/agit/konect/domain/chat/unified/controller/ChatApi.java | 통합 채팅 API 스펙에 맞게 응답/파라미터 타입 변경 및 문구 일부 수정 |
| src/main/java/gg/agit/konect/domain/chat/group/service/GroupChatService.java | 단체 채팅방 목록/메시지 조회/전송/음소거 토글 등 핵심 비즈니스 로직 추가 |
| src/main/java/gg/agit/konect/domain/chat/group/repository/GroupChatRoomRepository.java | 단체 채팅방 레포지토리 추가 |
| src/main/java/gg/agit/konect/domain/chat/group/repository/GroupChatReadStatusRepository.java | 단체 채팅 읽음 상태 레포지토리 추가 |
| src/main/java/gg/agit/konect/domain/chat/group/repository/GroupChatNotificationSettingRepository.java | 단체 채팅 알림 설정(음소거) 레포지토리 추가 |
| src/main/java/gg/agit/konect/domain/chat/group/repository/GroupChatMessageRepository.java | 단체 채팅 메시지 레포지토리 추가 |
| src/main/java/gg/agit/konect/domain/chat/group/model/GroupChatRoom.java | 단체 채팅방 엔티티 추가 |
| src/main/java/gg/agit/konect/domain/chat/group/model/GroupChatReadStatusId.java | 읽음 상태 복합키 IdClass 추가 |
| src/main/java/gg/agit/konect/domain/chat/group/model/GroupChatReadStatus.java | 읽음 상태 엔티티 추가 |
| src/main/java/gg/agit/konect/domain/chat/group/model/GroupChatNotificationSetting.java | 음소거 설정 엔티티 추가 |
| src/main/java/gg/agit/konect/domain/chat/group/model/GroupChatMessage.java | 단체 채팅 메시지 엔티티 추가 |
| src/main/java/gg/agit/konect/domain/chat/group/dto/GroupChatRoomsResponse.java | 단체 채팅방 리스트 응답 DTO 추가 |
| src/main/java/gg/agit/konect/domain/chat/group/dto/GroupChatRoomResponse.java | 단체 채팅방 ID 응답 DTO 추가 |
| src/main/java/gg/agit/konect/domain/chat/group/dto/GroupChatMuteResponse.java | 음소거 상태 응답 DTO 추가 |
| src/main/java/gg/agit/konect/domain/chat/group/dto/GroupChatMessagesResponse.java | 단체 메시지 리스트 응답 DTO 추가 |
| src/main/java/gg/agit/konect/domain/chat/group/dto/GroupChatMessageResponse.java | 단체 메시지 응답 DTO 추가 |
| src/main/java/gg/agit/konect/domain/chat/direct/service/ChatService.java | 기존 ChatService를 direct로 이동 및 import/타입 참조 갱신 |
| src/main/java/gg/agit/konect/domain/chat/direct/repository/ChatRoomRepository.java | direct 패키지로 이동 및 model import 갱신 |
| src/main/java/gg/agit/konect/domain/chat/direct/repository/ChatMessageRepository.java | direct 패키지로 이동 및 DTO/model import/JPQL 타입 갱신 |
| src/main/java/gg/agit/konect/domain/chat/direct/model/ChatRoom.java | direct 패키지로 이동 |
| src/main/java/gg/agit/konect/domain/chat/direct/model/ChatMessage.java | direct 패키지로 이동 |
| src/main/java/gg/agit/konect/domain/chat/direct/dto/UnreadMessageCount.java | direct 패키지로 이동 |
| src/main/java/gg/agit/konect/domain/chat/direct/dto/ChatRoomsResponse.java | direct 패키지로 이동 및 model import 갱신 |
| src/main/java/gg/agit/konect/domain/chat/direct/dto/ChatRoomResponse.java | direct 패키지로 이동 및 model import 갱신 |
| src/main/java/gg/agit/konect/domain/chat/direct/dto/ChatRoomCreateRequest.java | direct 패키지로 이동 |
| src/main/java/gg/agit/konect/domain/chat/direct/dto/ChatMessagesResponse.java | direct 패키지로 이동 및 model import 갱신 |
| src/main/java/gg/agit/konect/domain/chat/direct/dto/ChatMessageSendRequest.java | direct 패키지로 이동 |
| src/main/java/gg/agit/konect/domain/chat/direct/dto/ChatMessageResponse.java | direct 패키지로 이동 및 model import 갱신 |
Comments suppressed due to low confidence (3)
src/main/java/gg/agit/konect/domain/chat/unified/controller/ChatApi.java:72
- Unified 엔드포인트에서 type(DIRECT|GROUP) 파라미터가 필수로 추가됐는데, Operation 설명의 에러 섹션이 아직 FORBIDDEN_CHAT_ROOM_ACCESS만 언급하고 있습니다. GROUP 타입일 때의 에러 코드(예: FORBIDDEN_GROUP_CHAT_ACCESS / NOT_FOUND_GROUP_CHAT_ROOM)와 type 파라미터 의미를 문서에 반영해 주세요.
src/main/java/gg/agit/konect/domain/chat/unified/controller/ChatApi.java:94 - sendMessage Operation 설명이 1:1 채팅 전제를 포함하고 있고(수신자 자동 설정 등), GROUP 타입에서는 동작이 다릅니다. type 파라미터에 따라 동작/에러가 달라지는 점을 문서에 분리해서 명확히 해 주세요.
src/main/java/gg/agit/konect/domain/chat/unified/service/ChatPresenceService.java:18 - Presence Redis 키가 roomId만으로 구성되도록 설계되어 있는데(상단 PREFIX/TTL 근처), direct 채팅방 id와 group 채팅방 id가 겹치면 서로의 접속 상태가 충돌할 수 있습니다. ChatType을 키에 포함시키거나(프리픽스 분리), recordPresence/isUserInChatRoom에 type 파라미터를 추가해 채팅 타입별 네임스페이스를 분리해 주세요.
src/main/java/gg/agit/konect/domain/chat/group/service/GroupChatService.java
Outdated
Show resolved
Hide resolved
src/main/java/gg/agit/konect/domain/chat/group/repository/GroupChatMessageRepository.java
Outdated
Show resolved
Hide resolved
...java/gg/agit/konect/domain/chat/group/repository/GroupChatNotificationSettingRepository.java
Outdated
Show resolved
Hide resolved
src/main/java/gg/agit/konect/domain/notification/service/NotificationService.java
Show resolved
Hide resolved
src/main/java/gg/agit/konect/domain/chat/group/repository/GroupChatMessageRepository.java
Outdated
Show resolved
Hide resolved
src/main/java/gg/agit/konect/domain/chat/group/model/GroupChatMessage.java
Show resolved
Hide resolved
src/main/java/gg/agit/konect/domain/notification/model/NotificationMuteSetting.java
Show resolved
Hide resolved
src/main/java/gg/agit/konect/domain/chat/group/model/GroupChatReadStatus.java
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 43 out of 43 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (4)
src/main/java/gg/agit/konect/domain/chat/unified/controller/ChatApi.java:69
getChatRoomMessages가 DIRECT/GROUP 모두를 처리하는데 Swagger 설명의 로직/에러가 1:1 채팅 기준(FORBIDDEN_CHAT_ROOM_ACCESS 등)만 적혀 있어 오해 소지가 있습니다.type=GROUP일 때의 동작과 에러 코드(FORBIDDEN_GROUP_CHAT_ACCESS/NOT_FOUND_GROUP_CHAT_ROOM 등)를 문서에 반영해 주세요.
src/main/java/gg/agit/konect/domain/chat/unified/controller/ChatApi.java:90sendMessage설명에 “수신자는 채팅방 상대방으로 자동 설정” 등 1:1 채팅 전제를 포함하고 있어type=GROUP호출 시와 맞지 않습니다. 그룹 채팅 전송 시의 동작/응답 필드 차이를 Swagger 설명에 명확히 추가해 주세요.
src/main/java/gg/agit/konect/domain/chat/unified/service/ChatPresenceService.java:18- Redis presence 키가 roomId/userId만으로 구성되어(예: chat:presence:room:{roomId}:user:{userId}) 1:1 채팅방 ID와 단체 채팅방 ID가 겹치면 서로의 접속 상태를 덮어쓰거나 잘못 감지할 수 있습니다. 채팅 타입(DIRECT/GROUP) 또는 테이블 구분자를 키에 포함하도록 prefix를 분리해 충돌을 방지해 주세요.
src/main/java/gg/agit/konect/domain/chat/unified/controller/ChatApi.java:75 - 통합 API로 바뀌면서
type쿼리 파라미터가 필수가 되었는데(기존 클라이언트는 미전달 가능) 이는 하위 호환성을 깨는 변경입니다. 가능하면type에 기본값(DIRECT)을 두거나 required=false 처리, 혹은 별도 엔드포인트로 분리해 호환성을 유지해 주세요.
| groupChatReadStatusRepository.findByRoomIdAndUserId(roomId, userId) | ||
| .ifPresentOrElse(status -> { | ||
| status.updateLastReadAt(lastReadAt); | ||
| }, () -> { | ||
| GroupChatRoom room = groupChatRoomRepository.getById(roomId); |
There was a problem hiding this comment.
updateLastReadAt에서 상태가 없을 때 조회 후 INSERT를 수행해 동시 요청 시 PK(room_id,user_id) 중복으로 저장이 실패할 수 있습니다. DB upsert 사용 또는 DataIntegrityViolation 처리 후 재조회하는 방식으로 경쟁 조건을 안전하게 처리해 주세요.
🔍 개요
🚀 주요 변경 내용
동아리별 단체 채팅 기능을 구현했습니다.
동아리를 새로 생성하면 단체 채팅방이 자동으로 만들어집니다.
채팅 메시지 폴링 주기가 1초 이므로 접속 상태 TTL을 15초 -> 5초로 수정했습니다.
sequenceDiagram autonumber actor C as Client participant CC as ChatController (unified) participant US as UnifiedChatService participant DS as ChatService (direct) participant GS as GroupChatService (group) participant CR as ChatRoomRepository (direct) participant GR as GroupChatRoomRepository (group) Note over C,US: 1) 채팅방 목록 통합 조회 (GET /chats/rooms) C->>CC: GET /chats/rooms CC->>US: getChatRooms(userId) US->>DS: getChatRooms(userId) DS-->>US: ChatRoomsResponse (1:1) US->>GS: getChatRooms(userId) GS-->>US: GroupChatRoomsResponse (단체) US-->>CC: UnifiedChatRoomsResponse (병합/정렬) CC-->>C: 200 OK Note over C,US: 2) 메시지 조회 (GET /chats/rooms/{roomId}?type=DIRECT|GROUP) C->>CC: GET /chats/rooms/{roomId}?type=... CC->>US: getMessages(userId, type, roomId, page, limit) alt type == DIRECT US->>DS: getChatRoomMessages(userId, roomId, page, limit) DS->>CR: findById/getById + message 조회 DS-->>US: ChatMessagesResponse else type == GROUP US->>GS: getMessagesByRoomId(roomId, userId, page, limit) GS->>GR: getById(roomId) GS-->>US: GroupChatMessagesResponse end US-->>CC: UnifiedChatMessagesResponse CC-->>C: 200 OK Note over C,US: 3) 메시지 전송 (POST /chats/rooms/{roomId}/messages?type=...) C->>CC: POST /chats/rooms/{roomId}/messages?type=... CC->>US: sendMessage(userId, type, roomId, request) alt type == DIRECT US->>DS: sendMessage(userId, roomId, request) DS-->>US: ChatMessageResponse else type == GROUP US->>GS: sendMessageByRoomId(roomId, userId, content) GS->>GR: getById(roomId) GS-->>US: GroupChatMessageResponse end US-->>CC: UnifiedChatMessageResponse CC-->>C: 200 OK💬 참고 사항
✅ Checklist (완료 조건)