Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
98c7663
feat:채팅 서비스 구현
Sehi55 Feb 17, 2026
4d4607e
feat: 채팅방 나가기 ã메API 추가
Sehi55 Feb 17, 2026
37ea612
feat:채팅신고, 프로ê¸필 신고하기 구현
Sehi55 Feb 17, 2026
0376bd0
feat: loveview 프로필 사진 요청 구현
Sehi55 Feb 21, 2026
c847e1d
feat:meetingVerification 구현
Sehi55 Feb 22, 2026
ae2e0ad
fix:연애코드 프로필 사진 요청 상테 system 메시지 수정
Sehi55 Feb 25, 2026
8ad1ed5
fix:웹소켓 url 수정
Sehi55 Mar 2, 2026
98c5ab6
Merge branch 'feature/report' into temp
Sehi55 Mar 2, 2026
c60e405
merged report into temp
Sehi55 Mar 2, 2026
6d6deef
merged meetingVerification into temp
Sehi55 Mar 2, 2026
c6e56c4
fix:chatMemberRepository method
Sehi55 Mar 2, 2026
9bc05fe
merged feature/loveviewProfile into temp
Sehi55 Mar 2, 2026
0d66035
add flyway v12 sql file
Sehi55 Mar 2, 2026
2ced333
add flyway v11 sql file
Sehi55 Mar 2, 2026
b1dccbb
fix: flyway error
Sehi55 Mar 2, 2026
c6d13ef
fix: flyway error
Sehi55 Mar 2, 2026
dd3a47d
Merge branch 'develop' into temp
Sehi55 May 27, 2026
24f61ba
fix: merge develop branch
Sehi55 May 27, 2026
e3a08f9
fix: replace meeting hard delete with soft delete
Sehi55 May 27, 2026
9a34f66
fix: 웹소켓 커넥 할때 principal 이 생성되지 않아 채팅 보낼때 발생한 인증 오류 수정
Sehi55 May 27, 2026
dae01f0
refactor: 현재 참여중인 방인지 검증 로직 추가
Sehi55 May 28, 2026
922cab9
refactor: 쓰기 로직에 따라 readOnly=true 트랜잭션 컨텍스트 삭제
Sehi55 May 28, 2026
54f9a1a
refactor: @Transactional 추가로 영속성 컨텍스트 보장
Sehi55 May 28, 2026
b8f257e
refactor: 공백 삭제
Sehi55 May 28, 2026
97b5437
refactor: 쿼리 오류 수정
Sehi55 May 28, 2026
c66fbb9
refactor: builder 기본값 주입
Sehi55 May 28, 2026
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
@@ -0,0 +1,10 @@
package mannabom_server.manabom.application.chat.dto.event;

import mannabom_server.manabom.domain.chat.enums.ChatRoomType;

