Use Cases (업데이트: 2026. 6. 2.)

Claude Code로 RSS Feed 구현하기: 정적 사이트 RSS 2.0과 Atom 실전 가이드

Claude Code로 RSS 2.0/Atom을 만들고 XML 이스케이프, 날짜, 절대 URL, 다국어, 검증, 캐시를 정리합니다.

Claude Code로 RSS Feed 구현하기: 정적 사이트 RSS 2.0과 Atom 실전 가이드

RSS는 오래된 기능이 아니라 안정적인 배포 통로입니다

블로그 글을 공개했다고 독자가 바로 보는 것은 아닙니다. 검색, SNS, 뉴스레터, Slack, RSS 리더가 모두 입구가 됩니다. RSS feed는 글 제목, 링크, 설명, 날짜를 XML 형식으로 제공하는 파일입니다. XML은 규칙이 엄격해서 & 하나를 잘못 넣어도 feed가 깨질 수 있습니다.

Atom은 RSS와 비슷한 구독 형식이며 RFC 4287로 정의되어 있습니다. 대부분의 정적 사이트는 RSS 2.0부터 구현하고, 필요한 경우 Atom을 추가하면 충분합니다. 이 글은 Claude Code로 RSS를 만들 때 XML 이스케이프, 날짜, 절대 URL, 다국어 feed, 검증, 캐시, review prompt까지 함께 다룹니다.

기준 문서는 RSS Advisory Board RSS 2.0 Specification, IETF RFC 4287, W3C Feed Validation Service, Astro RSS recipe입니다. 관련 글로는 Claude Code 블로그 CMS, SEO 최적화, 사이트맵 생성을 함께 보면 좋습니다.

실제 사용 사례

첫 번째는 개발 블로그의 재방문입니다. RSS 리더를 쓰는 독자는 소수처럼 보이지만, 기술 문서를 많이 읽는 사람에게는 여전히 일상 도구입니다. Feedly나 Inoreader에 글이 들어가면 SNS 노출에 의존하지 않아도 됩니다.

두 번째는 사내 지식 배포입니다. 릴리스 노트, 장애 회고, 보안 공지, 아키텍처 결정 기록을 같은 feed로 제공하면 Slack bot이나 사내 포털이 읽을 수 있습니다. 사람이 보는 페이지와 기계가 읽는 XML을 같은 데이터에서 만들 수 있습니다.

세 번째는 다국어 SEO입니다. 한국어, 일본어, 영어, 중국어, 스페인어 글이 있는 사이트라면 하나의 feed에 모든 언어를 섞지 않는 것이 좋습니다. /ko/rss.xml은 한국어 collection과 /ko/blog/ URL만 사용해야 합니다.

네 번째는 수익 경로 유지입니다. ClaudeCodeLab처럼 교육, 템플릿, 상담으로 이어지는 사이트에서는 새 글이 feed에 들어가야 반복 독자에게 도달합니다. Claude Code 교육과 상담 CTA도 독자가 구현 후 다음 단계로 갈 때 자연스럽게 보여야 합니다.

구현 전에 정할 계약

Claude Code에 맡기기 전에 feed 계약을 써야 합니다.

항목권장이유
형식RSS 2.0 먼저, Atom은 선택지원이 넓고 단순함
URL절대 URL외부 리더가 안정적으로 열 수 있음
날짜RSS는 toUTCString(), Atom은 toISOString()reader의 정렬 오류를 줄임
본문description 중심전체 HTML은 sanitize와 이미지 URL 처리가 필요
개수20~50개feed가 너무 커지는 것을 방지
캐시명시적 cache header발행 후 업데이트 지연을 관리
검증로컬 스크립트와 W3C Validator브라우저 표시만으로는 부족

RSS 2.0의 기본은 channelitem입니다. guid는 글을 안정적으로 식별하는 값이며 보통 permalink를 씁니다. 제목과 설명은 XML에 들어가기 전에 반드시 이스케이프해야 합니다.

