본문으로 건너뛰기
cccskills
무료GitHub에 공개

seo-patterns

Meta tag patterns, structured data (JSON-LD), Core Web Vitals optimization, and SSR/SSG strategies for search visibility.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

연동 도구X (Twitter)
설치 방법 보기

포함된 파일(1)

  • SKILL.md12.2 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

SEO Patterns

Technical SEO patterns for web applications and content sites.

Meta Tags Template

// Next.js App Router metadata
import { Metadata } from 'next'

export function generateMetadata({ params }): Metadata {
  const product = getProduct(params.slug)

  return {
    title: `${product.name} | Your App`,        // 50-60 chars
    description: product.summary.slice(0, 155), // 150-160 chars
    alternates: {
      canonical: `https://example.com/products/${params.slug}`,
      languages: {
        'en': `https://example.com/en/products/${params.slug}`,
        'tr': `https://example.com/tr/products/${params.slug}`,
      }
    },
    openGraph: {
      title: product.name,
      description: product.summary,
      url: `https://example.com/products/${params.slug}`,
      siteName: 'Your App',
      images: [{
        url: product.imageUrl,
        width: 1200,
        height: 630,
        alt: product.name,
      }],
      type: 'website',
      locale: 'en_US',
    },
    twitter: {
      card: 'summary_large_image',
      title: product.name,
      description: product.summary,
      images: [product.imageUrl],
    },
    robots: {
      index: true,
      follow: true,
      'max-image-preview': 'large',
      'max-snippet': -1,
    }
  }
}

Structured Data (JSON-LD)

// Product schema
function ProductJsonLd({ product }: { product: Product }) {
  const schema = {
    '@context': 'https://schema.org',
    '@type': 'Product',
    name: product.name,
    description: product.description,
    image: product.images,
    sku: product.sku,
    brand: {
      '@type': 'Brand',
      name: product.brand,
    },
    offers: {
      '@type': 'Offer',
      url: `https://example.com/products/${product.slug}`,
      priceCurrency: 'USD',
      price: product.price,
      availability: product.inStock
        ? 'https://schema.org/InStock'
        : 'https://schema.org/OutOfStock',
      seller: {
        '@type': 'Organization',
        name: 'Your App',
      }
    },
    aggregateRating: product.reviewCount > 0 ? {
      '@type': 'AggregateRating',
      ratingValue: product.avgRating,
      reviewCount: product.reviewCount,
    } : undefined,
  }

  return <script type="application/ld+json">{JSON.stringify(schema)}</script>
}

// FAQ schema (wins featured snippets)
function FaqJsonLd({ faqs }: { faqs: { question: string; answer: string }[] }) {
  const schema = {
    '@context': 'https://schema.org',
    '@type': 'FAQPage',
    mainEntity: faqs.map(faq => ({
      '@type': 'Question',
      name: faq.question,
      acceptedAnswer: {
        '@type': 'Answer',
        text: faq.answer,
      }
    }))
  }

  return <script type="application/ld+json">{JSON.stringify(schema)}</script>
}

// BreadcrumbList schema
function BreadcrumbJsonLd({ items }: { items: { name: string; url: string }[] }) {
  const schema = {
    '@context': 'https://schema.org',
    '@type': 'BreadcrumbList',
    itemListElement: items.map((item, i) => ({
      '@type': 'ListItem',
      position: i + 1,
      name: item.name,
      item: item.url,
    }))
  }

  return <script type="application/ld+json">{JSON.stringify(schema)}</script>
}

Core Web Vitals Optimization

// LCP (Largest Contentful Paint) - Target: < 2.5s
// Priority: preload hero image, avoid lazy-loading above-fold content
import Image from 'next/image'

function HeroSection({ image }: { image: string }) {
  return (
    <Image
      src={image}
      alt="Hero"
      width={1200}
      height={600}
      priority           // Preload, no lazy loading
      sizes="100vw"      // Responsive sizing hints
      quality={85}       // Balance quality vs size
    />
  )
}

// CLS (Cumulative Layout Shift) - Target: < 0.1
// Always set explicit width/height on images and embeds
function VideoEmbed({ videoId }: { videoId: string }) {
  return (
    <div style={{ aspectRatio: '16/9', width: '100%' }}>
      <iframe
        src={`https://youtube.com/embed/${videoId}`}
        width="100%"
        height="100%"
        loading="lazy"
        title="Video"
      />
    </div>
  )
}

