diff --git a/frontend/src/routes/+layout.svelte b/frontend/src/routes/+layout.svelte
index 169b508..6393d8c 100644
--- a/frontend/src/routes/+layout.svelte
+++ b/frontend/src/routes/+layout.svelte
@@ -99,6 +99,7 @@
+
+ import { onMount } from 'svelte';
+ import { api, type ApiError } from '$lib/api';
+ import Card from '$lib/components/ui/Card.svelte';
+ import Skeleton from '$lib/components/ui/Skeleton.svelte';
+ import EmptyState from '$lib/components/ui/EmptyState.svelte';
+ import Tabs from '$lib/components/ui/Tabs.svelte';
+ import Badge from '$lib/components/ui/Badge.svelte';
+ import Button from '$lib/components/ui/Button.svelte';
+
+ type Topic = {
+ topic_rank: number;
+ topic_label: string;
+ summary: string;
+ article_ids: number[];
+ article_count: number;
+ importance_score: number;
+ llm_fallback_used: boolean;
+ };
+ type Country = { country: string; topics: Topic[] };
+ type Digest = {
+ digest_date: string;
+ total_articles: number;
+ total_countries: number;
+ total_topics: number;
+ llm_calls: number;
+ llm_failures: number;
+ status: string;
+ countries: Country[];
+ };
+
+ let digest = $state(null);
+ let loading = $state(true);
+ let error = $state(null);
+ let country = $state('');
+
+ async function load() {
+ loading = true;
+ error = null;
+ try {
+ digest = await api('/digest/latest');
+ const countries = digest?.countries ?? [];
+ if (!countries.some((c) => c.country === country)) {
+ country = countries[0]?.country ?? '';
+ }
+ } catch (e) {
+ const err = e as ApiError;
+ if (err && err.status === 404) {
+ digest = null;
+ error = null;
+ return;
+ }
+ error = err?.detail ?? (e as Error)?.message ?? '알 수 없는 오류';
+ } finally {
+ loading = false;
+ }
+ }
+
+ onMount(load);
+
+ let tabs = $derived(
+ (digest?.countries ?? []).map((c) => ({ id: c.country, label: c.country })),
+ );
+ let topics = $derived(
+ digest?.countries?.find((c) => c.country === country)?.topics ?? [],
+ );
+
+
+
+
+ 뉴스 다이제스트
+ {#if digest}
+
+ {digest.digest_date} · {digest.countries.length}국 · {digest.total_topics}주제
+
+ {/if}
+
+
+ {#if loading}
+
+
+
+ {:else if error}
+
+
+
+ {:else if !digest || digest.countries.length === 0}
+
+ {:else}
+
+ {#snippet children(_activeId)}
+ {#if topics.length === 0}
+
+ {:else}
+
+ {#each topics as t (t.topic_rank)}
+
+
+
+ {t.topic_rank}. {t.topic_label}
+
+ {#if t.llm_fallback_used}
+ fallback
+ {/if}
+
+ {t.summary}
+
+ {t.article_count} articles · importance {t.importance_score.toFixed(2)}
+
+
+ {/each}
+
+ {/if}
+ {/snippet}
+
+ {/if}
+