1. Introduction: Post Categorization Scalability and Serverless Invocations
SvelteKit Blog Engine (SKBE) is a self-hosted, modern blogging engine featuring native multilingual support (Korean, English, and Japanese) and diverse media handlers. As publishing volume expands and varied content types accumulate, the post management dashboard (apps/admin/src/routes/posts) encountered two specific technical requirements:
- Multidimensional Categorization: Beyond chronological ordering or simple language separation, the admin needed a systematic way to filter by specific categories, isolate category-less standalone static pages (
page), review unpublished drafts (draft), and identify uncategorized posts without paginating through dozens of pages. - Minimizing Cloudflare Serverless Invocations: Frequent navigation between admin sections (Dashboard, Posts, Settings, Media) triggered SvelteKit's client-side SPA routing to fetch
__data.jsonon every transition, causing unnecessary Cloudflare Workers executions and repetitive D1 read queries.
The SKBE v1.0.1.2 update addresses these requirements by introducing an orthogonal two-tier filtering system and establishing a browser caching pipeline with smart cache busting to eliminate redundant serverless calls.
2. Orthogonal Two-Tier Filtering Architecture: Language Axis × Classification Axis
1) Structural Layout: Two-Tier Filter Toolbar
Previously, the admin dashboard provided only a single row of language tabs. Locating drafts or specific category posts required manual multi-page traversals.
v1.0.1.2 introduces a two-tier toolbar that pairs a primary language axis (Tier 1) with a secondary category/type axis (Tier 2):
┌────────────────────────────────────────────────────────────────────────────────────────┐
│ [Tier 1: Language Tabs] │
│ [All (35)] [KR 한국어 (20)] [EN English (10)] [JA 日本語 (5)] │
├────────────────────────────────────────────────────────────────────────────────────────┤
│ [Tier 2: Category & Special Classifications Toolbar] │
│ [All (35)] │ [📁 Dev (12)] [📁 Life (6)] │ [📄 Static Pages (4)] [📝 Drafts (3)] [📂 Uncat (8)]│
└────────────────────────────────────────────────────────────────────────────────────────┘

2) Distinct Handling for Special Classifications
Beyond conventional database category slugs, three operational states are isolated into dedicated filter tabs:
📄 Static Pages(type === 'page'): Filters standalone pages such as About, Terms of Service, and Privacy Policy away from standard blog feed streams.📝 Drafts(status === 'draft'): Aggregates unpublished drafts for streamlined editing and review workflows.📂 Uncategorized(type !== 'page' && !category_slug): Highlights regular articles lacking category assignment to maintain organizational hygiene.
3) Svelte 5 Runes: Reactive In-Memory Synchronization
When switching languages in Tier 1 (e.g., KR ➔ EN), the categories used by English posts, along with category post counts and special classification counts, are recalculated in-memory in real time using Svelte 5's $derived.by:
// [apps/admin/src/routes/posts/+page.svelte]
// Reactive count derivation for drafts, static pages, and uncategorized posts per language
let specialCounts = $derived.by(() => {
let draft = 0, page = 0, uncategorized = 0;
postsByLang.forEach((p: any) => {
if (p.status === 'draft') draft++;
if (p.type === 'page') page++;
if (p.type !== 'page' && (!p.category_slug || p.category_slug.trim() === '')) {
uncategorized++;
}
});
return { draft, page, uncategorized };
});
4) Safeguards: Unique Post Numbering & Pagination Bounds
- Post Numbering Integrity (
#1-kr): The post numbering logic (postNumberMap) calculates labels strictly against the unfiltered raw dataset (cachedPosts). This ensures post identity numbers remain consistent regardless of active category or status filters. - Pagination Out-of-Bounds Protection: Switching to a category with fewer items immediately resets
currentPage = 1, while an$effectguard clamps the page index within validtotalPagesboundaries.
3. Minimizing Cloudflare Workers Invocations via Browser Caching
1) The Overhead of Client-Side SPA Navigation
Under SvelteKit's default routing behavior, navigating between admin routes prompts an HTTP request for __data.json to execute +page.server.ts. For administrators frequently inspecting settings, media, and articles, this generated high volumes of billable Workers requests and D1 read operations.
2) Browser HTTP Caching via Cache-Control
To eliminate these calls, +page.server.ts now specifies browser caching headers:
// [apps/admin/src/routes/posts/+page.server.ts]
export const load: PageServerLoad = async ({ locals, setHeaders, url }) => {
const isRefreshed = url.searchParams.has('refreshed');
if (!isRefreshed) {
// Standard view: serve from browser cache -> 0 Worker invocations
setHeaders({
'cache-control': 'private, max-age=86400, stale-while-revalidate=3600'
});
} else {
// Invalidation request: bypass cache and fetch directly from D1
setHeaders({
'cache-control': 'no-store, no-cache, must-revalidate'
});
}
// ... Parallel D1 queries
};
When an administrator navigates back to Posts from Dashboard or Media, the browser answers directly from memory/disk cache. No request hits Cloudflare Workers, and zero D1 read operations occur.
3) localStorage Persistence & Smart Cache Busting
- Instant Initial Load: Even across browser restarts, cached metadata in
localStorage(skbe_admin_posts_cache_v1) enables immediate UI rendering without waiting for network round-trips. - Automated Invalidation on Mutations:
- Creating (
new) or editing ([id]) a post redirects to/posts?refreshed=${Date.now()}, bypassing both HTTP and local caches to hydrate with fresh D1 data. - Deleting a post immediately clears the
localStoragekey and triggers a timestamped navigation.
- Creating (
- Manual Refresh Control (
[🔄]Button): A dedicated refresh button in the header allows administrators to force a clean cache purge and re-fetch from the database on demand.
4. Multilingual (i18n) Dictionary & Hub Syndication Enhancements
1) 14 New UI Translation Keys Registered
All newly introduced UI strings—including the refresh button, two-tier filter tabs, classification tooltips, and contextual empty state prompts—are formally defined in the centralized dictionary (packages/shared/src/i18n/index.ts):
// [packages/shared/src/i18n/index.ts]
"admin.posts.filter_page": { "ko": "정적 페이지", "en": "Static Pages", "ja": "固定ページ" },
"admin.posts.filter_draft": { "ko": "초안", "en": "Drafts", "ja": "下書き" },
"admin.posts.filter_uncategorized": { "ko": "미분류", "en": "Uncategorized", "ja": "未分類" },
"admin.posts.btn_refresh": { "ko": "캐시 비우고 최신 데이터로 새로고침", "en": "Clear cache and refresh with latest data", "ja": "キャッシュをクリアして最新データで更新" },
Switching admin language between Korean, English, and Japanese renders native labels without fallback anomalies.
2) Localized Site Name Extraction for Blog Hub Syndication
When syndicating posts to the centralized Blog Hub platform, the system now extracts the matching localized site title (resolveSiteName) from multilingual site_title settings JSON corresponding to the post's language (lang), ensuring accurate branding across syndicated feeds.
5. Conclusion
SKBE v1.0.1.2 focuses on practical operational efficiency: multidimensional post navigation in the UI paired with client-side caching architecture that curbs serverless network overhead and database reads.
We will continue refining system architecture to maintain high UI responsiveness and dependable data integrity as blog scale grows.
0 Comments
Login is required to write comments.