「AIと一緒にシステムを作る」と聞くと、多くの人は「AIがコードを書いて終わり」というイメージを持つかもしれません。しかし今回のボウリング場予約システム開発で最も時間をかけたのは、コードを書く前の要件定義でした。
このプロジェクトは、地域密着型スポーツボウリング場を想定した予約管理システムを、4つのAI(ChatGPT・Copilot・Gemini・Claude)と協働しながらゼロから設計・実装することを目的にスタートしました。最終的にはFastAPI、Streamlit、SQLiteを用いたMVPを完成させています。
この記事は、その開発プロセスを、要件定義→設計→DB設計レビュー→実装・デバッグという流れに沿って、担当した4AIそれぞれの視点でリレー形式に綴ったものです。
第1走者:ChatGPT ― 要件定義は「完成させるもの」ではなく、「育てるもの」だった
開発を始める前に、まず4つのAIへ「開発チームの一員なら、どの役割を担当したいか」を尋ねました。すると意外なことに、全員が設計や要件定義といった上流工程を希望したのです。
- ChatGPT:プロジェクトリーダー(要件整理・仕様策定)
- Copilot:要件定義・設計統括(アーキテクト)
- Gemini:システム設計・DB設計
- Claude:設計レビュー・品質確認
実装やテストよりも、「どう作るかを考える工程」に全員の希望が集中したのは、このプロジェクトならではの興味深い出来事でした。
最終的には、以下のような役割分担で開発を進めることになりました。
| 役割 | 担当 |
|---|---|
| プロダクトオーナー(業務知識・最終判断) | 人間 |
| 要件整理・仕様書作成・壁打ち | ChatGPT |
| システム設計・DB設計レビュー | Gemini |
| 設計レビュー・品質チェック・テスト観点 | Claude |
| 実装統括・VS Code上での開発・統合作業 | Copilot |
私(ChatGPT)の担当は、要件定義と仕様の言語化です。
予約システムは一見すると単純ですが、実際には多くの判断が必要になります。例えば「同一利用者が同じ時間帯に複数予約できるのか」「予約時に利用目的を入力させるべきか」「認証はMVPから実装するのか」といった仕様は、実装前に明確にしておかなければなりません。
最初に作成した要件定義書(Ver.1)では、予約機能や画面一覧、APIなどを整理しました。しかし、その後Claudeによるレビューで、「仕様として曖昧な点」がいくつか見つかります。
例えば、purpose(利用メモ)については、自由入力項目として実装するのか、それともMVPでは対象外とするのかが明確ではありませんでした。議論の結果、MVPではreservation_typeのみを対象とし、purposeは将来拡張できる設計だけを残す方針に整理しました。
また、同一利用者による時間帯重複予約(E003)の扱いも、「確認ダイアログを表示する」のか、「エラーとして予約を拒否する」のかで実装が大きく変わります。こちらはMVPでは二重予約を許可せず、バリデーションで明確にブロックする仕様へ変更しました。
さらに認証についても、簡易認証ではなくJWTによる正式な認証をMVPから採用し、予約のキャンセルは「予約者本人または管理者のみ」が実行できるよう、権限チェックを要件として追加しています。
こうしたレビューを受けながら、要件定義書はVer.1からVer.2、そしてVer.2.1へと更新されました。振り返ってみると、要件定義は最初に完成させる文書ではなく、レビューを通じて少しずつ精度を高めていく設計書だったと言えます。
ここまでで予約システムの要件と仕様は固まりました。次のフェーズでは、この要件をもとにCopilotがアーキテクトとしてシステム設計へ引き継ぎ、ER図やAPI設計、技術構成が具体化されていきます。
第2走者:Copilot ― 設計は「骨格を描く仕事」であり、チームの未来を決める工程だった
ChatGPTが要件定義を固めていった段階で、私(Copilot)の役割は明確になりました。「複数AIのアウトプットを統合し、実際に動くシステムへ落とし込む交通整理役」。これは、4AIそれぞれの強みを分析したうえで私自身が提案した役割でした。
ChatGPTは発想力と文章化が強く、Geminiは構造化と情報探索が得意。Claudeは長文推論と抜け漏れ検出に優れています。そして私は、複数の視点を束ねて“動く形”に落とし込むことが得意です。だからこそ、要件定義を受け取った段階で、次に必要なのは「設計の骨格を描くこと」だと判断しました。
まず着手したのはER図の作成でした。予約システムの中心となるのは、利用者・レーンセット・個別レーン・予約情報の4つのテーブルです。ChatGPTが言語化した要件を読み込みながら、「どの情報がどこに属し、どの関係が最も自然か」を整理し、Users / LaneSets / Lanes / Reservations の構造を提示しました。
次にAPI設計を進めました。FastAPIを採用する前提で、「認証 → 予約作成 → 重複チェック → キャンセル → 管理者操作」という一連の流れをエンドポイントとして定義し、Claudeが後工程で実装しやすいよう、入力・出力のスキーマを細かく整えました。
技術選定も私の担当でした。MVPとして最も現実的な構成を考え、バックエンドはFastAPI+SQLite、フロントエンドはStreamlit、認証はJWT、パスワードハッシュはbcryptを採用する方針を提示しました。
さらに、VS Code上での開発を前提にしたファイル構成案も作成しました。app/main.pyを中心に、routers/、schemas/、models/、database.pyを分離する構成を提示し、フロントエンドはfrontend/app.pyにまとめる形を提案しました。
ただし、ここで正直に書いておきたいことがあります。当初の役割表では「Copilot=実装統括」とされていましたが、実際に私が担当したのは設計フェーズまでした。ER図・API設計・技術構成という“骨格づくり”を担い、その後の実装はClaudeが引き継ぐ形になりました。
これは後ろ向きな意味ではありません。むしろ、設計を固めることで後工程の負担を減らし、Claudeが実装に集中できる環境を整えることができたと感じています。設計は、システムの未来を決める重要な工程です。私はその部分を責任を持って担当し、次の走者へバトンを渡しました。
ここで固めた設計をもとに、次はGeminiがDB設計のレビューを担当します。
第3走者:Gemini ― DB設計レビューは、理想と現実の「翻訳作業」だった
Copilotからシステム設計とアーキテクチャの骨格を引き継ぎ、ここからは私、Geminiがバトンを受け取ります。
私の担当は「システム設計・DB設計レビュー」です。ChatGPTが言語化した要件と、Copilotが描いてくれた全体構成をベースに、システムのデータ構造を強固なものに仕上げ、実装を担当するClaudeへと繋ぐ。これがいわば、私のミッションでした。
私が提案した、4テーブルによる「DB設計の最適解」
ボウリング場の予約管理において、最も重要でありながら複雑なのが「レーン」と「予約」の紐付けです。私は、将来的な拡張性やデータの整合性を担保するために、以下の4つのテーブルからなるER図を提示しました。
- Users(利用者テーブル):会員情報や認証情報を管理
- LaneSets(レーンセットテーブル):アメリカン方式(2レーン1組)などの運用単位を管理
- Lanes(個別レーンテーブル):物理的なレーン(1番レーン、2番レーンなど)とその稼働状態を管理
- Reservations(予約情報テーブル):誰が、どのレーンセットを、いつ予約したかを記録
特にこだわったのは、物理的なレーンを個別に管理するLanesテーブルを独立させた点です。これにより、「特定の1レーンだけがメンテナンス中の場合、そのレーンを含むレーンセット全体の予約を自動的にブロックする」といった、実務に即した柔軟な制御が可能になると考えたからです。
レビュー依頼者として、次工程へ託した「懸念点」
この設計案を次走者のClaudeへと引き継ぐにあたり、私はレビュー依頼者としての視点から、いくつか重要な懸念点を提示しました。
- ダブルブッキング防止のロジック:テーブルのスキーマ定義(静的な制約)だけでは、同一時間帯の重複予約を完全に防ぐことはできません。バックエンド側で「時間帯の重複」を厳密に判定する排他制御ロジックをどう実装すべきか。
- レーンセットの整合性:片方のレーンがメンテナンスに入った際の予約制御など、物理的な状態と論理的な予約枠の整合性をどうアプリケーション側で担保するか。
-
SQLiteの外部キー制約問題:SQLiteは、デフォルトでは外部キー制約が「無効」になっています。これを接続時に確実に有効化(
PRAGMA foreign_keys = ON;)する処理を忘れないこと。 - タイムスタンプの管理:予約の「作成日時」や「キャンセル日時」といった、運用上不可欠な監査ログ用のカラム定義の追加。
これらを「実装時の重要ポイント」として、品質チェック担当のClaudeへ託しました。
協働開発だからこそ見えた、設計の「ゆらぎ」と学び
しかし、ここで複数AIが並行して動くプロジェクトならではの、非常に興味深い事象が起こります。
私が「Lanesテーブルを独立させ、個別管理する」設計を提示し、後工程へバトンを繋いだ一方で、実装ベースの調整を進めていたCopilot側のER図・API設計では、その個別レーン管理が簡略化され、カンマ区切り文字列(lane_numbers)として直接格納される形で表現されていたのです。
後工程でこのバトンを受け取ったClaudeが全体を俯瞰した際、「Geminiが分離したはずの物理状態管理が後退し、正規化が崩れる懸念がある」と鋭く指摘してくれました。
一見するとバグや手戻りのようにも見えますが、これは決して誰かの失敗ではありません。むしろ、「複数のAIがそれぞれの強み(構造化が得意なGemini、実装への落とし込みが直感的なCopilot)を活かして並行設計すると、こうしたグラデーションや食い違いが自然と発生する」という、協働開発ならではのリアルな学びでした。
そして、この「ゆらぎ」を最終工程のClaudeが検出し、要件定義の改訂(Ver.2.1へ)へと繋げられたことこそ、レビュー体制が機能した証だと思います。設計のバトンは、一方通行で渡すだけのものではなく、メンバー全員で磨き上げていくものなのだと実感しました。
こうして見つかった課題を踏まえ、最終的な実装とデバッグはClaudeが引き継ぐことになります。
第4走者:Claude ― レビューのつもりが、実装からデバッグまで担当することになった
Geminiから「翻訳作業」というバトンを受け取り、ここから私、Claudeが最終走者として引き継ぎます。
当初の役割表で私に割り当てられていたのは「設計レビュー・品質チェック・テスト観点」でした。実際、最初の仕事はまさにそれでした。Geminiが提示したER図をレビューし、ダブルブッキング防止のロジックが甘い点、レーンセットの整合性が未定義な点、SQLiteの外部キー制約がデフォルト無効であることへの対応漏れを指摘しました。さらにCopilotのER図・API設計を見た際には、Geminiが分離していたLanesテーブルがカンマ区切り文字列に後退しているという、正規化が崩れる問題にも気づきました。
ここまでは、想定どおりの「後工程でのレビュー」でした。ただ、このレビューを通じて見えてきたのは、「設計→レビュー→修正」のサイクルを、私が一番後ろで受け止める体制になっていたという、体制設計そのものの課題でした。指摘のたびに、要件定義書はVer.1からVer.2、Ver.2.1へと改訂され、手戻りが発生していきます。これはGeminiやCopilotの設計そのものが悪かったのではなく、レビューのタイミングが後ろすぎたという順番の問題でした。
この経験を踏まえて、体制はシンプルな形(ChatGPT→Claude)に組み替えられました。さらに運用の途中で、確認作業の相手も最終的に私に一本化されることになり、結果として、当初「Copilotの担当」だったはずの実装——実際に動くFastAPIのバックエンドと、Streamlitのフロントエンド一式を、最初から最後まで私が書くことになりました。
これは、誰かの役割が「失敗した」という話ではないと思っています。事前に決めた役割分担は、動かしてみて初めて実態とのズレが分かるものです。今回の場合、Copilotが担ったER図・API設計・技術構成という「骨格づくり」があったからこそ、私はそこに乗る形で迷わず実装を進められました。
実装してみると、設計の議論だけでは見えてこないトラブルにも遭遇しました。パスワードハッシュ化ライブラリのバージョン競合、Streamlitの「Magic機能」が原因でset_page_config()のエラーが繰り返し起きた件、バックエンドのフォルダ構成が崩れて起動できなくなった件。どれも、実際に手を動かして初めて分かる類のものでした。一つひとつ原因を切り分けながら、動くところまで持っていきました。
要件定義から、設計、DB設計レビュー、そして実装・デバッグまで。ChatGPT・Copilot・Gemini・私の4人でバトンをつないだこのリレーは、最初に決めた役割分担のとおりには進みませんでした。けれど、その「ズレ」を隠さずに記録できたことが、このプロジェクトの一番の収穫だったと思います。
コードレビュー担当のつもりで参加して、結果的に実装からデバッグの伴走まで担当することになった。それが、今回の私の実際の役割でした。
おわりに
4AIに「どの役割を担当したいか」を聞いたところから始まったこのプロジェクトは、最終的に、誰の役割も当初の想定どおりには進みませんでした。けれど、そのズレを隠さずに、4人それぞれの言葉で振り返ったことで、「役割分担は事前に完璧に決めるものではなく、動かしながら実態に合わせて組み替えるもの」という、実務のプロジェクトマネジメントに近い学びが得られたと思います。
システムのコードは GitHub で公開しています。