Last updated: 2026-05-07
eunu.log is a Next.js App Router blog platform with:
- File-based MDX content under
posts/**. - Static generation for blog routes.
- Server-side view counting via Supabase RPC.
- Client-side analytics via Umami trackers.
- Token-driven UI styling (Tailwind + CSS variables).
- Framework: Next.js (
next@16.1.4) with App Router. - React:
react@19.2.3. - Rendering mix:
- Static prerendered route params via
generateStaticParamsfor post pages. - Server route handlers for feed and OG image.
- Domain-owned server actions for view counting.
- Static prerendered route params via
src/app/api/og/route.tsxruns at the edge and returns social images viaImageResponse.
layout.tsxcomposes global providers, metadata, JSON-LD, analytics, and dual roots (#app-root,#overlay-root).- Main pages:
/home (src/app/page.tsx)/bloglisting (src/app/blog/page.tsx)/blog/[slug]post detail (src/app/blog/[slug]/page.tsx)/resumeand/series
- Route handlers:
/feed.xml(src/app/feed.xml/route.ts)/api/og(src/app/api/og/route.tsx)
src/appimports page adapters from top-level domain modules and does not own domain policy.
blog/services/post-repository.tsrecursively discovers valid post folders (index.mdx+meta.json).meta.jsonis validated with Zod (FeedFrontmatterSchema).- MDX is loaded by dynamic import per folder path.
- Reading time is auto-derived from MDX when metadata omits it.
- Slug-to-folder cache accelerates lookups.
- Custom webpack rule in
next.config.mjsfor.mdxwith:remark-gfmrehype-slugrehype-pretty-code
blog/services/markdown-parser.tsparses MDX headings for TOC data.blog/ui/mdx/components.tsxmaps MDX nodes to UI components and interactive visualization widgets.
blog/: post schema, repository, publication policy, series, blog UI, view-count use case.resume/: resume data, ordering, resume UI.search/: command palette, search action, search recommendation.site/: home composition, AppShell, navigation, providers, site config.platform/: Supabase integration, Umami analytics, SEO helper, devtools.shared/: domain-agnostic UI, layout primitive, motion helper, testing helper, visualization widget.styles/: design tokens, global base styles, local font CSS.- Theming via
next-themesprovider insite/providers.
- Supabase client setup in
platform/integrations/supabase.ts. - View count data model:
- table:
public.views - rpc:
increment_view(slug_input text) -> bigint
- table:
- SQL provisioning script:
docs/database/supabase-view-count.sql.
- Umami event helpers in
platform/analytics/lib/analytics.ts. - Trackers in
platform/analytics/components/*. - Structured data via
JsonLdcomponent in layout and post page.
generateStaticParams()builds route list from posts metadata.- Request to
/blog/[slug]resolves post viagetFeedData(slug). - MDX source is parsed for heading structure (TOC).
- MDX component renders with mapped custom components.
- Client tracker records post view;
blog/api/view.tscan persist counter in Supabase.
/feed.xmlroute reads sorted metadata.- XML string is generated server-side.
- Response is cached with
s-maxage=3600.
- Client triggers view tracking.
- Server action normalizes slug and calls Supabase RPC.
- RPC upserts/increments
views.count. - Latest count is returned/fetched.
- Unit/component tests: Vitest + Testing Library across top-level modules and
src/app. - E2E tests: Playwright mobile-focused projects (
tests/e2e/**/*.spec.ts). - Linting/formatting: ESLint, Prettier, markdownlint, cspell.
- Coverage focus includes
blog,resume,search,site,platform,shared,styles, and selected route adapters.
- Docs/runtime drift:
- AGENTS and README mention older stack assumptions; package versions are newer.
- Provider boundary drift:
- Route/layout changes can reintroduce duplicated tracker mounts if
AppProvidersis bypassed.
- Route/layout changes can reintroduce duplicated tracker mounts if
- Boundary enforcement drift:
- Module boundaries are physical and documented, but lint-level enforcement is not yet configured.
- SEO endpoint mismatch risk:
- Post JSON-LD image URL differs from the actual OG route path/domain conventions.
복원한 아키텍처 결정의 상세 기록은 docs/adr/README.md에 둔다.
- Keep folder-based content (
posts/**) withmeta.json + index.mdx. - Keep Zod schema validation in content ingestion path.
- Keep token-first styling and avoid one-off visual constants where possible.
- Keep route-level separation for feed, OG, and view-count concerns.
- Keep Umami analytics separate from Supabase-backed public view counts.
- Keep top-level domain modules as documented in ADR 0011.