【React】Supabase CLI を使ってデータベース（PostgreSQL）関連を操作するやり方

**Supabase CLI を使ってデータベース（PostgreSQL）関連の操作を行う際の概要**を整理し、実際の使用パターンごとに「どのようなコマンドを使い、どんなフローになるか」の例を示します。特に、**マイグレーション管理**や**ローカル開発**などでよく使われるコマンドが中心です。

## 1. Supabase CLI で扱う主なDB関連コマンド

1. **`supabase start`**  
   - Dockerを使って **ローカル環境 (Postgres + Supabase API + Storage)** を立ち上げる。  
   - あくまで**ローカル専用**。外部からはアクセスできない。

2. **`supabase db pull`**  
   - **リモート（本番/ステージング）** のDBスキーマを **ローカル** に同期して、`supabase/schema.sql` や `supabase/migrations/` に書き出す。
   - すでにブラウザでテーブルを作ってしまった場合、そのスキーマをローカルに取り込める。

3. **`supabase db push`**  
   - ローカルにある **マイグレーション or スキーマ** を **リモート** に反映する。  
   - 「リモートにもローカルと同じDB構造を適用したい」ときに使う。

4. **`supabase migration new <name>`**  
   - **マイグレーションの雛形**となるSQLファイル or ディレクトリを `supabase/migrations/` に生成する。  
   - 生成されたファイルに `CREATE TABLE` や `ALTER TABLE` などのDDLを書く → その後 `supabase db push` でリモートに適用。

5. **`supabase migration up` / `supabase migration down`**  
   - ローカルDB または リモートDB に対して、**マイグレーションを順方向 / 逆方向** に適用する。  
   - 通常はローカル開発用か、あるいはCI/CDで使うことが多い。

6. **`supabase seed`** / **`supabase/seed.sql`**  
   - 初期データ（Seed）を挿入するためのSQLを実行する。  
   - `supabase db push` 時に自動実行される設定にすることも可能。  
   - ただし警告が出る場合（`no seed files matched`）は、`seed.sql` が存在しないかパターンが合っていないということ。

## 2. 代表的な使用パターン例

### 2.1 ローカル開発のみ行う場合

- **フロー**: 
  1. `supabase init`  
     - ローカルに `supabase/` フォルダを作り、設定ファイルを生成。
  2. `supabase start`  
     - Dockerコンテナ上で**ローカルPostgres + Supabase API** を起動。
  3. **テーブルやスキーマを作る**  
     - 2パターン：  
       A. ブラウザの Supabase Studio に**ローカルURL**でアクセス（`http://localhost:54323`など）して GUI で作成する  
       B. `supabase migration new` → SQLを書く → `supabase migration up`  
  4. **アプリからローカルSupabaseに接続して開発**  
     - `.env` や config で `SUPABASE_URL=http://localhost:54321` (CLIのデフォルトポート) などを指定

- **ポイント**:  
  - DBがすべてローカルで完結するため、**ネット接続不要**で開発できる。  
  - 実際に**ブラウザ版のSupabase Studio**とまったく同じUIをローカルで触れるようになり、DBの中身もチェックしやすい。

### 2.2 リモート（本番・ステージング） をメインに使い、ローカルは使わない場合

- **フロー**: 
  1. **ブラウザ** で Supabase プロジェクトを作成（本番 or ステージング）。  
  2. `supabase link <project-ref>`  
     - 既存プロジェクトとローカルディレクトリを紐づけ。
  3. `supabase db pull`  
     - すでに作ったテーブルがあれば、**DBスキーマをローカルに取り込み** → `supabase/migrations/` に生成される。
  4. **スキーマ変更**  
     - `supabase migration new add_some_feature` → 生成されたSQLに `CREATE TABLE` / `ALTER TABLE` などを記述。  
     - その後 `supabase db push` でリモート（本番orステージング）DBを更新。
  5. **アプリ（Next.js / Expo）** 側は **リモートSupabase** に接続 (`SUPABASE_URL`, `SUPABASE_ANON_KEY`) して実装を進める。

