refactor: 전체 코드베이스 감사 기반 리팩토링 — 버그 수정, 데드코드 제거, 보안 강화
P0 버그 수정: - stock-lab: trade 엔드포인트 NameError 수정 (resp 미정의) - deployer: 동시 배포 시 HTTP 200 → 503 반환 P1 데드코드 제거: - stock-lab: fetch_overseas_news(), get_broker_cash() 제거 - blog-lab: 미사용 urlparse import 제거 - lotto-lab: 중복 inline import json 7곳 제거 P2 성능/효율 개선: - lotto-lab: 가중 샘플링 3중 복사 → utils.weighted_sample_6() 통합 - lotto-lab: DB 인덱스 3개 추가 (recommendations, purchase_history) - stock-lab: Pydantic .dict() → .model_dump() 호환 - blog-lab: 페이지네이션 상한(le=100) 추가 P3 보안/인프라: - nginx: X-Frame-Options, X-Content-Type-Options, Referrer-Policy 헤더 추가 - docker-compose: travel-proxy CORS 와일드카드 → localhost 전용 - Dockerfile: music-lab, blog-lab, realestate-lab에 PYTHONUNBUFFERED 추가 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -17,11 +17,11 @@ from .db import (
|
||||
init_db, save_articles, get_latest_articles,
|
||||
add_portfolio_item, get_all_portfolio, get_portfolio_item,
|
||||
update_portfolio_item, delete_portfolio_item,
|
||||
upsert_broker_cash, get_all_broker_cash, get_broker_cash, delete_broker_cash,
|
||||
upsert_broker_cash, get_all_broker_cash, delete_broker_cash,
|
||||
upsert_asset_snapshot, get_asset_snapshots,
|
||||
add_sell_history, get_sell_history, update_sell_history, delete_sell_history,
|
||||
)
|
||||
from .scraper import fetch_market_news, fetch_major_indices, fetch_overseas_news
|
||||
from .scraper import fetch_market_news, fetch_major_indices
|
||||
from .price_fetcher import get_current_prices
|
||||
|
||||
app = FastAPI()
|
||||
@@ -118,17 +118,11 @@ def on_startup():
|
||||
|
||||
def run_scraping_job():
|
||||
logger.info("뉴스 스크래핑 시작")
|
||||
|
||||
# 1. 국내
|
||||
|
||||
articles_kr = fetch_market_news()
|
||||
count_kr = save_articles(articles_kr)
|
||||
|
||||
# 2. 해외 (임시 차단)
|
||||
# articles_world = fetch_overseas_news()
|
||||
# count_world = save_articles(articles_world)
|
||||
count_world = 0
|
||||
|
||||
logger.info(f"스크래핑 완료: 국내 {count_kr}건, 해외 {count_world}건")
|
||||
|
||||
logger.info(f"스크래핑 완료: 국내 {count_kr}건")
|
||||
|
||||
@app.get("/health")
|
||||
def health():
|
||||
@@ -156,14 +150,16 @@ def trigger_scrap():
|
||||
def get_balance():
|
||||
"""계좌 잔고 조회 (Windows AI Server Proxy)"""
|
||||
logger.info(f"Requesting Balance from {WINDOWS_AI_SERVER_URL}")
|
||||
resp = None
|
||||
try:
|
||||
resp = requests.get(f"{WINDOWS_AI_SERVER_URL}/trade/balance", timeout=5)
|
||||
if resp.status_code != 200:
|
||||
logger.error(f"Balance Error: {resp.status_code}")
|
||||
return JSONResponse(status_code=resp.status_code, content=resp.json())
|
||||
return resp.json()
|
||||
except requests.JSONDecodeError:
|
||||
return JSONResponse(status_code=resp.status_code, content={"error": f"Upstream error {resp.status_code}"})
|
||||
except ValueError:
|
||||
status = resp.status_code if resp is not None else 502
|
||||
return JSONResponse(status_code=status, content={"error": f"Upstream error {status}"})
|
||||
except Exception as e:
|
||||
logger.error(f"Balance Connection Failed: {e}")
|
||||
return JSONResponse(status_code=500, content={"error": "Connection Failed"})
|
||||
@@ -179,14 +175,16 @@ class OrderRequest(BaseModel):
|
||||
def order_stock(req: OrderRequest):
|
||||
"""주식 매수/매도 주문 (Windows AI Server Proxy)"""
|
||||
logger.info(f"Order Request: {req.action} {req.ticker} x{req.quantity}")
|
||||
resp = None
|
||||
try:
|
||||
resp = requests.post(f"{WINDOWS_AI_SERVER_URL}/trade/order", json=req.dict(), timeout=10)
|
||||
resp = requests.post(f"{WINDOWS_AI_SERVER_URL}/trade/order", json=req.model_dump(), timeout=10)
|
||||
if resp.status_code != 200:
|
||||
logger.error(f"Order Error: {resp.status_code}")
|
||||
return JSONResponse(status_code=resp.status_code, content=resp.json())
|
||||
return resp.json()
|
||||
except requests.JSONDecodeError:
|
||||
return JSONResponse(status_code=resp.status_code, content={"error": f"Upstream error {resp.status_code}"})
|
||||
except ValueError:
|
||||
status = resp.status_code if resp is not None else 502
|
||||
return JSONResponse(status_code=status, content={"error": f"Upstream error {status}"})
|
||||
except Exception as e:
|
||||
logger.error(f"Order Connection Failed: {e}")
|
||||
return JSONResponse(status_code=500, content={"error": "Connection Failed"})
|
||||
@@ -368,7 +366,7 @@ def update_portfolio(item_id: int, req: PortfolioUpdateRequest):
|
||||
"""포트폴리오 종목 수정"""
|
||||
if get_portfolio_item(item_id) is None:
|
||||
return JSONResponse(status_code=404, content={"error": "Item not found"})
|
||||
update_portfolio_item(item_id, **req.dict())
|
||||
update_portfolio_item(item_id, **req.model_dump())
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user