📚

生成AI時代の Docs as & with Code の実践 ~ プロダクト開発の全活動データのSSoT化

に公開

東芝 Advent Calendar 2025 3日目の記事です。

(株)東芝で "CCoE" という略称の部門を担当し、クラウドの活用推進や共通基盤的な社内サービスの企画・開発の旗振り役をしています。趣味で暗号系のライブラリ (hpke-js, pyseto など) を OSS として開発・メンテしたりしています。

はじめに

複数の開発プロジェクトを同時に見ている関係で、開発だけでなくプロジェクト管理を含めて、プロダクト開発のライフサイクル全般を生成AIで効率化したいと常々考えています。

試みの1つとして、生成AIがプロジェクト情報を最大限・効率的に活用できるよう、プロダクト開発のあらゆる活動とその成果物 (ソースコード、ドキュメント) の管理を単一の Git リポジトリで完結させる = SSoT (Single Source of Truth) 化する取り組み を行っています。徐々にですが、共通項をテンプレート (pj-template) として複数のプロジェクトに展開しつつあります。

本記事では、この pj-template の「ドキュメント管理」面にフォーカスして紹介します。昨今、ソフトウェア開発において「Docs as Code」の考え方は一般的になっている気がしますが、ここに少し踏み込んで、以下の4つの話題について、具体的な実践事例を共有します。

  1. プロダクト開発にまつわる多様なドキュメント群を収容するモノレポ構成
    • 企画書からはじまる様々な非公開の開発文書、ユーザ向けの公開文書、ドキュメントサイト実装を含むソースコードや各種設定をどうモノレポ構成に落とし込むか?
  2. セキュリティを考慮した公開文書のドキュメントサイト化
    • markdown 形式の公開文書のWebサイト化と、テンプレート展開するにあたり、セキュリティやコンプライアンス面をどうケアするか?
  3. ツールセットと規約によるドキュメンテーションの統制
    • 生成AI活用を見据えた markdown 形式でのドキュメンテーション推進にあたり、テンプレート上でどのような統制をかけるか?
  4. Docs with Code なモノレポ構成における CI/CD
    • ソフトウェアとドキュメントを共存させるモノレポにおいて CI/CD でやるべきことは? (ソフトウェア開発を邪魔しないドキュメント only な CI/CD パイプラインなど)

以下、pj-template の概念図です。pj-template の何たるかは上記4項に対応する各章で概ねカバーされますが、図中の (プロダクト開発の)「諸活動データ」については、末尾の「生成AI時代のプロジェクト管理基盤」を参照ください。

overview

予め言及しておくと、詳細パートで言及される技術・ツールは、DocusaurusTrivyremarkmarkdownlintGitLab CI/CD (pages, workflow, rules, etc.)Changesets 等です。

―― タイトルについて。「Docs as Code」は、ドキュメントをコードと同じツール・プロセスで扱う考え方・手法のことです。エディタを使ってプレーンテキスト (markdown等) でドキュメントを書き、Gitで構成管理し、PR (MR) でレビュー、CI/CD で自動ビルド・テスト・デプロイを行うような話です。「Docs with Code」は「Keep "docs with code" in version control(ドキュメントをコードと同じリポジトリに置こう)」ぐらいの意。「Docs as Code」に暗に含まれる気もしますが、生成AI活用の視点で強調し「Docs as & with Code」としてみた次第です。

前提 - GitLab セルフホスト環境

実は東芝は、GitLab を大規模にセルフホストし、社内の開発プロジェクトで活用しています[1][2]。事業部や技術部門単位でクローズドに利用できる個別環境だけでなく、InnerSource の公開用の共用環境も整備されており、数千人規模の開発者が日々利用しています。

本記事の取り組みも、この東芝の GitLab 環境上で共用されることを前提としたものです。したがって Git リポジトリとは GitLab リポジトリであり、例示する CI/CD パイプライン も GitLab の流儀 (.gitlab-ci.yml) です (GitHub な方々は、適宜読み換えてください) 。

pj-template リポジトリの構成