- **ポイント**:  
  - ローカルDBを立てず、常に **「クラウド上の本番orステージングDB」** にマイグレーションを適用していく。  
  - ブラウザのSupabase Studioで編集しても良いが、**マイグレーション管理を使うなら CLIベース** でやると履歴が残る。

### 2.3 ステージング環境と本番環境の切り替え

- **ステージング用** プロジェクトと **本番用** プロジェクトを分けて作るケースが多い（2つの Project Ref）。  
- 例えば1つのリポジトリで、本番用には `supabase link <prod-project-ref>`、ステージング用には `supabase link <stg-project-ref>` と設定ファイルを切り替える... という運用もできます。  
  - ただし、**1リポジトリに対して1つのconfig.toml** が基本なので、ステージングと本番でブランチを分けるか、フォルダを分けるか、CIで `supabase db push --project-ref ...` のようにオプション指定するか、といった工夫が必要です。

### 2.4 ローカル -> ステージング -> 本番 の3段階パターン

1. **ローカル**: `supabase start` で開発し、`supabase migration new` & `migration up` でスキーマテスト。  
2. **ステージング**: 変更が安定したら `supabase db push` (紐づけ先はステージング環境のProject Ref) で適用。データの挙動確認。  
3. **本番**: 最終的にマイグレーションを **本番環境** に `db push` する。  

- **ポイント**  
  - 実際には CI/CD (例: GitHub Actions) で `supabase db push --project-ref stg_...` / `prod_...` のように自動化することも多い。  
  - 個人開発なら、1プロジェクトのみでローカル or 直接クラウドにpushするだけでもOK。

## 3. 注意点・ベストプラクティス

1. **マイグレーションをGitでバージョン管理**  
   - `supabase/migrations` に作られたSQLファイルを **Gitにコミット** しておくと、「いつ・どんなDDLが追加/変更されたか」を追跡できて便利。  
   - 将来的に DBを再構築する際にも役立ちます。

2. **`supabase/seed.sql` やシードファイルの活用**  
   - テストデータの挿入や初期データ投入が必要なら、`seed.sql` を用意して `INSERT INTO ...` 文を記述。  
   - `supabase db push` 時に自動的にシードが流し込まれる設定もできる（CLIバージョンやconfig次第）。

3. **CLI バージョンとプロジェクト設定の整合性**  
   - CLI と Supabase スタジオの機能が食い違うことがあるので、**なるべく最新CLI** を使う。  
   - `npm install -g supabase` などでアップデート可能。

4. **リモートに反映する際の権限・パスワード**  
   - `supabase db push` では、**DBのパスワード入力**を求められることがある。  
   - Supabaseプロジェクトの**Settings > Database** でパスワードを確認し、正しく入力してください（あるいは環境変数に設定）。

## 4. まとめ

- **ローカルで DB を立ち上げての開発 (`supabase start`)** と、**リモートプロジェクトへのマイグレーション管理 (`db pull` / `db push`)** が、Supabase CLI での主な利用シーン。  
- `supabase migration new` でSQLファイルを作り、それをGit管理 → `db push` でリモート適用、という流れが**本格開発でのベストプラクティス**です。  
- 個人開発でも使っておくと、後から**「いつどんなスキーマが変更されたか」** を追跡しやすくなり、環境を作り直す時もスムーズ。  
- ステージング・本番の複数環境を運用する場合は、**プロジェクトごとに `supabase link`** したり、**CI/CD** で `--project-ref` オプションを使ったりする形になることが多いです。

このように、**Supabase CLI を活用すると、データベースの構造や初期データなどをコード化 (SQLファイル) して扱える**ため、チーム開発や運用が非常にやりやすくなります。

---

## Q&A
<details><summary>マイグレーションファイルの命名規則もしくは命名のベストプラクティスはありますか？</summary>
Supabaseには、**特定の強制命名規則**はありませんが、一般的には次のような「**時系列 + 内容**」を示す命名がベストプラクティスとしてよく使われます。

