kt-event-marketing/develop/dev/sample-data-analytics.md
doyeon b198c46d06 Analytics 서비스 및 보안 기능 업데이트
- Analytics 서비스 구현 추가 (API, 소스 코드)
- Event 서비스 소스 코드 추가
- 보안 관련 공통 컴포넌트 업데이트 (JWT, UserPrincipal, ErrorCode)
- API 컨벤션 및 명세서 업데이트
- 데이터베이스 SQL 스크립트 추가
- 백엔드 개발 문서 및 테스트 가이드 추가
- Kafka 메시지 체크 도구 추가

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-27 16:11:00 +09:00

13 KiB

Analytics 서비스 샘플 데이터 가이드

1. 개요

Analytics 서비스는 애플리케이션 시작 시 대시보드 테스트를 위한 샘플 데이터를 자동으로 적재합니다.

1.1 적용 환경

  • 개발 환경 (dev): 자동 적재
  • 로컬 환경 (local): 자동 적재
  • 운영 환경 (prod): 적재 안 함

1.2 구현 클래스

  • 파일: SampleDataLoader.java
  • 위치: analytics-service/src/main/java/com/kt/event/analytics/config/
  • 실행 시점: 애플리케이션 시작 시 자동 실행 (ApplicationRunner)

2. 샘플 데이터 구성

2.1 이벤트 통계 데이터 (EventStats)

3개 이벤트가 생성됩니다:

이벤트 1: 신년맞이 20% 할인 이벤트

{
  "eventId": "evt_2025012301",
  "eventTitle": "신년맞이 20% 할인 이벤트",
  "storeId": "store_001",
  "totalParticipants": 15420,
  "estimatedRoi": 280.5,
  "totalInvestment": 5000000
}

특징: 높은 성과, 진행 중 이벤트

이벤트 2: 설날 특가 선물세트 이벤트

{
  "eventId": "evt_2025020101",
  "eventTitle": "설날 특가 선물세트 이벤트",
  "storeId": "store_001",
  "totalParticipants": 8950,
  "estimatedRoi": 185.3,
  "totalInvestment": 3500000
}

특징: 중간 성과, 진행 중 이벤트

이벤트 3: 겨울 신메뉴 런칭 이벤트

{
  "eventId": "evt_2025011501",
  "eventTitle": "겨울 신메뉴 런칭 이벤트",
  "storeId": "store_001",
  "totalParticipants": 3240,
  "estimatedRoi": 95.5,
  "totalInvestment": 2000000
}

특징: 저조한 성과, 종료된 이벤트


2.2 채널별 통계 데이터 (ChannelStats)

각 이벤트당 4개 채널 데이터가 생성됩니다 (총 12건):

채널 구성

채널명 참여자 비율 비용 비율 특징
우리동네TV 35% 30% 조회수 많음, 참여율 중간
지니TV 30% 30% 조회수 중간, 참여율 높음
링고비즈 20% 20% 통화 기반, 높은 전환율
SNS 15% 20% 바이럴 효과, 높은 도달률

채널별 지표 생성 로직

1. 우리동네TV:

  • 조회수: 참여자의 8~12배
  • 클릭수: 조회수의 15~25%
  • 전환수: 참여자의 30~50%
  • SNS 반응: 낮음 (참여자의 30~50%)

2. 지니TV:

  • 조회수: 참여자의 8~12배
  • 클릭수: 조회수의 15~25%
  • 전환수: 참여자의 30~50%
  • SNS 반응: 낮음 (참여자의 30~50%)

3. 링고비즈:

  • 조회수: 참여자의 8~12배
  • 클릭수: 조회수의 15~25%
  • 전환수: 참여자의 30~50%
  • SNS 반응: 없음 (통화 중심 채널)

4. SNS:

  • 조회수: 참여자의 8~12배
  • 클릭수: 조회수의 15~25%
  • 전환수: 참여자의 30~50%
  • SNS 반응 (특화):
    • 좋아요: 참여자의 2~3배
    • 댓글: 참여자의 50~80%
    • 공유: 참여자의 80~120%

샘플 채널 데이터 예시

{
  "eventId": "evt_2025012301",
  "channelName": "우리동네TV",
  "views": 45000,
  "clicks": 8900,
  "participants": 5500,
  "conversions": 1850,
  "impressions": 98500,
  "likes": 1800,
  "comments": 350,
  "shares": 650,
  "distributionCost": 1500000
}

2.3 타임라인 데이터 (TimelineData)

각 이벤트당 180개 데이터 포인트 생성 (총 540건):

  • 기간: 최근 30일
  • 간격: 4시간 단위 (하루 6개 데이터 포인트)

시간대별 가중치

시간대 시간 범위 가중치 설명
새벽 00:00 ~ 05:59 1x 낮은 참여
아침 06:00 ~ 11:59 2x 높은 참여
점심~오후 12:00 ~ 17:59 3x 가장 높은 참여
저녁 18:00 ~ 23:59 2x 높은 참여

