{
"$type": "site.standard.document",
"coverImage": {
"$type": "blob",
"ref": {
"$link": "bafkreifacydu2nj54mqt2ecua6z777tvp333nxbnqyj5ko64ecom3mz4qm"
},
"mimeType": "image/png",
"size": 47637
},
"path": "/entry/2026/02/04/090000",
"publishedAt": "2026-02-04T00:00:00.000Z",
"site": "https://blog.studysapuri.jp",
"tags": [
"@chibicco",
"@kawai",
"Working Out Loud 大声作業(しなさい)、チームメンバー同士でのトレーニング文化の醸成",
"『そもそも生成AIでやるべきでない問い』に、企業が挑んでしまう問題"
],
"textContent": "こんにちは、コンテンツ基盤開発チームの @chibicco です。本記事はコンテンツ制作チームの @kawai との共著です。\n\n『スタディサプリ』では、学習コンテンツ1を管理するために、Web GUI ベースの CMS2 を10年以上運用してきました。しかし、コンテンツ制作の規模が拡大するにつれて、大量操作への制約やレビューの難しさなど、GUI ベースの仕組みでは限界が見えてきました。\n\n本記事では、コンテンツ制作の改善を目指してこの CMS をリアーキテクチャした取り組みについて、なぜその判断をしたのか、どう進めたのか、そして結果どうなったのかを紹介します。\n\n先に結論を書くと、学習コンテンツのデータを構造化されたテキストファイルとして GitHub で管理する仕組みに移行したことで、**制作速度が160倍** に改善しました。従来の仕組みでは2日で1講座だったのが、新しい仕組みでは半日で40講座を登録できるようになりました。そしてこの速度改善の主因は、構造化されたデータと AI Agent の組み合わせでした。\n\n * なぜ headless 化したのか\n * 既存の CMS が抱えていた構造的な課題\n * GUI を延命するか、headless 化に振り切るか\n * どう進めたか\n * 制作チームに価値が届く順序でマイルストーンを切る\n * まず動くものを作り、フィードバックを得る\n * 構造化データがもたらしたもの\n * 構造化データと AI Agent\n * 制作速度の向上\n * PR ベースのワークフローがもたらした安心感\n * ファイル単体で完結するバリデーション\n * 残る課題と今後の展望\n * 既存コンテンツの移行\n * 運用の中で見つかった課題\n * テキストで表現できるコンテンツの脱画像\n * おわりに\n\n\n\n## なぜ headless 化したのか\n\n本記事でいう headless 化とは、GUI(管理画面)を廃止し、コンテンツデータを構造化ファイルとして GitHub で宣言的に管理する構成への移行を指します。この headless 化に踏み切った背景はいくつかありました。\n\n### 既存の CMS が抱えていた構造的な課題\n\n既存の CMS は、ブラウザ上のフォームからコンテンツを1件ずつ登録・編集する Web アプリケーションです。以下にその画面例を示します。\n\n10年以上の歴史を持ち、フロントエンドは2015年頃の技術スタック(Backbone.js + Marionette、CoffeeScript、jQuery 2.2)で構築されており、エンハンスのたびにメンテナンスコストが重くのしかかっていました。\n\nこの CMS には長い間専任の開発チームが存在せず、各チームが持ち回りでメンテナンスする状態が続いていました。2024年にコンテンツ基盤開発チームが発足して引き継ぎましたが、コードが書かれた当時から時間が経ち、人も変わっており、コードの意図を理解する難易度が上がっていました。そのため、新機能を追加するにはまずリファクタリングが必要でした。\n\n一方で、コンテンツデータの性質を考えると、リッチな UI を維持することよりも、データを守りつつ開発速度を上げ、長期的なメンテナンス容易性を担保する方が重要でした。headless 化すれば、最小限のコードを書き直すだけで済み、実質不要なロジックを切り離して重要なドメインロジックに注力できます。\n\n### GUI を延命するか、headless 化に振り切るか\n\nMongoDB に格納されているコンテンツデータをあらためて見ると、その多くは静的なファイルとして管理できるものでした。GUI で動的に管理する必然性は薄く、むしろ GUI であるがゆえに大量操作ができない、という制約を生んでいました。\n\nその結果、GUI では対応しきれない操作のために、目的別のスクリプトやワークフローが個別に作られていました。こうしたスクリプトが数十個単位で存在しており、それぞれにメンテナンスコストがかかっていました。コンテンツが構造化されたテキストデータとして管理されていれば、汎用的に対応できる内容です。\n\n既存の CMS の上にツールを被せて支援する、というアプローチも検討しました。しかし、JS コード(Backbone.js / Marionette / CoffeeScript)をメンテナンスし続けるコストを考えると、GUI を延命するより headless 化した方が長期的に管理コストが下がると判断しました。制作チームが新しい仕組みに慣れるまでの学習コストは必要ですが、この点は覚悟の上での判断でした。\n\n## どう進めたか\n\n### 制作チームに価値が届く順序でマイルストーンを切る\n\nheadless 化を一気に進めるのではなく、段階的にマイルストーンを設定しました。進め方のポイントは、**制作チームに価値が届く順序** を意識することでした。結果として既存の CMS の課題解消にもつながりますが、あくまでコンテンツ制作の改善が主眼です。\n\nこの順序を決めるにあたっては、制作担当者へのヒアリングを重ねました。どの作業が日常的に負担になっているか、どんな粒度で移行すれば実際の制作フローで早く価値を届けられるかを確認し、マイルストーンの優先度に反映しました。\n\nなお、『スタディサプリ』の講座は下図のような階層構造になっており、ユーザーに届く学習素材(中身)と、それを束ねる構造・管理情報(箱)に大別できます。\n\nコンテンツの「中身」から優先して、以下の順序で対応範囲を広げていきました。\n\n段階 | 対象 | 中身 / 箱 | 狙い\n---|---|---|---\n1 | 動画・資料 | 中身 | 最もシンプルな領域で仕組みを検証\n2 | 問題データ | 中身 | コンテンツ制作の中核。構造化の恩恵が大きい\n3 | 画像を含む問題データ | 中身 | 画像管理を含む複雑なデータ構造への対応\n4 | ライセンス・講座グループなどの管理データ | 箱 | 既存の CMS の管理機能からの移行開始\n5 | 講座構造の定義 | 箱 | 依存関係が最も複雑。前段階の学びを反映\n\nこの順序は「簡単な方から」という単純な話ではありません。いくつかの意図がありました。順番に見ていきます。\n\nまず、コンテンツの「中身」と「箱」を分離し、中身から先に移行する戦略をとりました。講座構造(箱)は既存の CMS で引き続き管理しつつ、動画や問題データ(中身)だけを新しい仕組みで制作します。2つのシステムを並行運用する辛さはありますが、段階的に移行するために必要なステップだと判断し、制作チームにもこの過渡期の運用を許容してもらいました。\n\n講座構造を最後にしたのは、ライセンスなど他の構造との依存関係が複雑で、影響範囲が大きいからです。最初は影響範囲の小さい領域で運用に乗せ、そこで得たフィードバックを次の段階の設計に反映していきました。実際、前の段階で得た学びが仕組みの設計自体に影響したケースもあります。\n\nもう1つ意識したのは、制作チームの習熟です。全コンテンツを一度に移行するビッグバンは避け、エディタと GitHub を使った制作フローに慣れた人を徐々に増やしていく方針にしました。何を新しい仕組みに移行するか、誰が担当するかをセットで決め、段階的にチーム全体へ広げていきました。\n\nこの移行を支えたのは、『スタディサプリ』の開発組織に根づいている Working Out Loud3——作業の過程をオープンに共有する文化です。制作チームが新しい仕組みで困ったときに、すぐにエンジニアに声をかけられる環境があったことで、問題の発見と対応が素早く回りました。エンジニア側からもこまめに状況を共有し、仕組みの変更が制作チームにとって一方的なものにならないよう意識しました。\n\n### まず動くものを作り、フィードバックを得る\n\n半年間で必要最低限の動くものを実装し、2025年11月には実技教科(音楽・美術・家庭・技術・保健体育)の定期テスト向けコンテンツで、初めて本番環境でのコンテンツ制作に新しい仕組みを活用しました。\n\nタイトなスケジュールの中でも迅速に価値を検証するため、直近のリリースを控えていた実技講座を最初の対象に選定しました。\n\n制作担当者の視点では、初めて VS Code でファイルを編集するときは識別子の対応関係や記法に慣れるまで多少戸惑いがありました。ただ、従来の CMS に戻りたいとは思いませんでした。従来は問題を1つずつ人力で登録する必要があり、関連する問題や対応関係を横断して見渡せなかった点が辛かったからです。新しい仕組みでは1つの問題を他の講座で簡単に流用することができ、多くの講座を横断する形で、全体を見渡しながら作業できました。\n\n一方で、実際に使ってもらうことで改善点も見つかりました。たとえば、バリデーションエラーが英語のまま表示されており、何をどう直せばいいかが伝わらないケースや、エラーの発生箇所がわかりにくいケースがありました。こうしたフィードバックを受けて、エラーメッセージの日本語化やエラー箇所の詳細表示といった改善を重ねていきました。\n\n## 構造化データがもたらしたもの\n\nheadless 化にあたって、コンテンツデータを **YAML/CSV として構造化** し、GitHub リポジトリで Pull Request(PR)ベースで宣言的に管理する仕組みを構築しました。まず、従来と新しい仕組みの違いを整理します。以下の図は、それぞれのアーキテクチャの概要です。\n\n観点 | 従来 | 新しい仕組み\n---|---|---\nデータ管理 | GUI で MongoDB を手続き的に操作 | YAML/CSV ファイルを GitHub で宣言的に管理\n大量操作 | 目的別スクリプトが数十個 | AI Agent + 汎用スクリプト\nレビュー | 本番環境で同期的にダブルチェック | PR ベースで非同期レビュー\nバリデーション | GUI 側の制約のみ | JSON Schema + ドメインルール(CI 自動実行)\nやり直し | 本番環境の CMS で作業 | `git revert` で切り戻し可能\n\nたとえば、選択問題の YAML はこのような構造です(※ 架空の問題です)。\n\n\n --- kind: question_spec/v3 id: math_basic_001 components: choice: body: - markdown_text: \"3つの辺の長さが 3cm, 4cm, 5cm の三角形は、どのような三角形ですか。\" choices: - local_id: a text: \"正三角形\" is_correct: false - local_id: b text: \"直角三角形\" is_correct: true - local_id: c text: \"二等辺三角形\" is_correct: false explanation: markdown_text: \"3² + 4² = 5² が成り立つので、直角三角形です。\"\n\nこの YAML が『スタディサプリ』上では以下のように表示されます。\n\nでは、この変化がもたらした具体的な効果を紹介します。\n\n### 構造化データと AI Agent\n\n本記事では、生成 AI と対話しながらスクリプト生成や変換作業を支援するツールを AI Agent と呼びます。\n\nAI の活用は計画当初から視野に入れていました。ただし、計画を立てた2025年初頭の時点では、自分たちのコンテンツ構造で実用的にどこまで使えるかは未知数でした。\n\nそこで、データ構造を JSON Schema で定義し、実装例やリポジトリのルールをドキュメントとして整備しました。コンテンツの構造を AI Agent に把握させ、スクリプト生成に活用できる状態を作ることを意識しました。\n\nこの下地が効きました。2025年11月頃に実際に試してみると、**思ったよりも実用的に機能しました** 。\n\nたとえば、別システムで管理していた講座構造の CSV を新しい仕組み向けに書き直す作業があります。また、別システムの YAML 形式で書かれた問題データを、新しいフォーマットに変換する作業もあります。新規作成の場合は、問題の原稿を元に新しいフォーマットへ書き換える依頼をしています。 いずれのケースも、まず試しに3つほど手動で変換してから、AI Agent を活用してスクリプトを生成し一括で対応しています。記法やエラーの対処に迷ったときも AI を活用しながら自力で解決を進められるようになりました。\n\nポイントは、コンテンツそのものの生成に AI を使うのではなく、**Ruby などのスクリプトの生成に AI を活用することで大量処理の漏れを防ぐ** という点です。非エンジニアの制作チームが VS Code + AI Agent でこうした作業を行える体制が実現しました。\n\nただし、AI の出力をそのまま本番に反映するわけではありません。AI は確率的に動作するため、出力には必ず誤りが含まれる可能性があります4。そこで、「たたき台作り」や「スクリプト生成」に AI を活用しつつ、最終的には JSON Schema に基づく決定論的なバリデーションで**フォーマット違反や参照関係の誤り** を検出し、品質を担保しています。\n\n### 制作速度の向上\n\n従来の仕組みでは、1講座の登録に2日ほどかかっていました。新しい仕組みに移行した初日は1日で8講座、数日後には半日で40講座を登録できるようになりました。1講座あたりの所要時間で比較すると、約160倍の改善です。制作担当者からもこの成果を実感する声が上がりました。\n\n制作速度が向上した要因は、単に「GUI からファイル編集に変わった」ことではありません。データが構造化されていることで機械的な処理やバリデーションがしやすく、同時にテキストであることで AI が読み書きできる。この2つの性質が組み合わさったことで、AI Agent を活用した補完・生成が実用的に機能しました。\n\nheadless 化によってデータがこの形になっていたことが、AI を有効活用できるコンテンツ制作を可能にしました。この因果関係は、この記事の最後に改めて振り返ります。\n\n### PR ベースのワークフローがもたらした安心感\n\nコンテンツ制作のフローは以下のようになりました。\n\n 1. GitHub リポジトリでブランチを切る\n 2. YAML/CSV ファイルを編集する\n 3. PR を作成する\n 4. CI が自動でバリデーション(JSON Schema + ドメインルールで検証)\n 5. レビューしてマージ → 開発環境に反映\n 6. デプロイ PR をマージ → 本番環境に反映\n\n\n\n従来は GUI での操作が本番データベースに直接書き込まれていたため、「検品は本番でやるしかない」状態でした。ダブルチェックも同期的に行う必要があり、関係者のスケジュールを合わせなければなりませんでした。\n\nPR ベースのフローにより、差分が見える・レビューできる・やり直しがきく、という当たり前の安心感が得られるようになりました。レビューも非同期で行えるため、制作の柔軟性が上がっています。\n\nさらに、PR を作成すると、YAML ファイルの変更が最終的にコンテンツデータベースにどう反映されるかを示す diff が自動でコメントされます。GitHub のファイル差分だけでは、参照関係の解決やデータの正規化を経た結果がわからないため、「自分の編集が実際に何を変えるのか」をレビュー時に確認できる仕組みです。以下はその自動コメントの例です。\n\n#### ファイル単体で完結するバリデーション\n\nheadless 化にあたって、エンジニアがコンテンツ周りのドメイン知識をあらためて整理できたことで、スキーマ違反や構造の参照関係の誤りといった入力ミスを機械的に検出するバリデーションを実装できました。\n\n中でも大きいのは、YAML/CSV ファイルの段階で完結するバリデーションです。JSON Schema による型・構文チェックやビジネスルールの検証を、データベースや外部リソースへのアクセスなしに実行できます。CI で PR 単位に自動実行されるため、ファイルを編集して PR を出すだけで即座にフィードバックが返ります。\n\n一方、データベース上の既存データとの参照整合性など、外部リソースへのアクセスが必要な検証はデータベースへの書き込み直前まで遅延させています。外部依存のない検証は早く・軽く、外部依存のある検証は必要なタイミングでまとめて行う、という設計です。\n\nPR ベースのフローなので `git revert` による切り戻しも容易です。エンジニア・制作チーム双方にとって、心理的安全性が大きく向上しました。\n\n## 残る課題と今後の展望\n\nこの取り組みはまだ完成していません。正直に、残っている課題も書いておきます。\n\n### 既存コンテンツの移行\n\n従来の CMS で制作済みの既存コンテンツを新しいリポジトリに移行する作業が残っています。MongoDB の内容を出力して YAML/CSV ファイルに変換する仕組みの構築、リハーサル、段階的な本番移行が必要です。\n\n### 運用の中で見つかった課題\n\n実際に運用を始めてから見つかった改善点もあります。\n\n1つは、前述のバリデーションエラーメッセージの継続的な改善です。初期に日本語化やエラー箇所の詳細表示に対応しましたが、運用が広がるにつれて YAML の構文エラーや回答形式のバリデーションエラーなど、新たなパターンが次々と見つかりました。非エンジニアの制作チームが日常的に使う仕組みである以上、この改善に終わりはありません。\n\nもう1つは、YAML スキーマの厳格化です。当初は柔軟に受け入れていたデータ構造に対して、運用してみると意図しないプロパティが混入するケースがあり、追加プロパティを明示的に禁止する制約を加えました。早い段階で気づけたのは、実際に制作チームに使ってもらっていたからです。\n\nまた、新旧のシステムが同じデータベースを共有する並行運用期間では、本番環境への反映処理が競合しないよう制御する必要があり、この調整の仕組みは想定以上に複雑でした。これは並行運用を選んだことのトレードオフとして受け入れています。\n\n### テキストで表現できるコンテンツの脱画像\n\n現在、問題の本文や解説の多くは画像として管理しています(S3 に画像をアップロードし、YAML にその URL を記述)。図版や図解など画像でしか表現できないものは今後も画像のままですが、テキストや LaTeX で表現できるもの——たとえば英語の問題文や数式——は、画像をやめて構造化されたテキストとして管理したいと考えています。\n\nただし、縦書き・数式・装飾表現のレンダリングなど解決すべき技術課題は多く、教科ごとに実現可能性が異なります。段階的に進めていく予定です。\n\n## おわりに\n\nこの取り組みは、コンテンツ制作をどう改善するかという問いから始まりました。10年モノの CMS を延命するか、headless 化に振り切るか。私たちは後者を選びました。\n\n振り返ると、最も大きな学びは「データを構造化したこと自体が、次の可能性を開いた」ということです。AI Agent の進化は見込んでいましたが、実際にどこまで活用できるかは作ってみて初めてわかったことでした。確実に言えるのは、データが machine-readable な形になっていなければ、この成果は得られなかったということです。AI の能力が今後さらに向上していく中で、データが構造化されていることの価値はますます大きくなると考えています。\n\n一方で、この取り組みはまだ道半ばです。既存コンテンツの移行、テキストで表現できるコンテンツの脱画像、運用の中で見つかった課題の改善など、やることはまだまだあります。構造化データの恩恵をさらに広げていくために、引き続き取り組んでいきます。\n\n* * *\n\n 1. 講義動画・演習教材・テキスト等、『スタディサプリ』で生徒に届ける学習素材の総称です↩\n 2. ここでの CMS は WordPress 等の汎用的な Web CMS ではなく、学習コンテンツの制作・管理に特化した社内システムを指します↩\n 3. Working Out Loud 大声作業(しなさい)、チームメンバー同士でのトレーニング文化の醸成↩\n 4. 深津貴之「『そもそも生成AIでやるべきでない問い』に、企業が挑んでしまう問題」より:「生成AIは確率分布で、未来を予測したり、答えを予測するマシーンです。つまり、『確率的に間違えが発生する』ことは仕様の一部です。」↩\n\n",
"title": "制作速度160倍を実現した、コンテンツ管理システム(CMS)のリアーキテクチャ",
"updatedAt": "2026-02-04T00:00:02.000Z"
}