こんにちは、SRE2年生が終わろうとしている墨(YOUTRUST/X)です!
昨今AIの台頭によりリリース頻度が高くなっていく中でヘルプページの更新がリリースに追いつかないなどの課題をお持ちではないでしょうか?
今回は、NotionからGitベースのヘルプページへ移行し、さらにAIによる自動更新システムを構築した事例をご紹介します。
非エンジニアメンバーが簡単に運用できる仕組みを作ることで、運用工数を大幅に削減しつつ、品質管理を向上させた取り組みです。

プロジェクト概要
YOUTRUSTでは、ユーザー向け(to C)と公式リクルーター向け(to B)の2つのヘルプページを提供しています。
※ 以降ユーザー向け(to C)をSNS、公式リクルーター向け(to B)を採用管理画面と呼称します。
| 項目 | 詳細 |
|---|---|
| 対象サイト | https://help.youtrust.jp/ |
| 利用者 | 一般ユーザー(SNS) + 公式リクルーター(採用管理画面) |
| 記事数 | 160記事以上 |
| 更新頻度 | プロダクト更新に応じて随時 |
| 技術スタック | Material for MkDocs + Vercel + GitHub Actions |
| コスト | 月約$20(Vercel pro + GitHub Actions利用料) |
なぜNotionからの移行が必要だったのか
移行前の課題
従来のNotion版ヘルプページには、いくつかの運用課題がありました。
1. リリース情報の分断
最も大きな課題は、ヘルプページを運用する非エンジニアメンバー(マーケティング・CS担当)に、プロダクトのリリース情報が届かないことでした。
- エンジニアのPRマージ → プロダクト反映
- しかし、その情報が非エンジニアメンバーに漏れることがある
- 結果、ヘルプページの更新漏れが発生
ユーザーからの問い合わせで初めて、仕様変更への対応漏れに気づくこともありました。
2. 変更管理の弱さ
- Notionの履歴機能はあるが、コードレビューのようなワークフローが存在しない
- 誰が何を変更したのか追跡しづらい
3. 手動運用の手間
- 編集→公開を手動で行う必要があり、レビューフローも未整備
- プレビュー機能がないため、公開してから「イメージと違った」となることも
4. AI連携の困難さ
- Notionのデータ構造は外部システムとの連携が難しい
- 将来的なAI活用を見据えると、Markdown管理が望ましい
目指したゴール
これらの課題を解決するため、「Docs as Code」の思想に基づいた移行を決定しました。
- AIによるリリース監視: 日々のPRを自動監視し、ヘルプ更新が必要かAIが判定
- 非エンジニアメンバーでも簡単に運用: Slackボタンだけでマージ・デプロイできる仕組み
- Gitでのバージョン管理: 全変更履歴を完全管理
- PRベースのレビューフロー: マージ前にプレビュー確認が可能
- 自動デプロイ: mainブランチへのマージで即座に反映
技術選定のポイント
ホスティング:Vercel を選択
当初はGitHub Pagesを検討していましたが、最終的にVercelを採用しました。
| 候補 | 判定 | 理由 |
|---|---|---|
| GitHub Pages | 不採用 | 現在のTeamプランではpublicリポジトリでしか使えない |
| Vercel | 採用 | privateリポジトリ対応、Serverless Functions でSlack連携が可能 |
GitHub Pagesを断念した理由は、現在のGitHub Teamプランでは、publicリポジトリでしかGitHub Pagesを運用できないためです。ヘルプページのソースコードには内部情報が含まれる可能性があるため、リポジトリをpublicにすることはできませんでした。
Vercelであれば、privateリポジトリでもホスティング可能で、さらにServerless Functionsを使ったSlack連携も実現できました。
静的サイトジェネレータ:Material for MkDocs
| 候補 | 判定 | 理由 |
|---|---|---|
| MkDocs + Material | 採用 | 学習コスト低、ドキュメント特化、日本語検索対応 |
| Docusaurus | 不採用 | 高機能だがReact知識必要、初期設定が複雑 |
| Hugo | 不採用 | 汎用的だがドキュメント特化ではない |
| Next.js (Nextra) | 不採用 | React/Next.js 知識必要、オーバースペック |
Material for MkDocsは、ドキュメント作成に特化したフレームワークで、学習コストが非常に低いのが特徴です。Markdown記法さえ知っていれば、非エンジニアメンバーでもすぐに編集できます。
AIエージェント
| 候補 | 判定 | 理由 |
|---|---|---|
| GitHub Actions ai-inference | 採用 | 無料枠があり、Actionsからの呼び出しに最適 |
| Gemini | 不採用 | 実績はあったが、より安いai-inferenceを採用 |
| Claude API | 不採用 | 動作安定せず、システムに組み込むのは難しいと判断 |
アーキテクチャ全体像
システム全体は、大きく3つのコンポーネントで構成されています。
- ドキュメント管理(Material for MkDocs)
- docs/user/ (一般ユーザー向け)
- docs/recruiter/ (公式リクルーター向け)
- mkdocs.yml (ナビゲーション設定)
- CI/CD(GitHub Actions)
- deploy.yml (デプロイ+Slack通知)
- check-help-updates.yml (AI自動更新)
- pr-diff-summary.yml (PR差分サマリー)
- ホスティング+API(Vercel)
- site/ (MkDocsビルド出力)
- api/slack/ (Slack連携 Serverless API)
AI自動更新システムの仕組み
ここからが本記事のメインテーマです。プロダクトのmainブランチへのPRマージに連動して、ヘルプページの更新が必要かをAIが自動判定し、更新PRを作成するシステムを構築しました。
システムの全体フロー
毎朝9:00 JST ↓ GitHub Actions が起動 ↓ webapp / nativeapp の過去24時間のマージ済みPRを取得 ↓ 5件ずつバッチ処理で GPT-4.1 に分析依頼 ↓ 「追加」「更新」「削除」のいずれかを判定 ↓ 必要に応じてMarkdownファイルを自動生成・更新・削除 ↓ mkdocs.yml のナビゲーションを自動更新 ↓ SNS用 /採用管理画面用の2つのPRを自動作成 ↓ Slackに通知(ボタンでマージ・クローズ可能)
ステージ1:PR収集とバッチ処理
まず、対象リポジトリ(youtrust-webapp(Webアプリ) と youtrust-nativeapp(モバイルアプリ))から、過去24時間にマージされたPRを取得します。
取得したPRは、5件ずつのバッチに分割します。これはGitHub Models APIのレート制限対策と、分析精度を保つためです。
ステージ2:GPT-4.1による影響判定
各バッチに対して、GitHub Models API(GPT-4.1)を使って分析します。
ポイントは、判定基準を明文化したプロンプトファイル(.github/prompts/help-criteria.md)を用意していることです。
含めるべき変更の例
- ユーザー向け機能の追加・変更(UIの大幅な変更を含む)
- 機能の廃止・削除
- 全ユーザーに公開された新機能
- ユーザーが画面上から判断可能な情報のみに限定
除外すべき変更の例
- プレリリース機能
- A/Bテストやロールアウト中の機能
- 見た目の微調整(色、フォント、余白など)
- リファクタリング
- 管理画面・内部ツールの変更
- ドキュメントやテストの追加、修正
GPT-4.1は、以下のようなJSON形式で応答します。
{ "action": "add", "target_path": "user/account/login-settings.md", "target_section": "一般ユーザー向け", "reason": "新しいログイン方法が追加されたため", "requires_image": true }
リトライ機能も実装しており、API呼び出しが失敗した場合は指数バックオフで3回まで再試行します。
ステージ3:コンテンツ生成
判定結果が「追加」または「更新」の場合、GPT-4.1に再度依頼してMarkdownコンテンツを生成します。
生成時の制約条件
生成時の制約条件は、プロンプトに埋め込んでいます。
- リリース告知は書かない(「〜されました」という表現は禁止)
- 現在ある機能として説明する(「〜できます」「〜されます」)
- 日付や時期は書かない
- Material for MkDocsのアイコン記法を使う(
:material-xxx:) - 画像は含めない(テキストのみで説明)
ステージ4:ナビゲーション自動更新
生成されたMarkdownファイルを配置するだけでなく、mkdocs.yml のナビゲーション構造も自動更新します。
これにはPythonスクリプトを使用し、YAMLの階層構造を維持しながら新しいエントリを追加します。
import yaml with open('mkdocs.yml', 'r', encoding='utf-8') as f: config = yaml.safe_load(f) # 新しいページをナビゲーションに追加 nav_entry = { '新機能の使い方': 'user/account/login-settings.md' } for section in config['nav']: if '一般ユーザー向け' in section: account_section = next( (item for item in section['一般ユーザー向け'] if 'アカウント設定' in item), None ) if account_section: account_section['アカウント設定'].append(nav_entry) with open('mkdocs.yml', 'w', encoding='utf-8') as f: yaml.dump(config, f, allow_unicode=True)
ステージ5:PR自動作成とSlack通知
最後に、SNS用と採用管理画面用で別々のPRを作成します。これは、それぞれ担当チームが異なるためです。
- SNS用:マーケティングチーム担当
- 採用管理画面用:CSチーム担当
PR作成後、Slackに通知を送ります。この通知には、インタラクティブなボタンが含まれています。
- 👀 PRを見る(GitHubへのリンク)
- ✅ マージ(確認ダイアログ付き)
- ❌ クローズ(確認ダイアログ付き)
Slack通知は最低限とし具体的な内容はPRに記載してあります。
スレッドにプレビュー用のURLリンクが挿入されるため担当者は現在との差分を実際に確認し、マージ・修正・クローズを判断します。


