diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 8d1f14d..c49d02b 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -15,7 +15,11 @@ "Bash(git add:*)", "Bash(git commit:*)", "Bash(git push)", - "Bash(git pull:*)" + "Bash(git pull:*)", + "Bash(netstat:*)", + "Bash(findstr:*)", + "Bash(./gradlew analytics-service:compileJava:*)", + "Bash(python -m json.tool:*)" ], "deny": [], "ask": [] diff --git a/.gradle/8.10/checksums/checksums.lock b/.gradle/8.10/checksums/checksums.lock index 837e5b9..9546116 100644 Binary files a/.gradle/8.10/checksums/checksums.lock and b/.gradle/8.10/checksums/checksums.lock differ diff --git a/.gradle/8.10/checksums/md5-checksums.bin b/.gradle/8.10/checksums/md5-checksums.bin index 04c6d00..46554f5 100644 Binary files a/.gradle/8.10/checksums/md5-checksums.bin and b/.gradle/8.10/checksums/md5-checksums.bin differ diff --git a/.gradle/8.10/checksums/sha1-checksums.bin b/.gradle/8.10/checksums/sha1-checksums.bin index 19a5410..8fd88dc 100644 Binary files a/.gradle/8.10/checksums/sha1-checksums.bin and b/.gradle/8.10/checksums/sha1-checksums.bin differ diff --git a/.gradle/8.10/executionHistory/executionHistory.bin b/.gradle/8.10/executionHistory/executionHistory.bin index 2177cdd..cf52da0 100644 Binary files a/.gradle/8.10/executionHistory/executionHistory.bin and b/.gradle/8.10/executionHistory/executionHistory.bin differ diff --git a/.gradle/8.10/executionHistory/executionHistory.lock b/.gradle/8.10/executionHistory/executionHistory.lock index 0ce4c96..9fc5cce 100644 Binary files a/.gradle/8.10/executionHistory/executionHistory.lock and b/.gradle/8.10/executionHistory/executionHistory.lock differ diff --git a/.gradle/8.10/fileHashes/fileHashes.bin b/.gradle/8.10/fileHashes/fileHashes.bin index 8088fbb..300d2d1 100644 Binary files a/.gradle/8.10/fileHashes/fileHashes.bin and b/.gradle/8.10/fileHashes/fileHashes.bin differ diff --git a/.gradle/8.10/fileHashes/fileHashes.lock b/.gradle/8.10/fileHashes/fileHashes.lock index 340e0dd..44aad75 100644 Binary files a/.gradle/8.10/fileHashes/fileHashes.lock and b/.gradle/8.10/fileHashes/fileHashes.lock differ diff --git a/.gradle/8.10/fileHashes/resourceHashesCache.bin b/.gradle/8.10/fileHashes/resourceHashesCache.bin index 3d21896..7fcad2b 100644 Binary files a/.gradle/8.10/fileHashes/resourceHashesCache.bin and b/.gradle/8.10/fileHashes/resourceHashesCache.bin differ diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index 0350ff2..5885331 100644 Binary files a/.gradle/buildOutputCleanup/buildOutputCleanup.lock and b/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ diff --git a/.gradle/buildOutputCleanup/outputFiles.bin b/.gradle/buildOutputCleanup/outputFiles.bin index 4ed6f06..40052b6 100644 Binary files a/.gradle/buildOutputCleanup/outputFiles.bin and b/.gradle/buildOutputCleanup/outputFiles.bin differ diff --git a/.gradle/file-system.probe b/.gradle/file-system.probe index ac4beb4..6b17014 100644 Binary files a/.gradle/file-system.probe and b/.gradle/file-system.probe differ diff --git a/analytics-service/src/main/java/com/kt/event/analytics/config/KafkaTopicConfig.java b/analytics-service/src/main/java/com/kt/event/analytics/config/KafkaTopicConfig.java new file mode 100644 index 0000000..3c77521 --- /dev/null +++ b/analytics-service/src/main/java/com/kt/event/analytics/config/KafkaTopicConfig.java @@ -0,0 +1,53 @@ +package com.kt.event.analytics.config; + +import org.apache.kafka.clients.admin.NewTopic; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.config.TopicBuilder; + +/** + * Kafka 토픽 자동 생성 설정 + * + * ⚠️ MVP 전용: 샘플 데이터용 토픽을 생성합니다. + * 실제 운영 토픽(event.created 등)과 구분하기 위해 "sample." 접두사 사용 + * + * 서비스 시작 시 필요한 Kafka 토픽을 자동으로 생성합니다. + */ +@Configuration +@ConditionalOnProperty(name = "spring.kafka.enabled", havingValue = "true", matchIfMissing = false) +public class KafkaTopicConfig { + + /** + * sample.event.created 토픽 (MVP 샘플 데이터용) + */ + @Bean + public NewTopic eventCreatedTopic() { + return TopicBuilder.name("sample.event.created") + .partitions(3) + .replicas(1) + .build(); + } + + /** + * sample.participant.registered 토픽 (MVP 샘플 데이터용) + */ + @Bean + public NewTopic participantRegisteredTopic() { + return TopicBuilder.name("sample.participant.registered") + .partitions(3) + .replicas(1) + .build(); + } + + /** + * sample.distribution.completed 토픽 (MVP 샘플 데이터용) + */ + @Bean + public NewTopic distributionCompletedTopic() { + return TopicBuilder.name("sample.distribution.completed") + .partitions(3) + .replicas(1) + .build(); + } +} 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 f3c6571..7461258 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 @@ -52,10 +52,10 @@ public class SampleDataLoader implements ApplicationRunner { private final Random random = new Random(); - // Kafka Topic Names - private static final String EVENT_CREATED_TOPIC = "event.created"; - private static final String PARTICIPANT_REGISTERED_TOPIC = "participant.registered"; - private static final String DISTRIBUTION_COMPLETED_TOPIC = "distribution.completed"; + // Kafka Topic Names (MVP용 샘플 토픽) + private static final String EVENT_CREATED_TOPIC = "sample.event.created"; + private static final String PARTICIPANT_REGISTERED_TOPIC = "sample.participant.registered"; + private static final String DISTRIBUTION_COMPLETED_TOPIC = "sample.distribution.completed"; @Override @Transactional diff --git a/analytics-service/src/main/java/com/kt/event/analytics/messaging/consumer/DistributionCompletedConsumer.java b/analytics-service/src/main/java/com/kt/event/analytics/messaging/consumer/DistributionCompletedConsumer.java index eef502a..47770e8 100644 --- a/analytics-service/src/main/java/com/kt/event/analytics/messaging/consumer/DistributionCompletedConsumer.java +++ b/analytics-service/src/main/java/com/kt/event/analytics/messaging/consumer/DistributionCompletedConsumer.java @@ -33,9 +33,9 @@ public class DistributionCompletedConsumer { private static final long IDEMPOTENCY_TTL_DAYS = 7; /** - * DistributionCompleted 이벤트 처리 + * DistributionCompleted 이벤트 처리 (MVP용 샘플 토픽) */ - @KafkaListener(topics = "distribution.completed", groupId = "analytics-service") + @KafkaListener(topics = "sample.distribution.completed", groupId = "analytics-service") public void handleDistributionCompleted(String message) { try { log.info("📩 DistributionCompleted 이벤트 수신: {}", message); 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 c548c44..480125a 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 @@ -33,9 +33,9 @@ public class EventCreatedConsumer { private static final long IDEMPOTENCY_TTL_DAYS = 7; /** - * EventCreated 이벤트 처리 + * EventCreated 이벤트 처리 (MVP용 샘플 토픽) */ - @KafkaListener(topics = "event.created", groupId = "analytics-service") + @KafkaListener(topics = "sample.event.created", groupId = "analytics-service") public void handleEventCreated(String message) { try { log.info("📩 EventCreated 이벤트 수신: {}", message); diff --git a/analytics-service/src/main/java/com/kt/event/analytics/messaging/consumer/ParticipantRegisteredConsumer.java b/analytics-service/src/main/java/com/kt/event/analytics/messaging/consumer/ParticipantRegisteredConsumer.java index 7914b0f..6df8e6e 100644 --- a/analytics-service/src/main/java/com/kt/event/analytics/messaging/consumer/ParticipantRegisteredConsumer.java +++ b/analytics-service/src/main/java/com/kt/event/analytics/messaging/consumer/ParticipantRegisteredConsumer.java @@ -33,9 +33,9 @@ public class ParticipantRegisteredConsumer { private static final long IDEMPOTENCY_TTL_DAYS = 7; /** - * ParticipantRegistered 이벤트 처리 + * ParticipantRegistered 이벤트 처리 (MVP용 샘플 토픽) */ - @KafkaListener(topics = "participant.registered", groupId = "analytics-service") + @KafkaListener(topics = "sample.participant.registered", groupId = "analytics-service") public void handleParticipantRegistered(String message) { try { log.info("📩 ParticipantRegistered 이벤트 수신: {}", message); diff --git a/analytics-service/src/main/resources/application.yml b/analytics-service/src/main/resources/application.yml index f88bca1..cb011cf 100644 --- a/analytics-service/src/main/resources/application.yml +++ b/analytics-service/src/main/resources/application.yml @@ -51,6 +51,11 @@ spring: enable-auto-commit: true key-deserializer: org.apache.kafka.common.serialization.StringDeserializer value-deserializer: org.apache.kafka.common.serialization.StringDeserializer + producer: + key-serializer: org.apache.kafka.common.serialization.StringSerializer + value-serializer: org.apache.kafka.common.serialization.StringSerializer + acks: all + retries: 3 properties: connections.max.idle.ms: 10000 request.timeout.ms: 5000 diff --git a/tools/check-kafka-messages.ps1 b/tools/check-kafka-messages.ps1 new file mode 100644 index 0000000..2a9129b --- /dev/null +++ b/tools/check-kafka-messages.ps1 @@ -0,0 +1,63 @@ +# Kafka 메시지 확인 스크립트 (Windows PowerShell) +# +# 사용법: .\check-kafka-messages.ps1 + +$KAFKA_SERVER = "4.230.50.63:9092" + +Write-Host "========================================" -ForegroundColor Cyan +Write-Host "📊 Kafka 토픽 메시지 확인" -ForegroundColor Cyan +Write-Host "========================================" -ForegroundColor Cyan +Write-Host "" + +# Kafka 설치 확인 +$kafkaPath = Read-Host "Kafka 설치 경로를 입력하세요 (예: C:\kafka)" + +if (-not (Test-Path "$kafkaPath\bin\windows\kafka-console-consumer.bat")) { + Write-Host "❌ Kafka가 해당 경로에 설치되어 있지 않습니다." -ForegroundColor Red + exit 1 +} + +Write-Host "✅ Kafka 경로 확인: $kafkaPath" -ForegroundColor Green +Write-Host "" + +# 토픽 선택 +Write-Host "확인할 토픽을 선택하세요:" -ForegroundColor Yellow +Write-Host " 1. event.created (이벤트 생성)" +Write-Host " 2. participant.registered (참여자 등록)" +Write-Host " 3. distribution.completed (배포 완료)" +Write-Host " 4. 모두 확인" +Write-Host "" + +$choice = Read-Host "선택 (1-4)" + +$topics = @() +switch ($choice) { + "1" { $topics = @("event.created") } + "2" { $topics = @("participant.registered") } + "3" { $topics = @("distribution.completed") } + "4" { $topics = @("event.created", "participant.registered", "distribution.completed") } + default { + Write-Host "❌ 잘못된 선택입니다." -ForegroundColor Red + exit 1 + } +} + +# 각 토픽별 메시지 확인 +foreach ($topic in $topics) { + Write-Host "" + Write-Host "========================================" -ForegroundColor Cyan + Write-Host "📩 토픽: $topic" -ForegroundColor Cyan + Write-Host "========================================" -ForegroundColor Cyan + + # 최근 5개 메시지만 확인 + & "$kafkaPath\bin\windows\kafka-console-consumer.bat" ` + --bootstrap-server $KAFKA_SERVER ` + --topic $topic ` + --from-beginning ` + --max-messages 5 ` + --timeout-ms 5000 2>&1 | Out-String | Write-Host + + Write-Host "" +} + +Write-Host "✅ 확인 완료!" -ForegroundColor Green