# ThreadAuto 인스타그램 크로스 포스팅 기능 구현

## 목표
카드뉴스를 **Threads + Instagram에 동시 업로드**하는 크로스 포스팅 기능 구현.
텍스트 스레드는 대상 아님. **카드뉴스(이미지 캐러셀)만** 크로스 포스팅.

## 현재 구조 요약
- **Threads 업로드**: `api/client.py` → `ThreadsClient.post_carousel()` (구현 완료)
- **발행 관리**: `publisher/threads_publisher.py` → `ThreadsPublisher.publish_cardnews()`
- **이미지 서버**: `publisher/image_server.py` → Tailscale Funnel로 공개 URL 제공
- **스케줄러**: `scheduler/cron_runner.py` → APScheduler 기반 자동 발행
- **인증**: `auth/oauth.py` + `auth/token_store.py` → Threads API 토큰 관리
- **현재 Instagram 코드**: 없음 (신규 구현 필요)

## 핵심 설계 포인트

### 1. Instagram Graph API 연동
- Instagram Content Publishing API 사용 (Facebook Graph API 경유)
- **엔드포인트**: `https://graph.facebook.com/v22.0/{ig-user-id}/media` (컨테이너 생성)
- **엔드포인트**: `https://graph.facebook.com/v22.0/{ig-user-id}/media_publish` (발행)
- **캐러셀 흐름**: 개별 이미지 컨테이너 생성 → 캐러셀 컨테이너 생성 → 발행 (Threads와 유사)
- **필요 권한**: `instagram_basic`, `instagram_content_publish`, `pages_read_engagement`

### 2. 인증/토큰 관리
- Instagram과 Threads는 **같은 Meta 플랫폼**이지만 **별도 API 토큰 체계**
- Instagram은 Facebook Page 연결 필수 → Facebook Page Access Token 필요
- **토큰 저장**: `.tokens/instagram_token.json` (Threads 토큰과 분리)
- OAuth 플로우: Facebook Login → Page Token → Instagram User ID 조회

### 3. 크로스 포스팅 아키텍처
구현 방식: **발행자(Publisher) 레벨에서 분기**

```
카드뉴스 렌더링 → 이미지 파일 리스트
       ↓
ThreadsPublisher.publish_cardnews()  ← 기존 유지
       +
InstagramPublisher.publish_cardnews()  ← 신규 추가
       ↓
CrossPublisher (오케스트레이터) → 둘 다 호출, 결과 통합
```

### 4. 파일 구조 (신규/수정)

**신규 파일:**
- `api/instagram_client.py` — Instagram Graph API 클라이언트
- `auth/instagram_oauth.py` — Instagram/Facebook OAuth 플로우
- `auth/instagram_token_store.py` — Instagram 토큰 저장/갱신
- `publisher/instagram_publisher.py` — Instagram 발행 관리
- `publisher/cross_publisher.py` — 크로스 포스팅 오케스트레이터

**수정 파일:**
- `config.py` — Instagram 관련 환경변수 추가
- `scheduler/cron_runner.py` — CrossPublisher 호출로 변경
- `cli.py` — Instagram 인증 명령어 추가
- `main.py` — Instagram OAuth 콜백 라우터 추가

### 5. Instagram API 상세 흐름 (캐러셀)

```
1. 개별 이미지 컨테이너 생성 (각 이미지마다):
   POST /{ig-user-id}/media
   Body: { image_url: "공개URL", is_carousel_item: true }
   → creation_id 반환

2. 캐러셀 컨테이너 생성:
   POST /{ig-user-id}/media
   Body: { media_type: "CAROUSEL", children: [creation_id1, creation_id2, ...], caption: "텍스트" }
   → creation_id 반환

3. 발행:
   POST /{ig-user-id}/media_publish
   Body: { creation_id: carousel_creation_id }
   → media_id 반환
```

### 6. config.py 추가 환경변수
```python
INSTAGRAM_APP_ID = os.getenv("INSTAGRAM_APP_ID", "")
INSTAGRAM_APP_SECRET = os.getenv("INSTAGRAM_APP_SECRET", "")
INSTAGRAM_REDIRECT_URI = os.getenv("INSTAGRAM_REDIRECT_URI", "http://localhost:8200/auth/instagram/callback")
INSTAGRAM_USER_ID = os.getenv("INSTAGRAM_USER_ID", "")  # Instagram Business Account ID
FACEBOOK_PAGE_ID = os.getenv("FACEBOOK_PAGE_ID", "")
CROSS_POST_ENABLED = os.getenv("CROSS_POST_ENABLED", "true").lower() == "true"
```

### 7. CrossPublisher 로직
```python
class CrossPublisher:
    async def publish_cardnews(...):
        results = {}

        # Threads 발행 (기존)
        threads_result = await self.threads_publisher.publish_cardnews(...)
        results["threads"] = threads_result

        # Instagram 크로스 포스팅 (CROSS_POST_ENABLED일 때만)
        if config.CROSS_POST_ENABLED:
            ig_result = await self.instagram_publisher.publish_cardnews(...)
            results["instagram"] = ig_result

        return results
```

### 8. 캡션 차이
- **Threads**: 500자 제한, 해시태그 본문에 포함
- **Instagram**: 2,200자 제한, 해시태그 30개까지
- 캡션 빌더에서 플랫폼별 포맷 분기 필요

### 9. Instagram 인증 준비 (원격 브라우저 활용)
- **크롬 디버그**: `100.116.204.95:9222` (제이회장님 윈도우 노트북)
- **활용**: Facebook Developer Console에서 앱 설정, Instagram Business 연결 확인
- **스크립트**: `python3 scripts/browser.py --remote-cdp http://100.116.204.95:9222 <command>`
- Meta 앱에 Instagram 제품 추가 필요 여부 확인
- 기존 Threads 앱(THREADS_APP_ID)에 Instagram 권한 추가 가능한지 확인

### 10. 주의사항
- Instagram Content Publishing API는 **Business/Creator 계정만** 지원
- Facebook Page와 Instagram 계정 연결 필수
- 이미지 URL은 **공개 접근 가능**해야 함 (기존 Tailscale Funnel 활용)
- Rate Limit: 시간당 25건 (Instagram), Threads보다 제한적
- 이미지 규격: Instagram은 1:1(1080x1080) 권장이지만 4:5(1080x1350)도 지원
- 기존 4:5 규격 유지 가능 (Instagram에서도 잘 보임)

## 테스트 계획
1. Instagram OAuth 인증 플로우 테스트
2. 단일 이미지 업로드 테스트
3. 캐러셀(멀티 이미지) 업로드 테스트
4. Threads + Instagram 동시 발행 테스트
5. 실패 시 한쪽만 성공하는 케이스 처리 검증
6. 스케줄러 통합 테스트

## 산출물
- 신규 파일 5개 + 수정 파일 4개
- pytest 테스트 커버리지
- Instagram 인증 완료 (토큰 저장)
- 크로스 포스팅 1건 이상 성공 확인
