diff --git a/app/api/briefing.py b/app/api/briefing.py index f784a18..64cf2c0 100644 --- a/app/api/briefing.py +++ b/app/api/briefing.py @@ -195,8 +195,14 @@ async def regenerate( date 미지정 시 오늘 KST. 같은 날 row 존재 시 transaction 안에서 삭제 후 신규 생성. 응답 status='success' | 'partial' | 'failed' | 'empty'. """ + from core.config import settings from workers.briefing_worker import run + # held(정책상 정상 보류)를 409 로 표면화 (R8) — digest.py 정본 대칭. 이전엔 briefing_worker.run() + # 이 held/timeout/exception 셋 다 None 반환 → API 가 셋 다 500 으로 오보(silent-state-conflation). + if "briefing" in settings.pipeline_held_stages: + raise HTTPException(status_code=409, detail="briefing 단계가 일시 보류(held) 상태입니다") + result = await run(target_date=date) if result is None: raise HTTPException(status_code=500, detail="briefing 워커 실행 실패 (로그 확인)") diff --git a/app/models/study_question.py b/app/models/study_question.py index 040fab1..402e3f8 100644 --- a/app/models/study_question.py +++ b/app/models/study_question.py @@ -7,7 +7,7 @@ PR-2 가드레일: - correct_choice 변경 시 기존 attempt.is_correct 재계산 안 함 (기록은 그 시점의 사실). """ -from datetime import datetime +from datetime import datetime, timezone from pgvector.sqlalchemy import Vector from sqlalchemy import BigInteger, Boolean, DateTime, ForeignKey, Integer, SmallInteger, String, Text @@ -128,7 +128,9 @@ class StudyQuestionAttempt(Base): # PR-9: outcome 권장값 (correct/wrong/unsure). 강한 enum 미사용. outcome: Mapped[str] = mapped_column(String(20), nullable=False) answered_at: Mapped[datetime] = mapped_column( - DateTime(timezone=True), default=datetime.now, nullable=False + # TZ-aware 명시 (R8) — naive datetime.now() 는 컨테이너 TZ 의존. 현 컨테이너=UTC 라 + # 값 동일(백필 불요)이나, 컨테이너 TZ 가 바뀌면 9시간 어긋나는 잠복 의존 제거. + DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), nullable=False ) # PR-10: 어떤 quiz 세션의 attempt 인지 (NULL = 세션 외 직접 입력 또는 세션 삭제됨). quiz_session_id: Mapped[int | None] = mapped_column(