本記事の内容は私的に実施したものであり、個人の感想です。如何なる組織・製品を代表するものでもありません。
Summary
- Excel VBAで作成した就活管理シートの仕様書作成・移行計画・実装をすべてIBM Bobに任せ、約1時間で概ね移行が完了した
- 移行だけでなく途中からの新機能追加も問題なく対応。壁打ちを重ねながらも無料トライアル(40 Bob coin)の範囲に収まった
- BobはTodoリスト提示・モード切り替え提案・情報不足している要件定義の追加提案・CI/CD導入提案など、単なるコーディング補助を超えてSDLC全体をカバーする設計になっている
やらないこと
- Bobと他AIエージェントの詳細な性能比較
- 各技術スタック(React、Dexie.jsなど)の詳細な解説
- 完成アプリのデプロイ・公開
本記事における課題
私が学生の頃、就職活動中にExcel VBAで作成した企業研究管理シートを題材に、IBM Bob へWebアプリケーションヘのモダナイゼーションを依頼した。
移行イメージ
移行前
VBAを活用し、企業研究の入力内容を一覧したり、PDF出力・印刷したりできる。
移行後のアプリ
移行前のアプリが持っていた機能に加え、選考フェーズごとの記録追加、データのインポート・エクスポートができるようになっている。
やったこと
Bobへの依頼内容
今回、私自身が行った作業は大きく以下の3ステップのみである。
-
既存資産を渡して仕様書を作成させた
VBAソースコードとスクリーンショットから、まずは現物の仕様書を作成して。と依頼した。BobはVBAのソースコードとスクリーンショットを読み取り、現物ベースの仕様書を自動生成した。 -
仕様書をベースに移行計画を立ててもらった
生成された仕様書を確認した上で、そのまま移行計画の立案をBobに依頼した。 -
移行計画に従って実装させ、途中で新機能を追加させた
計画書を承認し、実装をBobに委ねた。移行が進む中で選考記録機能を新規に追加させるなど、壁打ちしながら育てていった。
この3ステップで、ソースコードとスクリーンショットを渡してから約1時間で概ね移行が完了した。
Bobが生成した現行仕様書(抜粋):
# 企業研究データベース 現行システム仕様書
## 1. システム概要
### 1.1 目的
就職活動における企業研究情報を一元管理し、効率的な企業分析と情報整理を支援するExcel VBAベースの管理システム。
### 1.2 システム構成
- **プラットフォーム**: Microsoft Excel + VBA
- **ファイル構成**: 単一のExcelブック(.xlsm形式)
- **バージョン管理**: 日付ベースの自動バージョニング(ver.YY.MM.DD形式)
### 1.3 対象ユーザー
就職活動中の学生・求職者
---
## 2. ワークシート構成
### 2.1 シート一覧
| シート名 | 用途 | 備考 |
|---------|------|------|
| データベース | 企業一覧の集約表示 | メインインデックス |
| _Template | 企業研究シートのテンプレート | 非表示・コピー元 |
| 企業別シート | 個別企業の詳細情報 | 動的に追加 |
### 2.2 データベースシート
#### レイアウト構成
- **ヘッダー部**: 操作ボタン群とバージョン表示
- **データ部**: 企業情報の一覧表
#### データ項目
| 列 | 項目名 | データ型 | 説明 |
|----|--------|----------|------|
| A | 企業ID | 数値 | 自動採番(1から連番) |
| B | 企業名 | 文字列 | 正式な企業名称(ハイパーリンク付き) |
| C | 本社 | 文字列 | 本社所在地 |
| D | 設立年 | 日付/文字列 | 設立年月日 |
| E | 資本金 | 文字列 | 日本語表記(億・万円単位) |
| F | 売上高 | 文字列 | 日本語表記(億・万円単位) |
| G | 平均年齢 | 数値 | 従業員の平均年齢 |
| H | 平均年収 | 数値 | 従業員の平均年収 |
| I | 初任給 | 数値 | 新卒初任給 |
#### 操作ボタン
- **シート作成**: 新規企業シートの作成
- **データ更新**: 各企業シートから情報を再読み込み
- **バージョン付与**: 現在日付でバージョン更新
- **PDF出力**: 選択企業のPDF出力
- **シート印刷**: 選択企業の印刷プレビュー
### 2.3 企業研究シート(テンプレート)
#### 基本情報セクション
| セル位置 | 項目名 | 説明 |
|---------|--------|------|
| D1 | 企業ID | 自動採番 |
| B3 | 企業名 | 正式名称 |
| B6 | 本社 | 本社所在地 |
| B8 | 設立年 | 設立年月日 |
| B10 | 資本金 | 資本金額 |
| B12 | 売上高 | 年間売上高 |
| B14 | 平均年齢 | 従業員平均年齢 |
| B15 | 平均年収 | 従業員平均年収 |
| B16 | 初任給 | 新卒初任給 |
#### 自由記述セクション
- **企業概要**: 事業内容の概要説明
- **企業理念**: 企業の理念・ビジョン
- **事業内容**: 詳細な事業説明
- **本社**: 本社情報
- **その他主な事業所**: 支社・支店情報
- **設立年**: 設立の経緯
- **従業員数**: 従業員規模
- **資本金**: 資本構成
- **親会社**: グループ企業情報
- **売上高**: 業績推移
- **営業利益**: 収益性
- **平均年齢**: 年齢構成
- **平均年収**: 給与水準
- **初任給**: 新卒待遇
- **業界内での立ち位置やシェア**: 市場ポジション
- **採用競合と比べた企業の強み、弱み、違い、特徴など**: 競合分析
- **成長性**: 将来性評価
- **企業の課題と解決・現状**: 課題認識
- **興味を持った企業・大学時代に学んだことがどのように活かせるか**: 志望動機
- **入社後に挑戦したいこと、自分の将来像、望みたい部署など**: キャリアビジョン
- **インターン参加の有無**: インターン経験
- **インターンの内容**: インターン詳細
- **説明会・セミナー、職場見学、インターンなど、社員やOB/OGと話して気付いたこと**: 接触記録
- **感想、ニュース等情報まとめなど**: その他メモ
---
## 3. 主要機能
### 3.1 企業シート管理機能
#### 3.1.1 新規企業シート作成([`make_new()`](original/main.vb:53))
**処理フロー**:
```mermaid
graph TD
A[開始] --> B[企業名入力ダイアログ表示]
B --> C[テンプレートシートをコピー]
C --> D[シート名を企業名に変更]
D --> E[企業IDを自動採番]
E --> F[データベースシートに企業情報を追加]
F --> G[ハイパーリンク設定]
G --> H[終了]
```
**機能詳細**:
- テンプレートシートを最後尾にコピー
- 企業IDは「総シート数 - 3」で自動計算
- データベースシートに企業名とIDを自動登録
- 企業名セルにハイパーリンクを自動設定
**制約事項**:
- 企業名の重複チェックなし
- 入力キャンセル時の処理なし
#### 3.1.2 データ更新機能([`read_Info()`](original/main.vb:69))
**処理フロー**:
```mermaid
graph TD
A[開始] --> B[全企業シートをループ]
B --> C[各シートから基本情報を読み取り]
C --> D[金額データを日本語形式に変換]
D --> E[データベースシートに書き込み]
E --> F[ハイパーリンク再設定]
F --> G{次のシートあり?}
G -->|Yes| B
G -->|No| H[終了]
```
**読み取り対象データ**:
- 企業ID、企業名、本社、設立年
- 資本金、売上高(金額変換処理あり)
- 平均年齢、平均年収、初任給
**データ変換処理**:
- [`conv_Num()`](original/main.vb:12)関数による金額の日本語表記変換
- 「億」「万」「円」単位での表示
### 3.2 ナビゲーション機能
#### 3.2.1 シート移動
- **トップへ移動**([`go_Top()`](original/main.vb:113)): データベースシートへ移動
- **前へ移動**([`go_Back()`](original/main.vb:117)): 1つ前のシートへ移動
- **次へ移動**([`go_Next()`](original/main.vb:121)): 1つ次のシートへ移動
**制約事項**:
- シート範囲外への移動時のエラーハンドリングなし
### 3.3 出力機能
#### 3.3.1 PDF出力([`print_Pdf()`](original/main.vb:154))
**処理フロー**:
```mermaid
graph TD
A[開始] --> B[企業選択ダイアログ表示]
B --> C[選択企業のシートを特定]
C --> D[ページ設定を構成]
D --> E[PDF出力パス生成]
E --> F[PDFファイル出力]
F --> G[完了メッセージ表示]
G --> H[終了]
```
**ページ設定**:
- 印刷範囲: A1:D28
- 向き: 縦(Portrait)
- ページ収め: 横1ページ × 縦2ページ
- ヘッダー右: バージョン情報
- フッター中央: ページ番号(現在/総数)
**出力先**: ブックと同じディレクトリに「企業名.pdf」
#### 3.3.2 印刷プレビュー([`print_Paper()`](original/main.vb:180))
**処理内容**:
- PDF出力と同じページ設定
- 印刷プレビュー画面を表示
- 実際の印刷はユーザーが実行
### 3.4 バージョン管理機能
#### 3.4.1 バージョン生成([`get_Version()`](original/main.vb:125))
- 形式: `ver.YY.MM.DD`
- 現在日付から自動生成
- 例: `ver.18.01.27`
#### 3.4.2 バージョン書き込み([`write_Version()`](original/main.vb:150))
- データベースシートのC1セルに書き込み
### 3.5 金額変換機能
#### 3.5.1 日本語金額表記変換([`conv_Num()`](original/main.vb:12))
**入力形式**:
- 数値文字列(カンマ区切り可)
- 日本語単位付き(億、千万、百万、万、千、円)
- 全角・半角混在可
- 特殊値: "N/A"、空文字列
**変換処理**:
1. 全角→半角変換
2. カンマ除去
3. 日本語単位を数式に変換(例: "億" → "* 100000000 +")
4. Evaluate関数で計算
5. 結果を日本語表記に再変換
**出力形式**:
- 兆円単位: "X兆Y億Z万W円"
- 億円単位: "X億Y万Z円"
- 万円単位: "X万Y円"
**制約事項**:
- 小数点以下は切り捨て
- 負の値は未対応
---
## 4. ユーザーインターフェース
### 4.1 企業選択ダイアログ(UserForm1)
#### 4.1.1 構成要素
- **ComboBox1**: 企業名選択ドロップダウン
- **CommandButton1**: 決定ボタン
- **CommandButton2**: キャンセルボタン
#### 4.1.2 動作仕様
**初期化処理**([`UserForm_Initialize()`](original/form.vb:3)):
- データベースシートから企業名を読み込み
- ComboBoxに企業名リストを設定
**決定ボタン処理**([`CommandButton1_Click()`](original/form.vb:11)):
- 選択された企業のインデックスを取得
- 未選択時はエラーメッセージ表示
- 選択時はグローバル変数`ret_ID`に格納
**キャンセルボタン処理**([`CommandButton2_Click()`](original/form.vb:26)):
- キャンセルメッセージ表示
- フォームを閉じる
**フォームクローズ処理**([`UserForm_QueryClose()`](original/form.vb:31)):
- 決定ボタン以外でのクローズ時はアプリケーション終了
---
## 5. データ仕様
### 5.1 データ型定義
| 項目 | データ型 | 形式 | 必須 | 備考 |
|------|----------|------|------|------|
| 企業ID | Integer | 数値 | ○ | 自動採番 |
| 企業名 | String | 文字列 | ○ | 255文字以内 |
| 本社 | String | 文字列 | - | 住所形式 |
| 設立年 | Date/String | 日付 | - | 和暦・西暦混在可 |
| 資本金 | String | 日本語金額 | - | 億・万円単位 |
| 売上高 | String | 日本語金額 | - | 億・万円単位 |
| 平均年齢 | Double | 数値 | - | 小数点1桁 |
| 平均年収 | Long | 数値 | - | 整数(円) |
| 初任給 | Long | 数値 | - | 整数(円) |
### 5.2 金額表記ルール
#### 入力可能形式
- 数値のみ: `1000000`
- カンマ区切り: `1,000,000`
- 日本語単位: `100万円`、`1億円`
- 混在形式: `1億2,000万円`
- 特殊値: `N/A`(データなし)
#### 出力形式
- 1兆円以上: `X兆Y億Z万W円`
- 1億円以上: `X億Y万Z円`
- 1万円以上: `X万Y円`
- 1万円未満: 表示なし(0円扱い)
### 5.3 データ整合性
**現状の制約**:
- 企業名の重複チェックなし
- データ型バリデーションなし
- 必須項目チェックなし
- 参照整合性チェックなし
(中略)
Bobが生成した移行計画書(抜粋):
# 企業研究データベース 移行システム仕様書
## 1. 移行システム概要
### 1.1 基本方針
現行のExcel VBAベースのシステムを、モダンなWebアプリケーションに移行します。
**主要な特徴**:
- ✅ **Webブラウザのみで動作**: インストール不要
- ✅ **PWA対応**: スマートフォンのホーム画面に追加可能
- ✅ **クライアントサイド完結**: サーバー不要、個人環境でデータ管理
- ✅ **オフライン対応**: インターネット接続不要で動作
- ✅ **プライバシー重視**: データは各ユーザーのブラウザにのみ保存
- ✅ **クロスプラットフォーム**: Windows/Mac/Linux/iOS/Android対応
### 1.2 システム要件
#### ユーザー要件
- モダンなWebブラウザ(Chrome、Firefox、Edge、Safari最新版)
- JavaScript有効化
- LocalStorage/IndexedDB対応ブラウザ
#### 非要件(不要なもの)
- ❌ サーバーのセットアップ
- ❌ データベースのインストール
- ❌ ユーザー登録・ログイン
- ❌ インターネット接続(初回アクセス後)
---
## 2. アーキテクチャ設計
### 2.1 システム構成
```
┌─────────────────────────────────────────┐
│ ユーザー環境(ブラウザ) │
├─────────────────────────────────────────┤
│ ┌─────────────────────────────────┐ │
│ │ React 18 + TypeScript │ │
│ │ (SPA フロントエンド) │ │
│ └─────────────────────────────────┘ │
│ ↓ ↓ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ LocalStorage │ │ IndexedDB │ │
│ │ (設定情報) │ │ (企業データ) │ │
│ └──────────────┘ └──────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────┐ │
│ │ File System Access API │ │
│ │ (インポート/エクスポート) │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────┘
↑ 初回アクセス時のみ
┌─────────────────────────────────────────┐
│ 静的ホスティング(CDN) │
│ GitHub Pages / Netlify / Vercel │
│ HTML / CSS / JavaScript (React) │
└─────────────────────────────────────────┘
```
### 2.2 技術スタック
#### フロントエンド
| カテゴリ | 採用技術 | 理由 |
|---------|---------|------|
| フレームワーク | **React 18+** | エコシステムが豊富、TypeScript統合が優れている |
| 言語 | **TypeScript** | 型安全性、開発効率向上 |
| UIライブラリ | **Tailwind CSS** | ユーティリティファースト、カスタマイズ性が高い |
| 状態管理 | **Zustand** | シンプル、軽量、学習コストが低い |
| ルーティング | **React Router v6** | 標準的、ドキュメントが充実 |
| フォーム管理 | **React Hook Form** | パフォーマンスが良い、バリデーション統合 |
| バリデーション | **Zod** | TypeScriptとの相性が良い、型推論 |
#### データ管理
| 用途 | 技術 | 容量制限 |
|------|------|---------|
| 設定情報 | LocalStorage | 5-10MB |
| 企業データ | IndexedDB | 数百MB〜数GB |
| ファイル操作 | File System Access API | 制限なし |
#### ビルド・デプロイ
| カテゴリ | 採用技術 | 理由 |
|---------|---------|------|
| ビルドツール | **Vite** | 高速、React + TypeScriptのテンプレート充実 |
| PWAプラグイン | **vite-plugin-pwa** | Vite用PWAプラグイン、自動Service Worker生成 |
| パッケージマネージャー | **pnpm** | 高速、ディスク効率が良い |
| リンター | **ESLint** | コード品質維持 |
| フォーマッター | **Prettier** | コードスタイル統一 |
| ホスティング | **GitHub Pages** | 無料、簡単、GitHub統合、HTTPS対応(PWA必須) |
| CI/CD | **GitHub Actions** | 自動デプロイ、無料枠が充実 |
### 2.3 データストレージ戦略
#### LocalStorage(軽量データ)
```javascript
// 設定情報の保存例
{
"theme": "light",
"language": "ja",
"lastExportDate": "2026-05-23",
"searchHistory": ["企業A", "企業B"],
"viewPreferences": {
"listView": "grid",
"sortBy": "name"
}
}
```
#### IndexedDB(企業データ)
```javascript
// データベーススキーマ
const schema = {
companies: {
keyPath: "id",
indexes: [
{ name: "companyName", unique: false },
{ name: "foundedYear", unique: false },
{ name: "capital", unique: false },
{ name: "createdAt", unique: false }
]
}
};
// 企業データの例
{
id: "uuid-v4",
companyName: "株式会社サンプル",
headquarters: "東京都千代田区",
foundedYear: "2000-04-01",
capital: "10億円",
revenue: "100億円",
averageAge: 35.5,
averageSalary: 6000000,
startingSalary: 250000,
overview: "企業概要...",
businessDescription: "事業内容の詳細...",
philosophy: "企業理念...",
// ... その他のフィールド
createdAt: "2026-05-23T09:00:00Z",
updatedAt: "2026-05-23T09:30:00Z"
}
```
---
## 3. 機能仕様
### 3.1 現行機能の移行
#### 3.1.1 企業管理機能
| 現行機能 | 移行後の実装 | 備考 |
|---------|-------------|------|
| 新規企業シート作成 | 企業追加フォーム | モーダルまたは専用ページ |
| 企業情報編集 | インライン編集 | 即座に保存 |
| 企業削除 | 削除ボタン + 確認ダイアログ | 論理削除も検討 |
| データ更新 | 自動保存 | 入力時に即座に保存 |
#### 3.1.2 ナビゲーション機能
| 現行機能 | 移行後の実装 |
|---------|-------------|
| トップへ移動 | ホームボタン / ロゴクリック |
| 前へ/次へ移動 | ブラウザの戻る/進む、またはナビゲーションボタン |
| 企業間移動 | 企業一覧からクリック、または検索 |
#### 3.1.3 出力機能
| 現行機能 | 移行後の実装 | ライブラリ |
|---------|-------------|-----------|
| PDF出力 | ブラウザ印刷 + PDF保存 | jsPDF / pdfmake |
| 印刷プレビュー | ブラウザ標準の印刷機能 | @media print CSS |
#### 3.1.4 金額変換機能
```javascript
// 日本語金額表記の変換関数
function formatCurrency(value) {
if (!value || value === "N/A") return value;
const num = parseFloat(value.replace(/[^\d.]/g, ''));
if (num >= 1e12) {
return `${(num / 1e12).toFixed(1)}兆円`;
} else if (num >= 1e8) {
return `${(num / 1e8).toFixed(1)}億円`;
} else if (num >= 1e4) {
return `${(num / 1e4).toFixed(1)}万円`;
}
return `${num.toLocaleString()}円`;
}
```
### 3.2 新規追加機能
#### 3.2.1 検索機能(新規)
**機能概要**:
- 全文検索: すべてのフィールドを対象
- インクリメンタルサーチ: 入力中にリアルタイム検索
- 複数条件検索: AND/OR条件の組み合わせ
- 検索履歴: 過去の検索条件を保存
**実装方針**:
```javascript
// 検索処理の例
async function searchCompanies(query) {
const db = await openDB();
const companies = await db.getAll('companies');
return companies.filter(company => {
const searchText = Object.values(company)
.join(' ')
.toLowerCase();
return searchText.includes(query.toLowerCase());
});
}
```
**UI設計**:
- 検索バー: ヘッダーに常時表示
- フィルター: サイドバーまたはドロップダウン
- 結果表示: カード形式またはテーブル形式
- ハイライト: 検索キーワードを強調表示
#### 3.2.2 インポート/エクスポート機能(新規)
**エクスポート機能**:
```javascript
// JSON形式でエクスポート
async function exportData() {
const db = await openDB();
const companies = await db.getAll('companies');
const exportData = {
version: "1.0",
exportDate: new Date().toISOString(),
companies: companies
};
const blob = new Blob(
[JSON.stringify(exportData, null, 2)],
{ type: 'application/json' }
);
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `companies_${Date.now()}.json`;
a.click();
}
```
**インポート機能**:
```javascript
// JSONファイルからインポート
async function importData(file) {
const text = await file.text();
const data = JSON.parse(text);
// バージョンチェック
if (data.version !== "1.0") {
throw new Error("Unsupported version");
}
// データ検証
validateImportData(data);
// IndexedDBに保存
const db = await openDB();
for (const company of data.companies) {
await db.put('companies', company);
}
}
```
**ファイル形式**:
```json
{
"version": "1.0",
"exportDate": "2026-05-23T09:00:00Z",
"companies": [
{
"id": "uuid",
"companyName": "企業名",
"headquarters": "本社",
"foundedYear": "2000-01-01",
"capital": "10億円",
"revenue": "100億円",
"averageAge": 35.5,
"averageSalary": 6000000,
"startingSalary": 250000,
"overview": "企業概要",
"businessDescription": "事業内容",
"createdAt": "2026-05-23T09:00:00Z",
"updatedAt": "2026-05-23T09:00:00Z"
}
]
}
```
---
## 4. データ移行計画
### 4.1 移行ツールの開発
#### Excel → JSON 変換マクロ
```vba
' Excel VBAマクロ(移行用)
Sub ExportToJSON()
Dim json As String
Dim i As Integer
Dim ws As Worksheet
json = "{" & vbCrLf
json = json & " ""version"": ""1.0""," & vbCrLf
json = json & " ""exportDate"": """ & Format(Now, "yyyy-mm-ddThh:nn:ss") & "Z""," & vbCrLf
json = json & " ""companies"": [" & vbCrLf
For i = 3 To Worksheets.Count
Set ws = Worksheets(i)
If ws.Name <> "_Template" And ws.Name <> "データベース" Then
json = json & " {" & vbCrLf
json = json & " ""id"": """ & CreateUUID() & """," & vbCrLf
json = json & " ""companyName"": """ & EscapeJSON(ws.Cells(3, 2).Value) & """," & vbCrLf
json = json & " ""headquarters"": """ & EscapeJSON(ws.Cells(6, 2).Value) & """," & vbCrLf
' ... 他のフィールド
json = json & " }"
If i < Worksheets.Count Then json = json & ","
json = json & vbCrLf
End If
Next i
json = json & " ]" & vbCrLf
json = json & "}" & vbCrLf
' ファイルに保存
SaveToFile json, ThisWorkbook.Path & "\export.json"
End Sub
```
### 4.2 移行手順
1. **準備**
- 現行Excelファイルのバックアップ
- データの整合性確認
2. **エクスポート**
- 移行用VBAマクロを実行
- JSON形式でエクスポート
- エクスポートファイルの確認
3. **インポート**
- 新システムにアクセス
- 「データをインポート」を選択
- JSONファイルをアップロード
- インポート結果の確認
4. **検証**
- 企業数の一致確認
- 各企業の詳細情報確認
- 特殊文字の表示確認
- 金額表記の確認
### 4.3 データクレンジング
#### 移行前の確認事項
- [ ] 企業名の重複チェック
- [ ] 必須項目の欠損確認
- [ ] 金額表記の統一
- [ ] 日付形式の統一
- [ ] 特殊文字のエスケープ
#### データ変換ルール
| 項目 | 変換前 | 変換後 |
|------|--------|--------|
| 金額 | "10億円" | "1000000000" または "10億円"(表示用) |
| 日付 | "平成12年4月1日" | "2000-04-01" |
| 改行 | Excel改行 | "\n" |
| 引用符 | " | \" |
---
## 5. ユーザーインターフェース設計
### 5.1 画面構成
#### 5.1.1 ホーム画面(企業一覧)
```
┌─────────────────────────────────────────────┐
│ [ロゴ] 企業研究データベース [検索バー] [+新規] │
├─────────────────────────────────────────────┤
│ [フィルター] │
│ ┌─────────────────────────────────────────┐ │
│ │ 企業カード │ │
│ │ ┌─────────────────────────────────────┐ │ │
│ │ │ 企業A [編集][削除] │ │ │
│ │ │ 本社: 東京都 資本金: 10億 │ │ │
│ │ │ 設立: 2000年 売上: 100億 │ │ │
│ │ └─────────────────────────────────────┘ │ │
│ │ ┌─────────────────────────────────────┐ │ │
│ │ │ 企業B [編集][削除] │ │ │
│ │ │ ... │ │ │
│ │ └─────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────┘ │
├─────────────────────────────────────────────┤
│ [エクスポート] [インポート] [設定] │
└─────────────────────────────────────────────┘
```
#### 5.1.2 企業詳細画面
```
┌─────────────────────────────────────────────┐
│ [←戻る] 企業A [編集][PDF] │
├─────────────────────────────────────────────┤
│ 基本情報 │
│ ┌─────────────────────────────────────────┐ │
│ │ 企業名: 株式会社A │ │
│ │ 本社: 東京都千代田区 │ │
│ │ 設立年: 2000年4月1日 │ │
│ │ 資本金: 10億円 │ │
│ │ 売上高: 100億円 │ │
│ │ 平均年齢: 35.5歳 │ │
│ │ 平均年収: 600万円 │ │
│ │ 初任給: 25万円 │ │
│ └─────────────────────────────────────────┘ │
│ │
│ 詳細情報 │
│ ┌─────────────────────────────────────────┐ │
│ │ [企業概要] │ │
│ │ テキストエリア... │ │
│ │ │ │
│ │ [事業内容] │ │
│ │ テキストエリア... │ │
│ │ │ │
│ │ [企業理念] │ │
│ │ テキストエリア... │ │
│ └─────────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
```
### 5.2 レスポンシブデザイン
#### デスクトップ(1920x1080以上)
- 3カラムレイアウト
- サイドバーでフィルター表示
- カード形式で企業一覧
#### タブレット(768x1024)
- 2カラムレイアウト
- フィルターは折りたたみ
- カード形式を維持
#### スマートフォン(375x667以上)
- 1カラムレイアウト
- ハンバーガーメニュー
- リスト形式で企業一覧
### 5.3 ダークモード対応
```css
/* ライトモード */
:root {
--bg-primary: #ffffff;
--bg-secondary: #f5f5f5;
--text-primary: #333333;
--text-secondary: #666666;
--border-color: #e0e0e0;
}
/* ダークモード */
@media (prefers-color-scheme: dark) {
:root {
--bg-primary: #1a1a1a;
--bg-secondary: #2d2d2d;
--text-primary: #ffffff;
--text-secondary: #b0b0b0;
--border-color: #404040;
}
}
```
Bobが移行計画を元に提案したTodoリスト:
最初にタスクを投げた時点でTodoリストは作成されているが、移行計画に沿って実装を支持すると、自らTodoリストを更新し承認を求めてくれる。
上記のタスクに沿って実装を進める中で、以下のように不足している要件(今回はフロントエンドフレームワークの選定)の確認やモード切り替えの提案を挟んでくれた。
Bobがやったこと
技術スタック
Bobが選定した構成は以下の通りである。
| カテゴリ | 採用技術 |
|---|---|
| UIライブラリ | React 19 |
| 言語 | TypeScript |
| ビルドツール | Vite |
| CSS | Tailwind CSS 4 |
| ルーティング | React Router v7 |
| フォーム | React Hook Form + Zod |
| DB | IndexedDB (Dexie.js) |
| 状態管理 | Zustand |
| PWA | vite-plugin-pwa |
| PDF出力 | jsPDF + html2canvas |
企業情報管理(CRUD)
BobはVBA版の入力項目を仕様書から読み取り、そのままWebアプリのデータモデルに変換した。(企業名・理念・財務情報・競合分析・志望動機・インターン記録など)
export interface Company {
id: string;
companyName: string;
philosophy?: string;
businessDescription?: string;
revenue?: string;
operatingIncome?: string;
motivation?: string;
careerVision?: string;
internshipParticipated?: boolean;
// ...他フィールド省略
createdAt: string;
updatedAt: string;
}
選考記録機能
移行が一段落したタイミングで、私自身が「選考フェーズごとの記録機能を追加したい」と指示して実装させた機能である。移行だけでなく新規機能の追加もBobが問題なく対応できることを確認できた。カジュアル面談・一次面接・二次面接などのフェーズと結果(通過/不合格/待機中)を管理できる。
export interface SelectionRecord {
id: string;
companyId: string;
phase: string;
date: string;
content: string;
result?: string;
createdAt: string;
updatedAt: string;
}
IndexedDBによるデータ永続化
クライアント環境で独立して動作させるため、BobはDexie.jsを採用してIndexedDBを扱う構成を選択した。バックエンドなしにデータが永続化できる。
export class CompanyDatabase extends Dexie {
companies!: Table<Company, string>;
selectionRecords!: Table<SelectionRecord, string>;
constructor() {
super('CompanyResearchDB');
this.version(3).stores({
companies: 'id, companyName, foundedYear, capital, createdAt, updatedAt',
selectionRecords: 'id, companyId, date, createdAt, updatedAt'
});
}
}
PDF出力(日本語対応)
jsPDFは標準で日本語フォントを持たない。Bobはこの問題を自律的に検知し、「カスタムフォント埋め込みはバンドルサイズが増大するため、html2canvasでHTMLを画像化してPDF変換する方式を採用する」と説明した上で実装した。
export async function exportCompanyToPDF(company: Company, selectionRecords: SelectionRecord[]) {
const container = document.createElement('div');
container.style.position = 'absolute';
container.style.left = '-9999px';
container.style.width = '210mm';
document.body.appendChild(container);
container.innerHTML = `<!-- 企業情報HTML -->`;
try {
const canvas = await html2canvas(container, { scale: 2, backgroundColor: '#ffffff' });
const pdf = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' });
const imgWidth = 210;
const pageHeight = 297;
const imgHeight = (canvas.height * imgWidth) / canvas.width;
let heightLeft = imgHeight;
let position = 0;
pdf.addImage(canvas.toDataURL('image/png'), 'PNG', 0, position, imgWidth, imgHeight);
heightLeft -= pageHeight;
while (heightLeft > 0) {
position = heightLeft - imgHeight;
pdf.addPage();
pdf.addImage(canvas.toDataURL('image/png'), 'PNG', 0, position, imgWidth, imgHeight);
heightLeft -= pageHeight;
}
pdf.save(`${company.companyName}_企業研究シート.pdf`);
} finally {
document.body.removeChild(container);
}
}
今回Skipしたこと:デプロイワークフローの実装
BobのTodoリストには本番環境へのデプロイワークフロー(CI/CD)の実装も提案として含まれていた。今回はスコープ外としてSkipしたが、これはBobが単なるコーディング補助ではなく、CI/CDを含む開発後のフローまでを視野に入れて設計されていることの表れだと感じた。BobのスコープがコーディングからデプロイまでのSDLC全体をカバーしようとしていることは、この提案からも実感できた。
Bobを使って気づいたこと
事前にTodoリストを提示してから動く
作業を依頼すると、即座に実装へ入るのではなく、まず計画をTodoリスト形式で提示する。承認後に初めて実装が開始されるため、何が行われるかを事前に把握できる。今回のような「既存コードを渡して仕様書を作れ」という雑な要件であっても、Bobが必要な作業を整理して明示してくれた。
モードの切り替えをBob自身が提案する
BobにはPlan・Code・Orchestratorなどのモードが存在するが、利用者がモードを意識する必要はほとんどない。状況に応じてBob自身が最適なモードへの切り替えを提案してくれるため、迷わず作業を進められる。
エラーの自律修正がほぼ機能する
実装中にモーダルが表示されないなどのエラーが何度か発生したが、ほとんどBob自身が解消した。途中の機能改善依頼も都度対応してくれた。これだけの壁打ちを経ても、無料トライアルの40 Bob coin以内に収まった点は、コスト感覚の把握という意味でも参考になった。
ただし、ライト/ダークモードの手動切り替え実装だけは完遂できなかった。Tailwind CSS 4でのダークモード制御とhtml・body要素へのクラス付与が絡む実装で、私の指示の出し方に問題があった可能性も否定できないが、他の実装と比べると明らかに苦戦した箇所であった。
まとめ・所感
私がやったことは「モダナイゼーションしたい」と伝えて既存コードとスクリーンショットを渡しただけで、仕様書・移行計画・技術選定・実装のすべてをBobが主導し、約1時間で概ね動くものができた。移行中に新規機能を追加させても対応でき、壁打ちを重ねても無料トライアルの範囲に収まった。
Bobの設計思想は、コード補完に留まらずSDLC全体(要件定義・設計・実装・テスト・デプロイ)をカバーする点にある。GitHub CopilotやCursorが「IDEの中でコードを書く速度を上げるツール」であるのに対し、Bobは「開発ワークフローの土台ごと置き換えようとするツール」となりうる。CI/CDのデプロイワークフローまでTodoに挙げてくる点が、その設計思想を示していた。
今回は試せていないが、Bob Shellによるエージェント型プロセスの自己文書化や、管理者向けに自動収集される監査ログといった機能は、アーキテクチャレベルで「AIが何をしたか追跡できない」という課題に応えている点は、エンタープライズでの活用が期待される。
実際に消費したコイン・トークン:








