-
Notifications
You must be signed in to change notification settings - Fork 1
refactor: PoseService 책임 분리 + 관리자 업로드용 userId nullable화 #314
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| package com.neki.domain.pose.infra.persist | ||
|
|
||
| import com.neki.core.domain.vo.SortOrder | ||
| import com.neki.domain.pose.dto.PoseQuery | ||
| import com.neki.domain.pose.infra.persist.jpa.JpaPoseRepository | ||
| import com.neki.domain.pose.infra.persist.jpa.PosesQueryRepository | ||
| import com.neki.domain.pose.models.HeadCount | ||
|
|
@@ -37,6 +38,13 @@ class PoseRepositoryAdapter( | |
| override fun listOwnedScrapPoses(userId: Long, offset: Int, limit: Int, sortOrder: SortOrder): List<Pose> = | ||
| queryRepository.findOwnedScrapPoses(userId, offset, limit, sortOrder) | ||
|
|
||
| // 어드민 목록 조회 전용이라 apps:api 에서는 호출 경로가 없다. | ||
| override fun findAll(query: PoseQuery.GetAllPoses): List<Pose> = | ||
| throw UnsupportedOperationException("어드민 전용 조회다. apps:admin 의 어댑터를 쓴다.") | ||
|
|
||
| override fun count(query: PoseQuery.GetAllPoses): Long = | ||
| throw UnsupportedOperationException("어드민 전용 조회다. apps:admin 의 어댑터를 쓴다.") | ||
|
Comment on lines
+41
to
+46
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
rg -n -C 6 --glob '*.kt' \
'class .*PoseRepositoryAdapter|: PoseRepository|findAll\(query: PoseQuery\.GetAllPoses\)|count\(query: PoseQuery\.GetAllPoses\)|listAllPoses\(' .
rg -n -C 6 --glob '*.kt' \
'PoseService\(|GetAllPoses|`@Primary`|`@Qualifier`|`@Bean`' .Repository: Team-Neki/Team-Neki-Server Length of output: 50382 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- admin pose sources ---'
rg -l --glob '*.kt' 'PoseRepository|PoseService|GetAllPoses|findAll\(query|count\(query' apps/admin domain/src/main/kotlin/com/neki/domain/pose 2>/dev/null | sort
printf '%s\n' '--- admin implementations and wiring ---'
rg -n -C 5 --glob '*.kt' \
'class .*Pose.*(Adapter|Repository)|: *PoseRepository|PoseService|GetAllPoses|findAll\(query: *PoseQuery\.GetAllPoses\)|count\(query: *PoseQuery\.GetAllPoses\)|`@Qualifier`|`@Primary`' \
apps/admin domain/src/main/kotlin/com/neki/domain/pose 2>/dev/nullRepository: Team-Neki/Team-Neki-Server Length of output: 1028 🤖 get_repo_knowledge executed:
Length of output: 1089 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- project modules and admin paths ---'
git ls-files \
'settings.gradle*' 'apps/**' ':apps/**' \
| rg '(^|/)(admin|api)(/|$)|settings\.gradle' || true
printf '%s\n' '--- pose repository implementations and consumers ---'
git ls-files '*.kt' \
| xargs -r rg -n -C 4 \
'class .*Pose.*(Adapter|Repository)|: *PoseRepository|PoseService\(|listAllPoses\(|GetAllPoses' \
|| true
printf '%s\n' '--- application wiring annotations ---'
git ls-files '*.kt' \
| xargs -r rg -n -C 3 \
'@(Component|Service|Repository|Configuration|Bean|Primary|Qualifier)|PoseRepository' \
| rg 'Pose|Repository|Component|Service|Bean|Primary|Qualifier' \
| head -n 240Repository: Team-Neki/Team-Neki-Server Length of output: 50382
현재 🤖 Prompt for AI Agents |
||
|
|
||
| override fun existsPose(poseId: Long): Boolean = jpaRepository.existsById(poseId) | ||
|
|
||
| override fun countPoses(headCount: HeadCount, excludeIds: List<Long>): Long = | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| package com.neki.domain.pose.service | ||
|
|
||
| import com.neki.core.code.ResultCode | ||
| import com.neki.core.domain.vo.Page | ||
| import com.neki.core.exception.BusinessException | ||
| import com.neki.domain.pose.dto.PoseCommand | ||
| import com.neki.domain.pose.dto.PoseQuery | ||
| import com.neki.domain.pose.models.Pose | ||
| import com.neki.domain.pose.models.PoseWithScrap | ||
| import com.neki.domain.pose.models.ScrapPose | ||
| import com.neki.domain.pose.repository.PoseRepository | ||
| import com.neki.domain.pose.repository.ScrapPoseRepository | ||
| import org.springframework.stereotype.Component | ||
|
|
||
| /** | ||
| * fileName : PoseScrapService | ||
| * author : koo | ||
| * date : 2026. 8. 10. | ||
| * description : 스크랩 상태 변경과, 스크랩 여부가 붙은 조회 | ||
| */ | ||
| @Component | ||
| class PoseScrapService( | ||
| private val poseRepository: PoseRepository, | ||
| private val scrapPoseRepository: ScrapPoseRepository, | ||
| ) { | ||
|
|
||
| fun getOwnedPoseWithScrap(query: PoseQuery.GetPose): PoseWithScrap = | ||
| poseRepository.getOwnedPoseWithScrap(query.userId, query.poseId) | ||
| ?: throw BusinessException(ResultCode.NOT_FOUND) | ||
|
|
||
| fun listPosesWithScrap(query: PoseQuery.GetPoses): Page<PoseWithScrap> = query.pagination.slice( | ||
| poseRepository.listPosesWithScrap( | ||
| userId = query.userId, | ||
| offset = query.pagination.offset, | ||
| limit = query.pagination.limit, | ||
| headCount = query.headCount, | ||
| sortOrder = query.pagination.sortOrder, | ||
| ), | ||
| ) | ||
|
|
||
| fun listOwnedScrapPoses(query: PoseQuery.GetScrapPoses): Page<Pose> = query.pagination.slice( | ||
| poseRepository.listOwnedScrapPoses( | ||
| userId = query.userId, | ||
| offset = query.pagination.offset, | ||
| limit = query.pagination.limit, | ||
| sortOrder = query.pagination.sortOrder, | ||
| ), | ||
| ) | ||
|
|
||
| /** | ||
| * 무작위로 고른 포즈는 query에 없으므로 함께 받는다. | ||
| */ | ||
| fun isScraped(query: PoseQuery.GetRandomPose, pose: Pose): Boolean = | ||
| scrapPoseRepository.existsOwnedPoseScrap(ScrapPose(query.userId, pose.id!!)) | ||
|
|
||
| fun updateScrap(command: PoseCommand.UpdatePoseScrap) { | ||
| if (!poseRepository.existsPose(command.poseId)) { | ||
| throw BusinessException(ResultCode.NOT_FOUND) | ||
| } | ||
|
|
||
| val scrapPose = ScrapPose(command.userId, command.poseId) | ||
| if (command.scrap) { | ||
| scrapPoseRepository.add(scrapPose) | ||
| } else { | ||
| scrapPoseRepository.delete(scrapPose) | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
관리자용 업로드 nullable화 진행하시는데, flyway로 null 허용하도록 flyway 추가가 필요합니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
반영했습니다 (468ebcd).
V30__alter_pose_user_id_nullable.sql추가:TB_POSE.user_idNOT NULL 해제, 컬럼 코멘트 갱신Pose엔티티user_id컬럼도nullable = true로 맞췄습니다. 테스트가 ddl-auto create-drop이라 엔티티 어노테이션이 곧 스키마여서 같이 바꿔야 했습니다.