Pattern E — 独立 docs 仓架构 spec
日期:2026-05-25
作者:Claude(per 用户 5/25 拍板)
状态:spec only(实施前必经用户批准,per 全局 CLAUDE.md「架构级别设计铁律」)
替代:Pattern A(各产品仓 docs/wiki/ + submodule + cross-repo PAT dispatch)
目录
- 0. 用户原话与触发
- R1 真验结论(必读)
- 1. 目标定位
- 2. 范围边界
- 3. 架构数据流
- 4. 模块边界
- 5. API 契约
- 6. 扩展点 / 插件接口
- 7. 错误处理 + 边界 case
- 8. 成本契约
- 9. 测试矩阵
- 10. 向后兼容 / migration path
- 11. 风险登记
- 附录 A:Pattern A vs Pattern E 对比矩阵
- 附录 B:新项目 5-min 接入路径(spec 描述)
0. 用户原话与触发
「我认为 docs 应该是独立仓库,你觉得呢?否则私人仓库和共有仓库,dispatch 的稳定性和标准都是不确定的。其他项目接入是否也是更容易出现问题?」 —— 用户 2026-05-25
触发背景:
5/24 Phase B 实施 Pattern A 后发现的实际摩擦:
- 私有仓 → public wiki-portal 的 dispatch token 需 fine-grained PAT 90 天过期(
WIKI_PORTAL_DISPATCH_TOKEN) - 主仓 workflow 与代码 CI 混合(
.github/workflows/wiki-dispatch.yml) - 新项目接入需主仓 owner 加 workflow + secret(摩擦大)
- 私有 vs 公开仓 dispatch 标准不一致
当前实际状态(5/25 仓内检查):
wiki-web仓docs/attune/、docs/lawcontrol/、docs/pluginhub/等子目录是 直接 markdown 文件(不是 submodule)- 无
.gitmodules - 无
wiki-dispatch.ymlworkflow(仅wiki-deploy.yml— push wiki-web 自身触发 build+deploy) - 即 Pattern A 设计文档化、但尚未在 wiki-web 仓真正落地为 submodule 拓扑
→ Pattern E 是在 Pattern A 物理 submodule 化之前就完成的架构调整,免去后续推倒重做。
R1 真验结论(必读)
问题:docs 仓 push 后用 secrets.GITHUB_TOKEN 调 repository_dispatch 触发 wiki-portal CI,能否绕过 fine-grained PAT 90 天过期?
答案:不能。GITHUB_TOKEN 严格只能操作自己所在仓。跨仓 repository_dispatch 必须 PAT 或 GitHub App installation token。
证据(GitHub 官方文档 , 2026-05-25 抓取):
docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication全文示例均以${{ github.repository }}为 target —— 即自己所在仓。明文:"If you need a token that requires permissions that aren't available in the GITHUB_TOKEN, create a GitHub App and generate an installation access token within your workflow. Alternatively, you can create a personal access token, store it as a secret in your repository."- GITHUB_TOKEN 已知设计约束:GitHub Actions 出于防工作流递归触发的安全考虑,
GITHUB_TOKEN触发的事件(push / repository_dispatch / workflow_dispatch)不会触发任何新的 workflow run。即使在同仓,GITHUB_TOKEN调POST /repos/{owner}/{repo}/dispatches也不会触发on: repository_dispatchworkflow(GitHub 官方限制)。 - 跨仓:
GITHUB_TOKEN的audience严格绑定本仓,对其他仓的 API 调用直接 401/403。
Pattern E 因此必须保留某种跨仓凭证,候选:
| 凭证类型 | 优点 | 缺点 |
|---|---|---|
| A. 用户 fine-grained PAT(90 天过期) | 简单、单一来源 | 过期需手动续 |
| B. 用户 classic PAT(无过期) | 不过期 | 权限粒度差、安全风险高 |
| C. GitHub App + installation token(无过期,仓粒度授权) | 安全 + 不过期 + 仓粒度 | 初次配置复杂(App 创建 + 安装 + JWT 流) |
| D. organization-level PAT(org 内共享) | 全 org docs 仓单凭证 | 仍 90 天过期(fine-grained)/ 权限管理粒度粗 |
Pattern E 推荐 C(GitHub App)作为最终形态,D(org-level fine-grained PAT)作为过渡形态。
→ Pattern E 的核心收益不再是"零 PAT"(这是不可达目标),而是:
- 统一标准 — 公开 docs 仓 + 同一种 dispatch 模式(不再 private / public 仓两套)
- 降低接入摩擦 — 新项目接入只需创建 docs 仓、加 GitHub App 安装,不需主仓 owner 协调
- 解耦 docs maintainer 与 code maintainer — 文档贡献者可单独有 docs 仓 write 权
- docs 历史与代码历史分离 — git filter-repo 不影响主仓
1. 目标定位
1.1 解决的核心痛点
| 痛点 | Pattern A 现状 | Pattern E 目标 |
|---|---|---|
| dispatch 凭证一致性 | 私有 attune / attune-pro 各需独立 PAT;公开 KVM 又是一套 | 全部公开 docs 仓 + 统一 GitHub App(或 org PAT) |
| 接入摩擦 | 新项目需主仓加 workflow + secret + .gitmodules + sidebar | 新项目独立 docs 仓 + 1 行 .gitmodules + 1 文件 sidebar |
| docs vs code 维护混乱 | 主仓 PR 同时改代码 + docs,CI 跑全套测试 | docs 仓 PR 只跑 markdown lint,主仓代码 PR 不带 docs |
| history 噪声 | docs/wiki/ 大量历史进主仓 git log | docs 历史独立,主仓 git log 干净 |
| docs 权限隔离 | docs 贡献者必须有主仓 write | 仅需 docs 仓 write |
1.2 与产品 positioning 对齐
- wiki-portal 仍中立门户(Pattern A 已确立的 multi-tenant 设计不变)
- content-driven(不依赖产品 release 版本)
- GitHub-native 单一来源(无外部 CMS,per cloud ARCHITECTURE.md D6)
- 零数据库(Docusaurus 静态站,per Pattern A)
1.3 不解决的范畴
- 不替代 README / DEVELOP / RELEASE.md(仍在主仓内)
- 不替代主仓
docs/内非 wiki 内容(INSTALL / TESTING / VERSIONING / ADR / specs — 这些是开发者文档,docs 仓只装"用户面 wiki"内容) - 不替代 product launch website(official-web 走自己的路径)
2. 范围边界
2.1 做(必须)
- ✅ 新建 5 个 public docs 仓:
qiurui144/attune-docs(通用 attune wiki:getting-started / chat / sources / wizard / plugins / agents / privacy / faq)qiurui144/attune-pro-docs(Pro plugin 详细文档)qiurui144/attune-enterprise-docs(B2B 律所 / KVM 一体机用户文档)qiurui144/attune-pluginhub-docs(plugin marketplace 文档)qiurui144/kvm-docs(KVM 一体机产品文档)
- ✅ git filter-repo 抽取 现有 wiki-web 仓
docs/attune//docs/lawcontrol//docs/pluginhub//docs/getting-started//docs/hardware/等到对应 docs 仓,保留 commit 历史 - ✅ wiki-portal 改造:
- 新建
.gitmodules引用 5 个 docs 仓(pin 到 main HEAD SHA) - 移除 wiki-portal 仓内 docs/ 直接 markdown,改为 submodule 挂载点
sidebars.ts改为按 submodule 路径引用
- 新建
- ✅ 每个 docs 仓加 dispatch workflow:push main → repository_dispatch 触发 wiki-portal
- ✅ 统一凭证模式(推荐 GitHub App,过渡期 org-level fine-grained PAT)
2.2 不做(明确划清)
- ❌ 不动主仓
docs/内非 wiki 内容(INSTALL.md / DEVELOP.md / RELEASE.md / specs/ / adr/) - ❌ 不动 wiki-portal
wiki-deploy.yml(push wiki-portal 自身触发 build+deploy 不变) - ❌ 不动主仓 README.md(仍指向 wiki-portal URL)
- ❌ 不在本 spec 阶段新建任何 GH 仓(per 用户红线)
- ❌ 不动 wiki-portal
.gitmodules(本 spec 仅设计,实施在用户批准后) - ❌ 不删任何主仓
docs/wiki/(同上)
2.3 后续 v.x 才做
- v0.2:docs 仓 markdown lint + link check CI(独立 workflow)
- v0.3:docs 仓 PR preview deploy(独立 Netlify / Vercel preview,非生产 wiki-portal)
- v0.4:i18n(中英 / 多语言分离到 docs 仓内 i18n/ 目录)
3. 架构数据流
3.1 Pattern A 现行(含 5/24 实施计划,尚未落地物理 submodule)
┌─────────────────────────┐
│ attune (private) │ push docs/wiki/**
│ docs/wiki/ ←── PR │─────────┐
└─────────────────────────┘ │
│ dispatch with FINE-GRAINED PAT
│ (WIKI_PORTAL_DISPATCH_TOKEN, 90d expire)
▼
┌─────────────────────────┐ ┌──────────────────────────┐
│ attune-pro (private) │────▶│ wiki-portal (public) │
│ docs/wiki/ │ │ .github/workflows/ │
└─────────────────────────┘ │ wiki-deploy.yml │
│ docs/attune/ ← copy │
┌─────────────────────────┐ │ docs/attune-pro/← copy │
│ kvm (public) │────▶│ docs/kvm/ ← copy │
│ docs/wiki/ │ └──────────────────────────┘
└─────────────────────────┘
摩擦点:3 不同私/公仓 → wiki-portal,每仓独立 PAT,90 天过期。
3.2 Pattern E 目标
┌──────────────────────────┐
│ attune (private, code 仓) │
│ docs/ │ 仅 INSTALL/DEVELOP/specs/adr
│ README.md → wiki URL │
└──────────────────────────┘
↑ 引用(README 中链接 wiki-portal)
┌──────────────────────────┐ push main
│ attune-docs (public) │──────────────┐
│ wiki/getting-started/ │ │
│ wiki/chat.md │ │ repository_dispatch
│ wiki/sources/** │ │ via GitHub App
│ .github/workflows/ │ │ (or org-PAT)
│ dispatch.yml │ │
└──────────────────────────┘ ▼
┌──────────────────────────┐
┌──────────────────────────┐ │ wiki-portal (public) │
│ attune-pro-docs (public) │─────▶│ .gitmodules │
└──────────────────────────┘ │ docs/ │
│ attune/ ← submodule │
┌──────────────────────────┐ │ attune-pro/← submod │
│ kvm-docs (public) │─────▶│ kvm/ ← submodule │
└──────────────────────────┘ │ sidebars.ts │
│ .github/workflows/ │
│ wiki-deploy.yml │
└──────────────────────────┘
│
▼ build & deploy
wiki.attune.dev
3.3 数据流时序
- 文档贡献者 PR 到
attune-docsmain - PR merge →
attune-docs仓内dispatch.yml触发 dispatch.yml用 GitHub App installation token 或 org PAT 调POST /repos/qiurui144/wiki-portal/dispatches { event_type: "wiki-content-update" }- wiki-portal
wiki-deploy.yml监听on: repository_dispatch: [wiki-content-update] - workflow 步骤:
- checkout wiki-portal + submodules(
submodules: recursive) git submodule update --remote attune-docs拉最新 attune-docs main- npm ci + npm run build
- SSH 部署到生产
- checkout wiki-portal + submodules(
- (可选)workflow 自动 commit 新 submodule pin SHA 回 wiki-portal main(避免 submodule pin 漂移)
3.4 DB / cache layer
- 零 DB(Docusaurus 静态)
- GitHub raw CDN 不参与(submodule 走 git protocol 拉,本地构建后生成静态文件)
- build artifact 仍在生产服务器
wiki-web/build/(不变)
4. 模块边界
4.1 5 个 docs 仓内部结构
每个 docs 仓最小化模板:
attune-docs/
├── README.md # 仓库说明 + 贡献指引 + 指向 wiki-portal URL
├── LICENSE # CC-BY-4.0 文档许可
├── .github/
│ └── workflows/
│ └── dispatch.yml # push main → dispatch wiki-portal
├── wiki/ # ★ 实际文档(被 wiki-portal submodule 挂载到 docs/attune/)
│ ├── index.md
│ ├── getting-started/
│ ├── quickstart.md
│ ├── wizard.md
│ ├── chat.md
│ ├── sources/
│ │ ├── index.md
│ │ ├── local-files.md
│ │ ├── webdav.md
│ │ ├── email.md
│ │ └── rss.md
│ ├── llm-setup.md
│ ├── plugins.md
│ ├── agents.md
│ ├── architecture.md
│ ├── privacy.md
│ ├── benchmarks.md
│ └── faq.md
└── tests/
└── markdown-lint.yml # 可选 lint CI
4.2 wiki-portal 仓改造点
wiki-portal/
├── .gitmodules # ★ 新增
│ [submodule "docs/attune"]
│ path = docs/attune
│ url = https://github.com/qiurui144/attune-docs.git
│ branch = main
│ (... 5 个 submodule 条目)
├── docs/ # ← 所有子目录改为 submodule
│ ├── attune/ # → attune-docs/wiki/
│ ├── attune-pro/ # → attune-pro-docs/wiki/
│ ├── attune-enterprise/ # → attune-enterprise-docs/wiki/
│ ├── pluginhub/ # → attune-pluginhub-docs/wiki/
│ └── kvm/ # → kvm-docs/wiki/
├── sidebars.ts # ★ 改:路径引用 docs/<submodule>/wiki/<file>
└── .github/workflows/
├── wiki-deploy.yml # ★ 改:add submodule checkout + remote update + on: repository_dispatch
└── wiki-content-update.yml # ★ 新增:on: repository_dispatch handler
注意:submodule mount path 不直接挂在 docs/attune/,而是 docs/attune/ 是 submodule root,其下的 wiki/ 子目录是 Docusaurus 读取的实际文档。这样可以让 docs 仓本身有 README + LICENSE 而不污染 wiki content。
但这意味着 sidebars.ts 引用路径变成 attune/wiki/index、attune/wiki/quickstart。或者用 Docusaurus path 配置把 docs plugin 指向 docs/attune/wiki 而不是 docs/。本 spec 倾向后者:
// docusaurus.config.ts
plugins: [
[
'@docusaurus/plugin-content-docs',
{
id: 'attune',
path: 'docs/attune/wiki',
routeBasePath: 'attune',
sidebarPath: './sidebars/attune.ts',
},
],
// 重复 5 次(attune / attune-pro / enterprise / pluginhub / kvm)
],
这样 sidebar 路径回归正常(index、quickstart),不带 wiki/ 前缀。
4.3 各主仓改造点
attune/ # 不动 docs/INSTALL / docs/specs / docs/adr
└── docs/
├── INSTALL.md # 留在主仓(开发者文档)
├── DEVELOP.md # 留在主仓
├── VERSIONING.md # 留在主仓
├── adr/ # 留在主仓
└── superpowers/ # 留在主仓(spec / plan)
# 删除:
# docs/wiki/ → 全部抽到 attune-docs
# docs/attune-*.md(用户面)→ 抽到 attune-docs
README.md # 在 "User Documentation" 章节链接 https://wiki.attune.dev
5. API 契约
5.1 docs 仓 → wiki-portal dispatch payload
HTTP:POST https://api.github.com/repos/qiurui144/wiki-portal/dispatches
Headers:
Authorization: Bearer <github-app-installation-token | org-pat>
Accept: application/vnd.github+json
X-GitHub-Api-Version: 2022-11-28
Body:
{
"event_type": "wiki-content-update",
"client_payload": {
"source_repo": "qiurui144/attune-docs",
"source_sha": "abc1234...",
"source_ref": "refs/heads/main",
"triggered_at": "2026-05-25T10:00:00Z"
}
}
wiki-portal wiki-content-update.yml:
name: Wiki content update from docs repo
on:
repository_dispatch:
types: [wiki-content-update]
jobs:
update-submodule-and-deploy:
runs-on: ubuntu-latest
permissions:
contents: write # to commit submodule pin
actions: write
steps:
- name: Checkout wiki-portal with submodules
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
token: ${{ secrets.SUBMODULE_TOKEN }} # PAT or App token to read submodules
- name: Determine source submodule
run: |
echo "SOURCE_REPO=${{ github.event.client_payload.source_repo }}" >> $GITHUB_ENV
# 映射 qiurui144/attune-docs → docs/attune
case "${{ github.event.client_payload.source_repo }}" in
*/attune-docs) echo "SUBMODULE_PATH=docs/attune" >> $GITHUB_ENV ;;
*/attune-pro-docs) echo "SUBMODULE_PATH=docs/attune-pro" >> $GITHUB_ENV ;;
*/attune-enterprise-docs) echo "SUBMODULE_PATH=docs/attune-enterprise" >> $GITHUB_ENV ;;
*/attune-pluginhub-docs) echo "SUBMODULE_PATH=docs/pluginhub" >> $GITHUB_ENV ;;
*/kvm-docs) echo "SUBMODULE_PATH=docs/kvm" >> $GITHUB_ENV ;;
*) echo "Unknown source repo"; exit 1 ;;
esac
- name: Update submodule to latest main
run: |
cd "$SUBMODULE_PATH"
git fetch origin main
git checkout main
git pull --ff-only origin main
cd -
git add "$SUBMODULE_PATH"
- name: Commit submodule pin
run: |
git config user.name "wiki-portal-bot"
git config user.email "wiki-portal-bot@attune.dev"
git commit -m "chore(wiki): bump ${SUBMODULE_PATH} to ${{ github.event.client_payload.source_sha }}" || echo "No change"
git push origin main
# (build & deploy steps same as wiki-deploy.yml)
5.2 docs 仓 dispatch.yml 标准模板
name: Notify wiki-portal
on:
push:
branches: [main]
workflow_dispatch:
jobs:
notify:
runs-on: ubuntu-latest
steps:
- uses: peter-evans/repository-dispatch@v3
with:
# ★ 必须 PAT 或 GitHub App token — GITHUB_TOKEN 不可跨仓(per R1)
token: ${{ secrets.WIKI_PORTAL_DISPATCH_TOKEN }}
repository: qiurui144/wiki-portal
event-type: wiki-content-update
client-payload: |
{
"source_repo": "${{ github.repository }}",
"source_sha": "${{ github.sha }}",
"source_ref": "${{ github.ref }}",
"triggered_at": "${{ github.event.head_commit.timestamp }}"
}
5.3 凭证存储
推荐 Phase E1 期:org-level fine-grained PAT
- 名称:
WIKI_PORTAL_DISPATCH_TOKEN - 权限:
repository_dispatchwrite to qiurui144/wiki-portal - 在 GitHub org settings 设为 organization secret,授权给所有 docs 仓
- 90 天过期 — 加日历提醒,单次操作即续
推荐 Phase E3 期:GitHub App(最终形态)
- App name:
attune-wiki-dispatch - App permissions:
contents:read+actions:writeon target wiki-portal - 安装到 qiurui144 / qiurui144-org
- workflow 用 actions/create-github-app-token@v1 在 job 内换 installation token
6. 扩展点 / 插件接口
6.1 新增第 6 个 docs 仓的流程(标准化)
参考附录 B的详细 5-min 步骤。
6.2 docs 仓模板(qiurui144/docs-template)
规划:实施 Phase E1 后立即建一个 qiurui144/docs-template 仓作为后续接入起点:
docs-template/
├── README.md # "Replace 'PROJECT' with your project name"
├── LICENSE
├── .github/workflows/dispatch.yml
└── wiki/
└── index.md
新项目接入 = gh repo create qiurui144/<project>-docs --template qiurui144/docs-template。
6.3 wiki-portal 端的扩展锚点
docusaurus.config.ts中plugins数组 — 每个 docs 仓 1 个 plugin entrysidebars/<project>.ts— 每个 docs 仓 1 个 sidebar 文件wiki-content-update.ymlcase语句 — 加 1 行映射
7. 错误处理 + 边界 case
7.1 错误码
| 场景 | exit code | 处理 |
|---|---|---|
| docs 仓 push 但 PAT 过期 | dispatch.yml fail step | 用户在仓页看到红勾,手动 re-run workflow 或续 PAT |
| dispatch 成功但 wiki-portal build fail | wiki-content-update.yml fail step | 通知 webhook → Slack(待 v0.2 实施);手动 workflow_dispatch 重试 |
| submodule 仓被删除 | wiki-portal CI submodule update fail | 显式报错 + 临时把 sidebar 该项注释掉,避免整站 build fail |
| docs 仓 main 不存在 | git checkout main fail | 显式报错;要求 docs 仓必须有 main |
7.2 边界 case
- docs 仓首 commit / main 空:wiki-portal 收 dispatch 后
git pull拉到空 tree → Docusaurus build 抱怨缺 index.md → 失败。对策:docs-template 强制含wiki/index.md占位。 - submodule pin 漂移(wiki-portal main 的 submodule SHA 与 docs 仓 main HEAD 不一致):
wiki-content-update.yml总是git pull --ff-only origin main+ commit 新 SHA,自动消除漂移。 - 并发 dispatch(多 docs 仓同时 push):用 GitHub Actions
concurrency: { group: wiki-deploy, cancel-in-progress: false }让队列串行,避免 deploy 冲突。 - rate limit:GitHub Actions 同仓 workflow 60/h;wiki-portal
wiki-content-update.yml受此限。docs 仓 push 频率 ≪ 60/h,安全。 - 构建产物为空:
Verify build outputstep 已有(per wiki-deploy.yml)— 不变。
7.3 graceful degradation
- 任一 docs 仓不可用(403 / DELETED) → wiki-portal 仍能 build 其他 4 个 docs(前提:删该 submodule + sidebar 条目)
- wiki-portal 不可用 → docs 仓 push 不影响主仓 CI,docs 维护人员仍能在 docs 仓内预览 markdown
- dispatch PAT 过期 → 影响仅 docs 仓 → wiki-portal 的自动触发;手动
workflow_dispatch仍可触发 wiki-portalwiki-deploy.yml
8. 成本契约
8.1 GitHub 资源
| 资源 | Pattern A | Pattern E | 增量 |
|---|---|---|---|
| public 仓数 | 1 (wiki-portal) | 6 (wiki-portal + 5 docs) | +5 |
| private 仓数 | 2-3 (attune / attune-pro 含 docs/wiki/) | 2-3 (不含 docs/wiki/) | 0 |
| GH Actions minutes | wiki-portal build ~5 min/push | docs dispatch ~10s + wiki-portal build ~5 min | +20s/push (可忽略) |
| GH secrets | 1 PAT × N 私仓 | 1 org PAT 共享 / 或 1 GitHub App | -N+1 |
| 月度估算 | ~10 push/月 × 5 min = 50 min | 同 | ~50 min(GitHub Actions 免费额度 2000 min/月,绰绰有余) |
8.2 维护成本
| 任务 | Pattern A | Pattern E |
|---|---|---|
| PAT 续 | N 次(每仓独立 PAT) | 1 次(org 共享 PAT)或 0 次(GitHub App) |
| 新项目接入 | 主仓 owner 协调 + 写 wiki-dispatch workflow + 加 secret | docs 仓 owner 自助 |
| docs PR review | 主仓 maintainer(混在代码 PR 里) | docs maintainer(独立) |
| sub-team docs 贡献 | 需主仓 write 权 | 仅 docs 仓 write 权 |
8.3 用户 UI 显示
不适用 —— Pattern E 是基础设施 / CI 层变更,对终端用户透明。wiki-portal URL 不变。
9. 测试矩阵
9.1 真验路径(必须在实施前完成)
| 测试项 | 方法 | 通过标准 |
|---|---|---|
| R1 验证(已完成) | 阅 GitHub 官方 docs | GITHUB_TOKEN 不能跨仓 ✓ |
| R2 验证 | 在测试 public 仓用 fine-grained PAT 真触发 wiki-portal dispatch | wiki-portal workflow run 成功启动 |
| R3 验证 | 测试 submodule pin commit 回写流程 | wiki-portal main 自动得到新 SHA commit |
| R4 验证 | 测试并发 dispatch | 两次同时 push 触发的 build 串行执行 |
9.2 实施后测试矩阵
| 类型 | case 数 | 工具 |
|---|---|---|
| golden case(push docs 仓 → wiki 更新) | 5 / docs 仓 = 25 | manual workflow trigger + curl check wiki URL |
| 属性测试 | 0 | N/A(基础设施层无属性) |
| 边界测试 | 5 | (1) 空 docs 仓首 push (2) submodule 不可达 (3) PAT 过期 (4) 大文件(10 MB markdown)(5) UTF-8 BOM markdown |
| 异常测试 | 3 | (1) docs 仓被删 (2) wiki-portal main protected (3) sidebar.ts 引用不存在 doc |
| 集成 E2E | 1 | 完整 push → dispatch → submodule update → build → deploy → wiki URL 验证 |
| 回归 fixture | 每修一个 bug 加 1 | wiki-portal CI 内 markdown lint + link check |
9.3 与 Pattern A 等价性测试
实施 Phase E2 期(并存)必须验证:
- 同样的 markdown 在 Pattern A submodule(如果实际部署过)和 Pattern E 仓产生完全相同的 wiki URL + 渲染结果
- sidebar 顺序一致
- search index 一致
10. 向后兼容 / migration path
10.1 5-phase 迁移计划
Phase E1 (1 day): 仓基础设施
- 新建 5 docs 仓(empty + LICENSE + README)
- 建 qiurui144/docs-template
- 配 org-level fine-grained PAT
Phase E2 (1 day): 内容迁移
- git filter-repo 抽 wiki-web 仓 docs/attune/ → attune-docs/wiki/(保留 commit 历史)
- 同上 docs/lawcontrol/ docs/pluginhub/ docs/getting-started/ docs/hardware/ 等
- 推到对应 docs 仓
- 验证 docs 仓 markdown 可独立预览(npm run start)
Phase E3 (1 day): wiki-portal 改造
- 加 .gitmodules + git submodule add(指向 5 docs 仓 main)
- 改 docusaurus.config.ts 加 5 个 plugin-content-docs 实例
- 改 sidebars.ts → 拆成 sidebars/<project>.ts
- 改 .github/workflows/wiki-deploy.yml 加 submodules: recursive
- 加 .github/workflows/wiki-content-update.yml
- 本地测试 npm run build 通过
Phase E4 (1 day): 旧 docs 仓内容删除
- wiki-portal main 内删 docs/attune/ docs/lawcontrol/ 等直接 markdown(已被 submodule 覆盖)
- 验证 wiki-portal build 仍正常
- 主仓 attune / attune-pro 的 docs/wiki/(若存在)删除
- 主仓 README 加链接到 https://wiki.attune.dev/attune
Phase E5 (0.5 day): 监控 + 文档
- 加 wiki-portal monitoring(GH Actions failure → Slack)
- 写 docs-template/README.md「新项目接入指南」
- 更新 wiki-portal README.md 描述 Pattern E
总工期:4.5 天
10.2 旧 URL 兼容
wiki-portal URL 不变(wiki.attune.dev/attune/getting-started 等),用户视角零迁移。
10.3 主仓 README 链接
主仓 README "Documentation" 节继续指 https://wiki.attune.dev。无变化。
10.4 rollback path
任意 phase 失败 → 回滚到 phase N-1:
- Phase E2 失败:git filter-repo 备份原始 wiki-web 仓
- Phase E3 失败:wiki-portal main 不合 PR,docs 仓继续存在(无害)
- Phase E4 失败:保留旧 docs/ markdown 副本到 phase 完成稳定后再删
11. 风险登记
| ID | 风险 | 概率 | 影响 | 缓解 |
|---|---|---|---|---|
| R1 | GITHUB_TOKEN 跨仓 dispatch 不可行(已验证) | ✓ 已确认 | 高 | 仍需 PAT 或 GitHub App,Pattern E 的"零 PAT"假设不成立。但其他收益(标准化 / 接入简单 / 维护解耦)仍 valid。 |
| R2 | git filter-repo 抽 docs/wiki/ 时漏 commit(重命名 / 移动文件历史断裂) | 中 | 中 | filter-repo --path docs/wiki + --path-rename;事后用 git log --follow 验证关键文件历史完整 |
| R3 | wiki-portal Phase A 设计的 layout(docs/ | 中 | 中 | 实测发现 Pattern A 物理 submodule 尚未落地(仓内仍是直接 markdown)→ 可以一次性跳过 Pattern A submodule 阶段,直接走 Pattern E |
| R4 | KVM / 其他项目 owner 不接受独立 docs 仓 | 低 | 低 | 用户主导决策;非用户拥有的项目(lawcontrol 等)可保留 Pattern A 老法 |
| R5 | docs ↔ code 双 commit 维护成本(feature 改 + docs 改要两个 PR) | 中 | 中 | 文档化 contributor flow;高频 changeset 可批量后一次性同步 docs 仓 |
| R6 | public docs 仓内容泄露内部 code-tied info(如未发布 feature 名 / 私有 endpoint) | 中 | 高 | docs 仓 PR review checklist:禁止引用未发布 feature;wiki-portal CI 加 grep 检查关键词(如 "INTERNAL"、"WIP") |
| R7 | qiurui144 org 仓数过多(已 10+) | 低 | 低 | docs 仓全部 public 不算 private 仓配额;命名约定 *-docs 后缀好筛 |
| R8 | submodule pin 漂移 → wiki-portal 不知道某 docs 仓有新 commit | 中 | 中 | wiki-content-update.yml workflow 自动 git pull --ff-only + commit 新 pin;每 dispatch event 触发一次同步 |
| R9 | fine-grained PAT 90 天到期忘续 | 高 | 中 | 加 GitHub App(无过期)作为最终方案;过渡期日历提醒 |
| R10 | dispatch event 丢失(GH Actions outage / rate limit) | 低 | 低 | docs 仓 README 提供「手动 workflow_dispatch」指引 |
| R11 | 5 个 plugin-content-docs 实例增加 wiki-portal build 时间 | 中 | 低 | Docusaurus 单 plugin 实例 build 平均 30s → 5 实例 ~2-3 min(仍 < 5 min CI 限) |
| R12 | docs 仓 README + LICENSE 与 wiki/ 内 index.md 重复 / 冲突 | 低 | 低 | README 描述「这是 wiki 内容源」;index.md 是 wiki 首页 — 用途明确不冲突 |
附录 A:Pattern A vs Pattern E 对比矩阵
| 维度 | Pattern A | Pattern E | 优胜 |
|---|---|---|---|
| 凭证管理 | N 个 PAT(每仓独立) | 1 个 org PAT 或 1 个 GitHub App | E(-N+1) |
| 凭证过期 | N × 90d 续期点 | 1 × 90d 或 0(App) | E |
| 新项目接入 | 需主仓 owner | docs 仓 owner 自助 | E |
| docs 维护权限 | 与主仓 write 耦合 | 独立 | E |
| history 干净度 | 主仓含 docs/wiki/ 历史 | 主仓干净 | E |
| docs PR review | 混在代码 PR | 独立 | E |
| dispatch 稳定性 | 私 / 公 仓两套标准 | 全公开 + 统一 | E |
| 初次实施复杂度 | 1 仓加 workflow | 5 仓新建 + filter-repo + wiki-portal 改 | A(简单) |
| 运维复杂度 | 中(PAT 续期 N 次) | 低(GitHub App 安装一次) | E |
| storage cost | 主仓 +docs 体积 | 5 个独立小仓 | 等价 |
| wiki-portal CI 复杂度 | 中(每仓 trigger 不同) | 低(统一 repository_dispatch handler) | E |
| 回滚成本 | 低 | 中(需 git filter-repo 反向) | A |
| docs 仓独立运营(如以后单独开源给社区贡献) | 不可(与代码耦合) | 可 | E |
总评:12 维度中 Pattern E 优胜 9 项,Pattern A 优胜 2 项(初次复杂度 + 回滚),1 等价。
→ 建议采用 Pattern E,实施工期 4.5 天。
附录 B:新项目 5-min 接入路径(spec 描述)
前提:org-level PAT 已存在 / GitHub App 已安装到 qiurui144。
步骤(以新项目 myproject-docs 为例):
# 1. 用 docs-template 建新 docs 仓(30s)
gh repo create qiurui144/myproject-docs \
--template qiurui144/docs-template \
--public --confirm
# 2. clone + 改 README + 加 wiki/index.md(2 min)
git clone https://github.com/qiurui144/myproject-docs.git
cd myproject-docs
sed -i 's/PROJECT/MyProject/g' README.md wiki/index.md
git add . && git commit -m "init: MyProject wiki" && git push
# 3. wiki-portal 加 submodule(1 min)
cd /path/to/wiki-portal
git submodule add https://github.com/qiurui144/myproject-docs.git docs/myproject
# 编辑 docusaurus.config.ts,加 myproject plugin-content-docs 实例
# 编辑 sidebars/myproject.ts,加 sidebar 定义
# 编辑 .github/workflows/wiki-content-update.yml,加 case */myproject-docs
# 4. wiki-portal commit + push(30s)
git add .
git commit -m "feat(wiki): add myproject docs"
git push origin main
# 5. 验证(1 min)
# - docs 仓 push main → 触发 dispatch
# - wiki-portal 收 dispatch → submodule update → build → deploy
# - 浏览 wiki.attune.dev/myproject/ 看到 index
总耗时:~5 min(不含等 CI build 完成的 ~5 min)。
vs Pattern A 接入:
- 主仓 owner 加 docs/wiki/ 目录 + workflow + secret + 协调跨权限 = ~20-30 min
实施前最终 checklist
- 用户书面批准本 spec(per 「架构级别设计铁律」§2.评审流程)
- 决定凭证模式:org PAT(过渡)vs GitHub App(最终)
- 决定 docs 仓 LICENSE(CC-BY-4.0 vs MIT vs Apache 2.0)
- 决定 docs 仓命名约定(
<project>-docs✓ vs<project>-wiki) - 决定 wiki-portal config 使用单 plugin 多实例 vs 单实例 multi-instance
- 实施前 R2 / R3 / R4 真验通过
spec 状态:draft → 待用户审 → 批准后 invoke superpowers:writing-plans 出 implementation plan。