구글콘솔 넥스트js 아키텍처 seo 권장사항 정리글

당신은 Next.js 14 App Router 기반 프로젝트의 Google SEO를 Google 공식 권장사항 기준으로 완전히 구현합니다. 아래 항목을 빠짐없이 전부 구현해주세요. 스택 가정: Next.js 14 App Router, TypeScript, Tailwi...

당신은 Next.js 14 App Router 기반 프로젝트의 Google SEO를 Google 공식 권장사항 기준으로 완전히 구현합니다.
아래 항목을 빠짐없이 전부 구현해주세요.

스택 가정: Next.js 14 App Router, TypeScript, TailwindCSS, Supabase
환경변수: NEXT_PUBLIC_SITE_URL=https://실제도메인.com

1. 기술 SEO - 크롤링/색인 기반

1-1. sitemap (app/sitemap.ts)

  • 정적 페이지(홈, 랭킹 등) + 동적 페이지(게시글, 프로필) 전부 포함
  • lastModified 반드시 포함
  • changeFrequency, priority 설정
  • 게시글에 이미지가 있으면 image sitemap 포함
    (Google이 이미지 검색에서 발견할 수 있는 유일한 방법)

예시:
import { MetadataRoute } from 'next';
import { supabaseAdmin } from '@/lib/supabase';

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL || 'https://example.com';
const { data: posts } = await supabaseAdmin
.from('posts')
.select('id, updated_at, content')
.eq('is_deleted', false);

