0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Laravel+Github Copilot】マスタデータ管理の実装をAIに書かせる

Last updated at Posted at 2025-07-21

背景

これまでUnityゲームの一部データ管理をSaasで行っていましたが、バージョンアップでSDKに合わせた修正や若干やりたいことができなかったりと不便だと感じていたので、自前でサーバ側処理を用意することにしました。

マスタデータ管理は直接SQLを書かず、Laravelで管理用Webアプリを開発して管理していました。
なのでSaasで管理していたマスタデータを管理するための画面、アプリ処理、マイグレーションファイルを追加する必要があります。

…全部自分で作るの面倒だな。ということで、VSCodeでGithubCopilotに作ってもらうことにしました。
触り始めて数日程度なので、「こうしたら便利になるんだなぁ」という感覚のメモです。

準備するもの

まずはAIに作業してもらうためのプラグインや設定ファイルなどを用意します。

プラグイン

作業してくれるGitHub CopilotをVSCodeに導入します。
https://marketplace.visualstudio.com/items?itemName=GitHub.copilot

コードを書いたりコマンドを実行させるにはAgentモードを使用します。
Freeプランでもそこそこのコードを実装してくれるので、個人でのんびり開発している自分には十分な機能です。

【Freeプランの機能】※2025/7/21時点

  • 1か月で50件のリクエスト
  • 1か月で2000件コード補完
  • Claude 3.5 Sonnet、GPT-4.1 モデルを利用可能

参考

設定ファイル

今回はエンハンス作業として、プロジェクトで追加機能を実装させたりコードからドキュメントを作らせるという使い方がメインになります。そのため、Copilotに指示をする際、プロジェクトの構造や実装ルールなどをAIに教える必要があります。

プロンプト毎にコードの場所やコーディングルールを教えるのは面倒なので、リクエストの度に読み込んでほしい情報をカスタムインストラクションファイルとして用意します。

カスタムインストラクション

中身は以下のように書きます。決まったフォーマットはないですがマークダウンで記述します。
(現状、AIへの指示書はマークダウンが一番理解してもらえるらしい)

.github\copilot-instructions.md
# Copilot Instructions

# コードガイドライン
## PHP
- コメントは日本語で記述してください
- Controllerの基本的な役割は、リクエストフォームオブジェクトをRepositoryに渡し、Repositoryから返された値をレスポンスします
- Repositoryの基本的な役割は、Controllerから渡されたデータを使ってDB操作や処理を行います
- クライアントアプリ向けのAPIエンドポイントは「#file:routes\api.php」に追加してください
- データマスタ管理画面機能向けのエンドポイントは「#file:routes\web.php」に追加してください
- データマスタ管理画面用の処理と、クライアントアプリ向けAPI処理は共有せず、独立して実装するようにしてください。
- サーバサイド処理にはエラーハンドリングも実装してください
- マスタデータModelクラスは「#file:app\Http\Model\BaseMaster\MasterModel.php」を継承してください
- ルートパスはキャメル記法にしてください

## DB
- DBはMySQLです
- DB操作はEloquentで行います
- DBのマイグレーションはファイルは 「#file:database\migrations」で管理し、ロールバック関数も一緒に実装してください
- テーブルの主キーは`unsignedBigInteger`で定義し、複合キーは作成せず必ず一意なキーを用意してください
- テーブル名、カラム名は英語ワードをアンダースコア(_)でつなぐようにしてください
- マイグレーションファイルの生成は、`php artisan`コマンドで作成してください

# 設計ドキュメント
設計ドキュメントは「#file:document」で管理します。
テーブル構造やAPI一覧などはここも参照し、追加実装をした場合はドキュメントを更新してください。

# その他プロンプト参照
実装する機能によって、追加で以下のプロンプトファイルを参照してください。
- データ管理向け機能: #file:.github\prompts\implement-data-master.prompt.md
- クライアントアプリ向けAPI機能: #file:.github\prompts\agent-implement-api.prompt.md