의존성 없는 RSS 생성 코드

scripts/generate-rss.mjs로 저장하고 node scripts/generate-rss.mjs를 실행합니다.

// scripts/generate-rss.mjs
import fs from "node:fs";
import path from "node:path";

const siteUrl = "https://example.com";
const outputPath = path.join(process.cwd(), "dist", "rss.xml");

const posts = [
  {
    title: "Claude Code로 RSS Feed 구현하기",
    description: "정적 사이트용 RSS 2.0 feed를 생성하고 검증합니다.",
    slug: "claude-code-rss-feed",
    pubDate: "2026-06-02T09:00:00+09:00",
    tags: ["Claude Code", "RSS"],
  },
];

function escapeXml(value) {
  return String(value ?? "")
    .replace(/&/g, "&")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&apos;");
}

function toRssDate(value) {
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) throw new Error(`Invalid date: ${value}`);
  return date.toUTCString();
}

const items = posts.map((post) => {
  const url = new URL(`/ko/blog/${post.slug}/`, siteUrl).toString();
  return `    <item>
      <title>${escapeXml(post.title)}</title>
      <link>${url}</link>
      <guid isPermaLink="true">${url}</guid>
      <description>${escapeXml(post.description)}</description>
      <pubDate>${toRssDate(post.pubDate)}</pubDate>
    </item>`;
}).join("\n");

const xml = `<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>ClaudeCodeLab Korea</title>
    <link>${siteUrl}/ko/</link>
    <description>Claude Code 실전 구현 가이드</description>
    <language>ko</language>
    <lastBuildDate>${new Date().toUTCString()}</lastBuildDate>
    <ttl>60</ttl>
${items}
  </channel>
</rss>
`;

fs.mkdirSync(path.dirname(outputPath), { recursive: true });
fs.writeFileSync(outputPath, xml, "utf8");
console.log(`Generated ${outputPath}`);

핵심은 escapeXml(), new URL(), 날짜 검증입니다. Claude Code가 코드를 줄이더라도 이 세 가지는 유지해야 합니다.

Astro에서 구현하기

Astro에서는 공식 @astrojs/rss를 사용합니다.

npm install @astrojs/rss
// src/pages/ko/rss.xml.ts
import rss from "@astrojs/rss";
import { getCollection } from "astro:content";

export async function GET(context: { site: URL }) {
  const posts = await getCollection("blog-ko", ({ data }) => !data.draft);

  const items = posts
    .sort((a, b) => {
      const aDate = new Date(a.data.updatedDate ?? a.data.pubDate).getTime();
      const bDate = new Date(b.data.updatedDate ?? b.data.pubDate).getTime();
      return bDate - aDate;
    })
    .slice(0, 30)
    .map((post) => ({
      title: post.data.title,
      description: post.data.description,
      pubDate: post.data.updatedDate ?? post.data.pubDate,
      link: `/ko/blog/${post.id}/`,
      categories: post.data.tags,
    }));

  return rss({
    title: "ClaudeCodeLab Korea",
    description: "Claude Code 실전 구현 가이드",
    site: context.site,
    items,
    customData: "<language>ko</language><ttl>60</ttl>",
  });
}

레이아웃에는 자동 발견 링크를 넣습니다.

<link rel="alternate" type="application/rss+xml" title="ClaudeCodeLab RSS" href="/ko/rss.xml" />
<link rel="alternate" type="application/atom+xml" title="ClaudeCodeLab Atom" href="/ko/atom.xml" />

전체 HTML feed는 가능하지만 sanitize, 이미지 절대 URL, interactive component 제거가 필요합니다. 처음에는 description만 넣는 방식이 안전합니다.

Atom, 다국어, 검증

Atom은 stable id와 ISO date가 중요합니다.

