mirror of
https://github.com/ktds-dg0501/kt-event-marketing.git
synced 2025-12-06 16:06:24 +00:00
- 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>
562 lines
13 KiB
Markdown
562 lines
13 KiB
Markdown
# 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% 할인 이벤트
|
|
```json
|
|
{
|
|
"eventId": "evt_2025012301",
|
|
"eventTitle": "신년맞이 20% 할인 이벤트",
|
|
"storeId": "store_001",
|
|
"totalParticipants": 15420,
|
|
"estimatedRoi": 280.5,
|
|
"totalInvestment": 5000000
|
|
}
|
|
```
|
|
**특징**: 높은 성과, 진행 중 이벤트
|
|
|
|
#### 이벤트 2: 설날 특가 선물세트 이벤트
|
|
```json
|
|
{
|
|
"eventId": "evt_2025020101",
|
|
"eventTitle": "설날 특가 선물세트 이벤트",
|
|
"storeId": "store_001",
|
|
"totalParticipants": 8950,
|
|
"estimatedRoi": 185.3,
|
|
"totalInvestment": 3500000
|
|
}
|
|
```
|
|
**특징**: 중간 성과, 진행 중 이벤트
|
|
|
|
#### 이벤트 3: 겨울 신메뉴 런칭 이벤트
|
|
```json
|
|
{
|
|
"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%
|
|
|
|
#### 샘플 채널 데이터 예시
|
|
```json
|
|
{
|
|
"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. **누적 카운트**: 시간이 지남에 따라 누적 참여자 증가
|
|
|
|
#### 샘플 타임라인 데이터 예시
|
|
```json
|
|
{
|
|
"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 성과 대시보드 조회
|
|
|
|
#### 요청
|
|
```bash
|
|
GET http://localhost:8086/api/events/evt_2025012301/analytics
|
|
Authorization: Bearer {JWT_TOKEN}
|
|
```
|
|
|
|
#### 예상 응답
|
|
```json
|
|
{
|
|
"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 채널별 성과 분석
|
|
|
|
#### 요청
|
|
```bash
|
|
GET http://localhost:8086/api/events/evt_2025012301/analytics/channels?sortBy=roi
|
|
Authorization: Bearer {JWT_TOKEN}
|
|
```
|
|
|
|
#### 예상 응답
|
|
```json
|
|
{
|
|
"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 시간대별 참여 추이
|
|
|
|
#### 요청
|
|
```bash
|
|
GET http://localhost:8086/api/events/evt_2025012301/analytics/timeline?interval=daily
|
|
Authorization: Bearer {JWT_TOKEN}
|
|
```
|
|
|
|
#### 예상 응답
|
|
```json
|
|
{
|
|
"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 상세 분석
|
|
|
|
#### 요청
|
|
```bash
|
|
GET http://localhost:8086/api/events/evt_2025012301/analytics/roi?includeProjection=true
|
|
Authorization: Bearer {JWT_TOKEN}
|
|
```
|
|
|
|
#### 예상 응답
|
|
```json
|
|
{
|
|
"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. **데이터베이스 초기화**:
|
|
```sql
|
|
TRUNCATE TABLE timeline_data;
|
|
TRUNCATE TABLE channel_stats;
|
|
TRUNCATE TABLE event_stats;
|
|
```
|
|
|
|
2. **애플리케이션 재시작**:
|
|
```bash
|
|
# 서비스 중지
|
|
# 서비스 시작
|
|
```
|
|
|
|
3. **자동 재적재**: 애플리케이션 시작 시 자동으로 샘플 데이터 재생성
|
|
|
|
### 5.2 프로파일별 동작
|
|
|
|
#### dev/local 프로파일
|
|
```yaml
|
|
spring:
|
|
profiles:
|
|
active: dev # 또는 local
|
|
```
|
|
→ 샘플 데이터 **자동 적재**
|
|
|
|
#### prod 프로파일
|
|
```yaml
|
|
spring:
|
|
profiles:
|
|
active: prod
|
|
```
|
|
→ 샘플 데이터 **적재 안 함**
|
|
|
|
---
|
|
|
|
## 6. 커스터마이징 가이드
|
|
|
|
### 6.1 이벤트 추가
|
|
|
|
`SampleDataLoader.java`의 `createEventStats()` 메서드에 이벤트 추가:
|
|
|
|
```java
|
|
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()` 메서드에 채널 추가:
|
|
|
|
```java
|
|
// 5. 모바일 앱 추가
|
|
channelStatsList.add(createChannelStats(
|
|
eventId,
|
|
"모바일앱",
|
|
(int) (totalParticipants * 0.25), // 참여자: 25%
|
|
distributionBudget.multiply(new BigDecimal("0.15")), // 비용: 15%
|
|
2.8 // 조회수 대비 참여자 비율
|
|
));
|
|
```
|
|
|
|
### 6.3 타임라인 간격 변경
|
|
|
|
현재: 4시간 단위 (하루 6개)
|
|
```java
|
|
for (int hour = 0; hour < 24; hour += 4) {
|
|
```
|
|
|
|
변경: 1시간 단위 (하루 24개)
|
|
```java
|
|
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로 설정됨
|
|
```yaml
|
|
spring:
|
|
profiles:
|
|
active: prod # ❌ 샘플 데이터 적재 안 함
|
|
```
|
|
|
|
**해결**: dev 또는 local로 변경
|
|
```yaml
|
|
spring:
|
|
profiles:
|
|
active: dev # ✅ 샘플 데이터 적재
|
|
```
|
|
|
|
**원인 2**: 기존 데이터가 이미 존재
|
|
- 확인: `SELECT COUNT(*) FROM event_stats;`
|
|
- 해결: 데이터 초기화 후 재시작
|
|
|
|
### 8.2 컴파일 오류
|
|
|
|
**원인**: Entity 필드명 불일치
|
|
- `TimelineData` 엔티티의 실제 필드명 확인 필요
|
|
- `participantCount` → `participants`
|
|
- `cumulativeCount` → `cumulativeParticipants`
|
|
|
|
---
|
|
|
|
## 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
|