diff --git a/src/main/kotlin/com/back/koreaTravelGuide/common/config/websocket/JwtHandshakeInterceptor.kt b/src/main/kotlin/com/back/koreaTravelGuide/common/config/websocket/JwtHandshakeInterceptor.kt deleted file mode 100644 index 8981c9e..0000000 --- a/src/main/kotlin/com/back/koreaTravelGuide/common/config/websocket/JwtHandshakeInterceptor.kt +++ /dev/null @@ -1,55 +0,0 @@ -package com.back.koreaTravelGuide.common.config.websocket - -import com.back.koreaTravelGuide.common.util.JwtUtil -import org.springframework.http.HttpMethod -import org.springframework.http.server.ServerHttpRequest -import org.springframework.http.server.ServerHttpResponse -import org.springframework.stereotype.Component -import org.springframework.web.socket.WebSocketHandler -import org.springframework.web.socket.server.HandshakeInterceptor -import org.springframework.web.util.UriComponentsBuilder -import java.lang.Exception -import java.net.URI - -@Component -class JwtHandshakeInterceptor : HandshakeInterceptor { - override fun beforeHandshake( - request: ServerHttpRequest, - response: ServerHttpResponse, - wsHandler: WebSocketHandler, - attributes: MutableMap, - ): Boolean { - val uri: URI = request.uri - val method = request.method - - // ✅ SockJS 호환을 위한 임시 우회 (브라우저 테스트용) - // - SockJS는 /info 요청을 토큰 없이 보냄 - // - 추후 순수 WebSocket 전환 시 제거 예정 - if (HttpMethod.OPTIONS == method || uri.path.endsWith("/info")) { - return true - } - - val token = - UriComponentsBuilder.fromUri(request.uri) - .build() - .queryParams - .getFirst("token") - ?: return false // 토큰 없으면 연결 거부 - - return if (JwtUtil.validateToken(token)) { - val userId = JwtUtil.getUserIdFromToken(token) - attributes["userId"] = userId - true - } else { - false - } - } - - override fun afterHandshake( - request: ServerHttpRequest, - response: ServerHttpResponse, - wsHandler: WebSocketHandler, - exception: Exception?, - ) { - } -} diff --git a/src/main/kotlin/com/back/koreaTravelGuide/common/config/websocket/WebSocketConfig.kt b/src/main/kotlin/com/back/koreaTravelGuide/common/config/websocket/WebSocketConfig.kt deleted file mode 100644 index 8e33346..0000000 --- a/src/main/kotlin/com/back/koreaTravelGuide/common/config/websocket/WebSocketConfig.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.back.koreaTravelGuide.common.config.websocket - -import org.springframework.context.annotation.Configuration -import org.springframework.messaging.simp.config.MessageBrokerRegistry -import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker -import org.springframework.web.socket.config.annotation.StompEndpointRegistry -import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer - -@Configuration -@EnableWebSocketMessageBroker -class WebSocketConfig( - private val jwtHandshakeInterceptor: JwtHandshakeInterceptor, -) : WebSocketMessageBrokerConfigurer { - override fun registerStompEndpoints(registry: StompEndpointRegistry) { - registry.addEndpoint("/ws/chat") - .addInterceptors(JwtHandshakeInterceptor()) // JWT 체크 - .setAllowedOrigins("*") - .withSockJS() // 개발 중 호환성 - } - - override fun configureMessageBroker(registry: MessageBrokerRegistry) { - registry.enableSimpleBroker("/sub") // 구독 경로 - registry.setApplicationDestinationPrefixes("/app") // 클라이언트에서 보낼 때 - } -} diff --git a/src/main/kotlin/com/back/koreaTravelGuide/common/util/JwtUtil.kt b/src/main/kotlin/com/back/koreaTravelGuide/common/util/JwtUtil.kt deleted file mode 100644 index 082a0d3..0000000 --- a/src/main/kotlin/com/back/koreaTravelGuide/common/util/JwtUtil.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.back.koreaTravelGuide.common.util - -/* - 임시 구현: 테스트 용 - 토큰이 "test-token"이면 유효하다고 간주 - 완성 후 이 파일은 삭제 또는 대체 - */ -object JwtUtil { - fun validateToken(token: String?): Boolean { - // 테스트용: "test-token"이면 통과 - return token != null && token == "test-token" - } - - fun getUserIdFromToken(token: String): String { - return "user123" // 테스트용 고정 사용자 ID - } -} diff --git a/src/main/kotlin/com/back/koreaTravelGuide/domain/userChat/chatmessage/entity/ChatMessage.kt b/src/main/kotlin/com/back/koreaTravelGuide/domain/userChat/chatmessage/entity/ChatMessage.kt new file mode 100644 index 0000000..ccd0e28 --- /dev/null +++ b/src/main/kotlin/com/back/koreaTravelGuide/domain/userChat/chatmessage/entity/ChatMessage.kt @@ -0,0 +1,28 @@ +package com.back.koreaTravelGuide.domain.userChat.chatmessage.entity + +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType +import jakarta.persistence.Id +import jakarta.persistence.Index +import jakarta.persistence.Table +import java.time.Instant + +@Entity +@Table( + name = "userchat_message", + indexes = [Index(name = "ix_msg_room_id_id", columnList = "room_id,id")], +) +data class ChatMessage( + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + val id: Long? = null, + @Column(name = "room_id", nullable = false) + val roomId: Long, + @Column(name = "sender_id", nullable = false) + val senderId: Long, + @Column(columnDefinition = "text", nullable = false) + val content: String, + @Column(name = "created_at", nullable = false) + val createdAt: Instant = Instant.now(), +) diff --git a/src/main/kotlin/com/back/koreaTravelGuide/domain/userChat/chatmessage/repository/ChatMessageRepository.kt b/src/main/kotlin/com/back/koreaTravelGuide/domain/userChat/chatmessage/repository/ChatMessageRepository.kt new file mode 100644 index 0000000..651ed17 --- /dev/null +++ b/src/main/kotlin/com/back/koreaTravelGuide/domain/userChat/chatmessage/repository/ChatMessageRepository.kt @@ -0,0 +1,15 @@ +package com.back.koreaTravelGuide.domain.userChat.chatmessage.repository + +import com.back.koreaTravelGuide.domain.userChat.chatmessage.entity.ChatMessage +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.stereotype.Repository + +@Repository +interface ChatMessageRepository : JpaRepository { + fun findTop50ByRoomIdOrderByIdDesc(roomId: Long): List + + fun findByRoomIdAndIdGreaterThanOrderByIdAsc( + roomId: Long, + afterId: Long, + ): List +} diff --git a/src/main/kotlin/com/back/koreaTravelGuide/domain/userChat/chatroom/entity/ChatRoom.kt b/src/main/kotlin/com/back/koreaTravelGuide/domain/userChat/chatroom/entity/ChatRoom.kt new file mode 100644 index 0000000..9a581c5 --- /dev/null +++ b/src/main/kotlin/com/back/koreaTravelGuide/domain/userChat/chatroom/entity/ChatRoom.kt @@ -0,0 +1,28 @@ +package com.back.koreaTravelGuide.domain.userChat.chatroom.entity + +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType +import jakarta.persistence.Id +import jakarta.persistence.Index +import jakarta.persistence.Table +import java.time.Instant + +@Entity +@Table( + name = "userchat_room", + indexes = [Index(name = "ix_room_updated_at", columnList = "updated_at")], +) +data class ChatRoom( + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + val id: Long? = null, + @Column(nullable = false) + val title: String, + @Column(name = "owner_id", nullable = false) + val ownerId: Long, + @Column(name = "updated_at", nullable = false) + val updatedAt: Instant = Instant.now(), + @Column(name = "last_message_id") + val lastMessageId: Long? = null, +) diff --git a/src/main/kotlin/com/back/koreaTravelGuide/domain/userChat/chatroom/repository/ChatRoomRepository.kt b/src/main/kotlin/com/back/koreaTravelGuide/domain/userChat/chatroom/repository/ChatRoomRepository.kt new file mode 100644 index 0000000..57287e7 --- /dev/null +++ b/src/main/kotlin/com/back/koreaTravelGuide/domain/userChat/chatroom/repository/ChatRoomRepository.kt @@ -0,0 +1,8 @@ +package com.back.koreaTravelGuide.domain.userChat.chatroom.repository + +import com.back.koreaTravelGuide.domain.userChat.chatroom.entity.ChatRoom +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.stereotype.Repository + +@Repository +interface ChatRoomRepository : JpaRepository