From 8a3d11ae59571aa6b6b4ffcdb38abab1c23b3e1f Mon Sep 17 00:00:00 2001
From: Klaus <klaus@vividnext.co.kr>
Date: Tue, 19 Dec 2023 21:12:20 +0900
Subject: [PATCH 01/18] =?UTF-8?q?=EC=BB=A4=EB=AE=A4=EB=8B=88=ED=8B=B0=20AP?=
 =?UTF-8?q?I=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../CreateCommunityPostRequest.kt             |   7 +
 .../creatorCommunity/CreatorCommunity.kt      |  24 ++
 .../CreatorCommunityController.kt             | 143 +++++++++
 .../CreatorCommunityRepository.kt             |  64 ++++
 .../CreatorCommunityService.kt                | 277 ++++++++++++++++++
 .../GetCommunityPostListResponse.kt           |  16 +
 .../ModifyCommunityPostRequest.kt             |   8 +
 .../CreateCommunityPostCommentRequest.kt      |   3 +
 .../comment/CreatorCommunityComment.kt        |  37 +++
 .../CreatorCommunityCommentRepository.kt      |  91 ++++++
 .../GetCommunityPostCommentListResponse.kt    |  16 +
 .../ModifyCommunityPostCommentRequest.kt      |   3 +
 .../like/CreatorCommunityLike.kt              |  22 ++
 .../like/CreatorCommunityLikeRepository.kt    |  30 ++
 .../like/PostCommunityPostLikeRequest.kt      |   3 +
 .../like/PostCommunityPostLikeResponse.kt     |   3 +
 16 files changed, 747 insertions(+)
 create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreateCommunityPostRequest.kt
 create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunity.kt
 create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityController.kt
 create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt
 create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
 create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt
 create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/ModifyCommunityPostRequest.kt
 create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreateCommunityPostCommentRequest.kt
 create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityComment.kt
 create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityCommentRepository.kt
 create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/GetCommunityPostCommentListResponse.kt
 create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/ModifyCommunityPostCommentRequest.kt
 create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/CreatorCommunityLike.kt
 create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/CreatorCommunityLikeRepository.kt
 create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/PostCommunityPostLikeRequest.kt
 create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/PostCommunityPostLikeResponse.kt

diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreateCommunityPostRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreateCommunityPostRequest.kt
new file mode 100644
index 0000000..d6320e4
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreateCommunityPostRequest.kt
@@ -0,0 +1,7 @@
+package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity
+
+data class CreateCommunityPostRequest(
+    val content: String,
+    val isCommentAvailable: Boolean,
+    val isAdult: Boolean
+)
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunity.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunity.kt
new file mode 100644
index 0000000..70be7d0
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunity.kt
@@ -0,0 +1,24 @@
+package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity
+
+import kr.co.vividnext.sodalive.common.BaseEntity
+import kr.co.vividnext.sodalive.member.Member
+import javax.persistence.Column
+import javax.persistence.Entity
+import javax.persistence.FetchType
+import javax.persistence.JoinColumn
+import javax.persistence.ManyToOne
+
+@Entity
+data class CreatorCommunity(
+    @Column(columnDefinition = "TEXT", nullable = false)
+    var content: String,
+    var isCommentAvailable: Boolean,
+    var isAdult: Boolean,
+    @Column(nullable = true)
+    var imagePath: String? = null,
+    val isActive: Boolean = true
+) : BaseEntity() {
+    @ManyToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name = "member_id", nullable = false)
+    var member: Member? = null
+}
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityController.kt
new file mode 100644
index 0000000..4aa66a6
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityController.kt
@@ -0,0 +1,143 @@
+package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity
+
+import kr.co.vividnext.sodalive.common.ApiResponse
+import kr.co.vividnext.sodalive.common.SodaException
+import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.CreateCommunityPostCommentRequest
+import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.ModifyCommunityPostCommentRequest
+import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like.PostCommunityPostLikeRequest
+import kr.co.vividnext.sodalive.member.Member
+import org.springframework.data.domain.Pageable
+import org.springframework.lang.Nullable
+import org.springframework.security.access.prepost.PreAuthorize
+import org.springframework.security.core.annotation.AuthenticationPrincipal
+import org.springframework.web.bind.annotation.GetMapping
+import org.springframework.web.bind.annotation.PathVariable
+import org.springframework.web.bind.annotation.PostMapping
+import org.springframework.web.bind.annotation.PutMapping
+import org.springframework.web.bind.annotation.RequestBody
+import org.springframework.web.bind.annotation.RequestParam
+import org.springframework.web.bind.annotation.RequestPart
+import org.springframework.web.bind.annotation.RestController
+import org.springframework.web.multipart.MultipartFile
+
+@RestController("/creator-community")
+class CreatorCommunityController(private val service: CreatorCommunityService) {
+    @PostMapping
+    @PreAuthorize("hasRole('CREATOR')")
+    fun createCommunityPost(
+        @Nullable
+        @RequestPart("postImage")
+        postImage: MultipartFile?,
+        @RequestPart("request") requestString: String,
+        @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
+    ) = run {
+        if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
+
+        ApiResponse.ok(
+            service.createCommunityPost(
+                postImage = postImage,
+                requestString = requestString,
+                member = member
+            )
+        )
+    }
+
+    @PutMapping
+    @PreAuthorize("hasRole('CREATOR')")
+    fun modifyCommunityPost(
+        @Nullable
+        @RequestPart("postImage")
+        postImage: MultipartFile?,
+        @RequestPart("request") requestString: String,
+        @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
+    ) = run {
+        if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
+
+        ApiResponse.ok(
+            service.modifyCommunityPost(
+                postImage = postImage,
+                requestString = requestString,
+                member = member
+            )
+        )
+    }
+
+    @GetMapping
+    fun getCommunityPostList(
+        @RequestParam creatorId: Long,
+        @RequestParam timezone: String,
+        @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?,
+        pageable: Pageable
+    ) = run {
+        if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
+
+        ApiResponse.ok(
+            service.getCommunityPostList(
+                creatorId = creatorId,
+                memberId = member.id!!,
+                timezone = timezone,
+                offset = pageable.offset,
+                limit = pageable.pageSize.toLong(),
+                isAdult = member.auth != null
+            )
+        )
+    }
+
+    @PostMapping("/like")
+    fun communityPostLike(
+        @RequestBody request: PostCommunityPostLikeRequest,
+        @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
+    ) = run {
+        if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
+
+        ApiResponse.ok(service.communityPostLike(request, member))
+    }
+
+    @PostMapping("/comment")
+    fun createCommunityPostComment(
+        @RequestBody request: CreateCommunityPostCommentRequest,
+        @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
+    ) = run {
+        if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
+
+        ApiResponse.ok(
+            service.createCommunityPostComment(
+                comment = request.comment,
+                postId = request.postId,
+                parentId = request.parentId,
+                member = member
+            )
+        )
+    }
+
+    @PutMapping("/comment")
+    fun modifyCommunityPostComment(
+        @RequestBody request: ModifyCommunityPostCommentRequest,
+        @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
+    ) = run {
+        if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
+
+        ApiResponse.ok(
+            service.modifyCommunityPostComment(request = request, member = member)
+        )
+    }
+
+    @GetMapping("/{id}/comment")
+    fun getCommunityPostCommentList(
+        @PathVariable("id") postId: Long,
+        @RequestParam timezone: String,
+        @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?,
+        pageable: Pageable
+    ) = run {
+        if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
+
+        ApiResponse.ok(
+            service.getCommunityPostCommentList(
+                postId = postId,
+                timezone = timezone,
+                offset = pageable.offset,
+                limit = pageable.pageSize.toLong()
+            )
+        )
+    }
+}
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt
new file mode 100644
index 0000000..d1e2089
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt
@@ -0,0 +1,64 @@
+package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity
+
+import com.querydsl.jpa.impl.JPAQueryFactory
+import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.QCreatorCommunity.creatorCommunity
+import kr.co.vividnext.sodalive.member.QMember.member
+import org.springframework.data.jpa.repository.JpaRepository
+
+interface CreatorCommunityRepository : JpaRepository<CreatorCommunity, Long>, CreatorCommunityQueryRepository
+
+interface CreatorCommunityQueryRepository {
+    fun findByIdAndMemberId(id: Long, memberId: Long): CreatorCommunity?
+
+    fun getCommunityPostList(
+        creatorId: Long,
+        offset: Long,
+        limit: Long,
+        isAdult: Boolean
+    ): List<CreatorCommunity>
+
+    fun findByIdAndActive(postId: Long): CreatorCommunity?
+}
+
+class CreatorCommunityQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : CreatorCommunityQueryRepository {
+    override fun findByIdAndMemberId(id: Long, memberId: Long): CreatorCommunity? {
+        return queryFactory
+            .selectFrom(creatorCommunity)
+            .where(
+                creatorCommunity.id.eq(id)
+                    .and(creatorCommunity.member.id.eq(memberId))
+            )
+            .fetchFirst()
+    }
+
+    override fun getCommunityPostList(
+        creatorId: Long,
+        offset: Long,
+        limit: Long,
+        isAdult: Boolean
+    ): List<CreatorCommunity> {
+        var where = creatorCommunity.member.id.eq(creatorId)
+
+        if (!isAdult) {
+            where = where.and(creatorCommunity.isAdult.isFalse)
+        }
+
+        return queryFactory
+            .selectFrom(creatorCommunity)
+            .innerJoin(creatorCommunity.member, member)
+            .where(where)
+            .offset(offset)
+            .limit(limit)
+            .fetch()
+    }
+
+    override fun findByIdAndActive(postId: Long): CreatorCommunity? {
+        return queryFactory
+            .selectFrom(creatorCommunity)
+            .where(
+                creatorCommunity.id.eq(postId)
+                    .and(creatorCommunity.isActive.isTrue)
+            )
+            .fetchFirst()
+    }
+}
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
new file mode 100644
index 0000000..67ada02
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
@@ -0,0 +1,277 @@
+package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity
+
+import com.amazonaws.services.s3.model.ObjectMetadata
+import com.fasterxml.jackson.databind.ObjectMapper
+import kr.co.vividnext.sodalive.aws.s3.S3Uploader
+import kr.co.vividnext.sodalive.common.SodaException
+import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.CreatorCommunityComment
+import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.CreatorCommunityCommentRepository
+import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.GetCommunityPostCommentListResponse
+import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.ModifyCommunityPostCommentRequest
+import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like.CreatorCommunityLike
+import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like.CreatorCommunityLikeRepository
+import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like.PostCommunityPostLikeRequest
+import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like.PostCommunityPostLikeResponse
+import kr.co.vividnext.sodalive.fcm.FcmEvent
+import kr.co.vividnext.sodalive.fcm.FcmEventType
+import kr.co.vividnext.sodalive.member.Member
+import kr.co.vividnext.sodalive.utils.generateFileName
+import org.springframework.beans.factory.annotation.Value
+import org.springframework.context.ApplicationEventPublisher
+import org.springframework.data.repository.findByIdOrNull
+import org.springframework.stereotype.Service
+import org.springframework.transaction.annotation.Transactional
+import org.springframework.web.multipart.MultipartFile
+import java.time.Duration
+import java.time.LocalDateTime
+
+@Service
+class CreatorCommunityService(
+    private val repository: CreatorCommunityRepository,
+    private val likeRepository: CreatorCommunityLikeRepository,
+    private val commentRepository: CreatorCommunityCommentRepository,
+
+    private val s3Uploader: S3Uploader,
+    private val objectMapper: ObjectMapper,
+    private val applicationEventPublisher: ApplicationEventPublisher,
+
+    @Value("\${cloud.aws.s3.bucket}")
+    private val imageBucket: String,
+
+    @Value("\${cloud.aws.cloud-front.host}")
+    private val imageHost: String
+) {
+    @Transactional
+    fun createCommunityPost(postImage: MultipartFile?, requestString: String, member: Member) {
+        val request = objectMapper.readValue(requestString, CreateCommunityPostRequest::class.java)
+
+        val post = CreatorCommunity(
+            content = request.content,
+            isCommentAvailable = request.isCommentAvailable,
+            isAdult = request.isAdult
+        )
+        post.member = member
+        repository.save(post)
+
+        if (postImage != null) {
+            val metadata = ObjectMetadata()
+            metadata.contentLength = postImage.size
+
+            // 커버 이미지 파일명 생성
+            val imageFileName = generateFileName(prefix = "${post.id}-image")
+
+            // 커버 이미지 업로드
+            val imagePath = s3Uploader.upload(
+                inputStream = postImage.inputStream,
+                bucket = imageBucket,
+                filePath = "creator_community/${post.id}/$imageFileName",
+                metadata = metadata
+            )
+
+            post.imagePath = imagePath
+        }
+
+        applicationEventPublisher.publishEvent(
+            FcmEvent(
+                type = FcmEventType.CHANGE_NOTICE,
+                title = member.nickname,
+                message = "공지를 등록했습니다.",
+                creatorId = member.id!!
+            )
+        )
+    }
+
+    @Transactional
+    fun modifyCommunityPost(postImage: MultipartFile?, requestString: String, member: Member) {
+        val request = objectMapper.readValue(requestString, ModifyCommunityPostRequest::class.java)
+
+        val post = repository.findByIdAndMemberId(id = request.creatorCommunityId, memberId = member.id!!)
+            ?: throw SodaException("잘못된 요청입니다.")
+
+        if (request.content != null) {
+            post.content = request.content
+        }
+
+        if (request.isCommentAvailable != null) {
+            post.isCommentAvailable = request.isCommentAvailable
+        }
+
+        if (request.isAdult != null) {
+            post.isAdult = request.isAdult
+        }
+
+        if (postImage != null) {
+            val metadata = ObjectMetadata()
+            metadata.contentLength = postImage.size
+
+            // 커버 이미지 파일명 생성
+            val imageFileName = generateFileName(prefix = "${post.id}-image")
+
+            // 커버 이미지 업로드
+            val imagePath = s3Uploader.upload(
+                inputStream = postImage.inputStream,
+                bucket = imageBucket,
+                filePath = "creator_community/${post.id}/$imageFileName",
+                metadata = metadata
+            )
+
+            post.imagePath = imagePath
+        }
+    }
+
+    fun getCommunityPostList(
+        creatorId: Long,
+        memberId: Long,
+        timezone: String,
+        offset: Long,
+        limit: Long,
+        isAdult: Boolean
+    ): List<GetCommunityPostListResponse> {
+        val postList = repository.getCommunityPostList(
+            creatorId = creatorId,
+            offset = offset,
+            limit = limit,
+            isAdult = isAdult
+        )
+
+        return postList
+            .asSequence()
+            .map {
+                val isLike = likeRepository.findByIdAndMemberId(id = it.id!!, memberId = memberId)?.isActive ?: false
+                val likeCount = likeRepository.totalCountCommunityPostLikeByPostId(it.id!!)
+                val commentCount = if (it.isCommentAvailable) {
+                    commentRepository.totalCountCommentByPostId(postId = it.id!!)
+                } else {
+                    0
+                }
+                val commentList = commentRepository.findByPostId(
+                    cloudFrontHost = imageHost,
+                    timezone = timezone,
+                    id = it.id!!,
+                    offset = 0,
+                    limit = 1
+                )
+
+                val firstComment = if (commentList.isNotEmpty()) {
+                    commentList[0]
+                } else {
+                    null
+                }
+
+                GetCommunityPostListResponse(
+                    creatorNickname = it.member!!.nickname,
+                    creatorProfileUrl = if (it.member!!.profileImage != null) {
+                        "$imageHost/${it.member!!.profileImage}"
+                    } else {
+                        "$imageHost/profile/default-profile.png"
+                    },
+                    imageUrl = if (it.imagePath != null) {
+                        "$imageHost/${it.imagePath!!}"
+                    } else {
+                        null
+                    },
+                    content = it.content,
+                    date = getTimeAgoString(it.createdAt!!),
+                    isLike = isLike,
+                    likeCount = likeCount,
+                    commentCount = commentCount,
+                    firstComment = firstComment
+                )
+            }
+            .toList()
+    }
+
+    private fun getTimeAgoString(dateTime: LocalDateTime): String {
+        val now = LocalDateTime.now()
+        val duration = Duration.between(dateTime, now)
+
+        return when {
+            duration.toMinutes() < 60 -> "${duration.toMinutes()}분전"
+            duration.toHours() < 24 -> "${duration.toHours()}시간전"
+            duration.toDays() < 30 -> "${duration.toDays()}일전"
+            duration.toDays() < 365 -> "${duration.toDays() / 30}분전"
+            else -> "${duration.toDays() / 365}년전"
+        }
+    }
+
+    @Transactional
+    fun communityPostLike(request: PostCommunityPostLikeRequest, member: Member): PostCommunityPostLikeResponse {
+        var postLike = likeRepository.findByIdAndMemberId(id = request.postId, memberId = member.id!!)
+
+        if (postLike == null) {
+            postLike = CreatorCommunityLike()
+            postLike.member = member
+
+            val post = repository.findByIdAndActive(request.postId)
+                ?: throw SodaException("잘못된 요청입니다.\n다시 시도해 주세요.")
+
+            postLike.creatorCommunity = post
+            likeRepository.save(postLike)
+        } else {
+            postLike.isActive = !postLike.isActive
+        }
+
+        return PostCommunityPostLikeResponse(like = postLike.isActive)
+    }
+
+    @Transactional
+    fun createCommunityPostComment(comment: String, postId: Long, parentId: Long?, member: Member) {
+        val post = repository.findByIdOrNull(id = postId)
+            ?: throw SodaException("잘못된 게시물 입니다.\n다시 시도해 주세요.")
+
+        val postComment = CreatorCommunityComment(comment = comment)
+        postComment.creatorCommunity = post
+        postComment.member = member
+
+        val parent = if (parentId != null) {
+            commentRepository.findByIdOrNull(id = parentId)
+        } else {
+            null
+        }
+
+        if (parent != null) {
+            postComment.parent = parent
+        }
+
+        commentRepository.save(postComment)
+    }
+
+    @Transactional
+    fun modifyCommunityPostComment(request: ModifyCommunityPostCommentRequest, member: Member) {
+        val postComment = commentRepository.findByIdOrNull(id = request.commentId)
+            ?: throw SodaException("잘못된 접근 입니다.\n확인 후 다시 시도해 주세요.")
+
+        if (request.comment != null && postComment.member!!.id!! == member.id!!) {
+            postComment.comment = request.comment
+        }
+
+        if (
+            request.isActive != null &&
+            (
+                postComment.member!!.id!! == member.id!! ||
+                    postComment.creatorCommunity!!.member!!.id!! == member.id!!
+                )
+        ) {
+            postComment.isActive = request.isActive
+        }
+    }
+
+    fun getCommunityPostCommentList(
+        postId: Long,
+        timezone: String,
+        offset: Long,
+        limit: Long
+    ): GetCommunityPostCommentListResponse {
+        val commentList = commentRepository.findByPostId(
+            cloudFrontHost = imageHost,
+            timezone = timezone,
+            id = postId,
+            offset = offset,
+            limit = limit
+        )
+
+        val totalCount = commentRepository.totalCountCommentByPostId(postId = postId)
+
+        return GetCommunityPostCommentListResponse(totalCount = totalCount, items = commentList)
+    }
+}
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt
new file mode 100644
index 0000000..f062e40
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt
@@ -0,0 +1,16 @@
+package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity
+
+import com.querydsl.core.annotations.QueryProjection
+import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.GetCommunityPostCommentListItem
+
+data class GetCommunityPostListResponse @QueryProjection constructor(
+    val creatorNickname: String,
+    val creatorProfileUrl: String,
+    val imageUrl: String?,
+    val content: String,
+    val date: String,
+    val isLike: Boolean,
+    val likeCount: Int,
+    val commentCount: Int,
+    val firstComment: GetCommunityPostCommentListItem?
+)
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/ModifyCommunityPostRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/ModifyCommunityPostRequest.kt
new file mode 100644
index 0000000..58ae72a
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/ModifyCommunityPostRequest.kt
@@ -0,0 +1,8 @@
+package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity
+
+data class ModifyCommunityPostRequest(
+    val creatorCommunityId: Long,
+    val content: String?,
+    val isCommentAvailable: Boolean?,
+    val isAdult: Boolean?
+)
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreateCommunityPostCommentRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreateCommunityPostCommentRequest.kt
new file mode 100644
index 0000000..5e833d6
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreateCommunityPostCommentRequest.kt
@@ -0,0 +1,3 @@
+package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment
+
+data class CreateCommunityPostCommentRequest(val comment: String, val postId: Long, val parentId: Long?)
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityComment.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityComment.kt
new file mode 100644
index 0000000..6e65c0a
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityComment.kt
@@ -0,0 +1,37 @@
+package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment
+
+import kr.co.vividnext.sodalive.common.BaseEntity
+import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.CreatorCommunity
+import kr.co.vividnext.sodalive.member.Member
+import javax.persistence.Column
+import javax.persistence.Entity
+import javax.persistence.FetchType
+import javax.persistence.JoinColumn
+import javax.persistence.ManyToOne
+import javax.persistence.OneToMany
+
+@Entity
+data class CreatorCommunityComment(
+    @Column(columnDefinition = "TEXT", nullable = false)
+    var comment: String,
+    var isActive: Boolean = true
+) : BaseEntity() {
+    @ManyToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name = "parent_id", nullable = true)
+    var parent: CreatorCommunityComment? = null
+        set(value) {
+            value?.children?.add(this)
+            field = value
+        }
+
+    @OneToMany(mappedBy = "parent")
+    var children: MutableList<CreatorCommunityComment> = mutableListOf()
+
+    @ManyToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name = "member_id", nullable = false)
+    var member: Member? = null
+
+    @ManyToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name = "creator_community_id", nullable = false)
+    var creatorCommunity: CreatorCommunity? = null
+}
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityCommentRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityCommentRepository.kt
new file mode 100644
index 0000000..ccd52bf
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityCommentRepository.kt
@@ -0,0 +1,91 @@
+package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment
+
+import com.querydsl.jpa.impl.JPAQueryFactory
+import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.QCreatorCommunityComment.creatorCommunityComment
+import org.springframework.data.jpa.repository.JpaRepository
+import java.time.ZoneId
+import java.time.format.DateTimeFormatter
+
+interface CreatorCommunityCommentRepository :
+    JpaRepository<CreatorCommunityComment, Long>, CreatorCommunityCommentQueryRepository
+
+interface CreatorCommunityCommentQueryRepository {
+    fun findByPostId(
+        cloudFrontHost: String,
+        timezone: String,
+        id: Long,
+        offset: Long,
+        limit: Long
+    ): List<GetCommunityPostCommentListItem>
+
+    fun commentReplyCountByCommentId(commentId: Long): Int
+
+    fun totalCountCommentByPostId(postId: Long): Int
+}
+
+class CreatorCommunityCommentQueryRepositoryImpl(
+    private val queryFactory: JPAQueryFactory
+) : CreatorCommunityCommentQueryRepository {
+    override fun findByPostId(
+        cloudFrontHost: String,
+        timezone: String,
+        id: Long,
+        offset: Long,
+        limit: Long
+    ): List<GetCommunityPostCommentListItem> {
+        return queryFactory
+            .selectFrom(creatorCommunityComment)
+            .where(
+                creatorCommunityComment.isActive.isTrue
+                    .and(creatorCommunityComment.creatorCommunity.id.eq(id))
+            )
+            .offset(offset)
+            .limit(limit)
+            .fetch()
+            .asSequence()
+            .map {
+                val date = it.createdAt!!
+                    .atZone(ZoneId.of("UTC"))
+                    .withZoneSameInstant(ZoneId.of(timezone))
+
+                GetCommunityPostCommentListItem(
+                    id = it.id!!,
+                    writerId = it.member!!.id!!,
+                    nickname = it.member!!.nickname,
+                    profileUrl = if (it.member!!.profileImage != null) {
+                        "$cloudFrontHost/${it.member!!.profileImage}"
+                    } else {
+                        "$cloudFrontHost/profile/default-profile.png"
+                    },
+                    comment = it.comment,
+                    date = date.format(DateTimeFormatter.ofPattern("yyyy.MM.dd E hh:mm a")),
+                    replyCount = commentReplyCountByCommentId(it.id!!)
+                )
+            }
+            .toList()
+    }
+
+    override fun commentReplyCountByCommentId(commentId: Long): Int {
+        return queryFactory.select(creatorCommunityComment.id)
+            .from(creatorCommunityComment)
+            .where(
+                creatorCommunityComment.isActive.isTrue
+                    .and(creatorCommunityComment.parent.isNotNull)
+                    .and(creatorCommunityComment.parent.id.eq(commentId))
+            )
+            .fetch()
+            .size
+    }
+
+    override fun totalCountCommentByPostId(postId: Long): Int {
+        return queryFactory.select(creatorCommunityComment.id)
+            .from(creatorCommunityComment)
+            .where(
+                creatorCommunityComment.creatorCommunity.id.eq(postId)
+                    .and(creatorCommunityComment.isActive.isTrue)
+                    .and(creatorCommunityComment.parent.isNull)
+            )
+            .fetch()
+            .size
+    }
+}
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/GetCommunityPostCommentListResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/GetCommunityPostCommentListResponse.kt
new file mode 100644
index 0000000..58c15a4
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/GetCommunityPostCommentListResponse.kt
@@ -0,0 +1,16 @@
+package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment
+
+data class GetCommunityPostCommentListResponse(
+    val totalCount: Int,
+    val items: List<GetCommunityPostCommentListItem>
+)
+
+data class GetCommunityPostCommentListItem(
+    val id: Long,
+    val writerId: Long,
+    val nickname: String,
+    val profileUrl: String,
+    val comment: String,
+    val date: String,
+    val replyCount: Int
+)
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/ModifyCommunityPostCommentRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/ModifyCommunityPostCommentRequest.kt
new file mode 100644
index 0000000..0a363fd
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/ModifyCommunityPostCommentRequest.kt
@@ -0,0 +1,3 @@
+package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment
+
+data class ModifyCommunityPostCommentRequest(val commentId: Long, val comment: String?, val isActive: Boolean?)
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/CreatorCommunityLike.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/CreatorCommunityLike.kt
new file mode 100644
index 0000000..36ea0d0
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/CreatorCommunityLike.kt
@@ -0,0 +1,22 @@
+package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like
+
+import kr.co.vividnext.sodalive.common.BaseEntity
+import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.CreatorCommunity
+import kr.co.vividnext.sodalive.member.Member
+import javax.persistence.Entity
+import javax.persistence.FetchType
+import javax.persistence.JoinColumn
+import javax.persistence.ManyToOne
+
+@Entity
+data class CreatorCommunityLike(
+    var isActive: Boolean = true
+) : BaseEntity() {
+    @ManyToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name = "member_id", nullable = false)
+    var member: Member? = null
+
+    @ManyToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name = "creator_community_id", nullable = false)
+    var creatorCommunity: CreatorCommunity? = null
+}
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/CreatorCommunityLikeRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/CreatorCommunityLikeRepository.kt
new file mode 100644
index 0000000..6d9668d
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/CreatorCommunityLikeRepository.kt
@@ -0,0 +1,30 @@
+package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like
+
+import com.querydsl.jpa.impl.JPAQueryFactory
+import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like.QCreatorCommunityLike.creatorCommunityLike
+import org.springframework.data.jpa.repository.JpaRepository
+
+interface CreatorCommunityLikeRepository :
+    JpaRepository<CreatorCommunityLike, Long>, CreatorCommunityLikeQueryRepository {
+    fun findByIdAndMemberId(id: Long, memberId: Long): CreatorCommunityLike?
+}
+
+interface CreatorCommunityLikeQueryRepository {
+    fun totalCountCommunityPostLikeByPostId(postId: Long): Int
+}
+
+class CreatorCommunityLikeQueryRepositoryImpl(
+    private val queryFactory: JPAQueryFactory
+) : CreatorCommunityLikeQueryRepository {
+    override fun totalCountCommunityPostLikeByPostId(postId: Long): Int {
+        return queryFactory
+            .select(creatorCommunityLike.id)
+            .from(creatorCommunityLike)
+            .where(
+                creatorCommunityLike.isActive.isTrue
+                    .and(creatorCommunityLike.creatorCommunity.id.eq(postId))
+            )
+            .fetch()
+            .size
+    }
+}
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/PostCommunityPostLikeRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/PostCommunityPostLikeRequest.kt
new file mode 100644
index 0000000..53a5c48
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/PostCommunityPostLikeRequest.kt
@@ -0,0 +1,3 @@
+package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like
+
+data class PostCommunityPostLikeRequest(val postId: Long)
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/PostCommunityPostLikeResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/PostCommunityPostLikeResponse.kt
new file mode 100644
index 0000000..199e6b5
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/PostCommunityPostLikeResponse.kt
@@ -0,0 +1,3 @@
+package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like
+
+data class PostCommunityPostLikeResponse(val like: Boolean)

