네이버 블로그 매일 자동 포스팅 시스템 설계 v1
작성일: 2026-05-07 환경: vhagar (kontology, BOSGAME M4 Plus) + Galaxy S23+ (USB ADB, serial R3CW60BHSAT) 계정: 분유타는대표 (tidtyd222) — 1계정 MVP, 안정화 후 민지(wngmlxx12) 추가 LLM: Claude Sonnet 1M (OpenClaw 채널콘솔 계정토큰) 폰 자동화: droidrun/mobilerun (8.3K stars) 문서 버전: v1 (액션테스트 전). 테스트 후 v2로 업데이트 예정.
0. 진행 순서
| 단계 | 내용 | 상태 |
|---|---|---|
| v1 문서화 | 이 문서. 설계 전체를 문서로 확정 | 현재 |
| Phase 0: S23 액션테스트 | mobilerun 설치 → S23 실물 테스트 → 동작 검증 | 다음 |
| v2 문서화 | 액션테스트 결과 반영하여 스펙 수정 | Phase 0 후 |
| 코딩 | v2 스펙 기반으로 구현 | v2 확정 후 |
코딩은 v2 스펙 확정 전까지 하지 않는다.
1. 전체 아키텍처
┌─────────────────────────────────────────────────────────────────┐
│ systemd timer (매일 19:00 ± 랜덤 10분) │
│ │
│ ① keyword_engine 오늘의 키워드 선정 │
│ ↓ │
│ ② content_generator Sonnet 1M 원고 생성 (OpenClaw 채널콘솔) │
│ ↓ │
│ ③ seo_formatter SE 호환 HTML 변환 │
│ ↓ │
│ ④ phone_poster mobilerun → S23 Chrome → SE → 발행 │
│ ↓ │
│ ⑤ result_logger Supabase 로깅 + Telegram 알림 │
│ │
└─────────────────────────────────────────────────────────────────┘
1.1 왜 Sonnet 1M인가
| 항목 | DeepSeek V4 (이전안) | Sonnet 1M (현재안) |
|---|---|---|
| 한국어 품질 | 중상 | 최상 |
| 컨텍스트 | 128K | 1M — 전체 키워드 DB + 전략문서 + 기발행 히스토리 한번에 로드 |
| 비용 | $0.01~0.02/포스트 | $0 (구독 내 계정토큰) |
| 페르소나 일관성 | few-shot 필요 | 1M 윈도우에 기존 발행글 전부 넣어서 톤 학습 |
| Vision | 없음 | 있음 (mobilerun에서도 사용) |
핵심 변경: 앤트로픽이 OpenClaw 채널콘솔(계정로그인토큰)을 다시 허용. 구독 기반 auth로 Sonnet 1M 호출 가능 → API 과금 없음.
1.2 왜 mobilerun + S23인가
네이버 블로그에는 공개 포스팅 API가 없다. 모든 자동화 도구(AutoPanda, Gazet 등)가 브라우저 자동화로 SmartEditor를 조작한다.
mobilerun이 다른 방식보다 나은 이유:
- IP/핑거프린트: 실제 폰의 LTE/WiFi IP + 실제 디바이스 핑거프린트. 서버발 Selenium보다 안전
- 네이버 봇 탐지 회피: 실제 Chrome on Android. WebDriver 감지 없음
- 세션 관리: 폰 Chrome에 로그인 유지. 쿠키/세션 자연스럽게 유지
- vision + 접근성 트리: WebView 내부도 조작 가능
- LLM reasoning: UI 변경에 적응 가능 (하드코딩된 좌표 아님)
1.3 파일 구조
~/projects/naver-blog/
├── automation/
│ ├── __init__.py
│ ├── pipeline.py # 메인 오케스트레이터
│ ├── keyword_engine.py # 키워드 선정
│ ├── content_generator.py # 원고 생성 (Sonnet 1M)
│ ├── seo_formatter.py # SE 호환 HTML 변환
│ ├── phone_poster.py # mobilerun S23 포스팅
│ └── result_logger.py # Supabase 로깅
├── templates/
│ ├── info_post.jinja2 # 정보성 글 프롬프트
│ └── daily_post.jinja2 # 일상 글 프롬프트
├── config/
│ ├── accounts.yaml # 계정별 설정 (페르소나/시간대/키워드풀)
│ ├── keywords_used.json # 사용된 키워드 이력 (날짜, 카테고리)
│ └── .env # API 키 (gitignore)
├── account_01_분유타는대표/
│ ├── drafts/ # 생성된 원고 (.md)
│ ├── published/ # 발행 완료 (날짜_키워드.md + .html)
│ ├── queue/ # 발행 대기 / needs_review
│ └── images/ # Phase 2: 이미지 자산
├── research/ # 기존 키워드 분석 데이터
│ └── keyword-analysis/ # 1,638개 키워드 DB
├── docs/
│ └── specs/ # 이 문서
├── tests/ # Phase 0 액션테스트 스크립트
│ ├── test_mobilerun_basic.py # mobilerun 기본 동작
│ ├── test_naver_se_paste.py # SE 에디터 HTML paste
│ └── test_e2e_post.py # 전체 플로우 E2E
└── .venv/ # Python 가상환경
2. LLM 연동: OpenClaw 채널콘솔
2.1 채널콘솔이란
- OpenClaw MCP Server (Lightsail 43.203.12.112:8765)가 Claude API를 호출할 때 사용하는 인증 경로
- 계정로그인토큰: Claude 구독 계정의 세션 토큰. API 키와 달리 별도 과금 없음
- 앤트로픽이 2026-05-07 기준 다시 허용
2.2 Sonnet 1M 호출 경로
automation/content_generator.py
→ OpenClaw Gateway (ws://127.0.0.1:18789 또는 Tailscale)
→ Anthropic API (account auth)
→ Sonnet 1M response
또는 직접 호출:
automation/content_generator.py
→ Anthropic SDK (python)
→ ANTHROPIC_API_KEY (채널콘솔 토큰)
→ Sonnet 1M response
액션테스트에서 확인할 것: 채널콘솔 토큰으로 Sonnet 1M 직접 호출이 되는지, 아니면 OpenClaw 게이트웨이 경유가 필요한지. 호출 방법에 따라 content_generator.py 구현이 달라짐.
2.3 mobilerun LLM provider
mobilerun도 LLM이 필요하다 (폰 UI 이해 + 액션 계획). 옵션:
| 방식 | 설명 | 비용 |
|---|---|---|
| Anthropic provider (채널콘솔) | mobilerun[anthropic] + 채널콘솔 토큰 |
$0 |
| OpenAI-compatible proxy | OpenClaw를 OpenAI 호환 엔드포인트로 노출 | $0 |
| DeepSeek fallback | 채널콘솔이 mobilerun에서 안 되면 | ~$0.05/세션 |
액션테스트에서 확인할 것: mobilerun이 채널콘솔 토큰을 ANTHROPIC_API_KEY로 받아들이는지.
3. 콘텐츠 생성 파이프라인
3.1 키워드 선정 (keyword_engine.py)
데이터 소스 (3중):
- 기존
research/keyword-analysis/— 1,638개 키워드, 검색량/경쟁도 데이터 - Naver SearchAd API — naver-search-mcp 오픈소스. 실시간 검색량 조회
published/히스토리 +keywords_used.json— 중복 방지
선정 로직:
1. 카테고리 결정 (라운드로빈 + 비율 가중)
육아 40% / 자영업 25% / 보안IT 20% / 운동 15%
→ 최근 발행 이력 기반으로 부족한 카테고리 우선
2. 후보 필터링
- 해당 카테고리 키워드 풀에서
- 30일 내 미사용
- 경쟁도 "낮음" 또는 "중간" 우선 (블루오션 전략)
- 월간 검색량 100+ (너무 적으면 의미 없음)
3. 최종 선택
score = 검색량 × (1 / 경쟁도 가중치) × 전환가치
상위 1개 선택
4. 기록
keywords_used.json에 {날짜, 키워드, 카테고리} append
SaaS 리버싱으로 고도화할 부분 (Phase 4):
- Blai 패턴: 블로그 현재 지수(DIA 점수) 대비 이길 수 있는 키워드만 선택
- BlogTalk 패턴: 블로그 레벨 매칭 — 신규 블로그가 빅키워드 가면 저품질 위험
- Gazet 패턴: SmartBlock 키워드 → 네이버가 원하는 소제목 구조 파악
3.2 원고 생성 (content_generator.py)
모델: Sonnet 1M (채널콘솔)
1M 컨텍스트 활용 전략: Sonnet 1M의 핵심 장점은 방대한 컨텍스트 윈도우. 한 번의 호출에 아래 전부를 로드:
[System Prompt]
├── 페르소나 정의 (POSTING_STRATEGY.md §분유타는대표)
├── marketer-system 규칙
│ ├── 다변수 임팩트 공식 v2 (V1~V10)
│ ├── 카피 파워 5피처 (MR, DA, ET, UC, GG)
│ └── 바디 핸들링 규칙 5 + 안티패턴 5
├── 네이버 SEO 규칙
│ ├── C-Rank 알고리즘 핵심
│ ├── 저품질 방지 가이드라인
│ └── SmartBlock 최적화 (리버싱 후 추가)
└── 출력 형식 지정 (마크다운 → HTML 변환 규칙)
[Few-shot Examples]
├── 기발행 글 3~5개 전문 (published/ 에서 로드)
│ → 톤, 구조, 분량의 실제 레퍼런스
└── 각 글의 키워드, 카테고리, 검색 성과 (있으면)
[User Prompt]
├── 오늘의 키워드: {keyword}
├── 카테고리: {category}
├── 템플릿: {info_post 또는 daily_post}
├── SmartBlock 소제목 가이드 (있으면)
└── 특별 지시 (시즌 이슈, 연결할 내부 글 등)
이렇게 하면 매 포스트가 기존 발행글과 톤이 일관되고, marketer-system 규칙을 자연스럽게 따른다.
템플릿 2종:
| 템플릿 | 용도 | 분량 | 구조 |
|---|---|---|---|
| info_post | 검색 유입용 | 1500~2500자 | 도입 3줄 → H2 3~4개(각 300~500자) → 관련글 → 결론 → 해시태그 → 서이추 |
| daily_post | 서이추/공감용 | 800~1200자 | 사진 → 에피소드 본문 → 사진 2~3장 → 질문 마무리 → 해시태그 |
카테고리→템플릿 매핑:
- 육아: daily_post 70% / info_post 30%
- 자영업: info_post 60% / daily_post 40%
- 보안IT: info_post 90% / daily_post 10%
- 운동: daily_post 80% / info_post 20%
품질 검증 (자동, 생성 직후):
| 항목 | 기준 | 실패 시 |
|---|---|---|
| 자수 | info: 1500~2500 / daily: 800~1200 | 재생성 |
| 키워드 밀도 | 2~4% (키워드 등장/총 자수) | 재생성 |
| H2 소제목 | info: 3~4개, daily: 0~2개 | 재생성 |
| 이미지 슬롯 | 최소 3개 [IMAGE_SLOT_N] |
경고 (Phase 1은 텍스트만) |
| 해시태그 | 5~7개 | 자동 보정 |
| 서이추 문구 | 하단에 존재 | 자동 append |
| 500자 미만 | 절대 차단 | 재생성 |
재생성은 1회만. 2회째도 실패 → queue/needs_review/ 저장 + Telegram 알림.
3.3 SEO 포매팅 (seo_formatter.py)
검증된 CDP SE 메서드 (2026-05-02, 프레데터 Chrome에서 확인):
clipboard에 inline style HTML을 넣고 Ctrl+V → SE 에디터가 자동으로 se-fs{N} 클래스로 매핑.
bold, color, center align, 표 모두 보존. 발행본 #224266857023 수준 polished output.
변환 규칙:
| 마크다운 요소 | SE HTML 출력 |
|---|---|
## 소제목 |
<p style="font-size:24px"><b>소제목</b></p> |
| 본문 단락 | <p style="font-size:16px">내용</p> |
**강조** |
<b>텍스트</b> |
| 색상 강조 | <span style="color:#00b4b4">텍스트</span> |
| 가운데 정렬 | <p style="text-align:center">...</p> |
| 구분선 | <hr> |
| 이미지 슬롯 | [IMAGE_SLOT_N] → Phase 1: 제거, Phase 2: Unsplash URL |
| 해시태그 | 별도 메타데이터로 분리 (mobilerun이 태그 필드에 입력) |
| 서이추 문구 | 마지막 <p> 블록 |
출력 형태:
{
"title": "신생아 홈캠 추천 — 업계 사람 기준 TOP 3",
"html_body": "<p style='font-size:16px'>도입부...</p>...",
"tags": ["신생아홈캠", "홈캠추천", "아기모니터", "육아필수템", "분유타는대표"],
"category": "보안IT",
"template": "info_post",
"word_count": 1850,
"keyword": "신생아 홈캠 추천"
}
액션테스트에서 확인할 것:
- S23 Chrome 모바일 SE 에디터에서 clipboard HTML paste가 동일하게 작동하는지
- PC Chrome과 모바일 Chrome에서 SE 동작 차이가 있는지
- 긴 HTML(2000자+)의 clipboard 전달 한계
4. 폰 포스팅 자동화 (mobilerun + S23)
4.1 mobilerun 아키텍처 이해
┌─────────────────────────────────────────────┐
│ vhagar (kontology) │
│ │
│ phone_poster.py │
│ → MobileAgent(goal="...", config=...) │
│ → mobilerun SDK │
│ ├── LLM (Sonnet 1M vision) │
│ ├── ADB 명령 실행 │
│ └── Portal APK 통신 (TCP 8080) │
│ │
│ ┌─── USB ADB ───┐ │
│ │ │ │
│ │ S23+ │ │
│ │ ├── Portal APK (접근성 트리 제공) │
│ │ ├── Chrome (m.blog.naver.com) │
│ │ └── 네이버 계정 로그인 상태 유지 │
│ │ │ │
│ └────────────────┘ │
└─────────────────────────────────────────────┘
Portal APK:
- mobilerun이
mobilerun setup --device R3CW60BHSAT으로 자동 설치 - 안드로이드 접근성 서비스 활성화 → UI 트리를 TCP 8080으로 노출
- 커스텀 키보드 IME 제공 → 한글 입력 지원
두 가지 인식 모드:
- 접근성 트리: 네이티브 앱 UI에 적합. 빠르고 정확
- Vision (스크린샷): WebView/복잡한 UI에 필수. SE 에디터는 이것이 필요
4.2 mobilerun 설치 계획
# 1. vhagar에 설치
cd ~/projects/naver-blog
python3 -m venv .venv
source .venv/bin/activate
pip install uv
uv pip install 'mobilerun[anthropic]'
# 2. 채널콘솔 토큰 설정 (테스트에서 확인 후 확정)
# 방법 A: 직접 Anthropic SDK
export ANTHROPIC_API_KEY=<채널콘솔 토큰>
# 방법 B: OpenClaw 경유 (OpenAI compatible)
export OPENAI_API_KEY=<openclaw 토큰>
export OPENAI_BASE_URL=http://127.0.0.1:18789/v1
# 3. S23 Portal 설치
mobilerun setup --device R3CW60BHSAT
# 4. 연결 검증
mobilerun ping --device R3CW60BHSAT
# 5. provider 설정
mobilerun configure
# → provider: Anthropic (또는 OpenAI compatible)
# → model: claude-sonnet-4-6 (1M)
4.3 포스팅 흐름 상세
사전 조건:
- S23 Chrome에 tidtyd222 로그인 상태
- S23 화면 켜짐 (adb shell input keyevent KEYCODE_WAKEUP)
- Portal APK 접근성 서비스 활성화
Step 1: 화면 준비
adb -s R3CW60BHSAT shell input keyevent KEYCODE_WAKEUP
adb -s R3CW60BHSAT shell input keyevent KEYCODE_MENU (잠금 해제 필요 시)
Step 2: HTML → S23 클립보드
방법 A: adb shell am broadcast
adb -s R3CW60BHSAT shell am broadcast -a clipper.set -e text "<html>"
(Clipper 앱 필요. 없으면 방법 B)
방법 B: 파일 push → 폰에서 읽기
adb -s R3CW60BHSAT push /tmp/post.html /data/local/tmp/post.html
adb -s R3CW60BHSAT shell "cat /data/local/tmp/post.html | am broadcast ..."
방법 C: mobilerun의 type 명령으로 직접 입력
(긴 텍스트는 느리지만, 클립보드 방식이 안 되면 대안)
→ 액션테스트에서 가장 안정적인 방법 결정
Step 3: mobilerun agent 실행
goal:
1. Chrome 앱 열기
2. 주소창에 m.blog.naver.com 입력 후 이동
3. 글쓰기(연필 아이콘) 버튼 탭
4. SmartEditor 로딩 대기 (2~3초)
5. 제목 입력 필드 탭 → 제목 텍스트 입력
6. 본문 영역 탭
7. 롱프레스 → 컨텍스트 메뉴에서 "붙여넣기" 탭
8. 붙여넣기 완료 대기 (1~2초)
9. 하단으로 스크롤
10. 태그/해시태그 입력 필드 찾아서 탭
11. 태그 하나씩 입력 + 엔터 (5~7개)
12. "발행" 또는 "완료" 버튼 탭
13. 발행 확인 다이얼로그가 나오면 확인 탭
14. 발행 완료 화면 확인
config:
max_steps: 40
reasoning: True (단계별 계획 수립)
vision: True (SE 에디터 WebView 인식)
timeout: 300초
Step 4: 결과 확인
- mobilerun result.success 체크
- 스크린샷 캡처 (선택적)
- 발행 URL 추출 시도 (Chrome 주소창에서)
4.4 네이버 로그인 세션 관리
| 시나리오 | 감지 방법 | 대응 |
|---|---|---|
| 정상 로그인 | 글쓰기 버튼 존재 | 정상 진행 |
| 세션 만료 | "로그인" 텍스트 감지 | Telegram 알림 → 수동 재로그인 |
| Chrome 업데이트 팝업 | "업데이트" 다이얼로그 감지 | 닫기 → 정상 진행 |
| 네이버 점검 | 에러 페이지 감지 | 30분 후 재시도 |
Phase 1에서는 자동 재로그인을 구현하지 않는다. 보안 이슈 + 2FA 가능성. 세션 만료는 Telegram 알림으로 대응.
4.5 mobilerun 주요 제약 & 대응
| 제약 | 심각도 | 대응 | 테스트 항목 |
|---|---|---|---|
| SE WebView 접근성 트리 불완전 | 높음 | vision 모드 필수 | AT0-3 |
| 클립보드 HTML 길이 제한 | 중간 | 파일 push fallback | AT0-4 |
| Portal APK 접근성 서비스 중지 | 중간 | 사전 체크 + 자동 재활성화 | AT0-2 |
| 한글 IME 입력 깨짐 | 중간 | mobilerun Portal IME 사용 | AT0-5 |
| vision 토큰 비용 | 낮음 | 채널콘솔 = $0 | - |
| 폰 화면 꺼짐 | 낮음 | KEYCODE_WAKEUP 사전 전송 | AT0-1 |
5. Phase 0: S23 액션테스트 계획
목적: 코딩 전에 mobilerun + S23 + 네이버 블로그 SE 에디터의 실제 동작을 검증. 결과를 v2 스펙에 반영.
5.1 테스트 환경 준비
# 0. venv 생성 + mobilerun 설치
cd ~/projects/naver-blog
python3 -m venv .venv && source .venv/bin/activate
pip install uv && uv pip install 'mobilerun[anthropic]'
# 1. S23 Portal APK 설치
mobilerun setup --device R3CW60BHSAT
# 2. 접근성 서비스 활성화 확인
mobilerun ping --device R3CW60BHSAT
# 3. LLM provider 설정
mobilerun configure
# provider → 채널콘솔 토큰 테스트 (안 되면 DeepSeek fallback)
5.2 테스트 항목
| ID | 테스트 | 방법 | 성공 기준 | 기록할 것 |
|---|---|---|---|---|
| AT0-1 | 폰 화면 제어 | mobilerun run "turn on screen, unlock phone" --device R3CW60BHSAT |
화면 켜짐 | 잠금 해제 필요 여부, PIN 필요 여부 |
| AT0-2 | Chrome 열기 + 네비게이션 | mobilerun run "open Chrome, go to m.blog.naver.com" --vision |
블로그 메인 표시 | 소요 시간, step 수, 에러 |
| AT0-3 | SE 에디터 진입 | 블로그 메인 → 글쓰기 버튼 → SE 에디터 로딩 | SE 에디터 표시 | vision으로 인식 가능 여부, 접근성 트리 상태 |
| AT0-4 | 클립보드 HTML paste | adb push post.html → SE 에디터에서 paste |
HTML 서식 보존 | paste 방법(broadcast/file/type), 서식 보존 여부, 길이 한계 |
| AT0-5 | 한글 제목 입력 | SE 제목 필드에 한글 텍스트 입력 | 한글 정상 표시 | IME 방식, 글자 깨짐 여부 |
| AT0-6 | 해시태그 입력 | 태그 필드에 5개 태그 입력 | 태그 5개 등록 | 태그 구분자(엔터/쉼표), 입력 속도 |
| AT0-7 | 임시저장 | 발행 대신 임시저장 | 임시저장 성공 | 임시저장 버튼 위치, 확인 다이얼로그 |
| AT0-8 | E2E 테스트 발행 | 전체 플로우: Chrome → SE → 제목+본문+태그 → 발행 | 글 발행 확인 | 총 소요 시간, 총 step 수, 실패 지점 |
| AT0-9 | LLM provider 테스트 | 채널콘솔 토큰으로 mobilerun 실행 | 정상 동작 | 토큰 형식, env 변수, 에러 메시지 |
| AT0-10 | 세션 만료 감지 | 로그아웃 상태에서 글쓰기 시도 | "로그인" 감지 | mobilerun이 로그인 화면을 인식하는지 |
5.3 테스트용 더미 원고
<p style="font-size:24px"><b>테스트 포스팅 — 자동화 시스템 검증용</b></p>
<p style="font-size:16px">이 글은 블로그 자동 포스팅 시스템의 E2E 테스트를 위한 더미 원고입니다.</p>
<p style="font-size:16px">서식이 정상적으로 적용되는지 확인합니다.</p>
<p style="font-size:24px"><b>소제목 테스트</b></p>
<p style="font-size:16px">본문 <b>볼드</b> 테스트. <span style="color:#00b4b4">색상</span> 테스트.</p>
<hr>
<p style="font-size:16px">구분선 위아래 텍스트.</p>
<p style="font-size:14px" style="color:#888">서이추 환영합니다 💕 소통해요!</p>
태그: 테스트, 자동화검증, 삭제예정
테스트 후 해당 글은 즉시 삭제 또는 비공개 처리.
5.4 테스트 결과 기록 양식
각 테스트 항목에 대해 tests/results/AT0-{N}.md에 기록:
# AT0-{N}: {테스트명}
- 일시: 2026-05-XX HH:MM
- 결과: PASS / FAIL / PARTIAL
- 소요시간: X초
- mobilerun steps: N
- 에러: (있으면)
- 스크린 기록: (텍스트 설명, 스크린샷 금지 — 세션 날림)
- 발견사항: (v2 스펙에 반영할 내용)
- 결론: (이 방식 유지 / 대안 필요)
5.5 테스트 순서
AT0-9 (LLM provider) → AT0-1 (화면) → AT0-2 (Chrome) → AT0-5 (한글)
→ AT0-3 (SE 에디터) → AT0-4 (HTML paste) → AT0-6 (태그)
→ AT0-7 (임시저장) → AT0-10 (세션만료) → AT0-8 (E2E)
LLM provider부터 테스트. 채널콘솔이 안 되면 나머지 테스트를 DeepSeek fallback으로 진행.
6. 스케줄링 & 모니터링
6.1 systemd timer
# ~/.config/systemd/user/naver-blog-post.timer
[Unit]
Description=Daily Naver Blog Post (분유타는대표)
[Timer]
OnCalendar=*-*-* 19:00:00
Persistent=true
RandomizedDelaySec=600
[Install]
WantedBy=timers.target
# ~/.config/systemd/user/naver-blog-post.service
[Unit]
Description=Naver Blog Posting Pipeline
[Service]
Type=oneshot
WorkingDirectory=/home/tlswk/projects/naver-blog
ExecStart=/home/tlswk/projects/naver-blog/.venv/bin/python -m automation.pipeline --account 분유타는대표
EnvironmentFile=/home/tlswk/projects/naver-blog/config/.env
TimeoutStartSec=600
설계 근거:
RandomizedDelaySec=600: 매일 정확히 같은 시각 방지 → 네이버 봇 탐지 회피Persistent=true: vhagar 꺼져있다가 켜지면 놓친 실행 보상 실행TimeoutStartSec=600: mobilerun vision + Sonnet 응답 시간 감안 (10분)- user-level systemd: root 불필요, ADB 권한 유지
6.2 모니터링 & 알림
pipeline.py 실행 결과:
성공:
→ published/ 에 {날짜}_{키워드}.md + .html 저장
→ Supabase daily_log에 append
→ Telegram "✅ 블로그 발행 완료: {제목}" 알림
실패:
├─ 키워드 선정 실패
│ → 수동 키워드 풀에서 랜덤 선택 (fallback)
│ → Telegram "⚠️ 키워드 선정 실패, fallback 사용" 알림
│
├─ 원고 생성 실패
│ → 1회 재시도 (5초 대기)
│ → 여전히 실패 → queue/needs_review/ 저장
│ → Telegram "❌ 원고 생성 실패, 수동 검토 필요" 알림
│
├─ 폰 포스팅 실패
│ → 3회 재시도 (60초 간격)
│ → 여전히 실패 → Telegram "❌ 포스팅 실패" + 마지막 에러
│ → 원고는 queue/에 보관 → 다음날 재시도 또는 수동 발행
│
└─ 세션 만료
→ Telegram "🔐 네이버 로그인 필요 — S23 Chrome에서 수동 로그인 해주세요"
Telegram 알림: 기존 BalerionBot (@BalrerionBot, id: 8620124076) 활용.
6.3 Supabase 로깅
daily_log에 블로그 포스팅 결과 append.
⚠️ CONTEXT_BRIDGE_GUARD 준수: summary SET 교체 금지, jsonb 배열 교체 금지.
{
"type": "blog_post",
"account": "분유타는대표",
"keyword": "신생아 홈캠 추천",
"category": "보안IT",
"template": "info_post",
"title": "신생아 홈캠 추천 — 업계 사람 기준 TOP 3",
"status": "published",
"url": "https://blog.naver.com/tidtyd222/...",
"word_count": 1850,
"mobilerun_steps": 23,
"mobilerun_duration_sec": 45,
"timestamp": "2026-05-07T19:03:22+09:00"
}
7. 에러 핸들링 & 네이버 보호
7.1 재시도 정책
| 단계 | 재시도 | 간격 | 최종 실패 시 |
|---|---|---|---|
| 키워드 선정 | 2회 | 즉시 | 수동 키워드 풀 랜덤 |
| 원고 생성 | 1회 | 5초 | queue/needs_review |
| SEO 포매팅 | 0회 | - | plain text 포스팅 |
| 폰 포스팅 | 3회 | 60초 | Telegram 알림, queue 보관 |
7.2 네이버 저품질 방지 가드레일
기존 POSTING_STRATEGY.md 규칙을 코드로 하드 강제:
| 규칙 | 구현 | 위반 시 |
|---|---|---|
| 하루 최대 1개 발행 | pipeline.py에서 오늘 published/ 체크 | 실행 중단 |
| 500자 미만 차단 | content_generator.py 검증 | 재생성 |
| 동일 키워드 30일 재사용 금지 | keywords_used.json 체크 | 다른 키워드 선택 |
| 발행 시간대 고정 | systemd timer 19:00±10분 | timer가 강제 |
| 계정간 30분 간격 | 민지 추가 시 timer 시간 분리 | timer가 강제 |
| 연속 포스팅 금지 | published/ 최근 기록 체크 | 최소 20시간 간격 |
7.3 디바이스 핑거프린트 보호
기존 POSTING_STRATEGY.md §리스크관리 준수:
- Chrome 프로필: tidtyd222 전용 (S23 기본 Chrome)
- NNB 쿠키: 자연 갱신 (강제 삭제 안 함)
- Canvas/WebGL 핑거프린트: S23 실제 디바이스 = 고유하고 일관됨 (문제없음)
- User-Agent: 실제 Chrome on Android (조작 없음)
8. SaaS 리버싱 대상 (Phase 4)
콘텐츠 생성 로직 고도화를 위한 리버싱 우선순위:
| 순위 | 서비스 | URL | RE 목표 | 방법 |
|---|---|---|---|---|
| 1 | Gazet AI | gazet.ai | SmartBlock 키워드 → 소제목 구조 | 웹 네트워크 탭 감청 |
| 2 | Blai | blai.co.kr | C-Rank/DIA 스코어링 모델 | API 엔드포인트 분석 |
| 3 | BlogTalk | blogtalk.io | 블로그 레벨 매칭 키워드 추천 | 크롬 확장 분석 |
| 4 | AutoPanda | autopanda.co.kr | SE 에디터 자동화 플로우 | 데스크탑 앱 디컴파일 |
| 5 | naver-search-mcp | github/isnow890 | SearchAd API 호출 패턴 | 오픈소스 직접 활용 |
리버싱에서 가져올 것:
- Gazet: "키워드를 넣으면 네이버가 원하는 소제목 구조가 나온다" — 이 파이프라인
- Blai: "이 블로그의 현재 DIA 점수는 X이고, 이 키워드는 이길 수 있다/없다" — 이 판단 로직
- BlogTalk: "신규 블로그인데 이 키워드는 가지 마라" — 레벨 매칭
9. 구현 로드맵
Phase 0: 액션테스트 (이 문서 확정 직후)
- mobilerun 설치 + S23 셋업
- AT0-1 ~ AT0-10 전수 테스트
- 결과 기록 → v2 스펙 반영
Phase 1: MVP 코딩 (v2 스펙 후, 2~3일)
- phone_poster.py: 검증된 방법으로 SE 포스팅
- seo_formatter.py: 마크다운 → SE HTML
- 수동 원고 1개 → 자동 포스팅 E2E
Phase 2: 콘텐츠 자동화 (2~3일)
- keyword_engine.py: 키워드 DB 기반 선정
- content_generator.py: Sonnet 1M 원고 생성
- pipeline.py: 전체 오케스트레이션
- 3일간 매일 1건 수동 모니터링
Phase 3: 스케줄링 + 모니터링 (1일)
- systemd timer 설정 (user-level)
- Supabase 로깅 연동
- Telegram 알림 연동
- 1주간 무인 운영 모니터링
Phase 4: 고도화 (지속)
- SaaS 리버싱 (Gazet, Blai) → 콘텐츠 품질 향상
- SearchAd API 연동 → 실시간 키워드 데이터
- 이미지 자동 삽입 (Unsplash API → AI 이미지 생성)
- 민지 계정 추가 (timer 분리, 시간대 오전 10:00)
- 성과 대시보드 (발행 이력 + 방문자 + 검색유입 추적)
10. 비용 추정 (월간)
| 항목 | 이전안 (DeepSeek) | 현재안 (Sonnet 1M 채널콘솔) |
|---|---|---|
| 원고 생성 (30회) | ~$0.30~0.60 | $0 (구독 내) |
| mobilerun vision (30회) | ~$1.50~3.00 | $0 (채널콘솔) |
| SearchAd API | 무료 | 무료 |
| Supabase | 기존 인프라 | 기존 인프라 |
| 합계 | ~$2~4/월 | ~$0/월 |
채널콘솔이 mobilerun에서 안 되면 mobilerun만 DeepSeek fallback → ~$1.50~3.00/월.
11. 의존성 정리
| 패키지 | 용도 | 설치 |
|---|---|---|
| mobilerun[anthropic] | 폰 자동화 | uv pip install |
| anthropic | Sonnet 1M 호출 | pip install anthropic |
| jinja2 | 프롬프트 템플릿 | pip install jinja2 |
| pyyaml | 설정 파일 | pip install pyyaml |
| supabase | 로깅 | pip install supabase |
| requests | HTTP 호출 | 내장 |
12. 미결 사항 (액션테스트에서 확인)
| ID | 질문 | 영향 범위 |
|---|---|---|
| Q1 | 채널콘솔 토큰이 Anthropic SDK에서 직접 작동하는가? | content_generator.py 구현 |
| Q2 | 채널콘솔 토큰이 mobilerun ANTHROPIC_API_KEY로 작동하는가? | phone_poster.py LLM provider |
| Q3 | S23 모바일 Chrome SE 에디터에서 HTML clipboard paste가 되는가? | clipboard 전달 방식 |
| Q4 | 긴 HTML (2000자+)의 ADB 클립보드 전달 한계는? | seo_formatter.py 출력 길이 |
| Q5 | mobilerun vision이 SE 에디터 WebView를 인식하는가? | phone_poster.py goal 작성 |
| Q6 | 한글 입력이 mobilerun Portal IME로 정상 동작하는가? | 제목/태그 입력 방식 |
| Q7 | S23 잠금화면 자동 해제가 필요한가? (PIN/패턴) | 사전 준비 스크립트 |
| Q8 | Portal APK 접근성 서비스가 재부팅 후에도 유지되는가? | 안정성 |