BluePeriod Docs
開発

データベース設計仕様書

Dexie.jsによるIndexedDBのスキーマ定義とデータ構造

データベース設計仕様書 (04_database_schema.md)

1. 概要

本アプリケーションのデータ永続化層は、クライアントサイドのIndexedDBをDexie.jsライブラリを介して利用しています。これにより、型安全なデータベースアクセスと効率的なクエリ、スキーマのバージョン管理を実現しています。

  • データベース名: blue-period-db
  • 主要ライブラリ: Dexie.js
  • 実装ファイル: next-app/src/lib/db.ts
  • 型定義ファイル: next-app/src/lib/types.ts
  • 設計思想:
    • データの自己所有: PublishなどのオンラインWebサービス以外の全てのプロジェクトデータはクライアントサイドに保存され、ユーザーデータのプライバシーと所有権を最優先します。このドキュメントで記述されているスキーマは、このクライアントサイドデータベースのものです。
    • オンラインWebサービス: Supabaseによって実装されるWebサービス(Publish・Explore等)に公開する際、既存の公開枠に対する更新操作はサービス層(publishProject)で所有権(user_idの一致)が厳密に検証されます。これにより、他者の公開作品を誤って上書きするリスクを排除しています。詳細は 01_architecture.md の「データ永続化」セクションを参照してください。
    • スキーマバージョン管理: スキーマはDexieのバージョン管理機能を通じて段階的に更新され、現在は バージョン 24 です。

2. テーブル一覧

このデータベースは、以下のテーブルで構成されています。

テーブル名主な役割主キーの型
projectsプロジェクト全体のメタデータと実データを格納UUID (string)
chatPromptsAIチャット設定用のプロンプトカードを管理UUID (string)
promptAssets再利用可能なプロンプトアセットを管理UUID (string)
charactersAIチャットのキャラクター(ペルソナ)を管理UUID (string)
chatSessionsチャットのセッション情報を管理UUID (string)
chatMessages個別のチャットメッセージを格納UUID (string)
localSnapshots手動操作前のDBスナップショットを保持Auto-increment (number)
vectorIndexOramaベクトルインデックスの永続化UUID (string)
sessionArtifactsエージェントセッションの資料(Artifacts)管理UUID (string)
stats日次の執筆・読書統計データを格納YYYY-MM-DD (string)
globalStoreアプリ全体の状態や永続的な小規模データstring (key)

3. テーブルスキーマ詳細

3.1. projects

プロジェクトの核心的なデータを格納するメインテーブルです。

  • 目的: ユーザーが作成した各小説プロジェクトのメタデータ(タイトル、作者名など)と、プロットや原稿といった全てのコンテンツを保持します。

  • スキーマ定義: &id, publishId, title, author, updatedAt

    • &id: 主キー。UUID v4形式の文字列。
    • publishId: インデックス付き。公開先スロットID。
    • title: インデックス付き。プロジェクトのタイトル。
    • author: インデックス付き。作者名。
    • updatedAt: インデックス付き。最終更新日時。
  • カラム詳細:

カラム名説明
idstringプロジェクトの一意なID (UUID)
publishIdstring (optional)公開先スロットID (UUID)
titlestringプロジェクトのタイトル
authorstring (optional)著者名
imageUrlstring (optional)画像URL
coverImage`Blobnull` (optional)
createdAtDate作成日時
updatedAtDate最終更新日時
contentProjectContentプロジェクトの本体データ。structuredPlotmanuscriptswritingPromptsが含まれる。
  • データモデル (ProjectRecord):
    interface ProjectRecord {
      id: string; // Primary Key (UUID)
      publishId?: string | null; // 公開先スロットID
      title: string;
      author?: string;
      imageUrl?: string;
      coverImage?: Blob | null;
      createdAt: Date;
      updatedAt: Date;
      content: ProjectContent; // ネストされたプロジェクト実体
      revision?: number; // 保存操作の順序を識別するためのリビジョン番号
      isSample?: boolean; // サンプルプロジェクトの場合true
    }
    
    interface ProjectContent {
      structuredPlot: StructuredPlot;
      manuscripts: Manuscript;
      writingPrompts: PromptCard[]; // 執筆プロンプト(スキーマバージョン12で統合)
      plotTranslations?: { // プロット要素の多言語翻訳(スキーマバージョン15付近で追加)
        [lang: string]: {
          [id: string]: PlotTranslation;
        }
      };
    }
    
    interface PlotTranslation {
      title?: string;
      purpose?: string;
      content?: string;
    }

3.2. writingPrompts (※スキーマバージョン12で削除)

