Portfolio Case Study

Yurasis Article

The public article reader built into the Yurasis platform: a server-rendered blog reader with per-blog primary color theming, Schema.org structured data, hreflang alternates, view tracking, related posts, and AdSense support — all derived dynamically from each blog's configuration without a separate deployment.

June 22, 20264 min readLive service
JSON-LD block types
4 (Article / Blog / BreadcrumbList / FAQ)
Multi-tenant
One route, N blogs
Theming
Per-blog primary color + AdSense publisher ID

Project brief

Client
Yurasis platform
Role
Reader architecture, SEO structured data, multi-tenant theming, hreflang routing, view analytics
Stack
Next.js 15 App RouterTypeScript strict modePrisma + PostgreSQLSchema.org JSON-LD (Article, Blog, FAQ, BreadcrumbList)hreflang alternatesGoogle AdSenseView tracking APIRelated posts engine

Highlights

Single route (/[lang]/article/[blogSlug]/[postSlug]) renders any blog on the platform — theming, nav, and footer adapt to each blog's primaryColor, name, and categories without a separate codebase per blog.
Every article page emits four Schema.org JSON-LD blocks: BlogPosting, Blog, BreadcrumbList, and FAQPage (when faqSchema is present), giving search engines structured signals for rich results without a third-party SEO plugin.
hreflang alternates are built from the post's stored translation references — canonicalization logic picks the right locale-slug pair even when the same content exists in multiple languages with different slugs.
View count is tracked client-side after hydration (fire-and-forget POST to /api/public/blogs/[slug]/posts/[slug]/view) so SSR performance is never blocked by analytics.

Multi-tenant reader

One route serves every blog on the platform

The article reader lives at /[lang]/article/[blogSlug]/[postSlug]. The blogSlug segment selects which blog's configuration to apply — primary color, name, categories, AdSense publisher ID, and site verification tags all come from the blog record. There is no per-blog deployment, no per-blog codebase, and no per-blog build.

A special slug value ("portfolio") short-circuits the lookup and renders portfolio case study content instead of a database post — the same route handler serves both article reading and the portfolio case study pages without a separate route.

SEO

Four Schema.org blocks and canonical hreflang alternates

Each article page injects BlogPosting (with headline, description, author, publisher, image, wordCount, and timeRequired), Blog (with publisher reference), BreadcrumbList (three-item chain: Yurasis → blog → post), and FAQPage (when the post stores a faqSchema array). All four blocks are rendered as <script type="application/ld+json"> in the server HTML.

hreflang alternates are derived from the post's translationOf and translations fields. canonicalTranslation() picks the authoritative locale-slug pair, preferring the requested language, falling back to the blog's defaultLocale, then ko/en. The canonical URL is always the default-locale version of the post.

Related posts

Same-category recommendations without a recommendation engine

When a post has a category, the reader fetches up to six posts from the same category, excludes the current post, and renders the first four as a related posts grid below the article. When no category exists the query falls back to the post's first tag. No embeddings, no ML model — just a filtered API call at request time.

The related post cards link to the canonical path for each post, respecting the language preference of the reader. If a translation exists for the reader's locale, the card links to that translation.

Analytics

Client-side view tracking that never blocks rendering

View count is incremented by a ViewTracker client component that fires a POST request after hydration using a keepalive fetch. The server renders the article without waiting for the view event — the count the reader sees is viewCount + 1, accounting for the current visit before the API confirms it.

Daily metrics are aggregated separately by a cron job that writes to blog_daily_metrics, keeping the hot path (article render) free from analytics writes. The dashboard reads from the aggregated table, not the live viewCount column.

Interactive build
Yurasis Article

The article reader is the live public surface of the Yurasis platform. Browse any published blog to see per-blog theming, structured data, related posts, and multilingual routing in action with real AI-generated content.

See demo

Yurasis

상호: 유라시스 랩

대표: 이규형

사업자등록번호: 842-05-03371

주소: 서울특별시 강남구 선릉로69길 19, 101동 401호(역삼동, 역삼래미안)

업태: 정보통신업 · 종목: 응용 소프트웨어 개발 및 공급업, 컴퓨터 프로그래밍 서비스업

TEL: 010-2709-9846

Email: siholee@yurasis.com

Yurasis Article Case study | YURASIS Portfolio