fix: DB 타임스탬프 KST 통일 + KIS 토큰 캐시 영속화

시간대 혼재: 모델 기본값은 datetime.utcnow(UTC), 수동 매매 등 일부 경로는 _get_kst_now(KST)로
저장해 같은 테이블에 9시간 차가 섞였다(화면 매매시각 02:14 등). 조회 구간(utcnow - days)도
KST 저장분과 비교돼 어긋났고, 추가매수 쿨다운은 (UTC now - KST created_at)이 음수라 상시
발동했다. app.core.timeutil.now_kst() 도입 후 모델 기본값 27곳과 app/ 전역 utcnow() 호출을
모두 KST 기준으로 통일(잔존 0건, 테스트로 고정).

KIS 토큰 캐시(~/.cache/auto-stock)가 컨테이너에만 있어 배포마다 사라지고 토큰을 새로
발급받다 KIS가 EGW00103(유효하지 않은 AppKey)로 거부 → 502·잔고 0 유발. 볼륨 마운트로
재배포 후에도 재사용.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-23 11:24:14 +09:00
parent e2d4b607cb
commit ec2fa2b423
22 changed files with 177 additions and 69 deletions

View File

@@ -27,6 +27,7 @@ from app.core.tenant_auth import CurrentUser, get_current_user
from app.models.models import UserKisCredential
from app.services.korea_investment_api import KoreaInvestmentAPI
from app.services.tenant.registry import user_context_registry
from app.core.timeutil import now_kst
logger = logging.getLogger(__name__)
router = APIRouter()
@@ -172,7 +173,7 @@ async def put_credentials(
if dup.scalar_one_or_none() is not None:
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="이미 다른 사용자가 등록한 앱키입니다.")
now = datetime.utcnow()
now = now_kst()
cred = await _get_own(db, user_id)
is_new = cred is None
if is_new:
@@ -278,7 +279,7 @@ async def verify_credentials(
"stock_value": _pick_float(output2, ["scts_evlu_amt", "evlu_amt_smtl_amt"]),
}
now = datetime.utcnow()
now = now_kst()
cred.last_verified_at = now
cred.is_enabled = True
cred.updated_at = now
@@ -306,7 +307,7 @@ async def patch_auto_trade(
)
cred.auto_trade_enabled = body.enabled
cred.updated_at = datetime.utcnow()
cred.updated_at = now_kst()
await db.commit()
# H3: 캐시된 UserContext.auto_trade_enabled 스냅샷이 갱신되도록 무효화(다음 호출에서 재조립).
await user_context_registry.invalidate(user_id)