mirror of
https://github.com/ktds-dg0501/kt-event-marketing.git
synced 2025-12-06 11:26:26 +00:00
이벤트별 성과분석 날짜 로직 수정 및 설정 개선
- 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 <noreply@anthropic.com>
This commit is contained in:
parent
108ee10293
commit
f80418f5ee
@ -24,7 +24,7 @@
|
||||
<!-- Kafka Configuration (원격 서버) -->
|
||||
<entry key="KAFKA_ENABLED" value="true" />
|
||||
<entry key="KAFKA_BOOTSTRAP_SERVERS" value="20.249.182.13:9095,4.217.131.59:9095" />
|
||||
<entry key="KAFKA_CONSUMER_GROUP_ID" value="analytics-service-consumers" />
|
||||
<entry key="KAFKA_CONSUMER_GROUP_ID" value="analytics-service-consumers-v3" />
|
||||
|
||||
<!-- Sample Data Configuration (MVP Only) -->
|
||||
<!-- ⚠️ Kafka Producer로 이벤트 발행 (Consumer가 처리) -->
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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<TopicPartition> 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);
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
/**
|
||||
* 참여자 수 증가
|
||||
*/
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -301,20 +301,17 @@ public class UserAnalyticsService {
|
||||
|
||||
/**
|
||||
* 기간 정보 구성
|
||||
*/
|
||||
/**
|
||||
* 전체 이벤트의 생성/수정 시간 기반으로 period 계산
|
||||
*
|
||||
* 전체 이벤트 중 가장 빠른 시작일 ~ 현재까지의 기간 계산
|
||||
*/
|
||||
private PeriodInfo buildPeriodFromEvents(List<EventStats> 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)
|
||||
|
||||
@ -80,7 +80,6 @@ server:
|
||||
charset: UTF-8
|
||||
enabled: true
|
||||
force: true
|
||||
context-path: /api/v1/analytics
|
||||
|
||||
# JWT
|
||||
jwt:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user