コンテンツにスキップ

デプロイ手順書

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 poolerConnection 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 poolerConnection string を控える → SUPABASE_DEV_DB_URL

dev プロジェクトは本番とは完全に独立しており、テストデータを自由に投入できる。

supabase/seed.sqlローカル専用 (supabase db reset 時のみ)。プロジェクトへは適用されない。


2. Cloudflare Pages: プロジェクト作成と Git 連携

2.1 プロジェクト作成

Cloudflare DashboardWorkers & PagesCreate applicationPagesConnect 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 で、ProductionPreview で別々に設定:

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 ブランチデプロイの挙動

  • main push → Production deployment (waste-link.pages.dev または独自ドメイン)
  • develop push → 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.exampledevelop ブランチに固定

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 pushsupabase_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_role key は DB を root 権限で操作できる。必ず Secrets で管理し、UI / git / Slack に置かない。 直接の db.<ref>.supabase.co は IPv6 only で GitHub Actions から到達できないため pooler 必須


5. 初回デプロイ / 2プロジェクト構成への移行手順 (カットオーバー)

既存の Supabase Branching 構成から本構成へ移行する場合の手順:

  1. dev プロジェクトを新規作成 (§1.2) → API URL / anon key / Session pooler URI を取得
  2. 本番プロジェクトの Branching を無効化 — Dashboard の Branches 画面から Branching (GitHub 連携) を解除
  3. GitHub Secrets / Variables を登録 (§4.1, §4.2) — SUPABASE_DEV_DB_URL / SUPABASE_PROD_DB_URL を設定
  4. Cloudflare Pages の Preview 環境変数を dev プロジェクトへ更新 (§2.2) — Preview の VITE_SUPABASE_URL / VITE_SUPABASE_ANON_KEY を dev プロジェクトの値に変更
  5. develop を push → supabase-deploy.yml が dev プロジェクトへ migration を適用し CF Preview デプロイを確認
  6. 本番プロジェクトの migration 適用済み状態を確認してから main へ merge → supabase-deploy.yml が本番へ適用
  7. 移行前から運用していた本番は既に migration 0〜23 が適用済みのはず。supabase migration list --db-url "$SUPABASE_PROD_DB_URL" で確認し、全て applied になっていることを確かめてから push する
  8. Supabase Auth の Site URL / Redirect URL を両プロジェクトで設定 (§3)
  9. (任意) Initial Setup workflow で 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 にしか出ていないバグの緊急修正:

  1. main から hotfix/xxx を切る
  2. main への PR + マージで本番反映 (supabase-deploy.yml が本番プロジェクトへ migration 適用)
  3. 同じコミットを 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=22PNPM_VERSION=9 を設定済みか確認
  • pnpm-lock.yaml がリポジトリにコミットされているか確認 (--frozen-lockfile 必須)

supabase-deploy.yml が「DB URL secret is not set」で落ちる

  • Settings > Secrets > ActionsSUPABASE_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 deploymentsdevelop が 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.jsonpreview プロファイル (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 ビルド & 配布

cd apps/mobile
eas build --platform android --profile preview
  • ビルドは 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.ymldevelop への 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 の 再ビルドが必要。