ざっくりと、必ず伝えておきたい内容を記述します。
ファイルコンテキストとして#file:で参照してほしい他ドキュメントやフォルダを記載しています。

データ管理機能のほかに、Unity側からデータ操作を受け付けるAPIも同じプロジェクトに実装しているので、
実装する機能によって、追加で別々の指示を参照するように最後の方で記述していますが、
実際ここは別途プロンプトファイルを作成することで、それぞれに対応したコンテキストを渡せるようになると思います。

プロンプトファイル

データ管理機能実装とAPI機能実装で、呼び出すプロンプトファイルを個別に用意します。

プロンプトファイルはChatで/を入力すれば選択できますし、コマンドパレットでプロンプト実行からもファイルを指定して呼び出せます。
image.png

内容は以下のように記述しました。これはAPI機能実装用のプロンプトです。

.github\prompts\implement-api.prompt.md
---
mode: agent
---
${input:variableName}のデータ操作API機能を実装してください。

基本的な実装ルールは「#file:.github/copilot-instructions.md」の内容に従ってください。

# クライアントアプリ向けAPI機能実装
クライアントアプリから受け付けるAPI機能を実装する際は、以下のサーバサイドの実装とマイグレーションファイルを作成してください。
- サーバサイド:
  - Controllerクラス: #file:app\Http\Controllers\WebAPI
  - Repositoryクラス: #file:app\Http\Repository
  - Modelクラス: #file:app\Http\Model
  - ルート設定: #file:routes\api.php
- マイグレーションファイル: #file:database\migrations 

API処理でエラーが発生した場合、500ステータスを返すようにハンドリングしてください


# 要件
以下要件とクライアントアプリ向けAPI機能実装ルールで競合する内容がある場合、以下の要件を優先してください。

${input:optional("要件", "要件を記載してください。")}

有効化設定

作成したカスタムインストラクションファイル、プロンプトファイルを参照してもらうためVSCodeの設定を修正します。
以下を追記します。

.vscode\settings.json
  "github.copilot.chat.codeGeneration.instructions": [
    {
      "file": ".github/copilot-instructions.md"
    }
  ],
  "chat.promptFilesLocations": {
    ".github/prompts": true,
    "setup/**/prompts": false
  }

最近知りましたが、setting.jsonってワークスペースではなく直接作業ディレクトリを開いていないと反映されないんですね…。

できあがったもの

プロンプトファイルを使って作成してもらったAPI機能の動作を簡単に確認していきます。
ここで取得するマスタデータでは、ガチャマスタ⇒レアリティグループ⇒レアリティラインナップアイテムという構造になっています。

マスタデータ取得APIの実装(不完全)

プロンプトを指定して、マスタ取得API機能を実装してもらいます。
※すでにマスタ管理画面は実装してもらって、データも数個登録した状態です。
image.png

API動作確認

この時点でのAPIレスポンスを確認してみます。Postmanでapi.phpに追加されたAPIパスを呼び出してみます。
まだレアリティグループまでしか取得してくれません。

[
    {
        "gacha_id": 6,
        "gacha_name": "定期演奏会",
        "description": "キャラクターやアイテムを取得できます。",
        "start_at": null,
        "end_at": null,
        "created_at": "2025-07-21 10:53:14",
        "updated_at": "2025-07-21 10:53:14",
        "rarity_groups": [
            {
                "rarity_group_id": 9,
                "gacha_id": 6,
                "rarity": "R",
                "rate": 97.1,
                "created_at": "2025-07-21 10:53:14",
                "updated_at": "2025-07-21 10:53:14"
            },
            {
                "rarity_group_id": 10,
                "gacha_id": 6,
                "rarity": "SR",
                "rate": 2,
                "created_at": "2025-07-21 10:53:14",
                "updated_at": "2025-07-21 10:53:14"
            },
            {
                "rarity_group_id": 11,
                "gacha_id": 6,
                "rarity": "SSR",
                "rate": 0.7,
                "created_at": "2025-07-21 10:53:14",
                "updated_at": "2025-07-21 10:53:14"
            },
            {
                "rarity_group_id": 12,
                "gacha_id": 6,
                "rarity": "UR",
                "rate": 0.2,
                "created_at": "2025-07-21 10:53:14",
                "updated_at": "2025-07-21 10:53:14"
            }
        ]
    }
]

