操作
機能 #193
未完了Redmine左ナビ AIチャット機能追加 - チャット一覧・1ペイン表示・履歴管理
開始日:
2025-06-04
期日:
進捗率:
0%
予定工数:
説明
機能要望概要¶
対象箇所: Redmine左ナビゲーションメニュー
要望内容: AIチャット機能をメインナビゲーションに追加
配置位置: カレンダーの位置(カレンダー削除後)
機能仕様¶
1. 左ナビゲーション追加¶
メニュー構成:
📊 ダッシュボード
🎫 チケット
🏗️ プロジェクト管理
📰 ニュース
📄 ドキュメント
🤖 AIチャット ← 新規追加(カレンダー位置)
2. AIチャット機能構成¶
A. チャット一覧表示¶
- 既存チャット履歴の表示
- チャット件名(タイトル)一覧
- 最終更新日時
- チャット状態(アクティブ/非アクティブ)
B. 新規チャット作成¶
- 「新規チャット」ボタン
- 1ペインでのチャット画面起動
- フルページでのチャット体験
C. 既存チャット再開¶
- 件名クリックでチャット画面表示
- 過去の会話履歴継続
- 1ペインでのWEB UI利用
UI/UX設計¶
1. ナビゲーションメニュー¶
<nav className="sidebar-nav">
{/* 既存メニュー */}
<NavItem icon="📊" label="ダッシュボード" to="/dashboard" />
<NavItem icon="🎫" label="チケット" to="/tickets" />
<NavItem icon="🏗️" label="プロジェクト管理" to="/projects" />
<NavItem icon="📰" label="ニュース" to="/news" />
<NavItem icon="📄" label="ドキュメント" to="/documents" />
{/* 新規追加 */}
<NavItem icon="🤖" label="AIチャット" to="/ai-chat" />
</nav>
2. AIチャット一覧ページ (/ai-chat
)¶
<div className="ai-chat-list-page">
{/* ヘッダー */}
<div className="page-header">
<h1 className="text-2xl font-bold">AIチャット</h1>
<button className="btn btn-primary">
➕ 新規チャット
</button>
</div>
{/* チャット一覧 */}
<div className="chat-list">
{chatHistory.map(chat => (
<div key={chat.id} className="chat-item">
<div className="chat-title">
<a href={`/ai-chat/${chat.id}`}>{chat.title}</a>
</div>
<div className="chat-meta">
<span className="last-updated">{chat.lastUpdated}</span>
<span className="message-count">{chat.messageCount}件</span>
</div>
</div>
))}
</div>
</div>
3. 1ペインチャット画面 (/ai-chat/new
, /ai-chat/:id
)¶
<div className="ai-chat-fullpage">
{/* チャットヘッダー */}
<div className="chat-header">
<button className="back-btn">← 一覧に戻る</button>
<h2 className="chat-title">{chatTitle || "新規チャット"}</h2>
<div className="chat-actions">
<button className="save-btn">💾 保存</button>
<button className="delete-btn">🗑️ 削除</button>
</div>
</div>
{/* チャットエリア */}
<div className="chat-messages-area">
{messages.map(message => (
<ChatMessage key={message.id} message={message} />
))}
</div>
{/* 入力エリア */}
<div className="chat-input-area">
<input
type="text"
placeholder="メッセージを入力..."
className="chat-input"
/>
<button className="send-btn">送信</button>
</div>
</div>
データ管理仕様¶
1. チャット履歴保存¶
// チャットデータ構造
const chatSession = {
id: 'chat_uuid_001',
title: 'Redmine設定について',
createdAt: '2025-06-04T18:30:00Z',
lastUpdated: '2025-06-04T19:15:00Z',
messageCount: 12,
messages: [
{
id: 'msg_001',
role: 'user',
content: 'Redmineの設定方法を教えて',
timestamp: '2025-06-04T18:30:00Z'
},
{
id: 'msg_002',
role: 'assistant',
content: 'Redmineの設定について説明します...',
timestamp: '2025-06-04T18:30:15Z'
}
],
context: {
url: 'https://task.call2arm.com/settings',
pageContent: '...'
}
};
2. 永続化ストレージ¶
- ローカルストレージ: ブラウザでの一時保存
- サーバーサイド: データベースでの永続保存
- セッション管理: ユーザー別のチャット履歴
技術実装要件¶
1. ルーティング追加¶
// React Router設定
<Routes>
{/* 既存ルート */}
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/tickets" element={<Tickets />} />
<Route path="/projects" element={<Projects />} />
{/* 新規追加 */}
<Route path="/ai-chat" element={<AIchatList />} />
<Route path="/ai-chat/new" element={<AIchatFullpage />} />
<Route path="/ai-chat/:chatId" element={<AIchatFullpage />} />
</Routes>
2. API エンドポイント¶
# チャット管理API
GET /api/ai-chat/sessions # チャット一覧取得
POST /api/ai-chat/sessions # 新規チャット作成
GET /api/ai-chat/sessions/:id # 特定チャット取得
PUT /api/ai-chat/sessions/:id # チャット更新
DELETE /api/ai-chat/sessions/:id # チャット削除
# メッセージ管理API
POST /api/ai-chat/sessions/:id/messages # メッセージ送信
GET /api/ai-chat/sessions/:id/messages # メッセージ履歴取得
3. 状態管理¶
// Zustand/Redux での状態管理
const useAIChatStore = create((set, get) => ({
chatSessions: [],
currentChat: null,
loadChatSessions: async () => {
const sessions = await fetchChatSessions();
set({ chatSessions: sessions });
},
createNewChat: async (initialMessage) => {
const newChat = await createChatSession(initialMessage);
set(state => ({
chatSessions: [newChat, ...state.chatSessions],
currentChat: newChat
}));
},
loadChat: async (chatId) => {
const chat = await fetchChatSession(chatId);
set({ currentChat: chat });
}
}));
期待効果¶
- アクセス性向上: AIチャットへの直接アクセス
- 履歴管理: 過去の相談内容の再参照
- 作業継続性: 中断したチャットの再開
- 統合体験: Redmine内でのシームレスなAI活用
関連チケット¶
優先度¶
- 緊急度: 中(UI改善・機能追加)
- 重要度: 高(AI統合の中核機能)
Redmine Admin さんが4日前に更新
追加要望: AIチャット一覧の検索・絞り込み機能¶
1. 検索機能¶
全文検索バー追加:
<div className="ai-chat-search-section">
<div className="search-bar">
<input
type="text"
placeholder="チャット内容を検索..."
className="w-full px-4 py-2 border rounded-lg"
onChange={handleSearchInput}
/>
<button className="search-btn">🔍</button>
</div>
</div>
検索対象:
- ✅ チャットタイトル/件名
- ✅ チャット内容(全メッセージ)
- ✅ ユーザーメッセージ
- ✅ AI回答内容
- ✅ 関連プロジェクト情報
2. 絞り込み機能¶
フィルタリングオプション:
<div className="filter-section">
{/* 表示範囲選択 */}
<select className="scope-filter">
<option value="all">全体</option>
<option value="my">自分のチャット</option>
<option value="project">プロジェクト別</option>
</select>
{/* 利用者別フィルタ */}
<select className="user-filter">
<option value="">すべてのユーザー</option>
<option value="1">Redmine Admin</option>
<option value="2">ユーザーB</option>
</select>
{/* プロジェクト別フィルタ */}
<select className="project-filter">
<option value="">すべてのプロジェクト</option>
<option value="ai-chat-general">AIチャット一覧</option>
<option value="1">Redmineの設定</option>
<option value="2">サービス監視基盤構築</option>
<option value="3">コーディング自動化基盤</option>
</select>
</div>
3. プロジェクト分類システム¶
デフォルトプロジェクト:
- プロジェクト未指定: 自動的に「AIチャット一覧」プロジェクトに格納
- プロジェクト指定: 対応するRedmineプロジェクトと紐付け
データ構造:
const chatSession = {
id: 'chat_uuid_001',
title: 'nginx設定について相談',
projectId: 'ai-chat-general', // デフォルト
projectName: 'AIチャット一覧',
userId: 1,
userName: 'Redmine Admin',
createdAt: '2025-06-04T18:30:00Z',
messages: [...],
tags: ['nginx', '設定', 'プロキシ'] // 検索用タグ
};
// プロジェクト指定の場合
const projectChat = {
id: 'chat_uuid_002',
title: 'VPSセキュリティ強化方針',
projectId: 5, // VPSセキュリティプロジェクト
projectName: 'VPSセキュリティ',
userId: 1,
// ...
};
4. 検索・フィルタ画面設計¶
<div className="ai-chat-list-page">
{/* 検索・フィルタセクション */}
<div className="search-filter-section bg-gray-50 p-4 rounded-lg mb-6">
{/* 検索バー */}
<div className="search-bar mb-4">
<input
type="text"
placeholder="チャット内容、タイトル、プロジェクト名で検索..."
className="w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-green-500"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
</div>
{/* フィルタ群 */}
<div className="filters grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<label className="block text-sm font-medium mb-2">表示範囲</label>
<select
className="w-full border rounded-lg px-3 py-2"
value={scopeFilter}
onChange={(e) => setScopeFilter(e.target.value)}
>
<option value="all">全体</option>
<option value="my">自分のチャット</option>
<option value="shared">共有チャット</option>
</select>
</div>
<div>
<label className="block text-sm font-medium mb-2">利用者</label>
<select
className="w-full border rounded-lg px-3 py-2"
value={userFilter}
onChange={(e) => setUserFilter(e.target.value)}
>
<option value="">すべてのユーザー</option>
{users.map(user => (
<option key={user.id} value={user.id}>{user.name}</option>
))}
</select>
</div>
<div>
<label className="block text-sm font-medium mb-2">プロジェクト</label>
<select
className="w-full border rounded-lg px-3 py-2"
value={projectFilter}
onChange={(e) => setProjectFilter(e.target.value)}
>
<option value="">すべてのプロジェクト</option>
<option value="ai-chat-general">AIチャット一覧</option>
{projects.map(project => (
<option key={project.id} value={project.id}>{project.name}</option>
))}
</select>
</div>
</div>
{/* アクティブフィルタ表示 */}
<div className="active-filters mt-4">
{activeFilters.map(filter => (
<span key={filter.id} className="inline-flex items-center px-3 py-1 rounded-full text-xs bg-green-100 text-green-800 mr-2">
{filter.label}
<button onClick={() => removeFilter(filter.id)} className="ml-1 text-green-600">×</button>
</span>
))}
</div>
</div>
{/* 検索結果・チャット一覧 */}
<div className="chat-list">
<div className="results-header mb-4">
<span className="text-sm text-gray-600">
{filteredChats.length}件のチャットが見つかりました
</span>
</div>
{filteredChats.map(chat => (
<div key={chat.id} className="chat-item border rounded-lg p-4 mb-3 hover:bg-gray-50">
<div className="flex justify-between items-start">
<div className="flex-1">
<h3 className="chat-title text-lg font-semibold">
<a href={`/ai-chat/${chat.id}`} className="text-blue-600 hover:underline">
{highlightSearchTerms(chat.title, searchQuery)}
</a>
</h3>
<div className="chat-meta text-sm text-gray-600 mt-1">
<span className="project-tag bg-blue-100 text-blue-800 px-2 py-1 rounded mr-2">
📁 {chat.projectName}
</span>
<span className="user-info">👤 {chat.userName}</span>
<span className="date-info ml-4">📅 {formatDate(chat.lastUpdated)}</span>
<span className="message-count ml-4">💬 {chat.messageCount}件</span>
</div>
{/* 検索結果のプレビュー */}
{searchQuery && (
<div className="search-preview mt-2 text-sm text-gray-700">
{generateSearchPreview(chat, searchQuery)}
</div>
)}
</div>
<div className="chat-actions">
<button className="text-gray-400 hover:text-gray-600">⋮</button>
</div>
</div>
</div>
))}
</div>
</div>
5. API拡張仕様¶
# 検索・フィルタ対応API
GET /api/ai-chat/sessions?search={query}&user={userId}&project={projectId}&scope={scope}
# 例: nginx設定に関するチャットを検索
GET /api/ai-chat/sessions?search=nginx&project=1
# 例: 自分のチャットのみ表示
GET /api/ai-chat/sessions?scope=my&user=1
# 例: AIチャット一覧プロジェクトのチャット
GET /api/ai-chat/sessions?project=ai-chat-general
6. 検索アルゴリズム¶
検索対象の重み付け:
- タイトル: 3.0
- 最新メッセージ: 2.0
- プロジェクト名: 1.5
- チャット内容: 1.0
- タグ: 2.5
検索機能:
- 部分一致検索
- AND/OR検索対応
- タグベース検索
- 日付範囲検索
7. 期待効果¶
- 効率的なチャット発見: 過去の相談内容の素早い検索
- プロジェクト管理: チャットのプロジェクト別整理
- チーム協働: 他メンバーのチャット参照(権限に応じて)
- 知識蓄積: AIとの対話履歴の有効活用
操作