コンテンツにスキップ

マルチテナント設計

方針

全テナントが同一スキーマを共有し、各行を tenant_id で分離する 共有DB + 行分離 方式を採用。さらに PostgreSQL の Row-Level Security (RLS) でテナント越境を DB レベルで防ぎます(多層防御)。

仕組み

リクエスト
└─ テナント解決 (現状: x-tenant-id ヘッダー / 将来: JWT claim)
└─ AsyncLocalStorage にテナントIDを格納
└─ withTenant(db, tenantId, fn)
└─ トランザクション内で set_config('app.current_tenant', ...)
└─ RLS ポリシーが tenant_id = current_tenant_id() で行を絞り込み
  • アプリは RLS が効く制限ロール app_user で接続する。
  • マイグレーションのみ、RLS をバイパスできるオーナーロールで実行する。
  • ポリシー定義は packages/db/sql/rls.sql

新しいテナント所属テーブルを追加するとき

  1. tenant_id カラム + テナント内一意制約 + tenant_id インデックスを付ける。
  2. packages/db/sql/rls.sqltenant_tables 配列にテーブル名を追記する。
  3. クエリは必ず withTenant 経由で実行する(直接 db.select() を呼ばない)。

詳細な決定経緯は ADR-0003 を参照。