// INP (Interaction to Next Paint) - Target: < 200ms
// Defer heavy computation, use web workers
function SearchResults() {
  const [query, setQuery] = useState('')
  const [results, setResults] = useState([])

  // Debounce input to prevent blocking main thread
  const debouncedSearch = useMemo(
    () => debounce((q: string) => {
      startTransition(() => {
        setResults(search(q))
      })
    }, 300),
    []
  )

  return (
    <input
      type="search"
      onChange={(e) => {
        setQuery(e.target.value)
        debouncedSearch(e.target.value)
      }}
    />
  )
}

SSR/SSG Strategy

// Static Generation (SSG): content that rarely changes
// Best for: blog posts, product pages, documentation
export async function generateStaticParams() {
  const products = await getProductSlugs()
  return products.map(slug => ({ slug }))
}

export default async function ProductPage({ params }) {
  const product = await getProduct(params.slug)
  return <ProductDetail product={product} />
}

// Incremental Static Regeneration (ISR): SSG with refresh
export const revalidate = 3600  // Regenerate every hour

// Server-Side Rendering (SSR): dynamic, personalized content
// Use only when content changes per request (user-specific, real-time data)
export const dynamic = 'force-dynamic'

Sitemap and Robots

// app/sitemap.ts
export default async function sitemap(): MetadataRoute.Sitemap {
  const products = await getAllProducts()
  const posts = await getAllBlogPosts()

  return [
    { url: 'https://example.com', lastModified: new Date(), priority: 1.0 },
    ...products.map(p => ({
      url: `https://example.com/products/${p.slug}`,
      lastModified: p.updatedAt,
      changeFrequency: 'weekly' as const,
      priority: 0.8,
    })),
    ...posts.map(p => ({
      url: `https://example.com/blog/${p.slug}`,
      lastModified: p.updatedAt,
      changeFrequency: 'monthly' as const,
      priority: 0.6,
    })),
  ]
}

// app/robots.ts
export default function robots(): MetadataRoute.Robots {
  return {
    rules: [
      { userAgent: '*', allow: '/', disallow: ['/api/', '/admin/', '/checkout/'] },
    ],
    sitemap: 'https://example.com/sitemap.xml',
  }
}

Checklist

  • Unique title (50-60 chars) and description (150-160 chars) per page
  • Canonical URL set on every page (avoid duplicate content)
  • JSON-LD structured data for products, FAQs, breadcrumbs, articles
  • Open Graph + Twitter Card meta tags for social sharing
  • LCP < 2.5s: preload hero images, inline critical CSS
  • CLS < 0.1: explicit dimensions on all images/embeds
  • INP < 200ms: debounce inputs, defer heavy JS
  • Dynamic sitemap.xml updated with all crawlable pages
  • robots.txt blocks API, admin, and auth routes from crawling
  • hreflang tags for multi-language sites

SaaS Landing Page Anatomy

┌──────────────────────────────────────┐
│  Nav: Logo | Features | Pricing | CTA │ ← Sticky, minimal
├──────────────────────────────────────┤
│  HERO SECTION                        │
│  H1: Value proposition (6-12 words)  │
│  Subtitle: How it works (1 sentence) │
│  CTA button + social proof line      │
│  Hero image/screenshot               │
├──────────────────────────────────────┤
│  SOCIAL PROOF BAR                    │
│  "Trusted by X teams" + logos        │
├──────────────────────────────────────┤
│  FEATURES (3-4 cards)                │
│  Icon + Title + 1 sentence each      │
├──────────────────────────────────────┤
│  HOW IT WORKS (3 steps)              │
│  Step 1 → Step 2 → Step 3           │
├──────────────────────────────────────┤
│  TESTIMONIALS (2-3 quotes)           │
│  Photo + Name + Role + Quote         │
├──────────────────────────────────────┤
│  PRICING (3 tiers)                   │
│  Free | Pro (highlighted) | Enterprise│
├──────────────────────────────────────┤
│  FAQ (5-8 questions, JSON-LD)        │
├──────────────────────────────────────┤
│  FINAL CTA                           │
│  Repeat hero CTA with urgency        │
├──────────────────────────────────────┤
│  FOOTER                              │
│  Legal links + sitemap links         │
└──────────────────────────────────────┘

Hero Section Formulas

