対象: 前の記事を読んで「GitHub連携は動いた。でも、入ったかどうかを毎回ダッシュボードで確かめるのが面倒」と思った方/非エンジニアの確認担当に状況を見せたい方
所要時間: 20分前後 / 使うもの: Supabaseのプロジェクト(無料でOK)、GitHubの公開リポジトリ、ブラウザ、ターミナル(ローカルサーバー用)
確認日: 2026-10-31
前の記事(手順編): https://qiita.com/tomozilla/items/fb7e6193ab07e01bcc9a
サンプルコード一式(GitHub): https://github.com/tomozilla/github-deploy-ja-demo
ビジネス編(やさしい解説・note): https://note.com/tomozilla/n/n77dc7e7d68dc
前の記事で、SQLファイルをマージするだけでデータベースに反映できることを試しました。でも、失敗したときに気づく場所はGitHubだけで、ダッシュボードには何も出ませんでした。「本番に入ったの?」と聞かれるたびに、GitHubとダッシュボードを行ったり来たりするのは、正直しんどいです。
そこで、1枚のページで、リポジトリにあるファイルのうち、どれが適用済みで、どれが待ちで、どれが失敗したかが分かる、小さな「デプロイボード」をつくりました。使うのは、変更の状況を、エンジニア以外の人にも見せたい小さなチームです。
0. 先に伝えておきたいこと
- 実際にやったのは、無料プロジェクトとGitHubの公開リポジトリで、ページを自分のPCで動かすこと。費用は$0。ページ自体はサーバーを使わず、ページを開いたときと、更新ボタンを押したときだけEdge Functionを1回ずつ呼びます。
- デモ用の近道:Edge FunctionはVerify JWTをオフにして、公開用(publishable)キーがあるかだけを確認します。公開用キーは公開される前提のキーなので、これは入場券にすぎず、認証ではありません。ログイン済みの人だけに見せたいなら、別の作りが必要です(10章)。
- GitHubのAPIは、トークンなしだと1時間に60回まで(IPごと)。ページは開く・更新するたびに2回使うので、自動更新はつけていません(最初から、そう決めました)。
- **見ているのは「GitHubの言い分」と「データベースの記録」**です。それ以上のこと(たとえば、失敗したファイルが途中まで反映していないか)は、このページでは分かりません(9章)。
- 試していないこと:プライベートのリポジトリ(トークンが必要になるはずですが、試していません)、複数のプロジェクト。
1. 何をつくったか
ブラウザのページが、3か所に聞いて、見比べます。
-
GitHub(ファイル一覧):リポジトリの
supabase/migrations/にあるSQLファイル。 -
GitHub(チェック結果):
mainの最新コミットに付く「Supabase Preview」チェックが、成功か失敗か。失敗なら、本物のエラー文。 - Edge Function:データベースが「適用済み」と記録しているマイグレーションの一覧。
ファイルがデータベースの記録にあれば「適用済み」、なければ、最新のチェックが失敗かどうかで**「待ち」か「失敗/後ろで待機」**にします。
2. 作り方(要点だけ)
全部のコードは、リポジトリにあります。ここでは、考え方の核だけ。
Edge Function(読み取り専用)は、データベースの記録テーブルを読んで返すだけです。
const rows = await sql`
select version, name from supabase_migrations.schema_migrations order by version`;
呼び出しに公開用キーがなければ、401を返します(入場券のチェック)。
状況の決め方は、ページのboard.jsにあります。
if (appliedVersions.has(f.version)) return row(f.name, "applied", ...);
// 順番に実行されるので、最初の未適用ファイルが「失敗」、残りは「待機」
const label = failed ? (firstUnapplied ? "failed / blocking" : "blocked") : ...
前の記事で分かった「1つ壊れると後ろも止まる」を、そのまま画面にしました。
3. 動かす
- リポジトリを取ってきて、
app/config.example.jsをapp/config.jsにコピー(config.jsはgit管理外です)。 -
config.jsに、リポジトリ名、Edge FunctionのURL、公開用キーを書く。秘密のキー(service_role)は絶対に入れません。 -
appフォルダで、簡単なサーバーを立てて開く(例:python3 -m http.server 8765)。
きれいなコピー(リポジトリとは別の場所)に、本物のconfig.jsを置いて動かして確かめました。
4. 使ってみる
すべて適用済みのときは、最初の画像のとおり、緑の帯で「Everything in the repo is applied」と出ます。
わざと壊したマイグレーション(存在しないテーブルへの変更)と、そのあとに続く正しいファイルをmainにマージして、更新を押すと……
- 赤い帯で「最後のデプロイが失敗」。
- 壊れたファイルは**「failed / blocking」、その後ろの正しいファイルは「blocked」**。
- 下に、GitHubが返したエラー文がそのまま出ます。
鍵を間違えたときの表示も確かめました。
一部しか読み込めないのに、表だけ出すと間違った安心を与えます。だから、どれか1つでも読み込めなかったときは、表には「No data」とだけ出し、黄色い帯で「読み込めませんでした」と伝えることにしました。
5. つまずいたこと
実際に起きた直したい点を、3つ書きます。
① 「データベースは変わっていません」と言い切ってしまった
最初の失敗時の帯に「失敗したファイルで、データベース自体は変わっていません」と書いていました。でも、私が確かめたのは、1文だけのファイルの失敗です。複数の文のファイルが途中で失敗したときどうなるかは試していません。言い切るのは危ないので、「データベースの記録に、適用済みとして載っていないファイルが○個」と、ページから確かに言えることだけに直しました。
② エラー表示に、プロジェクトのIDが出ていた
鍵が違うとき、最初は「(プロジェクトのホスト名)が401を返しました」と出ていました。スクリーンショットを撮ってから気づきました。画面を共有すると、プロジェクトのIDまで一緒に出るのは良くありません。「Edge Functionが401を返しました」のように、何に聞いたかの名前だけに直しました。
③ エラー文に、バッククォートがそのまま出ていた
GitHubが返すエラー文は、Markdownの囲み(```)つきでした。そのまま黒い枠に出すと、囲みの記号まで見えてしまうので、前後の囲みを取って表示しました。
最初から避けたこと:自動更新。GitHubの上限(1時間60回)がある以上、開きっぱなしにしたページが、いつの間にか上限を使い切るのを避けたかったからです。
6. 費用
- Supabase側:ページを開くたび・更新を押すたびに、Edge Functionを1回呼びます。私の実行では無料の範囲で、課金はありませんでした。
- GitHub側:更新1回につきAPIを2回。トークンなしだと1時間に60回までなので、開く・更新するを合わせて1時間に30回を超えると、上限に当たります(計算です)。
- ボードそのものに、有料のものは使っていません。プレビューブランチ(有料)の費用は、前の記事に書きました。
7. 実際の運用にするなら(まだ試していません)
- プライベートのリポジトリ:GitHubのトークンが必要になるはずです。トークンはブラウザに置かず、サーバー側(Edge Functionなど)で使うほうが安全です。
- ログイン済みの人だけに見せる:いまのEdge Functionは入場券だけです。ログインを使うなら、Verify JWTをオンにして、ログイン済みユーザーのトークンで呼ぶのが筋です。
- 失敗したら通知:ページを開いたときだけ分かる、では遅いです。通知は別の仕組みが要ります。
8. 後片付け
ローカルのサーバーを止め、config.jsを消しました。連携の無効化と、テーブル・Edge Function・使い捨てプロジェクトの削除は、前の記事のとおりです。
まとめ
- GitHubの言い分とデータベースの記録を見比べると、「入ったの?」に1枚で答えられる。
- **「1つ壊れると後ろも止まる」**を、そのまま表示にした。
- 言い切らない:ページから確かに言えることだけを書く。
- 読み込めないときは、表に「No data」と出して、黄色い帯で知らせる。
- 見ているのは入場券だけのEdge Function。ログイン付きにするなら別の作り。
次の話題は、「急にアクセスが増えたとき、データベースの『接続』はどう数える?」です。



