本記事は
【Advent Calendar 2025】
3日目の記事です。
🌟🎄
2日目
▶▶ 本記事 ▶▶
4日目
🎅🎁

はじめに
こんにちは、勝浦です。
みなさん、AIを業務に活用していますか?私はあまりできていません。。
ですが触りたい気持ちはとてもあるので、今回ブログを書くのをいい機会に少し遊んでみます。
業務ではRuby on Railsを使ったアプリをエンハンスすることが多いので、KiroもRailsが使えるのかどうか試してみたいと思います。
Kiro とは?
AWS 謹製のAI統合IDEです。
一番の特徴はなんといってもSpecモードでしょうか。
開発者はまず仕様を自然言語で入力し、それをAIエージェントが要件定義->設計->実装と各フェーズにわたり段階的に具体化を実施、最終的に落とし込まれた実装タスクリストを片付けてアプリケーションを構築してくれるというものです。
2025/7 の発表以降、新規ユーザーの登録が制限されていましたが、つい先日GAとなりました。
とりあえず使ってみよう
今回はSpecモードを使って会員情報を管理するWebアプリを作ってみます。

requirements.mdの作成
IDE右上の吹き出しをクリックすると会話セッションが開かれるので、Specモードを選択し以下の指示を与えました。

さっくり要件定義( requirements.md )を作成してくれました。
# 要件定義書 ## はじめに 本システムは、会員情報を管理するWebアプリケーションです。会員情報の登録、更新、削除、照会の基本機能を提供し、効率的な会員管理を実現します。 ## 用語集 - **会員管理システム**: 会員情報の登録、更新、削除、照会を行うWebアプリケーション - **会員情報**: 会員ID、氏名、メールアドレス、電話番号、登録日などの会員に関するデータ - **管理者**: 会員管理システムを操作するユーザー - **データベース**: 会員情報を永続的に保存するストレージ ## 要件 ### 要件1: 会員情報の登録 **ユーザーストーリー:** 管理者として、新しい会員情報を登録したい。これにより、新規会員をシステムに追加できる。 #### 受入基準 1. WHEN 管理者が会員登録フォームに必要な情報を入力して送信するとき、会員管理システムは新しい会員レコードをデータベースに保存しなければならない 2. THE 会員管理システムは会員IDを自動的に生成しなければならない 3. IF 必須項目が未入力の場合、会員管理システムはエラーメッセージを表示して登録を拒否しなければならない 4. IF メールアドレスが既に登録されている場合、会員管理システムは重複エラーメッセージを表示しなければならない 5. WHEN 会員登録が成功したとき、会員管理システムは成功メッセージを表示しなければならない ### 要件2: 会員情報の照会 **ユーザーストーリー:** 管理者として、登録されている会員情報を検索・閲覧したい。これにより、会員の詳細を確認できる。 #### 受入基準 1. THE 会員管理システムは全会員のリストを表示しなければならない 2. WHEN 管理者が検索条件を入力するとき、会員管理システムは条件に一致する会員情報を表示しなければならない 3. WHEN 管理者が特定の会員を選択するとき、会員管理システムはその会員の詳細情報を表示しなければならない 4. THE 会員管理システムは会員リストをページネーション形式で表示しなければならない 5. THE 会員管理システムは会員情報を氏名、登録日などでソートする機能を提供しなければならない ### 要件3: 会員情報の更新 **ユーザーストーリー:** 管理者として、既存の会員情報を更新したい。これにより、会員情報を最新の状態に保つことができる。 #### 受入基準 1. WHEN 管理者が会員情報を編集して保存するとき、会員管理システムは更新された情報をデータベースに保存しなければならない 2. IF 必須項目が削除された場合、会員管理システムはエラーメッセージを表示して更新を拒否しなければならない 3. IF 更新後のメールアドレスが他の会員と重複する場合、会員管理システムは重複エラーメッセージを表示しなければならない 4. WHEN 会員情報の更新が成功したとき、会員管理システムは成功メッセージを表示しなければならない 5. THE 会員管理システムは会員IDの変更を許可してはならない ### 要件4: 会員情報の削除 **ユーザーストーリー:** 管理者として、不要になった会員情報を削除したい。これにより、システムを整理できる。 #### 受入基準 1. WHEN 管理者が会員の削除を実行するとき、会員管理システムは確認ダイアログを表示しなければならない 2. WHEN 管理者が削除を確認したとき、会員管理システムは該当する会員レコードをデータベースから削除しなければならない 3. WHEN 会員削除が成功したとき、会員管理システムは成功メッセージを表示しなければならない 4. IF 削除対象の会員が存在しない場合、会員管理システムはエラーメッセージを表示しなければならない ### 要件5: データの検証とセキュリティ **ユーザーストーリー:** 管理者として、入力されたデータが正しい形式であることを保証したい。これにより、データの整合性を維持できる。 #### 受入基準 1. THE 会員管理システムはメールアドレスの形式を検証しなければならない 2. THE 会員管理システムは電話番号の形式を検証しなければならない 3. THE 会員管理システムは氏名の文字数制限を適用しなければならない 4. THE 会員管理システムはXSS攻撃を防ぐために入力値をサニタイズしなければならない 5. THE 会員管理システムはSQLインジェクション攻撃を防ぐためにパラメータ化クエリを使用しなければならない
各要件についてユーザーストーリーと受け入れ基準を示してくれていますね。
特に文句はないので、そのまま設計へすすめます。
design.mdの作成


