wiki-portal 接入规范 SSOT
状态:2026-05-25 起草,对应
chore/wiki-portal-rebrand分支当前 KVM 接入实施。 维护:每次新项目接入或接入模式升级时更新此文档。 关联:
- spec
docs/superpowers/specs/2026-05-25-pattern-e-independent-docs-repo.md- plan
docs/superpowers/plans/2026-05-25-pattern-e-impl.md- 诊断
docs/KVM-INTEGRATION-DIAGNOSIS.md
目录 (Table of Contents)
- 0. 触发与背景
- 1. 当前接入流程(Pattern A — 5/26 上架时事实)
- 1.5 通用化接入流程(Pattern A.5 — 5/25 起 wiki.yaml 驱动)
- 2. 目标接入流程(Pattern E — v1.0.1 实施后)
- 3. Pattern A vs Pattern A.5 vs Pattern E 对比矩阵
- 4. 项目侧接入 checklist(项目仓 maintainer)
- 5. wiki-portal 侧接入 checklist(wiki-portal maintainer)
- 6. 已知反模式
- 7. 历史版本
0. 触发与背景
用户原话(2026-05-25):「wiki 的框架接入规范是否还没有定,KVM 项目想进行接入,但是貌似还需要改动 wiki 的代码,并且建立了分支」
事实校准:
- wiki-portal 当前已有接入规范,体现在
chore/wiki-portal-rebrand分支 + spec2026-05-25-pattern-e-independent-docs-repo.md(718 行 11 节齐全)+ plan2026-05-25-pattern-e-impl.md(1795 行)。 - KVM 接入确实改动了 wiki 代码(
docusaurus.config.ts/sidebars-kvm.ts/.gitmodules),是当前 Pattern A 模式下的必然代价,不是 KVM 特例。 - KVM 已走到 Pattern E 边缘:commit
0a5c776把 KVM submodule 指向独立 docs 仓qiurui144/kvm-docs,但 wiki-portal 侧仍需手改 ts 代码(仅 1 个 plugin instance)。 - 真正的"接入规范"分两层:(A) 当前 5/26 上架前可用的 Pattern A;(B) v1.0.1 后实施的 Pattern E zero-code-change。
当前实际状态(5/25 仓内核查):
- 分支
chore/wiki-portal-rebrandahead master 6 commits external/kvmsubmodule 已指向https://github.com/qiurui144/kvm-docs.gitbranch=maindocusaurus.config.tsplugins[]含 kvm plugin instance(id='kvm', path='external/kvm/wiki', routeBasePath='kvm', sidebarPath='./sidebars-kvm.ts')sidebars-kvm.ts列 7 页(index / quickstart / hardware / api / security / architecture / faq)- 其他 tenant(attune / attune-enterprise / pluginhub)的 sidebar entry 在
chore/wiki-portal-rebrand已删(commit97b6344deinit submodules + commit2a88f1arename)— 当前分支仅 KVM 一个 tenant 可 build 通 - Pattern E plan #161 未实施(5/27-5/30 sprint 排期)
1. 当前接入流程(Pattern A — 5/26 上架时事实)
适用范围:5/26-5/27 上架窗口期 + 任何 Pattern E 实施前的新项目接入。
1.1 模型
项目仓 (e.g. KVM) wiki-portal
├── docs/wiki/ ──┐ ├── external/<project>/ (git submodule → 项目仓)
│ ├── index.md │ │ └── docs/wiki/
│ ├── quickstart.md │ ├── docusaurus.config.ts ★ 改 plugins[] + navbar
│ └── ... │ ├── sidebars-<project>.ts ★ 新增 sidebar 配置
└── wiki.yaml (可选) │ ├── .gitmodules ★ 新增 submodule entry
│ └── static/img/logos/<p>.svg (可选)
│
└─→ wiki-portal admin: edit ts → PR → merge → docker rebuild → deploy
1.2 接入步骤(10 步,2-4 小时手工)
项目侧(maintainer 自行完成):
- 项目仓建
docs/wiki/子目录,写 markdown 内容(首页index.md必须,其余按需) - 文件命名 kebab-case(
getting-started.md而非GettingStarted.md) - 顶部 frontmatter 可选
sidebar_position控制 sidebar 顺序,无则按文件名字母序 - 推到 main 分支
wiki-portal 侧(wiki-portal admin 完成):
5. .gitmodules 加:
[submodule "external/<project>"]
path = external/<project>
url = <项目仓 https URL>
branch = main
git submodule add+git submodule update --initdocusaurus.config.tsplugins[]数组加 plugin instance:['@docusaurus/plugin-content-docs', {id: '<project>',path: 'external/<project>/docs/wiki',routeBasePath: '<project>',sidebarPath: './sidebars-<project>.ts',}],themeConfig.navbar.items[]加 entry:{type: 'docSidebar', sidebarId: '<project>', docsPluginId: '<project>', position: 'left', label: '<Project>'},- 新建
sidebars-<project>.ts,列出 markdown 文件 ID(不含.md后缀) - PR → review → merge to
chore/wiki-portal-rebrand(或 master) → docker rebuild → 部署
1.3 依赖与限制
- wiki-portal admin 必须改 ts 代码 + commit + push + redeploy
- 项目 docs 更新需
git submodule update --remote+ commit + redeploy(无自动 webhook) - KVM 当前已走 commit
0a5c776完成上述步骤 6-10
1.5 通用化接入流程(Pattern A.5 — 5/25 起 wiki.yaml 驱动)
适用范围:5/25 generalize commit 之后 + Pattern E 实施前的所有新项目接入。
核心改动:docusaurus.config.ts 不再硬编码 plugin instance;改用 scripts/load-projects.ts helper 扫描 external/*/wiki.yaml,动态生成 plugins[] + navbar.items[]。新接入 tenant 零 ts 代码改动。
1.5.1 模型
项目仓 (e.g. <project>-docs) wiki-portal
├── wiki/ ├── external/<project>/ (git submodule → 项目仓)
│ ├── index.md │ ├── wiki.yaml ★ 项目侧 SSOT
│ ├── quickstart.md │ └── wiki/ (markdown 内容)
│ └── ... ├── scripts/load-projects.ts (扫 external/*/wiki.yaml)
└── wiki.yaml ├── docusaurus.config.ts (引用 helper,**不**改)
├── .generated/sidebars/ (auto-gen, gitignored)
│ └── <project>.ts
└── sidebars.ts (仅主门户用,**不**含 tenant)
1.5.2 wiki.yaml schema(项目侧 SSOT)
每个 tenant 在自己的 docs 仓根目录提供 wiki.yaml:
# external/<project>/wiki.yaml
project_id: kvm # 必填。URL slug + docusaurus plugin id + sidebar id
display_name: KVM # 必填。navbar tab 显示名
tagline: "..." # 可选。简介(reserved for landing page)
sidebar_section: development # 可选。development / product / legal / other(默认 other)
order: 30 # 可选。同 section 内升序(默认 999)
logo_path: static/img/...svg # 可选。logo 文件路径
external_url: https://... # 可选。upstream docs 仓 URL(用于 "Edit on GitHub")
maturity: stable # 可选。stable / beta / experimental
# 必填。markdown 根目录(相对 wiki.yaml 所在仓根)。
# wiki-portal 拼成 external/<project>/<doc_path> 作为 docusaurus plugin path。
doc_path: wiki
# 必填。Sidebar 树 —— 文件名(不含 .md)按显示顺序。
sidebar:
- index
- quickstart
- hardware
- api
scripts/load-projects.ts::loadProjectsFromYaml() 在 docusaurus 加载 config 时执行:
- 扫
external/*/wiki.yaml - 校验必填字段(project_id / display_name / sidebar / doc_path)
- 写出
.generated/sidebars/<project_id>.ts(每 tenant 一份独立 sidebar TS,gitignored) - 返回 ProjectMeta[](按 order 升序)
docusaurus.config.ts 用返回值生成 plugins[] + navbar items[],不写死任何 tenant id。
1.5.3 接入步骤(项目侧 + wiki-portal 侧)
项目侧(docs 仓 maintainer):
- docs 仓 root 写
wiki.yaml(per §1.5.2 schema) wiki/目录写 markdown(index.md必须)- push main 分支
wiki-portal 侧(wiki-portal maintainer):
4. .gitmodules 加 entry + git submodule add + git submodule update --init
5. docusaurus.config.ts / sidebars.ts / 其他 ts 文件零改动 — loadProjectsFromYaml() 自动接入
6. npm run build 验证 build/<project>/ 生成 + 顶栏 tab 出现
7. commit + push(仅 .gitmodules + submodule pointer)→ docker rebuild → 部署
1.5.4 反模式(在 Pattern A.5 下尤其要避免)
- ❌ wiki.yaml 写在 wiki-portal 仓内(应该写在项目 docs 仓的 root,wiki-portal 通过 submodule 拉取)— SSOT 错位会导致项目侧改 sidebar 还要 wiki-portal 协调
- ❌ 手动在
docusaurus.config.ts加 plugin instance(应该让 helper 自动生成;硬编码 = 退化回 Pattern A) - ❌
.generated/sidebars/进 git(gitignored,由 helper 在 build 时生成) - ❌ 绕过 schema 校验(必填字段缺失时 helper 抛 Error,不要 swallow)
1.5.5 自检:零 ts 改动验证
任意时间在本地:
mkdir -p external/fake-tenant/wiki
echo "# Fake" > external/fake-tenant/wiki/index.md
cat > external/fake-tenant/wiki.yaml <<EOF
project_id: fake-tenant
display_name: Fake
doc_path: wiki
sidebar: [index]
EOF
npm run build # 应该出现 build/fake-tenant/index.html + navbar 多一个 "Fake" tab
rm -rf external/fake-tenant
1.5.6 与 Pattern E 衔接
Pattern E(v1.0.1 实施)核心改动是数据源:
- Pattern A.5:
loadProjectsFromYaml()读 本地external/*/wiki.yaml - Pattern E:换成
loadProjectsFromDB()读 远端 DB / API(GitHub App fetched)
helper signature 改 1 行,docusaurus.config.ts 与 sidebars.ts 全部 0 改动。
2. 目标接入流程(Pattern E — v1.0.1 实施后)
适用范围:v1.0.1(5/27-5/30 sprint)Pattern E 实施完成后的所有新项目接入。
详见 spec docs/superpowers/specs/2026-05-25-pattern-e-independent-docs-repo.md + plan docs/superpowers/plans/2026-05-25-pattern-e-impl.md。
2.1 模型
独立 docs 仓 (e.g. qiurui144/kvm-docs) wiki-portal
├── wiki/ ├── docs/<project>/ (submodule → docs 仓)
│ ├── index.md │ └── wiki/
│ └── ... ├── sidebars/<project>.ts
├── README.md + LICENSE (CC-BY-4.0) ├── docusaurus.config.ts (5 plugin instances 写死)
└── .github/workflows/dispatch.yml ──┐ └── .github/workflows/
(GitHub App 触发 wiki-portal CI) │ ├── wiki-deploy.yml (on: repository_dispatch)
└──webhook──→ └── wiki-content-update.yml
2.2 接入步骤(项目侧 90 sec / 5 click)
项目侧:
- 在 GitHub fork
qiurui144/docs-template为<project>-docs(公开仓,CC-BY-4.0) - 编辑
wiki/index.md等 - 安装 wiki-portal GitHub App 到
<project>-docs(一次性,App owner 已配置好) - push main → 触发
dispatch.yml→ wiki-portalrepository_dispatch→ 自动 rebuild
wiki-portal 侧:0 改动(前置一次性配置 5 个 submodule 槽位 + 5 个 sidebar,新项目复用 external/<slot> 槽位即可)。
2.3 凭证
per spec §R1 真验结论:GITHUB_TOKEN 严格仅本仓内有效,跨仓 dispatch 必须 PAT 或 GitHub App installation token。Pattern E 选 GitHub App(无过期 + 仓粒度授权)。
3. Pattern A vs Pattern A.5 vs Pattern E 对比矩阵
| 维度 | Pattern A(旧硬编码) | Pattern A.5(5/25 起,yaml 驱动) | Pattern E(v1.0.1 目标) |
|---|---|---|---|
| 新项目接入 wiki-portal 侧改动 | 改 docusaurus.config.ts + sidebars-<p>.ts + .gitmodules(2-4 小时手工) | 仅 .gitmodules + submodule pointer(10 分钟) | 0 改动 |
| 新项目接入 项目侧改动 | 写 docs markdown | 写 docs markdown + wiki.yaml | 写 docs markdown + 装 GitHub App |
| docs 维护 | 项目仓 main push → 手动 submodule update --remote → 重新部署 | 同 Pattern A | docs 仓 push → 自动 webhook → 自动重新部署 |
| 凭证 | 私有项目仓需 PAT(90 天过期) | 同 Pattern A | GitHub App installation token(不过期) |
| docs 与代码历史 | 混在项目仓 | 同 Pattern A | 完全分离 |
| plugin/sidebar SSOT | 在 wiki-portal ts 内 | 在项目仓 wiki.yaml 内 | 同 Pattern A.5 |
| CI 噪声 | 项目仓 PR 跑全套测试 + docs PR 也跑 | 同 Pattern A | docs PR 只跑 markdown lint |
| 接入摩擦 | 高(需 wiki-portal admin 协调每次接入) | 低(wiki-portal admin 仅做 submodule add) | 极低(项目独立完成) |
4. 项目侧接入 checklist(项目仓 maintainer)
Pattern A 模式(旧硬编码,仅历史参考)
- 项目仓建
docs/wiki/子目录 - 写
index.md(必须)+ 其他 markdown 文件 - 文件名 kebab-case
- sidebar 顺序通过
sidebar_positionfrontmatter 或 sidebar.ts 文件顺序控制 - 不写绝对路径链接(
/<project>/foo而非/foo) - 不写 Docusaurus 不支持的 MDX 高级语法(如自定义 React 组件)— 仅 CommonMark + 基础 MDX
- push 到项目仓 main 分支
- 通知 wiki-portal admin 进入 §5 流程(要求改 ts 代码)
Pattern A.5 模式(当前,5/25 起)
- 项目仓 root 写
wiki.yaml(per §1.5.2 schema),含project_id/display_name/doc_path/sidebar - 项目仓建
wiki/目录(或wiki.yaml::doc_path指定的其他名) - 写
index.md(必须)+ 其他 markdown 文件 - 文件名 kebab-case,与
wiki.yaml::sidebar[]元素对应 - 不写绝对路径链接(
/<project>/foo而非/foo) - push 到项目仓 main 分支
- 通知 wiki-portal admin 进入 §5 Pattern A.5 流程(仅做 submodule add,零 ts 改动)
Pattern E 模式(v1.0.1 后)
- fork
qiurui144/docs-template为<project>-docs(public, CC-BY-4.0) - 编辑
wiki/*.md - 在 docs 仓 settings → integrations 安装
wiki-portal-dispatchGitHub App - push main → 自动触发 wiki-portal rebuild
- 0 wiki-portal admin 协调
5. wiki-portal 侧接入 checklist(wiki-portal maintainer)
Pattern A 模式(旧硬编码,仅历史参考)
- 收到项目 maintainer 接入请求 + docs 仓 URL
-
git submodule add <repo URL> external/<project>+git submodule update --init -
docusaurus.config.tsplugins[]加@docusaurus/plugin-content-docsinstance -
docusaurus.config.tsthemeConfig.navbar.items[]加 navbar entry - 新建
sidebars-<project>.ts,列文件 ID - 本地
npm run build验证build/<project>/7+ pages 生成 -
git add . && git commit -m "wiki: integrate <project>"+ push - CI build 通过 + 部署 wiki.attune.com/
<project>/ 可访问 - PR description 说明接入哪个仓 + 哪个分支 + commit SHA
Pattern A.5 模式(当前,5/25 起)
- 收到项目 maintainer 接入请求 + docs 仓 URL
- 确认项目仓 root 已含
wiki.yaml(per §1.5.2 schema) +wiki/*.md -
git submodule add <repo URL> external/<project>+git submodule update --init - 零 ts 改动(
docusaurus.config.ts/sidebars.ts都不动) - 本地
npm run build验证build/<project>/pages 生成 + navbar 多一个 tab -
git add .gitmodules external/<project>+ commit + push - CI build 通过 + 部署
https://wiki.engi-stack.com/<project>/可访问 - PR description 仅说明 submodule pointer commit SHA + wiki.yaml 内容快照
Pattern E 模式(v1.0.1 后)
- 0 改动(前置 5 个槽位 + 5 个 sidebar + GitHub App 安装已就绪)
- 仅监控 wiki-content-update.yml workflow 是否成功
6. 已知反模式
6.1 Pattern A 反模式
- ❌ 项目仓 docs 直接 cp 进 wiki-portal
docs/(应该走external/submodule)- 后果:docs 与代码历史耦合,更新需双仓 commit
- ❌
docusaurus.config.ts写死项目元数据(应该统一从external/<project>/wiki.yaml读取)- 当前 KVM 接入即此反模式(id / label / sidebarPath 全写死在 ts)
- ❌ 每接一个项目改 sidebars 文件名(应该规范化为
sidebars/<project>.ts目录) - ❌ 跨仓 PAT 用 classic(无过期)(应用 fine-grained + 90 天提醒续)
- ❌
.gitmodules用 SSH URL(应用 HTTPS,避免 CI 仅有 token 不能克隆)
6.2 Pattern A.5 反模式
- ❌ wiki.yaml 写在 wiki-portal 仓内(应该在项目 docs 仓 root,wiki-portal 通过 submodule 拉取)— SSOT 错位
- ❌ 手动在
docusaurus.config.ts加 plugin instance(退化回 Pattern A 硬编码) - ❌
.generated/sidebars/进 git(gitignored,每次 build 由 helper 自动生成) - ❌ wiki.yaml 必填字段缺失却 swallow 错误(helper 应该抛 Error 阻断 build)
- ❌ 同一仓内多个 wiki.yaml(每个 git submodule = 1 个 tenant = 1 个 wiki.yaml)
6.3 Pattern E 反模式
- ❌ 复用 docs 仓做代码 mirror(docs 仓只放 markdown + workflow + LICENSE)
- ❌ GitHub App 装到 org 全部仓(应仓粒度安装,仅 docs 仓)
- ❌ dispatch.yml 不 pin
actions/create-github-app-token@<sha>(应 pin SHA 防供应链)
7. 历史版本
| 日期 | 版本 | 变化 |
|---|---|---|
| 2026-05-22 | Phase B (Pattern A 设计) | spec 2026-05-22-wiki-portal-phaseB.md(已废弃,被 Pattern E 取代) |
| 2026-05-25 | Pattern E spec | 2026-05-25-pattern-e-independent-docs-repo.md 718 行落地 |
| 2026-05-25 | Pattern E plan | 2026-05-25-pattern-e-impl.md 1795 行 4.5 day / 12 commit migration |
| 2026-05-25 | KVM 实际接入 commit 0a5c776 | KVM 走到 Pattern E 边缘(docs 仓独立),但 wiki-portal 仍 Pattern A |
| 2026-05-25 | 本文档 v1 | INTEGRATION-GUIDE.md SSOT 首次落档 |
| 2026-05-25 | Pattern A.5 generalize | scripts/load-projects.ts + external/<p>/wiki.yaml 驱动;KVM 接入零 ts 改动验证通过 |