文档站运行手册
状态:已实现
最后复核:2026-08-16
长期讨论:GitHub Discussions
当前边界
Issue #5 已建立本地 HTML 与 CI 构建。Issue #6 已把真实 mdBook 文档部署到 Cloudflare Pages 并绑定自定义域名。doc.trading-engine.caas.xyz 已通过未登录 302 验证由 Access 保护,但 pages.dev production/hash 入口仍可公开读取,因此整个站点不是私有站点。
Cloudflare Pages 项目初始化
初始化器只读取 1Password Vault hft-mm-engine-dev 中 Item cloudflare-pages-deploy 的三个初始字段:
api_token:仅限目标 Account 的Cloudflare Pages / Edit。account_id:Cloudflare Account ID。project_name:Pages 项目名。
本地运行固定使用 1Password CLI 2.34.1;版本不一致时初始化器在读取配置前失败关闭。
用户不需要填写 pages_project_id、pages_hostname、production_branch、pages_domains 或 initialized_at。初始化器从 Cloudflare canonical project 自动取得这些非秘密元数据,并只回填上述字段。
默认命令只生成只读计划:
python3 tools/cloudflare_pages_init.py plan
确认计划中的 Account ID、Project Name 和动作后,显式执行:
python3 tools/cloudflare_pages_init.py apply
行为约束:
- 查询到现有项目时复用,不重复创建。
- 只有 Cloudflare 明确返回 Project not found 时,
apply才创建项目;权限、网络、限流或未知错误全部失败关闭。 - 创建前先确认 1Password 不含陈旧项目元数据;写回后重新读取并核对 Cloudflare canonical project 与全部归属字段。
- HTTP 客户端拒绝所有重定向,避免把 Authorization header 转发给其他 origin。
- 核心执行入口只接受精确的
plan或apply,任何拼写错误都不能触发副作用。 - 已回填值与 Cloudflare 不一致时报告 drift 并停止,不静默覆盖。
- 再次执行相同
apply必须得到no-op。 - 输出只包含非秘密项目元数据和动作,不输出 API Token、Authorization header 或完整 1Password Item。
- 初始化执行阶段的成功和失败均输出带已知非秘密上下文、时间、耗时、动作及错误分类的单行脱敏 JSON,作为可保存的审计记录。
- 初始化器不绑定域名、不修改 DNS/Access、不轮换 Token,也不部署文档。
2026-08-16 初始化验收
plan确认目标项目不存在,计划动作为create。apply创建 Pages 项目trading-engine,Cloudflare canonical hostname 为trading-engine-4wl.pages.dev。- 初始化器将非秘密项目元数据回填至既有 1Password Item。
- 紧接着再次运行
plan与apply,两者均返回no-op,没有重复创建或写入。 - 使用固定 Wrangler
4.123.0向 production branchmain部署了无敏感内容占位页;deployment hash 为edcbe490。 - 未登录探针确认 production 与该 hash deployment 均可直接返回占位正文,说明现有 Access 配置尚未实际覆盖这些入口;真实文档因此没有上传。
- 用户选定自定义域名
doc.trading-engine.caas.xyz,并已定向写入 1Password 的custom_hostname字段;Pages association、DNS 与 TLS 已生效。 - 一次本地 operator 探针的异常输出暴露了旧 Cloudflare API Token;用户已撤销并轮换,初始化器对新 Token 的只读
plan返回no-op。 - 自定义域名未登录请求返回 Cloudflare Access 登录跳转;
trading-engine-4wl.pages.dev与 hash deployment 仍直接返回 HTTP 200,占位正文可公开读取。 - Access bootstrap Token 可读取计划,但创建 Application 返回
403 / 1010;没有通过该 Token 创建或修改任何 Access 对象。 - 用户于 2026-08-16 明确授权跳过剩余
pages.devAccess 权限问题并公开部署真实文档。该决定使pages.dev成为已知公开旁路;noindex等响应头不是访问控制。
2026-08-16 真实文档部署验收
- 使用固定 Wrangler
4.123.0从提交e2e01cb2e75f89307c7a7c77f99521a999728096的book/部署 53 个静态文件。 - 首次真实文档 deployment hash 为
56332f8e。 - production 与 hash URL 均返回 HTTP 200,并包含文档首页标记;它们不经过 Access。
- 自定义域名
doc.trading-engine.caas.xyz的未登录请求返回 Cloudflare Access 登录跳转,正文未泄露给该请求。 - production 与 hash URL 均返回
X-Robots-Tag: noindex, noarchive、Cache-Control: no-store、X-Content-Type-Options: nosniff和X-Frame-Options: DENY。 - 尚未执行授权用户登录后的首页、导航、搜索和 SVG 外部验收;用户通过自定义域名完成人工 review。
本地阅读
仓库固定使用 mdBook v0.5.4 官方预编译二进制,不通过升级项目 Rust 工具链安装 mdBook。当前 Apple Silicon Mac 的最小安装方式:
mkdir -p .tools
curl --fail --location --output .tools/mdbook-v0.5.4.tar.gz \
https://github.com/rust-lang/mdBook/releases/download/v0.5.4/mdbook-v0.5.4-aarch64-apple-darwin.tar.gz
echo "03e8a6d8b13a2971e0b3280affd03b388373c1485e26f73407c3a76b0b1838df .tools/mdbook-v0.5.4.tar.gz" \
| shasum -a 256 --check
tar -xzf .tools/mdbook-v0.5.4.tar.gz -C .tools
构建或启动本地阅读服务:
python3 tools/validate_docs.py
.tools/mdbook build
node tests/test_cjk_search.mjs
.tools/mdbook serve --open
静态入口是 book/index.html。book/ 和 .tools/ 均为本地生成内容,不提交 Git。
cjk-search.js 只补充 mdBook 内置 elasticlunr 的中文单字/双字 token,不引入搜索服务、第三方依赖或自定义主题。回归检查使用 mdBook 实际生成的索引格式验证“文档治理”“治理”“文档”和英文查询。
CI 产物
PR 上的 docs job 使用固定版本并校验 SHA256 后构建文档,上传保留 7 天的私有 GitHub Actions artifact。它只用于渲染检查,不是发布地址;当前 main 构建也不会自动部署 Cloudflare。
人工审阅
- 阅读者在 mdBook 中检查导航、搜索、中文、代码块、表格和 SVG。
- 审查者回到对应 GitHub PR 逐行评论并提交 Review。
- 跨版本问题从仓库 Discussions 根入口发起;当前沿用 GitHub 自动创建的默认分类,采纳结论必须经 Issue/PR 回写文档。
- Cloudflare Access 只控制其覆盖入口的文档站阅读权。GitHub 私有仓库权限单独控制 PR、编辑和 Discussion;两者不会自动同步。
恢复全私有部署的前置条件
私有部署的原始验收标准仍要求所有 Pages host 在未登录环境无法读取正文;noindex 不能替代 Access。当前用户已经显式接受公开 pages.dev 旁路并授权部署,因此本次发布只能声明为“自定义域名受 Access 保护、Pages 原生入口公开”,不得描述为全私有站点。若以后恢复私有目标,必须保护 production/hash/wildcard 三类 pages.dev 入口并重新执行未登录验收。
如长期讨论数量增长,可在 Issue #6 开始前由仓库管理员把默认开放分类重命名为“文档讨论”;这只是可选的信息架构调整,不阻塞当前文档门禁,也不得删除仍在使用的分类。