Formula 1 — Problem-Solution:
  H1: "Stop [pain point]. Start [desired outcome]."
  Example: "Stop losing leads. Start converting visitors."

Formula 2 — Before-After:
  H1: "[Tool] turns [bad state] into [good state]."
  Example: "[Product] turns messy spreadsheets into real-time dashboards."

Formula 3 — Social Proof Lead:
  H1: "[N]+ teams use [tool] to [outcome]."
  Example: "2,000+ teams use [Product] to ship 3x faster."

Pricing Page SEO

// Pricing page structured data
function PricingJsonLd({ plans }: { plans: Plan[] }) {
  const schema = {
    '@context': 'https://schema.org',
    '@type': 'WebPage',
    name: 'Pricing',
    description: 'Plans and pricing for Your App',
    mainEntity: plans.map(plan => ({
      '@type': 'Offer',
      name: plan.name,
      price: plan.price,
      priceCurrency: 'USD',
      description: plan.description,
      eligibleDuration: { '@type': 'QuantitativeValue', value: 1, unitCode: 'MON' }
    }))
  }

  return <script type="application/ld+json">{JSON.stringify(schema)}</script>
}

// SEO tips for pricing pages:
// - Title: "[Product] Pricing — Free, Pro & Enterprise Plans"
// - Include pricing in meta description (Google shows it in snippets)
// - Use comparison table with feature checkmarks
// - FAQ section below pricing (common objections → JSON-LD)
// - "Free tier" callout improves CTR from search results

SaaS-Specific Structured Data

// SoftwareApplication schema (rich results for SaaS)
function SoftwareAppJsonLd({ app }: { app: SaaSApp }) {
  const schema = {
    '@context': 'https://schema.org',
    '@type': 'SoftwareApplication',
    name: app.name,
    applicationCategory: app.category,  // 'BusinessApplication', 'DeveloperApplication'
    operatingSystem: 'Web',
    offers: {
      '@type': 'AggregateOffer',
      lowPrice: app.freeTier ? '0' : app.lowestPrice,
      highPrice: app.highestPrice,
      priceCurrency: 'USD',
      offerCount: app.planCount
    },
    aggregateRating: app.reviewCount > 0 ? {
      '@type': 'AggregateRating',
      ratingValue: app.avgRating,
      ratingCount: app.reviewCount,
      bestRating: 5,
      worstRating: 1
    } : undefined,
    screenshot: app.screenshotUrl,
    featureList: app.features.join(', ')
  }

  return <script type="application/ld+json">{JSON.stringify(schema)}</script>
}

Anti-Patterns

  • Client-side only rendering: search engines may not execute JS
  • Duplicate content without canonical: pages compete against themselves
  • Missing alt text on images: accessibility and image search penalty
  • Blocking CSS/JS in robots.txt: prevents proper rendering by crawlers
  • Infinite scroll without pagination URLs: content invisible to crawlers
  • Meta description over 160 chars: truncated in search results
  • Pricing page without structured data: misses rich snippet opportunity
  • Landing page H1 focused on brand, not value: low click-through from SERPs

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

WCAG 2.2 AA compliance, ARIA patterns, keyboard navigation, screen reader optimization

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

vibeeval/vibecosystem5382026년 8월 9일 업데이트

axe-core integration, WCAG 2.2 AA checklist, keyboard navigation testing, screen reader testing, and ARIA pattern validation.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

vibeeval/vibecosystem5382026년 8월 9일 업데이트

Steam-style achievement system with XP, levels, streaks, and skill trees. Gamifies the development workflow. 25 achievements across 5 categories.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

vibeeval/vibecosystem5382026년 8월 9일 업데이트

Framework for measuring and tracking agent response quality over time. Detects regressions before they reach production. Use when evaluating agent changes, auditing quality, or establishing performance baselines.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

vibeeval/vibecosystem5382026년 8월 9일 업데이트

Agent Context Isolation

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

vibeeval/vibecosystem5382026년 8월 9일 업데이트

Agent ve skill dosyalarinin yapisal dogrulamasi. Frontmatter kontrol, naming convention, zorunlu bolum kontrolu, tutarlilik denetimi. Yeni agent/skill eklendiginde veya mevcut dosyalar duzenlediginde otomatik calistirilir.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

vibeeval/vibecosystem5382026년 8월 9일 업데이트

vibeeval의 스킬 모두 보기

이 스킬의 문제 신고