---
scope: task
task_id: ops-naver-sa-collect-260829
date: 2026-08-29
owner: dev2 (오딘)
type: ops-run
---

# 네이버 검색광고 SA 성과 수집 (스케줄 실행)

## 1. 지시 사항
`python3 /home/jay/workspace/tools/naver-ads/collect_sa_stats.py --days 7` 실행 후
`/home/jay/workspace/dashboard/data/naver-sa-stats.json` 저장 확인.

## 2. 실행 결과 — 지시 범위는 100% 완료

| 항목 | 결과 |
|---|---|
| 스크립트 실행 | exit 0, 에러 로그 없음 |
| 저장 파일 | `/home/jay/workspace/dashboard/data/naver-sa-stats.json` |
| md5 (실행 전 → 후) | `068c148f…` → `ca73ac3f…` (갱신 확인) |
| mtime | 2026-08-29 02:00:32 KST |
| JSON 유효성 | `json.load()` 통과 |
| `last_collected` | `2026-08-29T02:00:32+09:00` |
| daily_trend | 7행 (2026-08-23 ~ 2026-08-29) |

## 3. ★ 그러나 수집된 지표는 전부 0 — 원인 규명 완료

`today / yesterday / daily_trend / keyword_groups / budget.spent_today` 전 항목 0.

### 원인 A (주원인, 확정) — 조회 대상이 실계정이 아닌 **네이버 SA 샘플 계정**

`customer_id=1419414` 의 캠페인 실측:

| nccCampaignId | 이름 | 등록일 | totalChargeCost | status |
|---|---|---|---|---|
| cmp-a001-01-…1647137 | 전국민 꿀잠 프로젝트! "나이스드림" | 2018-12-19 | **0** | ELIGIBLE |
| cmp-a001-02-…1684254 | 나이스드림 쇼핑검색#1 | 2019-01-09 | **0** | PAUSED(그룹) |

- "나이스드림"은 네이버 검색광고 API **공식 예제 계정**의 샘플 캠페인명.
- 두 캠페인 모두 **2018~2019년 등록 후 editTm 이래 무변경, 누적 과금 0원**.
- `/stats` 원시 응답 = `{"data": [], "compTm": "202608290142"}` → **API 자체가 빈 배열**.
  즉 파싱 버그가 아니라 **해당 계정에 집행 데이터가 실제로 없음**.
- 광고그룹 실측 2개(`…_광고그룹#1` 2건)뿐 → 코드가 기대하는
  `보험영업 / 개인사업·지점장 / 무자본창업` 광고그룹은 **존재하지 않음**.

**결론: 스크립트는 정상 동작 중이며, 바라보는 광고 계정이 실계정이 아니다.**
`.env.keys` 의 `NAVER_SEARCHAD_CUSTOMER_ID / API_KEY / SECRET_KEY` 를 실제 집행 계정으로
교체하지 않는 한 이 파일은 영구히 0을 유지한다.

### 원인 B (코드 결함, 확정) — `keyword_groups` 는 **구조적으로 항상 0**

`collect_sa_stats.py` 실측:
- L82·L94 `adgroup_group_map` 를 만들지만 **이후 참조 0건**
- L99 `group_agg` 초기화 → L170 읽기. **증가 연산이 코드 어디에도 없음**

→ 설령 실계정으로 바꿔 데이터가 들어와도 `keyword_groups` 3개 항목은 **계속 0**.
데이터 문제와 무관한 별개의 버그.

### 원인 C (잠재 결함, 데이터 없어 실증 불가)
`client.get_stats()` 호출 시 `breakdown` 미지정인데, 집계 루프는 `record.get("date","")` 로
일자를 읽는다. 네이버 `/stats` 는 breakdown 없이는 기간 합산 행을 주므로 `date` 키가 없을 수 있고,
그 경우 `daily_trend`·`today`·`yesterday` 가 **데이터가 있어도 전부 0**이 된다.
현재 `data:[]` 라 실증 불가 → 실계정 전환 시 최우선 확인 대상.

## 4. ★ 스케줄이 101회 "성공" 보고해 온 문제

스케줄 `BFA48D87` (매일 02:00) 실행 이력: **총 112회 / status=ok 101회**.
전부 0 데이터를 저장하고도 `ok` 로 보고 → 대시보드 관점에서 **101회 연속 조용한 실패**.
`collect_sa_stats.py` 는 API 실패 시에도 `_empty_output()` 을 저장하고 **exit 0** 으로 끝나,
"저장 성공"과 "수집 성공"이 구분되지 않는다.

## 5. 회장님/아누 판단 필요 (범위 밖 — 코드 수정 없이 보고만)

1. **실광고 계정 자격증명 교체** — 최우선. 이것 없이는 나머지가 무의미.
2. `keyword_groups` 집계 로직 구현 (원인 B) — 별도 task 필요.
3. `breakdown=day` 지정 (원인 C) — 실계정 전환과 동시 검증 필요.
4. 수집 0건 시 **비-0 exit code + 경보** — 101회 침묵 재발 방지.

※ 본 실행은 "수집 실행 + 저장 확인" 지시 범위에 한정하여 **코드 0줄 수정**했다.
