"""검증용 수동 갱신 API. POST /api/refresh/{code} body: 없음 query: ?lookback_days=7 (기본) resp: refresh_one.RefreshReport.to_dict() POST /api/refresh/seed/symbols symbols 테이블 강제 재시드 (SEED 10 + KRX 전 종목). 부팅 시 시드가 실패한 경우 컨테이너 재기동 없이 복구하기 위한 admin 엔드포인트. """ from __future__ import annotations from fastapi import APIRouter, HTTPException, Query from sqlalchemy import text from app.db.connection import get_engine from app.fetch.symbols_seed import seed_symbols from app.pipelines.refresh_one import refresh_code router = APIRouter(prefix="/api", tags=["refresh"]) def _resolve_name(code: str) -> str | None: eng = get_engine() with eng.connect() as conn: row = conn.execute(text("SELECT name FROM symbols WHERE code = :code"), {"code": code}).first() return row[0] if row else None @router.post("/refresh/{code}") def refresh_endpoint( code: str, lookback_days: int = Query(default=7, ge=1, le=365), ) -> dict: name = _resolve_name(code) if not name: raise HTTPException(status_code=404, detail=f"unknown code: {code} (symbols 테이블에 없음. 시드 필요)") report = refresh_code(code, name, lookback_days=lookback_days) return report.to_dict() @router.post("/refresh/seed/symbols") def reseed_symbols() -> dict: """symbols 테이블 강제 재시드. 호출 예 (Windows cmd): curl -X POST http://localhost:8000/api/refresh/seed/symbols KRX 가 주말/장 마감 시간에 비정상 응답을 줄 때도 SEED 10 종목은 항상 보장하므로 엔드포인트는 200 을 돌려준다. 부분 성공 정보는 응답 body 에 담아 사용자가 판단. """ try: report = seed_symbols() return { "ok": True, "inserted": report.inserted, "updated": report.updated, "seed_marked": report.seed_marked, "markets": report.markets, } except Exception as e: # noqa: BLE001 # seed_symbols 내부에서 다 잡지만, 만에 하나 외부로 새는 예외 (logger 포매터 # 자체 버그 등) 도 200 으로 흡수해서 SEED 10 만이라도 살리는 게 UX 목표. return { "ok": False, "inserted": 0, "updated": 0, "seed_marked": 0, "markets": {}, "error": repr(e)[:300], }