function atomEntry(post, siteUrl) {
  const url = new URL(`/ko/blog/${post.slug}/`, siteUrl).toString();
  return `  <entry>
    <title>${escapeXml(post.title)}</title>
    <link href="${url}" />
    <id>${url}</id>
    <updated>${new Date(post.pubDate).toISOString()}</updated>
    <summary>${escapeXml(post.description)}</summary>
  </entry>`;
}

다국어 feed 설정은 collection, prefix, language를 함께 관리합니다.

const feeds = [
  { collection: "blog", prefix: "", language: "ja", title: "ClaudeCodeLab" },
  { collection: "blog-en", prefix: "/en", language: "en", title: "ClaudeCodeLab English" },
  { collection: "blog-ko", prefix: "/ko", language: "ko", title: "ClaudeCodeLab Korea" },
];

로컬 검증 스크립트도 추가합니다.

// scripts/check-feed.mjs
const feedUrl = process.argv[2] ?? "http://localhost:4321/ko/rss.xml";
const response = await fetch(feedUrl);
const xml = await response.text();
const failures = [];

if (!response.ok) failures.push(`HTTP status is ${response.status}`);
if (!xml.includes("<rss")) failures.push("missing rss root");
if (!xml.includes("<channel>")) failures.push("missing channel");
if (!xml.includes("<item>")) failures.push("missing item");
if (/&(?!amp;|lt;|gt;|quot;|apos;|#\d+;|#x[a-fA-F0-9]+;)/.test(xml)) failures.push("unescaped ampersand");
if (!/<guid[^>]*>https?:\/\//.test(xml)) failures.push("guid should be absolute");

if (failures.length) {
  console.error(failures.map((failure) => `- ${failure}`).join("\n"));
  process.exit(1);
}

console.log(`OK: ${feedUrl}`);

실패 사례는 구체적입니다. R&D 같은 문자열을 이스케이프하지 않아 XML이 깨지고, draft가 feed에 노출되고, 상대 URL이 외부 reader에서 열리지 않고, 한국어 feed가 영어 페이지로 연결됩니다. CDN 캐시가 너무 길면 수정 후에도 오래된 feed가 보입니다.

Claude Code prompt와 검증 결과

Astro 정적 사이트에 RSS 2.0을 구현하세요.
- src/pages/ko/rss.xml.ts만 수정합니다.
- @astrojs/rss를 사용합니다.
- draft는 제외합니다.
- updatedDate 또는 pubDate 기준 최신순으로 정렬합니다.
- 30개로 제한합니다.
- /ko/blog/ URL prefix를 유지합니다.
- language와 ttl을 넣습니다.
- 실행한 검증 명령과 결과를 보고합니다.

리뷰 prompt는 더 엄격하게 씁니다.

RSS 구현을 비판적으로 검토하세요.
XML 이스케이프, 상대 URL, draft 노출, 날짜 형식, guid 안정성, 다국어 prefix, 캐시, W3C 검증 문제를 우선 확인하세요.

작은 Astro 데이터셋으로 실제 확인했을 때, 로컬 스크립트가 이스케이프되지 않은 &와 절대 URL이 아닌 guid를 바로 잡아냈습니다. 사람이 봐야 할 부분은 번역 품질, CTA의 자연스러움, 실제 reader 표시였습니다. 팀에서 RSS, sitemap, 콘텐츠 QA, 수익 경로를 함께 운영하려면 Claude Code 교육과 상담에서 workflow를 정리하는 것이 좋습니다.

#Claude Code #RSS #Atom #Astro #static site
무료

무료 PDF: Claude Code 치트시트

이메일을 입력하면 명령, 리뷰 습관, 안전한 워크플로를 정리한 PDF를 받을 수 있습니다.

개인정보를 안전하게 관리하며 스팸을 보내지 않습니다.

Masa

작성자 소개

Masa

Claude Code 실무 워크플로와 팀 도입을 검증하는 엔지니어입니다.