アーキテクチャ設計
BluePeriodアプリケーションの全体アーキテクチャ設計
01. アーキテクチャ設計
1. 概要
このドキュメントは、blueperiodアプリケーションの技術的なアーキテクチャについて説明します。
本アプリケーションは、AIの力を活用して小説の執筆を支援することを目的とした、MPA (マルチページアプリケーション) です。
- サービス名:
BluePeriod - リポジトリ名:
blueperiod
1.2. ドメイン・デプロイ構成
本プロジェクトは、ブランドアイデンティティとSEOの最適化のため、以下のマルチプロジェクト構成で運用されています。
- メインアプリケーション (Next.js):
https://blueperiod.blue- 執筆支援ツールの本体。
- ランディングページ / 情報提供サイト (Astro):
https://blue.blueperiod.blue- 紹介ページ、ブログ、ドキュメントなどの静的コンテンツ。
両プロジェクトは単一のモノレポ内で管理され、Vercelによって個別にビルド・デプロイされています。
1.5. サイトマップとアーキテクチャ
本アプリケーションは、明確に責務が分離された複数のページで構成されるMPA (マルチページアプリケーション) として設計されています。これにより、各機能の独立性が高まり、将来的な拡張が容易になっています。
/->/homeにリダイレクト/home: ホームダッシュボード/bookshelf: プロジェクト一覧・管理ページ/project/[id]: 個別プロジェクトの執筆ページ/project/[id]/publish: 作品公開ウィザードページ/explore: 公開作品の閲覧・検索ページ/explore/details/[id]: 公開作品の詳細ページ/explore/library: ユーザーライブラリ(ブックマーク)ページ/read/[id]: 作品閲覧ページ(セクション一覧)/read/[id]/[storyId]: ストーリー単位の閲覧ページ/my-works: 自分の公開作品管理ページ/profile/[userId]: ユーザープロフィールページ/prompts: プロンプトマネージャー(グローバルなプロンプト管理)/settings: アプリケーション設定ページ/settings/characters: キャラクター管理ページ/database-management: データベース管理(長期記憶・メンテナンス)ページ/ai: AIチャットページ/login: ログインページ/pricing: 料金プランページ/privacy: プライバシーポリシー/terms: 利用規約/checkout/success: 決済完了ページ
1.6. 主要ページの責務
/home: ホームダッシュボード。現在の目標進捗、最近の執筆活動、スクラッチパッドなど、創作の「入り口」としてのツール群を提供し、ユーザーのモチベーションを維持する。/bookshelf: プロジェクトの一覧管理。ユーザーが作成したすべてのプロジェクトをカード形式で表示し、インポートや削除などの管理機能を提供する。/project/[id]: 執筆ワークスペース。単一のプロジェクトに特化し、プロット、原稿、執筆支援機能などを3パネルレイアウトで提供する。/explore: 全ユーザーに向けて公開された作品を閲覧、検索、フィルタリングできるページ。「オンライン書店」のような役割を持つ。/explore/details/[id]: 公開作品の詳細ページ。作品情報、あらすじ、レビューチャート、目次などを表示します。/explore/library: ユーザーがブックマーク(ライブラリに追加)した作品を管理するページ。/read/[id]: 作品の全文閲覧ページ。セクション単位の目次と本文を表示します。/read/[id]/[storyId]: ストーリー単位の閲覧ページ。特定のストーリーに焦点を当てた閲覧体験を提供します。/my-works: 自分が公開した作品の管理ページ。メタデータ編集、非公開化などの操作を行えます。/profile/[userId]: ユーザーの公開プロフィールページ。ユーザーの公開作品一覧を表示します。/prompts: アプリケーション全体で使用するAIプロンプトアセットを管理するページ。作成、編集、削除、およびタグによる分類が可能で、クラウド同期にも対応している。/settings: アプリケーション設定ページ。APIキー設定、プロバイダー選択、同期設定などを管理します。/settings/characters: AIチャット用キャラクター(ペルソナ)の管理ページ。/database-management: データベース管理ページ。長期記憶(ベクトルDB)のメンテナンス、バックアップ(.bluememory)のインポート/エクスポート、モデル変更に伴う再ベクタライズ、および肥大化したモデルキャッシュの削除など、アプリの健全性を維持するためのツール群を提供します。/ai: AIとの対話に特化したページ。プロジェクト横断的なチャット機能を提供し、API設定やプロンプト管理もこのページ内で行う。3パネルレイアウトで構成される。- 左パネル (
AILeftPanel.tsx): LLMプロバイダー選択やAPIキー、モデルパラメータ(温度など)を設定する。 - 中央パネル (
AICenterPanel.tsx): チャットの会話履歴と入力インターフェース。 - 右パネル (
AIRightPanel.tsx): チャットで使用するプロンプトを管理する。
- 左パネル (
2. 設計思想
2.1. Next.js (App Router) + Hono によるハイブリッド構成
アプリケーションは、Next.js (App Router) をベースとしつつ、API レイヤーには軽量・高速な Hono を採用しています。
-
next-app/: フロントエンドおよび BFF (Hono) のコードが格納されています。 -
Hono アダプター:
app/api/[[...route]]/route.tsが Hono のエントリポイントとなり、Next.js と Hono を接続します。 -
モジュール分割:
src/server/api/内で機能ごと(infra,auth,stripe,projects,library,publish,ai,chat等)に Hono アプリケーションを分割し、メインアプリにマウントする構成をとっています。これにより、AIフレンドリーで保守性の高いコードベースを実現しています。
2.3. ロジック抽出と Service Layer
API ハンドラから純粋なビジネスロジックを切り離し、src/lib/features/ 配下にサービスとして抽出しています。
- 目的:
- ポータビリティ: 同じロジックを API 経由(Web版)でも、直接の関数呼び出し(Desktop版)でも利用可能にする。
- テスト容易性: HTTP のコンテキストに依存せず、純粋なロジックとしてユニットテストを可能にする。
- AI 親和性: AI アシスタントがプロンプトや LLM 呼び出しの詳細を一つのディレクトリ (
lib/features/ai) で把握できる。
2.4. BYOK (Bring Your Own Key) モデル
APIキーの提供方法として、以下の2つのシナリオをサポートしています。
- ローカル開発者:
next-app/.env.localファイルにキーを記述します。 - ライブデモ利用者: UI上の設定画面からキーを直接入力します。 BFFは、リクエストに応じてこれらのキーを動的に利用し、外部APIへリクエストをプロキシします。
2.4. レスポンシブデザイン
src/hooks/use-mobile.tsxフックとTailwind CSSのブレークポイントを活用し、デバイスの画面幅に応じて最適なUIを提供します。
- PC: 3パネル構成のリッチな編集画面。
- モバイル: ボトムナビゲーションを基本とした、スペース効率の良いUI。
3. 主要な技術要素と責務
3.1. フロントエンド
- UIフレームワーク: React
- メタフレームワーク: Next.js (App Router)
- UIコンポーネント: shadcn/ui
- スタイリング: Tailwind CSS
- UIコンポーネント設計:
shadcn/uiをベースとしつつ、複数の場所で再利用されるUIセクションは、ロジックごとカプセル化した独立したコンポーネントとして設計します。- 例:
ApiSettingsPanel.tsxは、LLMプロバイダーやモデル選択などのAPI設定機能一式を提供し、AIページとSettingsページの両方から(現在はAIページのみから)利用可能なように設計されています。
3.2. 状態管理
- ライブラリ: Jotai
- 設計思想:
- Atomicモデル: 状態を小さな「アトム」に分割し、不要な再レンダリングを抑制します。
- 関心の分離: 状態定義、永続化、ビジネスロジック、UIを明確に分離します。詳細は
03_state_management.mdを参照。
3.3. バックエンド
- BFF (Backend for Frontend)
- 実装: Hono (on Next.js API Routes)
- ランタイム: Edge Runtime (Vercel)
- 役割: フロントエンドからのリクエストを受け取り、外部AIサービスや決済サービスへのリクエストをプロキシします。
- BaaS (Backend as a Service)
- 技術: Supabase
- 役割: 認証、データベース、ストレージなどのバックエンド機能を提供します。
3.4. AI連携
- ライブラリ: LangChain.js, LangGraph.js
- 役割:
- 複数のLLMプロバイダー(Google Gemini, Anthropic, OpenAI互換APIなど)を統一されたインターフェースで扱えるように抽象化します。
- プロンプトの組み立て、モデルの呼び出し、レスポンスの解析(JSONフォーマットへの整形など)といった一連の処理をパイプライン(LCEL)として構築します。
Client-Side LangGraph Agent (Bridge Pattern)
- アーキテクチャ: Local-Firstなデータ構造を活かすため、AIエージェントの「脳(ステートマシン)」はクライアントサイド(ブラウザ)で実行されます。
- Local Tools: エージェントはブラウザ内のIndexedDBに直接アクセスし、ユーザーの原稿やプロット情報を読み書きします。これにより、サーバーへのデータ送信リスクを最小化します。
- Server Proxy: Web検索や外部MCPサーバーへの接続など、ブラウザから直接実行できない操作は、Next.js API Route上のプロキシを経由して実行します(Bridge Pattern)。
- 2トラック戦略:
- Assistant Agent (Chat): リサーチや設定確認に特化した読み取り専用エージェント。
- Editorial Agent (Writing): 執筆、推敲、プロット修正を行う読み書き可能なエージェント。
Browser-Based Long-Term Memory
- 概要: ユーザーとの過去の対話を記憶し、文脈に応じた回答を提供するための検索システム。プライバシーを重視し、外部DBを使わずブラウザ内で完結します。
- 技術スタック:
- Orama: 全文検索とベクトル検索を統合したハイブリッド検索エンジン。
- Transformers.js: ブラウザ内(WebGPU/WASM)でテキストをベクトル化するライブラリ。モデルには
gte-multilingual-base(256次元/Matryoshka) とruri-v3-30m(312次元/日本語特化) をサポート。 - IndexedDB: インデックスデータの永続化先。
- Query Transformation: ユーザーの曖昧な入力(「先週の話」など)を、LLM(サブAI)を用いて構造化された検索クエリ(日時範囲指定など)に変換し、検索精度を向上させています。
- Scoped Memory: 記憶はAIキャラクターごとに分離されており、キャラクターAとの会話がキャラクターBに漏れることはありません。
- Dynamic Model Loading & Re-vectorization: ユーザーが設定から埋め込みモデルを変更すると、UI上で再構成が促されます。既存のテキストデータから新しいモデルでベクトルを再計算(再ベクタライズ)することで、モデル移行後も過去の記憶を継続して利用可能です。
AIリライト・推敲システム
- 概要: 既存の原稿をAIによって洗練させる機能。単一のセクションから最上位のPart階層まで、任意の範囲を一括で処理できます。
- 文脈考慮ロジック: リライト対象のセクションだけでなく、プロジェクト全体のプロット構造や直前のセクションの文脈(リライト済みの最新内容を含む)をAIに送信することで、物語の整合性を保った高度な推敲を実現しています。
- プランニングフェーズ: 大規模な改変を行う場合、AIがまず各セクションごとのリライト方針をJSON形式で策定し、その計画に基づいて実行するプロセスを採用しています。
3.5. デスクトップ・アーキテクチャ (Tauri V2)
BluePeriodは、Tauri V2を使用したデスクトップアプリケーション(Windows, macOS, Linux)としても提供されています。
- Honoサイドカーモデル: デスクトップ版では、Next.jsのRoute Handlers (Hono) をローカルのNode.jsプロセスとして起動し、WebView内から
fetch('/api/...')で通信します。これにより、Web版と全く同じAPIロジックをデスクトップ環境で実現しています。ランタイムにはBun単一バイナリをTauri Sidecarとして同梠しており、ユーザー環境へのNode.js/Bunインストールは不要です。 - Rust IPC ブリッジ: ブラウザのCORS制限を受けることなく、ユーザーのPC上で動作する LM Studio や Ollama 等のローカルLLMサーバーと通信するため、RustバックエンドのIPCコマンド (
call_local_llm) を経由します。 - ネイティブ連携: TauriプラグインおよびRustコマンドを活用し、ネイティブ通知、自動アップデート機能を提供します。ファイルアクセスはMCPツール群を通じて外部エージェント経由で行います(未使用のIPC
read_file/write_fileはセキュリティ上削除済み)。 - セキュリティファースト: 任意のファイルアクセスや外部通信を防ぐため、通信先の localhost 限定バリデーションをRustレイヤーで強制しています。また、Stripe(決済機能)はDesktop環境ではガードされ、Web環境でのみ有効化されます。
- SSOT (Single Source of Truth): Next.jsコードベースを唯一のソースコード(SSOT)として維持し、ビルド時にNode.jsサーバーを同梱する方式を採用することで、メンテナンスコストを最小限に抑えています。
- ランタイム環境変数: ビルド時に
.envファイルをTauriリソースとして同梠し、アプリ起動時にHonoサーバーへ環境変数として供給する仕組みを採用しています。これにより、CI/CDのシークレット管理と統合された安全な環境変数供給を実現しています。 - デスクトップ固有機能:
- システムトレイ: ウィンドウを閉じるとトレイに最小化し、トレイメニューから表示/終了を操作可能。
- スプラッシュスクリーン: 起動時にロゴとローディングアニメーションを表示し、Honoサーバーの準備完了後にメイン画面へ遷移。
- 自動アップデート: Tauri Updaterプラグインによる署名付きアップデート配信(AboutDialog UIから手動確認可能)。
- プロジェクトファイル形式:
.blueproject形式によるポータブルスナップショットのエクスポート/インポート。Bookshelfでのドラッグ&ドロップインポートに対応。 - ウィンドウ状態の永続化:
tauri-plugin-window-stateにより、ウィンドウの位置・サイズを次回起動時に自動復元。
- CI/CD: GitHub Actionsによるマルチプラットフォームビルド。
release.ymlでプラットフォーム選択が可能(開発中はWindowsのみビルドしてActions無料枠を節約)。
3.5. データ永続化とクラウド同期
-
クライアントサイド永続化:
- 技術: IndexedDB (ブラウザ内データベース)
- ライブラリ: Dexie.js
- 役割: ユーザーが作成した全データ(プロジェクト、チャット履歴、キャラクター設定など)をクライアントサイドで永続化します。Explore機能の実装のためにSupabaseの実装が完了したあとも、Bookshelfやチャットなどのデータの自己所有を維持するために維持されます。
-
E2E暗号化クラウド同期 (Simple Full Sync):
- 技術: Supabase Storage (E2E暗号化されたバックアップ保存), IndexedDB (ローカルデータソース)
- 役割: クライアントサイドのIndexedDB全体を単一のバックアップファイルとしてエクスポートし、ユーザーのSync KeyでE2E暗号化してSupabase Storageに安全に同期します。差分計算やマージロジックが不要な「Simple Full Sync(完全バックアップ同期)」方式を採用しており、単純性・整合性・安全性を優先した設計です。
- 詳細: 同期処理は
doc/system/10_sync_architecture.mdを参照してください。
-
サーバーサイド永続化 (Publish & User Accounts):
- 技術: Supabase (PostgreSQL & Storage)
- 役割: アプリケーションの公開機能を通じてユーザーが提出した作品(メタデータ、本文、カバー画像)およびユーザーアカウント情報をクラウド上で永続化します。これにより、ユーザーデータの自己所有権を尊重しつつ、Webプラットフォームとしての機能性を両立させます。
- Publish ID (Publish Slot) 概念: 公開機能に おいて、ローカルのプロジェクトIDとは別に「公開枠(スロット)」を識別する
publishIdを導入しています。これにより、プロジェクトを複製したりインポートしたりしてローカルIDが変わっても、同じpublishIdを保持し続けることで、単一の公開作品ページを継続的に更新することが可能です。また、閲覧統計や足跡データはこのpublishIdに紐付けて集計されます。
3.6. Prompt Engine & Dynamic Context Integration
本アプリケーションは、AIへのプロンプトを動的に構築し、外部データやプロジェクト情報を注入する高度なプロンプトエンジンを搭載しています。
- Prompt Resolver:
- 各プロンプトカードの内容を解析し、「APIコネクター」や「プロジェクト参照」を解決します。
{{DATA}}プレイスホルダーの置換や、ドット記法(Selector)による外部データの抽出を担当します。
- Dynamic Context Injection:
- 執筆時やチャット時に、別プロジェクトのプロット、特定のセクションの原稿本文、最新の外部ニュース(API経由)などを文脈に注入します。
- Message Normalization (LLM Provider Hygiene):
- Google Gemini や Claude 等の厳格なプロバイダー要件を満たすため、送信直前にメッセージリストを最適化します。
- 複数のシステムメッセージの統合、順序の正常化(必ず先頭に一つ)、連続する同一ロールメッセージの結合、空メッセージの除去等を行い、APIエラーを未然に防ぎます。
- 実装は
src/lib/chat/formatters.tsのnormalizeMessagesに集約され、BFF (Hono) レイヤーで自動適用されます。
4. データフローの概要 (プロジェクトデータ)
プロジェクトデータの読み込み、編集、保存のライフサイクルは、JotaiとDexie.jsの連携によって実現されています。
- 初期ロード:
AppManager.tsxがマウント時、loadProjectAtomをトリガーします。このAtomはIndexedDBからProjectRecordを読み込み、コア状態であるprojectAtomにセットします。 - UIとの連携: UIコンポーネントは
projectAtomを購読し、表示・編集を行います。ユーザーによる変更は即座にprojectAtomに反映されます。 - 自動保存:
AutoSaveManager.tsxがprojectAtomの変更を監視し、デバウンスを挟んでsaveProjectAtomをトリガーします。このAtomが最新の状態をIndexedDBに書き戻します。
このフローの詳細は 03_state_management.md のMermaid図を参照してください。
関連ドキュメント:
02_technology_stack.md03_state_management.md04_database_schema.md10_memory_portability_standard.md11_long_term_memory_architecture.md12_ai_agent_architecture.md