在大规模微服务平台中,文档治理往往比架构设计本身更容易失控。Confluence、Notion 等中心化 wiki 工具在团队规模扩大后,很容易出现"文档漂移"(documentation drift)——文档与实际代码脱节,没人确定哪个版本更接近现状。

最近给自己的微服务项目搭文档站,选了 Docs-as-Code 这条路——文档和代码放同一个仓库,每个服务维护自己的 /docs/,最后用 Docusaurus 聚合成一个统一的门户。

这种模式和 Domain-aligned multi-repo 架构(每个 domain 有独立的 MS/BFF/consumer)比较契合:service owner 维护自己的 ADR 和设计文档,文档也更贴近代码;同时再通过 Docusaurus 提供统一入口。它和 Team Topologies 里 Stream-Aligned Team 的自治原则也比较一致。

这篇文章整理的是一套目前可落地的方案:组织结构、各服务 /docs/ 内容规范、Docusaurus 聚合机制、ADR 落地,以及我调研时看到的几种开源方案。

整体架构:三种仓库角色#

在多仓库微服务平台中,文档体系涉及三种仓库角色:

graph TD A["platform-architecture
中央架构仓库"] -->|聚合| B["platform-docs
Docusaurus 统一文档站"] C["MS repo"] -->|/docs/| B D["BFF repo"] -->|/docs/| B E["Consumer repo"] -->|/docs/| B

三种仓库的职责分工:

仓库类型 示例 文档职责
中央架构仓库 platform-architecture 全局架构概览、跨域决策、平台级 ADR、共享关注点(Kafka/Redis/Observability)
服务仓库 order-msuser-bff 服务内部设计、服务级 ADR、API contract、Kafka 事件 schema、数据库 schema
Docusaurus 文档站仓库 platform-docs 聚合所有来源的 Markdown,构建统一文档站(部署到 Vercel/Netlify)

这种分工的关键好处是:service owner 只需要维护自己 repo 的 /docs/,平台团队负责聚合和样式一致性。文档不一定会自动变好,但至少更不容易和代码长期脱节。

部署选项:中央架构仓库与文档站是否合并#

上面画的是三种仓库的逻辑角色。实际部署时,中央架构仓库和 Docusaurus 文档站仓库可以选择合并为一个 repo,也可以分开。这是两种常见的部署策略:

选项 A:分开两个 repo(我目前更常想到的起点)#

中央架构仓库(platform-architecture)和文档站仓库(platform-docs)独立存在,platform-docs 通过 docusaurus-plugin-remote-content 或 CI 同步脚本从 platform-architecture 拉取文档。

适用场景:架构文档的审阅者和文档站的技术栈维护者是不同的人/团队。平台团队可以独立演进 Docusaurus 版本、主题、插件,不影响架构文档本身。

选项 B:合并为一个 repo(更适合小团队)#

把 Docusaurus 项目直接放进中央架构仓库,两者共用一个 repo。文档源就是 Docusaurus 的 docs/ 目录,不需要额外的远程拉取或同步脚本。

platform-architecture/
├── docs/                          # Docusaurus 文档源(就是中央架构文档本身)
│   ├── overall/
│   ├── adrs/
│   ├── cross-cutting/
│   └── services/                  # 从各服务 repo 聚合来的文档(CI 同步)
├── docusaurus.config.ts           # Docusaurus 配置
├── sidebars.js
├── package.json
├── src/                           # Docusaurus 自定义组件(如有)
├── README.md
└── .github/workflows/
    └── deploy.yml                 # PR Preview + Vercel/Netlify 部署

这种布局下,docs/overall/docs/adrs/docs/cross-cutting/ 本身就是仓库的固有内容,不需要"远程拉取"。只有 docs/services/ 目录需要通过 CI 从各服务仓库同步过来。

适用场景:小团队或单人项目,架构文档和文档站维护者是同一人,不需要区分两个 repo 的权限边界。CI 流程更简单——一次 push 就能同时更新文档内容和触发站点 rebuild。

两种选项的核心区别只在于中央架构文档是否需要被"拉取"到另一个 repo 才能构建。服务仓库的 /docs/ 规范、聚合机制、ADR 流程完全一样。

中央架构仓库的内容组织#

中央架构仓库(例如 platform-architecture)存放跨域文档和平台级决策。下面这套目录布局更适合作为起点:

platform-architecture/
├── docs/
│   ├── overall/              # 总体架构
│   │   ├── architecture-overview.md
│   │   ├── domain-ownership.md
│   │   ├── glossary.md
│   │   └── request-lifecycle.md
│   ├── adrs/                 # 全局 ADR(平台级决策)
│   │   ├── 0001-use-oceanbase-per-domain.md
│   │   ├── 0002-kafka-outbox-pattern.md
│   │   └── template.md
│   ├── cross-cutting/        # 共享关注点
│   │   ├── kafka-guidelines.md
│   │   ├── redis-guidelines.md
│   │   ├── observability.md
│   │   └── security.md
│   └── sidebar.js            # 全局侧边栏配置片段
├── README.md
└── .github/workflows/        # 可选:触发 docs 站 rebuild 的 dispatch

这个仓库的内容包括:

  • 架构概览:C4 Model 的 System Context 和 Container 级别图,描述所有 domain 的边界和交互
  • Domain 归属:每个业务域归哪个团队负责、SLO 目标是什么
  • 平台级 ADR:影响全局的架构决策(例如"每个 domain 使用独立 OceanBase 实例"、“跨域通信统一使用 Kafka outbox pattern”)
  • 共享关注点:Kafka 使用规范、Redis key namespace 策略、Observability 平台接入、安全基线

服务仓库的 /docs/ 目录规范#

每个服务仓库(无论是 *-ms*-bff、还是抽离的 *-mc)的 /docs/ 目录,如果能尽量遵循一套相对统一的结构,会更方便 service owner 维护,也更有利于 Docusaurus 聚合后形成一致、可搜索的统一文档站。

一套可参考的 /docs/ 目录结构#

docs/
├── index.md                          # 服务概览入口(必须)
├── architecture.md                   # 整体架构设计(C4 图、数据流)
├── adrs/                             # 架构决策记录(必须,每项决策一个文件)
│   ├── 0001-transactional-outbox.md
│   ├── 0002-oceanbase-schema-design.md
│   └── template.md                   # 复制模板用
├── api/                              # API 相关
│   └── endpoints.md                  # 关键端点说明 + 使用示例 + OpenAPI 文档入口
├── kafka/                            # 事件相关(MS 和 mc 必备)
│   ├── published-events.md           # 本服务发布的事件 schema + 版本
│   ├── subscribed-topics.md          # 订阅的 topic + 处理逻辑
│   └── consumer-groups.md            # consumer group 配置与 scaling
├── database/                         # 数据层(仅 MS)
│   ├── schema-overview.md
│   ├── liquibase-strategy.md
│   └── key-tables.md
├── bff-specific/                     # 仅 Player/Backoffice BFF 需要
│   ├── aggregation-logic.md
│   ├── mobile-optimization.md        # Player BFF 专用
│   └── bulk-operations.md            # Backoffice BFF 专用
├── dependencies.md                   # 外部依赖与调用关系
├── observability.md                  # 监控、日志、tracing 配置
├── deployment.md                     # K8s manifests、scaling、SLO
├── troubleshooting.md                # 常见问题 & 排查指南
├── diagrams/                         # 存放 Mermaid / PlantUML 源文件(可选)
└── _category_.json                   # Docusaurus 侧边栏元数据(推荐)

每个核心文件应该包含的内容#

index.md(服务首页,必备)#

服务概览入口,包含:

  • 服务全称、owner/team(GitHub CODEOWNERS 对应)
  • 简短职责描述(一句话对齐业务域)
  • 关键指标:SLO、吞吐目标、延迟 P99
  • 在整体架构中的位置(简短链接到中央架构 repo)
  • 快速导航到其他文档 section

示例结构:

# order-ms

- **Owner**: Order Team ([CODEOWNERS](./CODEOWNERS))
- **职责**: Order domain 的核心业务逻辑、数据持久化、事件发布
- **SLO**: 99.9% availability, P99 latency < 200ms
- **架构位置**: 参见 [Domain Ownership](link-to-central-arch)

## 快速导航

- [架构设计](./architecture.md)
- [ADR 决策记录](./adrs/)
- [API contract](./api/)
- [Kafka 事件](./kafka/)

architecture.md#

  • C4 Model 图:Context → Container → Component 级别(用 Mermaid 绘制)
  • 数据流与调用链(Frontend → BFF → 本 MS → 其他 MS / Foundation Engine)
  • 关键技术栈(Java 25 + Spring Boot 3.5 / Golang、高性能点如 WebFlux)
  • 与统一认证中心的集成方式(不同 auth context、权限传递)

Docusaurus 原生支持 Mermaid,可以直接在 Markdown 中绘制:

```mermaid
graph TD
    A[Frontend BFF] -->|HTTP/gRPC| B[Order MS]
    B -->|Kafka| C[Loyalty MS]
    B -->|Kafka| D[Wallet MS]
    B -->|Read| E[(OceanBase)]
```

adrs/(我更倾向采用 MADR 模板)#

每份 ADR 记录一次架构决策,采用 MADR(Markdown Architectural Decision Records)标准格式:

# ADR-0001: Use Transactional Outbox for Cross-Domain Events

## Status
Accepted

## Context
跨域事件需要保证与本地事务的一致性...

## Decision
采用 Transactional Outbox pattern,通过 Debezium CDC 同步到 Kafka...

## Alternatives
- 双写模式(应用层同时写 DB 和 Kafka)
- 事件溯源(Event Sourcing)

## Consequences
- 好处:保证 exactly-once 语义
- 代价:需要维护 outbox 表 + Debezium connector

如果团队愿意把 ADR 检查放进 PR 模板,涉及架构变更的 PR 就可以在 docs/adrs/ 下新增或更新 ADR。这更符合 You Build It You Run It 的思路,也更有助于减少文档漂移。

api/ 与 kafka/(高性能系统关键)#

api/ 目录:

  • OpenAPI 规范 + 关键端点语义、请求/响应示例、版本兼容策略
  • contract library 使用说明

kafka/ 目录:

  • 事件 schema(Avro/JSON Schema)、exactly-once 保证
  • dead-letter 策略、replay 机制
  • consumer group 配置与 scaling 策略

特别适合 payment/ecommerce 场景:强调幂等性、事务边界、补偿机制。

database/(仅 Domain MS)#

  • Schema 演进策略(例如 Liquibase 的演进约定)
  • 数据所有权边界(只写本域表)
  • 快照/denormalization 策略(通过 Kafka 事件维护)

dependencies.md#

  • 上游/下游服务调用列表(只允许 upper → foundation)
  • 同步调用(Feign / RestClient)与异步(Kafka)比例
  • 电路熔断、重试、bulkhead 配置(Resilience4j / Golang 对应库)

observability.md#

  • OpenTelemetry 配置、指标暴露、日志结构、tracing 采样率
  • 告警规则与 SLO 定义(与平台团队对齐)

deployment.md(K8s / Cloud Native 重点)#

  • Deployment / HPA / PDB 配置
  • 资源请求与 limit(高性能调优经验)
  • 滚动更新策略、canary 发布

不同服务类型的侧重点#

服务类型 示例 侧重内容
Domain MS order-msuser-ms business rules、transaction boundaries、data ownership、Kafka in/out
Frontend BFF frontend-bff mobile latency optimization、response shaping、caching 策略、trusted headers 处理
Backoffice BFF backoffice-bff bulk operations、search/query optimization、admin audit logging、异步 job 导出
Standalone Consumer *-mc scaling 原因、独立 consumer group、处理吞吐、错误重试与 dead-letter 机制
Foundation Engine wallet-ms one-way dependency 严格执行、底层性能特性(R2DBC 等)

Docusaurus 统一文档站#

platform-docs 是一个独立的 Docusaurus 3.x 项目,可以部署在 Vercel 或 Netlify(支持 PR Preview)。它的核心任务是聚合所有来源的 Markdown,形成统一、可搜索的文档门户。

docusaurus.config.ts 核心配置#

// docusaurus.config.ts
import { themes } from 'prism-react-renderer';

export default {
  title: '平台架构文档站',
  url: 'https://example.com',
  baseUrl: '/',
  presets: [['@docusaurus/preset-classic', {}]],
  plugins: [
    // 1. 中央架构文档(本地)
    [
      '@docusaurus/plugin-content-docs',
      {
        id: 'overall',
        path: 'docs/overall',
        routeBasePath: '/overall',
        sidebarPath: require.resolve('./sidebars/overall.js'),
      },
    ],
    // 2. 全局 ADR
    [
      '@docusaurus/plugin-content-docs',
      {
        id: 'adrs',
        path: 'docs/adrs',
        routeBasePath: '/adrs',
        sidebarPath: require.resolve('./sidebars/adrs.js'),
      },
    ],
    // 3. 服务级文档(远程聚合)
    [
      'docusaurus-plugin-remote-content',
      {
        sources: [
          {
            name: 'order-ms',
            url: 'RAW_ORDER_MS_DOCS_URL',
            pattern: '**/*.md',
          },
          {
            name: 'frontend-bff',
            url: 'RAW_FRONTEND_BFF_DOCS_URL',
            pattern: '**/*.md',
          },
          // ... 所有 domain 服务(可通过 repositories.json 动态加载)
        ],
        destination: 'docs/services',
      },
    ],
  ],
  themeConfig: {
    prism: { theme: themes.github, darkTheme: themes.dracula },
    navbar: {
      title: 'Platform Docs',
      items: [
        { to: '/overall/intro', label: '总体架构', position: 'left' },
        { to: '/adrs/global', label: 'ADR 决策', position: 'left' },
        { to: '/services', label: '服务文档', position: 'left' },
      ],
    },
  },
};

侧边栏配置(sidebars.js)#

// sidebars/main.js
module.exports = {
  main: [
    { type: 'doc', id: 'overall/intro' },
    {
      type: 'category',
      label: '业务域',
      items: [
        {
          type: 'category',
          label: 'Order',
          items: [
            'services/order-ms/index',
            'services/order-ms/architecture',
            'services/frontend-bff/index',
          ],
        },
        // ... 动态生成
      ],
    },
    {
      type: 'category',
      label: 'ADR 决策记录',
      items: ['adrs/global', 'services/*/adrs/**'],
    },
  ],
};

聚合机制方案对比#

我调研时最常见的三种方案:

方案 A(我目前更倾向):docusaurus-plugin-remote-content

  • 专为 multi-repo 设计,已被广泛用于微服务文档聚合
  • 在 docusaurus build 前自动从各 repo raw URL 下载最新 MD 文件
  • 支持 pattern 过滤、缓存
  • 社区里资料相对多,便于快速起步

方案 B(更强 CI 控制):GitHub Actions 同步脚本

  • 每个服务 PR 合并后,通过 repository_dispatch 触发 platform-docs rebuild
  • clone 所有 /docs/ 到临时目录,再 yarn build
  • 完整控制流程,适合对安全性要求高的组织

方案 C:Docusaurus 多实例(multi-instance)+ 自定义 preset

  • 实现 overall / services 分离但统一导航
  • 适合大型组织需要严格隔离文档源的场景

对多数团队来说,方案 A 往往是上手成本最低的选择。如果已经有比较完善的 CI/CD 基础设施,方案 B 会给你更多可控性。

CI/CD & 治理机制#

文档治理不只是写 Markdown,更需要一套 GitOps 风格的自动化流程。

GitOps 工作流#

sequenceDiagram participant Dev as Developer participant SR as Service Repo participant CI as GitHub Actions participant PD as platform-docs Repo participant Vercel as Vercel Dev->>SR: PR 更新 repo/docs/ SR->>SR: PR 模板检查 ADR SR->>SR: 合并到 main SR-->>CI: repository_dispatch CI->>PD: 触发 rebuild PD->>Vercel: 构建部署预览 Vercel-->>SR: PR 评论贴 Preview URL PD->>PD: PR Review → 合并 → 自动部署

关键环节:

  1. PR 模板强制检查:每个服务仓库的 PR 模板包含 checklist

    • 更新了 docs/adrs/ 吗?
    • index.md 是否反映了变更?
    • API 变更是否同步了 openapi.yaml
  2. GitHub Actions 触发链:服务 repo 合并 → repository_dispatchplatform-docs rebuild

  3. Vercel Preview:文档站每次 build 生成预览 URL,贴在 PR 评论中供 review

服务 Owner 与平台团队的责任边界#

角色 责任
Service Owner 维护自己 repo 的 /docs/(内容准确性、ADR、架构图)
Platform Team 维护 platform-docs 和同步 workflow、样式一致性、搜索/版本化基础设施
架构团队 维护中央架构仓库(跨域文档、平台级 ADR)

这种分工能保留 service owner 的自治性,同时让文档更容易跟随代码更新、支持版本控制和 PR review,也减少了手工复制的成本。

ADR 机制详解#

ADR(Architectural Decision Record)是文档治理的核心构件。它记录的不仅仅是"最终决定",而是决策的上下文、备选方案和后果。

MADR 模板#

采用 MADR(Markdown Architectural Decision Records)标准模板:

# ADR-NNNN: 决策标题

## Status
Proposed | Accepted | Deprecated | Superseded

## Context
描述做出这个决策的背景信息。包括技术约束、业务需求、现有方案的问题等。

## Decision
清晰描述做出的决策。用简洁的语言说明选择了什么方案。

## Alternatives
列出考虑过的备选方案,以及为什么没有选择它们。

- 备选方案 1:描述 + 不选原因
- 备选方案 2:描述 + 不选原因

## Consequences
这个决策带来的影响(正面和负面)。

- 正面:...
- 负面:...

## Related
- 相关的 ADR 链接
- 相关文档链接

ADR 编号策略#

两种常见方式:

  • 全局唯一编号(e.g. ADR-001):适合平台级决策,所有服务共享编号空间
  • Per-Service 编号(e.g. player-ms/ADR-001):适合服务内部决策,每个服务独立编号

按我目前的理解,混合模式会更顺手:中央架构仓库用全局编号,各服务仓库用 per-service 编号。Docusaurus 中统一展示为可搜索列表 + 状态标签(Proposed / Accepted / Deprecated)。

PR 强制检查#

.github/PULL_REQUEST_TEMPLATE.md 中添加:

## 文档更新检查

- [ ] 本次变更是否需要在 `docs/adrs/` 中新增/更新 ADR?
- [ ] `docs/index.md` 是否反映了最新的服务状态?
- [ ] API/Kafka schema 变更是否已同步 `docs/api/``docs/kafka/`

这确保了文档更新不是"有空再做"的可选事项,而是 PR 合入的前置条件。

2026 年开源项目与公司实践#

开源插件与工具#

ADR 标准与工具#

其他方案对比#

  • Antora:专为 multi-repo 文档设计的静态站生成器,支持多仓库聚合、版本化管理。缺点是使用 AsciiDoc 而非 Markdown,如果你已经是 Markdown 生态(Docusaurus),切换成本较高。
  • Backstage TechDocs:Spotify 开源的 Service Catalog + TechDocs 平台,适合大型组织需要 Service Registry 的场景。如果你只需要轻量文档站而不需要完整的 Service Catalog,Docusaurus 更简单直接。

作为架构 Leader 的落地建议#

如果你正在带领一个 Java/Spring Boot + Golang + K8s 团队尝试这套文档治理体系:

  1. 在服务脚手架中内置 /docs/ 模板:用 cookiecutter 或自定义 Maven archetype,直接内置 /docs/ 目录结构 + ADR template.md。让每个新服务开箱即用。

  2. GitHub PR 模板增加 checklist:“更新了 docs/adrs/ 吗?index.md 是否反映了变更?“让文档更新成为 PR 流程的一部分,而不是额外的负担。

  3. Platform Team 提供统一规范:统一的 _category_.json 和 Mermaid 样式规范,确保聚合后视觉一致。

  4. 高性能系统额外关注:Kafka 事件 schema 演进策略(向后兼容)、Redis key 命名空间隔离文档、OceanBase 索引/分区调优记录。

  5. 搜索与 AI:接入 Algolia DocSearch v4(Docusaurus 3.9+ 原生支持 AI Ask 功能,2025 年已成熟)。

  6. 版本化:Docusaurus 内置 versioning,可按 domain 或全局版本。

总结#

对采用 Domain-aligned multi-repo 的团队来说,“中央架构 Repo + 各服务 Repo 内 /docs/ 目录 + Docusaurus 统一站"是一条值得尝试的组合。至少在我的实践里,它有这些比较明确的好处:

  • 文档与代码更贴近:至少更容易让文档跟随代码一起变更,减少“过时 wiki 页面”
  • Service Owner 自治:每个团队只负责自己的 /docs/,不需要去维护中心化 wiki
  • 统一入口:Docusaurus 聚合所有文档,形成可搜索、可版本化的单一真相来源
  • 减少手工复制成本:Git 驱动、PR review、CI 自动 build,把重复劳动压到更少
  • 避免文档漂移:PR 模板强制检查 ADR 更新,文档变更是代码变更的一部分

对于采用 Domain-aligned multi-repo 架构的团队,文档站有机会逐渐变成一个相对稳定的架构入口——新成员 onboarding、跨团队协作、故障排查、架构 review,都能先从这里开始。