---

## 1. Supabase CLI でのデフォルト挙動

たとえば、`supabase migration new add_comments_table` のようにコマンドを打つと、下記のようなディレクトリやSQLファイルが自動生成されます（バージョンや設定により少し違いはあります）:

```
supabase/
  └── migrations/
      ├── 20230901123456_add_comments_table/
      │   └── initial.sql
```

- 自動でタイムスタンプ（`YYYYMMDDHHMMSS` 形式）が先頭に付与され、後ろにコマンド引数として指定した `add_comments_table` が付く  
- この**「タイムスタンプ + 内容」**という形は、**時系列の並び**と**マイグレーションの内容**が一目でわかりやすく、ファイル衝突も減らせるため、実質的にベストプラクティスといえます。

---

## 2. 一般的なマイグレーションファイルの命名パターン

1. **タイムスタンプ＋スネークケース**  
   - 例: `20230901123456_add_comments_table`  
   - Supabase CLI でもこの形式がデフォルト。  
   - 日付時刻が先頭に来ることで「いつ作られたか」「マイグレーションの適用順」が明確になります。

2. **連番＋意味のある名前**  
   - 例: `001_create_posts_table`, `002_add_comments_table`, ...  
   - Rails などに慣れている人は連番方式を好むこともありますが、チームメンバー複数人で同時に作成すると番号の競合が起きやすいため、**タイムスタンプの方が衝突しにくい**です。

3. **日付＋時刻＋ISO8601など**  
   - 例: `2023-09-01T12.34.56_add_comments_table` (ISO8601に近い表現)  
   - これも可読性は高いですが、実質的な意味は `YYYYMMDDHHMMSS` と同じです。

---

## 3. ベストプラクティスのポイント

1. **タイムスタンプを自動で付ける**  
   - ファイルの並びを自然に**時系列順**にし、マイグレーション適用順が明確になる。  
   - CI/CD など大人数開発でも衝突が起きにくい。

2. **名前の後半は「何をするマイグレーションか」を簡潔に表す**  
   - 例: `add_users_table`, `rename_title_column`, `create_address_index` など。  
   - 未来の自分やチームがぱっと見で「ああ、こういう変更ね」と分かるようにする。

3. **Supabase CLI の `supabase migration new <name>` を活用する**  
   - 上記コマンドを使うと、ほぼ自動でよい命名（タイムスタンプ＋与えた引数）がつきます。  
   - 自前でファイルを作るより、衝突リスクや間違いが少なくなります。

---

## 4. まとめ

- **Supabase CLI を使えば、`<timestamp>_<name>` 形式のディレクトリ・ファイルが生成されるため、これが実質的なベストプラクティス**です。  
- マイグレーション名には**変更内容**を短く明瞭に書く（例: `add_comments_table`, `alter_user_id_type`）のが望ましい。  
- 連番やISO 形式などもありますが、同時に複数人が作業するときは**タイムスタンプの自動生成方式**が最も衝突しにくく、わかりやすいです。
</details>

<details><summary>supabase db pushでDBを更新するとき、どのスキーマが反映されるんですか？</summary>
**結論として**、`supabase db push` は **「まだリモートに適用されていないマイグレーション(＝新しいSQLファイル)」** を順番に実行し、DBスキーマを更新します。  
**既に実行済みのマイグレーション**は再実行されないので、**前回の `create table` などは次回以降の `push` では発火しません**。

---

## 1. `supabase db push` が実際に何を行うか

- Supabase CLI は、`supabase/migrations/` フォルダに作成された各マイグレーション（例: `20230911123456_create_posts_table/initial.sql`）について、**「このマイグレーションはリモートDBにもう適用済みかどうか」** を確認します。  
- **未適用**であれば、そのSQLを順番に実行し、DBスキーマを更新。  
- **既に適用済み**であれば、再度実行しないので **重複してCREATEしたりはしない** ようになっています。