데이터 생성 로직

  1. 점진적 증가: 30일 동안 참여자 수가 점진적으로 증가
  2. 시간대 변동: 시간대별 가중치 적용 (점심~오후가 가장 활발)
  3. 랜덤 변동: ±20% 랜덤 변동으로 자연스러운 패턴 구현
  4. 누적 카운트: 시간이 지남에 따라 누적 참여자 증가

샘플 타임라인 데이터 예시

{
  "eventId": "evt_2025012301",
  "timestamp": "2025-01-23T14:00:00",
  "participants": 450,
  "views": 3500,
  "engagement": 280,
  "conversions": 45,
  "cumulativeParticipants": 5450
}

3. 데이터 적재 프로세스

3.1 실행 흐름

애플리케이션 시작
    ↓
Profile 확인 (dev/local만 실행)
    ↓
기존 데이터 확인
    ↓
데이터 없음 → 샘플 데이터 생성
데이터 있음 → 건너뛰기
    ↓
1. EventStats 생성 (3건)
    ↓
2. ChannelStats 생성 (12건)
    ↓
3. TimelineData 생성 (540건)
    ↓
데이터베이스 저장
    ↓
로그 출력 (테스트 가능한 이벤트 목록)

3.2 로그 출력 예시

========================================
샘플 데이터 적재 시작
========================================
이벤트 통계 데이터 적재 완료: 3 건
채널별 통계 데이터 적재 완료: 12 건
타임라인 데이터 적재 완료: 540 건
========================================
샘플 데이터 적재 완료!
========================================
테스트 가능한 이벤트:
  - 신년맞이 20% 할인 이벤트 (ID: evt_2025012301)
  - 설날 특가 선물세트 이벤트 (ID: evt_2025020101)
  - 겨울 신메뉴 런칭 이벤트 (ID: evt_2025011501)
========================================

4. API 테스트 방법

4.1 성과 대시보드 조회

요청

GET http://localhost:8086/api/events/evt_2025012301/analytics
Authorization: Bearer {JWT_TOKEN}

예상 응답

{
  "success": true,
  "data": {
    "eventId": "evt_2025012301",
    "eventTitle": "신년맞이 20% 할인 이벤트",
    "period": {
      "startDate": "2025-01-01T00:00:00",
      "endDate": "2025-01-31T23:59:59",
      "durationDays": 30
    },
    "summary": {
      "totalParticipants": 15420,
      "totalViews": 125300,
      "totalReach": 98500,
      "engagementRate": 12.3,
      "conversionRate": 3.8,
      "averageEngagementTime": 145,
      "socialInteractions": {
        "likes": 3450,
        "comments": 890,
        "shares": 1250
      }
    },
    "channelPerformance": [
      {
        "channelName": "우리동네TV",
        "views": 45000,
        "participants": 5500,
        "engagementRate": 12.2,
        "conversionRate": 4.1,
        "roi": 280.5
      }
    ],
    "roi": {
      "totalInvestment": 5000000,
      "expectedRevenue": 19025000,
      "netProfit": 14025000,
      "roi": 280.5,
      "costPerAcquisition": 324.35
    },
    "lastUpdatedAt": "2025-01-24T10:30:00",
    "dataSource": "cached"
  }
}

4.2 채널별 성과 분석

요청

GET http://localhost:8086/api/events/evt_2025012301/analytics/channels?sortBy=roi
Authorization: Bearer {JWT_TOKEN}

예상 응답

{
  "success": true,
  "data": {
    "eventId": "evt_2025012301",
    "channels": [
      {
        "channelName": "우리동네TV",
        "views": 45000,
        "participants": 5500,
        "engagementRate": 12.2,
        "roi": 295.3
      },
      {
        "channelName": "지니TV",
        "views": 38000,
        "participants": 4600,
        "engagementRate": 13.5,
        "roi": 285.7
      }
    ],
    "topPerformers": {
      "byViews": "우리동네TV",
      "byEngagement": "지니TV",
      "byRoi": "링고비즈"
    },
    "comparison": {
      "averageMetrics": {
        "engagementRate": 11.5,
        "conversionRate": 3.9,
        "roi": 275.8
      }
    }
  }
}

4.3 시간대별 참여 추이

요청

GET http://localhost:8086/api/events/evt_2025012301/analytics/timeline?interval=daily
Authorization: Bearer {JWT_TOKEN}

예상 응답

{
  "success": true,
  "data": {
    "eventId": "evt_2025012301",
    "interval": "daily",
    "dataPoints": [
      {
        "timestamp": "2025-01-15T00:00:00",
        "participants": 450,
        "views": 3500,
        "engagement": 280,
        "conversions": 45,
        "cumulativeParticipants": 5450
      }
    ],
    "trends": {
      "overallTrend": "increasing",
      "growthRate": 15.3,
      "projectedParticipants": 18500
    },
    "peakTimes": [
      {
        "timestamp": "2025-01-15T14:00:00",
        "metric": "participants",
        "value": 1250,
        "description": "주말 오후 최대 참여"
      }
    ]
  }
}

4.4 ROI 상세 분석

요청

GET http://localhost:8086/api/events/evt_2025012301/analytics/roi?includeProjection=true
Authorization: Bearer {JWT_TOKEN}

예상 응답