重要: 執筆プロンプトは、スキーマバージョン12で独立テーブルから削除され、プロジェクトの content.writingPrompts に統合されました。

  • 以前の目的: 特定のプロジェクトに紐付く、再利用可能なプロンプト群を管理していました。

  • 現在の状態: プロジェクトの ProjectContent オブジェクト内の writingPrompts フィールドに統合されています。

  • データモデル (PromptCard):

    interface PromptCard {
      id: string;
      role: 'system' | 'user' | 'assistant';
      content: string;
      enabled: boolean;
      cardType: 'text' | 'api_connector' | 'project_ref';
      dynamicConfig?: DynamicConfig;
      order: number;
      projectId?: string; // プロジェクトとの紐付け
      updatedAt: Date;
    }
  • プロジェクト構造 (ProjectContent):

    interface ProjectContent {
      structuredPlot: StructuredPlot;
      manuscripts: Manuscript;
      writingPrompts: PromptCard[]; // 執筆プロンプトはここに統合
    }

3.3. chatPrompts

AIチャット機能全体に影響を与えるシステムプロンプトを管理します。

  • 目的: writingPromptsとは異なり、特定のプロジェクトに依存しないグローバルなチャット設定用プロンプトを保持します。

  • スキーマ定義: &id

    • &id: 主キー。UUID v4形式の文字列。
  • カラム詳細:

カラム名説明
idstringプロンプトカードの一意なID
rolePromptCardRole`'system'
contentstringプロンプトの内容
enabledbooleanこのプロンプトが有効かどうか
cardTypestring`'text'
dynamicConfigobject動的設定(API URL、プロジェクトIDなど)
ordernumberカードの並び順
updatedAtDate (optional)最終更新日時
  • データモデル (PromptCard): 上記writingPromptsと同様。

3.4. characters

AIチャットで対話相手となるキャラクター(ペルソナ)の情報を管理します。

  • 目的: チャット相手のAIに特定の役割や口調を与えるための設定を保持します。

  • スキーマ定義: &id, name, updatedAt

    • &id: 主キー。UUID v4形式の文字列。
    • name: インデックス付き。キャラクター名。
    • updatedAt: インデックス付き。最終更新日時。
  • カラム詳細:

カラム名説明
idstringキャラクターの一意なID (UUID)
namestringキャラクター名
promptstringキャラクターのペルソナを定義するプロンプト
avatarUrlstringアバター画像のBase64エンコードデータ
createdAtDate作成日時
updatedAtDate最終更新日時(クラウド同期の差分検知に使用)
  • データモデル (Character):
    interface Character {
      id: string;
      name: string;
      prompt: string; // このキャラクターの役割を定義するシステムプロンプト
      avatarUrl: string; // Base64 encoded image data
      createdAt: Date;
      updatedAt: Date;
    }

3.5. chatSessions

個々のチャットセッションのメタデータを管理します。

  • 目的: 過去のチャット履歴をセッション単位で管理し、一覧表示や再開を可能にします。

  • スキーマ定義: &id, character_id, updatedAt, createdAt

    • &id: 主キー。UUID v4形式の文字列。
    • character_id: インデックス付き。charactersテーブルへの外部キー。
    • updatedAt: インデックス付き。セッションの最終更新日時。
    • createdAt: インデックス付き。作成日時。
  • カラム詳細:

カラム名説明
idstringセッションの一意なID (UUID)
titlestringセッションのタイトル
character_idstringどのキャラクターとの会話かを示す外部キー (characters.id)
createdAtDate作成日時
updatedAtDate最終更新日時
  • データモデル (ChatSession):
    interface ChatSession {
      id: string;
      title: string;
      character_id: string; // Foreign key to Character.id
      updatedAt: Date;
      createdAt: Date;
    }

3.6. chatMessages

各チャットセッションに含まれる個別のメッセージを時系列で格納します。

  • 目的: ユーザーとAI間の対話履歴を完全に保存します。

  • スキーマ定義: &id, session_id, createdAt, updatedAt

    • &id: 主キー。UUID v4形式の文字列。
    • session_id: インデックス付き。chatSessionsテーブルへの外部キー。
    • createdAt: インデックス付き。メッセージの作成日時。
    • updatedAt: インデックス付き。メッセージの最終更新日時。
  • カラム詳細:

