diff --git a/app/api/dashboard.py b/app/api/dashboard.py index d583df4..5c9246d 100644 --- a/app/api/dashboard.py +++ b/app/api/dashboard.py @@ -44,6 +44,10 @@ class DashboardResponse(BaseModel): pipeline_status: list[PipelineStatus] failed_count: int total_documents: int + # 카운트 분리: 문서함(비-note/비-news) / 메모(memo+note) / 뉴스(news) + documents_count: int = 0 + memos_count: int = 0 + news_count: int = 0 @router.get("/", response_model=DashboardResponse) @@ -108,9 +112,23 @@ async def get_dashboard( ) failed_count = failed_result.scalar() or 0 - # 전체 문서 수 - total_result = await session.execute(select(func.count(Document.id))) - total_documents = total_result.scalar() or 0 + # 전체 문서 수 + 카테고리별 분리 (단일 쿼리) + # 문서함: 비-note, 비-news / 메모: memo+note / 뉴스: news 유입 경로 기준 + count_result = await session.execute( + text(""" + SELECT + COUNT(*) AS total, + COUNT(*) FILTER (WHERE source_channel != 'news' AND file_type != 'note') AS documents, + COUNT(*) FILTER (WHERE source_channel = 'memo' AND file_type = 'note') AS memos, + COUNT(*) FILTER (WHERE source_channel = 'news') AS news + FROM documents WHERE deleted_at IS NULL + """) + ) + counts = count_result.one() + total_documents = counts[0] + documents_count = counts[1] + memos_count = counts[2] + news_count = counts[3] return DashboardResponse( today_added=today_added, @@ -135,4 +153,7 @@ async def get_dashboard( ], failed_count=failed_count, total_documents=total_documents, + documents_count=documents_count, + memos_count=memos_count, + news_count=news_count, ) diff --git a/frontend/src/lib/stores/system.ts b/frontend/src/lib/stores/system.ts index 15c44c0..3cfbb5b 100644 --- a/frontend/src/lib/stores/system.ts +++ b/frontend/src/lib/stores/system.ts @@ -35,6 +35,9 @@ export interface DashboardSummary { pipeline_status: PipelineStatus[]; failed_count: number; total_documents: number; + documents_count: number; + memos_count: number; + news_count: number; } const POLL_INTERVAL_MS = 60_000; diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte index 2bbd44a..0732bb0 100644 --- a/frontend/src/routes/+page.svelte +++ b/frontend/src/routes/+page.svelte @@ -15,7 +15,7 @@ import EmptyState from '$lib/components/ui/EmptyState.svelte'; import Skeleton from '$lib/components/ui/Skeleton.svelte'; import FormatIcon from '$lib/components/FormatIcon.svelte'; - import { Calendar, Inbox, Scale, FileText, Activity } from 'lucide-svelte'; + import { Calendar, Inbox, Scale, FileText, Activity, StickyNote, Newspaper } from 'lucide-svelte'; // ─── 파생 값들 ─────────────────────────────────────────────── // legacy store + runes 혼합: 템플릿에서 $dashboardSummary로 자동 구독. @@ -175,70 +175,78 @@ {:else if summary}
전체 문서
-문서함
+- {summary.total_documents.toLocaleString()} +
+ {(summary.documents_count ?? 0).toLocaleString()}
-- 오늘 +{summary.today_added} +
오늘 +{summary.today_added}
+메모
++ {(summary.memos_count ?? 0).toLocaleString()}
Inbox 미분류
-뉴스
++
+ {(summary.news_count ?? 0).toLocaleString()} +
+승인 대기
+{summary.inbox_count}
- {#if summary.inbox_count > 0} - - 분류하기 → - - {:else} -대기 없음
- {/if}법령 알림
-{summary.law_alerts}
-오늘 변경
+{summary.law_alerts}
+오늘 변경
시스템 상태
-시스템
++
{systemView.label}
-{systemView.sub}
+{systemView.sub}
{/if}