Files
2nd/10_Wiki/Topics/Frontend/대규모 콘텐츠 기반 애플리케이션 및 전자상거래 플랫폼 구축.md
Antigravity Agent f8b21af4be Wiki cleanup: error-doc removal, dedup merge, link normalization
10_Wiki/Topics 대규모 정리:
- 오류 캡처/미완성 stub 문서 227개 제거
- 교차폴더 중복 43클러스터 병합 (63파일 → redirect)
- 링크명 정규화: 깨진 링크 수정·redirect 직결·개념 매핑 ~2,400건
- 카테고리 MOC 6개 신규 생성
- Graph 섹션 미해결 related-keyword 링크 10,058건 제거

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 23:52:15 +09:00

7.3 KiB
Raw Permalink Blame History

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-대규모-콘텐츠-기반-애플리케이션-및-전자상거래-플랫폼-구축 대규모 콘텐츠 기반 애플리케이션 및 전자상거래 플랫폼 구축 10_Wiki/Topics verified self
E-commerce Platform
Content Platform
Headless Commerce
none A 0.9 applied
frontend
ecommerce
content
nextjs
headless
2026-05-10 pending
language framework
typescript nextjs

대규모 콘텐츠 기반 애플리케이션 및 전자상거래 플랫폼 구축

매 한 줄

"매 SEO + 속도 + 개인화 의 trilemma". 백만 SKU + CMS 콘텐츠 + 개인화 추천 을 동시에 빠르게 보여줘야 한다. 2026 답: Next.js 15 PPR + ISR + Edge runtime + headless CMS (Sanity/Contentful) + Stripe/Shopify Hydrogen.

매 핵심

매 대규모 commerce 의 도전

  • 카탈로그: 100k-1M SKU — search/filter 빠르게.
  • SEO: PDP (product detail page) 가 organic traffic 핵심 — SSR/ISR 필수.
  • 개인화: 추천, cart, region pricing — per-user dynamic.
  • 트래픽 spike: BFCM (Black Friday) 10-100× 평소.
  • 글로벌: i18n, currency, tax, shipping zone.

매 architecture 패턴

  • Headless commerce: storefront (Next.js) + commerce engine (Shopify/Commerce Layer/Saleor) 분리.
  • Composable: CMS + commerce + search (Algolia) + reviews + auth — 매 best-of-breed.
  • Static + dynamic mix: PDP는 ISR, cart/checkout 은 dynamic, 매 PPR 로 한 page 안에서 mix.

매 응용

  1. Shopify storefront (custom Hydrogen).
  2. Magazine + commerce hybrid.
  3. B2B catalog (gated pricing).
  4. Marketplace (multi-vendor).

💻 패턴

Next.js 15 PPR (Partial Prerendering) for PDP

// app/products/[slug]/page.tsx
export const experimental_ppr = true;