{
  "success": true,
  "data": {
    "eventId": "evt_2025012301",
    "investment": {
      "contentCreation": 2000000,
      "distribution": 2500000,
      "operation": 500000,
      "total": 5000000
    },
    "revenue": {
      "directSales": 12500000,
      "expectedSales": 6525000,
      "brandValue": 3000000,
      "total": 19025000
    },
    "roi": {
      "netProfit": 14025000,
      "roiPercentage": 280.5,
      "breakEvenPoint": "2025-01-10T15:30:00",
      "paybackPeriod": 9
    },
    "costEfficiency": {
      "costPerParticipant": 324.35,
      "costPerConversion": 850.34,
      "costPerView": 39.90,
      "revenuePerParticipant": 1234.25
    },
    "projection": {
      "currentRevenue": 12500000,
      "projectedFinalRevenue": 21000000,
      "confidenceLevel": 85.5,
      "basedOn": "현재 추세 및 과거 유사 이벤트 데이터"
    }
  }
}

5. 데이터 초기화 방법

5.1 샘플 데이터 재생성

  1. 데이터베이스 초기화:

    TRUNCATE TABLE timeline_data;
    TRUNCATE TABLE channel_stats;
    TRUNCATE TABLE event_stats;
    
  2. 애플리케이션 재시작:

    # 서비스 중지
    # 서비스 시작
    
  3. 자동 재적재: 애플리케이션 시작 시 자동으로 샘플 데이터 재생성

5.2 프로파일별 동작

dev/local 프로파일

spring:
  profiles:
    active: dev  # 또는 local

→ 샘플 데이터 자동 적재

prod 프로파일

spring:
  profiles:
    active: prod

→ 샘플 데이터 적재 안 함


6. 커스터마이징 가이드

6.1 이벤트 추가

SampleDataLoader.javacreateEventStats() 메서드에 이벤트 추가:

eventStatsList.add(EventStats.builder()
    .eventId("evt_2025030101")
    .eventTitle("3월 신학기 이벤트")
    .storeId("store_001")
    .totalParticipants(12000)
    .estimatedRoi(new BigDecimal("220.0"))
    .totalInvestment(new BigDecimal("4000000"))
    .build());

6.2 채널 추가

createChannelStats() 메서드에 채널 추가:

// 5. 모바일 앱 추가
channelStatsList.add(createChannelStats(
    eventId,
    "모바일앱",
    (int) (totalParticipants * 0.25),  // 참여자: 25%
    distributionBudget.multiply(new BigDecimal("0.15")),  // 비용: 15%
    2.8  // 조회수 대비 참여자 비율
));

6.3 타임라인 간격 변경

현재: 4시간 단위 (하루 6개)

for (int hour = 0; hour < 24; hour += 4) {

변경: 1시간 단위 (하루 24개)

for (int hour = 0; hour < 24; hour += 1) {

7. 주의사항

7.1 데이터 중복 방지

  • SampleDataLoader는 기존 데이터가 있으면 적재를 건너뜁니다.
  • 확인 로직: eventStatsRepository.count() > 0

7.2 프로파일 설정 필수

  • 운영 환경에서는 반드시 prod 프로파일 사용
  • 샘플 데이터가 운영 DB에 적재되지 않도록 주의

7.3 성능 고려사항

  • 샘플 데이터: 총 555건 (EventStats 3 + ChannelStats 12 + TimelineData 540)
  • 적재 시간: 약 1~2초 (데이터베이스 성능에 따라 다름)

8. 트러블슈팅

8.1 샘플 데이터가 적재되지 않음

원인 1: 프로파일이 prod로 설정됨

spring:
  profiles:
    active: prod  # ❌ 샘플 데이터 적재 안 함

해결: dev 또는 local로 변경

spring:
  profiles:
    active: dev  # ✅ 샘플 데이터 적재

원인 2: 기존 데이터가 이미 존재

  • 확인: SELECT COUNT(*) FROM event_stats;
  • 해결: 데이터 초기화 후 재시작

8.2 컴파일 오류

원인: Entity 필드명 불일치

  • TimelineData 엔티티의 실제 필드명 확인 필요
  • participantCountparticipants
  • cumulativeCountcumulativeParticipants

9. 결론

9.1 구현 완료 사항

  • 3개 이벤트 샘플 데이터 자동 생성
  • 12개 채널별 통계 데이터 생성
  • 540개 타임라인 데이터 생성 (30일, 4시간 단위)
  • 시간대별 가중치 적용
  • SNS 반응 데이터 생성
  • 프로파일별 자동 적재 제어 (dev/local만)

9.2 테스트 가능한 시나리오

  1. 높은 성과 이벤트: evt_2025012301
  2. 중간 성과 이벤트: evt_2025020101
  3. 저조한 성과 이벤트: evt_2025011501

9.3 다음 단계

  1. 서비스 시작 후 로그 확인
  2. 대시보드 API 호출 테스트
  3. 각 채널별 성과 분석 테스트
  4. 시간대별 추이 분석 테스트
  5. ROI 계산 정확도 검증

작성자: AI Backend Developer 최종 수정일: 2025-01-24 버전: 1.0.0