From f80418f5ee986dc5eed4b188ca9477ae0648e7f6 Mon Sep 17 00:00:00 2001 From: Hyowon Yang Date: Thu, 30 Oct 2025 12:47:19 +0900 Subject: [PATCH] =?UTF-8?q?=EC=9D=B4=EB=B2=A4=ED=8A=B8=EB=B3=84=20?= =?UTF-8?q?=EC=84=B1=EA=B3=BC=EB=B6=84=EC=84=9D=20=EB=82=A0=EC=A7=9C=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - EventCreatedEvent, EventStats에 startDate, endDate 필드 추가 - EventCreatedConsumer에서 이벤트 시작/종료 날짜 저장 - SampleDataLoader에서 실제 날짜로 이벤트 발행 - evt_2025012301: 2025-01-23 시작 (ACTIVE) - evt_2025020101: 2025-02-01 시작 (ACTIVE) - evt_2025011501: 2025-01-15~2025-01-31 (COMPLETED) - AnalyticsService: 이벤트 시작일~종료일(또는 현재) 기간 계산 - UserAnalyticsService: 가장 빠른 이벤트 시작일~현재 기간 계산 - application.yml에서 중복된 context-path 제거 - Consumer Group ID를 analytics-service-consumers-v3로 통일 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- analytics-service/.run/analytics-service.run.xml | 2 +- .../analytics/config/KafkaConsumerConfig.java | 2 +- .../event/analytics/config/SampleDataLoader.java | 14 +++++++++++--- .../com/kt/event/analytics/entity/EventStats.java | 12 ++++++++++++ .../messaging/consumer/EventCreatedConsumer.java | 6 ++++-- .../messaging/event/EventCreatedEvent.java | 11 +++++++++++ .../event/analytics/service/AnalyticsService.java | 7 ++++--- .../analytics/service/UserAnalyticsService.java | 13 +++++-------- .../src/main/resources/application.yml | 1 - 9 files changed, 49 insertions(+), 19 deletions(-) diff --git a/analytics-service/.run/analytics-service.run.xml b/analytics-service/.run/analytics-service.run.xml index de874e9..931ba8c 100644 --- a/analytics-service/.run/analytics-service.run.xml +++ b/analytics-service/.run/analytics-service.run.xml @@ -24,7 +24,7 @@ - + diff --git a/analytics-service/src/main/java/com/kt/event/analytics/config/KafkaConsumerConfig.java b/analytics-service/src/main/java/com/kt/event/analytics/config/KafkaConsumerConfig.java index e3c413b..1d71d31 100644 --- a/analytics-service/src/main/java/com/kt/event/analytics/config/KafkaConsumerConfig.java +++ b/analytics-service/src/main/java/com/kt/event/analytics/config/KafkaConsumerConfig.java @@ -23,7 +23,7 @@ public class KafkaConsumerConfig { @Value("${spring.kafka.bootstrap-servers}") private String bootstrapServers; - @Value("${spring.kafka.consumer.group-id:analytics-service}") + @Value("${spring.kafka.consumer.group-id:analytics-service-consumers-v3}") private String groupId; @Bean diff --git a/analytics-service/src/main/java/com/kt/event/analytics/config/SampleDataLoader.java b/analytics-service/src/main/java/com/kt/event/analytics/config/SampleDataLoader.java index 092c1d7..36c1cea 100644 --- a/analytics-service/src/main/java/com/kt/event/analytics/config/SampleDataLoader.java +++ b/analytics-service/src/main/java/com/kt/event/analytics/config/SampleDataLoader.java @@ -19,6 +19,7 @@ import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.beans.factory.annotation.Value; import org.springframework.kafka.core.KafkaAdmin; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.stereotype.Component; @@ -60,7 +61,8 @@ public class SampleDataLoader implements ApplicationRunner { private final Random random = new Random(); - private static final String CONSUMER_GROUP_ID = "analytics-service-consumers-v3"; + @Value("${spring.kafka.consumer.group-id}") + private String consumerGroupId; // Kafka Topic Names (MVP용 샘플 토픽) private static final String EVENT_CREATED_TOPIC = "sample.event.created"; @@ -181,7 +183,7 @@ public class SampleDataLoader implements ApplicationRunner { */ private void resetConsumerOffsets() { try (AdminClient adminClient = AdminClient.create(kafkaAdmin.getConfigurationProperties())) { - log.info("🔄 Kafka Consumer Offset 리셋 시작: group={}", CONSUMER_GROUP_ID); + log.info("🔄 Kafka Consumer Offset 리셋 시작: group={}", consumerGroupId); // 모든 토픽의 offset 삭제 Set partitions = new HashSet<>(); @@ -195,7 +197,7 @@ public class SampleDataLoader implements ApplicationRunner { // Consumer Group Offset 삭제 DeleteConsumerGroupOffsetsResult result = adminClient.deleteConsumerGroupOffsets( - CONSUMER_GROUP_ID, + consumerGroupId, partitions ); @@ -224,6 +226,8 @@ public class SampleDataLoader implements ApplicationRunner { .totalInvestment(new BigDecimal("5000000")) .expectedRevenue(new BigDecimal("15000000")) // 투자 대비 3배 수익 .status("ACTIVE") + .startDate(java.time.LocalDateTime.of(2025, 1, 23, 0, 0)) // 2025-01-23 시작 + .endDate(null) // 진행중 .build(); publishEvent(EVENT_CREATED_TOPIC, event1); @@ -235,6 +239,8 @@ public class SampleDataLoader implements ApplicationRunner { .totalInvestment(new BigDecimal("3500000")) .expectedRevenue(new BigDecimal("7000000")) // 투자 대비 2배 수익 .status("ACTIVE") + .startDate(java.time.LocalDateTime.of(2025, 2, 1, 0, 0)) // 2025-02-01 시작 + .endDate(null) // 진행중 .build(); publishEvent(EVENT_CREATED_TOPIC, event2); @@ -246,6 +252,8 @@ public class SampleDataLoader implements ApplicationRunner { .totalInvestment(new BigDecimal("2000000")) .expectedRevenue(new BigDecimal("3000000")) // 투자 대비 1.5배 수익 .status("COMPLETED") + .startDate(java.time.LocalDateTime.of(2025, 1, 15, 0, 0)) // 2025-01-15 시작 + .endDate(java.time.LocalDateTime.of(2025, 1, 31, 23, 59)) // 2025-01-31 종료 .build(); publishEvent(EVENT_CREATED_TOPIC, event3); diff --git a/analytics-service/src/main/java/com/kt/event/analytics/entity/EventStats.java b/analytics-service/src/main/java/com/kt/event/analytics/entity/EventStats.java index e3b4464..f19a282 100644 --- a/analytics-service/src/main/java/com/kt/event/analytics/entity/EventStats.java +++ b/analytics-service/src/main/java/com/kt/event/analytics/entity/EventStats.java @@ -97,6 +97,18 @@ public class EventStats extends BaseTimeEntity { @Column(length = 20) private String status; + /** + * 이벤트 시작일 + */ + @Column(name = "start_date") + private java.time.LocalDateTime startDate; + + /** + * 이벤트 종료일 (null이면 진행중) + */ + @Column(name = "end_date") + private java.time.LocalDateTime endDate; + /** * 참여자 수 증가 */ diff --git a/analytics-service/src/main/java/com/kt/event/analytics/messaging/consumer/EventCreatedConsumer.java b/analytics-service/src/main/java/com/kt/event/analytics/messaging/consumer/EventCreatedConsumer.java index 3f86256..ef3c530 100644 --- a/analytics-service/src/main/java/com/kt/event/analytics/messaging/consumer/EventCreatedConsumer.java +++ b/analytics-service/src/main/java/com/kt/event/analytics/messaging/consumer/EventCreatedConsumer.java @@ -64,11 +64,13 @@ public class EventCreatedConsumer { .totalInvestment(event.getTotalInvestment()) .expectedRevenue(event.getExpectedRevenue() != null ? event.getExpectedRevenue() : BigDecimal.ZERO) .status(event.getStatus()) + .startDate(event.getStartDate()) + .endDate(event.getEndDate()) .build(); eventStatsRepository.save(eventStats); - log.info("✅ 이벤트 통계 초기화 완료: eventId={}, userId={}, expectedRevenue={}", - eventId, eventStats.getUserId(), event.getExpectedRevenue()); + log.info("✅ 이벤트 통계 초기화 완료: eventId={}, userId={}, startDate={}, endDate={}", + eventId, eventStats.getUserId(), event.getStartDate(), event.getEndDate()); // 3. 캐시 무효화 (다음 조회 시 최신 데이터 반영) String cacheKey = CACHE_KEY_PREFIX + eventId; diff --git a/analytics-service/src/main/java/com/kt/event/analytics/messaging/event/EventCreatedEvent.java b/analytics-service/src/main/java/com/kt/event/analytics/messaging/event/EventCreatedEvent.java index a044a28..771f9a0 100644 --- a/analytics-service/src/main/java/com/kt/event/analytics/messaging/event/EventCreatedEvent.java +++ b/analytics-service/src/main/java/com/kt/event/analytics/messaging/event/EventCreatedEvent.java @@ -6,6 +6,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import java.math.BigDecimal; +import java.time.LocalDateTime; /** * 이벤트 생성 이벤트 @@ -45,4 +46,14 @@ public class EventCreatedEvent { * 이벤트 상태 */ private String status; + + /** + * 이벤트 시작일 + */ + private LocalDateTime startDate; + + /** + * 이벤트 종료일 (null이면 진행중) + */ + private LocalDateTime endDate; } diff --git a/analytics-service/src/main/java/com/kt/event/analytics/service/AnalyticsService.java b/analytics-service/src/main/java/com/kt/event/analytics/service/AnalyticsService.java index 2830a94..8d781df 100644 --- a/analytics-service/src/main/java/com/kt/event/analytics/service/AnalyticsService.java +++ b/analytics-service/src/main/java/com/kt/event/analytics/service/AnalyticsService.java @@ -146,11 +146,12 @@ public class AnalyticsService { } /** - * 기간 정보 구성 (이벤트 생성일 ~ 현재) + * 기간 정보 구성 (이벤트 시작일 ~ 종료일 또는 현재) */ private PeriodInfo buildPeriodInfo(EventStats eventStats) { - LocalDateTime start = eventStats.getCreatedAt(); - LocalDateTime end = LocalDateTime.now(); + LocalDateTime start = eventStats.getStartDate(); + LocalDateTime end = eventStats.getEndDate() != null ? + eventStats.getEndDate() : LocalDateTime.now(); long durationDays = ChronoUnit.DAYS.between(start, end); diff --git a/analytics-service/src/main/java/com/kt/event/analytics/service/UserAnalyticsService.java b/analytics-service/src/main/java/com/kt/event/analytics/service/UserAnalyticsService.java index 5b8ed29..fc0cc35 100644 --- a/analytics-service/src/main/java/com/kt/event/analytics/service/UserAnalyticsService.java +++ b/analytics-service/src/main/java/com/kt/event/analytics/service/UserAnalyticsService.java @@ -301,20 +301,17 @@ public class UserAnalyticsService { /** * 기간 정보 구성 - */ - /** - * 전체 이벤트의 생성/수정 시간 기반으로 period 계산 + * + * 전체 이벤트 중 가장 빠른 시작일 ~ 현재까지의 기간 계산 */ private PeriodInfo buildPeriodFromEvents(List events) { LocalDateTime start = events.stream() - .map(EventStats::getCreatedAt) + .map(EventStats::getStartDate) + .filter(Objects::nonNull) .min(LocalDateTime::compareTo) .orElse(LocalDateTime.now()); - LocalDateTime end = events.stream() - .map(EventStats::getUpdatedAt) - .max(LocalDateTime::compareTo) - .orElse(LocalDateTime.now()); + LocalDateTime end = LocalDateTime.now(); return PeriodInfo.builder() .startDate(start) diff --git a/analytics-service/src/main/resources/application.yml b/analytics-service/src/main/resources/application.yml index e15aaf6..0aa7c70 100644 --- a/analytics-service/src/main/resources/application.yml +++ b/analytics-service/src/main/resources/application.yml @@ -80,7 +80,6 @@ server: charset: UTF-8 enabled: true force: true - context-path: /api/v1/analytics # JWT jwt: