# データベース

> セルフホスティング環境の Nodaro を、同梱の Supabase スタックかマネージドの Supabase プロジェクトで動かします。マイグレーションの適用方法と、データベースのキーとパスワードの保護も説明します。

Source: https://nodaro.ai/ja/docs/self-hosting/database

Nodaro は、**データベース**として Supabase を使います。データの保存には Postgres、ログインには GoTrue、エディターが読み書きするデータ API には PostgREST を使います。Compose スタックにはこの 3 つが同梱されており、データベースのマイグレーションも自動で適用されます。代わりに、Nodaro の接続先をマネージドの Supabase プロジェクトにして、マイグレーションを自分で適用することもできます。

## 同梱のスタック
| サービス | イメージ | 役割 |
| --- | --- | --- |
| `db` | Supabase Postgres | データベース（`db-data` ボリュームに保存） |
| `auth` | GoTrue | メールアドレスとパスワードによるアカウント登録とログイン |
| `rest` | PostgREST | データ API |

ブラウザーと API は、アプリ自身のオリジンの `PUBLIC_URL/supabase` を通じて、ログインとデータ API にアクセスします。Nodaro コンテナ内の Web サーバーが `/supabase/auth/v1` を GoTrue に、`/supabase/rest/v1` を PostgREST に転送するため、追加のポートやドメインは必要ありません。

同梱のスタックは、メールを送信しません。アカウントは、登録後すぐに使えます。

### 同梱のスタックでのマイグレーション
アプリのコンテナは、API が起動する前に、`supabase/migrations/` 内のすべてのファイルを適用します。これには `RUN_MIGRATIONS_ON_BOOT=true` と `DATABASE_URL` が必要ですが、どちらも Compose ファイルで設定済みです。

- **適用済みのファイルは記録され**、次回の起動時にはスキップされます。
- **マイグレーションが途中までしか適用されていないデータベースで動くことはありません**。マイグレーションが失敗すると API は起動を拒否し、コンテナのログにそのファイル名が表示されます。
- **原因を修正してから、もう一度起動します**。修正したら、`docker compose -f docker-compose.community.yml up` をもう一度実行します。適用済みのファイルはスキップされます。

### 同梱のデータベースを保護する
デフォルトのキーとパスワードは、公開されている値です。スタックをネットワークに公開する前に、次の作業を行います。

1. `node tools/generate-selfhost-keys.mjs >> .env` で**新しい認証キーを発行します**。このスクリプトは、`SUPABASE_JWT_SECRET`、`SUPABASE_ANON_KEY`、`SUPABASE_SERVICE_ROLE_KEY` を出力します。キーはシークレットで署名されるため、3 つとも同じ実行で生成したものを使う必要があります。
2. **`POSTGRES_PASSWORD` と、それに合わせた `DATABASE_URL` を設定します**。たとえば `postgres://postgres:<new-password>@db:5432/postgres` のようにします。
3. `docker compose -f docker-compose.community.yml up -d` で**変更を反映します**。

データベースが `supabase_auth_admin` や `authenticator` などの内部ロールのパスワードを `POSTGRES_PASSWORD` に合わせるのは、**初回**の起動時だけです。`db-data` ボリュームがすでにある場合は、ボリュームを削除する（データも削除されます）か、`supabase_admin` としてロールのパスワードを手動で変更します。そうしないと、ログインが `password authentication failed for user "supabase_auth_admin"` で失敗します。

## マネージドの Supabase プロジェクトを使う
supabase.com のプロジェクトで、同梱の `db`、`auth`、`rest` サービスを置き換えます。無料プランで十分です。`.env` に次の値を設定します。

```bash
SUPABASE_URL=https://YOUR-PROJECT.supabase.co
SUPABASE_ANON_KEY=eyJ...
SUPABASE_SERVICE_ROLE_KEY=eyJ...
FRONTEND_SUPABASE_URL=https://YOUR-PROJECT.supabase.co
RUN_MIGRATIONS_ON_BOOT=false
NODARO_ENCRYPTION_KEY=<64-character hex>
```

- **`FRONTEND_SUPABASE_URL`** は、ブラウザーが使うプロジェクトの URL です。公開されているイメージは同梱のスタック向けにビルドされており、別の URL は、起動時にこの変数からしか読み取りません。
- **`RUN_MIGRATIONS_ON_BOOT=false`** は、マイグレーションランナーを無効にします。マイグレーションは、後述の方法で自分で適用します。
- **`NODARO_ENCRYPTION_KEY`** は、必ず設定します。たとえば `openssl rand -hex 32` で生成できます。スタックがこのキーを自動で生成するのは、マイグレーションランナーがオンのときだけです。キーがないと、プロバイダーキーの貼り付けと Nodaro Cloud への接続が `EncryptionKeyMissingError` で失敗します。

環境をすでに同梱のスタックで動かしていた場合は、そのキーを再利用します。キーは、`app-data` ボリュームの `/data/nodaro/encryption-key` にあります。新しいキーでは、古いキーで暗号化したデータを読み取れません。

### マネージドプロジェクトにマイグレーションを適用する
`supabase/migrations/` 内のすべてのファイルを、**ファイル名の順**に適用します。順序は、`001_` や `002_` のようなゼロ埋めの接頭辞で決まります。

- **SQL エディターを使う場合**：Supabase のダッシュボードで **SQL editor** を開き、各ファイルを順に実行します。
- **Supabase CLI を使う場合**：こちらのほうが速く適用できます。

```bash
supabase link --project-ref YOUR-REF
supabase db push
```

マイグレーションは、マイグレーション済みのデータベースで再実行しても問題ありません。ただし、シードデータ用のファイルなど、ファイル内に別の記載がある場合は除きます。新しいデータベースで実行する場合は、常に問題ありません。

アップデートのたびに、新しいイメージで再起動する**前に**、新しいファイルをファイル名の順に適用します。マイグレーションが欠けていても、通常は API は止まりません。ただし、そのマイグレーションを必要とする機能は、テーブルができるまで `500` を返します。

## マネージドプロジェクトを自分のオリジン経由で提供する
ネットワークによっては、ブラウザーのリクエストをすべてホスト名でフィルタリングし、Supabase のドメインをブロックしている場合があります。そのようなネットワークでは、Nodaro コンテナ内の Web サーバーが、アプリ自身のオリジンを通じてマネージドプロジェクトに転送できます。次の 3 つの変数を、まとめて設定します。

```bash
SUPABASE_MANAGED_PROXY=true
FRONTEND_SUPABASE_URL=/supabase
SUPABASE_PROXY_UPSTREAM=https://YOUR-PROJECT.supabase.co
```

- `SUPABASE_PROXY_UPSTREAM` には、パスを含まないオリジンを指定します。
- `SUPABASE_URL` は、プロジェクトの HTTPS の URL のままにします。API は引き続き、この URL に直接接続します。
- ブラウザーは、`/supabase` をページのオリジンを基準に解決します。Web サーバーは、ログイン、REST、ストレージ、Realtime のリクエストを、WebSocket のアップグレードも含めてプロジェクトに転送します。
- トークンと API キーは、そのまま通過します。プロキシが特権的な認証情報を追加することはありません。
- Supabase でカスタムドメインを追加しなくても、複数のドメインで同じ設定を使えます。

Compose ファイルは、`.env` の `SUPABASE_MANAGED_PROXY` と `SUPABASE_PROXY_UPSTREAM` をアプリに渡しません。`nodaro` サービスの `environment:` の下に追加してください。設定しない場合、プロキシはオフのままで、同梱のルートはこれまでどおりに動作します。

## データベースを利用できないとき
マイグレーションや復旧のために Postgres が停止すると、API は、データベースに再び接続できるまで再起動を繰り返します。これは想定どおりの動作です。Postgres が復帰したら、Nodaro コンテナを再起動します。

```bash
docker compose -f docker-compose.community.yml restart nodaro
```

## データベースに保存されるもの
ワークフローとプロジェクト、ユーザーのプロフィール、実行とその進行状況、ジョブ、生成したメディアの記録、API トークンと OAuth アプリ、そして暗号化されたプロバイダーキーと SNS のログイン用トークンです。すべてのテーブルで行レベルセキュリティが適用されるため、ユーザーは自分の行しか見られません。メディアファイル自体はオブジェクトストレージに保存され、Redis が保持するのは、短期間だけ必要なジョブの状態だけです。

データベースは、暗号化キーと一緒にバックアップします。[バックアップと復元](https://nodaro.ai/docs/self-hosting/backups)を参照してください。1 つのデータベースで 2 つの環境を動かす方法は、[スケーリング](https://nodaro.ai/docs/self-hosting/scaling#two-installs-one-database)を参照してください。

## Frequently asked questions

### Nodaro はどのデータベースを使いますか？

Supabase を使います。Supabase は、Postgres に、ログイン用のサービスである GoTrue とデータ API の PostgREST を組み合わせたものです。Compose スタックには 3 つとも同梱されています。supabase.com のマネージドプロジェクトを、Nodaro の接続先にすることもできます。

### データベースのマイグレーションは、自分で実行する必要がありますか？

同梱のスタックでは不要です。起動のたびにマイグレーションを適用し、適用済みのものはスキップします。マネージドの Supabase プロジェクトでは、RUN_MIGRATIONS_ON_BOOT=false を設定し、SQL エディターか supabase db push で、supabase/migrations/ をファイル名の順に適用します。

### マネージドの Supabase プロジェクトで、貼り付けたキーが EncryptionKeyMissingError で失敗するのはなぜですか？

スタックがインスタンスの暗号化キーを生成するのは、マイグレーションランナーがオンのときだけだからです。RUN_MIGRATIONS_ON_BOOT=false の場合は、NODARO_ENCRYPTION_KEY を自分で設定するか、以前に同梱のスタックで動かしていた環境が app-data ボリュームに保存したキーを再利用します。

### 初回の起動後に POSTGRES_PASSWORD を変更できますか？

手動でのみ変更できます。データベースが内部ロールのパスワードを POSTGRES_PASSWORD に合わせるのは、初回の起動時だけです。db-data ボリュームを削除する（データも削除されます）か、supabase_admin としてロールのパスワードを変更してください。

### マイグレーションはロールバックできますか？

いいえ。マイグレーションは前に進めることしかできません。以前のバージョンに戻すには、アップデートの前に取得したバックアップを復元します。
