diff --git a/frontend/src/lib/components/MarkdownStatusBadge.svelte b/frontend/src/lib/components/MarkdownStatusBadge.svelte index c73c29c..e4f8a88 100644 --- a/frontend/src/lib/components/MarkdownStatusBadge.svelte +++ b/frontend/src/lib/components/MarkdownStatusBadge.svelte @@ -77,6 +77,7 @@ case 'processing': return { tone: 'accent', label: 'Markdown 변환 중', tooltip: null }; case 'success': + case 'completed': // API field_validator 가 DB 'success'→'completed' remap (S1 backend) — 동의어 return { tone: 'success', label: 'Markdown', diff --git a/frontend/src/lib/utils/mdStatus.ts b/frontend/src/lib/utils/mdStatus.ts new file mode 100644 index 0000000..6311e82 --- /dev/null +++ b/frontend/src/lib/utils/mdStatus.ts @@ -0,0 +1,25 @@ +// md_status 어휘 단일 source. +// +// DB CHECK enum 은 'success' 이지만, API 직렬화 시 field_validator +// `_db_success_to_completed`(app/api/documents.py) 가 'success' → 'completed' 로 remap 한다 +// (S1 backend). 나머지 상태(pending/processing/partial/skipped/failed)는 양쪽 동일. +// +// 따라서 프론트는 두 어휘를 모두 "성공" 으로 취급해야 S1 backend 배포 전(API='success')· +// 후(API='completed') 모두 안전하다. (DB↔API enum divergence guard — md_status 비교는 +// 반드시 이 헬퍼 경유, raw `=== 'success'` / `=== 'completed'` 산재 금지.) + +/** DB 'success' 또는 API 'completed' = 변환 성공(markdown 준비됨). */ +export function isMdSuccess(status: string | null | undefined): boolean { + return status === 'success' || status === 'completed'; +} + +/** md상태 칩 렌더 대상 상태. pending/null 은 숨김(legacy 대량 노이즈 회피). */ +export function isMdStatusVisible(status: string | null | undefined): boolean { + return ( + status === 'processing' || + isMdSuccess(status) || + status === 'partial' || + status === 'skipped' || + status === 'failed' + ); +} diff --git a/frontend/src/routes/documents/+page.svelte b/frontend/src/routes/documents/+page.svelte index 0e2604f..1f2d96d 100644 --- a/frontend/src/routes/documents/+page.svelte +++ b/frontend/src/routes/documents/+page.svelte @@ -11,6 +11,7 @@ import { Info, X, Plus, Trash2, Tag, FolderTree, Sparkles, ChevronLeft, ArrowUpDown } from 'lucide-svelte'; import DocumentViewer from '$lib/components/DocumentViewer.svelte'; import MarkdownStatusBadge from '$lib/components/MarkdownStatusBadge.svelte'; + import { isMdStatusVisible } from '$lib/utils/mdStatus'; import UploadDropzone from '$lib/components/UploadDropzone.svelte'; import Drawer from '$lib/components/ui/Drawer.svelte'; import Modal from '$lib/components/ui/Modal.svelte'; @@ -679,7 +680,7 @@ {#if doc.ai_sub_group}
하위{doc.ai_sub_group}
{/if}
수정{shortDate(doc.updated_at || doc.created_at)}
{#if size}
원본{size}
{/if} - {#if ['processing', 'success', 'partial', 'skipped', 'failed'].includes(doc.md_status)}
md 상태
{/if} + {#if isMdStatusVisible(doc.md_status)}
md 상태
{/if} {#if doc.read_count}
읽음{doc.read_count}회
{/if} diff --git a/frontend/src/routes/documents/[id]/+page.svelte b/frontend/src/routes/documents/[id]/+page.svelte index 3ab8d40..40ad723 100644 --- a/frontend/src/routes/documents/[id]/+page.svelte +++ b/frontend/src/routes/documents/[id]/+page.svelte @@ -6,6 +6,7 @@ import { page } from '$app/stores'; import { goto } from '$app/navigation'; import { api, getAccessToken } from '$lib/api'; + import { isMdSuccess } from '$lib/utils/mdStatus'; import { addToast } from '$lib/stores/toast'; import { marked } from 'marked'; import DOMPurify from 'dompurify'; @@ -147,7 +148,7 @@ let pdfViewMode = $state('markdown'); // 'markdown' | 'pdf' let lastDocId = $state(null); let canShowMarkdown = $derived( - !!(doc?.md_status === 'success' && doc?.md_content?.trim()) + !!(isMdSuccess(doc?.md_status) && doc?.md_content?.trim()) ); $effect(() => {