X³M Notes 采用 Markdown-first、Git-native 的静态架构:Astro 负责生成站点,Content Collections 与 Zod 负责内容边界,Pagefind 负责本地全文搜索,Cloudflare Pages 负责部署。
结论
这套知识库的核心资产不是某个后台系统,而是可读的 Markdown 文件、可追踪的 Git 历史和一组确定性的检查脚本。网站只是这些内容经过筛选、渲染和验证后的公开视图。
当前 V1 不使用数据库、CMS 或 MDX。AI 可以协助理解、整理和编辑内容,但是否能进入公开构建由文章 Schema、状态与可见性规则、隐私扫描和生产构建共同决定。
最后核验:2026-07-26。
技术栈总览
| 层次 | 技术 | 在本项目中的职责 |
|---|---|---|
| 内容源 | UTF-8 Markdown、Git | 保存正文、记录修改、保持可迁移 |
| 站点生成 | Astro,静态输出 | 将文章、页面和布局构建为静态文件 |
| 内容模型 | Astro Content Collections、Zod | 加载 Markdown,并校验 frontmatter、状态和发布边界 |
| 页面组件 | Astro、React 19 | 负责页面模板、导航、文章布局和交互组件 |
| 视觉效果 | @react-three/fiber、Three.js | 为首页的知识场景提供低功耗 Canvas 装饰,不承载知识正文 |
| 全文搜索 | Pagefind | 在生产构建后为公开页面生成本地搜索索引 |
| 自动化检查 | Node.js ESM、TypeScript、ESLint、Prettier、markdownlint | 检查代码、Markdown、链接、Schema 和发布前约束 |
| 浏览器验收 | Playwright | 验证桌面端、移动端、搜索、主题、字体和公开边界 |
| 部署 | Cloudflare Pages | 构建并托管 dist/ 静态产物 |
内容与数据流
1. Markdown 是唯一正文格式
文章放在 src/content/articles/,文件名包含日期和 slug,例如:
src/content/articles/2026/2026-07-26-x3m-notes-tech-stack.md
原始输入、来源摘记、私密知识和已处理材料分别放在 content/inbox/、content/source-notes/、content/private/ 和 content/archive/。这些目录不参与生产构建,避免把采集过程误当成公开内容。
2. Content Collections 加载文章,Zod 定义边界
src/content.config.ts 使用 Astro 的 glob loader 读取文章,再交给 src/lib/article-schema.mjs 中的 Zod Schema。Schema 统一校验:
- ID、slug、标题、描述、语言、类型、分类和标签格式。
status、visibility、originality和confidence等受控字段。- 创建、更新和发布时间的顺序。
- 已发布文章必须有
published_at;草稿和审核中文章不能有发布时间。 unlisted必须设置noindex: true;派生内容必须记录来源。
这一步解决的是“内容是否结构正确”,不是“内容是否应该公开”。后者由发布过滤器和构建检查继续处理。
3. 页面和索引使用不同的公开白名单
src/lib/content.ts 中有两条重要规则:
isRoutable:只为status: published且visibility为public或unlisted的文章生成直接页面。isPublicIndexable:在此基础上只保留visibility: public且noindex: false的文章,用于首页、文章列表、分类、标签、搜索、RSS 和 Sitemap。
因此,文章存在于 Git 仓库并不等于它会出现在网站上。草稿、私密文章和测试材料不会通过客户端样式隐藏,而是在构建输入和路由生成阶段被排除。
前端与搜索
页面由 Astro 组件和布局组成,正文保持普通 Markdown。只有需要浏览器运行时的局部功能才使用 React;首页的 KnowledgeField 是一个遵守低功耗和减少动效设置的 React Three Fiber 视觉组件。
生产命令先运行 astro build,再用 Pagefind 扫描 dist/ 生成搜索索引。由于隐藏文章没有生成页面,它们也不会进入搜索索引;RSS 和 Sitemap 同样从公开白名单读取。
站点字体从 public/fonts/ 自托管,使用 Inter、Noto Sans SC、Source Serif 4、Noto Serif SC 和 JetBrains Mono。运行时不请求远程字体 CDN,字体许可证和来源记录在仓库文档中。
开发、检查与部署
当前项目的目标运行时是 Node.js 24.18.0,包管理器是 pnpm 11.9.0。常用检查分为三层:
pnpm format:check
pnpm lint
pnpm typecheck
pnpm kb:check
pnpm check:secrets
pnpm build
pnpm test:smoke
其中,kb:check 负责文章 Schema、文件名、H1、日期、来源、图片和内部链接;check:private 与生产构建验证最终产物没有泄漏私密或隐藏内容;Playwright 再从浏览器层面检查页面行为。
部署目标是 Cloudflare Pages,生产分支为 main,构建输出目录为 dist,目标域名是 https://md.xxxm.dev/。GitHub 仓库和 Cloudflare 凭据属于部署基础设施,不写入文章或代码。
这套选择解决什么问题
- 可迁移:Markdown 可以被编辑器、命令行工具和其他静态生成器继续读取。
- 可审查:Git diff 能直接显示正文、元数据和发布状态的变化。
- 可验证:Schema、隐私扫描、构建验证和浏览器测试可以重复执行。
- 边界清晰:采集、私密、草稿和公开内容不依赖 CSS 或客户端逻辑区分。
- 运维简单:没有数据库和长驻服务,部署的是构建后的静态文件。
风险与边界
- 依赖版本和框架 API 会变化;升级 Astro、Pagefind 或字体包后,需要重新执行完整检查。
- AI 协助写作不等于事实已经核验。涉及金融、医疗、法律和安全的内容仍需来源、地区、日期和人工审核。
- 静态构建不能替代账户权限管理。GitHub 应保持私有,部署 Token 只能配置在平台 Secret 中。
- 本文记录的是当前仓库的实现,不是对 Astro、Cloudflare Pages 或其他依赖的通用选型结论。