2.2. フロントエンド仕様
React (Vite) で構築されたシングルページアプリケーション (SPA)。ユーザーインターフェースの提供とバックエンドAPIとの通信を担います。
コンポーネント図
| コンポーネント | 説明 |
|---|---|
| Pages | 各画面(ページ)を構成するコンポーネント。 |
| Components | ボタンやナビゲーションバーなど、再利用可能なUI部品。 |
| Stores | Zustandを使用してアプリケーション全体の状態を管理するストア。 |
| Services | APIクライアントなど、外部との通信処理を責務とするモジュール。 |
画面一覧
| 画面 | パス | 認証 | 説明 |
|---|---|---|---|
| HomePage | / | 不要 | アプリケーションのトップページ。ログインや新規登録への導線。 |
| LoginPage | /login | 不要 | ログインフォーム画面。 |
| RegisterPage | /register | 不要 | 新規ユーザー登録フォーム画面。 |
| NetworkChatPage | /chat | 必要 | グラフ可視化とチャットUIを統合したメイン画面。 |
状態管理とAPI連携 (Zustand & Axios)
状態管理にはZustandを使用し、機能ごとにストアを分割します。API通信にはaxiosをベースとしたクライアント (services/api.js) を用い、各ストアのアクション内から呼び出します。APIクライアントは全てのリクエストに認証トークンを付与し、トークン失効時はログインページへリダイレクトします。
authStore
ユーザーの認証状態とアクセストークンを管理します。
- 状態:
isAuthenticated,user,token - 主要なアクションと連携API:
login(username, password):POST /auth/tokenを呼び出し、成功時にトークンを状態とlocalStorageに保存する。register(username, password):POST /auth/registerを呼び出す。logout(): トークンを削除し、状態をリセットする。
networkStore
表示中のグラフデータやレイアウト情報を管理します。
- 状態:
networkId,nodes,edges,layout - 主要なアクションと連携API:
fetchNetwork(networkId):GET /network/{networkId}/visdataを呼び出し、取得したデータでnodesとedgesを更新する。uploadNetwork(file):POST /network/uploadを呼び出す。applyLayout(layoutName):POST /network/{networkId}/layoutを呼び出す。
chatStore
会話の履歴やメッセージ一覧を管理します。
- 状態:
conversationId,messages,isLoading - 主要なアクションと連携API:
fetchHistory(conversationId):GET /conversations/{id}/messagesを呼び出し、messages状態を更新する。sendMessage(messageContent):POST /chat/processを呼び出し、UIのローディング状態を管理しつつ、返信メッセージとグラフの更新情報を受け取る。
コード例: sendMessage アクションの実装イメージ
// chatStore.js (Zustand)
import { create } from 'zustand';
import { api } from '../services/api'; // axios instance
import { useNetworkStore } from './networkStore';
export const useChatStore = create((set, get) => ({
messages: [],
isLoading: false,
sendMessage: async (messageContent) => {
const conversationId = get().conversationId;
set({ isLoading: true });
try {
// ユーザーのメッセージをUIに即時反映
const userMessage = { role: 'user', content: messageContent };
set((state) => ({ messages: [...state.messages, userMessage] }));
// バックエンドに処理をリクエスト
const response = await api.post('/chat/process', {
conversation_id: conversationId,
message: userMessage,
});
// アシスタントの返信をUIに反映
const assistantMessage = response.data.message;
set((state) => ({ messages: [...state.messages, assistantMessage] }));
// グラフが更新された場合、networkStoreのアクションを呼び出す
if (response.data.graph_updated) {
useNetworkStore.getState().setNetworkData(response.data.new_vis_data);
}
} catch (error) {
console.error("Failed to send message:", error);
// エラー処理
} finally {
set({ isLoading: false });
}
},
}));