kt-event-marketing/design/backend/api/analytics-service-api.yaml
2025-10-22 16:37:32 +09:00

943 lines
30 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

openapi: 3.0.3
info:
title: Analytics Service API
description: |
KT AI 기반 소상공인 이벤트 자동 생성 서비스 - Analytics Service API
이벤트 성과 분석 및 통합 대시보드를 제공하는 서비스입니다.
**주요 기능:**
- 실시간 성과 분석 대시보드 (UFR-ANAL-010)
- 채널별 성과 추적
- ROI 계산 및 비교 분석
- 참여자 프로필 분석
**데이터 소스:**
- Participation Service: 참여자 데이터
- Distribution Service: 채널별 노출 수
- 외부 API: 우리동네TV, 지니TV, SNS 통계
- POS 시스템: 매출 데이터 (연동 시)
version: 1.0.0
contact:
name: Analytics Service Team
email: analytics@kt-event-service.com
servers:
- url: https://api.kt-event-service.com/analytics/v1
description: Production Server
- url: https://dev-api.kt-event-service.com/analytics/v1
description: Development Server
- url: http://localhost:8084/api
description: Local Development Server
tags:
- name: Analytics
description: 성과 분석 대시보드 API
- name: Health
description: 서비스 헬스 체크
paths:
/health:
get:
tags:
- Health
summary: 헬스 체크
description: Analytics Service의 상태를 확인합니다.
operationId: healthCheck
responses:
'200':
description: 서비스 정상
content:
application/json:
schema:
type: object
properties:
status:
type: string
example: "UP"
service:
type: string
example: "analytics-service"
timestamp:
type: string
format: date-time
example: "2025-10-22T10:00:00Z"
/events/{eventId}/analytics:
get:
tags:
- Analytics
summary: 이벤트 성과 분석 대시보드 조회
description: |
특정 이벤트의 실시간 성과 분석 데이터를 조회합니다.
**유저스토리:** UFR-ANAL-010 - 성과 분석 대시보드
**주요 기능:**
- 4개 요약 카드 (참여자 수, 노출 수, ROI, 매출 증가율)
- 채널별 성과 분석
- 시간대별 참여 추이
- 참여자 프로필 분석
- 비교 분석 (업종 평균, 이전 이벤트)
**캐싱 전략:**
- Redis Cache-Aside 패턴
- TTL: 300초 (5분)
- Cache HIT 시 응답 시간: 약 0.5초
- Cache MISS 시 응답 시간: 약 3초
**데이터 업데이트:**
- 실시간 업데이트: Kafka 이벤트 구독
- EventCreated: 통계 초기화
- ParticipantRegistered: 참여자 수 증가
- DistributionCompleted: 배포 통계 업데이트
operationId: getEventAnalytics
security:
- BearerAuth: []
parameters:
- name: eventId
in: path
required: true
description: 이벤트 ID (UUID)
schema:
type: string
format: uuid
example: "550e8400-e29b-41d4-a716-446655440000"
responses:
'200':
description: 대시보드 데이터 조회 성공
content:
application/json:
schema:
$ref: '#/components/schemas/DashboardResponse'
examples:
success:
summary: 성공 응답 예시
value:
eventId: "550e8400-e29b-41d4-a716-446655440000"
storeId: "660e8400-e29b-41d4-a716-446655440001"
eventTitle: "신규 고객 환영 이벤트"
summaryCards:
totalParticipants:
count: 1234
targetGoal: 1000
achievementRate: 123.4
dailyChange: 150
totalViews:
count: 17200
yesterdayChange: 5.2
channelBreakdown:
- channel: "우리동네TV"
views: 5000
- channel: "지니TV"
views: 10000
- channel: "Instagram"
views: 2000
- channel: "Naver Blog"
views: 200
roi:
value: 250.0
industryAverage: 180.0
comparisonRate: 138.9
totalCost: 1000000
totalRevenue: 3500000
breakEvenStatus: "ACHIEVED"
salesGrowth:
rate: 15.2
beforeEventSales: 5000000
afterEventSales: 5760000
periodComparison: "이벤트 전후 7일 비교"
channelPerformance:
- channel: "우리동네TV"
views: 5000
participants: 400
conversionRate: 8.0
costPerAcquisition: 2500
status: "SUCCESS"
- channel: "지니TV"
views: 10000
participants: 500
conversionRate: 5.0
costPerAcquisition: 4000
status: "SUCCESS"
- channel: "Instagram"
views: 2000
participants: 200
conversionRate: 10.0
costPerAcquisition: 1000
status: "SUCCESS"
- channel: "Naver Blog"
views: 200
participants: 100
conversionRate: 50.0
costPerAcquisition: 500
status: "SUCCESS"
- channel: "Kakao Channel"
views: 0
participants: 34
conversionRate: 0
costPerAcquisition: 0
status: "SUCCESS"
participationTrend:
timeUnit: "DAILY"
dataPoints:
- timestamp: "2025-10-15T00:00:00Z"
participantCount: 100
- timestamp: "2025-10-16T00:00:00Z"
participantCount: 250
- timestamp: "2025-10-17T00:00:00Z"
participantCount: 400
- timestamp: "2025-10-18T00:00:00Z"
participantCount: 600
- timestamp: "2025-10-19T00:00:00Z"
participantCount: 850
- timestamp: "2025-10-20T00:00:00Z"
participantCount: 1050
- timestamp: "2025-10-21T00:00:00Z"
participantCount: 1234
peakTime:
timestamp: "2025-10-20T18:00:00Z"
participantCount: 200
roiAnalysis:
totalCost:
prizeCost: 500000
channelCosts:
- channel: "우리동네TV"
cost: 100000
- channel: "지니TV"
cost: 200000
- channel: "Instagram"
cost: 50000
- channel: "Naver Blog"
cost: 50000
- channel: "Kakao Channel"
cost: 0
otherCosts: 100000
total: 1000000
expectedRevenue:
salesIncrease: 760000
newCustomerLTV: 2740000
total: 3500000
roiCalculation:
formula: "(수익 - 비용) / 비용 × 100"
roi: 250.0
breakEvenPoint:
required: 1000000
achieved: 3500000
status: "ACHIEVED"
participantProfile:
ageDistribution:
- ageGroup: "10대"
count: 50
percentage: 4.1
- ageGroup: "20대"
count: 300
percentage: 24.3
- ageGroup: "30대"
count: 450
percentage: 36.5
- ageGroup: "40대"
count: 300
percentage: 24.3
- ageGroup: "50대 이상"
count: 134
percentage: 10.8
genderDistribution:
- gender: "남성"
count: 600
percentage: 48.6
- gender: "여성"
count: 634
percentage: 51.4
regionDistribution:
- region: "서울"
count: 500
percentage: 40.5
- region: "경기"
count: 400
percentage: 32.4
- region: "기타"
count: 334
percentage: 27.1
timeDistribution:
- timeSlot: "오전 (06:00-12:00)"
count: 200
percentage: 16.2
- timeSlot: "오후 (12:00-18:00)"
count: 500
percentage: 40.5
- timeSlot: "저녁 (18:00-24:00)"
count: 500
percentage: 40.5
- timeSlot: "새벽 (00:00-06:00)"
count: 34
percentage: 2.8
comparativeAnalysis:
industryComparison:
- metric: "참여율"
myValue: 7.2
industryAverage: 5.5
percentageDifference: 30.9
- metric: "ROI"
myValue: 250.0
industryAverage: 180.0
percentageDifference: 38.9
- metric: "전환율"
myValue: 8.5
industryAverage: 6.0
percentageDifference: 41.7
previousEventComparison:
- metric: "참여자 수"
currentValue: 1234
previousBest: 1000
improvementRate: 23.4
- metric: "ROI"
currentValue: 250.0
previousBest: 200.0
improvementRate: 25.0
- metric: "매출 증가율"
currentValue: 15.2
previousBest: 12.0
improvementRate: 26.7
lastUpdated: "2025-10-22T10:30:00Z"
cacheStatus: "HIT"
'400':
description: 잘못된 요청
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
examples:
invalidEventId:
summary: 잘못된 이벤트 ID
value:
error: "INVALID_REQUEST"
message: "유효하지 않은 이벤트 ID 형식입니다."
timestamp: "2025-10-22T10:00:00Z"
'401':
description: 인증 실패
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
examples:
unauthorized:
summary: 인증되지 않은 요청
value:
error: "UNAUTHORIZED"
message: "인증이 필요합니다."
timestamp: "2025-10-22T10:00:00Z"
'403':
description: 권한 없음
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
examples:
forbidden:
summary: 권한 없음
value:
error: "FORBIDDEN"
message: "해당 이벤트의 통계를 조회할 권한이 없습니다."
timestamp: "2025-10-22T10:00:00Z"
'404':
description: 이벤트를 찾을 수 없음
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
examples:
notFound:
summary: 이벤트 미존재
value:
error: "EVENT_NOT_FOUND"
message: "해당 이벤트를 찾을 수 없습니다."
timestamp: "2025-10-22T10:00:00Z"
'500':
description: 서버 내부 오류
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
examples:
internalError:
summary: 서버 오류
value:
error: "INTERNAL_SERVER_ERROR"
message: "서버 내부 오류가 발생했습니다."
timestamp: "2025-10-22T10:00:00Z"
'503':
description: 외부 API 서비스 이용 불가
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
examples:
externalServiceUnavailable:
summary: 외부 서비스 장애
value:
error: "EXTERNAL_SERVICE_UNAVAILABLE"
message: "일부 채널 데이터를 불러올 수 없습니다. Fallback 데이터를 사용합니다."
timestamp: "2025-10-22T10:00:00Z"
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: JWT 토큰 기반 인증. Authorization 헤더에 "Bearer {token}" 형식으로 전달합니다.
schemas:
DashboardResponse:
type: object
required:
- eventId
- storeId
- eventTitle
- summaryCards
- channelPerformance
- participationTrend
- roiAnalysis
- participantProfile
- comparativeAnalysis
- lastUpdated
properties:
eventId:
type: string
format: uuid
description: 이벤트 ID
example: "550e8400-e29b-41d4-a716-446655440000"
storeId:
type: string
format: uuid
description: 매장 ID
example: "660e8400-e29b-41d4-a716-446655440001"
eventTitle:
type: string
description: 이벤트 제목
example: "신규 고객 환영 이벤트"
summaryCards:
$ref: '#/components/schemas/SummaryCards'
channelPerformance:
type: array
description: 채널별 성과 분석
items:
$ref: '#/components/schemas/ChannelPerformance'
participationTrend:
$ref: '#/components/schemas/ParticipationTrend'
roiAnalysis:
$ref: '#/components/schemas/ROIAnalysis'
participantProfile:
$ref: '#/components/schemas/ParticipantProfile'
comparativeAnalysis:
$ref: '#/components/schemas/ComparativeAnalysis'
lastUpdated:
type: string
format: date-time
description: 마지막 업데이트 시각
example: "2025-10-22T10:30:00Z"
cacheStatus:
type: string
enum: [HIT, MISS]
description: 캐시 상태 (HIT/MISS)
example: "HIT"
SummaryCards:
type: object
description: 4개 요약 카드
required:
- totalParticipants
- totalViews
- roi
- salesGrowth
properties:
totalParticipants:
$ref: '#/components/schemas/TotalParticipantsCard'
totalViews:
$ref: '#/components/schemas/TotalViewsCard'
roi:
$ref: '#/components/schemas/ROICard'
salesGrowth:
$ref: '#/components/schemas/SalesGrowthCard'
TotalParticipantsCard:
type: object
description: 총 참여자 수 카드
required:
- count
- targetGoal
- achievementRate
properties:
count:
type: integer
description: 현재 참여자 수
example: 1234
targetGoal:
type: integer
description: 목표 참여자 수
example: 1000
achievementRate:
type: number
format: float
description: 목표 대비 달성률 (%)
example: 123.4
dailyChange:
type: integer
description: 전일 대비 증가 수
example: 150
TotalViewsCard:
type: object
description: 총 노출 수 카드
required:
- count
- yesterdayChange
properties:
count:
type: integer
description: 총 노출 수 (채널별 노출 합계)
example: 17200
yesterdayChange:
type: number
format: float
description: 전일 대비 증감률 (%)
example: 5.2
channelBreakdown:
type: array
description: 채널별 노출 수 분포
items:
type: object
properties:
channel:
type: string
description: 채널명
example: "우리동네TV"
views:
type: integer
description: 노출 수
example: 5000
ROICard:
type: object
description: 예상 투자 대비 수익률 카드
required:
- value
- industryAverage
- comparisonRate
- totalCost
- totalRevenue
- breakEvenStatus
properties:
value:
type: number
format: float
description: 실시간 ROI (%)
example: 250.0
industryAverage:
type: number
format: float
description: 업종 평균 ROI (%)
example: 180.0
comparisonRate:
type: number
format: float
description: 업종 평균 대비 비율 (%)
example: 138.9
totalCost:
type: integer
description: 총 비용 (원)
example: 1000000
totalRevenue:
type: integer
description: 총 수익 (원)
example: 3500000
breakEvenStatus:
type: string
enum: [ACHIEVED, NOT_ACHIEVED]
description: 손익분기점 달성 여부
example: "ACHIEVED"
SalesGrowthCard:
type: object
description: 매출 증가율 카드
required:
- rate
properties:
rate:
type: number
format: float
description: 매출 증가율 (%)
example: 15.2
beforeEventSales:
type: integer
description: 이벤트 전 매출 (원)
example: 5000000
afterEventSales:
type: integer
description: 이벤트 후 매출 (원)
example: 5760000
periodComparison:
type: string
description: 비교 기간 설명
example: "이벤트 전후 7일 비교"
ChannelPerformance:
type: object
description: 채널별 성과 분석
required:
- channel
- views
- participants
- conversionRate
- costPerAcquisition
- status
properties:
channel:
type: string
description: 채널명
example: "우리동네TV"
views:
type: integer
description: 노출 수
example: 5000
participants:
type: integer
description: 참여자 수
example: 400
conversionRate:
type: number
format: float
description: 전환율 (%)
example: 8.0
costPerAcquisition:
type: integer
description: 비용 대비 효율 (CPA, 원)
example: 2500
status:
type: string
enum: [SUCCESS, FAILED, PENDING]
description: 배포 상태
example: "SUCCESS"
ParticipationTrend:
type: object
description: 시간대별 참여 추이
required:
- timeUnit
- dataPoints
properties:
timeUnit:
type: string
enum: [HOURLY, DAILY]
description: 시간 단위 (시간별/일별)
example: "DAILY"
dataPoints:
type: array
description: 시간대별 데이터 포인트
items:
type: object
properties:
timestamp:
type: string
format: date-time
description: 시각
example: "2025-10-15T00:00:00Z"
participantCount:
type: integer
description: 참여자 수
example: 100
peakTime:
type: object
description: 피크 시간대
properties:
timestamp:
type: string
format: date-time
description: 피크 시각
example: "2025-10-20T18:00:00Z"
participantCount:
type: integer
description: 피크 참여자 수
example: 200
ROIAnalysis:
type: object
description: 투자 대비 수익률 상세 분석
required:
- totalCost
- expectedRevenue
- roiCalculation
- breakEvenPoint
properties:
totalCost:
$ref: '#/components/schemas/TotalCost'
expectedRevenue:
$ref: '#/components/schemas/ExpectedRevenue'
roiCalculation:
$ref: '#/components/schemas/ROICalculation'
breakEvenPoint:
$ref: '#/components/schemas/BreakEvenPoint'
TotalCost:
type: object
description: 총 비용 산출
required:
- prizeCost
- channelCosts
- otherCosts
- total
properties:
prizeCost:
type: integer
description: 경품 비용 (원)
example: 500000
channelCosts:
type: array
description: 채널별 플랫폼 비용
items:
type: object
properties:
channel:
type: string
description: 채널명
example: "우리동네TV"
cost:
type: integer
description: 비용 (원)
example: 100000
otherCosts:
type: integer
description: 기타 비용 (원)
example: 100000
total:
type: integer
description: 총 비용 (원)
example: 1000000
ExpectedRevenue:
type: object
description: 예상 수익 산출
required:
- salesIncrease
- newCustomerLTV
- total
properties:
salesIncrease:
type: integer
description: 매출 증가액 (원)
example: 760000
newCustomerLTV:
type: integer
description: 신규 고객 LTV (원)
example: 2740000
total:
type: integer
description: 총 예상 수익 (원)
example: 3500000
ROICalculation:
type: object
description: ROI 계산
required:
- formula
- roi
properties:
formula:
type: string
description: ROI 계산 공식
example: "(수익 - 비용) / 비용 × 100"
roi:
type: number
format: float
description: ROI (%)
example: 250.0
BreakEvenPoint:
type: object
description: 손익분기점
required:
- required
- achieved
- status
properties:
required:
type: integer
description: 손익분기점 (원)
example: 1000000
achieved:
type: integer
description: 달성 금액 (원)
example: 3500000
status:
type: string
enum: [ACHIEVED, NOT_ACHIEVED]
description: 달성 여부
example: "ACHIEVED"
ParticipantProfile:
type: object
description: 참여자 프로필 분석
required:
- ageDistribution
- genderDistribution
- regionDistribution
- timeDistribution
properties:
ageDistribution:
type: array
description: 연령대별 분포
items:
type: object
properties:
ageGroup:
type: string
description: 연령대
example: "20대"
count:
type: integer
description: 인원 수
example: 300
percentage:
type: number
format: float
description: 비율 (%)
example: 24.3
genderDistribution:
type: array
description: 성별 분포
items:
type: object
properties:
gender:
type: string
description: 성별
example: "남성"
count:
type: integer
description: 인원 수
example: 600
percentage:
type: number
format: float
description: 비율 (%)
example: 48.6
regionDistribution:
type: array
description: 지역별 분포
items:
type: object
properties:
region:
type: string
description: 지역
example: "서울"
count:
type: integer
description: 인원 수
example: 500
percentage:
type: number
format: float
description: 비율 (%)
example: 40.5
timeDistribution:
type: array
description: 참여 시간대 분석
items:
type: object
properties:
timeSlot:
type: string
description: 시간대
example: "오전 (06:00-12:00)"
count:
type: integer
description: 참여자 수
example: 200
percentage:
type: number
format: float
description: 비율 (%)
example: 16.2
ComparativeAnalysis:
type: object
description: 비교 분석
required:
- industryComparison
- previousEventComparison
properties:
industryComparison:
type: array
description: 업종 평균과 비교
items:
type: object
properties:
metric:
type: string
description: 지표명
example: "참여율"
myValue:
type: number
format: float
description: 내 값
example: 7.2
industryAverage:
type: number
format: float
description: 업종 평균
example: 5.5
percentageDifference:
type: number
format: float
description: 차이율 (%)
example: 30.9
previousEventComparison:
type: array
description: 내 이전 이벤트와 비교
items:
type: object
properties:
metric:
type: string
description: 지표명
example: "참여자 수"
currentValue:
type: number
format: float
description: 현재 값
example: 1234
previousBest:
type: number
format: float
description: 이전 최고 기록
example: 1000
improvementRate:
type: number
format: float
description: 개선율 (%)
example: 23.4
ErrorResponse:
type: object
description: 에러 응답
required:
- error
- message
- timestamp
properties:
error:
type: string
description: 에러 코드
example: "INVALID_REQUEST"
message:
type: string
description: 에러 메시지
example: "유효하지 않은 요청입니다."
timestamp:
type: string
format: date-time
description: 에러 발생 시각
example: "2025-10-22T10:00:00Z"