### 1.1 どこで「適用済み」かを記録しているの？

- Supabase (Postgres) 内部に **マイグレーションの履歴を記録するためのテーブル** が自動的に作られており、CLI はそこを参照して、「どのバージョンのマイグレーションが既に適用されたか」を把握します。  
- そのため、一度`create table`などが実行済みのSQLは、次回以降の push ではスキップされるわけです。

---

## 2. 具体的な流れ

1. **`supabase migration new create_posts_table`**  
   - `supabase/migrations/2023..._create_posts_table/initial.sql` というフォルダ/ファイルが生成。
2. **そのファイルに `CREATE TABLE` や `ALTER TABLE` などのDDLを記述**  
3. **`supabase db push`**  
   - CLI が「まだ適用していないマイグレーション」があるかチェック → あれば実行し、DB を更新。  
   - ここであなたの `CREATE TABLE posts` や `RLSポリシー作成`, `TRIGGER` などが**1度だけ**走る。
4. **次回以降の `push`**  
   - すでにリモートで “create_posts_table” マイグレーションは実行済みなので、**もう一度同じSQLは走らない**（再適用しない）。
   - 新しいマイグレーション (`add_comments_table` など) があるなら、それだけ実行される。

---

## 3. 「次回以降 pushをするとき、今回作った create…も発火しないの？」について

- はい、**発火しません。** 既に適用されたマイグレーションはスキップされます。  
- もし「`posts` テーブルを削除して再作成したい」など大きな変更をしたい場合は、新しいマイグレーションファイルを作り、そこに `DROP TABLE posts;` / `CREATE TABLE posts;` などを書きます。

---

## 4. 「pushってどこまで本番に反映させるの？」

- `supabase db push` のデフォルト挙動は、**リンク済みのSupabaseプロジェクト**（本番 or ステージング）に対して「未適用マイグレーション」をすべて実行し、**直近のマイグレーションまで反映**させます。  
- 過去のマイグレーションファイルも含めて **「リモートに適用されていないもの」があればすべて実行** されるイメージです。  
- 新しく追加したマイグレーションだけでなく、もし途中で何か別のファイルも未適用だったら全部まとめて反映します。

---

## 5. まとめ

- **一度 `push` して適用されたマイグレーションは、次回以降再度実行されない**。  
- 追加のスキーマ変更をしたければ、**別のマイグレーションファイル** を作成し、また `db push` することになります。  
- 結果として、データベーススキーマの変更履歴を**ファイルとして積み上げ**ていき、CLI は「まだ適用していない分」を順番に実行してDBと整合性を保つわけです。
</details>

<details><summary>別ブランチでDBを操作したが、それを取り込まなかった場合に整合性が崩れる時どうしたらいい？</summary>
作業ブランチ上で行ったマイグレーションを**最終的に捨てる**ことになった場合、**「DBにだけ変更が反映されてしまい、mainブランチに戻ったときに整合性が崩れる」**という状況が起こりがちです。  
その際の対応策としては、**「そもそも作業ブランチで使うDB環境を分離する」** か、**「マイグレーションを取り消す（ロールバック）作業を行う」** の2つが代表的です。以下に詳しく解説します。

---

## 1. ブランチごとに「別のDB環境」を使う（推奨）

### 1.1 ローカル開発環境をブランチごとに立ち上げる

- **`supabase start`** でローカルのSupabase（Postgres + API）を起動し、ブランチ作業時には**一時的なDB**を使う。  
- ブランチから離れる際に `supabase stop` + Dockerコンテナ破棄すれば、**DB変更を後に引きずらず**に済みます。  
- メリット:  
  - 「機能ブランチの実験的マイグレーションを、本番/ステージングDBに影響させずに試せる」  
  - 「ブランチを捨てればコンテナも捨てるだけで、DBが汚れない」  
- デメリット:  
  - ローカルでDockerが必要、チーム全体で設定する手間がある

