검색 K
밝은/어두운 배경
밝은/어두운 배경
VitePress 기반 RSS 스크래퍼 프로젝트의 설계 결정 과정을 정리한 학습 문서입니다. GitHub Actions 환경, Git 저장소 관리, 데이터 설계 관점을 함께 다룹니다.
src/_data/
└── 2026/
└── 05/
├── policy-news.json
├── tech-geeknews.json
├── yjk-blog.json
└── ga-anseongsi.json피드 ID가 곧 파일명이고, 이용자 구분은 저장 레이어가 아닌 config가 담당합니다.
현행 구조에서 policy-news가 rss와 yjk 양쪽에 있으면 2개 파일에 중복 저장됩니다. 이 구조에서는 policy-news.json 하나만 존재합니다. 어떤 이용자가 그 피드를 보는지는 config가 알고 있으므로 저장 레이어에서 구분할 이유가 없습니다.
현행은 "이 스토어에서 이 피드의 포스트를 꺼낸다"는 2단계 구조입니다.
monthlyStore (여러 피드 혼재) → feedId로 filter → 마크다운 빌드제안 구조는 파일 자체가 이미 피드 단위로 분리되어 있습니다.
policy-news.json → 그대로 마크다운 빌드insertIfNotExists()의 중복 검사 범위도 파일 하나 = 피드 하나로 좁혀져 명확해집니다.
우려할 수준이 아닙니다.
현행: 파일 1개 로드 → 메모리에서 filter
제안: 파일 N개 로드 → filter 불필요
파일 수: 피드 11개 × 12개월 = 132개/년
파일 크기: 피드 하나의 월별 데이터 = 수 KB ~ 수십 KBNode.js에서 수십 KB짜리 파일 수십 개를 읽는 것은 부담이 없습니다. GitHub Actions 환경에서도 문제없습니다.
마크다운 빌드 시 "이 이용자가 구독하는 피드 파일들을 모아서 출력" 하는 로직이 필요합니다. 하지만 이것은 config에서 folderName으로 피드를 그룹핑하면 자연스럽게 해결됩니다.
// config에서 folderName 기준으로 그룹핑
const yjkFeeds = RSS_FEEDS.filter(f => f.folderName === 'yjk');
// 해당 피드 파일들만 로드해서 병합오히려 현행의 store.getPostsByFeed() 같은 우회 로직이 사라집니다.
제안하신 구조가 현 조합에서 가장 자연스럽습니다. 규칙이 단순하고(feedId = 파일명), 중복이 없으며, 이용자 구분 책임이 config에 명확히 귀속됩니다. A안처럼 _shared 예약어를 보호할 필요도 없습니다.
aiSummary) 파이프라인 확장 예정사이트에 복수의 이용자가 존재하고, 각 이용자마다 구독하는 RSS 피드가 다릅니다. folderName 속성으로 이용자별 마크다운 출력 경로를 분리하는 것은 기술적으로 가능하지만, 데이터 저장 단위를 어떻게 설계하느냐에 따라 중복·비용·복잡도가 달라집니다.
src/_data/
├── rss/2026/05.json
└── yjk/2026/05.json장점
단점
src/_data/
├── _shared/2026/05.json ← 공용 피드 (1회 수집)
├── yjk/2026/05.json ← yjk 전용 피드
└── alice/2026/05.json ← alice 전용 피드마크다운 빌드 시 _shared 데이터를 각 이용자 md에 병합해서 출력합니다.
장점
단점
_shared를 예약어로 보호하는 검증 로직 필요config에 sharedWith: ['yjk', 'alice'] 필드를 추가해서, fetch는 1회만 하고 여러 이용자 스토어에 동시 삽입합니다.
src/_data/
├── yjk/2026/05.json ← 공용 피드 + yjk 전용 피드 포함
└── alice/2026/05.json ← 공용 피드 + alice 전용 피드 포함장점
단점
src/_data/db.sqlite ← 전체 데이터 단일 DB스키마 예시:
posts -- PostRecord 전체 (중복 없음)
feeds -- RssFeedConfig
user_feeds -- 이용자 ↔ 피드 다대다 (userId, feedId, folderName)장점
단점
src/_data/
├── rss/2026/05.db
├── rss/2026/04.db ← 월 마감 후 불변
└── yjk/2026/05.db장점
단점
Git이 파일을 저장하는 방식은 파일 형식에 따라 크게 다릅니다.
커밋 1: 포스트 10개 → 10줄 추가 (delta)
커밋 2: 포스트 1개 추가 → 1줄 추가 (delta)
누적 비용: 변경된 줄의 합산 → 매우 작음커밋 1: DB 500KB → 500KB 저장
커밋 2: 포스트 1개 추가 → 500KB 저장 (전체 스냅샷)
커밋 3: 포스트 1개 추가 → 500KB 저장
누적 비용: 500KB × 커밋 횟수결론: 내용 증가폭이 같아도 Git 히스토리에 쌓이는 용량은 구조적으로 다릅니다. SQLite를 Git으로 관리할 경우 .gitignore 처리 + 외부 persist 전략을 별도로 설계해야 합니다.
| 항목 | 이용자별 JSON | A안 (공유 스토어) | B안 (sharedWith) | 단일 SQLite | SQLite 월별 | ||||||| | 중복 수집 | 있음 | 없음 | 없음 | 없음 | 없음 | | 중복 저장 | 있음 | 없음 | 있음 | 없음 | 없음 | | Git 히스토리 | 가벼움 | 가벼움 | 가벼움 | 매우 무거움 | 중간 | | 빌드 로직 복잡도 | 낮음 | 높음 | 낮음 | 중간 | 중간 | | AI 분석 중복 | 있음 | 없음 | 있음 | 없음 | 없음 | | 운영 편의성 | 높음 | 중간 | 높음 | 낮음 | 낮음 | | 구현 비용 | 낮음 | 중간 | 낮음 | 높음 | 높음 |
현재 규모 (이용자 소수, AI 분석 미구현)
→ JSON 월별 + 이용자별 구조 유지
→ 공용 피드 중복은 B안(sharedWith)으로 최소화
AI 분석 파이프라인 구현 시점
→ SQLite 이전 재검토
→ 단, GitHub Actions DB persist 전략 먼저 결정 필요
(Actions cache / 외부 오브젝트 스토리지 / Turso 등)
이용자 수가 많아지는 시점
→ A안(공유 스토어) 또는 SQLite 이전 검토"어떤 이용자가 보는가"는 뷰의 문제이고, 데이터 저장은 별개의 문제다.
저장 단위를 이용자별로 쪼개면 뷰 분리는 쉬워지지만, 중복·비용·일관성 문제가 저장 레이어에 전가됩니다. 규모가 작을 때는 단순함이 최선이고, 확장이 필요해지는 시점에 적절한 전략으로 전환하는 것이 현실적입니다.
매우 합리적인 판단입니다. 정리해보겠습니다.