# Task: Tailscale Funnel 문제 진단 + 이미지 서빙 시스템화 (task-293.1)

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

## 배경
Threads API로 카드뉴스를 발행하려면 이미지가 공개 URL로 접근 가능해야 한다.
현재 Tailscale Funnel로 로컬 이미지를 서빙하고 있으나, Funnel 재설정 후 Meta 서버에서 이미지 접근 불가 현상 발생.

**에러**: Threads API 400 Bad Request — "미디어 다운로드에 실패했습니다. 미디어 URI가 요구 사항을 충족하지 않습니다." (error_subcode: 2207052)

**현재 상태**:
- Tailscale Funnel 활성화 상태: `https://aidevserver.tail2cdab6.ts.net/images`
- 로컬 curl은 200 OK (이미지 접근 가능)
- Meta 서버에서는 접근 불가 (외부 DNS 전파 또는 도메인 신뢰 문제)
- 이전에는 `walrus.tail4906f4.ts.net` 도메인으로 정상 작동했던 이력 있음

## 작업 내용

### Phase 1: 문제 진단
1. **외부 접근 테스트**: 서버 외부에서 Funnel URL 접근 가능 여부 확인
   - `curl -v https://aidevserver.tail2cdab6.ts.net/images/<이미지파일>` 으로 상세 로그
   - DNS 해석 확인: `dig aidevserver.tail2cdab6.ts.net` 또는 `nslookup`
   - TLS 인증서 확인: `openssl s_client -connect aidevserver.tail2cdab6.ts.net:443`
2. **Meta 서버 관점 분석**: Meta가 이미지를 못 가져오는 원인 특정
   - Content-Type 확인 (image/png 필수)
   - 응답 시간 확인 (3초 이내 필수)
   - SSL 인증서 유효성 (자체서명 인증서 차단될 수 있음)
   - Tailscale Funnel이 Let's Encrypt 인증서를 사용하는지 확인
3. **이전 동작 분석**: `walrus.tail4906f4.ts.net` → `aidevserver.tail2cdab6.ts.net` 호스트 변경 원인

### Phase 2: 해결 방안 설계 + 구현
원인에 따라 아래 중 최적의 방안을 선택하여 구현:

**방안 A: Tailscale Funnel 수정**
- Funnel 설정 최적화 (포트, 경로, 인증서 등)
- 필요시 Funnel 재생성

**방안 B: 대체 이미지 서빙 시스템**
- nginx 등 정적 파일 서버 + Let's Encrypt SSL
- Cloudflare Tunnel (무료, 안정적)
- Firebase Storage / S3 등 클라우드 스토리지 업로드 방식

**방안 C: 하이브리드**
- 1순위 클라우드 업로드, 2순위 Funnel 폴백

### Phase 3: 시스템화
어떤 방안이든 아래를 코드로 구현:
1. `publisher/image_server.py` (신규 모듈) — 이미지를 공개 URL로 서빙하는 통합 인터페이스
   - `get_public_url(local_path: str) -> str` — 로컬 이미지 → 공개 URL 변환
   - 서빙 방식은 config로 선택 가능 (funnel / upload / etc)
   - 헬스체크: 발행 전 URL 접근 가능 여부 확인 (`verify_url(url) -> bool`)
2. `publisher/threads_publisher.py` 수정 — image_server.py 연동
   - 기존 하드코딩된 base_url 제거
   - image_server.get_public_url() 호출로 전환
3. 자동 복구: Funnel 다운 시 자동 재시작 또는 대체 방식 전환

## 수정 대상 파일
- `publisher/image_server.py` (신규)
- `publisher/threads_publisher.py` — image_server 연동
- **renderer/ 수정 금지** — 1팀 작업 영역

## 참조
- 현재 Funnel 상태: `tailscale funnel status`
- Tailscale 호스트: `aidevserver.tail2cdab6.ts.net`
- 이미지 디렉토리: `/home/jay/projects/ThreadAuto/output/`
- HTTP 서버: `python3 -m http.server 8080` (127.0.0.1:8080에서 실행 중)
- Threads API 이미지 요구사항: JPEG/PNG, 8MB 미만, 공개 HTTPS URL

## 테스트 요구사항
1. image_server.get_public_url() 호출 시 유효한 공개 URL 반환
2. verify_url()로 해당 URL이 외부에서 접근 가능한지 확인
3. 테스트 이미지로 Threads API container 생성 성공 확인 (실제 발행은 선택)
4. Funnel 다운 시나리오에서 에러 핸들링 확인

## 산출물
1. 진단 보고서: 보고서에 포함
2. `publisher/image_server.py` (신규 모듈)
3. `publisher/threads_publisher.py` 수정