테마
Story: AI 진단 API + 캐싱
메타
| 항목 | 값 |
|---|---|
| Story ID | E-04-S-02 |
| Epic | E-04 AI 진단 엔진 |
| 상태 | draft |
| 우선순위 | P0 |
| 규모 | M |
| 담당 개발자 | BE (하록님) |
사용자 스토리
As a Pro10+ 셀러, I want 캠페인별 AI 진단 결과를 받는 API, So that 복잡한 광고 상황을 쉽게 이해하고 행동할 수 있다.
수락 기준 (Acceptance Criteria)
AC-01: AI 진단 API 엔드포인트
| 항목 | 내용 |
|---|---|
| Given | Pro10+ 셀러가 Surface Layer 조회 |
| When | 캠페인 진단 요청 |
| Then | AI 진단 결과 반환 |
API 스펙:
GET /api/v1/campaigns/:campaignId/diagnosis
Response:
{
"campaignId": "camp_123",
"badge": "🟡",
"diagnosis": "최근 7일간 ROAS가 180% → 150%로 하락...",
"suggestion": {
"type": "bid_reduction",
"action": "비검색 입찰가 15% 인하",
"expectedEffect": "순이익 +12% 예상"
},
"source": "ai" | "rule", // AI 생성 vs 규칙 기반
"cachedAt": "2026-01-27T10:00:00Z" | null
}AC-02: 캐시 히트
| 항목 | 내용 |
|---|---|
| Given | 동일 캠페인 진단 요청 (24시간 이내) |
| When | API 호출 |
| Then | 캐시된 결과 즉시 반환 (LLM 호출 없음) |
캐시 키: diagnosis:{vendorId}:{campaignId}:{dataDate}TTL: 24시간
AC-03: 캐시 미스 → LLM 호출
| 항목 | 내용 |
|---|---|
| Given | 캐시 없음 또는 만료 |
| When | API 호출 |
| Then | LLM 호출 → 결과 캐시 저장 → 반환 |
플로우:
1. 캐시 확인 → Miss
2. 셀러 컨텍스트 로드
3. 캠페인 데이터 조회
4. LLM API 호출 (E-04-S-01)
5. 응답 파싱 + 검증
6. 캐시 저장
7. 응답 반환AC-04: 폴백 처리
| 항목 | 내용 |
|---|---|
| Given | LLM API 실패 또는 타임아웃 |
| When | 진단 요청 |
| Then | 규칙 기반 폴백 결과 반환 (source: "rule") |
폴백 규칙:
if ROAS < 100% → 🔴 "광고비가 매출보다 많아요"
else if ROAS < 200% → 🟡 "효율 개선이 필요해요"
else → 🟢 "잘 운영되고 있어요"태스크 분해
Task 1: API 엔드포인트 AC-01
- [ ] 1.1:
GET /campaigns/:campaignId/diagnosis라우트 생성 - [ ] 1.2: 요청 검증 (campaignId, 권한)
- [ ] 1.3: 응답 DTO 정의
Task 2: 캐싱 레이어 AC-02 AC-03
- [ ] 2.1: 캐시 테이블 생성 (또는 기존 활용)
- [ ] 2.2: 캐시 키 생성 로직
- [ ] 2.3: 캐시 조회/저장 함수
- [ ] 2.4: TTL 관리
Task 3: 진단 생성 로직 AC-03
- [ ] 3.1: 셀러 컨텍스트 로드
- [ ] 3.2: 캠페인 데이터 조회
- [ ] 3.3: LLM 엔진 호출 (E-04-S-01)
- [ ] 3.4: 결과 조합 및 반환
Task 4: 폴백 로직 AC-04
- [ ] 4.1: 규칙 기반 진단 함수
- [ ] 4.2: 에러 핸들링 + 폴백 트리거
- [ ] 4.3: 로깅 (폴백 발생 시)
Task 5: 테스트
- [ ] 5.1: 캐시 히트/미스 테스트
- [ ] 5.2: 폴백 테스트
- [ ] 5.3: E2E 테스트
Dev Notes (AI Agent 최적화)
영향 받는 소스 트리
src/
├── campaigns/
│ ├── campaigns.controller.ts # 🔧 수정 (진단 엔드포인트)
│ └── diagnosis/
│ ├── diagnosis.service.ts # 🆕 진단 서비스
│ ├── diagnosis.cache.ts # 🆕 캐싱 로직
│ └── diagnosis.fallback.ts # 🆕 폴백 로직
├── ai/
│ └── (E-04-S-01에서 생성)
└── tests/
└── campaigns/
└── diagnosis.spec.ts # 🆕 테스트캐시 테이블 스키마 (예시)
sql
CREATE TABLE AIDiagnosisCache (
id INT PRIMARY KEY AUTO_INCREMENT,
vendorId VARCHAR(50) NOT NULL,
campaignId VARCHAR(50) NOT NULL,
dataDate DATE NOT NULL,
badge VARCHAR(10) NOT NULL,
diagnosis TEXT NOT NULL,
suggestionType VARCHAR(50),
suggestionAction TEXT,
suggestionEffect TEXT,
source ENUM('ai', 'rule') NOT NULL,
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
expiresAt TIMESTAMP NOT NULL,
UNIQUE KEY uk_diagnosis (vendorId, campaignId, dataDate),
INDEX idx_expires (expiresAt)
);충돌 감지
| 항목 | 상태 | 설명 |
|---|---|---|
| 기존 코드 충돌 | 🟡 주의 | campaigns.controller.ts 수정 |
| DB 스키마 변경 | 🟡 추가 | 캐시 테이블 생성 필요 |
의존성
| 의존 | 설명 | 상태 |
|---|---|---|
| E-04-S-01 | LLM 클라이언트 & 프롬프트 엔진 | 선행 필요 |
Dev Agent Record
| 항목 | 값 |
|---|---|
| 생성 Agent | Claude Opus 4.5 |
| 생성일 | 2026-01-27 |
| 마지막 수정 | 2026-01-27 |
| 검증자 | - |
검증 결과: 🔄 PENDING (PO 승인 대기) 검증일: -
생성일: 2026-01-27마지막 수정: 2026-01-27
