diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte index a92eb8d..66abf66 100644 --- a/frontend/src/routes/+page.svelte +++ b/frontend/src/routes/+page.svelte @@ -5,6 +5,7 @@ import { onMount } from 'svelte'; import { dashboardSummary, + refresh, type DashboardSummary, type PipelineStatus, type QueueLag, @@ -67,6 +68,7 @@ await api('/memos/', { method: 'POST', body: JSON.stringify({ content }) }); captureText = ''; addToast('success', '메모 저장됨'); + void refresh(); // 메모 수 등 요약 즉시 갱신(60s 폴 기다리지 않음) } catch { addToast('error', '메모 저장 실패'); } finally { @@ -103,7 +105,7 @@ article_count: topics[0].article_count, importance_score: topics[0].importance_score, country: topics[0].country, - date: d.date, + date: d.digest_date, }; } } catch { /* 디제스트 없으면 블록 자동 생략 */ } @@ -182,6 +184,7 @@ function formatTime(dateStr: string) { const d = new Date(dateStr); + if (isNaN(d.getTime())) return ''; // 빈 문자열/유효하지 않은 created_at → 'Invalid Date' 회피 const diff = Date.now() - d.getTime(); if (diff < 60000) return '방금'; if (diff < 3600000) return `${Math.floor(diff / 60000)}분 전`; @@ -262,7 +265,7 @@ -
+
{@render stat((summary.documents_count ?? 0).toLocaleString(), '문서', 'text-accent')} {@render stat((summary.news_count ?? 0).toLocaleString(), '뉴스')} {#if domainTotal > 0} @@ -480,6 +483,6 @@ {/snippet} diff --git a/frontend/src/routes/documents/+page.svelte b/frontend/src/routes/documents/+page.svelte index bc187f4..0aad960 100644 --- a/frontend/src/routes/documents/+page.svelte +++ b/frontend/src/routes/documents/+page.svelte @@ -231,8 +231,15 @@ goto(`/documents${qs ? '?' + qs : ''}`, { noScroll: true }); } - function selectDoc(doc) { - selectedDoc = selectedDoc?.id === doc.id ? null : doc; + async function selectDoc(doc) { + if (selectedDoc?.id === doc.id) { selectedDoc = null; return; } + selectedDoc = doc; // 즉시 표시(리더 + 기본 인스펙터) + // 인스펙터 풀 메타 하이드레이션 — 검색 결과(SearchResult)는 메타가 빈약(태그/크기/하위/md상태/읽음 없음). + // 풀 문서를 조회해 채운다(기존 GET /documents/{id}, 백엔드 무변). 리스트 모드도 md상태 등 보강. + try { + const full = await api(`/documents/${doc.id}`); + if (selectedDoc?.id === doc.id) selectedDoc = { ...doc, ...full }; + } catch { /* 실패 시 기본 정보 유지 */ } } // bulk 선택 @@ -271,7 +278,13 @@ if (!tag) return; await runBulk('태그 추가', async (id) => { const doc = sortedItems.find((d) => d.id === id); - const existing = Array.isArray(doc?.ai_tags) ? doc.ai_tags : []; + // ★ 검색 결과(SearchResult)는 ai_tags 가 없음 → 빈 배열로 PATCH 하면 기존 태그 전체 유실(덮어쓰기). + // 미확인이면 풀 문서를 조회해 실제 태그를 머지(데이터 손실 방지). + let existing = Array.isArray(doc?.ai_tags) ? doc.ai_tags : null; + if (existing == null) { + try { const full = await api(`/documents/${id}`); existing = Array.isArray(full?.ai_tags) ? full.ai_tags : []; } + catch { return; } // 현재 태그를 못 읽으면 덮어쓰지 않고 건너뜀 + } if (existing.includes(tag)) return; return api(`/documents/${id}`, { method: 'PATCH', body: JSON.stringify({ ai_tags: [...existing, tag] }) }); }); @@ -282,12 +295,6 @@ await runBulk('삭제', (id) => api(`/documents/${id}?delete_file=true`, { method: 'DELETE' })); } - function handleDocDelete() { - selectedDoc = null; - if (ui.isDrawerOpen('meta')) ui.closeDrawer(); - loadDocuments(); - } - function handleKeydown(e) { if (e.key === 'Escape') { if (selectedDoc && !ui.isDrawerOpen('meta') && !isXl.current) { selectedDoc = null; return; } @@ -298,7 +305,8 @@ let totalPages = $derived(Math.ceil(total / 50)); let items = $derived(searchResults || documents); let sortedItems = $derived.by(() => { - if (!sortKey) return items; + // 검색 모드는 서버 관련도순 유지 + SearchResult 에 updated_at 부재(NaN 비교=무의미) → 클라 정렬 비활성 + if (!sortKey || searchResults) return items; const arr = [...items]; const dir = sortDir === 'asc' ? 1 : -1; arr.sort((a, b) => { @@ -497,14 +505,21 @@
- - - {#if !loading}{total}건{/if} - + {#if searchResults} + + 관련도순 + + {#if !loading}{total}건{/if} + {:else} + + + {#if !loading}{total}건{/if} + + {/if}
diff --git a/frontend/src/routes/news/+page.svelte b/frontend/src/routes/news/+page.svelte index fed06d4..7f92075 100644 --- a/frontend/src/routes/news/+page.svelte +++ b/frontend/src/routes/news/+page.svelte @@ -205,6 +205,9 @@ {isLead ? 'mt-4' : ''} {topic.highlighted ? 'border-accent ring-2 ring-accent/25' : 'border-default'} {topic.is_read ? 'opacity-50 hover:opacity-80' : ''}"> + {#if topic.is_read} + 읽음 + {/if}
{q.quote}
-
{countryLabel(q.country)} · {q.source}
+
+ {#if q.country}{countryLabel(q.country)}{/if} + {q.source} +
{/each}