From 13dc77666af979fa6bda6414ca7d3e6a9d6d42fc Mon Sep 17 00:00:00 2001
From: Klaus <klaus@vividnext.co.kr>
Date: Tue, 19 Dec 2023 23:45:39 +0900
Subject: [PATCH 02/18] =?UTF-8?q?=EC=BB=A4=EB=AE=A4=EB=8B=88=ED=8B=B0=20AP?=
 =?UTF-8?q?I=20-=20url=20path=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../profile/creatorCommunity/CreatorCommunityController.kt    | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityController.kt
index 4aa66a6..348bed8 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityController.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityController.kt
@@ -15,12 +15,14 @@ import org.springframework.web.bind.annotation.PathVariable
 import org.springframework.web.bind.annotation.PostMapping
 import org.springframework.web.bind.annotation.PutMapping
 import org.springframework.web.bind.annotation.RequestBody
+import org.springframework.web.bind.annotation.RequestMapping
 import org.springframework.web.bind.annotation.RequestParam
 import org.springframework.web.bind.annotation.RequestPart
 import org.springframework.web.bind.annotation.RestController
 import org.springframework.web.multipart.MultipartFile
 
-@RestController("/creator-community")
+@RestController
+@RequestMapping("/creator-community")
 class CreatorCommunityController(private val service: CreatorCommunityService) {
     @PostMapping
     @PreAuthorize("hasRole('CREATOR')")

From 290be744a33719d861e90bf84a14203f9748e009 Mon Sep 17 00:00:00 2001
From: Klaus <klaus@vividnext.co.kr>
Date: Wed, 20 Dec 2023 00:03:13 +0900
Subject: [PATCH 03/18] =?UTF-8?q?=EC=B1=84=EB=84=90=20=ED=94=84=EB=A1=9C?=
 =?UTF-8?q?=ED=95=84=20API=20-=20community=20=EA=B2=8C=EC=8B=9C=EB=AC=BC?=
 =?UTF-8?q?=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../vividnext/sodalive/explorer/ExplorerService.kt | 14 ++++++++++++++
 .../sodalive/explorer/GetCreatorProfileResponse.kt |  2 ++
 2 files changed, 16 insertions(+)

diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerService.kt
index af0b47d..3cf3390 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerService.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerService.kt
@@ -11,6 +11,7 @@ import kr.co.vividnext.sodalive.explorer.profile.CreatorCheers
 import kr.co.vividnext.sodalive.explorer.profile.CreatorCheersRepository
 import kr.co.vividnext.sodalive.explorer.profile.PostWriteCheersRequest
 import kr.co.vividnext.sodalive.explorer.profile.PutWriteCheersRequest
+import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.CreatorCommunityService
 import kr.co.vividnext.sodalive.fcm.FcmEvent
 import kr.co.vividnext.sodalive.fcm.FcmEventType
 import kr.co.vividnext.sodalive.live.room.detail.GetRoomDetailUser
@@ -36,6 +37,8 @@ class ExplorerService(
     private val queryRepository: ExplorerQueryRepository,
     private val cheersRepository: CreatorCheersRepository,
     private val noticeRepository: ChannelNoticeRepository,
+    private val communityService: CreatorCommunityService,
+
     private val applicationEventPublisher: ApplicationEventPublisher,
 
     @Value("\${cloud.aws.cloud-front.host}")
@@ -227,6 +230,16 @@ class ExplorerService(
         // 공지사항
         val notice = queryRepository.getNoticeString(creatorId)
 
+        // 커뮤니티
+        val communityPostList = communityService.getCommunityPostList(
+            creatorId = creatorId,
+            memberId = member.id!!,
+            timezone = timezone,
+            offset = 0,
+            limit = 3,
+            isAdult = member.auth != null
+        )
+
         // 응원
         val cheers = queryRepository.getCheersList(creatorId, timezone = timezone, offset = 0, limit = 4)
 
@@ -262,6 +275,7 @@ class ExplorerService(
             liveRoomList = liveRoomList,
             contentList = contentList,
             notice = notice,
+            communityPostList = communityPostList,
             cheers = cheers,
             activitySummary = GetCreatorActivitySummary(
                 liveCount = liveCount,
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/GetCreatorProfileResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/GetCreatorProfileResponse.kt
index d7f9a83..da86441 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/GetCreatorProfileResponse.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/GetCreatorProfileResponse.kt
@@ -1,6 +1,7 @@
 package kr.co.vividnext.sodalive.explorer
 
 import kr.co.vividnext.sodalive.content.GetAudioContentListItem
+import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.GetCommunityPostListResponse
 
 data class GetCreatorProfileResponse(
     val creator: CreatorResponse,
@@ -9,6 +10,7 @@ data class GetCreatorProfileResponse(
     val liveRoomList: List<LiveRoomResponse>,
     val contentList: List<GetAudioContentListItem>,
     val notice: String,
+    val communityPostList: List<GetCommunityPostListResponse>,
     val cheers: GetCheersResponse,
     val activitySummary: GetCreatorActivitySummary,
     val isBlock: Boolean

From e090a2fe7af069b1cd3a7e005928a7a3972f23eb Mon Sep 17 00:00:00 2001
From: Klaus <klaus@vividnext.co.kr>
Date: Wed, 20 Dec 2023 02:11:47 +0900
Subject: [PATCH 04/18] =?UTF-8?q?=EC=BB=A4=EB=AE=A4=EB=8B=88=ED=8B=B0=20?=
 =?UTF-8?q?=EA=B2=8C=EC=8B=9C=EB=AC=BC=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20-?=
 =?UTF-8?q?=20=EA=B2=8C=EC=8B=9C=EB=AC=BC=20ID=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../explorer/profile/creatorCommunity/CreatorCommunityService.kt | 1 +
 .../profile/creatorCommunity/GetCommunityPostListResponse.kt     | 1 +
 2 files changed, 2 insertions(+)

diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
index 67ada02..8335f82 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
@@ -159,6 +159,7 @@ class CreatorCommunityService(
                 }
 
                 GetCommunityPostListResponse(
+                    postId = it.id!!,
                     creatorNickname = it.member!!.nickname,
                     creatorProfileUrl = if (it.member!!.profileImage != null) {
                         "$imageHost/${it.member!!.profileImage}"
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt
index f062e40..8693eb1 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt
@@ -4,6 +4,7 @@ import com.querydsl.core.annotations.QueryProjection
 import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.GetCommunityPostCommentListItem
 
 data class GetCommunityPostListResponse @QueryProjection constructor(
+    val postId: Long,
     val creatorNickname: String,
     val creatorProfileUrl: String,
     val imageUrl: String?,

From 72042336639cffbac1cde3fb378a94a1a760fded Mon Sep 17 00:00:00 2001
From: Klaus <klaus@vividnext.co.kr>
Date: Wed, 20 Dec 2023 03:18:19 +0900
Subject: [PATCH 05/18] =?UTF-8?q?=EC=BB=A4=EB=AE=A4=EB=8B=88=ED=8B=B0=20?=
 =?UTF-8?q?=EA=B2=8C=EC=8B=9C=EB=AC=BC=20=EB=8C=93=EA=B8=80=20=EC=A0=95?=
 =?UTF-8?q?=EB=A0=AC=20-=20=EB=93=B1=EB=A1=9D=20=EB=82=B4=EB=A6=BC?=
 =?UTF-8?q?=EC=B0=A8=EC=88=9C=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../explorer/profile/creatorCommunity/CreatorCommunityService.kt | 1 -
 .../comment/CreatorCommunityCommentRepository.kt                 | 1 +
 2 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
index 8335f82..b69fd08 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
@@ -272,7 +272,6 @@ class CreatorCommunityService(
         )
 
         val totalCount = commentRepository.totalCountCommentByPostId(postId = postId)
-
         return GetCommunityPostCommentListResponse(totalCount = totalCount, items = commentList)
     }
 }
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityCommentRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityCommentRepository.kt
index ccd52bf..265d9d1 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityCommentRepository.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityCommentRepository.kt
@@ -41,6 +41,7 @@ class CreatorCommunityCommentQueryRepositoryImpl(
             )
             .offset(offset)
             .limit(limit)
+            .orderBy(creatorCommunityComment.createdAt.desc())
             .fetch()
             .asSequence()
             .map {

From 0df0d716604cd31dcfe737cae1e38e4616dd9169 Mon Sep 17 00:00:00 2001
From: Klaus <klaus@vividnext.co.kr>
Date: Wed, 20 Dec 2023 03:32:45 +0900
Subject: [PATCH 06/18] =?UTF-8?q?=EC=BB=A4=EB=AE=A4=EB=8B=88=ED=8B=B0=20?=
 =?UTF-8?q?=EA=B2=8C=EC=8B=9C=EB=AC=BC=20=EC=A0=95=EB=A0=AC=20-=20?=
 =?UTF-8?q?=EB=93=B1=EB=A1=9D=20=EB=82=B4=EB=A6=BC=EC=B0=A8=EC=88=9C?=
 =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../profile/creatorCommunity/CreatorCommunityRepository.kt       | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt
index d1e2089..ded8d8b 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt
@@ -49,6 +49,7 @@ class CreatorCommunityQueryRepositoryImpl(private val queryFactory: JPAQueryFact
             .where(where)
             .offset(offset)
             .limit(limit)
+            .orderBy(creatorCommunity.createdAt.desc())
             .fetch()
     }
 

From 25022e4909926e39e3f8a2ced73881e81983e984 Mon Sep 17 00:00:00 2001
From: Klaus <klaus@vividnext.co.kr>
Date: Wed, 20 Dec 2023 03:47:14 +0900
Subject: [PATCH 07/18] =?UTF-8?q?=EC=BB=A4=EB=AE=A4=EB=8B=88=ED=8B=B0=20?=
 =?UTF-8?q?=EA=B2=8C=EC=8B=9C=EB=AC=BC=20=EC=A2=8B=EC=95=84=EC=9A=94=20?=
 =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../CreatorCommunityService.kt                 |  5 +++--
 .../like/CreatorCommunityLikeRepository.kt     | 18 +++++++++++++++---
 2 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
index b69fd08..5bff567 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
@@ -137,7 +137,8 @@ class CreatorCommunityService(
         return postList
             .asSequence()
             .map {
-                val isLike = likeRepository.findByIdAndMemberId(id = it.id!!, memberId = memberId)?.isActive ?: false
+                val isLike =
+                    likeRepository.findByPostIdAndMemberId(postId = it.id!!, memberId = memberId)?.isActive ?: false
                 val likeCount = likeRepository.totalCountCommunityPostLikeByPostId(it.id!!)
                 val commentCount = if (it.isCommentAvailable) {
                     commentRepository.totalCountCommentByPostId(postId = it.id!!)
@@ -197,7 +198,7 @@ class CreatorCommunityService(
 
     @Transactional
     fun communityPostLike(request: PostCommunityPostLikeRequest, member: Member): PostCommunityPostLikeResponse {
-        var postLike = likeRepository.findByIdAndMemberId(id = request.postId, memberId = member.id!!)
+        var postLike = likeRepository.findByPostIdAndMemberId(postId = request.postId, memberId = member.id!!)
 
         if (postLike == null) {
             postLike = CreatorCommunityLike()
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/CreatorCommunityLikeRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/CreatorCommunityLikeRepository.kt
index 6d9668d..263548b 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/CreatorCommunityLikeRepository.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/CreatorCommunityLikeRepository.kt
@@ -1,21 +1,33 @@
 package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like
 
 import com.querydsl.jpa.impl.JPAQueryFactory
+import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.QCreatorCommunity.creatorCommunity
 import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like.QCreatorCommunityLike.creatorCommunityLike
 import org.springframework.data.jpa.repository.JpaRepository
 
 interface CreatorCommunityLikeRepository :
-    JpaRepository<CreatorCommunityLike, Long>, CreatorCommunityLikeQueryRepository {
-    fun findByIdAndMemberId(id: Long, memberId: Long): CreatorCommunityLike?
-}
+    JpaRepository<CreatorCommunityLike, Long>, CreatorCommunityLikeQueryRepository
 
 interface CreatorCommunityLikeQueryRepository {
+    fun findByPostIdAndMemberId(postId: Long, memberId: Long): CreatorCommunityLike?
+
     fun totalCountCommunityPostLikeByPostId(postId: Long): Int
 }
 
 class CreatorCommunityLikeQueryRepositoryImpl(
     private val queryFactory: JPAQueryFactory
 ) : CreatorCommunityLikeQueryRepository {
+    override fun findByPostIdAndMemberId(postId: Long, memberId: Long): CreatorCommunityLike? {
+        return queryFactory
+            .selectFrom(creatorCommunityLike)
+            .innerJoin(creatorCommunityLike.creatorCommunity, creatorCommunity)
+            .where(
+                creatorCommunityLike.creatorCommunity.id.eq(postId)
+                    .and(creatorCommunityLike.member.id.eq(memberId))
+            )
+            .fetchFirst()
+    }
+
     override fun totalCountCommunityPostLikeByPostId(postId: Long): Int {
         return queryFactory
             .select(creatorCommunityLike.id)

From 29c7d5c6777a990aab30b47ab4f802d2e1a142b1 Mon Sep 17 00:00:00 2001
From: Klaus <klaus@vividnext.co.kr>
Date: Wed, 20 Dec 2023 20:27:04 +0900
Subject: [PATCH 08/18] =?UTF-8?q?=EC=BB=A4=EB=AE=A4=EB=8B=88=ED=8B=B0=20?=
 =?UTF-8?q?=EB=8C=93=EA=B8=80=20-=20=EB=8B=B5=EA=B8=80=20=EB=A6=AC?=
 =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20API=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../CreatorCommunityController.kt             | 19 +++++++
 .../CreatorCommunityService.kt                | 18 +++++++
 .../CreatorCommunityCommentRepository.kt      | 49 +++++++++++++++++++
 3 files changed, 86 insertions(+)

diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityController.kt
index 348bed8..3d42e9d 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityController.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityController.kt
@@ -142,4 +142,23 @@ class CreatorCommunityController(private val service: CreatorCommunityService) {
             )
         )
     }
+
+    @GetMapping("/comment/{id}")
+    fun getCommentReplyList(
+        @PathVariable("id") commentId: Long,
+        @RequestParam timezone: String,
+        @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?,
+        pageable: Pageable
+    ) = run {
+        if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
+
+        ApiResponse.ok(
+            service.getCommentReplyList(
+                commentId = commentId,
+                timezone = timezone,
+                offset = pageable.offset,
+                limit = pageable.pageSize.toLong()
+            )
+        )
+    }
 }
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
index 5bff567..2916c97 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
@@ -275,4 +275,22 @@ class CreatorCommunityService(
         val totalCount = commentRepository.totalCountCommentByPostId(postId = postId)
         return GetCommunityPostCommentListResponse(totalCount = totalCount, items = commentList)
     }
+
+    fun getCommentReplyList(
+        commentId: Long,
+        timezone: String,
+        offset: Long,
+        limit: Long
+    ): GetCommunityPostCommentListResponse {
+        val commentList = commentRepository.getCommunityCommentReplyList(
+            cloudFrontHost = imageHost,
+            commentId = commentId,
+            timezone = timezone,
+            offset = offset,
+            limit = limit
+        )
+
+        val totalCount = commentRepository.commentReplyCountByCommentId(commentId)
+        return GetCommunityPostCommentListResponse(totalCount = totalCount, items = commentList)
+    }
 }
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityCommentRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityCommentRepository.kt
index 265d9d1..ee46c5a 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityCommentRepository.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityCommentRepository.kt
@@ -21,6 +21,14 @@ interface CreatorCommunityCommentQueryRepository {
     fun commentReplyCountByCommentId(commentId: Long): Int
 
     fun totalCountCommentByPostId(postId: Long): Int
+
+    fun getCommunityCommentReplyList(
+        cloudFrontHost: String,
+        commentId: Long,
+        timezone: String,
+        offset: Long,
+        limit: Long
+    ): List<GetCommunityPostCommentListItem>
 }
 
 class CreatorCommunityCommentQueryRepositoryImpl(
@@ -89,4 +97,45 @@ class CreatorCommunityCommentQueryRepositoryImpl(
             .fetch()
             .size
     }
+
+    override fun getCommunityCommentReplyList(
+        cloudFrontHost: String,
+        commentId: Long,
+        timezone: String,
+        offset: Long,
+        limit: Long
+    ): List<GetCommunityPostCommentListItem> {
+        return queryFactory
+            .selectFrom(creatorCommunityComment)
+            .where(
+                creatorCommunityComment.isActive.isTrue
+                    .and(creatorCommunityComment.parent.isNotNull)
+                    .and(creatorCommunityComment.parent.id.eq(commentId))
+            )
+            .offset(offset)
+            .limit(limit)
+            .orderBy(creatorCommunityComment.createdAt.desc())
+            .fetch()
+            .asSequence()
+            .map {
+                val date = it.createdAt!!
+                    .atZone(ZoneId.of("UTC"))
+                    .withZoneSameInstant(ZoneId.of(timezone))
+
+                GetCommunityPostCommentListItem(
+                    id = it.id!!,
+                    writerId = it.member!!.id!!,
+                    nickname = it.member!!.nickname,
+                    profileUrl = if (it.member!!.profileImage != null) {
+                        "$cloudFrontHost/${it.member!!.profileImage}"
+                    } else {
+                        "$cloudFrontHost/profile/default-profile.png"
+                    },
+                    comment = it.comment,
+                    date = date.format(DateTimeFormatter.ofPattern("yyyy.MM.dd E hh:mm a")),
+                    replyCount = commentReplyCountByCommentId(it.id!!)
+                )
+            }
+            .toList()
+    }
 }

From ee35a0c13e82aa48f15eced57f79ff7a75f7af2f Mon Sep 17 00:00:00 2001
From: Klaus <klaus@vividnext.co.kr>
Date: Wed, 20 Dec 2023 21:08:00 +0900
Subject: [PATCH 09/18] =?UTF-8?q?=EC=BB=A4=EB=AE=A4=EB=8B=88=ED=8B=B0=20?=
 =?UTF-8?q?=EB=8C=93=EA=B8=80=20-=20=EB=8B=B5=EA=B8=80=EC=9D=B4=20?=
 =?UTF-8?q?=EC=95=84=EB=8B=8C=20=EB=8C=93=EA=B8=80=EB=A7=8C=20=EB=B6=88?=
 =?UTF-8?q?=EB=9F=AC=EC=98=A4=EA=B8=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../comment/CreatorCommunityCommentRepository.kt                 | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityCommentRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityCommentRepository.kt
index ee46c5a..2ee60bd 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityCommentRepository.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityCommentRepository.kt
@@ -46,6 +46,7 @@ class CreatorCommunityCommentQueryRepositoryImpl(
             .where(
                 creatorCommunityComment.isActive.isTrue
                     .and(creatorCommunityComment.creatorCommunity.id.eq(id))
+                    .and(creatorCommunityComment.parent.isNull)
             )
             .offset(offset)
             .limit(limit)

From 2735ac32bbbf16008450aeb9e673e36546535153 Mon Sep 17 00:00:00 2001
From: Klaus <klaus@vividnext.co.kr>
Date: Wed, 20 Dec 2023 22:44:25 +0900
Subject: [PATCH 10/18] =?UTF-8?q?=EC=BB=A4=EB=AE=A4=EB=8B=88=ED=8B=B0=20?=
 =?UTF-8?q?=EA=B2=8C=EC=8B=9C=EB=AC=BC=20=EC=8B=A0=EA=B3=A0=20=EC=B6=94?=
 =?UTF-8?q?=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/main/kotlin/kr/co/vividnext/sodalive/report/Report.kt      | 2 +-
 .../kotlin/kr/co/vividnext/sodalive/report/ReportRequest.kt    | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/report/Report.kt b/src/main/kotlin/kr/co/vividnext/sodalive/report/Report.kt
index 3133dcc..08c11fe 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/report/Report.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/report/Report.kt
@@ -30,5 +30,5 @@ data class Report(
 }
 
 enum class ReportType {
-    PROFILE, USER, CHEERS, AUDIO_CONTENT
+    PROFILE, USER, CHEERS, AUDIO_CONTENT, COMMUNITY_POST
 }
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/report/ReportRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/report/ReportRequest.kt
index 0c52797..e94e345 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/report/ReportRequest.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/report/ReportRequest.kt
@@ -5,5 +5,6 @@ data class ReportRequest(
     val reason: String,
     val reportedMemberId: Long? = null,
     val cheersId: Long? = null,
-    val audioContentId: Long? = null
+    val audioContentId: Long? = null,
+    val communityPostId: Long? = null
 )

From 421846e08ae332fa9071446697df3de218002dc6 Mon Sep 17 00:00:00 2001
From: Klaus <klaus@vividnext.co.kr>
Date: Wed, 20 Dec 2023 23:09:59 +0900
Subject: [PATCH 11/18] =?UTF-8?q?=EC=BB=A4=EB=AE=A4=EB=8B=88=ED=8B=B0=20?=
 =?UTF-8?q?=EA=B2=8C=EC=8B=9C=EB=AC=BC=20=EC=8B=A0=EA=B3=A0=20=EC=B6=94?=
 =?UTF-8?q?=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../kr/co/vividnext/sodalive/report/Report.kt |  5 +++++
 .../sodalive/report/ReportService.kt          | 22 ++++++++++++++++---
 2 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/report/Report.kt b/src/main/kotlin/kr/co/vividnext/sodalive/report/Report.kt
index 08c11fe..25075e4 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/report/Report.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/report/Report.kt
@@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.report
 
 import kr.co.vividnext.sodalive.common.BaseEntity
 import kr.co.vividnext.sodalive.explorer.profile.CreatorCheers
+import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.CreatorCommunity
 import kr.co.vividnext.sodalive.member.Member
 import javax.persistence.Entity
 import javax.persistence.EnumType
@@ -27,6 +28,10 @@ data class Report(
     @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "cheers_id", nullable = true)
     var cheers: CreatorCheers? = null
+
+    @ManyToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name = "community_post_id", nullable = true)
+    var communityPost: CreatorCommunity? = null
 }
 
 enum class ReportType {
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/report/ReportService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/report/ReportService.kt
index 2926dda..5a8107b 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/report/ReportService.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/report/ReportService.kt
@@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.report
 
 import kr.co.vividnext.sodalive.common.SodaException
 import kr.co.vividnext.sodalive.explorer.profile.CreatorCheersRepository
+import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.CreatorCommunityRepository
 import kr.co.vividnext.sodalive.member.Member
 import kr.co.vividnext.sodalive.member.MemberRepository
 import org.springframework.data.repository.findByIdOrNull
@@ -13,7 +14,8 @@ import org.springframework.transaction.annotation.Transactional
 class ReportService(
     private val repository: ReportRepository,
     private val memberRepository: MemberRepository,
-    private val cheersRepository: CreatorCheersRepository
+    private val cheersRepository: CreatorCheersRepository,
+    private val creatorCommunityRepository: CreatorCommunityRepository
 ) {
     @Transactional
     fun save(member: Member, request: ReportRequest) {
@@ -35,18 +37,32 @@ class ReportService(
             null
         }
 
+        val communityPost = if (request.communityPostId != null) {
+            creatorCommunityRepository.findByIdOrNull(request.communityPostId)
+                ?: throw SodaException("신고가 접수되었습니다.")
+        } else {
+            null
+        }
+
         val report = Report(type = request.type, reason = request.reason)
         report.member = member
         report.reportedAccount = reportedAccount
         report.cheers = cheers
+        report.communityPost = communityPost
         repository.save(report)
     }
 
     private fun conditionAllIsNull(request: ReportRequest, isNull: Boolean): Boolean {
         return if (isNull) {
-            request.reportedMemberId == null && request.cheersId == null && request.audioContentId == null
+            request.reportedMemberId == null &&
+                request.cheersId == null &&
+                request.audioContentId == null &&
+                request.communityPostId == null
         } else {
-            request.reportedMemberId != null && request.cheersId != null && request.audioContentId != null
+            request.reportedMemberId != null &&
+                request.cheersId != null &&
+                request.audioContentId != null &&
+                request.communityPostId != null
         }
     }
 }

From 024b8ce872ae0bb087fda345ee3a8fa38aca8161 Mon Sep 17 00:00:00 2001
From: Klaus <klaus@vividnext.co.kr>
Date: Thu, 21 Dec 2023 00:22:38 +0900
Subject: [PATCH 12/18] =?UTF-8?q?=EC=BB=A4=EB=AE=A4=EB=8B=88=ED=8B=B0=20?=
 =?UTF-8?q?=EA=B2=8C=EC=8B=9C=EB=AC=BC=20=EC=88=98=EC=A0=95=20API=20-=20is?=
 =?UTF-8?q?Active=20=EC=88=98=EC=A0=95=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?=
 =?UTF-8?q?=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../explorer/profile/creatorCommunity/CreatorCommunity.kt     | 2 +-
 .../profile/creatorCommunity/CreatorCommunityService.kt       | 4 ++++
 .../profile/creatorCommunity/ModifyCommunityPostRequest.kt    | 3 ++-
 3 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunity.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunity.kt
index 70be7d0..7dea288 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunity.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunity.kt
@@ -16,7 +16,7 @@ data class CreatorCommunity(
     var isAdult: Boolean,
     @Column(nullable = true)
     var imagePath: String? = null,
-    val isActive: Boolean = true
+    var isActive: Boolean = true
 ) : BaseEntity() {
     @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "member_id", nullable = false)
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
index 2916c97..9c71bab 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
@@ -100,6 +100,10 @@ class CreatorCommunityService(
             post.isAdult = request.isAdult
         }
 
+        if (request.isActive != null) {
+            post.isActive = request.isActive
+        }
+
         if (postImage != null) {
             val metadata = ObjectMetadata()
             metadata.contentLength = postImage.size
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/ModifyCommunityPostRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/ModifyCommunityPostRequest.kt
index 58ae72a..d887db4 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/ModifyCommunityPostRequest.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/ModifyCommunityPostRequest.kt
@@ -4,5 +4,6 @@ data class ModifyCommunityPostRequest(
     val creatorCommunityId: Long,
     val content: String?,
     val isCommentAvailable: Boolean?,
-    val isAdult: Boolean?
+    val isAdult: Boolean?,
+    val isActive: Boolean?
 )

From e48fcc9d25fa2dd7bab2d53e918b3afbdd1ac91e Mon Sep 17 00:00:00 2001
From: Klaus <klaus@vividnext.co.kr>
Date: Thu, 21 Dec 2023 00:30:21 +0900
Subject: [PATCH 13/18] =?UTF-8?q?=EC=BB=A4=EB=AE=A4=EB=8B=88=ED=8B=B0=20?=
 =?UTF-8?q?=EA=B2=8C=EC=8B=9C=EB=AC=BC=20=EC=A1=B0=ED=9A=8C=20API=20-=20?=
 =?UTF-8?q?=ED=99=9C=EC=84=B1=ED=99=94=20=EB=90=9C=20=EA=B2=8C=EC=8B=9C?=
 =?UTF-8?q?=EB=AC=BC=EB=A7=8C=20=EB=B6=88=EB=9F=AC=EC=98=A4=EA=B8=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../profile/creatorCommunity/CreatorCommunityRepository.kt       | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt
index ded8d8b..10f99df 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt
@@ -38,6 +38,7 @@ class CreatorCommunityQueryRepositoryImpl(private val queryFactory: JPAQueryFact
         isAdult: Boolean
     ): List<CreatorCommunity> {
         var where = creatorCommunity.member.id.eq(creatorId)
+            .and(creatorCommunity.isActive.isTrue)
 
         if (!isAdult) {
             where = where.and(creatorCommunity.isAdult.isFalse)

From d1d9ef5d24c03270ce9a698ef71d902985676ce6 Mon Sep 17 00:00:00 2001
From: Klaus <klaus@vividnext.co.kr>
Date: Thu, 21 Dec 2023 01:24:27 +0900
Subject: [PATCH 14/18] =?UTF-8?q?=EC=BB=A4=EB=AE=A4=EB=8B=88=ED=8B=B0=20?=
 =?UTF-8?q?=EA=B2=8C=EC=8B=9C=EB=AC=BC=20=EC=A1=B0=ED=9A=8C=20=EC=83=81?=
 =?UTF-8?q?=EC=84=B8=20API=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../CreatorCommunityController.kt             | 18 ++++++
 .../CreatorCommunityRepository.kt             | 16 +++--
 .../CreatorCommunityService.kt                | 58 ++++++++++++++++++-
 .../GetCommunityPostListResponse.kt           |  2 +
 4 files changed, 87 insertions(+), 7 deletions(-)

diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityController.kt
index 3d42e9d..7aa36dc 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityController.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityController.kt
@@ -85,6 +85,24 @@ class CreatorCommunityController(private val service: CreatorCommunityService) {
         )
     }
 
+    @GetMapping("/{id}")
+    fun getCommunityPostDetail(
+        @PathVariable("id") postId: Long,
+        @RequestParam timezone: String,
+        @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
+    ) = run {
+        if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
+
+        ApiResponse.ok(
+            service.getCommunityPostDetail(
+                postId = postId,
+                memberId = member.id!!,
+                timezone = timezone,
+                isAdult = member.auth != null
+            )
+        )
+    }
+
     @PostMapping("/like")
     fun communityPostLike(
         @RequestBody request: PostCommunityPostLikeRequest,
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt
index 10f99df..c0d3d35 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt
@@ -17,7 +17,7 @@ interface CreatorCommunityQueryRepository {
         isAdult: Boolean
     ): List<CreatorCommunity>
 
-    fun findByIdAndActive(postId: Long): CreatorCommunity?
+    fun findByIdAndActive(postId: Long, isAdult: Boolean): CreatorCommunity?
 }
 
 class CreatorCommunityQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : CreatorCommunityQueryRepository {
@@ -54,13 +54,17 @@ class CreatorCommunityQueryRepositoryImpl(private val queryFactory: JPAQueryFact
             .fetch()
     }
 
-    override fun findByIdAndActive(postId: Long): CreatorCommunity? {
+    override fun findByIdAndActive(postId: Long, isAdult: Boolean): CreatorCommunity? {
+        var where = creatorCommunity.id.eq(postId)
+            .and(creatorCommunity.isActive.isTrue)
+
+        if (!isAdult) {
+            where = where.and(creatorCommunity.isAdult.isFalse)
+        }
+
         return queryFactory
             .selectFrom(creatorCommunity)
-            .where(
-                creatorCommunity.id.eq(postId)
-                    .and(creatorCommunity.isActive.isTrue)
-            )
+            .where(where)
             .fetchFirst()
     }
 }
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
index 9c71bab..5c7bf25 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
@@ -178,6 +178,8 @@ class CreatorCommunityService(
                     },
                     content = it.content,
                     date = getTimeAgoString(it.createdAt!!),
+                    isCommentAvailable = it.isCommentAvailable,
+                    isAdult = it.isAdult,
                     isLike = isLike,
                     likeCount = likeCount,
                     commentCount = commentCount,
@@ -187,6 +189,60 @@ class CreatorCommunityService(
             .toList()
     }
 
+    fun getCommunityPostDetail(
+        postId: Long,
+        memberId: Long,
+        timezone: String,
+        isAdult: Boolean
+    ): GetCommunityPostListResponse {
+        val post = repository.findByIdAndActive(postId, isAdult = isAdult)
+            ?: throw SodaException("잘못된 요청입니다.\n다시 시도해 주세요.")
+
+        val isLike = likeRepository.findByPostIdAndMemberId(postId = post.id!!, memberId = memberId)?.isActive ?: false
+        val likeCount = likeRepository.totalCountCommunityPostLikeByPostId(post.id!!)
+        val commentCount = if (post.isCommentAvailable) {
+            commentRepository.totalCountCommentByPostId(postId = post.id!!)
+        } else {
+            0
+        }
+        val commentList = commentRepository.findByPostId(
+            cloudFrontHost = imageHost,
+            timezone = timezone,
+            id = post.id!!,
+            offset = 0,
+            limit = 1
+        )
+
+        val firstComment = if (commentList.isNotEmpty()) {
+            commentList[0]
+        } else {
+            null
+        }
+
+        return GetCommunityPostListResponse(
+            postId = post.id!!,
+            creatorNickname = post.member!!.nickname,
+            creatorProfileUrl = if (post.member!!.profileImage != null) {
+                "$imageHost/${post.member!!.profileImage}"
+            } else {
+                "$imageHost/profile/default-profile.png"
+            },
+            imageUrl = if (post.imagePath != null) {
+                "$imageHost/${post.imagePath!!}"
+            } else {
+                null
+            },
+            content = post.content,
+            date = getTimeAgoString(post.createdAt!!),
+            isCommentAvailable = post.isCommentAvailable,
+            isAdult = post.isAdult,
+            isLike = isLike,
+            likeCount = likeCount,
+            commentCount = commentCount,
+            firstComment = firstComment
+        )
+    }
+
     private fun getTimeAgoString(dateTime: LocalDateTime): String {
         val now = LocalDateTime.now()
         val duration = Duration.between(dateTime, now)
@@ -208,7 +264,7 @@ class CreatorCommunityService(
             postLike = CreatorCommunityLike()
             postLike.member = member
 
-            val post = repository.findByIdAndActive(request.postId)
+            val post = repository.findByIdAndActive(request.postId, isAdult = member.auth != null)
                 ?: throw SodaException("잘못된 요청입니다.\n다시 시도해 주세요.")
 
             postLike.creatorCommunity = post
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt
index 8693eb1..b147761 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt
@@ -10,6 +10,8 @@ data class GetCommunityPostListResponse @QueryProjection constructor(
     val imageUrl: String?,
     val content: String,
     val date: String,
+    val isCommentAvailable: Boolean,
+    val isAdult: Boolean,
     val isLike: Boolean,
     val likeCount: Int,
     val commentCount: Int,

From e4ca84252de46268b8de1cc5b188fb90c89103e0 Mon Sep 17 00:00:00 2001
From: Klaus <klaus@vividnext.co.kr>
Date: Thu, 21 Dec 2023 22:35:52 +0900
Subject: [PATCH 15/18] =?UTF-8?q?=ED=8C=94=EB=A1=9C=EC=9A=B0=20=ED=95=9C?=
 =?UTF-8?q?=20=ED=81=AC=EB=A6=AC=EC=97=90=EC=9D=B4=ED=84=B0=EC=9D=98=207?=
 =?UTF-8?q?=EC=9D=BC=20=EC=9D=B4=EB=82=B4=EC=9D=98=20=EC=BB=A4=EB=AE=A4?=
 =?UTF-8?q?=EB=8B=88=ED=8B=B0=20=EA=B2=8C=EC=8B=9C=EB=AC=BC=2010=EA=B0=9C?=
 =?UTF-8?q?=20=EA=B0=80=EC=A0=B8=EC=98=A4=EA=B8=B0=20API=20=EC=B6=94?=
 =?UTF-8?q?=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../CreatorCommunityController.kt             | 16 +++++
 .../CreatorCommunityRepository.kt             | 43 ++++++++++++++
 .../CreatorCommunityService.kt                | 58 +++++++++++++++++++
 3 files changed, 117 insertions(+)

diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityController.kt
index 7aa36dc..9c18a29 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityController.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityController.kt
@@ -179,4 +179,20 @@ class CreatorCommunityController(private val service: CreatorCommunityService) {
             )
         )
     }
+
+    @GetMapping("/latest")
+    fun getLatestPostListFromCreatorsYouFollow(
+        @RequestParam timezone: String,
+        @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
+    ) = run {
+        if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
+
+        ApiResponse.ok(
+            service.getLatestPostListFromCreatorsYouFollow(
+                timezone = timezone,
+                memberId = member.id!!,
+                isAdult = member.auth != null
+            )
+        )
+    }
 }
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt
index c0d3d35..1ebc02a 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt
@@ -1,9 +1,12 @@
 package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity
 
+import com.querydsl.core.types.dsl.Expressions
 import com.querydsl.jpa.impl.JPAQueryFactory
 import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.QCreatorCommunity.creatorCommunity
 import kr.co.vividnext.sodalive.member.QMember.member
+import kr.co.vividnext.sodalive.member.following.QCreatorFollowing.creatorFollowing
 import org.springframework.data.jpa.repository.JpaRepository
+import java.time.LocalDateTime
 
 interface CreatorCommunityRepository : JpaRepository<CreatorCommunity, Long>, CreatorCommunityQueryRepository
 
@@ -18,6 +21,7 @@ interface CreatorCommunityQueryRepository {
     ): List<CreatorCommunity>
 
     fun findByIdAndActive(postId: Long, isAdult: Boolean): CreatorCommunity?
+    fun getLatestPostListFromCreatorsYouFollow(memberId: Long, isAdult: Boolean): List<CreatorCommunity>
 }
 
 class CreatorCommunityQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : CreatorCommunityQueryRepository {
@@ -67,4 +71,43 @@ class CreatorCommunityQueryRepositoryImpl(private val queryFactory: JPAQueryFact
             .where(where)
             .fetchFirst()
     }
+
+    override fun getLatestPostListFromCreatorsYouFollow(memberId: Long, isAdult: Boolean): List<CreatorCommunity> {
+        val creatorCommunity = QCreatorCommunity.creatorCommunity
+        val latest = QCreatorCommunity.creatorCommunity
+
+        var where = creatorCommunity.isActive.isTrue
+            .and(creatorCommunity.createdAt.after(LocalDateTime.now().minusDays(7)))
+
+        if (!isAdult) {
+            where = where.and(creatorCommunity.isAdult.isFalse)
+        }
+
+        val subQuery = queryFactory
+            .select(latest.member.id, latest.createdAt.max().`as`("maxCreatedAt"))
+            .from(latest)
+            .groupBy(latest.member.id)
+
+        where = where.and(
+            Expressions.list(creatorCommunity.member.id, creatorCommunity.createdAt).`in`(subQuery)
+        )
+
+        val memberSubQuery = queryFactory
+            .select(creatorFollowing.creator.id)
+            .from(creatorFollowing)
+            .where(creatorFollowing.member.id.eq(memberId))
+
+        where = where.and(
+            creatorCommunity.member.id.`in`(memberSubQuery)
+        )
+
+        return queryFactory
+            .selectFrom(creatorCommunity)
+            .innerJoin(creatorCommunity.member, member)
+            .innerJoin(member)
+            .where(where)
+            .orderBy(creatorCommunity.createdAt.desc())
+            .limit(10)
+            .fetch()
+    }
 }
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
index 5c7bf25..c4ff494 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
@@ -353,4 +353,62 @@ class CreatorCommunityService(
         val totalCount = commentRepository.commentReplyCountByCommentId(commentId)
         return GetCommunityPostCommentListResponse(totalCount = totalCount, items = commentList)
     }
+
+    fun getLatestPostListFromCreatorsYouFollow(
+        timezone: String,
+        memberId: Long,
+        isAdult: Boolean
+    ): List<GetCommunityPostListResponse> {
+        val postList = repository.getLatestPostListFromCreatorsYouFollow(memberId = memberId, isAdult = isAdult)
+
+        return postList
+            .asSequence()
+            .map {
+                val isLike =
+                    likeRepository.findByPostIdAndMemberId(postId = it.id!!, memberId = memberId)?.isActive ?: false
+                val likeCount = likeRepository.totalCountCommunityPostLikeByPostId(it.id!!)
+                val commentCount = if (it.isCommentAvailable) {
+                    commentRepository.totalCountCommentByPostId(postId = it.id!!)
+                } else {
+                    0
+                }
+                val commentList = commentRepository.findByPostId(
+                    cloudFrontHost = imageHost,
+                    timezone = timezone,
+                    id = it.id!!,
+                    offset = 0,
+                    limit = 1
+                )
+
+                val firstComment = if (commentList.isNotEmpty()) {
+                    commentList[0]
+                } else {
+                    null
+                }
+
+                GetCommunityPostListResponse(
+                    postId = it.id!!,
+                    creatorNickname = it.member!!.nickname,
+                    creatorProfileUrl = if (it.member!!.profileImage != null) {
+                        "$imageHost/${it.member!!.profileImage}"
+                    } else {
+                        "$imageHost/profile/default-profile.png"
+                    },
+                    imageUrl = if (it.imagePath != null) {
+                        "$imageHost/${it.imagePath!!}"
+                    } else {
+                        null
+                    },
+                    content = it.content,
+                    date = getTimeAgoString(it.createdAt!!),
+                    isCommentAvailable = it.isCommentAvailable,
+                    isAdult = it.isAdult,
+                    isLike = isLike,
+                    likeCount = likeCount,
+                    commentCount = commentCount,
+                    firstComment = firstComment
+                )
+            }
+            .toList()
+    }
 }

From 555c3bfc73d5c5e25f069a1a764aa8d0f2c93fc2 Mon Sep 17 00:00:00 2001
From: Klaus <klaus@vividnext.co.kr>
Date: Thu, 21 Dec 2023 23:17:38 +0900
Subject: [PATCH 16/18] =?UTF-8?q?=ED=8C=94=EB=A1=9C=EC=9A=B0=20=ED=95=9C?=
 =?UTF-8?q?=20=ED=81=AC=EB=A6=AC=EC=97=90=EC=9D=B4=ED=84=B0=EC=9D=98=207?=
 =?UTF-8?q?=EC=9D=BC=20=EC=9D=B4=EB=82=B4=EC=9D=98=20=EC=BB=A4=EB=AE=A4?=
 =?UTF-8?q?=EB=8B=88=ED=8B=B0=20=EA=B2=8C=EC=8B=9C=EB=AC=BC=2010=EA=B0=9C?=
 =?UTF-8?q?=20=EA=B0=80=EC=A0=B8=EC=98=A4=EA=B8=B0=20API=20=EC=B6=94?=
 =?UTF-8?q?=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../creatorCommunity/CreatorCommunityRepository.kt        | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt
index 1ebc02a..cd426d6 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt
@@ -6,7 +6,9 @@ import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.QCreatorCommun
 import kr.co.vividnext.sodalive.member.QMember.member
 import kr.co.vividnext.sodalive.member.following.QCreatorFollowing.creatorFollowing
 import org.springframework.data.jpa.repository.JpaRepository
+import java.time.LocalDate
 import java.time.LocalDateTime
+import java.time.LocalTime
 
 interface CreatorCommunityRepository : JpaRepository<CreatorCommunity, Long>, CreatorCommunityQueryRepository
 
@@ -76,8 +78,10 @@ class CreatorCommunityQueryRepositoryImpl(private val queryFactory: JPAQueryFact
         val creatorCommunity = QCreatorCommunity.creatorCommunity
         val latest = QCreatorCommunity.creatorCommunity
 
+        val localDate = LocalDate.now().minusDays(7)
+        val localTime = LocalTime.of(0, 0)
         var where = creatorCommunity.isActive.isTrue
-            .and(creatorCommunity.createdAt.after(LocalDateTime.now().minusDays(7)))
+            .and(creatorCommunity.createdAt.after(LocalDateTime.of(localDate, localTime)))
 
         if (!isAdult) {
             where = where.and(creatorCommunity.isAdult.isFalse)
@@ -103,8 +107,6 @@ class CreatorCommunityQueryRepositoryImpl(private val queryFactory: JPAQueryFact
 
         return queryFactory
             .selectFrom(creatorCommunity)
-            .innerJoin(creatorCommunity.member, member)
-            .innerJoin(member)
             .where(where)
             .orderBy(creatorCommunity.createdAt.desc())
             .limit(10)

From 7326babc491416c815ac8be508fc2e28412274a2 Mon Sep 17 00:00:00 2001
From: Klaus <klaus@vividnext.co.kr>
Date: Thu, 21 Dec 2023 23:36:20 +0900
Subject: [PATCH 17/18] =?UTF-8?q?=EC=BB=A4=EB=AE=A4=EB=8B=88=ED=8B=B0=20?=
 =?UTF-8?q?=EA=B2=8C=EC=8B=9C=EB=AC=BC=20response=20-=20creatorId=20?=
 =?UTF-8?q?=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../profile/creatorCommunity/CreatorCommunityService.kt        | 3 +++
 .../profile/creatorCommunity/GetCommunityPostListResponse.kt   | 1 +
 2 files changed, 4 insertions(+)

diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
index c4ff494..9d7aed0 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
@@ -165,6 +165,7 @@ class CreatorCommunityService(
 
                 GetCommunityPostListResponse(
                     postId = it.id!!,
+                    creatorId = it.member!!.id!!,
                     creatorNickname = it.member!!.nickname,
                     creatorProfileUrl = if (it.member!!.profileImage != null) {
                         "$imageHost/${it.member!!.profileImage}"
@@ -221,6 +222,7 @@ class CreatorCommunityService(
 
         return GetCommunityPostListResponse(
             postId = post.id!!,
+            creatorId = post.member!!.id!!,
             creatorNickname = post.member!!.nickname,
             creatorProfileUrl = if (post.member!!.profileImage != null) {
                 "$imageHost/${post.member!!.profileImage}"
@@ -388,6 +390,7 @@ class CreatorCommunityService(
 
                 GetCommunityPostListResponse(
                     postId = it.id!!,
+                    creatorId = it.member!!.id!!,
                     creatorNickname = it.member!!.nickname,
                     creatorProfileUrl = if (it.member!!.profileImage != null) {
                         "$imageHost/${it.member!!.profileImage}"
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt
index b147761..4aed806 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt
@@ -5,6 +5,7 @@ import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.GetCom
 
 data class GetCommunityPostListResponse @QueryProjection constructor(
     val postId: Long,
+    val creatorId: Long,
     val creatorNickname: String,
     val creatorProfileUrl: String,
     val imageUrl: String?,

From 8c5b7b811d998128d3e2da4d6b9ade7542ffea79 Mon Sep 17 00:00:00 2001
From: Klaus <klaus@vividnext.co.kr>
Date: Thu, 21 Dec 2023 23:53:33 +0900
Subject: [PATCH 18/18] =?UTF-8?q?=EC=BB=A4=EB=AE=A4=EB=8B=88=ED=8B=B0=20?=
 =?UTF-8?q?=EA=B2=8C=EC=8B=9C=EB=AC=BC=20=EC=A1=B0=ED=9A=8C=20-=20?=
 =?UTF-8?q?=EB=8C=93=EA=B8=80=20=EC=B6=94=EA=B0=80=20=EB=B6=88=EA=B0=80?=
 =?UTF-8?q?=EB=8A=A5=ED=95=9C=20=EA=B2=BD=EC=9A=B0=20=EB=8C=93=EA=B8=80?=
 =?UTF-8?q?=EC=A1=B0=ED=9A=8C=EB=A5=BC=20=ED=95=98=EC=A7=80=20=EC=95=8A?=
 =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../CreatorCommunityService.kt                | 60 +++++++++++--------
 1 file changed, 36 insertions(+), 24 deletions(-)

diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
index 9d7aed0..37e0dae 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt
@@ -149,15 +149,19 @@ class CreatorCommunityService(
                 } else {
                     0
                 }
-                val commentList = commentRepository.findByPostId(
-                    cloudFrontHost = imageHost,
-                    timezone = timezone,
-                    id = it.id!!,
-                    offset = 0,
-                    limit = 1
-                )
+                val commentList = if (it.isCommentAvailable) {
+                    commentRepository.findByPostId(
+                        cloudFrontHost = imageHost,
+                        timezone = timezone,
+                        id = it.id!!,
+                        offset = 0,
+                        limit = 1
+                    )
+                } else {
+                    listOf()
+                }
 
-                val firstComment = if (commentList.isNotEmpty()) {
+                val firstComment = if (it.isCommentAvailable && commentList.isNotEmpty()) {
                     commentList[0]
                 } else {
                     null
@@ -206,15 +210,19 @@ class CreatorCommunityService(
         } else {
             0
         }
-        val commentList = commentRepository.findByPostId(
-            cloudFrontHost = imageHost,
-            timezone = timezone,
-            id = post.id!!,
-            offset = 0,
-            limit = 1
-        )
+        val commentList = if (post.isCommentAvailable) {
+            commentRepository.findByPostId(
+                cloudFrontHost = imageHost,
+                timezone = timezone,
+                id = post.id!!,
+                offset = 0,
+                limit = 1
+            )
+        } else {
+            listOf()
+        }
 
-        val firstComment = if (commentList.isNotEmpty()) {
+        val firstComment = if (post.isCommentAvailable && commentList.isNotEmpty()) {
             commentList[0]
         } else {
             null
@@ -374,15 +382,19 @@ class CreatorCommunityService(
                 } else {
                     0
                 }
-                val commentList = commentRepository.findByPostId(
-                    cloudFrontHost = imageHost,
-                    timezone = timezone,
-                    id = it.id!!,
-                    offset = 0,
-                    limit = 1
-                )
+                val commentList = if (it.isCommentAvailable) {
+                    commentRepository.findByPostId(
+                        cloudFrontHost = imageHost,
+                        timezone = timezone,
+                        id = it.id!!,
+                        offset = 0,
+                        limit = 1
+                    )
+                } else {
+                    listOf()
+                }
 
-                val firstComment = if (commentList.isNotEmpty()) {
+                val firstComment = if (it.isCommentAvailable && commentList.isNotEmpty()) {
                     commentList[0]
                 } else {
                     null