mirror of
https://github.com/ktds-dg0501/kt-event-marketing.git
synced 2025-12-06 10:46:23 +00:00
1037 lines
32 KiB
YAML
1037 lines
32 KiB
YAML
openapi: 3.0.3
|
|
info:
|
|
title: AI Service API
|
|
description: |
|
|
AI 기반 트렌드 분석 및 이벤트 추천 서비스 API
|
|
|
|
## 주요 기능
|
|
- 업종/지역/시즌별 트렌드 분석
|
|
- AI 기반 이벤트 기획안 추천 (3가지 옵션)
|
|
- 비동기 Job 처리 및 폴링 기반 결과 조회
|
|
|
|
## 기술 스택
|
|
- AI Engine: Claude API / GPT-4 API
|
|
- 캐싱: Redis (트렌드 1시간, 추천안 24시간)
|
|
- 메시지 큐: Kafka (비동기 Job 처리)
|
|
- 안정성: Circuit Breaker 패턴
|
|
version: 1.0.0
|
|
contact:
|
|
name: AI Service Team
|
|
email: ai-team@kt.com
|
|
|
|
servers:
|
|
- url: https://api.kt-event.com/ai/v1
|
|
description: 프로덕션 서버
|
|
- url: https://dev-api.kt-event.com/ai/v1
|
|
description: 개발 서버
|
|
- url: http://localhost:8083/ai/v1
|
|
description: 로컬 개발 서버
|
|
|
|
tags:
|
|
- name: AI Analysis
|
|
description: AI 기반 트렌드 분석 및 추천 엔드포인트
|
|
- name: Job Status
|
|
description: 비동기 Job 상태 조회 엔드포인트
|
|
|
|
paths:
|
|
/analyze-trends:
|
|
post:
|
|
tags:
|
|
- AI Analysis
|
|
summary: 트렌드 분석 요청
|
|
description: |
|
|
업종, 지역, 시즌을 기반으로 트렌드 분석을 수행합니다.
|
|
|
|
## 처리 방식
|
|
- **비동기 처리**: Kafka를 통한 비동기 Job 생성
|
|
- **응답 시간**: 즉시 Job ID 반환 (< 100ms)
|
|
- **실제 처리 시간**: 5~30초 이내 (AI API 응답 시간 포함)
|
|
|
|
## 캐싱 전략
|
|
- 캐시 키: `trend:{업종}:{지역}`
|
|
- TTL: 1시간
|
|
- 캐시 히트 시 즉시 응답
|
|
|
|
## Circuit Breaker
|
|
- Failure Rate Threshold: 50%
|
|
- Timeout: 30초
|
|
- Half-Open Wait Duration: 30초
|
|
operationId: analyzeTrends
|
|
security:
|
|
- bearerAuth: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/TrendAnalysisRequest"
|
|
examples:
|
|
restaurant:
|
|
summary: 음식점 트렌드 분석
|
|
value:
|
|
eventDraftId: "evt_draft_001"
|
|
industry: "음식점"
|
|
region: "서울 강남구"
|
|
purpose: "신규 고객 유치"
|
|
storeInfo:
|
|
storeName: "맛있는 고깃집"
|
|
storeSize: "중형"
|
|
monthlyRevenue: 30000000
|
|
cafe:
|
|
summary: 카페 트렌드 분석
|
|
value:
|
|
eventDraftId: "evt_draft_002"
|
|
industry: "카페"
|
|
region: "서울 홍대"
|
|
purpose: "재방문 유도"
|
|
storeInfo:
|
|
storeName: "커피스토리"
|
|
storeSize: "소형"
|
|
monthlyRevenue: 15000000
|
|
responses:
|
|
"202":
|
|
description: |
|
|
트렌드 분석 Job이 생성되었습니다.
|
|
- Job ID를 사용하여 `/jobs/{jobId}` 엔드포인트로 결과 폴링
|
|
- 예상 처리 시간: 5~30초
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/JobCreatedResponse"
|
|
example:
|
|
jobId: "job_ai_20250122_001"
|
|
status: "PROCESSING"
|
|
message: "트렌드 분석이 진행 중입니다"
|
|
estimatedCompletionTime: "2025-01-22T10:05:30Z"
|
|
"400":
|
|
$ref: "#/components/responses/BadRequest"
|
|
"401":
|
|
$ref: "#/components/responses/Unauthorized"
|
|
"429":
|
|
$ref: "#/components/responses/TooManyRequests"
|
|
"500":
|
|
$ref: "#/components/responses/InternalServerError"
|
|
|
|
/recommend-events:
|
|
post:
|
|
tags:
|
|
- AI Analysis
|
|
summary: 이벤트 추천 요청
|
|
description: |
|
|
트렌드 분석 결과를 기반으로 3가지 차별화된 이벤트 기획안을 생성합니다.
|
|
|
|
## 처리 방식
|
|
- **비동기 처리**: Kafka를 통한 비동기 Job 생성
|
|
- **응답 시간**: 즉시 Job ID 반환 (< 100ms)
|
|
- **실제 처리 시간**: 5~30초 이내
|
|
|
|
## 3가지 추천 옵션
|
|
1. **저비용 옵션**: 높은 참여율 중심
|
|
2. **중비용 옵션**: 균형잡힌 ROI
|
|
3. **고비용 옵션**: 높은 매출 증대 효과
|
|
|
|
## 병렬 처리
|
|
- 3가지 옵션 동시 생성 (병렬)
|
|
- 전체 처리 시간: 단일 요청 시간과 동일
|
|
|
|
## 캐싱 전략
|
|
- 캐시 키: `ai:recommendation:{eventDraftId}`
|
|
- TTL: 24시간
|
|
operationId: recommendEvents
|
|
security:
|
|
- bearerAuth: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/EventRecommendationRequest"
|
|
examples:
|
|
newCustomer:
|
|
summary: 신규 고객 유치 이벤트
|
|
value:
|
|
eventDraftId: "evt_draft_001"
|
|
purpose: "신규 고객 유치"
|
|
industry: "음식점"
|
|
region: "서울 강남구"
|
|
storeInfo:
|
|
storeName: "맛있는 고깃집"
|
|
storeSize: "중형"
|
|
monthlyRevenue: 30000000
|
|
trendAnalysisJobId: "job_ai_20250122_001"
|
|
responses:
|
|
"202":
|
|
description: |
|
|
이벤트 추천 Job이 생성되었습니다.
|
|
- Job ID를 사용하여 `/jobs/{jobId}` 엔드포인트로 결과 폴링
|
|
- 예상 처리 시간: 5~30초
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/JobCreatedResponse"
|
|
example:
|
|
jobId: "job_ai_20250122_002"
|
|
status: "PROCESSING"
|
|
message: "이벤트 추천이 진행 중입니다"
|
|
estimatedCompletionTime: "2025-01-22T10:05:30Z"
|
|
"400":
|
|
$ref: "#/components/responses/BadRequest"
|
|
"401":
|
|
$ref: "#/components/responses/Unauthorized"
|
|
"429":
|
|
$ref: "#/components/responses/TooManyRequests"
|
|
"500":
|
|
$ref: "#/components/responses/InternalServerError"
|
|
|
|
/jobs/{jobId}:
|
|
get:
|
|
tags:
|
|
- Job Status
|
|
summary: Job 상태 조회
|
|
description: |
|
|
비동기 Job의 처리 상태 및 결과를 조회합니다.
|
|
|
|
## 폴링 전략
|
|
- **초기 폴링**: 1초 간격 (처음 5회)
|
|
- **장기 폴링**: 3초 간격 (이후)
|
|
- **최대 대기 시간**: 60초
|
|
|
|
## Job 상태
|
|
- `PENDING`: 대기 중
|
|
- `PROCESSING`: 처리 중
|
|
- `COMPLETED`: 완료
|
|
- `FAILED`: 실패
|
|
|
|
## 캐싱
|
|
- Redis를 통한 Job 상태 저장
|
|
- 키: `job:{jobId}`
|
|
operationId: getJobStatus
|
|
security:
|
|
- bearerAuth: []
|
|
parameters:
|
|
- name: jobId
|
|
in: path
|
|
required: true
|
|
description: Job ID
|
|
schema:
|
|
type: string
|
|
example: "job_ai_20250122_001"
|
|
responses:
|
|
"200":
|
|
description: Job 상태 조회 성공
|
|
content:
|
|
application/json:
|
|
schema:
|
|
oneOf:
|
|
- $ref: "#/components/schemas/TrendAnalysisJobResponse"
|
|
- $ref: "#/components/schemas/EventRecommendationJobResponse"
|
|
examples:
|
|
processing:
|
|
summary: 처리 중
|
|
value:
|
|
jobId: "job_ai_20250122_001"
|
|
status: "PROCESSING"
|
|
message: "트렌드 분석 중입니다"
|
|
progress: 50
|
|
createdAt: "2025-01-22T10:05:00Z"
|
|
estimatedCompletionTime: "2025-01-22T10:05:30Z"
|
|
trendCompleted:
|
|
summary: 트렌드 분석 완료
|
|
value:
|
|
jobId: "job_ai_20250122_001"
|
|
status: "COMPLETED"
|
|
message: "트렌드 분석이 완료되었습니다"
|
|
result:
|
|
industryTrends:
|
|
successfulEventTypes:
|
|
- type: "할인 이벤트"
|
|
successRate: 85
|
|
- type: "경품 추첨"
|
|
successRate: 78
|
|
popularPrizes:
|
|
- prize: "커피 쿠폰"
|
|
preferenceScore: 92
|
|
- prize: "현금 할인"
|
|
preferenceScore: 88
|
|
effectiveParticipationMethods:
|
|
- method: "간단한 설문조사"
|
|
engagementRate: 75
|
|
regionalCharacteristics:
|
|
successRate: 82
|
|
demographicProfile:
|
|
ageGroups:
|
|
- range: "20-29"
|
|
percentage: 35
|
|
- range: "30-39"
|
|
percentage: 40
|
|
genderDistribution:
|
|
male: 45
|
|
female: 55
|
|
seasonalPatterns:
|
|
currentSeason: "겨울"
|
|
recommendedEventTypes:
|
|
- "따뜻한 음료 할인"
|
|
- "연말 감사 이벤트"
|
|
specialOccasions:
|
|
- occasion: "설날"
|
|
daysUntil: 15
|
|
completedAt: "2025-01-22T10:05:25Z"
|
|
recommendationCompleted:
|
|
summary: 이벤트 추천 완료
|
|
value:
|
|
jobId: "job_ai_20250122_002"
|
|
status: "COMPLETED"
|
|
message: "이벤트 추천이 완료되었습니다"
|
|
result:
|
|
recommendations:
|
|
- option: 1
|
|
title: "신규 고객 환영 커피 쿠폰 증정"
|
|
budget: "low"
|
|
prize:
|
|
name: "아메리카노 쿠폰"
|
|
quantity: 100
|
|
estimatedCost: 300000
|
|
participationMethod:
|
|
type: "간단한 설문조사"
|
|
difficulty: "low"
|
|
description: "매장 방문 후 QR 코드 스캔 및 간단한 설문"
|
|
estimatedParticipants: 150
|
|
estimatedROI: 250
|
|
promotionalTexts:
|
|
- "따뜻한 커피 한 잔으로 시작하는 하루!"
|
|
- "신규 방문 고객님께 특별한 선물"
|
|
hashtags:
|
|
- "#강남맛집"
|
|
- "#커피쿠폰"
|
|
- "#신규고객환영"
|
|
- option: 2
|
|
title: "런치 세트 20% 할인 이벤트"
|
|
budget: "medium"
|
|
prize:
|
|
name: "런치 세트 할인권"
|
|
quantity: 50
|
|
estimatedCost: 500000
|
|
participationMethod:
|
|
type: "재방문 미션"
|
|
difficulty: "medium"
|
|
description: "첫 방문 후 리뷰 작성 시 할인권 제공"
|
|
estimatedParticipants: 80
|
|
estimatedROI: 320
|
|
promotionalTexts:
|
|
- "점심 시간, 특별한 할인 기회!"
|
|
- "리뷰 남기고 할인받자"
|
|
hashtags:
|
|
- "#강남맛집"
|
|
- "#런치할인"
|
|
- "#점심특가"
|
|
- option: 3
|
|
title: "디너 코스 무료 업그레이드 추첨"
|
|
budget: "high"
|
|
prize:
|
|
name: "디너 코스 업그레이드권"
|
|
quantity: 10
|
|
estimatedCost: 1000000
|
|
participationMethod:
|
|
type: "바이럴 확산"
|
|
difficulty: "high"
|
|
description: "SNS 공유 및 친구 태그 3명 이상"
|
|
estimatedParticipants: 200
|
|
estimatedROI: 450
|
|
promotionalTexts:
|
|
- "프리미엄 디너 코스로 업그레이드!"
|
|
- "친구와 함께 즐기는 특별한 저녁"
|
|
hashtags:
|
|
- "#강남맛집"
|
|
- "#디너코스"
|
|
- "#프리미엄디너"
|
|
completedAt: "2025-01-22T10:05:35Z"
|
|
failed:
|
|
summary: 처리 실패
|
|
value:
|
|
jobId: "job_ai_20250122_003"
|
|
status: "FAILED"
|
|
message: "AI API 오류로 인해 처리에 실패했습니다"
|
|
error:
|
|
code: "AI_API_ERROR"
|
|
detail: "External AI API timeout after 30 seconds"
|
|
failedAt: "2025-01-22T10:05:45Z"
|
|
"404":
|
|
$ref: "#/components/responses/NotFound"
|
|
"401":
|
|
$ref: "#/components/responses/Unauthorized"
|
|
"500":
|
|
$ref: "#/components/responses/InternalServerError"
|
|
|
|
components:
|
|
securitySchemes:
|
|
bearerAuth:
|
|
type: http
|
|
scheme: bearer
|
|
bearerFormat: JWT
|
|
description: |
|
|
JWT 토큰 기반 인증
|
|
- User Service에서 발급한 JWT 토큰 사용
|
|
- 헤더: `Authorization: Bearer {token}`
|
|
|
|
schemas:
|
|
TrendAnalysisRequest:
|
|
type: object
|
|
required:
|
|
- eventDraftId
|
|
- industry
|
|
- region
|
|
- purpose
|
|
properties:
|
|
eventDraftId:
|
|
type: string
|
|
description: 이벤트 초안 ID (Event Service에서 생성)
|
|
example: "evt_draft_001"
|
|
industry:
|
|
type: string
|
|
description: 업종
|
|
enum:
|
|
- 음식점
|
|
- 카페
|
|
- 소매점
|
|
- 뷰티/미용
|
|
- 의료/헬스케어
|
|
- 기타
|
|
example: "음식점"
|
|
region:
|
|
type: string
|
|
description: 지역 (시/구/동)
|
|
example: "서울 강남구"
|
|
purpose:
|
|
type: string
|
|
description: 이벤트 목적
|
|
enum:
|
|
- 신규 고객 유치
|
|
- 재방문 유도
|
|
- 매출 증대
|
|
- 인지도 향상
|
|
example: "신규 고객 유치"
|
|
storeInfo:
|
|
$ref: "#/components/schemas/StoreInfo"
|
|
|
|
EventRecommendationRequest:
|
|
type: object
|
|
required:
|
|
- eventDraftId
|
|
- purpose
|
|
- industry
|
|
- region
|
|
- storeInfo
|
|
properties:
|
|
eventDraftId:
|
|
type: string
|
|
description: 이벤트 초안 ID
|
|
example: "evt_draft_001"
|
|
purpose:
|
|
type: string
|
|
description: 이벤트 목적
|
|
enum:
|
|
- 신규 고객 유치
|
|
- 재방문 유도
|
|
- 매출 증대
|
|
- 인지도 향상
|
|
example: "신규 고객 유치"
|
|
industry:
|
|
type: string
|
|
description: 업종
|
|
example: "음식점"
|
|
region:
|
|
type: string
|
|
description: 지역
|
|
example: "서울 강남구"
|
|
storeInfo:
|
|
$ref: "#/components/schemas/StoreInfo"
|
|
trendAnalysisJobId:
|
|
type: string
|
|
description: |
|
|
트렌드 분석 Job ID (선택)
|
|
- 제공 시 해당 트렌드 분석 결과 재사용
|
|
- 미제공 시 새로운 트렌드 분석 수행
|
|
example: "job_ai_20250122_001"
|
|
|
|
StoreInfo:
|
|
type: object
|
|
required:
|
|
- storeName
|
|
properties:
|
|
storeName:
|
|
type: string
|
|
description: 매장명
|
|
example: "맛있는 고깃집"
|
|
storeSize:
|
|
type: string
|
|
description: 매장 크기
|
|
enum:
|
|
- 소형
|
|
- 중형
|
|
- 대형
|
|
example: "중형"
|
|
monthlyRevenue:
|
|
type: integer
|
|
format: int64
|
|
description: 월 평균 매출 (원)
|
|
minimum: 0
|
|
example: 30000000
|
|
|
|
JobCreatedResponse:
|
|
type: object
|
|
required:
|
|
- jobId
|
|
- status
|
|
- message
|
|
properties:
|
|
jobId:
|
|
type: string
|
|
description: Job ID (폴링 조회용)
|
|
example: "job_ai_20250122_001"
|
|
status:
|
|
type: string
|
|
enum:
|
|
- PENDING
|
|
- PROCESSING
|
|
description: Job 상태
|
|
example: "PROCESSING"
|
|
message:
|
|
type: string
|
|
description: 상태 메시지
|
|
example: "트렌드 분석이 진행 중입니다"
|
|
estimatedCompletionTime:
|
|
type: string
|
|
format: date-time
|
|
description: 예상 완료 시간 (ISO 8601)
|
|
example: "2025-01-22T10:05:30Z"
|
|
|
|
TrendAnalysisJobResponse:
|
|
type: object
|
|
required:
|
|
- jobId
|
|
- status
|
|
- message
|
|
- createdAt
|
|
properties:
|
|
jobId:
|
|
type: string
|
|
description: Job ID
|
|
example: "job_ai_20250122_001"
|
|
status:
|
|
type: string
|
|
enum:
|
|
- PENDING
|
|
- PROCESSING
|
|
- COMPLETED
|
|
- FAILED
|
|
description: Job 상태
|
|
example: "COMPLETED"
|
|
message:
|
|
type: string
|
|
description: 상태 메시지
|
|
example: "트렌드 분석이 완료되었습니다"
|
|
progress:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 100
|
|
description: 진행률 (%)
|
|
example: 100
|
|
result:
|
|
$ref: "#/components/schemas/TrendAnalysisResult"
|
|
error:
|
|
$ref: "#/components/schemas/JobError"
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
description: Job 생성 시간
|
|
example: "2025-01-22T10:05:00Z"
|
|
estimatedCompletionTime:
|
|
type: string
|
|
format: date-time
|
|
description: 예상 완료 시간 (PROCESSING 상태일 때만)
|
|
example: "2025-01-22T10:05:30Z"
|
|
completedAt:
|
|
type: string
|
|
format: date-time
|
|
description: Job 완료 시간 (COMPLETED 상태일 때만)
|
|
example: "2025-01-22T10:05:25Z"
|
|
failedAt:
|
|
type: string
|
|
format: date-time
|
|
description: Job 실패 시간 (FAILED 상태일 때만)
|
|
example: "2025-01-22T10:05:45Z"
|
|
|
|
EventRecommendationJobResponse:
|
|
type: object
|
|
required:
|
|
- jobId
|
|
- status
|
|
- message
|
|
- createdAt
|
|
properties:
|
|
jobId:
|
|
type: string
|
|
description: Job ID
|
|
example: "job_ai_20250122_002"
|
|
status:
|
|
type: string
|
|
enum:
|
|
- PENDING
|
|
- PROCESSING
|
|
- COMPLETED
|
|
- FAILED
|
|
description: Job 상태
|
|
example: "COMPLETED"
|
|
message:
|
|
type: string
|
|
description: 상태 메시지
|
|
example: "이벤트 추천이 완료되었습니다"
|
|
progress:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 100
|
|
description: 진행률 (%)
|
|
example: 100
|
|
result:
|
|
$ref: "#/components/schemas/EventRecommendationResult"
|
|
error:
|
|
$ref: "#/components/schemas/JobError"
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
description: Job 생성 시간
|
|
example: "2025-01-22T10:05:00Z"
|
|
estimatedCompletionTime:
|
|
type: string
|
|
format: date-time
|
|
description: 예상 완료 시간 (PROCESSING 상태일 때만)
|
|
example: "2025-01-22T10:05:30Z"
|
|
completedAt:
|
|
type: string
|
|
format: date-time
|
|
description: Job 완료 시간 (COMPLETED 상태일 때만)
|
|
example: "2025-01-22T10:05:35Z"
|
|
failedAt:
|
|
type: string
|
|
format: date-time
|
|
description: Job 실패 시간 (FAILED 상태일 때만)
|
|
example: "2025-01-22T10:05:45Z"
|
|
|
|
TrendAnalysisResult:
|
|
type: object
|
|
required:
|
|
- industryTrends
|
|
- regionalCharacteristics
|
|
- seasonalPatterns
|
|
properties:
|
|
industryTrends:
|
|
$ref: "#/components/schemas/IndustryTrends"
|
|
regionalCharacteristics:
|
|
$ref: "#/components/schemas/RegionalCharacteristics"
|
|
seasonalPatterns:
|
|
$ref: "#/components/schemas/SeasonalPatterns"
|
|
|
|
IndustryTrends:
|
|
type: object
|
|
required:
|
|
- successfulEventTypes
|
|
- popularPrizes
|
|
- effectiveParticipationMethods
|
|
properties:
|
|
successfulEventTypes:
|
|
type: array
|
|
description: 최근 성공한 이벤트 유형 (최대 5개)
|
|
items:
|
|
type: object
|
|
required:
|
|
- type
|
|
- successRate
|
|
properties:
|
|
type:
|
|
type: string
|
|
description: 이벤트 유형
|
|
example: "할인 이벤트"
|
|
successRate:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 100
|
|
description: 성공률 (%)
|
|
example: 85
|
|
popularPrizes:
|
|
type: array
|
|
description: 고객 선호 경품 Top 5
|
|
items:
|
|
type: object
|
|
required:
|
|
- prize
|
|
- preferenceScore
|
|
properties:
|
|
prize:
|
|
type: string
|
|
description: 경품명
|
|
example: "커피 쿠폰"
|
|
preferenceScore:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 100
|
|
description: 선호도 점수
|
|
example: 92
|
|
effectiveParticipationMethods:
|
|
type: array
|
|
description: 효과적인 참여 방법
|
|
items:
|
|
type: object
|
|
required:
|
|
- method
|
|
- engagementRate
|
|
properties:
|
|
method:
|
|
type: string
|
|
description: 참여 방법
|
|
example: "간단한 설문조사"
|
|
engagementRate:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 100
|
|
description: 참여율 (%)
|
|
example: 75
|
|
|
|
RegionalCharacteristics:
|
|
type: object
|
|
required:
|
|
- successRate
|
|
- demographicProfile
|
|
properties:
|
|
successRate:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 100
|
|
description: 해당 지역 이벤트 성공률 (%)
|
|
example: 82
|
|
demographicProfile:
|
|
type: object
|
|
required:
|
|
- ageGroups
|
|
- genderDistribution
|
|
properties:
|
|
ageGroups:
|
|
type: array
|
|
description: 연령대별 분포
|
|
items:
|
|
type: object
|
|
required:
|
|
- range
|
|
- percentage
|
|
properties:
|
|
range:
|
|
type: string
|
|
description: 연령대
|
|
example: "20-29"
|
|
percentage:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 100
|
|
description: 비율 (%)
|
|
example: 35
|
|
genderDistribution:
|
|
type: object
|
|
required:
|
|
- male
|
|
- female
|
|
properties:
|
|
male:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 100
|
|
description: 남성 비율 (%)
|
|
example: 45
|
|
female:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 100
|
|
description: 여성 비율 (%)
|
|
example: 55
|
|
|
|
SeasonalPatterns:
|
|
type: object
|
|
required:
|
|
- currentSeason
|
|
- recommendedEventTypes
|
|
properties:
|
|
currentSeason:
|
|
type: string
|
|
description: 현재 계절
|
|
enum:
|
|
- 봄
|
|
- 여름
|
|
- 가을
|
|
- 겨울
|
|
example: "겨울"
|
|
recommendedEventTypes:
|
|
type: array
|
|
description: 계절별 추천 이벤트 유형
|
|
items:
|
|
type: string
|
|
example:
|
|
- "따뜻한 음료 할인"
|
|
- "연말 감사 이벤트"
|
|
specialOccasions:
|
|
type: array
|
|
description: 다가오는 특별 이벤트 (명절, 기념일 등)
|
|
items:
|
|
type: object
|
|
required:
|
|
- occasion
|
|
- daysUntil
|
|
properties:
|
|
occasion:
|
|
type: string
|
|
description: 특별 이벤트명
|
|
example: "설날"
|
|
daysUntil:
|
|
type: integer
|
|
description: 남은 일수
|
|
example: 15
|
|
|
|
EventRecommendationResult:
|
|
type: object
|
|
required:
|
|
- recommendations
|
|
properties:
|
|
recommendations:
|
|
type: array
|
|
description: 3가지 이벤트 추천안
|
|
minItems: 3
|
|
maxItems: 3
|
|
items:
|
|
$ref: "#/components/schemas/EventRecommendation"
|
|
|
|
EventRecommendation:
|
|
type: object
|
|
required:
|
|
- option
|
|
- title
|
|
- budget
|
|
- prize
|
|
- participationMethod
|
|
- estimatedParticipants
|
|
- estimatedROI
|
|
- promotionalTexts
|
|
- hashtags
|
|
properties:
|
|
option:
|
|
type: integer
|
|
description: 옵션 번호 (1, 2, 3)
|
|
enum: [1, 2, 3]
|
|
example: 1
|
|
title:
|
|
type: string
|
|
description: 이벤트 제목 (수정 가능)
|
|
maxLength: 50
|
|
example: "신규 고객 환영 커피 쿠폰 증정"
|
|
budget:
|
|
type: string
|
|
description: 예산 수준
|
|
enum:
|
|
- low
|
|
- medium
|
|
- high
|
|
example: "low"
|
|
prize:
|
|
type: object
|
|
required:
|
|
- name
|
|
- quantity
|
|
- estimatedCost
|
|
properties:
|
|
name:
|
|
type: string
|
|
description: 경품명 (수정 가능)
|
|
example: "아메리카노 쿠폰"
|
|
quantity:
|
|
type: integer
|
|
minimum: 1
|
|
description: 경품 수량
|
|
example: 100
|
|
estimatedCost:
|
|
type: integer
|
|
minimum: 0
|
|
description: 예상 비용 (원)
|
|
example: 300000
|
|
participationMethod:
|
|
type: object
|
|
required:
|
|
- type
|
|
- difficulty
|
|
- description
|
|
properties:
|
|
type:
|
|
type: string
|
|
description: 참여 방법 유형
|
|
example: "간단한 설문조사"
|
|
difficulty:
|
|
type: string
|
|
description: 난이도
|
|
enum:
|
|
- low
|
|
- medium
|
|
- high
|
|
example: "low"
|
|
description:
|
|
type: string
|
|
description: 참여 방법 상세 설명
|
|
example: "매장 방문 후 QR 코드 스캔 및 간단한 설문"
|
|
estimatedParticipants:
|
|
type: integer
|
|
minimum: 0
|
|
description: 예상 참여자 수
|
|
example: 150
|
|
estimatedROI:
|
|
type: integer
|
|
minimum: 0
|
|
description: 예상 투자 대비 수익률 (%)
|
|
example: 250
|
|
promotionalTexts:
|
|
type: array
|
|
description: 홍보 문구 (5개)
|
|
minItems: 5
|
|
maxItems: 5
|
|
items:
|
|
type: string
|
|
example:
|
|
- "따뜻한 커피 한 잔으로 시작하는 하루!"
|
|
- "신규 방문 고객님께 특별한 선물"
|
|
- "강남 최고의 고깃집에서 만나요"
|
|
- "지금 바로 참여하세요!"
|
|
- "한정 수량! 서두르세요!"
|
|
hashtags:
|
|
type: array
|
|
description: SNS 해시태그 (자동 생성)
|
|
items:
|
|
type: string
|
|
example:
|
|
- "#강남맛집"
|
|
- "#커피쿠폰"
|
|
- "#신규고객환영"
|
|
|
|
JobError:
|
|
type: object
|
|
required:
|
|
- code
|
|
- detail
|
|
properties:
|
|
code:
|
|
type: string
|
|
description: 에러 코드
|
|
enum:
|
|
- AI_API_ERROR
|
|
- TIMEOUT
|
|
- CIRCUIT_BREAKER_OPEN
|
|
- INVALID_PARAMETERS
|
|
- INTERNAL_ERROR
|
|
example: "AI_API_ERROR"
|
|
detail:
|
|
type: string
|
|
description: 에러 상세 메시지
|
|
example: "External AI API timeout after 30 seconds"
|
|
|
|
ErrorResponse:
|
|
type: object
|
|
required:
|
|
- error
|
|
- message
|
|
- timestamp
|
|
properties:
|
|
error:
|
|
type: string
|
|
description: 에러 타입
|
|
example: "BAD_REQUEST"
|
|
message:
|
|
type: string
|
|
description: 에러 메시지
|
|
example: "필수 파라미터가 누락되었습니다"
|
|
details:
|
|
type: array
|
|
description: 상세 에러 정보
|
|
items:
|
|
type: object
|
|
properties:
|
|
field:
|
|
type: string
|
|
description: 에러 필드
|
|
example: "industry"
|
|
message:
|
|
type: string
|
|
description: 필드별 에러 메시지
|
|
example: "업종은 필수 입력 항목입니다"
|
|
timestamp:
|
|
type: string
|
|
format: date-time
|
|
description: 에러 발생 시간
|
|
example: "2025-01-22T10:05:00Z"
|
|
|
|
responses:
|
|
BadRequest:
|
|
description: 잘못된 요청
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
example:
|
|
error: "BAD_REQUEST"
|
|
message: "필수 파라미터가 누락되었습니다"
|
|
details:
|
|
- field: "industry"
|
|
message: "업종은 필수 입력 항목입니다"
|
|
timestamp: "2025-01-22T10:05:00Z"
|
|
|
|
Unauthorized:
|
|
description: 인증 실패
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
example:
|
|
error: "UNAUTHORIZED"
|
|
message: "유효하지 않은 인증 토큰입니다"
|
|
timestamp: "2025-01-22T10:05:00Z"
|
|
|
|
NotFound:
|
|
description: 리소스를 찾을 수 없음
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
example:
|
|
error: "NOT_FOUND"
|
|
message: "Job을 찾을 수 없습니다"
|
|
timestamp: "2025-01-22T10:05:00Z"
|
|
|
|
TooManyRequests:
|
|
description: 요청 제한 초과
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
example:
|
|
error: "TOO_MANY_REQUESTS"
|
|
message: "요청 제한을 초과했습니다. 잠시 후 다시 시도해주세요"
|
|
timestamp: "2025-01-22T10:05:00Z"
|
|
headers:
|
|
Retry-After:
|
|
description: 재시도 가능 시간 (초)
|
|
schema:
|
|
type: integer
|
|
example: 60
|
|
|
|
InternalServerError:
|
|
description: 서버 내부 오류
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
example:
|
|
error: "INTERNAL_SERVER_ERROR"
|
|
message: "서버 내부 오류가 발생했습니다"
|
|
timestamp: "2025-01-22T10:05:00Z"
|