운영 NAS에서 DSM_HOST=https://192.168.x.x:5001 같은 LAN IP 사용 시
DSM의 self-signed 인증서가 IP 주소에 매칭되지 않아 SSL 검증 실패
(SSL: CERTIFICATE_VERIFY_FAILED — IP address mismatch).
LAN 내부 통신이라 verify=False 허용 가능. 환경변수로 토글:
- DSM_VERIFY_SSL=true (default) — 도메인 + 정상 cert 환경
- DSM_VERIFY_SSL=false — LAN IP + self-signed 환경
dsm_client.py가 환경변수 읽어 httpx.AsyncClient(verify=...)에 전달.
docker-compose.yml + .env.example + CLAUDE.md에 신규 env 명시.
회귀 25/25 passing.
이전: upload가 컨테이너 경로(/app/data/packs/...)를 Supabase에 저장 →
sign-link 시 그 경로를 DSM에 전달 → DSM은 NAS 호스트 절대경로
(/volume1/.../media/packs/...) 기준이라 파일을 찾지 못함.
수정:
- routes.py: PACK_HOST_DIR 신규 (env, fallback=PACK_BASE_DIR)
- upload 시 host_path = PACK_HOST_DIR/{tier}/{filename}을 Supabase에 INSERT
- sign-link 시 PACK_HOST_DIR 기준 경로 검증
- docker-compose: PACK_HOST_DIR env 주입 (default=PACK_DATA_PATH)
- .env.example + CLAUDE.md: 환경변수 의미 분리 명시
- tests: 호스트경로 저장 검증 신규 (test_upload_stores_host_path_not_container_path)
- 25/25 passing
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
이전 docker-compose는 컨테이너 내부 /app/data/packs로 마운트하지만 routes.py는
/volume1/docker/webpage/media/packs를 하드코딩하고 있어 mismatch였다.
- routes.py: PACK_BASE_DIR = Path(os.getenv("PACK_BASE_DIR", "/app/data/packs"))
- docker-compose: PACK_BASE_DIR env 추가 + volume 마운트가 같은 경로 사용
- .env.example: PACK_BASE_DIR 신규 명시 (마운트 경로와 반드시 일치 안내)
- docker-compose.yml: 포트 18910→18950 수정, env 형식을 list 스타일로 통일,
TZ/UPLOAD_TOKEN_TTL_SEC 추가, volume 경로를 /app/data/packs으로 정정
- .env.example: packs-lab 섹션 신규 추가 (DSM_HOST/DSM_USER/DSM_PASS/
BACKEND_HMAC_SECRET/SUPABASE_URL/SUPABASE_SERVICE_KEY/UPLOAD_TOKEN_TTL_SEC/PACK_DATA_PATH)
- nginx/default.conf: 이전 커밋(9a0bbec)에 이미 포함 — 변경 없음
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Synology ACL이 username 기반 chown을 거부하고 컨테이너 내부에 bgg8988
사용자가 없어 매 배포마다 WARN 로그가 쏟아지던 문제 해결.
- PUID/PGID 환경변수를 deployer 컨테이너에 전달
- find로 소유자가 다른 항목만 골라 numeric chown (idempotent)
- 실패는 silent — 어차피 파일 기능엔 영향 없음
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
.env에 값이 있어도 docker-compose.yml의 environment 블록에 선언되지
않으면 컨테이너에 전달되지 않음. ANTHROPIC_API_KEY 미전달로 로또
큐레이터가 schema validation 직전 CuratorError로 실패하던 문제 해결.
추가된 passthrough: ANTHROPIC_API_KEY, LOTTO_BACKEND_URL,
LOTTO_CURATOR_MODEL, TELEGRAM_WIFE_CHAT_ID, CONVERSATION_MODEL,
CONVERSATION_HISTORY_LIMIT, CONVERSATION_RATE_PER_MIN.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
기존 Stock/Music 에이전트 패턴을 따라 2개 신규 에이전트 도입.
- Blog 에이전트 (10:00 매일): 트렌드 키워드 1개 자동 선택
→ blog-lab 파이프라인 전체 (research→generate→market→review) 자동 실행
→ 평가 점수와 본문 요약을 텔레그램 승인 요청으로 푸시
→ 승인 시 published 전환, 거절 시 작업 종료
- Realestate 에이전트 (09:15 매일): realestate-lab 수집 트리거
→ 신규 매칭 상위 5건 + 대시보드를 텔레그램 리포트
→ 조회한 매칭은 자동 읽음 처리
- service_proxy: blog-lab/realestate-lab REST 호출 래퍼 추가
- agents 레지스트리 + DB 시드 + 스케줄러 3개 잡 등록
- docker-compose: agent-office에 BLOG_LAB_URL/REALESTATE_LAB_URL 주입
- README: 에이전트 구성 표 + 명령어 + 스케줄러 잡 정리
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PC 메모리 부하 해소를 위해 뉴스 요약 기본 provider를 Ollama qwen3:14b
→ Claude Haiku 4.5로 변경. LLM_PROVIDER 환경변수로 언제든 ollama 롤백 가능.
- ai_summarizer.py: provider 분리 (_summarize_with_claude / _summarize_with_ollama)
- OllamaError는 LLMError alias로 유지 (main.py 수정 불필요)
- Anthropic Messages API 직접 호출 (httpx, 의존성 추가 없음)
- docker-compose + .env.example: LLM_PROVIDER, ANTHROPIC_MODEL 추가
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- stock-lab: POST /api/stock/news/summarize 추가 (Ollama /api/generate 호출, 토큰/duration 추적)
- agent-office: telegram 패키지 분해 (client/formatter/messaging/webhook/router/agent_registry)
- send_agent_message 통합 API로 에이전트 중립 메시지 포맷 표준화
- 텔레그램 → 에이전트 명령 라우터 (/status, /stock news, /music credits 등)
- 토큰 사용량 집계 API 및 GET /agents/{id}/token-usage
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
deployer 내부(/runtime)와 NAS 호스트(/volume1/docker/webpage)에서 docker compose
실행 시 디렉토리명 기반 프로젝트명이 달라져 컨테이너 관리가 불가능한 문제 수정.
name: webpage으로 고정하여 어디서 실행해도 동일한 프로젝트로 인식.
deprecated version: "3.8" 제거.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
deployer 컨테이너 내부에서 docker compose up 실행 시 상대 경로(./data/music)가
/runtime/data/music으로 해석되어 호스트에서 bind mount 실패하는 문제 수정.
${RUNTIME_PATH}/data/<service> 패턴으로 통일하여 NAS 환경에서도 호스트 절대
경로(/volume1/docker/webpage/data/*)가 정확히 전달되도록 함.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
네이버 검색 API 키워드 분석 + Claude AI 글 생성 + 품질 리뷰 + 수익 추적
- blog-lab/ 서비스 전체 (FastAPI, SQLite 5테이블, 18 엔드포인트)
- docker-compose.yml: blog-lab 서비스 (port 18700)
- nginx: /api/blog-marketing/ 라우팅 추가
- .env.example: NAVER_CLIENT_ID/SECRET 추가
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- backend/main.py: logging 모듈 도입, print() 제거
- stock-lab/main.py: print() → logger 전환, _calc_portfolio_totals 공용 함수 추출
- stock-lab/scraper.py: logging 모듈 도입, print() 제거
- docker-compose.yml: 전 서비스 healthcheck 블록 추가 (30s 간격, 3회 재시도)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
docker-compose.yml stock-lab environment에 GEMINI_API_KEY, GEMINI_MODEL 추가.
.env에 값이 있어도 컨테이너에 전달 안 됐던 문제 수정.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- frontend depends_on music-lab 추가 (시작 순서 보장)
- /api/music/ location에 resolver 127.0.0.11 + 변수 proxy_pass 적용
(Nginx 시작 시점에 music-lab이 미준비여도 기동 가능)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- music-lab/ 신규 서비스 (포트 18600)
- POST /api/music/generate 비동기 음악 생성 (task_id 반환)
- GET /api/music/status/:id 폴링 (queued→processing→succeeded/failed)
- GET /api/music/library 라이브러리 조회
- POST /api/music/library 트랙 수동 추가
- DELETE /api/music/library/:id 트랙 삭제 (파일 포함)
- SQLite: music_tasks + music_library 테이블
- 생성 완료 시 라이브러리 자동 등록
- AI 서버 응답: binary audio / JSON audio_url 모두 지원
- nginx: /api/music/ 프록시 + /media/music/ 오디오 파일 직접 서빙
- docker-compose: music-lab 서비스 + frontend 볼륨 마운트 추가
- CLAUDE.md 업데이트
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>