24 KiB
24 KiB
CLAUDE.md — web-backend 프로젝트 가이드
Claude Code가 이 프로젝트를 작업할 때 참조하는 설정 및 구조 문서.
1. 프로젝트 개요
Synology NAS 기반의 개인 웹 플랫폼 백엔드 모노레포.
- 서비스: lotto-lab, stock-lab, travel-album, music-lab, blog-lab, realestate-lab, deployer
- 프론트엔드: 별도 레포 (React + Vite SPA), 빌드 산출물만 NAS에 배포
- 인프라: Docker Compose + Nginx(리버스 프록시) + Gitea Webhook 자동 배포
2. NAS 환경
| 항목 | 값 |
|---|---|
| 장비 | Synology NAS |
| CPU | Intel Celeron J4025 (2 Core, 2.0 GHz) |
| 메모리 | 18 GB |
| Docker | Synology Container Manager |
| Git 서버 | Gitea (self-hosted, NAS 내부) |
| AI 서버 | Windows PC (192.168.45.59:8000) — NVIDIA 3070 Ti + Ollama |
3. NAS 디렉토리 구조
/volume1
├── docker/webpage/ # 운영 런타임 (Docker Compose 실행 위치)
│ ├── backend/ # lotto-backend 소스 (rsync 동기화)
│ ├── stock-lab/ # stock-lab 소스 (rsync 동기화)
│ ├── travel-proxy/ # travel-proxy 소스 (rsync 동기화)
│ ├── deployer/ # deployer 소스 (rsync 동기화)
│ ├── nginx/default.conf # Nginx 설정
│ ├── scripts/deploy.sh # Webhook 트리거 배포 스크립트
│ ├── docker-compose.yml
│ ├── .env # 운영 환경변수
│ ├── data/lotto.db # SQLite DB
│ └── data/music/ # 생성된 오디오 파일 (music-lab)
│
├── workspace/web-page-backend/ # Git 레포 클론 위치 (REPO_PATH)
│
└── web/images/webPage/travel/ # 원본 여행 사진 (RO 마운트)
4. Docker 서비스 & 포트
| 컨테이너 | 포트 | 역할 |
|---|---|---|
lotto-backend |
18000 | 로또 데이터 수집·분석·추천 API |
stock-lab |
18500 | 주식 뉴스·AI 분석·KIS API 연동 |
music-lab |
18600 | AI 음악 생성·라이브러리 관리 API |
blog-lab |
18700 | 블로그 마케팅 수익화 API |
realestate-lab |
18800 | 부동산 청약 자동 수집·매칭 API |
agent-office |
18900 | AI 에이전트 오피스 (실시간 WebSocket + 텔레그램 연동) |
travel-proxy |
19000 | 여행 사진 API + 썸네일 생성 |
lotto-frontend (nginx) |
8080 | 정적 SPA 서빙 + API 리버스 프록시 |
webpage-deployer |
19010 | Gitea Webhook 수신 → 자동 배포 |
5. Nginx 라우팅 규칙
| 경로 | 프록시 대상 | 비고 |
|---|---|---|
/api/ |
lotto-backend:8000 |
lotto API (기본) |
/api/travel/ |
travel-proxy:8000 |
travel API |
/api/stock/ |
stock-lab:8000 |
stock API |
/api/trade/ |
stock-lab:8000 |
KIS 실계좌 API |
/api/portfolio |
stock-lab:8000 |
trailing slash 유무 모두 매칭 |
/api/music/ |
music-lab:8000 |
AI 음악 생성·라이브러리 API |
/api/blog-marketing/ |
blog-lab:8000 |
블로그 마케팅 수익화 API |
/api/realestate/ |
realestate-lab:8000 |
부동산 청약 API |
/api/agent-office/ |
agent-office:8000 |
AI 에이전트 오피스 API + WebSocket |
/webhook, /webhook/ |
deployer:9000 |
Gitea Webhook |
/media/music/ |
/data/music/ (파일 직접 서빙) |
생성된 오디오 파일 |
/media/travel/.thumb/ |
/data/thumbs/ (파일 직접 서빙) |
썸네일 캐시 |
/media/travel/ |
/data/travel/ (파일 직접 서빙) |
원본 사진 |
/assets/ |
정적 파일 (장기 캐시) | Vite 해시 파일 |
/ |
SPA fallback (try_files → index.html) |
6. 기술 스택
| 레이어 | 기술 |
|---|---|
| Backend 언어 | Python 3.12 |
| API 프레임워크 | FastAPI |
| DB | SQLite (/app/data/*.db) |
| 스케줄러 | APScheduler |
| 컨테이너 | Docker (python:3.12-slim 기반) |
| AI 연동 | Ollama (Llama 3.1) — Windows PC (192.168.45.59) |
| 주식 API | KIS (한국투자증권) Open API |
7. 자동 배포 흐름
개발자 git push → Gitea → Webhook (HMAC SHA256 검증)
→ deployer 컨테이너 → /scripts/deploy.sh
→ rsync(REPO→RUNTIME) → docker compose up -d --build
- 배포 스크립트 위치:
scripts/deploy-nas.sh(레포) /scripts/deploy.sh(런타임) - 환경변수 파일:
.env(RUNTIME_PATH, REPO_PATH, PHOTO_PATH, PUID, PGID 등) - 백업:
.releases/디렉토리에 자동 백업
8. 로컬 개발 환경
# .env 기본값으로 즉시 실행 가능 (RUNTIME_PATH=., PHOTO_PATH=./mock_data/photos)
docker compose up -d
| 서비스 | 로컬 URL |
|---|---|
| Frontend + API | http://localhost:8080 |
| Lotto Backend | http://localhost:18000 |
| Travel API | http://localhost:19000 |
| Stock Lab | http://localhost:18500 |
| Blog Lab | http://localhost:18700 |
| Realestate Lab | http://localhost:18800 |
9. 서비스별 핵심 정보
lotto-lab (backend/)
- DB:
/app/data/lotto.db - 데이터 소스:
smok95.github.io/lotto/results/ - 파일 구조:
main.py,db.py,recommender.py,collector.py,checker.py,generator.py,analyzer.py,utils.py,purchase_manager.py,strategy_evolver.py
lotto.db 테이블
| 테이블 | 설명 |
|---|---|
draws |
로또 당첨번호 |
recommendations |
추천 이력 (즐겨찾기·태그·채점 포함) |
simulation_runs |
시뮬레이션 실행 기록 |
simulation_candidates |
시뮬레이션 후보 (점수 5종) |
best_picks |
현재 활성 최적 번호 20개 (is_active 플래그로 교체) |
purchase_history |
구매 이력 (실제/가상, 번호, 전략 출처, 결과) |
strategy_performance |
전략별 회차 성과 (EMA 입력 데이터) |
strategy_weights |
메타 전략 가중치 (EMA + Softmax) |
weekly_reports |
주간 공략 리포트 캐시 |
todos |
투두리스트 (UUID PK) |
blog_posts |
블로그 글 (tags: JSON 배열) |
스케줄러 job
- 09:10 / 21:10 매일 — 당첨번호 동기화 + 채점 (
sync_latest→check_results_for_draw) - 00:05, 04:05, 08:05, 12:05, 16:05, 20:05 — 몬테카를로 시뮬레이션 (20,000후보 → 상위100 → best_picks 20개 교체)
lotto-lab API 목록
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET | /api/lotto/latest |
최신 당첨번호 |
| GET | /api/lotto/{drw_no} |
특정 회차 |
| GET | /api/lotto/stats |
번호 빈도 통계 |
| GET | /api/lotto/analysis |
5가지 통계 분석 리포트 |
| GET | /api/lotto/best |
시뮬레이션 최적 번호 (기본 20쌍) |
| GET | /api/lotto/simulation |
시뮬레이션 상세 결과 |
| GET | /api/lotto/recommend |
통계 기반 추천 |
| GET | /api/lotto/recommend/heatmap |
히트맵 기반 추천 |
| GET | /api/lotto/recommend/batch |
배치 추천 |
| POST | /api/lotto/recommend/batch |
배치 추천 저장 |
| GET | /api/lotto/recommend/smart |
전략 진화 기반 메타 추천 |
| GET | /api/lotto/purchase |
구매 이력 조회 (is_real, strategy, draw_no, days 필터) |
| POST | /api/lotto/purchase |
구매 등록 (실제/가상, 번호, 전략 출처 포함) |
| PUT | /api/lotto/purchase/{id} |
구매 이력 수정 |
| DELETE | /api/lotto/purchase/{id} |
구매 이력 삭제 |
| GET | /api/lotto/purchase/stats |
구매 통계 (전체/실제/가상 + 전략별) |
| GET | /api/lotto/strategy/weights |
전략별 가중치 + 성과 + trend |
| GET | /api/lotto/strategy/performance |
전략별 회차 성과 이력 (차트용) |
| POST | /api/lotto/strategy/evolve |
수동 가중치 재계산 |
| POST | /api/admin/simulate |
시뮬레이션 수동 실행 |
| POST | /api/admin/sync_latest |
당첨번호 수동 동기화 |
| GET | /api/history |
추천 이력 (limit, offset, favorite, tag, sort) |
| PATCH | /api/history/{id} |
즐겨찾기·메모·태그 수정 |
| DELETE | /api/history/{id} |
삭제 |
| GET | /api/todos |
투두 전체 목록 |
| POST | /api/todos |
투두 생성 (status: todo|in_progress|done) |
| PUT | /api/todos/{id} |
투두 수정 |
| DELETE | /api/todos/done |
완료 항목 일괄 삭제 |
| DELETE | /api/todos/{id} |
투두 개별 삭제 |
| GET | /api/blog/posts |
블로그 글 목록 ({"posts": [...]}, date DESC) |
| POST | /api/blog/posts |
블로그 글 생성 (date 미입력 시 오늘) |
| PUT | /api/blog/posts/{id} |
블로그 글 수정 |
| DELETE | /api/blog/posts/{id} |
블로그 글 삭제 |
stock-lab (stock-lab/)
- Windows AI 서버 연동:
WINDOWS_AI_SERVER_URL=http://192.168.45.59:8000 - KIS API 연동으로 실계좌 잔고·거래 조회
- 뉴스 스크래핑: 네이버 증권 + 해외 사이트
- DB:
/app/data/stock.db(articles, portfolio, broker_cash, asset_snapshots, sell_history 테이블) - 파일 구조:
main.py,db.py,scraper.py,price_fetcher.py,holidays.json
stock-lab API 목록
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET | /api/stock/news |
뉴스 조회 (limit, category 파라미터) |
| GET | /api/stock/indices |
주요 지표 실시간 조회 |
| POST | /api/stock/scrap |
수동 뉴스 스크랩 트리거 |
| GET | /api/trade/balance |
실계좌 잔고 조회 (Windows AI 서버 프록시) |
| POST | /api/trade/order |
주식 주문 (Windows AI 서버 프록시) |
| GET | /api/portfolio |
포트폴리오 전체 조회 (현재가·손익·예수금 포함) |
| POST | /api/portfolio |
종목 추가 |
| PUT | /api/portfolio/{id} |
종목 수정 |
| DELETE | /api/portfolio/{id} |
종목 삭제 |
| GET | /api/portfolio/cash |
예수금 전체 조회 |
| PUT | /api/portfolio/cash |
예수금 등록·수정 (upsert) |
| DELETE | /api/portfolio/cash/{broker} |
예수금 삭제 |
| POST | /api/portfolio/snapshot |
총 자산 스냅샷 수동 저장 |
| GET | /api/portfolio/snapshot/history |
스냅샷 이력 조회 (days=0: 전체, days=N: 최근 N건) |
| GET | /api/portfolio/sell-history |
매도 내역 조회 (broker, days 필터 선택) |
| POST | /api/portfolio/sell-history |
매도 기록 저장 (id 포함 레코드 반환) |
| PUT | /api/portfolio/sell-history/{id} |
매도 기록 수정 (수정된 레코드 반환) |
| DELETE | /api/portfolio/sell-history/{id} |
매도 기록 삭제 |
매도 히스토리 (sell_history)
- 독립 테이블 —
portfolio테이블과 별개로 관리 sold_at: UTC ISO8601 형식 (new Date().toISOString())realized_profit/realized_rate: 프론트 계산값 저장 (백엔드 재계산 무방)- 응답 정렬:
sold_at DESC(최신순)
총 자산 스냅샷 (asset_snapshots)
- 평일 15:40 APScheduler 자동 실행 (
save_daily_snapshot) - 공휴일 판별:
holidays.json(매년 수동 갱신, KRX 기준) →is_market_open()함수 - 같은 날 중복 저장 시 upsert (date UNIQUE 제약)
- 수동 저장:
POST /api/portfolio/snapshot - 이력 조회:
GET /api/portfolio/snapshot/history?days=30(ASC 정렬, 차트용)
스케줄러 job
- 08:00 매일 — 뉴스 스크랩 (
run_scraping_job) - 15:40 평일 — 총 자산 스냅샷 저장 (
save_daily_snapshot)
music-lab (music-lab/)
- 듀얼 프로바이더 음악 생성 서비스 (Suno API + 로컬 MusicGen)
- 생성된 오디오 파일:
/app/data/music/(Nginx가/media/music/로 직접 서빙) - DB:
/app/data/music.db(music_tasks, music_library 테이블) - 파일 구조:
main.py,db.py,suno_provider.py,local_provider.py - 생성 흐름: POST generate (provider 지정) → task_id 반환 → BackgroundTask → 파일 저장 → 라이브러리 자동 등록
Provider 구조
suno: Suno REST API (apicast.suno.ai/v1) — 보컬·가사·인스트루멘탈 지원local: Windows AI 서버 (MusicGen) — 인스트루멘탈 전용
music-lab API 목록
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET | /api/music/providers |
사용 가능한 프로바이더 목록 |
| GET | /api/music/models |
Suno 모델 목록 (V4~V5.5) |
| GET | /api/music/credits |
Suno 크레딧 조회 |
| POST | /api/music/generate |
음악 생성 (provider, model, vocal_gender, negative_tags, style_weight, audio_weight) |
| GET | /api/music/status/{task_id} |
생성 상태 폴링 |
| POST | /api/music/lyrics |
Suno AI 가사 생성 |
| GET | /api/music/library |
라이브러리 전체 조회 |
| POST | /api/music/library |
트랙 수동 추가 |
| DELETE | /api/music/library/{id} |
트랙 삭제 |
| POST | /api/music/extend |
곡 연장 |
| POST | /api/music/vocal-removal |
보컬/인스트 분리 (2트랙) |
| POST | /api/music/cover-image |
커버 이미지 2장 생성 |
| POST | /api/music/wav |
WAV 고음질 변환 |
| POST | /api/music/stem-split |
12스템 분리 (50cr) |
| GET | /api/music/timestamped-lyrics |
타임스탬프 가사 (가라오케) |
| POST | /api/music/style-boost |
AI 스타일 프롬프트 생성 |
| POST | /api/music/upload-cover |
외부 음원 AI Cover |
| POST | /api/music/upload-extend |
외부 음원 확장 |
| POST | /api/music/add-vocals |
인스트에 AI 보컬 추가 |
| POST | /api/music/add-instrumental |
보컬에 AI 반주 추가 |
| POST | /api/music/video |
뮤직비디오 MP4 생성 |
| GET | /api/music/lyrics/library |
저장된 가사 목록 |
| POST | /api/music/lyrics/library |
가사 저장 |
| PUT | /api/music/lyrics/library/{id} |
가사 수정 |
| DELETE | /api/music/lyrics/library/{id} |
가사 삭제 |
환경변수
SUNO_API_KEY: Suno API 키 (미설정 시 Suno provider 비활성화)MUSIC_AI_SERVER_URL: 로컬 MusicGen 서버 URL (미설정 시 local provider 비활성화)MUSIC_MEDIA_BASE: 오디오 파일 공개 URL prefix (기본/media/music)MUSIC_DATA_PATH: NAS 오디오 파일 저장 경로 (기본./data/music)
music_library 테이블 (확장 컬럼)
provider:suno|local— 생성에 사용된 프로바이더lyrics: Suno 생성 가사 텍스트image_url: Suno 생성 커버 이미지 URLsuno_id: Suno 곡 ID (CDN 참조용)file_hash: MD5 해시 (rename 감지용)cover_images: JSON 배열 — 커버 이미지 URL 목록wav_url: WAV 변환 URLvideo_url: 뮤직비디오 URLstem_urls: JSON 객체 — 12스템 URL 맵
Suno 생성 특이사항
- 1회 생성 시 2개 변형(variation) 반환 → 둘 다 라이브러리에 저장
- CDN URL(
cdn1.suno.ai)은 임시 → 반드시 로컬 다운로드 필요 - 가사 섹션 태그:
[Verse],[Chorus],[Bridge],[Instrumental]등
realestate-lab (realestate-lab/)
- 공공데이터포털 API 연동: 한국부동산원 청약홈 분양정보 조회 서비스
- DB:
/app/data/realestate.db(announcements, announcement_models, user_profile, match_results, collect_log 테이블) - 파일 구조:
main.py,db.py,collector.py,matcher.py,models.py
환경변수
DATA_GO_KR_API_KEY: 공공데이터포털 API 키 (미설정 시 수동 등록만 가능)
스케줄러 job
- 09:00 매일 — 청약 공고 수집 + 매칭 (
scheduled_collect) - 00:00 매일 — 상태 갱신 + 재매칭 (
scheduled_status_update)
realestate-lab API 목록
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET | /api/realestate/announcements |
공고 목록 (region, status, house_type, matched_only, sort, page, size) |
| GET | /api/realestate/announcements/{id} |
공고 상세 (주택형별 포함) |
| POST | /api/realestate/announcements |
수동 공고 등록 |
| PUT | /api/realestate/announcements/{id} |
공고 수정 |
| DELETE | /api/realestate/announcements/{id} |
공고 삭제 |
| POST | /api/realestate/collect |
수동 수집 트리거 |
| GET | /api/realestate/collect/status |
마지막 수집 결과 |
| GET | /api/realestate/profile |
내 프로필 조회 |
| PUT | /api/realestate/profile |
프로필 수정 (upsert) |
| GET | /api/realestate/matches |
매칭 결과 목록 |
| POST | /api/realestate/matches/refresh |
매칭 재계산 |
| PATCH | /api/realestate/matches/{id}/read |
신규 알림 읽음 처리 |
| GET | /api/realestate/dashboard |
요약 (진행중 공고수, 신규 매칭수, 다가오는 일정) |
travel-proxy (travel-proxy/)
- 원본 사진:
/data/travel/(RO) - 썸네일 캐시:
/data/thumbs/(RW) - 메타:
/data/travel/_meta/region_map.json,regions.geojson - 썸네일: 480×480 리사이징 (Pillow), 온디맨드 생성 후 영구 캐시
- 메모리 캐시: TTL 300초 (앨범 스캔 결과)
travel-proxy API 목록
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET | /api/travel/regions |
지역 GeoJSON |
| GET | /api/travel/photos |
사진 목록 (region, page=1, size=20) |
| POST | /api/travel/reload |
메모리 캐시 초기화 |
blog-lab (blog-lab/)
- 블로그 마케팅 수익화 서비스 (키워드 분석 → AI 글 생성 → 마케팅 강화 → 품질 리뷰 → 포스팅 → 수익 추적)
- AI 엔진: Claude API (Anthropic,
claude-sonnet-4-20250514) - 웹 검색: Naver Search API (블로그 + 쇼핑) + 상위 블로그 본문 크롤링
- DB:
/app/data/blog_marketing.db - 파일 구조:
main.py,db.py,config.py,naver_search.py,content_generator.py,marketer.py,quality_reviewer.py,web_crawler.py
파이프라인: 리서치(+크롤링) → 작가(초안) → 마케터(링크 삽입) → 평가자(6기준 60점)
상태 흐름: draft → marketed → reviewed → published
blog_marketing.db 테이블
| 테이블 | 설명 |
|---|---|
keyword_analyses |
키워드 분석 결과 (네이버 검색 데이터 + 경쟁도/기회 점수 + 크롤링 본문) |
blog_posts |
블로그 글 (draft → marketed → reviewed → published) |
brand_links |
브랜드커넥트 제휴 링크 (post_id/keyword_id FK) |
commissions |
포스트별 월간 클릭/구매/수익 |
generation_tasks |
비동기 작업 상태 (research/generate/market/review) |
prompt_templates |
AI 프롬프트 템플릿 (DB 저장, 코드 배포 없이 수정 가능) |
blog-lab API 목록
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET | /api/blog-marketing/status |
서비스 상태 (API 키 설정 현황) |
| POST | /api/blog-marketing/research |
키워드 분석 시작 (+ 상위 블로그 크롤링) |
| GET | /api/blog-marketing/research/history |
분석 이력 조회 |
| GET | /api/blog-marketing/research/{id} |
분석 상세 조회 |
| DELETE | /api/blog-marketing/research/{id} |
분석 삭제 |
| GET | /api/blog-marketing/task/{task_id} |
작업 상태 폴링 |
| POST | /api/blog-marketing/generate |
작가 단계: AI 글 생성 (크롤링 참고 + 링크 반영) |
| POST | /api/blog-marketing/market/{post_id} |
마케터 단계: 전환율 강화 + 링크 삽입 |
| POST | /api/blog-marketing/review/{post_id} |
평가자 단계: 품질 리뷰 (6기준 × 10점, 42/60 통과) |
| POST | /api/blog-marketing/regenerate/{post_id} |
피드백 기반 재생성 |
| POST | /api/blog-marketing/links |
브랜드커넥트 링크 등록 |
| GET | /api/blog-marketing/links |
링크 조회 (post_id, keyword_id 필터) |
| PUT | /api/blog-marketing/links/{id} |
링크 수정 |
| DELETE | /api/blog-marketing/links/{id} |
링크 삭제 |
| GET | /api/blog-marketing/posts |
포스트 목록 (status 필터) |
| GET | /api/blog-marketing/posts/{id} |
포스트 상세 |
| PUT | /api/blog-marketing/posts/{id} |
포스트 수정 |
| DELETE | /api/blog-marketing/posts/{id} |
포스트 삭제 |
| POST | /api/blog-marketing/posts/{id}/publish |
발행 (네이버 URL 등록) |
| GET | /api/blog-marketing/commissions |
수익 내역 조회 |
| POST | /api/blog-marketing/commissions |
수익 기록 추가 |
| PUT | /api/blog-marketing/commissions/{id} |
수익 기록 수정 |
| DELETE | /api/blog-marketing/commissions/{id} |
수익 기록 삭제 |
| GET | /api/blog-marketing/dashboard |
대시보드 집계 |
환경변수
ANTHROPIC_API_KEY: Claude API 키 (미설정 시 AI 생성 비활성화)NAVER_CLIENT_ID: 네이버 검색 API 클라이언트 IDNAVER_CLIENT_SECRET: 네이버 검색 API 시크릿BLOG_DATA_PATH: SQLite DB 저장 경로 (기본./data/blog)
agent-office (agent-office/)
- AI 에이전트 가상 오피스 — 2D 픽셀아트 사무실에서 에이전트가 실제 작업 수행
- stock-lab/music-lab 기존 API를 서비스 프록시로 호출 (직접 DB 접근 없음)
- 실시간 상태 동기화: WebSocket (
/api/agent-office/ws) - 텔레그램 봇: 양방향 알림 + 승인 (인라인 키보드)
- DB:
/app/data/agent_office.db(agent_config, agent_tasks, agent_logs, telegram_state 테이블) - 파일 구조:
main.py,db.py,config.py,models.py,websocket_manager.py,service_proxy.py,telegram_bot.py,scheduler.py,agents/base.py,agents/stock.py,agents/music.py
에이전트 FSM 상태: idle → working → waiting (승인 대기) → reporting → break (휴식)
환경변수
STOCK_LAB_URL: stock-lab 내부 URL (기본http://stock-lab:8000)MUSIC_LAB_URL: music-lab 내부 URL (기본http://music-lab:8000)TELEGRAM_BOT_TOKEN: 텔레그램 봇 토큰 (미설정 시 알림 비활성화)TELEGRAM_CHAT_ID: 텔레그램 채팅 IDTELEGRAM_WEBHOOK_URL: 텔레그램 Webhook URL
스케줄러 job
- 07:30 매일 — 주식 뉴스 요약 (
stock_news_job) - 60초 간격 — 유휴 에이전트 휴식 체크 (
idle_check_job)
agent-office API 목록
| 메서드 | 경로 | 설명 |
|---|---|---|
| WS | /api/agent-office/ws |
WebSocket (init, agent_state, task_complete, command_result) |
| GET | /api/agent-office/agents |
에이전트 목록 |
| GET | /api/agent-office/agents/{id} |
에이전트 상세 (설정 + 상태) |
| PUT | /api/agent-office/agents/{id} |
에이전트 설정 수정 |
| GET | /api/agent-office/agents/{id}/tasks |
에이전트 작업 이력 |
| GET | /api/agent-office/agents/{id}/logs |
에이전트 로그 |
| GET | /api/agent-office/tasks/pending |
승인 대기 작업 목록 |
| GET | /api/agent-office/tasks/{id} |
작업 상세 |
| POST | /api/agent-office/command |
에이전트에 명령 전송 |
| POST | /api/agent-office/approve |
작업 승인/거부 |
| POST | /api/agent-office/telegram/webhook |
텔레그램 Webhook 수신 |
| GET | /api/agent-office/states |
전체 에이전트 상태 조회 |
deployer (deployer/)
- Webhook 검증:
X-Gitea-Signature(HMAC SHA256,compare_digest사용) WEBHOOK_SECRET환경변수로 시크릿 관리- Webhook 수신 즉시
{"ok": True}응답 후 BackgroundTask로 배포 실행 - 배포 타임아웃: 10분 (
scripts/deploy.sh)
10. 주의사항
- Nginx trailing slash:
/api/portfolio는 trailing slash 없이도 매칭되도록 두 location 블록으로 처리 - 라우트 순서:
DELETE /api/todos/done은DELETE /api/todos/{id}보다 반드시 먼저 등록 (FastAPI prefix 매칭 순서) - PUID/PGID: travel-proxy는 NAS 파일 권한을 위해 PUID/PGID를 환경변수로 주입
- 캐시 전략:
index.html은no-store,assets/는 1년 장기 캐시(immutable) - Frontend 배포: git push로 자동 배포되지 않음. 로컬 빌드 후 NAS에 수동 업로드
- .env 파일: 절대 커밋 금지.
.env.example만 레포에 포함 - 공휴일 목록:
stock-lab/app/holidays.json매년 수동 갱신 필요 (KRX 기준) - Windows AI 서버 IP:
192.168.45.59— 공유기 DHCP 고정 예약으로 고정. Tailscale은 Synology에서 TCP 불가(userspace 모드)라 로컬 IP 사용 - 현재가 조회: 네이버 모바일 API → HTML 파싱 폴백, 3분 TTL 캐시 (
price_fetcher.py) - 시뮬레이션 교체 방식:
best_picks는 교체형 — 새 시뮬레이션 실행 시is_active=0으로 비활성화 후 신규 입력