本題に入りますが、pj-template の主要な部分をピックアップしたディレクトリ構成は以下のとおりです。ポイントは、まず docs/srcs/ (微妙ですが src/ が複数ってことで) 。コードとドキュメントをモノレポ構成で管理します。テンプレートには デフォルトで srcs/pages が組み込まれており、これが Docusaurus ベースのドキュメントサイト実装です。

.
├── .changeset/           # リリースノートに記載する変更履歴管理
├── .gitlab/
│   └── issue_templates   # プロジェクト管理に必要な様々な Issue テンプレート
├── .gitlab-ci.yml        # CI/CD 設定
├── CHANGELOG.md          # @pj-template/base のリリースノート (変更履歴)
├── CONTRIBUTING.md       # コーディング規約、ドキュメンテーション規約の文章はココ
├── .prettierrc           # コーディング規約の一部 (prettier 設定)
├── eslint.config.js      # コーディング規約の一部 (eslint 設定)
├── .markdownlint.jsonc   # ドキュメンテーション規約の一部 (markdownlint-cli2 設定)
├── package.json          # ドキュメンテーション規約の一部 (remark-cli 設定)
├── LICENSE               # ★ Toshiba InnerSource License 2.1 ★
├── docs/       # ドキュメント用ディレクトリ
│   └── ...               # **後述**
└── srcs/       # ソースコード用ディレクトリ (普通は packages/ だがちょっと抵抗感あり..)
    └── pages/            # ドキュメントサイト実装
        ├── CHANGELOG.md  # @pj-template/pages のリリースノート (変更履歴)
        ├── package.json
        └── docs/
            ├── guides/
            │   └── _category_.json
            └── specs/
                └── _category_.json

プロダクト開発にまつわるドキュメントテンプレート群

プロダクト開発にまつわるあらゆる文書を管理する docs/ は、以下の構成になっています。まずprivate/public/ があり、非公開・公開をディレクトリレベルで分離しています。

├── docs/
│   ├── private/          # 非公開文書
│   │   ├── development/  # 開発関連文書
│   │   ├── forms/        # 帳票類
│   │   └── misc/         # その他の参考文書
│   └── public/           # 公開文書
│       ├── intro.md      # プロダクトのカタログ的概要説明文書
│       ├── guides/       # マニュアル文書
│       └── specs/        # 規約・仕様書

非公開・公開それぞれに含まれるドキュメントの種別と概要は以下の通りです。

非公開文書

プロダクト開発に係るドキュメントは、当然ながら大半は利用者に公開するものではなく、非公開文書です。多くは社内の開発プロセス標準上必要な文書を markdown 化したものです。

  • private/development
    • プロダクト開発関連文書 (構想企画書、要件定義書、基本設計書など、10以上ある) が、markdown形式の文書テンプレートとして含まれてます。例えば、構想企画書のテンプレートは、リーンキャンバス をベースに作り、コンセプト、想定顧客や売り(代替品との違い)、コストに見合うか等、企画の採択判断に足る情報をしっかり書かせるものになっています。プロジェクトのはじまりの最上流の文書から、ソースコードも入れる Git リポジトリで一緒に管理していくところが、この試みのポイントかなと思っています。
  • private/forms
    • 社内の開発プロセス標準への準拠、法令遵守のためのチェックシート等の帳票類が含まれています。現時点では xlsx シートが多かったりします。
  • private/misc
    • なんだかんだとプロダクトを紹介するpptx資料や、利用する外部SaaSのカタログ資料、技術選定時の評価報告など、関連文書は増えていきます。markdown でないことも多いこれらの文書は、リポジトリ肥大化回避のため、別の兄弟リポジトリに逃がすのも手ですが、重要なものはこのディレクトリで管理します。

公開文書

端的に言えば、ユーザ向けのドキュメントです。次節で述べるドキュメントサイトで公開されるドキュメント群が公開文書に位置づけられます。

  • public/intro.md
    • ユーザ向けに公開するイントロダクション文書。このプロダクトは何か?なぜ必要か?既存プロダクトとの違いは何か?等を記すカタログ的な文書です。構想企画書とセットで最初期から書いてみるべきものとしてテンプレート化しています。
  • public/guides
    • ユーザ向けの利用マニュアル (典型的には Getting Started など) やガイドが含まれています。プロダクトによって大きく変わってきますので、現状ではテンプレート化はしていません。
  • public/specs
    • サービス仕様書や利用規約、プライバシーポリシーといったユーザ向けに公開すべき規約文書や仕様書のmarkdown形式のテンプレートが含まれています。

