feat(home-following): 팔로잉 소식 inbox 저장 모델을 추가한다

This commit is contained in:
2026-06-25 22:15:20 +09:00
parent cbcd87875c
commit a28991b585
3 changed files with 142 additions and 0 deletions

View File

@@ -0,0 +1,73 @@
package kr.co.vividnext.sodalive.v2.home.following.adapter.out.persistence
import kr.co.vividnext.sodalive.common.BaseEntity
import kr.co.vividnext.sodalive.v2.home.following.domain.FollowingNewsType
import java.time.LocalDateTime
import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.EnumType
import javax.persistence.Enumerated
import javax.persistence.Table
import javax.persistence.UniqueConstraint
@Entity
@Table(
name = "home_following_news_inbox",
uniqueConstraints = [
UniqueConstraint(
name = "uk_home_following_news_inbox_member_type_source",
columnNames = ["member_id", "news_type", "source_key"]
)
]
)
class HomeFollowingNewsInbox(
@Column(name = "member_id", nullable = false, updatable = false)
val memberId: Long,
@Column(name = "creator_id", nullable = false, updatable = false)
val creatorId: Long,
@Enumerated(EnumType.STRING)
@Column(name = "news_type", nullable = false, updatable = false, length = 30)
val newsType: FollowingNewsType,
@Column(name = "source_key", nullable = false, updatable = false, length = 200)
val sourceKey: String,
@Column(name = "target_id", nullable = false, updatable = false)
val targetId: Long,
@Column(name = "occurred_at_utc", nullable = false, updatable = false)
val occurredAtUtc: LocalDateTime,
@Column(name = "visible_from_at_utc", nullable = false, updatable = false)
val visibleFromAtUtc: LocalDateTime,
@Column(name = "creator_nickname", nullable = false, updatable = false, length = 100)
val creatorNickname: String,
@Column(name = "creator_profile_image_path", updatable = false, length = 500)
val creatorProfileImagePath: String?,
@Column(name = "title", nullable = false, updatable = false, length = 255)
val title: String,
@Column(name = "body", nullable = false, updatable = false, length = 1000)
val body: String,
@Column(name = "thumbnail_image_path", updatable = false, length = 500)
val thumbnailImagePath: String?,
@Column(name = "rank_no", updatable = false)
val rank: Int?,
@Column(name = "is_adult", nullable = false, updatable = false)
val isAdult: Boolean,
@Column(name = "is_active", nullable = false)
var isActive: Boolean = true
) : BaseEntity() {
fun deactivate() {
isActive = false
}
}

View File

@@ -0,0 +1,43 @@
package kr.co.vividnext.sodalive.v2.home.following.adapter.out.persistence
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Modifying
import org.springframework.data.jpa.repository.Query
import org.springframework.data.repository.query.Param
interface HomeFollowingNewsInboxJpaRepository : JpaRepository<HomeFollowingNewsInbox, Long> {
fun existsByMemberIdAndNewsTypeAndSourceKey(
memberId: Long,
newsType: kr.co.vividnext.sodalive.v2.home.following.domain.FollowingNewsType,
sourceKey: String
): Boolean
@Modifying(clearAutomatically = true, flushAutomatically = true)
@Query(
value = """
update home_following_news_inbox
set is_active = false,
updated_at = current_timestamp
where member_id = :memberId
and creator_id = :creatorId
and is_active = true
""",
nativeQuery = true
)
fun deactivateByMemberIdAndCreatorId(
@Param("memberId") memberId: Long,
@Param("creatorId") creatorId: Long
): Int
@Query(
value = """
select cf.member_id
from creator_following cf
where cf.creator_id = :creatorId
and cf.is_active = true
order by cf.member_id asc
""",
nativeQuery = true
)
fun findActiveFollowerIds(@Param("creatorId") creatorId: Long): List<Long>
}

View File

@@ -0,0 +1,26 @@
package kr.co.vividnext.sodalive.v2.home.following.port.out
import java.time.LocalDateTime
interface HomeFollowingNewsInboxPort {
fun insertIgnoreAll(records: List<HomeFollowingNewsInboxRecord>): Int
fun deactivateByMemberIdAndCreatorId(memberId: Long, creatorId: Long): Long
fun findActiveFollowerIds(creatorId: Long): List<Long>
}
data class HomeFollowingNewsInboxRecord(
val memberId: Long,
val creatorId: Long,
val newsType: String,
val sourceKey: String,
val targetId: Long,
val occurredAtUtc: LocalDateTime,
val visibleFromAtUtc: LocalDateTime,
val creatorNickname: String,
val creatorProfileImagePath: String?,
val title: String,
val body: String,
val thumbnailImagePath: String?,
val rank: Int?,
val isAdult: Boolean
)