fix(home-following): 최근 대화를 팔로우 크리에이터로 제한한다

This commit is contained in:
2026-08-19 12:23:33 +09:00
parent b18e40d4fc
commit b1be87b46f
9 changed files with 570 additions and 20 deletions
@@ -1,5 +1,10 @@
package kr.co.vividnext.sodalive.v2.api.home.following.adapter.`in`.web
import kr.co.vividnext.sodalive.chat.character.ChatCharacter
import kr.co.vividnext.sodalive.chat.room.ChatMessage
import kr.co.vividnext.sodalive.chat.room.ChatParticipant
import kr.co.vividnext.sodalive.chat.room.ChatRoom
import kr.co.vividnext.sodalive.chat.room.ParticipantType
import kr.co.vividnext.sodalive.common.CountryContext
import kr.co.vividnext.sodalive.content.AudioContent
import kr.co.vividnext.sodalive.content.theme.AudioContentTheme
@@ -9,6 +14,7 @@ import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like.CreatorCo
import kr.co.vividnext.sodalive.live.room.LiveRoom
import kr.co.vividnext.sodalive.member.Member
import kr.co.vividnext.sodalive.member.MemberAdapter
import kr.co.vividnext.sodalive.member.MemberKind
import kr.co.vividnext.sodalive.member.MemberRole
import kr.co.vividnext.sodalive.member.following.CreatorFollowing
import kr.co.vividnext.sodalive.support.EmbeddedRedisInitializer
@@ -85,10 +91,19 @@ class HomeFollowingEndToEndTest @Autowired constructor(
.andExpect(jsonPath("$.data.followingCreators[0].creatorNickname").value("home-following-creator"))
.andExpect(jsonPath("$.data.onAirLives[0].liveId").value(fixture.liveId))
.andExpect(jsonPath("$.data.onAirLives[0].title").value("home-following-live"))
.andExpect(jsonPath("$.data.recentChats[0].roomId").value(fixture.chatRoomId))
.andExpect(jsonPath("$.data.recentChats[0].chatType").value("DM"))
.andExpect(jsonPath("$.data.recentChats[0].targetName").value("home-following-creator"))
.andExpect(jsonPath("$.data.recentChats[0].lastMessage").value("recent dm"))
.andExpect(jsonPath("$.data.recentChats.length()").value(2))
.andExpect(jsonPath("$.data.recentChats[0].roomId").value(fixture.aiChatRoomId))
.andExpect(jsonPath("$.data.recentChats[0].chatType").value("AI"))
.andExpect(jsonPath("$.data.recentChats[1].roomId").value(fixture.dmChatRoomId))
.andExpect(jsonPath("$.data.recentChats[1].chatType").value("DM"))
.andExpect(jsonPath("$.data.recentChats[1].targetName").value("home-following-creator"))
.andExpect(jsonPath("$.data.recentChats[1].lastMessage").value("recent dm"))
.andExpect(
jsonPath("$.data.recentChats[?(@.roomId == ${fixture.unfollowedDmRoomIds.first()})]").isEmpty
)
.andExpect(
jsonPath("$.data.recentChats[?(@.roomId == ${fixture.inactiveFollowingDmRoomId})]").isEmpty
)
.andExpect(jsonPath("$.data.monthlySchedules[0].scheduleId").value("LIVE:${fixture.liveId}"))
.andExpect(jsonPath("$.data.monthlySchedules[1].scheduleId").value("AUDIO:${fixture.audioId}"))
.andExpect(jsonPath("$.data.recentNews[0].newsId").value(fixture.rankedNewsId.toString()))
@@ -172,7 +187,21 @@ class HomeFollowingEndToEndTest @Autowired constructor(
val rankedVisibleFromAtUtc = now.minusHours(1)
saveCreatorRankingSnapshot(creator, rankNo = 7, visibleFromAtUtc = rankedVisibleFromAtUtc)
val rankedNews = saveNews(viewer.id!!, creator.id!!, "ranked-news", rankedVisibleFromAtUtc, rank = 7)
val chatRoom = saveDmChatRoom(viewer, creator, now.minusMinutes(10))
val dmChatRoom = saveDmChatRoom(viewer, creator, now.minusMinutes(10))
val aiCreator = saveMember(
"home-following-ai-creator",
MemberRole.CREATOR,
memberKind = MemberKind.AI_CHARACTER
)
saveFollowing(viewer, aiCreator)
val aiChatRoom = saveAiChatRoom(viewer, aiCreator, now.minusMinutes(5))
val unfollowedDmRoomIds = (1..11).map { index ->
val unfollowedCreator = saveMember("home-following-unfollowed-$index", MemberRole.CREATOR)
saveDmChatRoom(viewer, unfollowedCreator, now.minusSeconds(index.toLong())).id!!
}
val inactiveFollowingCreator = saveMember("home-following-inactive", MemberRole.CREATOR)
saveFollowing(viewer, inactiveFollowingCreator, isActive = false)
val inactiveFollowingDmRoom = saveDmChatRoom(viewer, inactiveFollowingCreator, now.minusMinutes(1))
entityManager.flush()
entityManager.clear()
@@ -181,7 +210,10 @@ class HomeFollowingEndToEndTest @Autowired constructor(
creatorId = creator.id!!,
liveId = live.id!!,
audioId = audio.id!!,
chatRoomId = chatRoom.id!!,
dmChatRoomId = dmChatRoom.id!!,
aiChatRoomId = aiChatRoom.id!!,
unfollowedDmRoomIds = unfollowedDmRoomIds,
inactiveFollowingDmRoomId = inactiveFollowingDmRoom.id!!,
rankedNewsId = rankedNews.id!!,
audioNewsId = audioNews.id!!,
communityNewsId = communityNews.id!!,
@@ -191,21 +223,27 @@ class HomeFollowingEndToEndTest @Autowired constructor(
}!!
}
private fun saveMember(seed: String, role: MemberRole, profileImage: String? = null): Member {
private fun saveMember(
seed: String,
role: MemberRole,
profileImage: String? = null,
memberKind: MemberKind = MemberKind.HUMAN
): Member {
val member = Member(
email = "$seed@test.com",
password = "password",
nickname = seed,
profileImage = profileImage,
role = role,
memberKind = memberKind,
countryCode = "US"
)
entityManager.persist(member)
return member
}
private fun saveFollowing(member: Member, creator: Member): CreatorFollowing {
val following = CreatorFollowing(isActive = true).apply {
private fun saveFollowing(member: Member, creator: Member, isActive: Boolean = true): CreatorFollowing {
val following = CreatorFollowing(isActive = isActive).apply {
this.member = member
this.creator = creator
}
@@ -354,12 +392,42 @@ class HomeFollowingEndToEndTest @Autowired constructor(
return room
}
private fun saveAiChatRoom(viewer: Member, creator: Member, messageCreatedAt: LocalDateTime): ChatRoom {
val character = ChatCharacter(
characterUUID = "home-following-ai-character-uuid",
name = "home-following-ai-character",
description = "description",
systemPrompt = "system"
).apply { creatorMember = creator }
entityManager.persist(character)
val room = ChatRoom(sessionId = "home-following-ai-room", title = "home-following-ai-room")
entityManager.persist(room)
val viewerParticipant = ChatParticipant(room, ParticipantType.USER, member = viewer)
val characterParticipant = ChatParticipant(room, ParticipantType.CHARACTER, character = character)
entityManager.persist(viewerParticipant)
entityManager.persist(characterParticipant)
val message = ChatMessage(
message = "recent ai",
chatRoom = room,
participant = characterParticipant,
isActive = true
)
entityManager.persist(message)
entityManager.flush()
message.createdAt = messageCreatedAt
message.updatedAt = messageCreatedAt
return room
}
private data class Fixture(
val viewer: Member,
val creatorId: Long,
val liveId: Long,
val audioId: Long,
val chatRoomId: Long,
val dmChatRoomId: Long,
val aiChatRoomId: Long,
val unfollowedDmRoomIds: List<Long>,
val inactiveFollowingDmRoomId: Long,
val rankedNewsId: Long,
val audioNewsId: Long,
val communityNewsId: Long,
@@ -60,7 +60,8 @@ class HomeFollowingFacadeTest {
)
Mockito.doReturn(home).`when`(queryService).findHomeFollowing(member)
Mockito.doReturn(ChatRoomListPageResponse(rooms = listOf(recentChat), hasMore = false, nextCursor = null))
.`when`(chatRoomListService).getRooms(member, filter = "ALL", cursor = null, limit = 10)
.`when`(chatRoomListService)
.getRooms(member, filter = "ALL", cursor = null, limit = 10, followedCreatorsOnly = true)
val response = facade.getFollowingTab(member)
@@ -71,7 +72,8 @@ class HomeFollowingFacadeTest {
assertEquals("LIVE:4", response.monthlySchedules.single().scheduleId)
assertEquals("news-5", response.recentNews.single().newsId)
Mockito.verify(queryService).findHomeFollowing(member)
Mockito.verify(chatRoomListService).getRooms(member, filter = "ALL", cursor = null, limit = 10)
Mockito.verify(chatRoomListService)
.getRooms(member, filter = "ALL", cursor = null, limit = 10, followedCreatorsOnly = true)
}
private fun homeFollowing(): HomeFollowing {