Analytics Service 프론트엔드 연동을 위한 DTO 필드명 수정 및 증감 데이터 추가

- DTO 필드명 통일 (프론트엔드 호환)
  - totalParticipants → participants
  - channelName → channel
  - totalInvestment → totalCost

- 증감 데이터 필드 추가
  - participantsDelta: 참여자 증감 (현재 0, TODO)
  - targetRoi: 목표 ROI (EventStats에서 가져옴)

- EventStats 엔티티 스키마 변경
  - targetRoi 컬럼 추가 (BigDecimal, default: 0)

- Service 로직 수정
  - AnalyticsService: 필드명 변경 및 증감 데이터 적용
  - ROICalculator: totalCost 필드명 변경
  - UserAnalyticsService: 필드명 변경 및 증감 데이터 적용

- 검증 문서 추가
  - frontend-backend-validation.md: 수정 내용 및 다음 단계 정리

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Hyowon Yang 2025-10-28 15:59:49 +09:00
parent 02fd82e0af
commit 4421f4447f
8 changed files with 140 additions and 11 deletions

View File

@ -0,0 +1,108 @@
# 백엔드-프론트엔드 API 연동 검증 및 수정 결과
**작업일시**: 2025-10-28
**브랜치**: feature/analytics
**작업 범위**: Analytics Service 백엔드 DTO 및 Service 수정
---
## 📝 수정 요약
### 1⃣ 필드명 통일 (프론트엔드 호환)
**목적**: 프론트엔드 Mock 데이터 필드명과 백엔드 Response DTO 필드명 일치
| 수정 전 (백엔드) | 수정 후 (백엔드) | 프론트엔드 |
|-----------------|----------------|-----------|
| `summary.totalParticipants` | `summary.participants` | `summary.participants` ✅ |
| `channelPerformance[].channelName` | `channelPerformance[].channel` | `channelPerformance[].channel` ✅ |
| `roi.totalInvestment` | `roi.totalCost` | `roiDetail.totalCost` ✅ |
### 2⃣ 증감 데이터 추가
**목적**: 프론트엔드에서 요구하는 증감 표시 및 목표값 제공
| 필드 | 타입 | 설명 | 현재 값 |
|-----|------|------|---------|
| `summary.participantsDelta` | `Integer` | 참여자 증감 (이전 기간 대비) | `0` (TODO: 계산 로직 필요) |
| `summary.targetRoi` | `Double` | 목표 ROI (%) | EventStats에서 가져옴 |
---
## 🔧 수정 파일 목록
### DTO (Response 구조 변경)
1. **AnalyticsSummary.java**
- ✅ `totalParticipants``participants`
- ✅ `participantsDelta` 필드 추가
- ✅ `targetRoi` 필드 추가
2. **ChannelSummary.java**
- ✅ `channelName``channel`
3. **RoiSummary.java**
- ✅ `totalInvestment``totalCost`
### Entity (데이터베이스 스키마 변경)
4. **EventStats.java**
- ✅ `targetRoi` 필드 추가 (`BigDecimal`, default: 0)
### Service (비즈니스 로직 수정)
5. **AnalyticsService.java**
- ✅ `.participants()` 사용
- ✅ `.participantsDelta(0)` 추가 (TODO 마킹)
- ✅ `.targetRoi()` 추가
- ✅ `.channel()` 사용
6. **ROICalculator.java**
- ✅ `.totalCost()` 사용
7. **UserAnalyticsService.java**
- ✅ `.participants()` 사용
- ✅ `.participantsDelta(0)` 추가
- ✅ `.channel()` 사용
- ✅ `.totalCost()` 사용
---
## ✅ 검증 결과
### 컴파일 성공
\`\`\`bash
$ ./gradlew analytics-service:compileJava
BUILD SUCCESSFUL in 8s
\`\`\`
---
## 📊 데이터베이스 스키마 변경
### EventStats 테이블
\`\`\`sql
ALTER TABLE event_stats
ADD COLUMN target_roi DECIMAL(10,2) DEFAULT 0.00;
\`\`\`
**⚠️ 주의사항**
- Spring Boot JPA `ddl-auto` 설정에 따라 자동 적용됨
---
## 📌 다음 단계
### 우선순위 HIGH
1. **프론트엔드 API 연동 테스트**
2. **participantsDelta 계산 로직 구현**
3. **targetRoi 데이터 입력** (Event Service 연동)
### 우선순위 MEDIUM
4. 시간대별 분석 구현
5. 참여자 프로필 구현
6. ROI 세분화 구현

View File

@ -17,7 +17,12 @@ public class AnalyticsSummary {
/**
* 참여자
*/
private Integer totalParticipants;
private Integer participants;
/**
* 참여자 증감 (이전 기간 대비)
*/
private Integer participantsDelta;
/**
* 조회수
@ -44,6 +49,11 @@ public class AnalyticsSummary {
*/
private Integer averageEngagementTime;
/**
* 목표 ROI (%)
*/
private Double targetRoi;
/**
* SNS 반응 통계
*/

View File

@ -17,7 +17,7 @@ public class ChannelSummary {
/**
* 채널명
*/
private String channelName;
private String channel;
/**
* 조회수

View File

@ -19,7 +19,7 @@ public class RoiSummary {
/**
* 투자 비용 ()
*/
private BigDecimal totalInvestment;
private BigDecimal totalCost;
/**
* 예상 매출 증대 ()

View File

@ -63,6 +63,13 @@ public class EventStats extends BaseTimeEntity {
@Builder.Default
private BigDecimal estimatedRoi = BigDecimal.ZERO;
/**
* 목표 ROI (%)
*/
@Column(precision = 10, scale = 2)
@Builder.Default
private BigDecimal targetRoi = BigDecimal.ZERO;
/**
* 매출 증가율 (%)
*/

View File

@ -179,12 +179,14 @@ public class AnalyticsService {
.build();
return AnalyticsSummary.builder()
.totalParticipants(eventStats.getTotalParticipants())
.participants(eventStats.getTotalParticipants())
.participantsDelta(0) // TODO: 이전 기간 데이터와 비교하여 계산
.totalViews(totalViews)
.totalReach(totalReach)
.engagementRate(Math.round(engagementRate * 10.0) / 10.0)
.conversionRate(Math.round(conversionRate * 10.0) / 10.0)
.averageEngagementTime(145) // 고정값 (실제로는 외부 API에서 가져와야 )
.targetRoi(eventStats.getTargetRoi() != null ? eventStats.getTargetRoi().doubleValue() : null)
.socialInteractions(socialStats)
.build();
}
@ -202,7 +204,7 @@ public class AnalyticsService {
(stats.getParticipants() * 100.0 / stats.getDistributionCost().doubleValue()) : 0.0;
summaries.add(ChannelSummary.builder()
.channelName(stats.getChannelName())
.channel(stats.getChannelName())
.views(stats.getViews())
.participants(stats.getParticipants())
.engagementRate(Math.round(engagementRate * 10.0) / 10.0)

View File

@ -192,7 +192,7 @@ public class ROICalculator {
}
return RoiSummary.builder()
.totalInvestment(eventStats.getTotalInvestment())
.totalCost(eventStats.getTotalInvestment())
.expectedRevenue(eventStats.getExpectedRevenue())
.netProfit(netProfit)
.roi(roi)

View File

@ -190,7 +190,8 @@ public class UserAnalyticsService {
double avgConversionRate = totalParticipants > 0 ? (double) totalConversions / totalParticipants * 100 : 0.0;
return AnalyticsSummary.builder()
.totalParticipants(totalParticipants)
.participants(totalParticipants)
.participantsDelta(0) // TODO: 이전 기간 데이터와 비교하여 계산
.totalViews(totalViews)
.engagementRate(Math.round(avgEngagementRate * 10) / 10.0)
.conversionRate(Math.round(avgConversionRate * 10) / 10.0)
@ -231,7 +232,7 @@ public class UserAnalyticsService {
: 0.0;
return ChannelSummary.builder()
.channelName(channelName)
.channel(channelName)
.participants(participants)
.views(views)
.engagementRate(Math.round(engagementRate * 10) / 10.0)
@ -263,7 +264,7 @@ public class UserAnalyticsService {
: 0.0;
return RoiSummary.builder()
.totalInvestment(totalInvestment)
.totalCost(totalInvestment)
.expectedRevenue(totalExpectedRevenue)
.netProfit(totalProfit)
.roi(Math.round(roi * 10) / 10.0)
@ -316,7 +317,8 @@ public class UserAnalyticsService {
*/
private AnalyticsSummary buildEmptyAnalyticsSummary() {
return AnalyticsSummary.builder()
.totalParticipants(0)
.participants(0)
.participantsDelta(0)
.totalViews(0)
.engagementRate(0.0)
.conversionRate(0.0)
@ -328,7 +330,7 @@ public class UserAnalyticsService {
*/
private RoiSummary buildEmptyRoiSummary() {
return RoiSummary.builder()
.totalInvestment(BigDecimal.ZERO)
.totalCost(BigDecimal.ZERO)
.expectedRevenue(BigDecimal.ZERO)
.netProfit(BigDecimal.ZERO)
.roi(0.0)