From 46b282a81708aa78d7fb4c73a94c082236f36c10 Mon Sep 17 00:00:00 2001 From: Klaus Date: Mon, 13 Apr 2026 14:55:59 +0900 Subject: [PATCH] =?UTF-8?q?fix(agent-assignment):=20=EC=86=8C=EC=86=8D=20?= =?UTF-8?q?=ED=81=AC=EB=A6=AC=EC=97=90=EC=9D=B4=ED=84=B0=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EC=8B=9C=EA=B0=81=EC=9D=84=20KST=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=ED=99=98=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...60413_에이전트크리에이터소속시간UTC변환.md | 16 ++++++++ .../agent/read/AdminAgentReadService.kt | 12 +++++- .../agent/read/AdminAgentReadServiceTest.kt | 40 +++++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/docs/20260413_에이전트크리에이터소속시간UTC변환.md b/docs/20260413_에이전트크리에이터소속시간UTC변환.md index 16ea3af8..8c3e58de 100644 --- a/docs/20260413_에이전트크리에이터소속시간UTC변환.md +++ b/docs/20260413_에이전트크리에이터소속시간UTC변환.md @@ -7,6 +7,9 @@ - [x] `LocalDateTimeExtensions`에 타임존 입력 기반 UTC 변환 확장함수를 추가하고 기본 타임존을 KST로 둔다. - [x] `AdminAgentCreatorService`의 시간 변환을 확장함수 호출로 리팩터링한다. - [x] 확장함수 테스트와 관련 서비스 테스트를 다시 검증하고 기록한다. +- [x] `AdminAgentReadService.getAssignedCreators` 응답의 `assignedAt`을 UTC에서 KST로 변환해 내려오도록 수정한다. +- [x] `AdminAgentReadServiceTest`에 `getAssignedCreators` 응답 시간이 KST로 변환되는 회귀 테스트를 추가한다. +- [x] 변경 파일 진단과 관련 Gradle 테스트를 수행하고 결과를 기록한다. --- @@ -33,3 +36,16 @@ - `AdminAgentCreatorService`는 내부 변환 함수를 제거하고 `request.assignedAt.convertToUtc()` / `request.unassignedAt.convertToUtc()`를 사용하도록 수정했다. - `./gradlew test --tests "kr.co.vividnext.sodalive.extensions.LocalDateTimeExtensionsTest" --tests "kr.co.vividnext.sodalive.admin.partner.agent.assignment.AdminAgentCreatorServiceTest"` 실행: 성공(BUILD SUCCESSFUL). - `./gradlew ktlintCheck` 실행: 성공(BUILD SUCCESSFUL). + +### 3차 수정 + +- 무엇을: 관리자 에이전트 소속 크리에이터 목록 응답의 `assignedAt`을 UTC 기준 저장값에서 KST 기준 시각으로 변환해 반환하도록 수정. +- 왜: 현재 `getAssignedCreators`는 DB에서 조회한 UTC `assignedAt`을 그대로 내려주고 있어 관리자 화면에서 소속 시각이 9시간 늦게 보일 수 있음. +- 어떻게: + - 내부 패턴 조사 결과, 저장소에서는 UTC raw 값을 유지하고 서비스/DTO 경계에서 `UTC -> Asia/Seoul` 변환을 적용하는 방식이 가장 가까운 관례임을 확인했다. + - `AdminAgentReadServiceTest`에 `assignedAt = 2026-04-10T03:00:00` UTC 조회값이 `2026-04-10T12:00:00` KST로 반환되는 회귀 테스트를 먼저 추가했고, 수정 전 해당 테스트가 실패함을 확인했다. + - `AdminAgentReadService.getAssignedCreators`에서 조회 결과를 매핑하며 `assignedAt.atZone(UTC).withZoneSameInstant(Asia/Seoul).toLocalDateTime()`으로 변환하도록 수정했다. + - `lsp_diagnostics` 실행: `.kt` 확장자용 LSP 서버 미설정으로 도구 진단 불가. + - `./gradlew test --tests "kr.co.vividnext.sodalive.admin.partner.agent.read.AdminAgentReadServiceTest.shouldConvertAssignedAtToKstWhenGettingAssignedCreators"` 실행: 최초 실패 후 수정 뒤 성공(BUILD SUCCESSFUL). + - `./gradlew test --tests "kr.co.vividnext.sodalive.admin.partner.agent.read.AdminAgentReadServiceTest" --tests "kr.co.vividnext.sodalive.admin.partner.agent.read.AdminAgentReadQueryRepositoryTest"` 실행: 성공(BUILD SUCCESSFUL). + - `./gradlew ktlintCheck` 실행: 성공(BUILD SUCCESSFUL). diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/partner/agent/read/AdminAgentReadService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/partner/agent/read/AdminAgentReadService.kt index 08c5d5cd..4268f6b9 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/partner/agent/read/AdminAgentReadService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/partner/agent/read/AdminAgentReadService.kt @@ -56,9 +56,19 @@ class AdminAgentReadService( fun getAssignedCreators(agentId: Long, offset: Long, limit: Long): GetAdminAgentAssignedCreatorResponse { validateAgent(agentId) val now = LocalDateTime.now() + val items = queryRepository.getAssignedCreators(agentId = agentId, offset = offset, limit = limit, currentTime = now) + .map { + it.copy( + assignedAt = it.assignedAt + .atZone(ZoneId.of("UTC")) + .withZoneSameInstant(kstZoneId) + .toLocalDateTime() + ) + } + return GetAdminAgentAssignedCreatorResponse( totalCount = queryRepository.getAssignedCreatorTotalCount(agentId = agentId, currentTime = now), - items = queryRepository.getAssignedCreators(agentId = agentId, offset = offset, limit = limit, currentTime = now) + items = items ) } diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/admin/partner/agent/read/AdminAgentReadServiceTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/admin/partner/agent/read/AdminAgentReadServiceTest.kt index 0e37cce5..b5a2dbf7 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/admin/partner/agent/read/AdminAgentReadServiceTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/admin/partner/agent/read/AdminAgentReadServiceTest.kt @@ -15,6 +15,7 @@ import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test import org.mockito.Mockito +import java.time.LocalDateTime import java.time.ZonedDateTime import java.util.Optional @@ -117,6 +118,45 @@ class AdminAgentReadServiceTest { assertEquals("partner.agent.ratio.invalid_agent", exception.messageKey) } + @Test + @DisplayName("소속 크리에이터 목록 조회는 assignedAt을 UTC에서 KST로 변환해 반환한다") + fun shouldConvertAssignedAtToKstWhenGettingAssignedCreators() { + val agent = Member( + email = "agent@test.com", + password = "password", + nickname = "agent", + role = MemberRole.AGENT + ) + agent.id = 11L + + Mockito.`when`(memberRepository.findById(11L)).thenReturn(Optional.of(agent)) + Mockito.`when`( + queryRepository.getAssignedCreatorTotalCount( + Mockito.eq(11L), + Mockito.any(LocalDateTime::class.java) ?: LocalDateTime.now() + ) + ).thenReturn(1) + Mockito.doReturn( + listOf( + GetAdminAgentAssignedCreatorItem( + creatorId = 21L, + creatorNickname = "creator-a", + assignedAt = LocalDateTime.of(2026, 4, 10, 3, 0) + ) + ) + ).`when`(queryRepository).getAssignedCreators( + Mockito.eq(11L), + Mockito.eq(0L), + Mockito.eq(20L), + Mockito.any(LocalDateTime::class.java) ?: LocalDateTime.now() + ) + + val actual = service.getAssignedCreators(agentId = 11L, offset = 0L, limit = 20L) + + assertEquals(1, actual.totalCount) + assertEquals(LocalDateTime.of(2026, 4, 10, 12, 0), actual.items.first().assignedAt) + } + @Test @DisplayName("라이브 정산 상세 조회는 기존 AgentCalculateService로 위임한다") fun shouldDelegateLiveSettlementToAgentCalculateService() {