reviewer 지적사항 반영:
1. KIS 분봉이 한 번에 30개만 와서 10분봉이 최대 3개만 나오던 문제 →
fetch_minute_range() 추가. FID_INPUT_HOUR_1 을 30분씩 후퇴시키며
페이지네이션, 중복 ts 자연 dedupe, max_pages=20 으로 무한루프 방지.
_ensure_intraday_fresh 는 last_ts+1m ~ now 빈 구간만 채우므로 평소엔
1~2 페이지로 끝남.
2. 장외/주말에 매번 KIS 를 때리던 문제 →
- 주말: 'weekend' 반환, KIS 안 부름 (분봉 endpoint 는 당일만 지원)
- 평일 장외 + 오늘 데이터 있음: 'cached_closed' 반환
- 장중 + 10분 이내: 'fresh' 반환
토큰/조회 제한 다시 밟지 않음.
3. 프론트 horizon 입력 60 vs 백엔드 30 불일치 →
PredictionPanel 의 cap 을 30 으로 맞춤. 백엔드 predict.py 의 학습/검증
범위와 일치. placeholder 도 '1~30' 으로 명시.
- backend/app/api/chart.py: interval=10m|1d|1w|1mo. 10m 은 ohlcv_1m 을
time_bucket(10min) 으로 집계, stale(>10분) 이면 KIS 분봉 fetch 후 재조회.
1w/1mo 는 ohlcv_daily 를 date_trunc 로 집계. today 필드 추가.
- backend/app/fetch/kis.py: fetch_minute_price() 추가 (tr_id FHKST03010200).
KIS 응답 KST 시각을 tz-aware datetime 으로 변환, 오름차순 정렬.
- web/lib/api.ts: ChartInterval 타입, getChart(interval), predict(horizons[]).
- web/components/StockChart.tsx: 10m 이면 timeVisible. 일·주·월에서 오늘
화살표 마커 표시. ISO datetime 도 파싱.
- web/components/PredictionPanel.tsx: 단기/중기/장기 프리셋 + 사용자 직접
지정 (예: 1,2,3,7). API 에 horizons 배열 전달.
- web/app/[code]/page.tsx: interval 칩 (10분/일/주/월). 10m 일 때 60초마다
폴링. interval 별 기본 lookback (10m=1, 1d=180, 1w=730, 1mo=1825).
리뷰어 지적: docker-compose 가 NEXT_PUBLIC_API_BASE=http://localhost:8000 을
주입해서 클라이언트 번들에 localhost 가 inline 됨. 사금향 게임컴 (192.168.10.13)
브라우저에선 동작하지만, 같은 내부망의 다른 PC 또는 외부 검증자가
http://192.168.10.13:3000 에 접속하면 fetch 가 그 PC 의 localhost:8000 으로 가서
연결 실패. 백엔드는 정상인데도 '검색 결과 없음' 으로 보임.
해석 우선순위:
1) NEXT_PUBLIC_API_BASE 가 비 localhost 값 → 그대로 (프로덕션 도메인 케이스)
2) 브라우저 → window.location.hostname:8000 (LAN/localhost 자동 대응)
3) SSR 폴백 → localhost:8000
localhost/127.0.0.1 판별은 //(localhost|127.0.0.1)(?::|$) 정규식 — 'localhost.evil.com'
같은 서브도메인 우회는 매치 안 됨. node 로 7케이스 검증 완료.
web/app 코드만이라 사금향 PC 는 restart.bat 으로 반영 (next dev hot-reload).
`web/package.json` 의 next/eslint-config-next ^14.2.33 상향 (6c79230) 에
맞춰 lockfile 갱신. npm 이 resolve 한 실제 버전은 14.2.35 (14.2.x 최신
patched). 자동 생성되는 next-env.d.ts 의 문서 URL 한 줄도 함께 동기화.
검증:
- `npm install --package-lock-only` 통과
- `npm run typecheck` 통과
- `npm run build` 통과 (Next.js 14.2.35, 4 페이지 정상 생성)
- ensemble.predict() 가 chronos_raw / lgbm_raw 를 함께 반환
- predict_and_store() 가 매 호출마다 3종 행 적재:
model='ensemble' (user_triggered=인자)
model='chronos' (user_triggered=FALSE, shadow)
model='lgbm' (user_triggered=FALSE, shadow)
- retrain_weekly.adjust_weights(): 최근 30일 prediction_outcomes 의
chronos vs lgbm hit_rate 로 ensemble_weights upsert
w_chronos = clamp(0.1, hr_c/(hr_c+hr_l), 0.9), w_lgbm = 1 - w_chronos
모델별 표본 < 10 이면 기본값(0.6/0.4) 유지
- API 응답에 saved_shadow_ids 추가 (TS 타입도 동기화)
- README: 동작 모델 메모 섹션을 실제 구현과 일치하도록 갱신
리뷰어 지적 3번 (ensemble_weights 가 영원히 갱신 안됨, upsert_weights 미호출) 해결.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>