Skip to main content

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. 触发与背景

用户原话(2026-05-25):「wiki 的框架接入规范是否还没有定,KVM 项目想进行接入,但是貌似还需要改动 wiki 的代码,并且建立了分支」

事实校准

  • wiki-portal 当前已有接入规范,体现在 chore/wiki-portal-rebrand 分支 + spec 2026-05-25-pattern-e-independent-docs-repo.md(718 行 11 节齐全)+ plan 2026-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-rebrand ahead master 6 commits
  • external/kvm submodule 已指向 https://github.com/qiurui144/kvm-docs.git branch=main
  • docusaurus.config.ts plugins[] 含 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 已删(commit 97b6344 deinit submodules + commit 2a88f1a rename)— 当前分支仅 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 自行完成):

  1. 项目仓建 docs/wiki/ 子目录,写 markdown 内容(首页 index.md 必须,其余按需)
  2. 文件命名 kebab-case(getting-started.md 而非 GettingStarted.md
  3. 顶部 frontmatter 可选 sidebar_position 控制 sidebar 顺序,无则按文件名字母序
  4. 推到 main 分支

wiki-portal 侧(wiki-portal admin 完成): 5. .gitmodules 加:

[submodule "external/<project>"]
path = external/<project>
url = <项目仓 https URL>
branch = main
  1. git submodule add + git submodule update --init
  2. docusaurus.config.ts plugins[] 数组加 plugin instance:
    ['@docusaurus/plugin-content-docs', {
    id: '<project>',
    path: 'external/<project>/docs/wiki',
    routeBasePath: '<project>',
    sidebarPath: './sidebars-<project>.ts',
    }],
  3. themeConfig.navbar.items[] 加 entry:
    {type: 'docSidebar', sidebarId: '<project>', docsPluginId: '<project>', position: 'left', label: '<Project>'},
  4. 新建 sidebars-<project>.ts,列出 markdown 文件 ID(不含 .md 后缀)
  5. 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):

  1. docs 仓 root 写 wiki.yaml(per §1.5.2 schema)
  2. wiki/ 目录写 markdown(index.md 必须)
  3. 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)

项目侧

  1. 在 GitHub fork qiurui144/docs-template<project>-docs(公开仓,CC-BY-4.0)
  2. 编辑 wiki/index.md
  3. 安装 wiki-portal GitHub App 到 <project>-docs(一次性,App owner 已配置好)
  4. push main → 触发 dispatch.yml → wiki-portal repository_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 Adocs 仓 push → 自动 webhook → 自动重新部署
凭证私有项目仓需 PAT(90 天过期)同 Pattern AGitHub App installation token(不过期)
docs 与代码历史混在项目仓同 Pattern A完全分离
plugin/sidebar SSOT在 wiki-portal ts 内在项目仓 wiki.yaml 内同 Pattern A.5
CI 噪声项目仓 PR 跑全套测试 + docs PR 也跑同 Pattern Adocs 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_position frontmatter 或 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-dispatch GitHub 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.ts plugins[]@docusaurus/plugin-content-docs instance
  • docusaurus.config.ts themeConfig.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-22Phase B (Pattern A 设计)spec 2026-05-22-wiki-portal-phaseB.md(已废弃,被 Pattern E 取代)
2026-05-25Pattern E spec2026-05-25-pattern-e-independent-docs-repo.md 718 行落地
2026-05-25Pattern E plan2026-05-25-pattern-e-impl.md 1795 行 4.5 day / 12 commit migration
2026-05-25KVM 实际接入 commit 0a5c776KVM 走到 Pattern E 边缘(docs 仓独立),但 wiki-portal 仍 Pattern A
2026-05-25本文档 v1INTEGRATION-GUIDE.md SSOT 首次落档
2026-05-25Pattern A.5 generalizescripts/load-projects.ts + external/<p>/wiki.yaml 驱动;KVM 接入零 ts 改动验证通过