ここでRailsを使って設計してほしいとお願いしました。

しっかり、対応してくれましたね。以下が生成された設計( design.md )になります
# 設計書
## 概要
会員管理システムは、Ruby on RailsのMVCアーキテクチャを採用したWebアプリケーションです。Railsの規約に従い、モデル、ビュー、コントローラーを明確に分離します。フロントエンドはRailsのビューテンプレート(ERB)とHotwire(Turbo + Stimulus)を使用し、データベースにはSQLiteを使用して会員情報を永続化します。
## アーキテクチャ
### システム構成
┌─────────────────────────────────────┐
│ ビュー層 (ERB) │
│ - 会員一覧画面 │
│ - 会員登録/編集フォーム │
│ - 会員詳細画面 │
│ + Hotwire (Turbo + Stimulus) │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ コントローラー層 │
│ - MembersController │
│ - ルーティング処理 │
│ - リクエスト/レスポンス処理 │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ モデル層 │
│ - Member モデル │
│ - バリデーション │
│ - ビジネスロジック │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ データベース (SQLite) │
│ - membersテーブル │
└─────────────────────────────────────┘
### 技術スタック
- **フレームワーク**: Ruby on Rails 7.1+
- **Ruby**: 3.2+
- **データベース**: SQLite3
- **フロントエンド**: Hotwire (Turbo + Stimulus)
- **ビューテンプレート**: ERB
- **スタイリング**: Tailwind CSS
- **テスト**: RSpec, FactoryBot
## コンポーネントとインターフェース
### データモデル
#### Member(会員)
# app/models/member.rb
class Member < ApplicationRecord
# 属性
# id: integer (主キー、自動生成)
# name: string (氏名、必須、1-100文字)
# email: string (メールアドレス、必須、ユニーク)
# phone: string (電話番号、必須、形式: XXX-XXXX-XXXX)
# created_at: datetime (登録日時、自動生成)
# updated_at: datetime (更新日時、自動更新)
end
### ルーティング
Railsの RESTful ルーティングを使用します。
# config/routes.rb
Rails.application.routes.draw do
root 'members#index'
resources :members
end
#### ルート一覧
| HTTPメソッド | パス | アクション | 用途 |
|-------------|------|-----------|------|
| GET | /members | index | 会員一覧表示 |
| GET | /members/:id | show | 会員詳細表示 |
| GET | /members/new | new | 会員登録フォーム表示 |
| POST | /members | create | 会員登録処理 |
| GET | /members/:id/edit | edit | 会員編集フォーム表示 |
| PATCH/PUT | /members/:id | update | 会員更新処理 |
| DELETE | /members/:id | destroy | 会員削除処理 |
#### クエリパラメータ(一覧表示)
- `page`: ページ番号(デフォルト: 1)
- `search`: 検索キーワード(氏名、メールアドレスで検索)
- `sort`: ソート項目(name, email, created_at)
- `direction`: ソート順(asc, desc)
### Railsディレクトリ構成
app/
├── controllers/
│ ├── application_controller.rb
│ └── members_controller.rb # 会員コントローラー
├── models/
│ └── member.rb # 会員モデル
├── views/
│ ├── layouts/
│ │ └── application.html.erb # レイアウトテンプレート
│ └── members/
│ ├── index.html.erb # 会員一覧
│ ├── show.html.erb # 会員詳細
│ ├── new.html.erb # 会員登録フォーム
│ ├── edit.html.erb # 会員編集フォーム
│ └── _form.html.erb # フォーム部分テンプレート
├── helpers/
│ └── members_helper.rb # ビューヘルパー
└── javascript/
└── controllers/
└── member_controller.js # Stimulusコントローラー
config/
├── routes.rb # ルーティング定義
└── database.yml # データベース設定
db/
├── migrate/
│ └── XXXXXX_create_members.rb # マイグレーションファイル
└── seeds.rb # 初期データ
spec/
├── models/
│ └── member_spec.rb # モデルテスト
├── requests/
│ └── members_spec.rb # リクエストテスト
└── factories/
└── members.rb # テストデータファクトリ
## データモデル
### データベーススキーマ
#### membersテーブル
CREATE TABLE members (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL CHECK(length(name) >= 1 AND length(name) <= 100),
email TEXT NOT NULL UNIQUE,
phone TEXT NOT NULL,
registered_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE INDEX idx_members_email ON members(email);
CREATE INDEX idx_members_name ON members(name);
### バリデーションルール
#### 会員情報バリデーション
# app/models/member.rb
class Member < ApplicationRecord
validates :name, presence: { message: "氏名は必須です" },
length: { maximum: 100, message: "氏名は100文字以内で入力してください" }
validates :email, presence: { message: "メールアドレスは必須です" },
uniqueness: { message: "このメールアドレスは既に登録されています" },
format: { with: URI::MailTo::EMAIL_REGEXP, message: "有効なメールアドレスを入力してください" }
validates :phone, presence: { message: "電話番号は必須です" },
format: { with: /\A\d{3}-\d{4}-\d{4}\z/, message: "電話番号は XXX-XXXX-XXXX の形式で入力してください" }
end
## エラーハンドリング
### エラーレスポンス形式
{
"error": {
"code": string,
"message": string,
"details": object (optional)
}
}
### エラーコード一覧
| コード | 説明 | HTTPステータス |
|--------|------|----------------|
| VALIDATION_ERROR | 入力値が不正 | 400 |
| DUPLICATE_EMAIL | メールアドレスが重複 | 409 |
| MEMBER_NOT_FOUND | 会員が見つからない | 404 |
| DATABASE_ERROR | データベースエラー | 500 |
| INTERNAL_ERROR | 内部サーバーエラー | 500 |
### エラーハンドリング戦略
1. **バリデーションエラー**: Zodスキーマでリクエストを検証し、エラーメッセージをクライアントに返す
2. **データベースエラー**: SQLiteエラーをキャッチし、適切なエラーメッセージに変換
3. **重複エラー**: UNIQUE制約違反を検出し、ユーザーフレンドリーなメッセージを返す
4. **404エラー**: 存在しない会員IDへのアクセスを検出
5. **XSS対策**: 入力値をエスケープ処理
6. **SQLインジェクション対策**: パラメータ化クエリを使用
## テスト戦略
### テストレベル
1. **単体テスト**
- バリデーション関数のテスト
- リポジトリ層のテスト(モックDB使用)
- サービス層のビジネスロジックテスト
2. **統合テスト**
- APIエンドポイントのテスト
- データベース操作を含むエンドツーエンドテスト
3. **E2Eテスト**
- フロントエンドからバックエンドまでの主要フローテスト
- 会員登録→照会→更新→削除の一連の操作
### テストツール
- **テストフレームワーク**: RSpec
- **テストデータ**: FactoryBot
- **モック**: RSpec Mocks
- **システムテスト**: Capybara + Selenium(オプション)
### テストカバレッジ目標
- コアビジネスロジック: 80%以上
- API エンドポイント: 主要な成功/失敗パスをカバー
- バリデーション: 全パターンをカバー
## セキュリティ考慮事項
1. **入力検証**: すべての入力をモデルレベルで検証
2. **SQLインジェクション対策**: ActiveRecordのパラメータ化クエリを使用
3. **XSS対策**: ERBの自動エスケープ機能を活用
4. **CSRF対策**: Railsのビルトイン CSRF トークン保護
5. **マスアサインメント対策**: Strong Parameters の使用
6. **セッション管理**: Railsのセキュアなセッション管理
## パフォーマンス考慮事項
1. **データベースインデックス**: email、nameカラムにインデックスを作成
2. **ページネーション**: 大量データ対応のためのページング実装
3. **キャッシング**: 頻繁にアクセスされるデータのキャッシュ(将来的な拡張)
エラーまわりの設計やテスト戦略まで考えてくれています。(すごい)
これでよさそうですので、次に実装タスクリストを作成してもらいます。
task.mdの作成、実装開始そして完成


今回時間もあるのでオプション含めて全部やってもらいましょう。

作成されたタスクリスト( task.md ) をIDE上で開いて、表示されている「Start Task」を上から順番にポチポチしていきます。
# 実装タスクリスト
- [ ] 1. Railsプロジェクトのセットアップ
- 新しいRailsアプリケーションを作成(`rails new member_management --database=sqlite3 --css=tailwind`)
- 必要なgemをGemfileに追加(rspec-rails, factory_bot_rails等)
- RSpecの初期設定を実行
- _要件: すべての要件の基盤_
- [ ] 2. 会員モデルとデータベースの作成
- [ ] 2.1 マイグレーションファイルの作成
- membersテーブルのマイグレーションを生成(name, email, phone カラム)
- emailカラムにユニークインデックスを追加
- nameカラムにインデックスを追加
- マイグレーションを実行してテーブルを作成
- _要件: 1.1, 1.2, 2.1, 3.1, 4.2_
- [ ] 2.2 Memberモデルの実装
- Memberモデルクラスを作成
- バリデーションを実装(name: 必須・最大100文字、email: 必須・形式・ユニーク、phone: 必須・形式)
- カスタムエラーメッセージを日本語で設定
- _要件: 1.3, 1.4, 3.2, 3.3, 5.1, 5.2, 5.3_
- [ ] 2.3 モデルのテスト作成
- FactoryBotでMemberファクトリを作成
- バリデーションのテストを作成(正常系・異常系)
- ユニーク制約のテストを作成
- _要件: 1.3, 1.4, 3.2, 3.3, 5.1, 5.2, 5.3_
- [ ] 3. 会員コントローラーの実装
- [ ] 3.1 MembersControllerの基本構造作成
- MembersControllerを生成
- 7つのRESTfulアクション(index, show, new, create, edit, update, destroy)のスケルトンを作成
- Strong Parametersを実装(member_params メソッド)
- _要件: 1.1, 2.1, 3.1, 4.1_
- [ ] 3.2 会員一覧機能の実装(indexアクション)
- 全会員を取得してビューに渡す
- ページネーション機能を実装(kaminari gem使用)
- 検索機能を実装(氏名・メールアドレスで部分一致検索)
- ソート機能を実装(氏名、登録日でソート可能)
- _要件: 2.1, 2.2, 2.4, 2.5_
- [ ] 3.3 会員詳細表示機能の実装(showアクション)
- 指定されたIDの会員を取得
- 会員が見つからない場合は404エラーを表示
- _要件: 2.3_
- [ ] 3.4 会員登録機能の実装(new, createアクション)
- newアクションで空のMemberオブジェクトを作成
- createアクションで会員を保存
- 保存成功時は成功メッセージを表示して詳細画面にリダイレクト
- 保存失敗時はエラーメッセージを表示してフォームを再表示
- _要件: 1.1, 1.2, 1.3, 1.4, 1.5_
- [ ] 3.5 会員更新機能の実装(edit, updateアクション)
- editアクションで既存の会員データを取得
- updateアクションで会員情報を更新
- 更新成功時は成功メッセージを表示して詳細画面にリダイレクト
- 更新失敗時はエラーメッセージを表示してフォームを再表示
- 会員IDの変更を防止
- _要件: 3.1, 3.2, 3.3, 3.4, 3.5_
- [ ] 3.6 会員削除機能の実装(destroyアクション)
- 指定されたIDの会員を削除
- 削除成功時は成功メッセージを表示して一覧画面にリダイレクト
- 会員が見つからない場合はエラーメッセージを表示
- _要件: 4.2, 4.3, 4.4_
- [ ] 3.7 コントローラーのテスト作成
- 各アクションのリクエストテストを作成
- 正常系・異常系のテストケースを網羅
- _要件: すべての要件_
- [ ] 4. ビューテンプレートの作成
- [ ] 4.1 レイアウトとナビゲーションの作成
- application.html.erbにヘッダーとナビゲーションを追加
- フラッシュメッセージ表示エリアを追加
- Tailwind CSSでスタイリング
- _要件: すべての要件_
- [ ] 4.2 会員一覧画面の作成(index.html.erb)
- 会員リストをテーブル形式で表示
- 検索フォームを実装
- ソートリンクを実装
- ページネーションコントロールを表示
- 新規登録ボタンを配置
- 各会員に詳細・編集・削除リンクを配置
- _要件: 2.1, 2.2, 2.4, 2.5_
- [ ] 4.3 会員詳細画面の作成(show.html.erb)
- 会員情報を見やすく表示
- 編集・削除・一覧に戻るボタンを配置
- _要件: 2.3_
- [ ] 4.4 会員フォームの作成(_form.html.erb部分テンプレート)
- 氏名、メールアドレス、電話番号の入力フィールドを作成
- バリデーションエラーメッセージを表示
- フォームヘルパーを使用してCSRF対策を実装
- プレースホルダーとラベルを日本語で設定
- _要件: 1.1, 1.3, 3.1, 3.2, 5.1, 5.2, 5.3, 5.4_
- [ ] 4.5 会員登録画面の作成(new.html.erb)
- フォーム部分テンプレートを読み込み
- ページタイトルと送信ボタンを配置
- _要件: 1.1_
- [ ] 4.6 会員編集画面の作成(edit.html.erb)
- フォーム部分テンプレートを読み込み
- ページタイトルと更新ボタンを配置
- 会員IDは表示のみ(編集不可)
- _要件: 3.1, 3.5_
- [ ] 4.7 削除確認機能の実装
- 削除リンクにdata-turbo-methodとdata-turbo-confirmを設定
- 確認ダイアログのメッセージを日本語で設定
- _要件: 4.1_
- [ ] 5. ルーティングの設定
- config/routes.rbにresources :membersを追加
- ルートパスを会員一覧画面に設定
- _要件: すべての要件_
- [ ] 6. エラーハンドリングとセキュリティの強化
- [ ] 6.1 エラーページのカスタマイズ
- 404エラーページを日本語化
- 500エラーページを日本語化
- _要件: 4.4_
- [ ] 6.2 セキュリティ設定の確認
- Strong Parametersが正しく機能することを確認
- CSRF保護が有効であることを確認
- XSS対策(ERBの自動エスケープ)が機能することを確認
- SQLインジェクション対策(ActiveRecordのパラメータ化クエリ)を確認
- _要件: 5.4, 5.5_
- [ ] 7. 初期データとシードの作成
- db/seeds.rbにサンプル会員データを追加
- rails db:seedコマンドで初期データを投入できるようにする
- _要件: 開発・テスト用_
- [ ] 8. システムテストの作成
- Capybaraを使用したE2Eテストを作成
- 会員登録→照会→更新→削除の一連のフローをテスト
- _要件: すべての要件_
- [ ] 9. 最終確認と調整
- すべての機能が要件を満たしているか確認
- UIの使いやすさを確認
- エラーメッセージが適切に表示されるか確認
- レスポンシブデザインの確認
- _要件: すべての要件_

新しい会話セッション上で進行状況を逐次報告してもらいながら、タスクを進行します。
今回ここで問題があり、自分のPC上にデフォルトで入っているRubyのバージョンが古く、設計にあるバージョンのRailsをインストールできませんでした。
それでもKiroは力技でRailsもどきのディレクトリ構成を作ろうとしたので、一旦それを止めてRubyのインストールから指示します。

うまくいきました。この後はとくに引っかかることもなく、こちらはいくつか承認ボタンを押すだけでアプリが作成されました。
下はローカルで起動したときのTOPページです。

ただE2Eテストで1件失敗しているものがありました。

画面を小さくすると列項目が消えているんですね。
そういえば最後のレスポンシブデザインの修正のときにテストしていなかったな。。
ということで修正を指示します。


うまくいきました。E2Eテストもパスしています。
完成までにかかった時間
会話セッションの最後に所要時間が記録されているので集計してみました。合計で2時間弱という結果でした。私が自力でやると要件定義を完成させるのすら難しそうな時間ですね。。
- requirements.md作成開始からtask.md作成完了まで:43分
- task.mdにある全タスク完了まで:55分
使ってみての感想
いいなと思った点
- やはり少ない労力で動くアプリをつくれる体験は素晴らしいですね。Railsを使用したアプリがちゃんと作れるのか、若干不安はありましたが難なくこなしてくれました。
- 最終成果物にSECURITY.mdとVERIFICATION_CHECKLIST.mdという2つのファイルが含まれていました。前者はどのようなセキュリティ対策がアプリに施され、本番環境にアプリを公開するときは追加でどのような対策をすべきか記載されています。後者はすべてのタスク完了後にどのようなチェックをしたか、また改善の余地がある点はなにか、ということが一覧で記載されています。文章でさっと確認できる形で出力してくれるのは気がきいていますね。
- 間違いやいけてないな〜と思った点に関してはvibeコーディング的にも修正できるのもいいですね。今回はデフォルトのオートパイロットモードでさっと作ってもらいましたが、監視モードにすれば1STEPごとに自分の意見を反映させることができそうです。
改善点
- 最初のRailsインストールが失敗した件、ここは環境情報を記載しておいたステアリングファイルを設定しておけば事前に防げましたね。
- ステアリングファイルについては弊社のブログが参考になります!
tech.nri-net.com
ステアリングファイルは、Kiroに永続的な知識や指示を提供するマークダウンファイルです。.kiro/steering/ディレクトリにマークダウンファイルを配置するだけで設定でき、Kiroの振る舞いや回答スタイルをプロジェクトやチームの要件に合わせてカスタマイズできます。チーム共通のコーディング規約、プロジェクト固有のルール、使用技術のガイドライン、レビュー基準などを設定することで、Kiroがプロジェクトの文脈を永続的に記憶し、一貫性のあるサポートを提供できるようになります。
- ステアリングファイルについては弊社のブログが参考になります!
tech.nri-net.com
- 最後に修正後、E2Eテストができていなかった件、ファイルの修正後テストを必ず実行するAgent Hooksを設定しておくことで改善できそうですね。
- Agent Hooksについても上のブログが参考になります!
Agent Hooksは、ファイル保存やボタンクリックなどの特定のイベントをトリガーにKiroを自動実行する機能です。コマンドパレットから「Open Kiro Hook UI」を選択して設定でき、例えば*.mdファイルの保存時に「保存したファイルの内容を要約して」といった処理を自動実行できます。
- Agent Hooksについても上のブログが参考になります!
- あらためて見返すとdesign.mdに書いてある内容と微妙にちがった実装をしている箇所があります(目についたのはファイルネーミング)。このあたりも実装後にあらためてdesign.mdと突合するAgent Hooksを設定しておくと整合性がとれていくのかもしれません。
次やってみるなら
- 今回はRailsを利用できるか、というところに主観があったのでシンプルな構成のアプリ作成を依頼しましたが、もう少し複雑な要件をあたえるとどこまでできるのかは見てみたいところです。
- 現状は徐々に要件を与えてシステムを拡張していくvibeコーディング的な実装のほうが、軌道修正も容易ですので感覚的には良さそうな気もします。