Skip to content
⚠️ この翻訳は機械翻訳です。ネイティブによるレビューは保留中のため、訳文に誤りが含まれる場合があります。

ADR 002 — 派生読み取りキャッシュとしてのSQLite

ステータス: 受理済み
日付: 2026-04

更新(2026-06)

署名付きイベントログはまだ実装されていません — 今日、取り込みはSQLiteに直接書き込みます(トレードオフで述べた「フェーズ1」の経路)。ログの設計もHypercoreから、Raiznetネイティブの追記専用イベントログへと移りました(ADR-004); SQLiteを派生インデックスとする原則は変わりません。

文脈

Raiznetが意図するソースオブトゥルースは、追記専用で暗号学的に署名されたイベントログです。しかし、そのようなログから直接、高速なAPIクエリ(時間範囲の読み取り、集計、H3セルでのフィルタ)を提供するのは非現実的です。それは逐次追記と複製のために設計されており、ランダムアクセスのインデックスクエリのためではありません。

二次インデックス層が必要です。

決定

SQLitebetter-sqlite3 経由)を派生読み取りキャッシュとして使います。長期的なソースオブトゥルースを意図していません。イベントログが存在すれば、破損または削除されたSQLiteデータベースは、最初のイベントからログを再生することで完全に再構築できます。

2つの別個のデータベースを維持します。

データベース供給元アクセス
raiznet_public.db公開取り込み(イベントログ複製は計画中)公開エンドポイント
raiznet_private.dbローカル取り込みのみローカルエンドポイントのみ

根拠

  • クエリ性能: REAL 型の固定カラムにより、インデックス付きの標準SQL集計(AVG、MIN、MAX、GROUP BY)が可能。クエリ時のJSONパースなし。
  • スキーマの単純さ: ORMなし — better-sqlite3 の同期APIで型付き結果を直接SQL。
  • 再構築の保証(イベントログが入ったら): SQLiteはログから派生するため、スキーマの進化はデータ損失を意味しません。ファイルを削除し、再生すれば完了です。
  • 分離によるセキュリティ: 公開エンドポイントのFastifyインスタンスは raiznet_public.db への接続のみを保持します。データベース接続オブジェクトがそもそも利用できないため、公開エンドポイントのクエリはプライベートデータを返せません — 分離はクエリレベルではなく接続レベルです。
  • better-sqlite3 の同期API: Fastifyの非同期ルートハンドラに自然に収まり、別個のスレッドプールやコールバックの間接化を必要としません。

トレードオフ

  • 新しいセンサー型の追加にはスキーマ移行(3つの新カラム: _plain, _cipher, _nonce)が必要です。これは高速な集計クエリのために受け入れたコストです。
  • ワイドテーブル設計(1読み取りにつき1行、すべてのセンサーカラムを同じ行に)は、狭いキー値テーブルより多くのディスク容量を使いますが、joinなしでインデックス付き範囲クエリを可能にします。
  • フェーズ1はSQLiteに直接書き込みます。フェーズ2はイベントログ → インデクサ → SQLiteのパイプラインを追加します。API層は両フェーズで常にSQLiteから読みます。

帰結

  • apps/server/src/storage/public-db.tsprivate-db.ts がスキーマ作成(CREATE TABLE IF NOT EXISTS)を所有します。
  • フェーズ1には移行フレームワークなし — テーブルは初回起動時に作成され、スキーマは安定です。
  • インデクサ(フェーズ2)は、イベントログ複製が有効になると raiznet_public.db への唯一の書き込み手になります。
  • raiznet_private.db は常にローカル取り込み経路で直接書き込まれます — 決して複製されません。