# ThreadAuto 텍스트 믹스 도입 (Phase 0)

## 목표
현재 카드뉴스(이미지) 20개/일만 올리는 ThreadAuto에 **텍스트 전용 포스트**를 추가한다.
총 발행량 20개를 유지하면서, 카드뉴스 12개 + 텍스트 6개 + 영상 2개 믹스로 전환.

## 배경
- Threads는 텍스트 중심 SNS. 이미지만 20개 올리면 광고 계정처럼 보임.
- 에이전트 미팅 결론: 볼륨 유지 + 유형만 변경 (알고리즘 충격 최소화)
- 미팅 기록: `/home/jay/workspace/memory/meetings/2026-03-07-threads-content-mix-strategy.md`

## 프로젝트 경로
`/home/jay/projects/ThreadAuto/`

## 작업 상세

### 1. content_type 필드 추가 (topic_selector.py 수정)

`/home/jay/projects/ThreadAuto/content/topic_selector.py`의 DAILY_MIX를 V2로 교체:

```python
DAILY_MIX_V2 = {
    "고민공감": {"count": 3, "types": [("cardnews", 2), ("text_short", 1)]},
    "정보제공": {"count": 5, "types": [("cardnews", 2), ("text_info", 2), ("text_story", 1)]},
    "사회적증거": {"count": 2, "types": [("cardnews", 2)]},
    "업계동향": {"count": 6, "types": [("cardnews", 2), ("text_news", 2), ("video", 2)]},
    "CTA": {"count": 2, "types": [("text_short", 2)]},  # soft-CTA 내장
}
```

- `select_daily_topics()` 반환값에 `content_type` 필드 추가
- 기존 반환 형태: `[{"category": "고민공감", "topic": {...}}]`
- V2 반환 형태: `[{"category": "고민공감", "topic": {...}, "content_type": "text_short"}]`
- 기존 호환: content_type이 없으면 "cardnews"로 간주

### 2. 텍스트 콘텐츠 생성기 (신규)

`/home/jay/projects/ThreadAuto/content/text_generator.py` 신규 생성.

```python
class TextContentGenerator:
    """텍스트 전용 포스트 생성기 (Claude CLI 호출)"""

    TEXT_TYPES = {
        "text_short": {
            "max_length": 280,
            "description": "짧은 생각/감상. 구어체, 임팩트 있게.",
        },
        "text_info": {
            "max_length": 500,
            "description": "정보 해설. 구조 5종 순환(역피라미드/Q&A/3줄요약/비교/오해깨기).",
        },
        "text_story": {
            "max_length": 500,
            "description": "사례/스토리. 3인칭 시점, 열린 결말 선호.",
        },
        "text_news": {
            "max_length": 500,
            "description": "뉴스 코멘트. 출처 언급 + 짧은 코멘트.",
        },
    }

    def generate(self, topic: dict, text_type: str) -> dict:
        """텍스트 포스트 생성. Claude CLI 호출."""
        ...

    def _build_prompt(self, topic: dict, text_type: str) -> str:
        """text_type별 시스템 프롬프트 구성"""
        ...

    def _validate(self, text: str, text_type: str) -> bool:
        """길이, 금칙어, AI냄새 블랙리스트 검증"""
        ...
```

#### AI 냄새 방지 규칙 (프롬프트에 포함):
- 이모지 0~2개. 3개 이상 시 자동 삭제
- 시작어 블랙리스트: "안녕하세요!", "오늘은~에 대해", "여러분"
- 접속사 블랙리스트: "또한", "아울러", "더불어", "뿐만 아니라"
- 구어체 필수: "~거든요", "~인 거임", "~해봄" 등 자연스러운 말투
- 해시태그 0~3개. 5개 이상 금지. 30% 포스트는 해시태그 없음
- 완벽한 기승전결 금지. 끝 흐리기, 열린 결말 허용

#### 텍스트 프롬프트 파일:
`/home/jay/projects/ThreadAuto/content/text_prompts.py` 신규 생성.
- text_type별 시스템 프롬프트
- 시그니처 오프닝 패턴 5종 (유형별 고정)
- 구조 템플릿 5종 (text_info용 순환)

### 3. 파이프라인 분기 (pipeline.py 수정)

`/home/jay/projects/ThreadAuto/content/pipeline.py`의 `run_daily_pipeline()`:

```python
# content_type에 따라 생성기 분기
if content_type.startswith("text_"):
    from content.text_generator import TextContentGenerator
    gen = TextContentGenerator()
    result = gen.generate(topic, content_type)
    # 이미지 렌더링 스킵, text만 저장
else:
    # 기존 카드뉴스 파이프라인 유지
    gen = ContentGeneratorV2()
    ...
```

### 4. 발행 분기 (publish_worker.py 수정)

`/home/jay/projects/ThreadAuto/scheduler/publish_worker.py`의 `publish_post()`:

```python
content_type = post.get("content_type", "cardnews")

if content_type.startswith("text_"):
    # 텍스트 전용 발행 (API: media_type="TEXT")
    text = post.get("text", post.get("caption", ""))
    result = await client.post_text(text=text)
elif content_type == "video":
    # 기존 영상 발행
    ...
else:
    # 기존 카드뉴스 발행 (이미지/캐러셀)
    ...
```

### 5. daily_queue 스키마 content_type 필드 추가

기존 큐 JSON에 `content_type` 필드 추가. 없으면 "cardnews" 기본값.

```json
{
  "slot_index": 0,
  "content_type": "text_short",
  "category": "고민공감",
  "text": "포스트 본문...",
  "hashtags": ["#보험"],
  "image_paths": [],
  "status": "pending"
}
```

### 6. Threads API 텍스트 발행 확인

`/home/jay/projects/ThreadAuto/api/client.py`에 `post_text()` 메서드가 있는지 확인.
없으면 추가:

```python
async def post_text(self, text: str) -> str:
    """텍스트 전용 스레드 게시"""
    params = {"media_type": "TEXT", "text": text}
    container_id = await self._create_container(**params)
    return await self._publish(container_id)
```

## 수정 파일 목록
1. `content/topic_selector.py` — DAILY_MIX_V2, content_type 반환 (수정)
2. `content/text_generator.py` — 텍스트 생성기 (신규)
3. `content/text_prompts.py` — 텍스트 프롬프트 (신규)
4. `content/pipeline.py` — content_type 분기 (수정)
5. `scheduler/publish_worker.py` — 텍스트 발행 분기 (수정)
6. `api/client.py` — post_text() 추가 (수정, 없으면)

## 테스트
- text_generator: 4종 텍스트 타입별 생성 + 검증 테스트
- topic_selector: DAILY_MIX_V2 content_type 포함 검증
- pipeline: content_type 분기 동작 확인
- publish_worker: 텍스트/카드뉴스/영상 분기 동작 확인
- AI 냄새 블랙리스트 필터 테스트
- 기존 카드뉴스 테스트 전체 PASS 확인 (회귀 테스트)

## 주의사항
- 기존 카드뉴스 파이프라인은 절대 깨뜨리지 않을 것
- content_type이 없는 기존 큐 데이터 하위 호환 보장
- text_type별 max_length 초과 시 재생성 (최대 3회)
- video 타입은 이번 Phase에서 기존 영상 모듈 연동만 확인 (새 개발 없음)

## 보고서
완료 시 `/home/jay/workspace/memory/reports/task-391.1.md`에 작성.
머지 판단 섹션 필수 포함.