公開文書としては、他にも API 仕様書などが含まれるでしょうが、プロダクトの形態に大きく依存しますので、テンプレートには含めていません。

公開文書のドキュメントサイト化

前述したように srcs/pages に Docusaurus ベースのドキュメントサイト実装が含まれています。これが、ドキュメントのCI/CDパイプライン を通じてビルドされ、GitLab Pages で公開されます。リリース時には、冒頭に掲げた概念図に示すように、共用環境の GitLab リポジトリにミラーリングされ、公開環境にドキュメンテーションサイトが展開されるようになっています。

デフォルトでは以下のようなサイトが立ち上がります。デザインは、Docusaurus の素のテンプレに近いですが、色々そぎ落としつつ、全文検索機能等、有用な機能を追加したりしています。

pj-template overview

なお、ディレクトリ構成 にあるように srcs/pages/docs 以下が、docs/public のミラーになっています。サイトのビルド時には、docs/public 以下の markdown ファイルや画像ファイルが srcs/pages/docsに展開されます。

ドキュメントサイトのカスタマイズ開発・表示確認用に以下の Package Script を用意していて、CI/CDでもこれらが実行されます。

# ドキュメントサイトの `npm ci`
npm run pages:ci

# ドキュメントサイトをビルドする
npm run pages:build

# ドキュメントサイトの ローカル開発サーバを起動する
npm run pages:start

# ./docs のドキュメントを ドキュメントサイト (./srcs/pages/docs) に取り込む
# ローカル開発サーバ起動中、このスクリプトの実行によって ./docs の変更が取り込まれる
# build、start スクリプト内部では、最初に sync が実行される
npm run pages:sync

# ドキュメントサイト (./srcs/pages/docs) のドキュメントを全て削除する
# sync スクリプト内部では、最初に clean が実行される
npm run pages:clean

セキュリティの考慮

サプライチェーンセキュリティ重要です。Meta 社が保守する Docusaurus で滅多なことは起こらないと思いますが、プラグイン (全文検索等) も使ってますし、テンプレとして社内に広く展開する際の影響も鑑み、このドキュメントサイト実装に対して、CI 上で Trivy を用いた依存関係、脆弱性、ライセンスのスキャンを行っています (Trivy は OSS のセキュリティ・スキャナー)。

同時に、スキャン結果を複数フォーマット (CycloneDX、SPDX) の SBOM、及びライセンスレポートとして出力し、CI/CD のパイプライン実行結果としてダウンロードできるようにもしています。

ドキュメンテーションの統制

pj-template には、当然ながら markdown のリンタ・フォーマッタを組み込んでおり、かつ、規約文書も pj-template 内に記載しておくことで、緩やかな品質の統制を図っています。

ツールセット(フォーマッタ・リンタ)

現状、markdown ファイルのフォーマッタ・リンタとしては、以下の2つを併用しています。

markdownlint(-cli2) をベースとして使いつつ、TOC の自動生成、テーブル自動整形 (の個人的好み) frontmatter 対応など幾つかの理由から remark(-cli) も利用している状況です (正直、あまり満足しているわけではなく、eslint のmarkdown 機能なども評価したいし、要改善と思っている)。

pj-template としては、なるべくデフォルト設定のまま使うようにしており、カスタマイズしたければ、プロジェクト側でしてくれというスタンスを取っています。が、やはりいかんともしがたいところがあり、多少のルールの無効化はしています (具体的な設定は Appendix 参照)。

ドキュメントサイトと同様、こちらも Package Script を用意しています。本記事では触れませんが、Docusaurus ベースの実装を組み込んでいる関係で、TypeScript/JavaScript 関連のリンタ・フォーマッタ、及びコーディング規約も、ドキュメントと同様に pj-template に組み込んでいます。

