kt-event-marketing/design/backend/api/ai-service-api.yaml
cherry2250 6b1c4224f7 7개 마이크로서비스 API 명세서 컨벤션 통일
- 공통 OpenAPI 3.0.3 컨벤션 문서 작성 (design/backend/api/API_CONVENTION.md)
- 7개 서비스 API 명세서 표준화 완료:
  * User Service (8081)
  * Event Service (8080)
  * Content Service (8082)
  * AI Service (8083)
  * Participation Service (8084)
  * Distribution Service (8085)
  * Analytics Service (8086)

주요 변경사항:
- API 경로에서 /api prefix 제거 (/api/users → /users)
- 서버 URL 패턴 통일 (Local → Dev → Prod)
- 연락처 정보 표준화 (Digital Garage Team)
- ErrorResponse 스키마 통일 (error → message, details 추가)
- securitySchemes 이름 통일 (BearerAuth)
- 포트 번호 명확히 할당

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-23 17:12:28 +09:00

850 lines
26 KiB
YAML

openapi: 3.0.3
info:
title: AI Service API
description: |
KT AI 기반 소상공인 이벤트 자동 생성 서비스 - AI Service
## 서비스 개요
- Kafka를 통한 비동기 AI 추천 처리
- Claude API / GPT-4 API 연동
- Redis 기반 결과 캐싱 (TTL 24시간)
## 처리 흐름
1. Event Service가 Kafka Topic에 Job 메시지 발행
2. AI Service가 메시지 구독 및 처리
3. 트렌드 분석 수행 (Claude/GPT-4 API)
4. 3가지 이벤트 추천안 생성
5. 결과를 Redis에 저장 (TTL 24시간)
6. Job 상태를 Redis에 업데이트
## 외부 API 통합
- **Claude API / GPT-4 API**: 트렌드 분석 및 이벤트 추천
- **Circuit Breaker**: 5분 타임아웃, Fallback to 캐시
- **Retry**: 최대 3회, Exponential Backoff
version: 1.0.0
contact:
name: Digital Garage Team
email: support@kt-event-marketing.com
servers:
- url: http://localhost:8083
description: Local Development Server
- url: https://dev-api.kt-event-marketing.com/ai/v1
description: Development Server
- url: https://api.kt-event-marketing.com/ai/v1
description: Production Server
tags:
- name: Health Check
description: 서비스 상태 확인
- name: Internal API
description: 내부 서비스 간 통신용 API
- name: Kafka Consumer
description: 비동기 작업 처리 (문서화만)
paths:
/health:
get:
tags:
- Health Check
summary: 서비스 헬스체크
description: AI Service 상태 및 외부 연동 확인
operationId: healthCheck
x-user-story: System
x-controller: HealthController
responses:
'200':
description: 서비스 정상
content:
application/json:
schema:
$ref: '#/components/schemas/HealthCheckResponse'
example:
status: UP
timestamp: "2025-10-23T10:30:00Z"
services:
kafka: UP
redis: UP
claude_api: UP
gpt4_api: UP
circuit_breaker: CLOSED
/internal/jobs/{jobId}/status:
get:
tags:
- Internal API
summary: 작업 상태 조회
description: Redis에 저장된 AI 추천 작업 상태 조회 (Event Service에서 호출)
operationId: getJobStatus
x-user-story: UFR-AI-010
x-controller: InternalJobController
parameters:
- name: jobId
in: path
required: true
schema:
type: string
description: Job ID
example: "job-ai-evt001-20251023103000"
responses:
'200':
description: 작업 상태 조회 성공
content:
application/json:
schema:
$ref: '#/components/schemas/JobStatusResponse'
examples:
processing:
summary: 처리 중
value:
jobId: "job-ai-evt001-20251023103000"
status: "PROCESSING"
progress: 50
message: "AI 추천 생성 중"
createdAt: "2025-10-23T10:30:00Z"
startedAt: "2025-10-23T10:30:05Z"
completed:
summary: 완료
value:
jobId: "job-ai-evt001-20251023103000"
status: "COMPLETED"
progress: 100
message: "AI 추천 완료"
createdAt: "2025-10-23T10:30:00Z"
startedAt: "2025-10-23T10:30:05Z"
completedAt: "2025-10-23T10:35:00Z"
processingTimeMs: 295000
failed:
summary: 실패
value:
jobId: "job-ai-evt001-20251023103000"
status: "FAILED"
progress: 0
message: "Claude API timeout"
errorMessage: "Claude API timeout after 5 minutes"
createdAt: "2025-10-23T10:30:00Z"
startedAt: "2025-10-23T10:30:05Z"
failedAt: "2025-10-23T10:35:05Z"
retryCount: 3
'404':
$ref: '#/components/responses/NotFound'
'500':
$ref: '#/components/responses/InternalServerError'
/internal/recommendations/{eventId}:
get:
tags:
- Internal API
summary: AI 추천 결과 조회
description: Redis에 캐시된 AI 추천 결과 조회 (Event Service에서 호출)
operationId: getRecommendation
x-user-story: UFR-AI-010
x-controller: InternalRecommendationController
parameters:
- name: eventId
in: path
required: true
schema:
type: string
description: 이벤트 ID
example: "evt-001"
responses:
'200':
description: 추천 결과 조회 성공
content:
application/json:
schema:
$ref: '#/components/schemas/AIRecommendationResult'
example:
eventId: "evt-001"
trendAnalysis:
industryTrends:
- keyword: "프리미엄 디저트"
relevance: 0.85
description: "고급 디저트 카페 트렌드 증가"
regionalTrends:
- keyword: "핫플레이스"
relevance: 0.78
description: "강남 신논현역 주변 유동인구 증가"
seasonalTrends:
- keyword: "가을 시즌"
relevance: 0.92
description: "가을 시즌 한정 메뉴 선호도 증가"
recommendations:
- optionNumber: 1
concept: "프리미엄 경험형"
title: "가을 한정 시그니처 디저트 페어링 이벤트"
description: "가을 제철 재료를 활용한 시그니처 디저트와 음료 페어링 체험"
targetAudience: "20-30대 여성, SNS 활동적인 고객"
duration:
recommendedDays: 14
recommendedPeriod: "10월 중순 ~ 11월 초"
mechanics:
type: "EXPERIENCE"
details: "디저트+음료 페어링 세트 주문 시 인스타그램 업로드 고객에게 다음 방문 시 사용 가능한 10% 할인권 제공"
promotionChannels:
- "Instagram"
- "카카오톡 채널"
- "네이버 플레이스"
estimatedCost:
min: 300000
max: 500000
breakdown:
material: 200000
promotion: 150000
discount: 150000
expectedMetrics:
newCustomers:
min: 50
max: 80
repeatVisits:
min: 30
max: 50
revenueIncrease:
min: 15.0
max: 25.0
roi:
min: 120.0
max: 180.0
socialEngagement:
estimatedPosts: 100
estimatedReach: 5000
differentiator: "프리미엄 경험 제공으로 고객 만족도와 SNS 바이럴 효과 극대화"
generatedAt: "2025-10-23T10:35:00Z"
expiresAt: "2025-10-24T10:35:00Z"
aiProvider: "CLAUDE"
'404':
$ref: '#/components/responses/NotFound'
'500':
$ref: '#/components/responses/InternalServerError'
components:
schemas:
# ==================== Health Check ====================
HealthCheckResponse:
type: object
description: 서비스 헬스체크 응답
required:
- status
- timestamp
- services
properties:
status:
type: string
enum: [UP, DOWN, DEGRADED]
description: 전체 서비스 상태
example: UP
timestamp:
type: string
format: date-time
description: 체크 시각
example: "2025-10-23T10:30:00Z"
services:
type: object
description: 개별 서비스 상태
required:
- kafka
- redis
- claude_api
- circuit_breaker
properties:
kafka:
type: string
enum: [UP, DOWN]
description: Kafka 연결 상태
example: UP
redis:
type: string
enum: [UP, DOWN]
description: Redis 연결 상태
example: UP
claude_api:
type: string
enum: [UP, DOWN, CIRCUIT_OPEN]
description: Claude API 상태
example: UP
gpt4_api:
type: string
enum: [UP, DOWN, CIRCUIT_OPEN]
description: GPT-4 API 상태 (선택)
example: UP
circuit_breaker:
type: string
enum: [CLOSED, OPEN, HALF_OPEN]
description: Circuit Breaker 상태
example: CLOSED
# ==================== Kafka Job Message (문서화만) ====================
KafkaAIJobMessage:
type: object
description: |
**Kafka Topic**: `ai-event-generation-job`
**Consumer Group**: `ai-service-consumers`
**처리 방식**: 비동기
**최대 처리 시간**: 5분
AI 이벤트 생성 요청 메시지
required:
- jobId
- eventId
- objective
- industry
- region
properties:
jobId:
type: string
description: Job 고유 ID
example: "job-ai-evt001-20251023103000"
eventId:
type: string
description: 이벤트 ID (Event Service에서 생성)
example: "evt-001"
objective:
type: string
description: 이벤트 목적
enum:
- "신규 고객 유치"
- "재방문 유도"
- "매출 증대"
- "브랜드 인지도 향상"
example: "신규 고객 유치"
industry:
type: string
description: 업종
example: "음식점"
region:
type: string
description: 지역 (시/구/동)
example: "서울 강남구"
storeName:
type: string
description: 매장명 (선택)
example: "맛있는 고깃집"
targetAudience:
type: string
description: 목표 고객층 (선택)
example: "20-30대 여성"
budget:
type: integer
description: 예산 (원) (선택)
example: 500000
requestedAt:
type: string
format: date-time
description: 요청 시각
example: "2025-10-23T10:30:00Z"
# ==================== AI Recommendation Result ====================
AIRecommendationResult:
type: object
description: |
**Redis Key**: `ai:recommendation:{eventId}`
**TTL**: 86400초 (24시간)
AI 이벤트 추천 결과
required:
- eventId
- trendAnalysis
- recommendations
- generatedAt
- aiProvider
properties:
eventId:
type: string
description: 이벤트 ID
example: "evt-001"
trendAnalysis:
$ref: '#/components/schemas/TrendAnalysis'
recommendations:
type: array
description: 추천 이벤트 기획안 (3개)
minItems: 3
maxItems: 3
items:
$ref: '#/components/schemas/EventRecommendation'
generatedAt:
type: string
format: date-time
description: 생성 시각
example: "2025-10-23T10:35:00Z"
expiresAt:
type: string
format: date-time
description: 캐시 만료 시각 (생성 시각 + 24시간)
example: "2025-10-24T10:35:00Z"
aiProvider:
type: string
enum: [CLAUDE, GPT4]
description: 사용된 AI 제공자
example: "CLAUDE"
TrendAnalysis:
type: object
description: 트렌드 분석 결과 (업종/지역/시즌)
required:
- industryTrends
- regionalTrends
- seasonalTrends
properties:
industryTrends:
type: array
description: 업종 트렌드 키워드 (최대 5개)
maxItems: 5
items:
type: object
required:
- keyword
- relevance
- description
properties:
keyword:
type: string
description: 트렌드 키워드
example: "프리미엄 디저트"
relevance:
type: number
format: float
minimum: 0
maximum: 1
description: 연관도 (0-1)
example: 0.85
description:
type: string
description: 트렌드 설명
example: "고급 디저트 카페 트렌드 증가"
regionalTrends:
type: array
description: 지역 트렌드 키워드 (최대 5개)
maxItems: 5
items:
type: object
required:
- keyword
- relevance
- description
properties:
keyword:
type: string
example: "핫플레이스"
relevance:
type: number
format: float
minimum: 0
maximum: 1
example: 0.78
description:
type: string
example: "강남 신논현역 주변 유동인구 증가"
seasonalTrends:
type: array
description: 시즌 트렌드 키워드 (최대 5개)
maxItems: 5
items:
type: object
required:
- keyword
- relevance
- description
properties:
keyword:
type: string
example: "가을 시즌"
relevance:
type: number
format: float
minimum: 0
maximum: 1
example: 0.92
description:
type: string
example: "가을 시즌 한정 메뉴 선호도 증가"
EventRecommendation:
type: object
description: 이벤트 추천안 (차별화된 3가지 옵션)
required:
- optionNumber
- concept
- title
- description
- targetAudience
- duration
- mechanics
- promotionChannels
- estimatedCost
- expectedMetrics
- differentiator
properties:
optionNumber:
type: integer
description: 옵션 번호 (1-3)
minimum: 1
maximum: 3
example: 1
concept:
type: string
description: 이벤트 컨셉
example: "프리미엄 경험형"
title:
type: string
description: 이벤트 제목
maxLength: 100
example: "가을 한정 시그니처 디저트 페어링 이벤트"
description:
type: string
description: 이벤트 설명
maxLength: 500
example: "가을 제철 재료를 활용한 시그니처 디저트와 음료 페어링 체험"
targetAudience:
type: string
description: 목표 고객층
example: "20-30대 여성, SNS 활동적인 고객"
duration:
type: object
description: 이벤트 기간
required:
- recommendedDays
properties:
recommendedDays:
type: integer
description: 권장 진행 일수
minimum: 1
example: 14
recommendedPeriod:
type: string
description: 권장 진행 시기
example: "10월 중순 ~ 11월 초"
mechanics:
type: object
description: 이벤트 메커니즘
required:
- type
- details
properties:
type:
type: string
enum: [DISCOUNT, GIFT, STAMP, EXPERIENCE, LOTTERY, COMBO]
description: 이벤트 유형
example: "EXPERIENCE"
details:
type: string
description: 상세 메커니즘
maxLength: 500
example: "디저트+음료 페어링 세트 주문 시 인스타그램 업로드 고객에게 다음 방문 시 사용 가능한 10% 할인권 제공"
promotionChannels:
type: array
description: 추천 홍보 채널 (최대 5개)
maxItems: 5
items:
type: string
example:
- "Instagram"
- "카카오톡 채널"
- "네이버 플레이스"
estimatedCost:
type: object
description: 예상 비용
required:
- min
- max
properties:
min:
type: integer
description: 최소 비용 (원)
minimum: 0
example: 300000
max:
type: integer
description: 최대 비용 (원)
minimum: 0
example: 500000
breakdown:
type: object
description: 비용 구성
properties:
material:
type: integer
description: 재료비 (원)
example: 200000
promotion:
type: integer
description: 홍보비 (원)
example: 150000
discount:
type: integer
description: 할인 비용 (원)
example: 150000
expectedMetrics:
$ref: '#/components/schemas/ExpectedMetrics'
differentiator:
type: string
description: 다른 옵션과의 차별점
maxLength: 500
example: "프리미엄 경험 제공으로 고객 만족도와 SNS 바이럴 효과 극대화, 브랜드 이미지 향상에 집중"
ExpectedMetrics:
type: object
description: 예상 성과 지표
required:
- newCustomers
- revenueIncrease
- roi
properties:
newCustomers:
type: object
description: 신규 고객 수
required:
- min
- max
properties:
min:
type: integer
minimum: 0
example: 50
max:
type: integer
minimum: 0
example: 80
repeatVisits:
type: object
description: 재방문 고객 수 (선택)
properties:
min:
type: integer
minimum: 0
example: 30
max:
type: integer
minimum: 0
example: 50
revenueIncrease:
type: object
description: 매출 증가율 (%)
required:
- min
- max
properties:
min:
type: number
format: float
minimum: 0
example: 15.0
max:
type: number
format: float
minimum: 0
example: 25.0
roi:
type: object
description: ROI - 투자 대비 수익률 (%)
required:
- min
- max
properties:
min:
type: number
format: float
minimum: 0
example: 120.0
max:
type: number
format: float
minimum: 0
example: 180.0
socialEngagement:
type: object
description: SNS 참여도 (선택)
properties:
estimatedPosts:
type: integer
description: 예상 게시물 수
minimum: 0
example: 100
estimatedReach:
type: integer
description: 예상 도달 수
minimum: 0
example: 5000
# ==================== Job Status ====================
JobStatusResponse:
type: object
description: |
**Redis Key**: `ai:job:status:{jobId}`
**TTL**: 86400초 (24시간)
작업 상태 응답
required:
- jobId
- status
- progress
- message
- createdAt
properties:
jobId:
type: string
description: Job ID
example: "job-ai-evt001-20251023103000"
status:
type: string
enum: [PENDING, PROCESSING, COMPLETED, FAILED]
description: 작업 상태
example: "COMPLETED"
progress:
type: integer
minimum: 0
maximum: 100
description: 진행률 (%)
example: 100
message:
type: string
description: 상태 메시지
example: "AI 추천 완료"
eventId:
type: string
description: 이벤트 ID
example: "evt-001"
createdAt:
type: string
format: date-time
description: 작업 생성 시각
example: "2025-10-23T10:30:00Z"
startedAt:
type: string
format: date-time
description: 작업 시작 시각
example: "2025-10-23T10:30:05Z"
completedAt:
type: string
format: date-time
description: 작업 완료 시각 (완료 시)
example: "2025-10-23T10:35:00Z"
failedAt:
type: string
format: date-time
description: 작업 실패 시각 (실패 시)
example: "2025-10-23T10:35:05Z"
errorMessage:
type: string
description: 에러 메시지 (실패 시)
example: "Claude API timeout after 5 minutes"
retryCount:
type: integer
description: 재시도 횟수
minimum: 0
example: 0
processingTimeMs:
type: integer
description: 처리 시간 (밀리초)
minimum: 0
example: 295000
# ==================== Error Response ====================
ErrorResponse:
type: object
description: 에러 응답
required:
- code
- message
- timestamp
properties:
code:
type: string
description: 에러 코드
enum:
- AI_SERVICE_ERROR
- JOB_NOT_FOUND
- RECOMMENDATION_NOT_FOUND
- REDIS_ERROR
- KAFKA_ERROR
- CIRCUIT_BREAKER_OPEN
- INTERNAL_ERROR
example: "JOB_NOT_FOUND"
message:
type: string
description: 에러 메시지
example: "작업을 찾을 수 없습니다"
timestamp:
type: string
format: date-time
description: 에러 발생 시각
example: "2025-10-23T10:30:00Z"
details:
type: object
description: 추가 에러 상세
additionalProperties: true
example:
jobId: "job-ai-evt001-20251023103000"
responses:
NotFound:
description: 리소스를 찾을 수 없음
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
code: "JOB_NOT_FOUND"
message: "작업을 찾을 수 없습니다"
timestamp: "2025-10-23T10:30:00Z"
InternalServerError:
description: 서버 내부 오류
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
code: "INTERNAL_ERROR"
message: "서버 내부 오류가 발생했습니다"
timestamp: "2025-10-23T10:30:00Z"
# ==================== 기술 구성 문서화 ====================
x-technical-specifications:
circuit-breaker:
claude-api:
failureThreshold: 5
successThreshold: 2
timeout: 300000
resetTimeout: 60000
fallbackStrategy: CACHED_RECOMMENDATION
gpt4-api:
failureThreshold: 5
successThreshold: 2
timeout: 300000
resetTimeout: 60000
fallbackStrategy: CACHED_RECOMMENDATION
redis-cache:
patterns:
recommendation: "ai:recommendation:{eventId}"
jobStatus: "ai:job:status:{jobId}"
fallback: "ai:fallback:{industry}:{region}"
ttl:
recommendation: 86400
jobStatus: 86400
fallback: 604800
kafka:
topics:
input: "ai-event-generation-job"
consumer:
groupId: "ai-service-consumers"
maxRetries: 3
retryBackoffMs: 5000
maxPollRecords: 10
sessionTimeoutMs: 30000
external-apis:
claude:
endpoint: "https://api.anthropic.com/v1/messages"
model: "claude-3-5-sonnet-20241022"
maxTokens: 4096
timeout: 300000
gpt4:
endpoint: "https://api.openai.com/v1/chat/completions"
model: "gpt-4-turbo-preview"
maxTokens: 4096
timeout: 300000