カラム名説明
idstringメッセージの一意なID (UUID)
session_idstringどのセッションに属するかを示す外部キー (chatSessions.id)
author`'user'string`
contentstringメッセージの内容
updatedAtDate最終更新日時(同期および並び替え用)
createdAtDate作成日時
type`'message''separator'` (optional)
metadataChatMessageMetadata (optional)AIの応答に関するメタデータ
  • データモデル (ChatMessage):
    interface ChatMessage {
      id: string;
      session_id: string; // Foreign key to ChatSession.id
      author: 'user' | string; // 'user' または Character.id
      content: string;
      createdAt: Date;
      updatedAt: Date; // スキーマバージョン21で追加
      type?: 'message' | 'separator';
      metadata?: ChatMessageMetadata;
    }

3.13. 索引に関する重要事項

IndexedDBにおいて日付フィールド(createdAt, updatedAt)を正しく索引するためには、標準の JavaScript Date オブジェクトである必要があります。Temporal APIのポリフィルオブジェクトや、単なるISO文字列をそのまま保存すると、索引から除外され、並び替えや検索が機能しなくなります。

これを防ぐため、データの保存および同期からの復元時には必ず @/lib/utils/dateensureDate ユーティリティを使用します。

3.7. localSnapshots

危険な操作の直前に、ローカルデータベースのバックアップ(スナップショット)を保存します。

  • 目的: 意図しないデータ消失や上書き事故が発生した際に、直前の状態に復旧できるようにします。

  • 重要: データベースのエクスポート時(スナップショット作成、クラウド同期、手動エクスポート)には、再帰的な肥大化を防ぐため、この localSnapshots テーブル自体はエクスポート対象から除外されます。また、自動同期ループからも除外されます。

  • スキーマ定義: ++id, timestamp, reason

    • ++id: 主キー。
    • timestamp: インデックス付き。作成日時のタイムスタンプ。
    • reason: 作成理由(例: 'pre-sync')。
  • カラム詳細:

カラム名説明
idnumberスナップショットの一意なID
timestampnumber作成日時のタイムスタンプ
reasonstring作成理由(例: 'pre-sync')
dataBlobデータベース全体のBlobダンプ
  • データモデル (SnapshotRecord):
    interface SnapshotRecord {
      id?: number;
      timestamp: number;
      reason: string;
      data: Blob;
    }

3.8. promptAssets

再利用可能なプロンプトテンプレート(アセット)を管理します。

  • 目的: グローバルで再利用可能なプロンプトテンプレートを保持し、執筆やチャットの際にテンプレートとして利用できるようにします。タグ、説明、公開設定などのメタデータを含みます。

  • スキーマ定義: &id, title, updatedAt

    • &id: 主キー。UUID v4形式の文字列。
    • title: インデックス付き。プロンプトアセットのタイトル。
    • updatedAt: インデックス付き。最終更新日時。
  • カラム詳細:

カラム名説明
idstringプロンプトアセットの一意なID
titlestringプロンプトアセットのタイトル
descriptionstring (optional)プロンプトアセットの説明
contentstringプロンプトの内容
assetTypestring`'text'
dynamicConfigobject動的設定(アセット自体のデフォルト設定)
tagsstring[] (optional)タグ一覧
enabledbooleanこのアセットが有効かどうか
isPublicboolean (optional)公開設定
createdAtDate作成日時
updatedAtDate最終更新日時
  • データモデル (PromptAsset):
    interface PromptAsset {
      id: string;
      title: string;
      description?: string;
      content: string;
      assetType: 'text' | 'api_connector' | 'project_ref';
      dynamicConfig?: DynamicConfig;
      tags?: string[];
      enabled: boolean;
      isPublic?: boolean;
      createdAt: Date;
      updatedAt: Date;
    }

3.9. vectorIndex

Oramaによる全文検索・ベクトル検索のためのインデックスデータを永続化するテーブルです。

  • 目的: AIチャットの長期記憶(Long-Term Memory)機能において、ユーザーの過去の会話を検索可能にするためのベクトルインデックスを保存します。

  • スキーマ定義: &id, updatedAt

    • &id: 主キー。UUID v4形式の文字列。
    • updatedAt: インデックス付き。最終更新日時。
  • カラム詳細:

カラム名説明
idstringインデックスの一意なID
dataunknownシリアライズされたOramaインデックスデータ
updatedAtstring最終更新日時(ISO文字列)
modelIdstring (optional)埋め込みモデルの識別子

3.9.1. ベクトル整合性とモデル管理

長期記憶のベクトル検索を正常に機能させるため、以下の整合性管理ルールが適用されます:

  1. 次元の一致: ベクトル次元数は埋め込みモデル(Embedding Model)に固有であり、異なるモデルのベクトルが同一のインデックスに混在することはできません。混在した場合、検索結果が破壊されるか、ランタイムエラーが発生します。
  2. モデル不一致の検出: 永続化された modelId がアプリの現在の設定値と異なる場合、システムはUI上で「再ベクタライズ」を促す警告を表示します。管理画面上では、不一致が発生していても旧モデルのインデックスからデータを一時的に読み出し、件数を表示することが可能です。
  3. 明示的操作: 記憶の取得、追加、更新、削除のすべての操作において、常に現在の modelId が明示的に渡され、そのモデルに対応する正しい Orama インスタンスが選択されます。
  4. 再ベクタライズ (実装済み): 過去のモデルで作成された記憶を現在の新モデルでも利用可能にするため、以下のプロセスを実行します:
    • 旧モデルの modelId をキーに IndexedDB からシリアライズされたインデックスを取得。
    • 旧 Orama インスタンスを展開し、全記憶ドキュメント(テキスト・メタデータ)を抽出。
    • 現在(新)のモデルを使用して、テキストデータを再ベクトル化。
    • 新しい Orama インデックスを生成し、同一のキー(chat-memory-index)で IndexedDB を上書き保存。

3.10. sessionArtifacts

エージェントセッションにおける一時的な資料(Artifacts)を管理するテーブルです。

  • 目的: AIエージェントがWeb検索やプロジェクトデータ参照で得た情報を「机の上の資料」として保存し、後続の対話で再利用可能にします。

  • スキーマ定義: &id, sessionId, isActive, createdAt

    • &id: 主キー。UUID v4形式の文字列。
    • sessionId: インデックス付き。紐付くチャットセッションID。
    • isActive: インデックス付き。コンテキスト注入のON/OFF。
    • createdAt: インデックス付き。作成日時(タイムスタンプ)。
  • カラム詳細:

カラム名説明
idstringアーティファクトの一意なID
sessionIdstring紐付くチャットセッションのID
typestringアーティファクトの種類(`'web_search'
titlestring資料のタイトル
contentstring資料の内容(JSON文字列またはテキスト)
isActivebooleanコンテキスト注入が有効かどうか
createdAtnumber作成日時(タイムスタンプ)
updatedAtnumber更新日時(タイムスタンプ)

3.11. stats

日次の執筆文字数や読書アクティビティを記録するための統計テーブルです。

  • 目的: ユーザーの創作意欲を高めるため、日ごとの進捗を可視化します。

  • スキーマ定義: date

    • date: 主キー。YYYY-MM-DD 形式の文字列。
  • カラム詳細:

カラム名説明
datestring日付(YYYY-MM-DD)
totalWordCountnumberその日の終了時点での全プロジェクト合計文字数
readPublishIdsstring[]その日に閲覧したプロジェクト/作品の公開スロットIDリスト
updatedAtnumber最終更新タイムスタンプ
  • データモデル (DailyStats):
    interface DailyStats {
      date: string;
      totalWordCount: number;
      readPublishIds: string[];
      updatedAt: number;
    }

3.12. globalStore

アプリケーション全体の状態管理や、特定のページの状態を永続化するための汎用的なキーバリューストアです。

  • 目的: ページをリロードしても維持したい小さなデータ(ダッシュボードの目標値、スクラッチパッドの内容など)を保存します。

  • スキーマ定義: key

    • key: 主キー。一意の識別子。
  • カラム詳細:

カラム名説明
keystringキー(例: 'daily-word-goal', 'atelier-scratchpad')
valueany保存される値
  • データモデル:
    interface GlobalStoreRecord {
      key: string;
      value: any;
    }

4. データポータビリティとエクスポートフォーマット

4.1. .bluememory (長期記憶エクスポート形式)

長期記憶 (Long-term Memory) のデータを特定の埋め込みモデルに依存しない形式で可搬させるためのフォーマットです。

  • ファイル拡張子: .bluememory
  • データ構造 (JSON):
    • version: フォーマットバージョン。
    • memories: 各メッセージの内容、ロール、キャラクター背景、タイムスタンプを含むリスト。
  • 設計思想:
    • ベクトル非依存: ベクトル(Embedding)自体は保存せず、テキストとメタデータのみを保存します。これにより、インポート時に異なるモデル(例: gte-multilingual から ruri-v3)で再ベクトル化することが可能です。
    • 選択的エクスポート: プロジェクト全体の情報を含まず、AIとの会話文脈(外部記憶)のみを抽出してポータブルにします。

4.2. .blueperiod (プロジェクトバックアップ形式)

  • 詳細: doc/system/10_sync_architecture.md を参照。
  • 特徴: IndexedDB全体の完全に同一の環境を再現するためのフォーマットです。

On this page