開発eurekapuアクティブ
背景
eurekapu財務データSaaSでは、複数のタブでMiller Columns形式のUIを使用している。しかし、各タブで個別に実装されており、以下の問題が発生していた。
- 同じような機能のコンポーネントが複数存在
- 見た目や挙動に一貫性がない
- 新機能追加時に同じ修正を複数箇所に適用する必要がある
- コードベースが肥大化している
今回、7つのタブを調査し、Miller Columnsコンポーネントを3つのタイプに整理する計画を立てた。
調査対象の7タブ
以下の7つのタブを調査対象とした。
| タブ名 | 主な用途 | 現状のコンポーネント |
|---|---|---|
| 読取一覧 | OCR結果の一覧表示・編集 | 独自実装 |
| クレカ明細 | クレジットカード明細の表示 | 独自実装 |
| 科目別一覧 | 勘定科目ごとの取引一覧 | 独自実装 |
| 帳票設定 | 帳票テンプレートの設定 | DocumentTypeForm.vue |
| 仕訳ルール | 自動仕訳ルールの管理 | 独自実装 |
| 勘定科目マスター | 勘定科目の管理 | 独自実装 |
| 月次推移表 | 月次の財務推移表示 | 独自実装 |
スクリーンショット撮影と分析
各タブのスクリーンショットを撮影し、UIパターンを分析した。
共通パターンの発見
撮影したスクリーンショットから、以下の共通パターンを発見した。
- 左ペイン: カテゴリやフィルタ条件の選択
- 中央ペイン: 一覧表示(テーブルまたはカード形式)
- 右ペイン: 詳細表示または編集フォーム
相違点
- 左ペインの階層数(1階層〜3階層)
- 選択モード(単一選択/複数選択)
- 右ペインの有無
- 編集機能の有無
3つのコンポーネントタイプの定義
分析結果から、以下の3タイプを定義した。
Type A: フィルタ型(MillerColumnsFilter)
用途: 一覧表示のフィルタリング
特徴:
- 左ペインで条件を選択
- 選択に応じて中央の一覧がフィルタリングされる
- 右ペインは通常なし(または簡易プレビュー)
適用タブ:
- 読取一覧
- クレカ明細
- 科目別一覧
インターフェース設計:
interface MillerColumnsFilterProps {
// フィルタ階層の定義
levels: FilterLevel[]
// 選択されたフィルタ値
selectedFilters: Record<string, string | string[]>
// フィルタ変更時のコールバック
onFilterChange: (filters: Record<string, string | string[]>) => void
}
interface FilterLevel {
key: string
label: string
// 選択肢を取得する関数(前の階層の選択値に依存)
getOptions: (parentSelection?: string) => FilterOption[]
// 複数選択を許可するか
multiple?: boolean
}
interface FilterOption {
value: string
label: string
count?: number // 該当件数
}
Type B: 選択型(MillerColumnsSelect)
用途: マスターデータの選択・編集
特徴:
- 左ペインで階層をドリルダウン
- 中央ペインで項目を選択
- 右ペインで選択項目の詳細表示・編集
適用タブ:
- 勘定科目マスター
- 仕訳ルール
インターフェース設計:
interface MillerColumnsSelectProps<T> {
// 階層データ
levels: SelectLevel<T>[]
// 選択中の項目
selectedItem: T | null
// 選択変更時のコールバック
onSelect: (item: T) => void
// 編集可能か
editable?: boolean
// 編集時のコールバック
onEdit?: (item: T) => void
}
interface SelectLevel<T> {
key: string
label: string
// 階層データを取得
getData: (parentId?: string) => T[]
// 表示用のレンダラー
renderItem: (item: T) => VNode
}
Type C: 詳細表示型(MillerColumnsDetail)
用途: 設定画面や詳細表示
特徴:
- 左ペインでカテゴリを選択
- 右ペインに詳細フォームや設定画面を表示
- 中央ペインはオプション
適用タブ:
- 帳票設定
- 月次推移表
インターフェース設計:
interface MillerColumnsDetailProps {
// カテゴリ一覧
categories: Category[]
// 選択中のカテゴリ
selectedCategory: string | null
// カテゴリ選択時のコールバック
onCategorySelect: (categoryId: string) => void
// 詳細コンテンツのスロット
detailSlot: VNode
}
interface Category {
id: string
label: string
icon?: string
badge?: string | number
}
既存コンポーネントの問題点
重複実装
同じ機能が複数のコンポーネントに実装されていた。
components/
├── DocumentTypeForm.vue # 帳票設定用(Type C相当)
├── DocumentTypeCard.vue # カード表示(未使用)
├── FilterPanel.vue # 読取一覧用フィルタ
├── FilterPanelCredit.vue # クレカ明細用フィルタ(ほぼ同じ)
├── AccountSelect.vue # 科目選択
├── AccountSelectModal.vue # モーダル版科目選択
└── ...
一貫性のなさ
| 問題点 | 例 |
|---|---|
| スタイルの不統一 | ボーダー色、パディング、フォントサイズが異なる |
| APIの不統一 | v-model / @select / @change が混在 |
| 状態管理の不統一 | ローカル状態 / Pinia / props経由が混在 |
未使用コンポーネントの存在
調査の結果、以下のコンポーネントが未使用であることが判明した。
DocumentTypeForm.vue: 古い帳票設定フォームDocumentTypeCard.vue: 使われていないカード表示
Codexレビューの活用
計画の妥当性を確認するため、Codex(GPT-5.2)に2回レビューを依頼した。
第1回レビュー:タイプ分類の妥当性
レビュー依頼内容:
- 3タイプへの分類は適切か
- 他に考慮すべきパターンはあるか
レビュー結果:
- 3タイプ分類は妥当
- Type A と Type B の境界が曖昧なケースがあるため、判断基準を明確にすべき
- 「フィルタリング目的か、選択・編集目的か」で判断することを推奨
第2回レビュー:インターフェース設計
レビュー依頼内容:
- 各タイプのインターフェース設計は適切か
- Vue 3 Composition API との相性は良いか
レビュー結果:
- ジェネリクスの使用は適切
onXxx形式のコールバックよりemitを使う Vue 慣習に合わせるべきcomposables/にロジックを切り出すことを推奨
未使用コンポーネントの削除
調査結果を踏まえ、以下のコンポーネントを削除した。
削除対象
# 削除したファイル
rm components/DocumentTypeForm.vue
rm components/DocumentTypeCard.vue
削除理由
| ファイル | 削除理由 |
|---|---|
| DocumentTypeForm.vue | 新しい帳票設定画面に置き換え済み |
| DocumentTypeCard.vue | どこからも参照されていない |
削除前の確認
削除前に以下を確認した。
# 参照箇所の確認
grep -r "DocumentTypeForm" --include="*.vue" --include="*.ts"
grep -r "DocumentTypeCard" --include="*.vue" --include="*.ts"
結果、どちらも参照箇所がなかったため削除を実行した。
今後の作業計画
Phase 1: 基盤コンポーネントの作成
MillerColumnsBase.vueの作成(共通ロジック)useMillerColumnscomposable の作成- 共通スタイルの定義(
miller-columns.css)
Phase 2: Type A(フィルタ型)の実装
MillerColumnsFilter.vueの作成- 読取一覧への適用
- クレカ明細への適用
- 科目別一覧への適用
Phase 3: Type B(選択型)の実装
MillerColumnsSelect.vueの作成- 勘定科目マスターへの適用
- 仕訳ルールへの適用
Phase 4: Type C(詳細表示型)の実装
MillerColumnsDetail.vueの作成- 帳票設定への適用
- 月次推移表への適用
Phase 5: クリーンアップ
- 旧コンポーネントの削除
- テストの追加
- ドキュメントの整備
設計上の決定事項
命名規則
MillerColumns + [Type] + [Variant]
例: MillerColumnsFilterCompact, MillerColumnsSelectTree
ディレクトリ構造
components/
└── miller-columns/
├── MillerColumnsBase.vue
├── MillerColumnsFilter.vue
├── MillerColumnsSelect.vue
├── MillerColumnsDetail.vue
├── parts/
│ ├── ColumnPane.vue
│ ├── ColumnItem.vue
│ └── ColumnHeader.vue
└── composables/
├── useMillerColumns.ts
├── useColumnNavigation.ts
└── useColumnSelection.ts
スタイル方針
- Tailwind CSS を使用
- 共通のデザイントークンを定義
- ダークモード対応
まとめ
7つのタブを調査し、Miller Columnsコンポーネントを3タイプに整理する計画を立てた。
- Type A(フィルタ型): 読取一覧、クレカ明細、科目別一覧
- Type B(選択型): 勘定科目マスター、仕訳ルール
- Type C(詳細表示型): 帳票設定、月次推移表
未使用コンポーネント(DocumentTypeForm.vue、DocumentTypeCard.vue)は削除済み。Codexレビューで設計の妥当性も確認した。
今後はPhase 1から順次実装を進める。