# ドキュメント、ソースコード双方に対し、それぞれの規約に則っているかをチェックする。
# 問題がある場合には警告・エラーが出力される。 
npm run check
npm run check:doc  # ドキュメントのみ
npm run check:code # コードのみ

# ドキュメント、ソースコード双方に対し、それぞれの規約に則る整形を可能な範囲で施す。
npm run fmt
npm run fmt:doc  # ドキュメントのみ
npm run fmt:code # コードのみ

将来的には、markdown のフォーマット&リントにとどまらず、textlint を導入し、共通語彙・頻出語彙の表記ゆれ矯正なども検討できるといいなと思っています。

規約文書

ドキュメンテーションの規約は、フォーマッタ・リンタの導入だけでは済まないので、CONTRIBUTING.md 内に「ドキュメンテーション規約」の節を設けて規約文書化しています。

規約文書には、例えば以下のような内容を記載しています。

  • フォーマット: 基本的にmarkdown形式で書くべし云々。
  • フォーマッタ・リンタ: 採用しているツール(前述)の説明、それぞれの設定の説明。
  • ドキュメントの管理場所: 上記のdocsディレクトリの説明に近い。何をどこに置くか。
  • 日本語: 常体(である調)と敬体(ですます調)の使い分け。公開文書は敬体、非公開文書は常体、など。
  • 規約への準拠の方法: Package Script を利用した自動整形・チェックの手順説明や、Index の作成方法の説明など。

これらをテンプレートに組み込んでおくことで、一応ガードレールとして機能する規約のベースラインにはなります。最低限の記述に留め、適宜プロジェクト側で補強してもらえばよいというスタンスです。

Docs with Code のための CI/CD

一般的だと思いますが、pj-template でもドキュメンテーション作業が純粋なソフトウェア開発 (コード変更) に干渉しないような工夫を入れたり、ワンクリックで一連のリリース作業が自動実行されるようにしていたりもしています。このあたりの CI/CDパイプラインについても一事例として紹介します。

DOCS_ONLY パイプライン

markdownファイルだけを更新するのに、プロダクトのテストやビルドが何十分何時間も回ってしまう事態は避けるべきなので、DOCS_ONLY なパイプラインを組んでいます。

以下、変更されたファイル群が DOCS_ONLY か否かを判定する設定の例 (・・GitHub だと、paths-ignoreでスッキリ書けるのですが、GitLab だと酷くまどろっこしくなってしまう・・)

# ドキュメントの定義。markdown だけでなく、microsoftなファイル、画像も
.docs_paths: &DOCS_PATHS
  - '**/*.{md,mdx}'
  - '**/*.{docx,pptx,xlsx,txt}'
  - '**/*.{ico,svg,svgz,png,jpg,jpeg,gif,webp,woff,woff2}'

# ソースコードの定義。デフォルトで、ビルトインの Docusaurus (TypeSript/JavaScript) で
# 使われているものを中心に、設定ファイル系も。
.code_paths: &CODE_PATHS
  - '**/*.{ts,tsx,js,jsx,mjs,cjs,json,jsonc,xml,yml,yaml,css,scss,html}'
  # ... 他にも.gitignore 等、単発ファイル含めて色々あるが省略

# 上記の定義を用いた DOCS_ONLY 判定ワークフロー
workflow:
  rules:
    - changes: *CODE_PATHS
      when: always
      variables:
        DOCS_ONLY: 'false'
    - changes: *DOCS_PATHS
      when: always
      variables:
        DOCS_ONLY: 'true'
    - when: always
      variables:
        DOCS_ONLY: 'false'

# コード変更の有無にかかわらず実行するジョブのためルール
# (ドキュメント変更時に実行したいジョブに適用する)
.rules_dev: &RULES_DEV
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: never
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

# コード変更時にのみ実行するジョブのためのルール
# (DOCS_ONLY=true の場合にはCIでの自動実行がスキップされる。必要に応じて手動実行できる)
.rules_dev_code: &RULES_DEV_CODE
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: never
    - if: $DOCS_ONLY == "true"
      when: manual
      allow_failure: true
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

このルール定義を使い、例えば、DOCS_ONLY=true でも走る (常に走る) ジョブは以下のようになっています。