const postEntries = (posts || []).map(post => {
const imgMatch = post.content?.match(/![.*?]((https?://[^)]+))/);
return {
url: ${SITE_URL}/post/${post.id},
lastModified: new Date(post.updated_at),
changeFrequency: 'weekly' as const,
priority: 0.8,
...(imgMatch?.[1] && { images: [imgMatch[1]] }),
};
});

return [
{ url: SITE_URL, lastModified: new Date(), changeFrequency: 'daily', priority: 1.0 },
{ url: ${SITE_URL}/ranking, lastModified: new Date(), changeFrequency: 'daily', priority: 0.7 },
...postEntries,
];
}

1-2. robots (app/robots.ts)

  • /admin, /api 크롤링 차단
  • sitemap 경로 명시
  • 사용자 비공개 페이지 차단

예시:
import { MetadataRoute } from 'next';
export default function robots(): MetadataRoute.Robots {
const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL || 'https://example.com';
return {
rules: [
{
userAgent: '',
allow: '/',
disallow: ['/admin/', '/api/', '/mypage/
/settings'],
},
],
sitemap: ${SITE_URL}/sitemap.xml,
};
}

1-3. public/robots.txt (정적 fallback용)

User-agent: *
Allow: /
Disallow: /admin/
Disallow: /api/
Sitemap: https://실제도메인.com/sitemap.xml

1-4. canonical URL

  • 모든 동적 페이지 generateMetadata에 반드시 포함
    alternates: { canonical: ${SITE_URL}/경로 }
  • 중복 콘텐츠 방지 (같은 내용이 여러 URL에서 접근 가능한 경우)

1-5. ads.txt (AdSense 사용 시, public/ads.txt)

google.com, pub-XXXXXXXXXXXXXXXX, DIRECT, f08c47fec0942fa0

2. 메타데이터 (generateMetadata)

규칙

  • 모든 동적 페이지에 generateMetadata 함수 구현 (서버 컴포넌트에서만 가능)
  • generateMetadata와 page 함수가 같은 데이터를 쓰면 select 필드 통일해서 DB 쿼리 재사용
  • supabaseAdmin(서버 전용) 사용 — 클라이언트 Supabase 사용 금지

필수 포함 항목

  • title (페이지별 고유 제목)
  • description (150자 이내, 핵심 내용 요약)
  • keywords (관련 검색어 배열)
  • authors
  • openGraph:
    type: 게시글은 'article', 프로필은 'profile', 나머지는 'website'
    locale: 'ko_KR'
    url: 전체 URL
    siteName: 사이트명
    images: [{ url, width, height, alt }]
  • twitter:
    card: 'summary_large_image'
    title, description, images
  • alternates.canonical

layout.tsx 전역 메타데이터 필수 항목

export const metadata: Metadata = {
metadataBase: new URL(SITE_URL), // 상대 경로 이미지 URL 자동 변환
title: { default: '사이트명', template: '%s | 사이트명' },
description: ...,
keywords: [...],
robots: {
index: true, follow: true,
googleBot: { index: true, follow: true, 'max-image-preview': 'large', 'max-snippet': -1 },
},
verification: { google: process.env.NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION },
openGraph: { ... },
twitter: { ... },
icons: { icon: [...], apple: [...] },
alternates: { canonical: SITE_URL },
};

3. 구조화 데이터 (JSON-LD, Schema.org)

핵심 규칙

  • next/script의 Script 컴포넌트 사용 금지 → 반드시 [removed] 태그 사용
    (next/script는 서버 컴포넌트에서 동작 안 함)
  • 반드시 서버 컴포넌트(page.tsx)에서 렌더링
  • 하드코딩 도메인 금지 → process.env.NEXT_PUBLIC_SITE_URL 사용
  • 'use client' 페이지: 서버 page.tsx + 클라이언트 XxxClient.tsx로 분리

components/StructuredData.tsx 구현 목록

[전체 페이지 - layout.tsx에 삽입]

// Organization: 사이트 정체성, 지식 패널 노출 가능
export function OrganizationSchema() {
const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL || 'https://example.com';
const schema = {
'@context': 'https://schema.org',
'@type': 'Organization',
name: '사이트명',
url: SITE_URL,
logo: ${SITE_URL}/logo.webp,
description: '사이트 설명',
sameAs: ['소셜미디어URL1', '소셜미디어URL2'], // SNS 있으면 추가
};
return [removed];
}

// WebSite + SearchAction: Google 검색창에 사이트 내 검색 기능 노출
export function WebSiteSchema() {
const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL || 'https://example.com';
const schema = {
'@context': 'https://schema.org',
'@type': 'WebSite',
name: '사이트명',
url: SITE_URL,
potentialAction: {
'@type': 'SearchAction',
target: ${SITE_URL}/search?q={search_term_string},
'query-input': 'required name=search_term_string',
},
};
return [removed];
}

[게시글 페이지 - app/post/[id]/page.tsx에 삽입]

// Article: 뉴스/블로그 리치 결과 (큰 이미지, 날짜, 작성자 표시)
export function ArticleSchema({ title, description, author, authorId, datePublished, dateModified, url, image, tags = [] }) {
const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL || 'https://example.com';
const schema = {
'@context': 'https://schema.org',
'@type': 'Article',
headline: title, // 110자 이내 권장
description,
author: {
'@type': 'Person',
name: author,
...(authorId && { url: ${SITE_URL}/mypage/${authorId} }),
},
datePublished,
dateModified: dateModified || datePublished,
url,
...(image && { image }), // 이미지 없으면 필드 자체 생략 (기본값 하드코딩 금지)
publisher: {
'@type': 'Organization',
name: '사이트명',
logo: ${SITE_URL}/logo.webp,
},
keywords: tags.join(', '),
inLanguage: 'ko',
};
return [removed];
}

// 게시글 본문에서 첫 이미지 추출 방법 (page.tsx에서 사용)
const imgMatch = post.content?.match(/![.*?]((https?://[^)]+))/);
const firstImage = imgMatch?.[1] || undefined;

// BreadcrumbList: 검색 결과에 경로 표시 (홈 > 페이지명)
export function BreadcrumbSchema({ items }) {
const schema = {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: items.map((item, index) => ({
'@type': 'ListItem',
position: index + 1,
name: item.name,
item: item.url,
})),
};
return [removed];
}

[프로필 페이지 - app/mypage/[id]/page.tsx에 삽입]

// ProfilePage: 프로필 리치 결과
export function ProfileSchema({ username, description, url, image, level, rank }) {
const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL || 'https://example.com';
const schema = {
'@context': 'https://schema.org',
'@type': 'ProfilePage',
mainEntity: {
'@type': 'Person',
name: username,
description,
url,
...(image && { image }),
jobTitle: rank || '멤버',
worksFor: { '@type': 'Organization', name: '사이트명', url: SITE_URL },
...(level && { knowsAbout: 레벨 ${level} }),
},
};
return [removed];
}

[FAQ 페이지 - 해당 페이지에 삽입]

// FAQPage: FAQ 리치 결과 (검색 결과에서 질문/답변 펼쳐서 표시)
export function FAQSchema({ questions }) {
const schema = {
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: questions.map(q => ({
'@type': 'Question',
name: q.question,
acceptedAnswer: { '@type': 'Answer', text: q.answer },
})),
};
return [removed];
}

[커뮤니티/포럼 사이트 추가 권장]

// DiscussionForumPosting: 포럼/커뮤니티 게시글 전용 리치 결과
// Article 대신 사용하거나 병행 가능
export function DiscussionForumPostingSchema({ headline, text, url, author, authorId, datePublished }) {
const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL || 'https://example.com';
const schema = {
'@context': 'https://schema.org',
'@type': 'DiscussionForumPosting',
headline,
text,
url,
datePublished,
author: {
'@type': 'Person',
name: author,
...(authorId && { url: ${SITE_URL}/mypage/${authorId} }),
},
};
return [removed];
}

서버/클라이언트 분리 패턴 (use client 페이지에 스키마 추가 방법)

// app/mypage/[id]/page.tsx — 서버 컴포넌트 (use client 없음)
export default async function MyPagePage({ params }) {
const { data: user } = await supabaseAdmin.from('users').select(...).eq('id', params.id).single();
return (

{user && }
{user && }
// useParams()로 URL 직접 읽는 클라이언트 컴포넌트

);
}

4. 이미지 SEO

모든 태그 필수 규칙

  • alt 속성: 이미지 내용을 구체적으로 설명 (빈 문자열 금지)
    좋은 예: alt="2024년 나스닥 차트 분석"
    나쁜 예: alt="이미지", alt=""
  • 데코레이티브(장식용) 이미지: alt="" aria-hidden="true"
  • onError 핸들러: 깨진 이미지 fallback 처리
    예: onError={(e) => { e.currentTarget.src = '/default-avatar.png'; e.currentTarget.onerror = null; }}
    (e.currentTarget.onerror = null → 무한 루프 방지)

next/image 사용 규칙

  • 내부 이미지: next/image 사용 (자동 WebP 변환, lazy loading, 크기 최적화)
  • 외부 이미지 도메인: next.config.js의 images.domains 또는 remotePatterns에 등록
  • sizes 속성으로 반응형 크기 명시
  • priority 속성: LCP(Largest Contentful Paint) 대상 이미지에만 사용

이미지 파일 자체 최적화

  • 포맷: WebP 또는 AVIF 권장 (JPG/PNG 대비 30~50% 용량 절감)
  • 크기: 실제 표시 크기의 최대 2배 이하
  • 압축: browser-image-compression 라이브러리 활용
    maxSizeMB: 1, maxWidthOrHeight: 1920, fileType: 'image/webp'

이미지 sitemap

  • 게시글 본문 이미지를 sitemap에 포함시켜야 Google 이미지 검색 노출 가능
    (1번 sitemap.ts 예시 참고)

5. 링크 SEO

외부 링크 rel 속성

  • 사용자 생성 콘텐츠(댓글, 게시글 본문) 내 외부 링크: rel="noopener noreferrer ugc"
  • 일반 외부 링크 (편집자 작성): rel="noopener noreferrer"
  • 유료 광고/제휴 링크: rel="noopener noreferrer sponsored"
  • href="#" 사용 금지 → 실제 의미 있는 URL로 대체

내부 링크

  • 관련 페이지 간 내부 링크 적극 활용 (크롤링 경로 확장)
  • 앵커 텍스트를 구체적으로 작성 ("여기를 클릭" 금지, "나스닥 분석 글 보기" 권장)
  • 깨진 링크(404) 정기적으로 점검

접근성 (SEO 영향)

  • 아이콘만 있는 링크/버튼: aria-label 필수
    예:
  • 로고 링크: aria-label="사이트명 홈으로 이동"
  • 스크린리더가 읽어야 하는 요소에 aria-hidden="true" 금지
  • 순수 장식 요소에만 aria-hidden="true" 적용

6. 페이지 타이틀 & 설명

타이틀 작성 규칙

  • 페이지마다 고유한 타이틀
  • 60자 이내 (초과 시 검색 결과에서 잘림)
  • 핵심 키워드를 앞쪽에 배치
  • 브랜드명은 뒤에 붙임: "나스닥 분석 | 사이트명"
  • Next.js: title: { template: '%s | 사이트명' } 패턴 사용

설명(description) 작성 규칙

  • 페이지마다 고유한 설명
  • 150자 이내 (초과 시 잘림)
  • 사용자가 클릭하고 싶게 내용 요약
  • 핵심 키워드 자연스럽게 포함
  • 동일 설명 여러 페이지에 재사용 금지

URL 구조

  • 영문 소문자, 숫자, 하이픈(-)만 사용 권장
  • 의미 있는 단어 포함: /post/[id] 보다 /post/[slug] 권장 (가능하면)
  • 불필요한 파라미터 최소화

7. 콘텐츠 품질 (Google E-E-A-T)

Google이 평가하는 기준

  • Experience (경험): 실제 경험 기반 콘텐츠
  • Expertise (전문성): 주제 관련 전문 지식
  • Authoritativeness (권위성): 신뢰받는 출처
  • Trustworthiness (신뢰성): 정확하고 투명한 정보

구현 방법

  • 작성자 정보 명시 (이름, 프로필 링크) → ArticleSchema의 author 필드
  • 게시 날짜 / 수정 날짜 명시 → datePublished, dateModified
  • 관련 내부/외부 링크 연결
  • 이미지에 관련 텍스트 배치 (이미지 주변 설명 텍스트)

8. 성능 (Core Web Vitals) - Google 랭킹 직접 반영

LCP (Largest Contentful Paint) - 2.5초 이하 목표

  • 히어로 이미지/배너: 사용
  • 폰트: font-display: swap 설정, preconnect 추가
  • 중요 CSS 인라인 처리

FID/INP (Interaction to Next Paint) - 200ms 이하 목표

  • 무거운 연산을 useCallback/useMemo로 메모이제이션
  • 이벤트 핸들러 최적화

CLS (Cumulative Layout Shift) - 0.1 이하 목표

  • 이미지/영상에 width, height 반드시 명시 (레이아웃 안정화)
  • 동적 콘텐츠 삽입 시 공간 미리 확보
  • 웹폰트 로딩 중 fallback 폰트 크기 맞추기

일반 성능

  • 불필요한 JavaScript 제거 (bundle analyzer로 점검)
  • 이미지 lazy loading (next/image 기본 적용)
  • API 응답 캐싱 (Cache-Control 헤더 설정)

9. 모바일 최적화

  • viewport 메타태그 필수
    export const viewport: Viewport = { width: 'device-width', initialScale: 1 }
  • 터치 타겟 크기: 최소 48x48px
  • 폰트 크기: 최소 16px (모바일에서 확대 없이 읽을 수 있도록)
  • 가로 스크롤 금지: overflow-x: hidden
  • Google은 모바일 우선 색인(Mobile-First Indexing) 적용 중

10. 국제화 / 한국어 사이트

  • 필수
  • hreflang 태그: 다국어 지원 시
  • OpenGraph locale: 'ko_KR'
  • Schema.org inLanguage: 'ko'
  • 날짜 표시: toLocaleString('ko-KR')

11. 검증 및 모니터링

구현 후 필수 검증

  1. npm run build → 빌드 오류 0건 확인
  2. https://search.google.com/test/rich-results → 구조화 데이터 검증
  3. https://validator.schema.org → 전체 Schema.org 유효성 검사
  4. https://pagespeed.web.dev → Core Web Vitals 점수 확인
  5. Google Search Console → URL 검사 → 색인 요청

Google Search Console 설정

  • 사이트 소유권 확인: NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION 환경변수
    metadata.verification.google = process.env.NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION
  • sitemap 제출: Search Console → Sitemaps → sitemap.xml URL 등록
  • Core Web Vitals 리포트 정기 확인

환경변수 체크리스트

NEXT_PUBLIC_SITE_URL=https://실제도메인.com
NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION=구글서치콘솔인증코드
(AdSense 사용 시) 광고 클라이언트 ID

12. 절대 하면 안 되는 것 (Google 스팸 정책)

  • 키워드 스터핑: 같은 키워드 반복 남용 금지
  • 숨겨진 텍스트: display:none 또는 배경색과 같은 색상 텍스트로 키워드 삽입 금지
  • 클로킹: 사용자와 크롤러에게 다른 콘텐츠 제공 금지
  • 자동 생성 저품질 콘텐츠 대량 생산 금지
  • 구매한 링크로 PageRank 조작 금지
  • 구조화 데이터 허위 정보 삽입 금지 (실제 없는 별점, 리뷰 등)
— ✦ —

콘텐츠 정보

마지막 검토: 2026년 6월 22일법률 자문 아님 · 참고용 정보

질문 및 댓글

혹시 본문과 상황이 조금 다르신가요?

실제 사건은 가족관계, 채무 시점, 소송 여부에 따라 결과가 달라질 수 있습니다. 질문을 남겨주시면 판례·실무 사례 기반 AI 참고 답변을 받을 수 있습니다.

🤖 판례 데이터 기반 AI 답변|⚖️ 법률 자문이 아닙니다|🔒 본인·관리자만 열람

아직 질문이 없습니다. 첫 번째 질문을 등록해보세요.

이어서 읽기

쿠팡 개인정보 유출 6,247억 과징금 확정! 6월 26일 마감 전 꼭 챙겨야 할 보상금 신청 전략

쿠팡 개인정보 유출 사태, 핵심만 빠르게 짚어드려요 - 보상 신청의 골든타임: 정부가 주관하는 무료 '집단분쟁조정'은 2026년 6월 26일에 마감되니, 비용 부담 없이 빠르게 신청하고 싶은 분들은 이번 기회를 절대 놓치지 마세요. - ...

8회 읽음자세히 보기 →
SNS에서 허위 사실 퍼날랐다가 고소당하는 실제 절차 — 공유자 처벌 기준과 수사 흐름 정리

SNS에서 허위 사실 퍼날랐다가 고소당하는 실제 절차 — 공유자 처벌 기준과 수사 흐름 정리

처음에는 대부분 "그냥 퍼 나른 것뿐인데"라고 생각한다. 직접 만든 게 아니니 책임이 없다는 판단이다. 그러나 수사기관은 다르게 접근한다. 공유 행위가 허위 정보의 확산에 기여했다고 판단되면, 원본 작성자와 별개로 처벌 대상이 될 수 있다. SNS에서 특정인의 신상,...

14회 읽음자세히 보기 →
월급 빼고 다 오른 시대, ISA가 3040 직장인에게 '절세 통장'이 된 이유

월급 빼고 다 오른 시대, ISA가 3040 직장인에게 '절세 통장'이 된 이유

오늘은 특별하게 30,40대를 위한 금융재테크 방법에 대해 글을 써봤습니다. 저도 40대 가장으로서 월급을 받아서 생활하기가 빠듯하기에 이런 금융정보를 알고 있으면 도움이 될것같아 절세통장이라 불리는 isa계좌에 대해 공부하고 정리했습니다. 2026년 개정안을 중심으로...

11회 읽음자세히 보기 →
미성년 자녀가 담배 피우는 걸 발견했을 때, 법적으로 할 수 있는 것과 없는 것

미성년 자녀가 담배 피우는 걸 발견했을 때, 법적으로 할 수 있는 것과 없는 것

자녀가 담배를 피운다는 걸 알게 된 순간, 부모 대부분은 아이를 혼내는 것에만 집중한다. 판매자를 신고할 수 있다는 사실은 나중에, 혹은 아예 모르고 지나친다. 그런데 이 두 가지는 완전히 별개의 문제다. 자녀의 흡연은 훈육 영역이고, 판매자의 행위는 법률 위반 영역이...

9회 읽음자세히 보기 →
공유오피스 보증금 돌려받으려다 지급명령까지 간 사람들이 실제로 겪는 것들

공유오피스 보증금 돌려받으려다 지급명령까지 간 사람들이 실제로 겪는 것들

공유오피스 계약이 끝나고 보증금을 돌려달라고 했을 때, 처음에는 대부분 "며칠 안에 처리해준다"는 말을 듣는다. 운영사 측에서 내부 정산 절차가 있다거나, 담당자가 바뀌었다거나, 시스템 문제가 있다는 식의 설명이 나온다. 한두 주 기다리다 다시 연락하면 또 비슷한 말이...

6회 읽음자세히 보기 →
전세사기 특별법 신청했는데 보증금 못 돌려받는 사람들 실제로 어디서 막힐까

전세사기 특별법 신청했는데 보증금 못 돌려받는 사람들 실제로 어디서 막힐까

전세사기 특별법이 시행됐을 때, 많은 피해자들이 "신청하면 보증금을 돌려받을 수 있다"고 받아들였다. 실제로는 그렇지 않다. 특별법이 주는 것은 보증금 회수 자체가 아니라, 피해자 지위 인정과 그에 따른 몇 가지 우선권, 그리고 지원 연계다. 보증금 회수는 여전히 별도...

8회 읽음자세히 보기 →