mirror of
https://github.com/ktds-dg0501/kt-event-marketing-fe.git
synced 2026-06-13 08:59:10 +00:00
Analytics 테스트 페이지 디버그 로그 추가
- 이벤트 기간 계산 함수에 상세 디버그 로그 추가 - 차트 데이터 생성 함수에 필터링 과정 로그 추가 - Timeline dataPoints 구조 확인을 위한 콘솔 출력 추가 - ROI 필드 매핑 검증을 위한 로그 추가
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
import { analyticsClient } from './analyticsClient';
|
||||
import type {
|
||||
ApiResponse,
|
||||
UserAnalyticsDashboardResponse,
|
||||
AnalyticsDashboardResponse,
|
||||
UserTimelineAnalyticsResponse,
|
||||
TimelineAnalyticsResponse,
|
||||
UserRoiAnalyticsResponse,
|
||||
RoiAnalyticsResponse,
|
||||
UserChannelAnalyticsResponse,
|
||||
ChannelAnalyticsResponse,
|
||||
AnalyticsQueryParams,
|
||||
TimelineQueryParams,
|
||||
ChannelQueryParams,
|
||||
RoiQueryParams,
|
||||
} from '../model/types';
|
||||
|
||||
const API_VERSION = process.env.NEXT_PUBLIC_API_VERSION || 'v1';
|
||||
|
||||
/**
|
||||
* Analytics API Service
|
||||
* 실시간 효과 측정 및 통합 대시보드 API
|
||||
*/
|
||||
export const analyticsApi = {
|
||||
// ============= User Analytics (사용자 전체 이벤트 통합) =============
|
||||
|
||||
/**
|
||||
* 사용자 전체 성과 대시보드 조회
|
||||
*/
|
||||
getUserAnalytics: async (
|
||||
userId: string,
|
||||
params?: AnalyticsQueryParams
|
||||
): Promise<UserAnalyticsDashboardResponse> => {
|
||||
const response = await analyticsClient.get<ApiResponse<UserAnalyticsDashboardResponse>>(
|
||||
`/api/${API_VERSION}/users/${userId}/analytics`,
|
||||
{ params }
|
||||
);
|
||||
return response.data.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 사용자 전체 시간대별 참여 추이
|
||||
*/
|
||||
getUserTimelineAnalytics: async (
|
||||
userId: string,
|
||||
params?: TimelineQueryParams
|
||||
): Promise<UserTimelineAnalyticsResponse> => {
|
||||
const response = await analyticsClient.get<ApiResponse<UserTimelineAnalyticsResponse>>(
|
||||
`/api/${API_VERSION}/users/${userId}/analytics/timeline`,
|
||||
{ params }
|
||||
);
|
||||
return response.data.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 사용자 전체 ROI 상세 분석
|
||||
*/
|
||||
getUserRoiAnalytics: async (
|
||||
userId: string,
|
||||
params?: AnalyticsQueryParams & RoiQueryParams
|
||||
): Promise<UserRoiAnalyticsResponse> => {
|
||||
const response = await analyticsClient.get<ApiResponse<UserRoiAnalyticsResponse>>(
|
||||
`/api/${API_VERSION}/users/${userId}/analytics/roi`,
|
||||
{ params }
|
||||
);
|
||||
return response.data.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 사용자 전체 채널별 성과 분석
|
||||
*/
|
||||
getUserChannelAnalytics: async (
|
||||
userId: string,
|
||||
params?: ChannelQueryParams
|
||||
): Promise<UserChannelAnalyticsResponse> => {
|
||||
const response = await analyticsClient.get<ApiResponse<UserChannelAnalyticsResponse>>(
|
||||
`/api/${API_VERSION}/users/${userId}/analytics/channels`,
|
||||
{ params }
|
||||
);
|
||||
return response.data.data;
|
||||
},
|
||||
|
||||
// ============= Event Analytics (특정 이벤트 분석) =============
|
||||
|
||||
/**
|
||||
* 이벤트 성과 대시보드 조회
|
||||
*/
|
||||
getEventAnalytics: async (
|
||||
eventId: string,
|
||||
params?: AnalyticsQueryParams
|
||||
): Promise<AnalyticsDashboardResponse> => {
|
||||
const response = await analyticsClient.get<ApiResponse<AnalyticsDashboardResponse>>(
|
||||
`/api/${API_VERSION}/events/${eventId}/analytics`,
|
||||
{ params }
|
||||
);
|
||||
return response.data.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 이벤트 시간대별 참여 추이
|
||||
*/
|
||||
getEventTimelineAnalytics: async (
|
||||
eventId: string,
|
||||
params?: TimelineQueryParams
|
||||
): Promise<TimelineAnalyticsResponse> => {
|
||||
const response = await analyticsClient.get<ApiResponse<TimelineAnalyticsResponse>>(
|
||||
`/api/${API_VERSION}/events/${eventId}/analytics/timeline`,
|
||||
{ params }
|
||||
);
|
||||
return response.data.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 이벤트 ROI 상세 분석
|
||||
*/
|
||||
getEventRoiAnalytics: async (
|
||||
eventId: string,
|
||||
params?: RoiQueryParams
|
||||
): Promise<RoiAnalyticsResponse> => {
|
||||
const response = await analyticsClient.get<ApiResponse<RoiAnalyticsResponse>>(
|
||||
`/api/${API_VERSION}/events/${eventId}/analytics/roi`,
|
||||
{ params }
|
||||
);
|
||||
return response.data.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 이벤트 채널별 성과 분석
|
||||
*/
|
||||
getEventChannelAnalytics: async (
|
||||
eventId: string,
|
||||
params?: ChannelQueryParams
|
||||
): Promise<ChannelAnalyticsResponse> => {
|
||||
const response = await analyticsClient.get<ApiResponse<ChannelAnalyticsResponse>>(
|
||||
`/api/${API_VERSION}/events/${eventId}/analytics/channels`,
|
||||
{ params }
|
||||
);
|
||||
return response.data.data;
|
||||
},
|
||||
};
|
||||
|
||||
export default analyticsApi;
|
||||
@@ -0,0 +1,67 @@
|
||||
import axios, { AxiosInstance, AxiosError, InternalAxiosRequestConfig } from 'axios';
|
||||
|
||||
const ANALYTICS_HOST =
|
||||
process.env.NEXT_PUBLIC_ANALYTICS_HOST || 'http://localhost:8086';
|
||||
|
||||
export const analyticsClient: AxiosInstance = axios.create({
|
||||
baseURL: ANALYTICS_HOST,
|
||||
timeout: 30000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
// Request interceptor - JWT 토큰 추가
|
||||
analyticsClient.interceptors.request.use(
|
||||
(config: InternalAxiosRequestConfig) => {
|
||||
console.log('🚀 Analytics API Request:', {
|
||||
method: config.method?.toUpperCase(),
|
||||
url: config.url,
|
||||
baseURL: config.baseURL,
|
||||
params: config.params,
|
||||
});
|
||||
|
||||
const token = localStorage.getItem('accessToken');
|
||||
if (token && config.headers) {
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
console.log('🔑 Token added to analytics request');
|
||||
}
|
||||
return config;
|
||||
},
|
||||
(error: AxiosError) => {
|
||||
console.error('❌ Analytics Request Error:', error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// Response interceptor - 에러 처리
|
||||
analyticsClient.interceptors.response.use(
|
||||
(response) => {
|
||||
console.log('✅ Analytics API Response:', {
|
||||
status: response.status,
|
||||
url: response.config.url,
|
||||
data: response.data,
|
||||
});
|
||||
return response;
|
||||
},
|
||||
(error: AxiosError) => {
|
||||
console.error('❌ Analytics API Error:', {
|
||||
message: error.message,
|
||||
status: error.response?.status,
|
||||
statusText: error.response?.statusText,
|
||||
url: error.config?.url,
|
||||
data: error.response?.data,
|
||||
});
|
||||
|
||||
if (error.response?.status === 401) {
|
||||
console.warn('🔒 401 Unauthorized - Redirecting to login');
|
||||
localStorage.removeItem('accessToken');
|
||||
if (typeof window !== 'undefined') {
|
||||
window.location.href = '/login';
|
||||
}
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export default analyticsClient;
|
||||
@@ -0,0 +1,3 @@
|
||||
export { analyticsApi } from './analyticsApi';
|
||||
export { analyticsClient } from './analyticsClient';
|
||||
export * from '../model/types';
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './api';
|
||||
export * from './model/types';
|
||||
@@ -0,0 +1,295 @@
|
||||
/**
|
||||
* Analytics API Types
|
||||
* Based on Analytics Service OpenAPI Specification
|
||||
*/
|
||||
|
||||
// ============= Common Types =============
|
||||
export interface PeriodInfo {
|
||||
startDate: string;
|
||||
endDate: string;
|
||||
durationDays: number;
|
||||
}
|
||||
|
||||
export interface SocialInteractionStats {
|
||||
likes: number;
|
||||
comments: number;
|
||||
shares: number;
|
||||
}
|
||||
|
||||
// ============= Summary Types =============
|
||||
export interface AnalyticsSummary {
|
||||
participants: number;
|
||||
participantsDelta: number;
|
||||
totalViews: number;
|
||||
totalReach: number;
|
||||
engagementRate: number;
|
||||
conversionRate: number;
|
||||
averageEngagementTime: number;
|
||||
targetRoi: number;
|
||||
socialInteractions?: SocialInteractionStats;
|
||||
}
|
||||
|
||||
export interface ChannelSummary {
|
||||
channel: string;
|
||||
views: number;
|
||||
participants: number;
|
||||
engagementRate: number;
|
||||
conversionRate: number;
|
||||
roi: number;
|
||||
}
|
||||
|
||||
export interface RoiSummary {
|
||||
totalCost: number;
|
||||
expectedRevenue: number;
|
||||
netProfit: number;
|
||||
roi: number;
|
||||
costPerAcquisition: number;
|
||||
}
|
||||
|
||||
export interface EventPerformanceSummary {
|
||||
eventId: string;
|
||||
eventTitle: string;
|
||||
participants: number;
|
||||
views: number;
|
||||
roi: number;
|
||||
status: string;
|
||||
}
|
||||
|
||||
// ============= Timeline Types =============
|
||||
export interface TimelineDataPoint {
|
||||
timestamp: string;
|
||||
participants: number;
|
||||
views: number;
|
||||
engagement: number;
|
||||
conversions: number;
|
||||
cumulativeParticipants: number;
|
||||
}
|
||||
|
||||
export interface PeakTimeInfo {
|
||||
timestamp: string;
|
||||
metric: string;
|
||||
value: number;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export interface TrendAnalysis {
|
||||
overallTrend: string;
|
||||
growthRate: number;
|
||||
projectedParticipants: number;
|
||||
peakPeriod: string;
|
||||
}
|
||||
|
||||
// ============= ROI Types =============
|
||||
export interface InvestmentDetails {
|
||||
prizeCost: number;
|
||||
contentCreation: number;
|
||||
distribution: number;
|
||||
operation: number;
|
||||
total: number;
|
||||
breakdown?: Record<string, unknown>[];
|
||||
}
|
||||
|
||||
export interface RevenueDetails {
|
||||
directSales: number;
|
||||
expectedSales: number;
|
||||
brandValue: number;
|
||||
newCustomerRevenue: number;
|
||||
total: number;
|
||||
}
|
||||
|
||||
export interface RoiCalculation {
|
||||
netProfit: number;
|
||||
roiPercentage: number;
|
||||
breakEvenPoint?: string;
|
||||
paybackPeriod: number;
|
||||
}
|
||||
|
||||
export interface CostEfficiency {
|
||||
costPerParticipant: number;
|
||||
costPerConversion: number;
|
||||
costPerView: number;
|
||||
revenuePerParticipant: number;
|
||||
}
|
||||
|
||||
export interface RevenueProjection {
|
||||
currentRevenue: number;
|
||||
projectedFinalRevenue: number;
|
||||
confidenceLevel: number;
|
||||
basedOn: string;
|
||||
}
|
||||
|
||||
// ============= Channel Types =============
|
||||
export interface VoiceCallStats {
|
||||
totalCalls: number;
|
||||
completedCalls: number;
|
||||
averageDuration: number;
|
||||
completionRate: number;
|
||||
}
|
||||
|
||||
export interface ChannelMetrics {
|
||||
impressions: number;
|
||||
views: number;
|
||||
clicks: number;
|
||||
participants: number;
|
||||
conversions: number;
|
||||
socialInteractions?: SocialInteractionStats;
|
||||
voiceCallStats?: VoiceCallStats;
|
||||
}
|
||||
|
||||
export interface ChannelPerformance {
|
||||
clickThroughRate: number;
|
||||
engagementRate: number;
|
||||
conversionRate: number;
|
||||
averageEngagementTime: number;
|
||||
bounceRate: number;
|
||||
}
|
||||
|
||||
export interface ChannelCosts {
|
||||
distributionCost: number;
|
||||
costPerView: number;
|
||||
costPerClick: number;
|
||||
costPerAcquisition: number;
|
||||
roi: number;
|
||||
}
|
||||
|
||||
export interface ChannelAnalytics {
|
||||
channelName: string;
|
||||
channelType: string;
|
||||
metrics: ChannelMetrics;
|
||||
performance: ChannelPerformance;
|
||||
costs: ChannelCosts;
|
||||
externalApiStatus?: string;
|
||||
}
|
||||
|
||||
export interface ChannelComparison {
|
||||
bestPerforming: Record<string, string>;
|
||||
averageMetrics: Record<string, number>;
|
||||
}
|
||||
|
||||
// ============= Dashboard Response Types =============
|
||||
export interface UserAnalyticsDashboardResponse {
|
||||
userId: string;
|
||||
period: PeriodInfo;
|
||||
totalEvents: number;
|
||||
activeEvents: number;
|
||||
overallSummary: AnalyticsSummary;
|
||||
channelPerformance: ChannelSummary[];
|
||||
overallRoi: RoiSummary;
|
||||
eventPerformances: EventPerformanceSummary[];
|
||||
lastUpdatedAt: string;
|
||||
dataSource: string;
|
||||
}
|
||||
|
||||
export interface AnalyticsDashboardResponse {
|
||||
eventId: string;
|
||||
eventTitle: string;
|
||||
period: PeriodInfo;
|
||||
summary: AnalyticsSummary;
|
||||
channelPerformance: ChannelSummary[];
|
||||
roi: RoiSummary;
|
||||
lastUpdatedAt: string;
|
||||
dataSource: string;
|
||||
}
|
||||
|
||||
export interface TimelineAnalyticsResponse {
|
||||
eventId: string;
|
||||
interval: string;
|
||||
dataPoints: TimelineDataPoint[];
|
||||
trends: TrendAnalysis;
|
||||
peakTimes: PeakTimeInfo[];
|
||||
lastUpdatedAt: string;
|
||||
}
|
||||
|
||||
export interface UserTimelineAnalyticsResponse {
|
||||
userId: string;
|
||||
period: PeriodInfo;
|
||||
totalEvents: number;
|
||||
interval: string;
|
||||
dataPoints: TimelineDataPoint[];
|
||||
trend: TrendAnalysis;
|
||||
peakTime: PeakTimeInfo;
|
||||
lastUpdatedAt: string;
|
||||
dataSource: string;
|
||||
}
|
||||
|
||||
export interface RoiAnalyticsResponse {
|
||||
eventId: string;
|
||||
investment: InvestmentDetails;
|
||||
revenue: RevenueDetails;
|
||||
roi: RoiCalculation;
|
||||
costEfficiency: CostEfficiency;
|
||||
projection: RevenueProjection;
|
||||
lastUpdatedAt: string;
|
||||
}
|
||||
|
||||
export interface UserRoiAnalyticsResponse {
|
||||
userId: string;
|
||||
period: PeriodInfo;
|
||||
totalEvents: number;
|
||||
overallInvestment: InvestmentDetails;
|
||||
overallRevenue: RevenueDetails;
|
||||
overallRoi: RoiCalculation;
|
||||
costEfficiency: CostEfficiency;
|
||||
projection: RevenueProjection;
|
||||
eventRois: EventRoiSummary[];
|
||||
lastUpdatedAt: string;
|
||||
dataSource: string;
|
||||
}
|
||||
|
||||
export interface EventRoiSummary {
|
||||
eventId: string;
|
||||
eventTitle: string;
|
||||
totalInvestment: number;
|
||||
expectedRevenue: number;
|
||||
roi: number;
|
||||
status: string;
|
||||
}
|
||||
|
||||
export interface ChannelAnalyticsResponse {
|
||||
eventId: string;
|
||||
channels: ChannelAnalytics[];
|
||||
comparison: ChannelComparison;
|
||||
lastUpdatedAt: string;
|
||||
}
|
||||
|
||||
export interface UserChannelAnalyticsResponse {
|
||||
userId: string;
|
||||
period: PeriodInfo;
|
||||
totalEvents: number;
|
||||
channels: ChannelAnalytics[];
|
||||
comparison: ChannelComparison;
|
||||
lastUpdatedAt: string;
|
||||
dataSource: string;
|
||||
}
|
||||
|
||||
// ============= API Response Wrapper =============
|
||||
export interface ApiResponse<T> {
|
||||
success: boolean;
|
||||
data: T;
|
||||
errorCode?: string;
|
||||
message?: string;
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
// ============= API Request Types =============
|
||||
export interface AnalyticsQueryParams {
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
refresh?: boolean;
|
||||
}
|
||||
|
||||
export interface TimelineQueryParams extends AnalyticsQueryParams {
|
||||
interval?: 'hourly' | 'daily' | 'weekly' | 'monthly';
|
||||
metrics?: string;
|
||||
}
|
||||
|
||||
export interface ChannelQueryParams extends AnalyticsQueryParams {
|
||||
channels?: string;
|
||||
sortBy?: 'views' | 'participants' | 'engagement_rate' | 'conversion_rate' | 'roi';
|
||||
order?: 'asc' | 'desc';
|
||||
}
|
||||
|
||||
export interface RoiQueryParams {
|
||||
includeProjection?: boolean;
|
||||
refresh?: boolean;
|
||||
}
|
||||
Reference in New Issue
Block a user