# ドキュメンテーション規約準拠チェック
test:docs:
  stage: test
  <<: *RULES_DEV
  before_script:
    - *BEFORE_SCRIPT_SETUP_NPM
  script:
    - npm run check:doc

# ドキュメントサイトのビルド
build:pages:
  stage: build
  extends:
  <<: *RULES_DEV
  before_script:
    - *BEFORE_SCRIPT_SETUP_NPM
  script:
    - npm run pages:ci
    - npm run pages:build
    - mv srcs/pages/build public
  artifacts:
    paths:
      - public

ややこしいですが、逆に <<: *RULES_DEV_CODE を extends に噛ませたものが、DOCS_ONLY=true では自動実行されないジョブであり、典型的にはコーディング規約準拠チェックや、実装のテスト、実装の脆弱性やライセンスチェックが該当します。

例えば、markdown ファイルのみを変更した場合の pj-template の CI/CD パイプラインは以下のようになっています (test:codetest:license というコーディング系のジョブが手動実行になっている = 自動実行がスキップされている)。

pipeline

ドキュメントサイト公開の自動化

続いて、上記パイプラインの一番右の release:bump-version ▶ について説明します。この再生ボタンをクリックすると、バージョンアップの MR (Merge Request) が Changesets ボットによって作成され、その MR をレビュー・承認の上、マージすると一連のリリース作業が自動実行されるようになっています。その中でドキュメントサイトの公開処理 (公開用ミラーリポジトリへの同期によるデプロイ) も行われる流れです。

以下、Changesets を使ったシンプルなリリース自動化の一事例として:

# CHANGELOG.md の変更を含む main ブランチへのマージ時に発動するルール。
.rules_release:
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $UPSTREAM_PROJECT_URL == $CI_PROJECT_URL
      changes:
        - '**/CHANGELOG.md'
      when: on_success
    - when: never

# パイプライン右端の再生ボタンを押すと開始されるリリースプロセス。
# `npm run release` の中で、changesets が .changesets下の変更ログをリリースノートに
# 巻き上げ、パッケージのバージョンをアップしたMRを作る。
release:bump-version:
  stage: manual
  before_script:
    - *BEFORE_SCRIPT_SETUP_GIT
    - *BEFORE_SCRIPT_SETUP_NPM
  script:
    - echo "🚀 Bump version."
    - npm run release
    - |
      curl --cacert ${ROOT_CA_PATH} --request POST \
      --header "PRIVATE-TOKEN: ${PROJECT_ACCESS_TOKEN}" \
      --data "source_branch=bump-version" \
      --data "target_branch=main" \
      --data "title=Bump version." \
      "${CI_SERVER_URL}/api/v4/projects/${CI_PROJECT_ID}/merge_requests"
  rules:
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
      changes:
        - '**/CHANGELOG.md'
      when: never
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
      when: manual
    - when: never
  allow_failure:
    true

# `release:bump-version` で作られるリリース用MRをマージすると実行されるジョブ。
# リリースバージョンのタグを作成し、公開用のミラーリポジトリへの同期処理が行われる。
release:
  stage: release
  extends:
    - .rules_release
  before_script:
    - *BEFORE_SCRIPT_SETUP_GIT
  script:
    - VERSION=$(node -p "require('./package.json').version")
    - echo $VERSION
    - git tag v$VERSION
    - git push origin v$VERSION
    # Mirror the tags to the mirror repository.
    - echo "🚀 Mirror tags to the mirror repository."
    - git clone "$CI_REPOSITORY_URL" repo.git
    - cd repo.git
    - git remote add mirror https://gitlab-token:${SYNC_TOKEN}@${PROD_PROJECT_URL#https://}.git
    - git push mirror main
    - git push mirror --tags

生成AI時代のプロジェクト管理基盤

ここまで、ドキュメント管理の側面で説明してきましたが、冒頭に「プロダクト開発のあらゆる活動とその成果物 (ソースコード、ドキュメント) の管理を単一の Git リポジトリで完結させる = SSoT (Single Source of Truth) 化する取り組み」と書いていました。

