Merge remote-tracking branch 'origin/feat/study-memo-card-p1' into feat/email-pkm-folder
This commit is contained in:
+16
-9
@@ -16,7 +16,7 @@ from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy import func, or_, select, update
|
||||
from sqlalchemy import and_, func, or_, select, update
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
@@ -261,24 +261,31 @@ async def due_cards(
|
||||
session: Annotated[AsyncSession, Depends(get_session)],
|
||||
limit: Annotated[int, Query(ge=1, le=200)] = 30,
|
||||
):
|
||||
"""오늘 복습할 카드 (due_at<=now, stage<4, 검수 통과만). due_at 오름차순."""
|
||||
"""오늘 복습할 카드 (검수 통과만). 두 부류:
|
||||
- 신규 승인 카드(progress 없음=첫 회상 전) — SR 큐 진입 경로(첫 회상). '암'이면 due 안
|
||||
박고 종료('큐 폭발 방지'), 애매/모름이면 평가 즉시 due(내일)로 입고.
|
||||
- 예정 due 카드(due_at<=now, stage<4).
|
||||
progress 는 user+card UNIQUE 라 outer join 으로 최대 1행. 예정 due 먼저, 신규(due NULL) 뒤로."""
|
||||
now = datetime.now(timezone.utc)
|
||||
P = StudyMemoCardProgress
|
||||
rows = (
|
||||
await session.execute(
|
||||
select(StudyMemoCard, StudyMemoCardProgress.review_stage)
|
||||
.join(StudyMemoCardProgress, StudyMemoCardProgress.card_id == StudyMemoCard.id)
|
||||
select(StudyMemoCard, P.review_stage)
|
||||
.outerjoin(P, and_(P.card_id == StudyMemoCard.id, P.user_id == user.id))
|
||||
.where(
|
||||
StudyMemoCard.user_id == user.id,
|
||||
StudyMemoCard.deleted_at.is_(None),
|
||||
StudyMemoCard.needs_review.is_(False),
|
||||
StudyMemoCardProgress.due_at.is_not(None),
|
||||
StudyMemoCardProgress.due_at <= now,
|
||||
or_(
|
||||
StudyMemoCardProgress.review_stage.is_(None),
|
||||
StudyMemoCardProgress.review_stage < 4,
|
||||
P.id.is_(None), # 신규(첫 회상 전) — progress 미생성
|
||||
and_(
|
||||
P.due_at.is_not(None),
|
||||
P.due_at <= now,
|
||||
or_(P.review_stage.is_(None), P.review_stage < 4),
|
||||
),
|
||||
),
|
||||
)
|
||||
.order_by(StudyMemoCardProgress.due_at.asc())
|
||||
.order_by(P.due_at.asc().nulls_last(), StudyMemoCard.id.asc())
|
||||
.limit(limit)
|
||||
)
|
||||
).all()
|
||||
|
||||
@@ -22,9 +22,11 @@
|
||||
import EmptyState from '$lib/components/ui/EmptyState.svelte';
|
||||
|
||||
// sr_schedule.py 단일 source 미러 — '암'(correct) 다음 복습일 라벨 전용(실제 스케줄은 백엔드).
|
||||
// stage===null = 신규 카드(progress 없음): '암'이면 백엔드가 due 안 박음(외움→큐 제외)이라 '안 나옴'.
|
||||
const REVIEW_INTERVAL_DAYS = { 1: 3, 2: 7, 3: 14 };
|
||||
function correctLabel(stage) {
|
||||
const ns = (stage ?? 0) + 1;
|
||||
if (stage === null || stage === undefined) return '안 나옴';
|
||||
const ns = stage + 1;
|
||||
if (ns >= 4) return '졸업';
|
||||
return `+${REVIEW_INTERVAL_DAYS[ns]}일`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user