테마
Story: E-12-S-05 제외키워드 관리 API
메타
| 항목 | 값 |
|---|---|
| Story ID | E-12-S-05 |
| Epic | E-12 Keyword Analysis |
| 상태 | backlog |
| 우선순위 | P0 |
| 규모 | S (1pt) |
| 담당 | BE (하록) |
| 의존성 | 없음 |
사용자 스토리
As a 검토가 필요한 키워드를 발견한 셀러, I want 제외할 키워드를 장사왕에 등록/관리, So that 쿠팡에 등록할 제외키워드 목록을 체계적으로 관리할 수 있다.
수락 기준 (Acceptance Criteria)
AC-01: 제외키워드 등록
| 항목 | 내용 |
|---|---|
| Given | 셀러가 전체 키워드 탭에서 키워드를 선택함 |
| When | 제외키워드 등록 API 호출 (campaignId, keywords[]) |
| Then | 해당 키워드들이 제외키워드로 등록됨 |
AC-02: 제외키워드 목록 조회
| 항목 | 내용 |
|---|---|
| Given | 캠페인에 제외키워드가 등록되어 있음 |
| When | 제외키워드 목록 API 호출 (campaignId) |
| Then | 등록된 제외키워드 목록 반환 (키워드명, 등록일, 성과 데이터) |
AC-03: 제외키워드 해제
| 항목 | 내용 |
|---|---|
| Given | 셀러가 제외키워드 탭에서 키워드를 선택함 |
| When | 제외키워드 해제 API 호출 (campaignId, keywords[]) |
| Then | 해당 키워드들이 제외키워드에서 해제됨 |
AC-04: 중복 등록 방지
| 항목 | 내용 |
|---|---|
| Given | 이미 제외키워드로 등록된 키워드 |
| When | 같은 키워드를 다시 등록 시도 |
| Then | 무시 (에러 없이 성공 응답, 중복 방지) |
태스크 분해
Task 1: DB 스키마 AC-01, AC-02, AC-03
- [ ] 1.1: ExcludedKeyword 테이블 생성 (vendorId, campaignId, keyword, createdAt)
- [ ] 1.2: 복합 유니크 인덱스 (vendorId, campaignId, keyword)
Task 2: 제외키워드 등록 API AC-01, AC-04
- [ ] 2.1: POST
/ads/campaign/{campaignId}/excluded-keywords엔드포인트 - [ ] 2.2: 벌크 등록 지원 (keywords[])
- [ ] 2.3: 중복 시 무시 (UPSERT)
Task 3: 제외키워드 목록 조회 API AC-02
- [ ] 3.1: GET
/ads/campaign/{campaignId}/excluded-keywords엔드포인트 - [ ] 3.2: 성과 데이터 조인 (CoupangAdKeywordDaily)
Task 4: 제외키워드 해제 API AC-03
- [ ] 4.1: DELETE
/ads/campaign/{campaignId}/excluded-keywords엔드포인트 - [ ] 4.2: 벌크 삭제 지원 (keywords[])
Dev Notes
API 스펙
제외키워드 등록
typescript
POST /ads/campaign/{campaignId}/excluded-keywords
Request:
{
keywords: string[] // ["봄신상", "여름특가", "할인세일"]
}
Response:
{
success: true,
addedCount: number, // 신규 등록된 수
skippedCount: number // 중복으로 스킵된 수
}제외키워드 목록 조회
typescript
GET /ads/campaign/{campaignId}/excluded-keywords?startDt=&endDt=
Response:
{
totalCount: number,
dataList: [{
keyword: string,
createdAt: string, // 등록일
impressions: number, // 기간 내 성과 (optional)
clicks: number,
adCost: number,
netProfit: number | null
}]
}제외키워드 해제
typescript
DELETE /ads/campaign/{campaignId}/excluded-keywords
Request:
{
keywords: string[]
}
Response:
{
success: true,
removedCount: number
}DB 스키마
sql
CREATE TABLE ExcludedKeyword (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
vendorId VARCHAR(50) NOT NULL,
campaignId VARCHAR(50) NOT NULL,
keyword VARCHAR(255) NOT NULL,
createdAt DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE INDEX idx_excluded_keyword (vendorId, campaignId, keyword)
);참고 구현
| 항목 | 경로 |
|---|---|
| 기존 캠페인 API | backend/src/ads/campaign/ |
충돌 감지
| 항목 | 상태 | 설명 |
|---|---|---|
| 기존 코드 충돌 | ✅ 없음 | 신규 엔드포인트 |
| DB 스키마 변경 | ⚠️ 주의 | 신규 테이블 생성 필요 |
References
| 출처 | 경로/링크 | 참조 섹션 |
|---|---|---|
| Epic Spec | epic-specs/E-12-keyword-analysis.md | 로직 5: 제외키워드 관리 |
핸드오프 전 체크리스트
- [x] 사용자 스토리가 명확한가?
- [x] 수락 기준이 Given-When-Then 형식인가?
- [x] API 스펙이 정의되었는가?
- [x] DB 스키마가 명시되었는가?
검증 결과: ✅ PASS 검증일: 2026-01-28
생성일: 2026-01-28생성자: 📋 Penny
