デプロイ手順書¶
waste-link の 本番 / 開発 デプロイをゼロから構築するためのガイド。
Supabase は 本番 (prod) / 開発 (dev) の 2 独立プロジェクト構成を採用し、
マイグレーションの適用は CI (supabase-deploy.yml) が supabase db push で明示実行する。
コードを書く前にこのドキュメントに従って外部サービスのセットアップを完了させること。
0. 全体像¶
| 環境 | git ブランチ | Cloudflare Pages | Supabase | EAS チャネル |
|---|---|---|---|---|
| production | main |
Production deployment | 本番 Supabase プロジェクト (独立) | production |
| develop | develop |
Preview (branch=develop) |
dev Supabase プロジェクト (独立・新規) | preview |
| PR プレビュー | feature/* → develop |
Preview (branch deployment) | dev プロジェクトを共有参照 | (なし) |
自動化されているもの:
- develop / main push の lint・typecheck・test・build (CI) → .github/workflows/ci.yml
- DB マイグレーションの適用 → .github/workflows/supabase-deploy.yml が push 契機に supabase db push --db-url で実行
(develop push → dev プロジェクトへ適用 / main push → 本番プロジェクトへ適用)
- develop / main push 時の Web デプロイ → Cloudflare Pages Git Integration が直接実行
- PR 時の マイグレーションファイル検証 + dev dry-run → .github/workflows/supabase-migrations-check.yml
手動が必要なもの:
- 本番 Supabase プロジェクトの確認 + dev プロジェクトの新規作成
- 各プロジェクトの接続情報 (URL / anon key / Session pooler URI) の取得
- 初回の Cloudflare Pages プロジェクト作成 + GitHub 連携 + 環境別 env (Production=本番鍵 / Preview=dev 鍵)
- (任意) dev プロジェクトの初期テストデータ投入 → Initial Setup (develop branch test data) workflow
- Mobile (Expo) の EAS Build 実行
1. Supabase: 本番 / dev の 2 独立プロジェクト¶
本プロジェクトは 本番と dev を完全に独立した 2 つの Supabase プロジェクトで管理する。
マイグレーション適用は CI が supabase db push --db-url で明示実行するため、
Supabase Branching / GitHub 連携は不要。
1.1 本番プロジェクトを確認¶
Supabase Dashboard で本番プロジェクト (waste-link-prod 等) を確認する。
- Region:
Tokyo (ap-northeast-1) - メモ: Project Ref / Project URL (
https://<prod-ref>.supabase.co) / anon public key Connect > Session poolerの Connection string (URI 形式postgresql://postgres.<ref>:<pw>@...pooler.supabase.com:5432/postgres) を控える →SUPABASE_PROD_DB_URL
直接の
db.<ref>.supabase.coは IPv6 only で GitHub Actions から到達できないため Session pooler 必須。
1.2 dev プロジェクトを新規作成¶
Dashboard で dev 用プロジェクトを新規作成する。
- Region:
Tokyo (ap-northeast-1) - Plan: Free または Pro (Branching は不要)
- メモ: Project Ref / Project URL (
https://<dev-ref>.supabase.co) / anon public key Connect > Session poolerの Connection string を控える →SUPABASE_DEV_DB_URL
dev プロジェクトは本番とは完全に独立しており、テストデータを自由に投入できる。
supabase/seed.sql は ローカル専用 (supabase db reset 時のみ)。プロジェクトへは適用されない。
2. Cloudflare Pages: プロジェクト作成と Git 連携¶
2.1 プロジェクト作成¶
Cloudflare Dashboard → Workers & Pages → Create application → Pages → Connect to Git。
- リポジトリ:
kyoei-paper/waste-linkを選択 - Production branch:
main
ビルド設定:
| 項目 | 値 |
|---|---|
| Framework preset | None |
| Build command | pnpm install --frozen-lockfile && pnpm --filter @waste-link/web build |
| Build output directory | apps/web/dist |
| Root directory | / (リポジトリのルート) |
| Environment variables (Build) | NODE_VERSION=22, PNPM_VERSION=9 |
2.2 環境別の Environment Variables¶
Settings > Environment variables で、Production と Preview で別々に設定:
Production (= main ブランチのデプロイで使う → Supabase 本番プロジェクト)¶
| Key | Value |
|---|---|
VITE_SUPABASE_URL |
https://<prod-ref>.supabase.co |
VITE_SUPABASE_ANON_KEY |
本番プロジェクトの anon (publishable) key |
NODE_VERSION |
22 |
PNPM_VERSION |
9 |
Preview (= develop / feature ブランチのデプロイで使う → Supabase dev プロジェクト)¶
| Key | Value |
|---|---|
VITE_SUPABASE_URL |
dev プロジェクトの API URL (https://<dev-ref>.supabase.co) |
VITE_SUPABASE_ANON_KEY |
dev プロジェクトの anon (publishable) key |
NODE_VERSION |
22 |
PNPM_VERSION |
9 |
PR ごとのプレビューデプロイは dev プロジェクトを共有参照する運用とする。 PR 単位で完全分離したい場合は動的注入が必要になるが、本プロジェクトでは dev 固定で十分とする。
2.3 ブランチデプロイの挙動¶
mainpush → Production deployment (waste-link.pages.devまたは独自ドメイン)developpush → Preview deployment (develop.waste-link.pages.dev形式の固定 URL)feature/*push → PR ごとの動的 Preview URL
2.4 独自ドメインを使う場合¶
Custom domains から以下のパターンで割り当て:
app.waste-link.example→ Production (=main)develop.waste-link.example→developブランチに固定
3. Supabase Auth リダイレクト URL の追加¶
Supabase の Auth は許可リスト方式。本番と dev それぞれのプロジェクトで設定する (Authentication > URL Configuration):
- Site URL:
- 本番プロジェクト:
https://app.waste-link.example - dev プロジェクト:
https://develop.waste-link.pages.dev(またはdevelop.waste-link.example) - Additional Redirect URLs (両プロジェクト共通):
http://localhost:5173(ローカル開発)wastelink://(モバイル deep link)
4. GitHub Secrets 設定¶
GitHub リポジトリ Settings > Secrets and variables > Actions で以下を登録。
4.1 Repository secrets (マイグレーション適用)¶
| Key | 値 | 用途 |
|---|---|---|
SUPABASE_DEV_DB_URL |
dev プロジェクトの Session pooler URI (postgresql://postgres.<ref>:<pw>@...pooler.supabase.com:5432/postgres) |
supabase-deploy.yml の develop push 時・supabase-migrations-check.yml の dry-run |
SUPABASE_PROD_DB_URL |
本番プロジェクトの Session pooler URI | supabase-deploy.yml の main push 時 |
supabase db pushはsupabase_migrations.schema_migrationsを参照し未適用分のみ順に適用する (重複適用なし)。
4.2 Initial Setup (dev プロジェクトのテストデータ投入) を使う場合のみ¶
Initial Setup (develop branch test data) workflow を使う場合、dev プロジェクトの接続情報を登録:
| Key | 値 |
|---|---|
SUPABASE_DEV_DB_URL |
§4.1 と共通 (Session pooler URI) |
SUPABASE_DEV_SERVICE_ROLE_KEY |
dev プロジェクトの service_role key |
SUPABASE_DEV_API_URL |
dev プロジェクトの API URL (https://<dev-ref>.supabase.co) |
service_rolekey は DB を root 権限で操作できる。必ず Secrets で管理し、UI / git / Slack に置かない。 直接のdb.<ref>.supabase.coは IPv6 only で GitHub Actions から到達できないため pooler 必須。
5. 初回デプロイ / 2プロジェクト構成への移行手順 (カットオーバー)¶
既存の Supabase Branching 構成から本構成へ移行する場合の手順:
- dev プロジェクトを新規作成 (§1.2) → API URL / anon key / Session pooler URI を取得
- 本番プロジェクトの Branching を無効化 — Dashboard の
Branches画面から Branching (GitHub 連携) を解除 - GitHub Secrets / Variables を登録 (§4.1, §4.2) —
SUPABASE_DEV_DB_URL/SUPABASE_PROD_DB_URLを設定 - Cloudflare Pages の Preview 環境変数を dev プロジェクトへ更新 (§2.2) — Preview の
VITE_SUPABASE_URL/VITE_SUPABASE_ANON_KEYを dev プロジェクトの値に変更 developを push →supabase-deploy.ymlが dev プロジェクトへ migration を適用し CF Preview デプロイを確認- 本番プロジェクトの migration 適用済み状態を確認してから
mainへ merge →supabase-deploy.ymlが本番へ適用 - 移行前から運用していた本番は既に migration 0〜23 が適用済みのはず。
supabase migration list --db-url "$SUPABASE_PROD_DB_URL"で確認し、全て applied になっていることを確かめてから push する - Supabase Auth の Site URL / Redirect URL を両プロジェクトで設定 (§3)
- (任意)
Initial Setupworkflow で dev プロジェクトにテストデータを投入
6. デプロイのライフサイクル¶
通常のフロー¶
feature/foo ─PR→ develop ─merge→ main
│ │ │
│ │ └─→ Cloudflare Pages (production)
│ │ Supabase 本番プロジェクト ← supabase-deploy.yml が適用
│ │
│ └─→ Cloudflare Pages (develop Preview)
│ Supabase dev プロジェクト ← supabase-deploy.yml が適用
│
└─→ Cloudflare Pages (PR Preview)
Supabase dev プロジェクト (共有参照)
ホットフィックスの扱い¶
production にしか出ていないバグの緊急修正:
mainからhotfix/xxxを切るmainへの PR + マージで本番反映 (supabase-deploy.ymlが本番プロジェクトへ migration 適用)- 同じコミットを
developにも cherry-pick または revert マージで反映
7. ロールバック手順¶
Web (Cloudflare Pages)¶
Deployments タブから任意の過去デプロイを Rollback ボタンで即時復元可能。
Cloudflare Pages は履歴を全て保持しているので最も簡単な経路。
Supabase migrations¶
重要: マイグレーションは forward only。安易にロールバックできない。
- 緊急時は手動で down マイグレーションを書き、新しい migration ファイルとして push する
(次の
supabase db pushで適用される)。 - データを失う変更 (DROP COLUMN 等) は事前に
pg_dumpでバックアップを取ること。 - Supabase Pro は Point-in-Time Recovery (PITR) が有料アドオン。
Mobile (EAS)¶
- EAS Update で OTA ロールバック:
eas update --branch production --message "rollback to <sha>" - ネイティブコードを含む場合は新規ビルド + Submit が必要
8. トラブルシューティング¶
CI が「VITE_SUPABASE_URL is undefined」で落ちる¶
.github/workflows/ci.yml がダミー値を渡しているはず。
コード側で「未定義なら throw」する実装になっていないか確認。
Cloudflare Pages のビルドが pnpm install で落ちる¶
Environment variables (Build)でNODE_VERSION=22とPNPM_VERSION=9を設定済みか確認pnpm-lock.yamlがリポジトリにコミットされているか確認 (--frozen-lockfile必須)
supabase-deploy.yml が「DB URL secret is not set」で落ちる¶
Settings > Secrets > ActionsでSUPABASE_DEV_DB_URL/SUPABASE_PROD_DB_URLが登録済みか確認- Secret の値が
postgresql://で始まる Session pooler URI になっているか確認 - 直接ホスト (
db.<ref>.supabase.co) を使っていないか確認 (IPv6 only で GitHub Actions から到達不可)
マイグレーションが dev / 本番に反映されない¶
supabase/migrations/**に実際に差分があるか確認 (採番重複はsupabase-migrations-checkが検出)supabase-deploy.ymlの実行ログを Actions タブで確認supabase db pushは未適用分のみ適用するため、supabase migration listで適用済み状態を確認
develop を push したのに Preview に反映されない¶
- Cloudflare Pages の
Deploymentsで develop ブランチのビルドが回っているか確認 Settings > Builds & deployments > Branch deploymentsでdevelopが allowed か確認
9. Mobile (Expo / EAS) テスト配布 — Android preview (内部配布 APK)¶
現状モバイルは 3 ロール対応。ログインすると
homeForRole(apps/mobile/src/lib/routing.ts) がロール別の初期画面へ振り分ける: - 排出業者 ((discharger)): 案件一覧ホーム - 処理業者 admin/normal ((collector)): 受託待ち / 今日の配車 / 進行中の KPI ダッシュボード + 配車予定リスト - 処理業者 driver ((driver)): 本日の配車 + 配車履歴Web (
apps/web) との機能差はまだ大きく、モバイルは一覧・ホーム中心。詳細/作成フォームや カメラ OCR 等の残タスクはdocs/mobile-roadmap.mdの Phase A〜C を参照。
eas.json の preview プロファイル (internal 配布 / Android は APK) で
テスト用ビルドを作り、関係者に直接配布できる。
9.1 一度だけ必要なセットアップ (Expo アカウント要)¶
cd apps/mobile
# 1. Expo にログイン (アカウントが無ければ https://expo.dev で作成)
eas login
# 2. プロジェクトを Expo に登録 → app.json に extra.eas.projectId が書き込まれる
# (この変更はリポジトリにコミットする)
eas init
# 3. preview 環境に dev プロジェクトの Supabase 値を登録 (EXPO_PUBLIC_* は publishable)
eas env:create --environment preview --name EXPO_PUBLIC_SUPABASE_URL --value https://<dev-ref>.supabase.co
eas env:create --environment preview --name EXPO_PUBLIC_SUPABASE_ANON_KEY --value <dev-project-anon-key>
9.2 ビルド & 配布¶
- ビルドは Expo のサーバーで実行され、完了すると APK のダウンロード URL が発行される。
- その URL (または
eas build:list/ Expo ダッシュボード) を配布。Android 端末で 「提供元不明アプリ」を許可してインストール。 - 接続先は preview 環境変数の dev プロジェクト Supabase。ログイン ID 欄には
デモアカウントの login_id を入力する (メールアドレスではない。内部で
<login_id>@members.waste-link.localに決定的変換される)。例: ドライバー画面はdriver1/Demo!2026、排出業者ホームはdisch1、処理業者ダッシュボードはadmin1(全アカウントの一覧は README.md「テストアカウント」節・scripts/setup-demo-users.mjs)。
9.3 CI から起動 (任意)¶
.github/workflows/mobile-build.yml を Actions タブから手動起動しても同じビルドを投げられる。
事前に GitHub Secrets へ EXPO_TOKEN (Expo Dashboard > Account > Access tokens) を登録し、
9.1 の eas init 済み (projectId コミット済み) であること。
9.4 補足¶
- iOS:
--platform iosには Apple Developer アカウント + 実機 UDID 登録 (ad hoc) が必要。 - OTA 更新: JS のみの変更は
eas update --branch previewで再ビルド不要に配信可能 (ネイティブ依存の変更時は再ビルド必須)。 EXPO_PUBLIC_*はビルド時にバンドルへ埋め込まれるため、接続先 (develop/production) を変えるにはビルドまたは OTA のやり直しが必要。
9.5 開発環境を「常に」確認可能にする (EAS Update / Metro 不要)¶
ローカルで expo start (Metro) を動かし続けなくても、EAS Update で JS バンドルを
Expo のサーバーへ公開 (OTA) すれば、いつでも最新の develop をスマホで開ける。
(本プロジェクトは expo-updates 導入済みで EAS Update 対応済み)
仕組み:
- eas update --branch preview で現在の JS を preview チャンネルへ公開 (Expo の CDN にホスト)。
- 公開後、Expo ダッシュボード (Project > Updates > preview) に QR / リンク が出る。
これを開けば Metro 不要で起動する。再公開すると次回起動時に最新へ更新される。
開く側の選択肢:
1. Expo Go (追加インストール不要・本アプリは Expo Go 互換モジュールのみ):
Updates の QR を Expo Go で開く。最も手軽。SDK / モジュール次第で稀にランタイム差異あり。
2. development build (Expo 推奨・最も安定): eas build --profile development で dev client を
1 度ビルド・インストールしておくと、以後は development チャンネルの最新を自動取得する。
ネイティブ依存を増やしても壊れない。
「常に最新」を自動化 (CI):
- .github/workflows/mobile-update.yml が develop への apps/mobile / packages/* 変更で
eas update --branch preview を自動実行 (要 EXPO_TOKEN secret)。
→ 誰も Metro を動かさなくても preview チャンネルが常に develop 最新になる。
EXPO_TOKEN 未設定の間は自動スキップ (push が失敗にならない)。
- 手動公開: Actions から Mobile OTA Update を実行、またはローカルで
cd apps/mobile && eas update --branch preview --message "..."。
注意:
- 接続先 EXPO_PUBLIC_* は update 公開時に preview の EAS env から埋め込まれる
(§9.1 の eas env:create --environment preview を済ませておく)。
- OTA は JS のみ反映。ネイティブ依存 (新しい expo-* 等) を足した場合は dev build / APK の
再ビルドが必要。