public record ChatRoomLeaveEvent(
Long userId,
ChatRoomType roomType,
Long referenceId
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package mannabom_server.manabom.application.chat.dto.request;

import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class ChatMessageRequest {
private Long lastReadMessageId;
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
package mannabom_server.manabom.application.chat.dto.request;

import lombok.AllArgsConstructor;
import lombok.Getter;

import mannabom_server.manabom.domain.chat.enums.ChatMessageType;
import mannabom_server.manabom.domain.chat.enums.ChatRoomType;

@Getter
@AllArgsConstructor
public class ChatSendRequest {
private Long roomId;
private ChatRoomType chatRoomType;
private ChatMessageType messageType;
private String content;
private String clientMeesageId;
private String clientMessageId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package mannabom_server.manabom.application.chat.dto.response;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;

import java.util.List;

@Getter
@Builder
@AllArgsConstructor
public class ChatHistoryResponse {
private Long roomId;
private List<ChatMessageResponse> messages;
private boolean hasNext;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package mannabom_server.manabom.application.chat.dto.response;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class ChatInitialSyncResponse {
private int unreadMessageCount;
private boolean hasNewRoom;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package mannabom_server.manabom.application.chat.dto.response;

import lombok.Builder;
import lombok.Getter;
import mannabom_server.manabom.domain.user.entity.Profile;
import mannabom_server.manabom.domain.user.enums.Gender;

@Getter
@Builder
public class ChatMemberInfo {
private Long userId;
private String nickname;
private String profileImageUrl;
private Gender gender;

public static ChatMemberInfo of(Profile profile, String displayImageUrl){
return ChatMemberInfo.builder()
.userId(profile.getUser().getUserId())
.nickname(profile.getNickName())
.profileImageUrl(displayImageUrl)
.gender(profile.getGender())
.build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
@Builder
public class ChatMessageEvent {
private Long roomId;
private String roomType;

private Long senderUserId;
private String messageType;
private String content;
private int unreadCount;

private Long messageId;
private String clientMessageId;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package mannabom_server.manabom.application.chat.dto.response;

import lombok.Builder;
import lombok.Getter;
import mannabom_server.manabom.domain.chat.entity.ChatMessage;

import java.time.Instant;

@Getter
@Builder
public class ChatMessageResponse {
private Long messageId;
private String content;
private String messageType;
private Instant createdAt;

private Long senderId;
private int unreadCount;

public static ChatMessageResponse of(ChatMessage msg, int unreadCount){
return ChatMessageResponse.builder()
.messageId(msg.getId())
.createdAt(msg.getCreatedAt())
.messageType(msg.getType().name())
.unreadCount(unreadCount)
.senderId(msg.getUser().getUserId())
.content(msg.getContent())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package mannabom_server.manabom.application.chat.dto.response;

import lombok.Builder;
import lombok.Getter;

@Builder
@Getter
public class ChatReadEvent {
private Long roomId;
private Long userId;
private Long lastReadMessageId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package mannabom_server.manabom.application.chat.dto.response;

import lombok.Builder;
import lombok.Getter;
import mannabom_server.manabom.domain.chat.entity.ChatMessage;
import mannabom_server.manabom.domain.chat.entity.ChatRoom;
import mannabom_server.manabom.domain.chat.enums.ChatRoomType;

import java.time.Instant;

@Builder
@Getter
public class ChatRoomListResponse {
private Long roomId;
private String roomName;
private String lastMessage;
private Instant lastmessageAt;
private int unreadCount;

public static ChatRoomListResponse of(ChatRoom room,String roomName, ChatMessage lastMsg, int unreadCount){
return ChatRoomListResponse.builder()
.roomId(room.getId())
.roomName(roomName)
.lastMessage(lastMsg!=null ? lastMsg.getType().getDisplayMessage(lastMsg.getContent()): null )
.unreadCount(unreadCount)
.build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package mannabom_server.manabom.application.chat.dto.response;

import lombok.Builder;
import lombok.Getter;

import java.util.List;

@Builder
@Getter
public class ChatSyncResponse {
private Long roomId;
private List<ChatMemberInfo> members;
private List<ChatMessageResponse> messages;
private boolean hasGap;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package mannabom_server.manabom.application.chat.handler;

import lombok.RequiredArgsConstructor;
import mannabom_server.manabom.application.chat.dto.event.ChatRoomLeaveEvent;
import mannabom_server.manabom.application.meeting.service.MeetingMatchingService;
import mannabom_server.manabom.application.meeting.service.MeetingService;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class MeetingChatEventHandler {
private final MeetingService meetingService;
private final MeetingMatchingService meetingMatchingService;

@EventListener
public void handleChatRoomLeave(ChatRoomLeaveEvent event){
switch (event.roomType()){
case MEETING_GROUP -> {
meetingService.handleMemberLeave(event.referenceId(), event.userId());
}
case MEETING_MATCH -> {
meetingMatchingService.handleMatchMemberLeave(event.referenceId(), event.userId());
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package mannabom_server.manabom.application.chat.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import mannabom_server.manabom.application.chat.dto.response.ChatReadEvent;
import mannabom_server.manabom.domain.chat.entity.ChatMember;
import mannabom_server.manabom.domain.chat.entity.ChatMessage;
import mannabom_server.manabom.domain.chat.enums.ChatMemberStatus;
import mannabom_server.manabom.domain.chat.repository.ChatMemberRepository;
import mannabom_server.manabom.domain.chat.repository.ChatMessageRepository;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@Slf4j
@RequiredArgsConstructor
public class ChatMemberService {
private static final String UNREAD_PREFIX = "unread:count:";
private final ChatMemberRepository chatMemberRepository;
private final ChatMessageRepository chatMessageRepository;
private final SimpMessagingTemplate messagingTemplate;
private final StringRedisTemplate stringRedisTemplate;

public void updateReadStatus(Long roomId, Long userId,Long lastSeenMessageId) {
ChatMember chatMember = chatMemberRepository.findByRoomIdAndUser_UserIdAndStatus(roomId, userId, ChatMemberStatus.ACTIVATE)
.orElseThrow(() -> new IllegalArgumentException("해당 채팅방 멤버가 아닙니다."));

long lastReadId = chatMember.getLastReadMessageId() == null ? 0L : chatMember.getLastReadMessageId();

if (lastSeenMessageId <= lastReadId) return;

List<ChatMessage> unreadMessages = chatMessageRepository.findByRoomIdAndIdBetween(roomId, lastReadId + 1, lastSeenMessageId);
for (ChatMessage m : unreadMessages) {
String key = UNREAD_PREFIX + m.getId();
Long count = stringRedisTemplate.opsForValue().decrement(key);
if (count != null && count < 0) {
stringRedisTemplate.opsForValue().set(key, "0");
}
}


ChatReadEvent readEvent = ChatReadEvent.builder()
.roomId(roomId)
.userId(userId)
.lastReadMessageId(lastSeenMessageId)
.build();
messagingTemplate.convertAndSend("/topic/rooms/" + roomId + "/read", readEvent);


}
}
Loading