KAIROS.WORKSPACE
技术宇宙 / ONLINE
返回文章列表
内容系统intermediate6 分钟

内容一致性校验:把坏数据挡在构建期而不是发布后

个人内容站如何在构建阶段用脚本校验 frontmatter、slug 引用、日期逻辑、阅读时长与关联关系,形成可持续的内容卫生机制。

#内容治理#构建#CI#数据校验
排版
字号
行宽
目录 · 5 节

内容站的 bug 大多不是代码 bug,而是数据 bug:写错的日期、被改名的文章留下的死引用、缺 frontmatter 字段的半成品。这些问题构建不会报错,只会在读者点开的瞬间变成空白页或 404。解法是给内容层装一道“构建期校验”。

值得校验的六类问题

1. 必填与格式:字段缺失在 schema 层拦(zod/内容集合 schema),格式在脚本层兜:

// 阅读时长字段必须符合 "N 分钟",避免混入 "5 mins" / "约五分钟"
const readingTimePattern = /^[1-9]\d*\s*分钟$/;

2. 引用完整性relatedPosts、项目关联文章、系列成员这些“指向别的文档”的字段,构建期逐个解析目标是否存在:

for (const ref of data.relatedPosts ?? []) {
  if (!postIds.has(ref)) issues.push(`${file}: relatedPost "${ref}" 不存在`);
}

这是收益最高的一条——slug 改名后忘记同步引用,前端表现为“关联文章点开 404”,而只有这条断言能提前抓到。

3. 日期逻辑updatedAt < publishedAt 必然是笔误(除非你允许未来预约发布,那也要单独校验);RSS 排序、图谱时间衰减都依赖这个不变量。

4. slug 唯一性:不同目录同名 slug、大小写碰撞,在静态路由生成阶段直接互相覆盖——提前在校验里报。

5. 公开产物的草稿泄漏draft: true 的文章绝不能出现在 search-index.jsongraph-data.json、RSS、sitemap、dist/ 里。这条要作为发布门禁(对每个公开产物断言不含任一草稿 ID):

const draftSlugs = collectDraftIds(); // 从内容集合读
for (const artifact of ['search-index', 'graph', 'rss', 'sitemap']) {
  const leaked = findIdsInArtifact(artifact).filter((id) => draftSlugs.has(id));
  if (leaked.length) fail(artifact, leaked);
}

6. 覆盖度报表:必填字段覆盖率、各集合数量(文章/踩坑/项目),输出成机器可读 JSON 供后台“内容健康”页消费——把“还差多少内容达标”从感觉变成数字。

分层:schema 管结构,脚本管语义

内容集合 schema(zod)适合声明式约束:类型、枚举、默认值、正则。它管不了跨文档引用和集合级统计。两级配合:

zod schema(结构合法性)→ check-content.mjs(语义/引用/统计)→ 生成器(索引/图谱/RSS)

顺序很关键:校验在生成之前,坏数据直接让构建失败,而不是生成出半错的索引再靠下游兜。本项目把它接进 prebuild,任何 npm run build 自动执行。

严重度与豁免

校验脚本要区分 error(挡构建)与 warning(记录不挡):缺标题是 error,缺 difficulty 可以只是 warning(有默认值)。全 error 策略的结局一定是有人绕过门禁,分层策略才能长期活着。临时豁免要有过期日:

// 允许豁免,但必须写理由和到期日,过期自动升级为 error
{ file: 'old-post.mdx', rule: 'missing-updatedAt', until: '2026-10-01', reason: '存量迁移中' }

反馈形态决定执行力

校验结果不要只丢在终端日志里。落一份 content-health.json,后台页渲染成清单——作者改内容时看到的应该是“3 篇文章缺 description”这样可执行的条目,而不是一屏 grep 输出。数据、门禁、可视化三件套齐了,内容卫生才是可持续机制而不是一次性大扫除。

小结

代码有类型系统兜底,内容凭什么裸奔?把 frontmatter 当 schema、把跨文档引用当外键、把公开产物当边界测试对象,用一条 prebuild 命令把六类数据 bug 挡在构建期——这是内容站在“写作自由”和“发布可靠”之间唯一划算的折中。

Conversation

评论与互动

正在加载评论…

提交后需审核,不会立即公开。

Keep exploring

继续探索