背景
当前架构中,采集与 Digest 生成耦合在一起:每次调用采集逻辑就直接生成 Digest,同一个 Source 如果有多个用户订阅,会重复抓取。这在多用户场景下既浪费资源,又难以扩展。
kevinho/clawfeed PR #15(feat: raw_items collection pipeline)已 MERGED,本 issue 跟踪将其合并到 coco-xyz/clawfeed 并完成后续集成工作。
目标
将 Source 级采集与 Digest 生成完全解耦。同一个 Source 无论有多少人订阅,只采集一次,结果写入 raw_items 表,供所有订阅者共享。
技术方案
新增数据表
CREATE TABLE IF NOT EXISTS raw_items (
id INTEGER PRIMARY KEY AUTOINCREMENT,
source_id INTEGER NOT NULL REFERENCES sources(id) ON DELETE CASCADE,
title TEXT NOT NULL DEFAULT '',
url TEXT NOT NULL DEFAULT '',
author TEXT DEFAULT '',
content TEXT NOT NULL DEFAULT '',
fetched_at TEXT NOT NULL DEFAULT (datetime('now')),
published_at TEXT,
dedup_key TEXT NOT NULL, -- source_id + ":" + url,无 URL 时用 content hash
metadata TEXT DEFAULT '{}', -- 点赞数、评论数等原始信号
UNIQUE(source_id, dedup_key)
);
CREATE INDEX idx_raw_items_source_fetched ON raw_items(source_id, fetched_at DESC);
CREATE INDEX idx_raw_items_fetched ON raw_items(fetched_at DESC);
核心改动
db/migrations/006_raw_items.sql — DDL migration
src/db.mjs — 新增 raw_items CRUD 函数:insertRawItem(), getRawItemsBySource(), pruneOldRawItems()
- 重构现有采集逻辑:采集结果写入
raw_items 而非直接生成 Digest
- Digest 生成改为从
raw_items 读取(为 1.2 个性化做准备)
- 并发采集池:多个 Source 并行采集,互不阻塞
去重策略
dedup_key = source_id + ":" + url
- 无 URL 内容使用 SHA256(content) 作为 dedup_key
- 通过
UNIQUE(source_id, dedup_key) + INSERT OR IGNORE 实现零代码去重
安全与稳定性
- SSRF 防护:校验 RSS/RSS Feed URL 不指向内网地址
- 错误隔离:单个 Source 采集失败不影响其他 Source
- 自动暂停:连续失败 N 次(如 5 次)自动将 Source 标记为
is_active = 0
验收标准
依赖
无(此为 Phase 1 基础,其他三个 issue 均依赖此 issue)
背景
当前架构中,采集与 Digest 生成耦合在一起:每次调用采集逻辑就直接生成 Digest,同一个 Source 如果有多个用户订阅,会重复抓取。这在多用户场景下既浪费资源,又难以扩展。
kevinho/clawfeed PR #15(
feat: raw_items collection pipeline)已 MERGED,本 issue 跟踪将其合并到 coco-xyz/clawfeed 并完成后续集成工作。目标
将 Source 级采集与 Digest 生成完全解耦。同一个 Source 无论有多少人订阅,只采集一次,结果写入
raw_items表,供所有订阅者共享。技术方案
新增数据表
核心改动
db/migrations/006_raw_items.sql— DDL migrationsrc/db.mjs— 新增raw_itemsCRUD 函数:insertRawItem(),getRawItemsBySource(),pruneOldRawItems()raw_items而非直接生成 Digestraw_items读取(为 1.2 个性化做准备)去重策略
dedup_key = source_id + ":" + urlUNIQUE(source_id, dedup_key)+INSERT OR IGNORE实现零代码去重安全与稳定性
is_active = 0验收标准
raw_items表创建成功,包含正确索引raw_items,不再直接触发 Digest 生成INSERT OR IGNORE验证)is_active = 0暂停GET /api/raw-items/stats返回各 Source 的采集统计(条数、最近采集时间)依赖
无(此为 Phase 1 基础,其他三个 issue 均依赖此 issue)