### 1.2 テスト用の「別プロジェクト or ステージング環境」を用意

- 本番やメインの開発環境とは**別のSupabaseプロジェクト**を用意しておき、ブランチごとにリンクさせる。  
- 作業が不要になったら、そのプロジェクトのDBをリセット or 放棄。  
- 大規模チームでは、**ステージング**や**ephemeral environment**（プレビュー用）として活用するパターンが多い。

---

## 2. マイグレーションを「取り消す」ロールバックを行う

もし既に**本番/ステージングDBにマイグレーションを適用してしまった**後で、「変更が不要になった」となった場合は、**逆のDDLを実行する**マイグレーションを作る、もしくは手動でDBを修正する手順をとります。

1. **逆マイグレーションファイルを作る**  
   - 例: ブランチで `create table new_feature;` を作ったが不要になった → `drop table new_feature;` というマイグレーションを作り、`supabase db push` で適用し、DBから削除する。  
   - 現状のSupabase CLIは「down.sql」を自動追跡しないので、**「undo用のmigration」を別途書いて `push`** する形が多いです。

2. **手動でSQLを実行**  
   - Supabase Studio や `psql` などで、不要なテーブル・カラムをDROPする  
   - ただし、この場合「どのバージョンが適用済みか」という**マイグレーション履歴**と食い違う可能性があるので、追加で整合性を取る必要が出る（あまり推奨されません）。

3. **DBをバックアップから戻す**  
   - 大がかりですが、「開発用ならDBをまるごと過去状態に巻き戻す」という手もある。  
   - 本番で誤適用した場合の緊急対応策としては検討されますが、ローカルやステージングなら簡単にリセットするほうが早い場合もあります。

---

## 3. オススメのフローまとめ

- **基本方針**: 「作業ブランチで試すマイグレーションは、本番/メインと分離したDB環境で行う」のが安全。  
  - ローカルコンテナ(`supabase start`)やブランチ専用ステージングプロジェクトなら、捨てるときにその環境ごと廃棄すれば済みます。

- **やむを得ず本番/メインDBに適用し、後から捨てるなら**:  
  - ロールバック専用（undo用）のマイグレーションファイルを作り、DROP/ALTER などで元に戻す。  
  - 本番運用では慎重にテストした上で適用し、**マイグレーション履歴**にも「取り消し」の記録を残すとよいです。

---

## 4. 具体的シナリオへの対応

### シナリオ: mainブランチ → work1 でマイグレーション → 破棄 → mainに戻る

1. **次回から**  
   - work1ブランチ切ったら `supabase start` などで**ローカルDB**を立ち上げ、そこで**`supabase migration new` → `db push`**。  
   - ブランチで作ったマイグレーションはローカルだけに適用。本番/メインDBには触れない。
   - ブランチを破棄するなら `supabase stop` でコンテナ破棄、マイグレーションも捨てればOK。  
   - mainに戻ったとき、**本番DBは影響ゼロ**。

2. **今すぐ対応策**  
   - 既に本番orメインDBにwork1のマイグレーションを適用してしまった場合:  
     1. **新しいマイグレーション**をmainブランチで作成し、不要なテーブルやカラムを`DROP`する  
     2. `supabase db push` で適用 → DBが元の状態に戻る  
     3. work1のマイグレーションファイルはGit上では破棄（マージしない）  
   - これで**DBの整合性**が再びmainブランチと揃います。

---

## 5. まとめ

- **ベストプラクティス**は「**開発ブランチと本番（またはメインDB）を分離**して、捨てるブランチのマイグレーションが本番に混ざらないようにする」こと。  
- 既に不要なマイグレーションをリモートDBに適用してしまったら、「逆マイグレーション」を作って**手動でロールバック**します。  
- **Supabase CLI は `down` マイグレーションを自動管理してくれない**ので、こういったときには**「削除や元に戻す用のDDL」を書いたマイグレーション**を自分で用意するのが手早いです
</details>