追加で、レアリティグループに紐づくラインナップアイテムも取得してもらうように修正を依頼します。
ここは通常のチャット上でのやり取りと同じように指示します。

image.png

修正後

修正後のAPIレスポンスを確認し、ガチャで排出されるレアリティグループ別のラインナップも取得できるようになりました。

[
    {
        "gacha_id": 1,
        "gacha_name": "定期演奏会",
        "description": "キャラクターやアイテムを取得できます。",
        "start_at": null,
        "end_at": null,
        "created_at": "2025-07-21 13:34:21",
        "updated_at": "2025-07-21 13:34:21",
        "rarity_groups": [
            {
                "rarity_group_id": 1,
                "gacha_id": 1,
                "rarity": "R",
                "rate": 97.1,
                "created_at": "2025-07-21 13:34:21",
                "updated_at": "2025-07-21 13:34:21",
                "lineups": [
                    {
                        "lineup_id": 1,
                        "rarity_group_id": 1,
                        "item_type": "ITEM",
                        "item_id": 123,
                        "rate": 1,
                        "created_at": "2025-07-21 13:35:51",
                        "updated_at": "2025-07-21 13:35:51"
                    },
                    {
                        "lineup_id": 2,
                        "rarity_group_id": 1,
                        "item_type": "ITEM",
                        "item_id": 123,
                        "rate": 1,
                        "created_at": "2025-07-21 13:44:29",
                        "updated_at": "2025-07-21 13:44:29"
                    },
                    {
                        "lineup_id": 3,
                        "rarity_group_id": 1,
                        "item_type": "ITEM",
                        "item_id": 123,
                        "rate": 1,
                        "created_at": "2025-07-21 13:44:37",
                        "updated_at": "2025-07-21 13:44:37"
                    },
                    {
                        "lineup_id": 4,
                        "rarity_group_id": 1,
                        "item_type": "ITEM",
                        "item_id": 123,
                        "rate": 1,
                        "created_at": "2025-07-21 13:52:45",
                        "updated_at": "2025-07-21 13:52:45"
                    }
                ]
            },
            {
                "rarity_group_id": 2,
                "gacha_id": 1,
                "rarity": "SR",
                "rate": 2,
                "created_at": "2025-07-21 13:34:21",
                "updated_at": "2025-07-21 13:34:21",
                "lineups": []
            },
            {
                "rarity_group_id": 3,
                "gacha_id": 1,
                "rarity": "SSR",
                "rate": 0.7,
                "created_at": "2025-07-21 13:34:21",
                "updated_at": "2025-07-21 13:34:21",
                "lineups": []
            },
            {
                "rarity_group_id": 4,
                "gacha_id": 1,
                "rarity": "UR",
                "rate": 0.2,
                "created_at": "2025-07-21 13:34:21",
                "updated_at": "2025-07-21 13:34:21",
                "lineups": []
            }
        ]
    }
]

おわりに

予めプロジェクトの情報を用意してそれを参照させることで、アーキテクト、コーディングルールに沿った
精度の高い実装をしてくれるためかなり使い勝手がよくなりました。

似たようなエラーを出して同じような修正を指示することも多かったので、そのあたりも
ナレッジや考慮ポイントとして記載しておくと今後の実装効率も上がるのではないでしょうか。

「実装内容は分かっているけど書くのが面倒」という時に、AIに任せてしまうのが今のところ個人的に良い付き合い方になっています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?