개발 slecs

블로그 포스트 페이지의 구조화 데이터 세 곳을 한꺼번에 수정

목차

Post.astro 한 파일에서 구조화 데이터 세 군데를 한 번에 정리했다.

왜 이게 한꺼번에 터졌나

SEO 관련 structured data는 처음에 대충 넣어두고 나중에 다듬겠다고 생각하는 순간 대부분 그 상태로 프로덕션에 나간다. 이번도 비슷한 케이스였다. BreadcrumbList가 잘못 구성된 채 붙어있었고, _pageUrl 계산 로직에 버그가 있었고, publisherOrganization 이름이 서버 SEO 쪽과 일치하지 않았다. 세 개가 따로 노는 상황. 각각 다른 시점에 작성된 코드가 Post.astro 한 파일 안에서 서로 다른 방향을 보고 있었던 것.

머지 브랜치가 "server SEO" 계열이었다는 점도 중요하다. 클라이언트 렌더링 환경에서 structured data를 주입하는 방식과 서버에서 렌더링 시점에 직접 박아넣는 방식은 URL 계산 방식부터 다르다. 브랜치가 합쳐지면서 서로 다른 전제를 가진 코드가 공존하게 된 거고, 그게 세 가지 증상으로 드러난 것이다.

변경 내용 정리

항목 문제 수정 방향
BreadcrumbList 구조 오류 (item 순서 / url 누락 등) JSON-LD spec 기준으로 재구성
_pageUrl 잘못된 URL 조합 로직 서버 SEO 머지 이후 기준으로 통일
publisher org name 클라이언트 측 값과 서버 측 값 불일치 단일 소스로 통합

BreadcrumbList는 Google Search Console 기준으로 @type: ListItem 안에 position, name, item 세 필드가 모두 있어야 유효하다. 누락된 필드가 있으면 리치 결과에서 빠지는 게 아니라 아예 오류로 분류된다. 이게 티가 안 나서 방치되는 경우가 많은데, Search Console 들어가서 확인해보면 꽤 자주 발견된다.

// BreadcrumbList 기본 구조 (JSON-LD)
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    {
      "@type": "ListItem",
      "position": 1,
      "name": "홈",
      "item": "https://example.com/"
    },
    {
      "@type": "ListItem",
      "position": 2,
      "name": "카테고리",
      "item": "https://example.com/category/"
    },
    {
      "@type": "ListItem",
      "position": 3,
      "name": "포스트 제목"
      // 마지막 항목은 item URL 생략 가능 (현재 페이지)
    }
  ]
}

_pageUrl 문제는 조금 더 골치 아팠다. Astro에서 서버 렌더링 환경이면 Astro.url을 쓸 수 있는데, 이전 코드가 클라이언트 환경을 가정해서 window.location이나 하드코딩된 base URL을 조합하는 방식이었다. 서버 SEO 브랜치가 들어오면서 Astro.url 기반으로 전환됐고, 그 충돌이 _pageUrl에서 잘못된 URL을 뱉는 형태로 나타났다.

머지 후 SEO 코드를 항상 다시 봐야 하는 이유

structured data는 컴포넌트 단위로 쪼개져 있으면 각 컴포넌트가 서로 다른 값을 내보낼 수 있다. publishername이 어떤 컴포넌트에서는 "My Blog", 다른 곳에서는 "My Blog — Dev"처럼 조금씩 다른 형태로 박혀있으면 Google 입장에서는 동일 엔터티로 인식하지 못할 수 있다. 이번에 Post.astro에서 서버 SEO 머지 직후 org name을 통일한 게 작은 수정이지만, 일관성 측면에서는 꽤 중요한 작업이었다.

개인적으로 이런 상황에서 배운 패턴은 하나다 — structured data에 들어가는 값은 단일 상수 또는 단일 유틸 함수에서 가져오도록 강제하기. 컴포넌트가 직접 문자열을 들고있으면 머지 충돌 때 반드시 발산한다.

// seo.config.ts 같은 파일에 모아두는 패턴
export const SITE_PUBLISHER = {
  "@type": "Organization",
  name: "My Blog",
  url: "https://example.com",
} as const;

이렇게 하나로 묶어두면 Post.astro든 다른 레이아웃이든 같은 객체를 import해서 쓰면 되고, 머지 후에도 한 군데만 보면 된다.

Post.astro 파일 하나 고친 커밋이지만 실제로는 세 개의 독립적인 버그를 잡은 거라 꽤 밀도 있는 작업이었다. 다음 번엔 서버 SEO 브랜치 머지 전에 structured data 항목들을 체크리스트로 만들어서 미리 훑는 게 낫겠다 싶다.

끝.


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.