pj-template の重要な試みの1つとして、プロダクト開発のあらゆる活動データの集約も志向している点が挙げられます。極端ですが、一旦、GitLab リポジトリ上での Issue に全て寄せる、というアプローチを試しています。前述した ディレクトリ構成 の以下の部分です。

.
├── .gitlab/
│   └── issue_templates   # プロジェクト管理に必要な様々な Issue テンプレート

そのために、プロジェクト管理に係る様々な活動 (開発プロセス標準に則ったレビューや承認、リスク管理、PBI管理、インシデント・バグ管理、問合せ管理などなどなど) を Issue テンプレート化し、ラベルで分類・フィルタできるようにし、issue_template として、pj-template に組み込んでいます。

同時に、例えば Issue テンプレートをリスク管理でどう使うか、というルール・手順も全て文書化し pj-template に、プロジェクト管理計画のテンプレートとして組み込んでいます。

現実はなかなか難しいものがありますが、なるべく重要な活動は Issue 上で行い、Issueに残るようにしようと試みています。ADR (Architecture Decision Record) もラベルを付けて Issue として残すのが良いかな等と考えたり・・。

ということで、pj-template は単なるドキュメント管理を組み込んだテンプレートリポジトリではなく、生成AI活用を前提としたプロジェクト管理基盤的なものを「GitLab リポジトリに寄せ切る」アプローチで目指したものと言えます。

生成AI活用への効用

で、生成AI活用に実際効果あったの?とか出力精度上がったの?という肝心なところは、SSoT 化を優先していてあまり試せていません(笑)。生成AI に食わせるルールセットの整備も含めてこれからです。

ただ、「要件定義書はしっかり書けているが構想企画書とかはすっ飛ばしていた」ケースにおいて、要件定義書を参考に、構想企画書やイントロダクション文書を吐かせてみると、たたき台としてはまずまずなものが作成されたりして、まあ、そこそこ「そうなるよね」という効果は実感できた場面はありました。

いずれにしても、"プロダクト開発のあらゆる活動とその成果物 (ソースコード、ドキュメント) の管理を単一の Git リポジトリで完結させる"ことで、QA ボット整備、ソースコード<=>ドキュメントの相互生成・改善、プロダクト管理業務の自動化・省人化等は、それなりに捗るのではないかと甘く考えていたりします。

おわりに

"An SSoT for All Product Development Activities" として取り組んでいる pj-template について、ドキュメント管理にフォーカスして紹介しました。世の OSS プロジェクトや、テック企業では結構ふつうに行われていることかもしれませんが、うちのような会社での一実践例として参照いただければと思います。

まだ全然べスプラと呼べるようなものではなく、手探り (かつ、片手間) で徐々に整備・改善していっている発展途上の取り組みですので、この点ご留意ください。

Appendix

.markdownlint.jsonc

現状の .markdownlint.jsonc は以下のように4つほど ルール を無効化しています。

{
  "default": true,
  // no-reversed-links
  "MD011": false,
  // line-length
  "MD013": false,
  // no-duplicate-header
  "MD024": false,
  // no-inline-html
  "MD033": false,
}

package.json/remarkConfig

package.json 内の remark の設定は以下。

// remark 設定
"remarkConfig": {
    "settings": {
      "bullet": "-"
    },
    "plugins": [
      "remark-frontmatter",
      [
        "remark-gfm",
        {
          "tableCellPadding": false,
          "tablePipeAlign": false
        }
      ],
      "remark-preset-lint-consistent",
      "remark-preset-lint-recommended",
      [
        "remark-toc",
        {
          "heading": "contents"
        }
      ],
      [
        "remark-lint-no-undefined-references",
        {
          "allow": [
            " "
          ]
        }
      ]
    ]
  },
// ...
脚注
  1. 発表 #1683: 第29回 講演: 2万人が利用するソフトウェア開発管理支援サービスのご紹介 - redmine.tokyo: https://redmine.tokyo/issues/1683 ↩︎

  2. 開発効率を向上させる共創ソフトウェア開発プラットフォーム: https://www.global.toshiba/content/dam/toshiba/migration/corp/techReviewAssets/tech/review/2020/05/75_05pdf/a07.pdf ↩︎

Discussion