Vercel Serverless Functions によるSlack連携
非エンジニアメンバーでも簡単に運用できるようにするという要件を満たすため、Slackボタンのクリックだけでマージ・クローズができる仕組みを実装しました。
API設計
エンドポイントは /api/slack/merge で、以下のフローで動作します。
Slackボタンクリック ↓ POST /api/slack/merge ↓ 署名検証(HMAC-SHA256) ↓ 即座に200 OKを返す(Slackの3秒タイムアウト回避) ↓ バックグラウンドで処理 ├─ Slackメッセージを「🕐 処理中...」に更新 ├─ GitHub API で PR をマージ/クローズ ├─ PR にコメント追加(実行者名を記録) └─ Slackメッセージを最終結果に更新
セキュリティ対策
Slackからのリクエストが正規のものであることを確認するため、署名検証を実装しています。
import crypto from 'crypto'; function verifySlackRequest( body: string, timestamp: string, signature: string, secret: string ): boolean { // 5分以上古いリクエストは拒否 const now = Math.floor(Date.now() / 1000); if (Math.abs(now - parseInt(timestamp)) > 300) { return false; } // HMAC-SHA256で署名を検証 const sigBasestring = `v0:${timestamp}:${body}`; const mySignature = 'v0=' + crypto .createHmac('sha256', secret) .update(sigBasestring) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(mySignature), Buffer.from(signature) ); }
GitHub API連携
PRのマージには、Octokitを使用します。マージ前に mergeable ステータスをチェックし、コンフリクトがある場合はエラーを返します。
// マージ可能かチェック const { data: pr } = await octokit.pulls.get({ owner: 'team-youtrust', repo: 'youtrust-help-page', pull_number: prNumber, }); if (pr.mergeable_state === 'dirty') { throw new Error('❌ コンフリクトがあるためマージできません'); } if (pr.state !== 'open') { throw new Error('❌ このPRは既にクローズされています'); } // マージ実行 await octokit.pulls.merge({ owner: 'team-youtrust', repo: 'youtrust-help-page', pull_number: prNumber, merge_method: 'squash', }); // コメント追加 await octokit.issues.createComment({ owner: 'team-youtrust', repo: 'youtrust-help-page', issue_number: prNumber, body: `✅ Slackから @${slackUserName} によってマージされました`, });
これにより、非エンジニアメンバーはGitHubを開くことなく、Slackだけでヘルプページの更新ができるようになりました。
デプロイフローの自動化
PRがマージされると、deploy.yml ワークフローが起動します。
ビルドとデプロイ
- name: Setup Python uses: actions/setup-python@v5 with: python-version: '3.12' - name: Install MkDocs run: pip install -r requirements.txt - name: Build site run: mkdocs build - name: Deploy to Vercel run: | vercel deploy --prod --token=${{ secrets.VERCEL_TOKEN }}
重要なのは、Vercel側ではビルドを行わないという設計です。vercel.json の buildCommand は空文字列にしており、GitHub Actions側で mkdocs build を実行しています。
これにより、ビルドログがGitHub Actionsに集約され、トラブルシューティングが容易になります。
プレビューデプロイとSlack連携
PRブランチへのプッシュ時は、プレビューデプロイを作成し、そのURLをSlackスレッドに投稿します。
- name: Deploy preview to Vercel id: deploy run: | URL=$(vercel deploy --token=${{ secrets.VERCEL_TOKEN }}) echo "url=$URL" >> $GITHUB_OUTPUT - name: Post preview URL to Slack thread if: contains(github.event.head_commit.message, 'slack_thread:') run: | # コミットメッセージから slack_thread:CHANNEL:TIMESTAMP を抽出 THREAD_INFO=$(echo "${{ github.event.head_commit.message }}" | grep -o 'slack_thread:[^:]*:[0-9.]*') CHANNEL=$(echo "$THREAD_INFO" | cut -d: -f2) TS=$(echo "$THREAD_INFO" | cut -d: -f3) # Slackスレッドに投稿 curl -X POST https://slack.com/api/chat.postMessage \ -H "Authorization: Bearer ${{ secrets.SLACK_BOT_TOKEN }}" \ -d "channel=$CHANNEL" \ -d "thread_ts=$TS" \ -d "text=プレビューデプロイ: ${{ steps.deploy.outputs.url }}"
このとき、PR作成時にコミットメッセージに slack_thread:CHANNEL_ID:MESSAGE_TS というメタデータを埋め込んでおくことで、元のSlack通知のスレッドに返信する形でプレビューURLを投稿できます。
これにより、非エンジニアメンバーはSlackスレッド内で全ての情報(更新内容、プレビューURL、マージボタン)にアクセスできます。
運用フローの確立
日々の運用(非エンジニアメンバー向け)
- 毎朝9:00に自動実行(またはエンジニアが手動実行)
- Slackに通知が届く
- 担当者(非エンジニアメンバー)がPRの内容を確認
- 必要に応じて修正・画像追加(後述)
- Slackボタンで「✅ マージ」または「❌ クローズ」をクリック
- マージされると自動的に本番反映
ポイント:GitHubを開く必要がない
非エンジニアメンバーはGitHubのアカウントを持っていなくても、Slackだけで全ての操作が完結します。
修正や画像が必要な場合の対応
AIは requires_image: true を判定しますが、画像の生成・挿入は人間(またはDevin)が行います。
Slackスレッド内でDevinを呼び出し、スクリーンショット撮影と画像挿入を依頼します。 画像挿入後、再度プレビューURLがSlackスレッドに投稿されるので、確認してからマージします。
効果測定
工数削減
| 作業項目 | 移行前(Notion) | 移行後(Git + AI) |
|---|---|---|
| リリース情報の把握 | 手動で各チームに確認(見落としあり) | AI自動監視(24時間以内に検知) |
| ヘルプ更新の判断 | 手動(担当者の判断に依存) | AI自動判定(基準を明文化) |
| コンテンツ作成 | 手動(30分〜1時間/記事) | AI下書き + 人間レビュー(10分/記事) |
| デプロイ | 手動公開ボタン | Slackボタン1クリック |
| レビュー | なし | PRベース(プレビュー確認可能) |
概算で、1記事あたりの作業時間が1/3以下になりました。
品質向上
- リリース情報の見落としがゼロに: AIが24時間以内に全PRをチェック
- 変更履歴がGitで完全管理される: いつ、誰が、何を変更したか全て記録
- PRプレビューで公開前に見た目を確認可能: 公開後の修正が不要に
- レビューフローにより誤字脱字が減少: AI生成でも人間がチェック
- 統一された文体・スタイル: AIプロンプトで制御
非エンジニアメンバーの負担軽減
- GitHubの知識不要: Slackだけで操作完結
- リリース情報の追跡不要: AIが自動検知してSlackに通知
- プレビュー確認が簡単: SlackスレッドにURLが投稿される
- マージ操作が簡単: ボタン1クリックで完了
学びと今後の展開
技術的な学び
1. AIに任せる範囲の見極めが重要
当初はAIに全て任せようとしましたが、以下は人間の判断が必要でした。
- 画像の選定と挿入
- 微妙なニュアンスの調整
- ユーザー目線での分かりやすさ
AIは「下書き」を作る役割と割り切ることで、うまく協業できるようになりました。
2. プロンプトエンジニアリングの重要性
判定精度を上げるため、help-criteria.md を何度も改善しました。
- 具体例を豊富に含める
- 除外条件を明確にする
- 出力フォーマットを厳密に指定する
特に「プレリリース機能は除外」「A/Bテストは除外」など、除外条件を明確にすることが精度向上のカギでした。
3. 非エンジニアメンバー向けのUX設計
「GitHubを開かなくても運用できる」という要件は、技術的には簡単ですが、UX設計が重要でした。
- Slackボタンの配置
- 確認ダイアログの文言
- プレビューURLの投稿タイミング
- エラーメッセージの分かりやすさ
実際に非エンジニアメンバーにテストしてもらい、フィードバックを反映しました。
まとめ
Notion→Git移行とAI自動更新システムの構築により、以下を実現しました。
- リリース情報の見落としゼロ: AIが24時間以内に全PRを監視
- 運用工数を1/3以下に削減: AI下書き + Slackボタンマージ
- 非エンジニアメンバーでも簡単に運用: GitHubの知識不要
- PRベースのレビューフローで品質向上: プレビュー確認 + 変更履歴管理
「Docs as Code」の思想と、AIの活用、そして非エンジニアメンバーでも使いやすいUX設計により、ドキュメント運用の新しい形が見えてきました。
今後はヘルプコンテンツをベースに、Slackで動作するAI問い合わせエージェントを開発し、CX業務など他領域の効率化も目指していきます!
同じような課題を抱えているチームの参考になれば幸いです。
We're hiring!
YOUTRUSTではエンジニアを積極募集中です! 仕事専用SNSを一緒に作りましょう!