export default async function PDP({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params;
  const product = await getProduct(slug); // 매 static (ISR)

  return (
    <>
      <ProductGallery images={product.images} />
      <ProductInfo product={product} />
      <Suspense fallback={<PriceSkeleton />}>
        <DynamicPrice productId={product.id} /> {/* 매 per-user / region */}
      </Suspense>
      <Suspense fallback={<RecsSkeleton />}>
        <Recommendations productId={product.id} />
      </Suspense>
    </>
  );
}

export async function generateStaticParams() {
  const top = await getTopProducts(1000);
  return top.map(p => ({ slug: p.slug }));
}

ISR with on-demand revalidation

export const revalidate = 3600; // 매 1h auto-revalidate

// app/api/revalidate/route.ts — webhook from CMS
export async function POST(req: Request) {
  const { slug, secret } = await req.json();
  if (secret !== process.env.REVALIDATE_SECRET) return new Response('forbidden', { status: 403 });
  revalidateTag(`product-${slug}`);
  return Response.json({ revalidated: true });
}

// in fetch
fetch(`${API}/products/${slug}`, { next: { tags: [`product-${slug}`] } });

Algolia search with InstantSearch

import { InstantSearch, SearchBox, Hits, RefinementList } from 'react-instantsearch';
import { liteClient } from 'algoliasearch/lite';

const client = liteClient(APP_ID, SEARCH_KEY);

<InstantSearch searchClient={client} indexName="products">
  <SearchBox />
  <RefinementList attribute="brand" />
  <RefinementList attribute="category" />
  <Hits hitComponent={ProductCard} />
</InstantSearch>

Headless CMS content (Sanity)

import { groq } from 'next-sanity';

const POST_QUERY = groq`*[_type == "post" && slug.current == $slug][0]{
  title, body, "author": author->name, publishedAt
}`;

export async function getPost(slug: string) {
  return client.fetch(POST_QUERY, { slug }, { next: { tags: [`post-${slug}`] } });
}
'use server';
import { cookies } from 'next/headers';

export async function addToCart(variantId: string, qty: number) {
  const cartId = (await cookies()).get('cart_id')?.value;
  const cart = cartId
    ? await shopify.cart.add(cartId, variantId, qty)
    : await shopify.cart.create(variantId, qty);
  (await cookies()).set('cart_id', cart.id, { httpOnly: true, secure: true });
  revalidateTag('cart');
}

i18n with next-intl

// app/[locale]/layout.tsx
import { NextIntlClientProvider } from 'next-intl';
import { getMessages } from 'next-intl/server';

export default async function Layout({ children, params }: { children: ReactNode, params: Promise<{ locale: string }> }) {
  const { locale } = await params;
  const messages = await getMessages();
  return (
    <html lang={locale}>
      <body>
        <NextIntlClientProvider messages={messages}>{children}</NextIntlClientProvider>
      </body>
    </html>
  );
}

Image optimization at scale

import Image from 'next/image';

<Image
  src={product.image}
  alt={product.name}
  width={800}
  height={800}
  sizes="(max-width: 768px) 100vw, 50vw"
  priority={isAboveFold}
  placeholder="blur"
  blurDataURL={product.imageBlur}
/>

Edge runtime for personalization

// middleware.ts
import { NextResponse } from 'next/server';

export function middleware(req: NextRequest) {
  const country = req.geo?.country ?? 'US';
  const res = NextResponse.next();
  res.cookies.set('region', country);
  return res;
}

Web Vitals tracking

'use client';
import { useReportWebVitals } from 'next/web-vitals';

export function Analytics() {
  useReportWebVitals(metric => {
    fetch('/api/vitals', { method: 'POST', body: JSON.stringify(metric) });
  });
  return null;
}

매 결정 기준

상황 Approach
< 1k SKU static-only + on-demand ISR.
1k-100k SKU ISR top-N + on-demand for tail.
1M+ SKU dynamic + heavy CDN cache.
Personalized price PPR — static shell + dynamic price hole.
Search Algolia / Meilisearch / Typesense.
BFCM-scale edge cache + queue checkout.

기본값: Next.js 15 + PPR + ISR + Algolia + Shopify Storefront API + Stripe.

🔗 Graph

🤖 LLM 활용

언제: 콘텐츠 + 거래 동시 제공, SEO 핵심, 100+ pages. 언제 X: SPA dashboard, 매 small custom shop (Shopify default theme 으로 충분).

안티패턴

  • Full SSR for everything: PDP 매 request 마다 DB hit → ISR + tag-based revalidate.
  • No CDN for images: origin 직접 serve → Vercel Image / Cloudflare Images / imgix.
  • Client-side cart in localStorage only: 매 device 간 sync 안 됨 → server cart + cookie id.
  • Synchronous 3rd-party scripts: GTM, A/B → 매 next/script strategy="lazyOnload".
  • Hardcoded i18n strings: 시작부터 namespace 분리.
  • No cache stampede protection: revalidate 시 동시 1000 request → SWR / lock.

🧪 검증 / 중복

  • Verified (Next.js 15 docs, Vercel commerce template, Shopify Hydrogen, web.dev/commerce).
  • 신뢰도 A.

🕓 Changelog

날짜 변경
2026-05-08 Phase 1
2026-05-10 Manual cleanup — Next.js 15 PPR + headless commerce stack