コンテンツにスキップ

Vendure Fly.io デプロイメントガイド

概要

この文書では、Vendure を Fly.io で本番環境にデプロイするための完全な手順を説明します。

現在の構成

  • アプリケーション名: ritsubi-ecommerce(本番)、ritsubi-ecommerce-staging(ステージング)
  • PostgreSQL: Dockerコンテナ(ritsubi-postgres-db、PostgreSQL 17 + PGroonga)
  • Redis: 未使用(in-memoryキャッシュを使用)
  • 設定ファイル: apps/vendure-server/fly.toml(本番)、apps/vendure-server/fly.staging.toml(ステージング)

詳細は PostgreSQL Dockerコンテナ設定 を参照してください。

前提条件

必要なツール

# Node.js (22系以上)
node --version  # v18.0.0+

# pnpm パッケージマネージャー
npm install -g pnpm

# Fly.io CLI
curl -L https://fly.io/install.sh | sh

# Git
git --version

アカウント作成

  1. Fly.io アカウント: https://fly.io/app/sign-up
  2. Upstash アカウント: https://console.upstash.com (Fly.io 経由で作成推奨)
  3. Cloudflare アカウント: https://dash.cloudflare.com/sign-up (R2 ストレージ用)

Step 1: Fly.io 初期設定

Fly.io CLI セットアップ

# Fly.io にログイン
flyctl auth login

# 組織確認
flyctl orgs list

# 組織作成(必要に応じて)
flyctl orgs create ritsubi

# 支払い情報設定
flyctl billing show

プロジェクト初期化

# プロジェクトルートに移動
cd /home/genm/Projects/ritsubi

# Fly.io アプリを作成(既に存在する場合はスキップ)
flyctl apps create ritsubi-ecommerce

# 設定ファイルは apps/vendure-server/fly.toml に配置済み

Step 2: データベース設定

PostgreSQL Dockerコンテナデプロイ

現在の構成では、PostgreSQLをDockerコンテナとしてデプロイしています。詳細な手順は PostgreSQL Dockerコンテナ設定 を参照してください。

クイックスタート

# 1. Postgresアプリ作成
cd /home/genm/Projects/ritsubi/apps/postgres
flyctl apps create ritsubi-postgres-db --org ritsubi

# 2. ボリューム作成
flyctl volumes create postgres_data \
  --region nrt \
  --size 10 \
  -a ritsubi-postgres-db

# 3. パスワード設定
flyctl secrets set POSTGRES_PASSWORD="$(openssl rand -base64 32)" -a ritsubi-postgres-db

# 4. デプロイ
flyctl deploy -a ritsubi-postgres-db

# 5. Vendureアプリに接続設定
flyctl secrets set DATABASE_URL="postgres://postgres:PASSWORD@ritsubi-postgres-db.internal:5432/ritsubi_vendure" -a ritsubi-ecommerce

データベース初期化

デプロイ後、Vendureアプリケーションが自動的にデータベーススキーマを初期化します。

Step 3: Redis 設定(オプション)

現在の構成

現在の構成では、Redisは使用していません。VendureはREDIS_HOSTが未設定の場合、自動的にin-memoryキャッシュを使用します。

将来の拡張: Upstash Redis 設定

スケーリングが必要になった場合や、複数インスタンス間でセッション・キャッシュを共有する必要がある場合は、Upstash Redisを追加できます。詳細は Upstash Redis 統合設計書 を参照してください。

# Upstash Redis 作成(将来の拡張用)
flyctl redis create

# 設定項目:
# Organization: ritsubi
# Redis name: ritsubi-ecommerce-redis
# Primary region: nrt (Tokyo)
# Eviction policy: noeviction
# Plan: Fixed $3 plan (3GB)

# 接続情報確認
flyctl redis status ritsubi-ecommerce-redis

# Redis接続情報をシークレットに設定
flyctl secrets set UPSTASH_REDIS_URL="redis://..." -a ritsubi-ecommerce
flyctl secrets set UPSTASH_REDIS_PASSWORD="..." -a ritsubi-ecommerce

Step 4: 環境変数・シークレット設定

必須シークレット設定

# セッション・認証関連
flyctl secrets set SESSION_SECRET="$(openssl rand -base64 32)" -a ritsubi-ecommerce
flyctl secrets set COOKIE_SECRET="$(openssl rand -base64 32)" -a ritsubi-ecommerce
flyctl secrets set JWT_SECRET="$(openssl rand -base64 32)" -a ritsubi-ecommerce

# 管理者アカウント
flyctl secrets set ADMIN_EMAIL="admin@ritsubi.co.jp" -a ritsubi-ecommerce
flyctl secrets set ADMIN_PASSWORD="secure_admin_password" -a ritsubi-ecommerce

# SMTP設定
flyctl secrets set SMTP_HOST="smtp.gmail.com" -a ritsubi-ecommerce
flyctl secrets set SMTP_USER="your-email@gmail.com" -a ritsubi-ecommerce
flyctl secrets set SMTP_PASSWORD="your-app-password" -a ritsubi-ecommerce

## Vendure でさくらのメールサーバーを使う場合

### 1. さくらのレンタルサーバー側で確認する値

- `SMTP_HOST=<初期ドメイン名>.sakura.ne.jp`
- `SMTP_PORT=587`
- `SMTP_SECURE=true` (STARTTLS を要求するため `true` に固定)
- `SMTP_USER=<メールアカウント>@<独自ドメイン>`
- `SMTP_PASSWORD=<上記メールアカウントのパスワード>`

Vendure では `.env` かホスティング環境のシークレットに上記を設定する。例:

```bash
flyctl secrets set SMTP_HOST="xxxx.sakura.ne.jp" -a ritsubi-ecommerce
flyctl secrets set SMTP_PORT="587" -a ritsubi-ecommerce
flyctl secrets set SMTP_SECURE="true" -a ritsubi-ecommerce
flyctl secrets set SMTP_USER="noreply@example.com" -a ritsubi-ecommerce
flyctl secrets set SMTP_PASSWORD="********" -a ritsubi-ecommerce

2. 独自ドメインの DNS レコード

さくらのメールサーバーから送信可とするため、独自ドメインの DNS ゾーンに以下を登録する。SPF/DKIM はメールサーバーごとに値が異なるため、さくらのコントロールパネルで発行したレコードのみを必ず使用すること。DMARC はドメイン単位で共通のポリシーを適用できるので、既存の DMARC レコードがあれば流用して問題ない。

  • A レコード(※ MX レコードを用意できない場合のみ): さくらから指定された初期ドメインの IP を登録
  • MX レコード: 既に MX を設定済みなら追加変更は不要(A が存在するだけでも送信は可能)
  • TXT(SPF): さくらが提示する SPF 記述をそのまま TXT レコードに登録
  • TXT(DKIM): さくらで DKIM 秘密鍵を発行後、提示された公開鍵を TXT レコードとして登録

最小構成として MX もしくは A のいずれかが存在し、SPF/DKIM が正しく設定されていれば Vendure からメール送信ができる。

3. SMTP 接続テスト

環境変数を投入したら、下記の curl または swaks コマンドで SMTP 送信テストを行う。<username><your domain> は実際の値に置き換える。

curl --url "smtp://xxxx.sakura.ne.jp:587" \
  --mail-from <username>@<your domain> \
  --mail-rcpt <receiver email> \
  --user "<username>@<your domain>:<password>" \
  --ssl-reqd \
  --upload-file - <<'EOF'
Subject: HTML テスト
Content-Type: text/html; charset=UTF-8

<h1>こんにちは</h1>
<p>これは <b>curl</b> による HTML メールです。</p>
EOF
swaks --to <receiver email> \
  --from <username>@<your domain> \
  --server xxxx.sakura.ne.jp \
  --port 587 \
  --auth LOGIN \
  --auth-user <username>@<your domain> \
  --auth-password <password> \
  --tls \
  --header "Subject: swaks SMTP テスト" \
  --header "Content-Type: text/html; charset=UTF-8" \
  --body '<h1>こんにちは</h1><p>これは <b>swaks</b> による HTML メールです。</p>'

成功すれば Vendure の通知メールや注文メールも同じ認証情報で送信できる。失敗する場合は DNS 伝播状況、ユーザー名の@以降が独自ドメインになっているか、TLS 強制 (--ssl-reqd) の有無を再確認する。

4. さくらレンタルサーバー(ライトプラン相当)の送信件数目安

  • 15分あたり最大100通(換算で1時間400通、1日約9,600通)を超えないようにバッチ処理や通知のスケジュールを調整する。※さくら公式サポート「基本仕様を知りたい(さくらのレンタルサーバ)」に準拠(2025年11月確認)。
  • 新規契約から15日以内、または会員IDの電話番号認証が未完了の場合は、上記より厳しい暫定制限が掛かる。解除には電話番号認証または 15 日経過を待つ必要がある。
  • 送信数はコントロールパネルでモニタリングできるため、Vendure 側でメール通知が増える場合は事前に送信数を把握し、しきい値を越えないようジョブの間隔を調整する。

決済設定(PayPay)

flyctl secrets set PAYPAY_API_KEY="your_paypay_api_key" -a ritsubi-ecommerce flyctl secrets set PAYPAY_SECRET_KEY="your_paypay_secret_key" -a ritsubi-ecommerce flyctl secrets set PAYPAY_MERCHANT_ID="your_merchant_id" -a ritsubi-ecommerce

ファイルストレージ(Cloudflare R2)

flyctl secrets set R2_ACCOUNT_ID="your_r2_account_id" -a ritsubi-ecommerce flyctl secrets set R2_ACCESS_KEY_ID="your_access_key" -a ritsubi-ecommerce flyctl secrets set R2_SECRET_ACCESS_KEY="your_secret_key" -a ritsubi-ecommerce flyctl secrets set R2_BUCKET_NAME="ritsubi-assets" -a ritsubi-ecommerce

外部連携(SMILE ERP)

flyctl secrets set SMILE_API_ENDPOINT="https://api.smile.co.jp" -a ritsubi-ecommerce flyctl secrets set SMILE_API_KEY="your_smile_api_key" -a ritsubi-ecommerce flyctl secrets set SMILE_COMPANY_ID="your_company_id" -a ritsubi-ecommerce

### 公開環境変数設定

```bash
# fly.toml で設定される環境変数を確認
flyctl config show -a ritsubi-ecommerce

Step 5: Cloudflare R2 ストレージ設定

R2 バケット作成

# Cloudflare R2 バケット作成(Cloudflare ダッシュボードで実行)
# 1. https://dash.cloudflare.com にログイン
# 2. R2 Object Storage に移動
# 3. "Create bucket" をクリック
# 4. Bucket name: ritsubi-assets
# 5. Location: Asia Pacific (推奨)

R2 API トークン作成

# 1. Cloudflare ダッシュボード > My Profile > API Tokens
# 2. "Create Token" > "Custom token"
# 3. Permissions:
#    - Account: Cloudflare R2:Edit
#    - Zone Resources: Include All zones
# 4. 生成されたトークンをシークレットに設定(上記参照)

Step 6: ボリューム作成

永続データ用ボリューム

# データ永続化用ボリューム作成
flyctl volumes create vendure_data \
  --region nrt \
  --size 5 \
  -a ritsubi-ecommerce

# ボリューム確認
flyctl volumes list -a ritsubi-ecommerce

Step 7: Depotビルダー設定(高速ビルド)

Depotビルダーとは

Fly.ioにはDepotビルダーが組み込まれており、--depotフラグを使用するだけで、追加のアカウント作成や設定なしでDockerビルドを高速化できます。ビルドキャッシュを活用することで、デプロイ時間を大幅に短縮できます。

デプロイ時のDepot使用

自動デプロイ(GitHub Actions)

GitHub Actionsワークフローは自動的にDepotビルダーを使用します(--depotフラグが設定済み)。

手動デプロイ

# Depotビルダーを使用してデプロイ(追加設定不要)
cd apps/vendure-server
flyctl deploy --config fly.toml -a ritsubi-ecommerce --remote-only --depot

# またはデプロイスクリプトを使用(自動で--depotを使用)
./scripts/fly-deploy.sh production

ビルドキャッシュの確認

Depotビルダーを使用すると、ビルドログにキャッシュヒット情報が表示されます:

=> CACHED [base 3/8] COPY package.json pnpm-lock.yaml...
=> CACHED [base 4/8] RUN pnpm fetch --frozen-lockfile

Dockerfileの最適化

apps/vendure-server/Dockerfile.flyは、ビルドキャッシュを最大限活用するように最適化されています:

  • レイヤー分離: 依存関係とソースコードを分離
  • pnpm fetch: lockfileのみでキャッシュ可能な依存関係取得
  • オフラインインストール: fetch済みの依存関係を高速インストール

詳細はapps/vendure-server/Dockerfile.flyのコメントを参照してください。

Step 8: アプリケーションデプロイ

初回デプロイ

# プロジェクトルートで依存関係インストール
pnpm install

# Vendure サーバーをビルド
cd apps/vendure-server
pnpm run build:production

# 初回デプロイ(ルートディレクトリから実行)
cd ../..
# Depotビルダーを使用して高速ビルド(追加設定不要)
flyctl deploy --config apps/vendure-server/fly.toml -a ritsubi-ecommerce --remote-only --depot

# デプロイ状況確認
flyctl status -a ritsubi-ecommerce
flyctl logs -a ritsubi-ecommerce

データベースマイグレーション実行

# マイグレーション実行(Vendureは起動時に自動実行)
# 手動で実行する場合:
flyctl ssh console -a ritsubi-ecommerce
# コンテナ内で:
cd /app/apps/vendure-server
npm run db:migrate

# 初期データセットアップ(必要に応じて)
npm run db:seed

Step 9: ヘルスチェック・動作確認

基本動作確認

# アプリケーション URL 確認
flyctl info -a ritsubi-ecommerce

# ヘルスチェック
curl https://ritsubi-ecommerce.fly.dev/health

# GraphQL Playground(開発時のみ)
curl https://ritsubi-ecommerce.fly.dev/admin-api

管理画面アクセス

# 管理画面URL: https://ritsubi-ecommerce.fly.dev/admin
# 設定したSUPERADMIN_USERNAME/SUPERADMIN_PASSWORDでログイン

Step 10: カスタムドメイン設定

ドメイン追加

# カスタムドメイン追加
flyctl certs create order.ritsubi.co.jp -a ritsubi-ecommerce

# DNS設定確認
flyctl certs show order.ritsubi.co.jp -a ritsubi-ecommerce

DNS レコード設定

# DNS プロバイダーで以下を設定:
# Type: CNAME
# Name: order
# Value: ritsubi-ecommerce.fly.dev
# TTL: 300 (5分)

Step 11: SSL/TLS 証明書設定

自動SSL証明書

# Let's Encrypt 証明書自動発行(Fly.io 標準機能)
flyctl certs check order.ritsubi.co.jp -a ritsubi-ecommerce

# 証明書確認
curl -I https://order.ritsubi.co.jp/health

Step 12: 監視・ログ設定

ログ監視設定

# リアルタイムログ確認
flyctl logs -a ritsubi-ecommerce --follow

# 過去ログ確認
flyctl logs -a ritsubi-ecommerce --since 1h

メトリクス確認

# アプリケーションメトリクス
flyctl metrics -a ritsubi-ecommerce

# PostgreSQL メトリクス
flyctl metrics -a ritsubi-postgres-db

# Redis メトリクス(使用している場合)
# flyctl redis metrics ritsubi-ecommerce-redis

Step 13: スケーリング設定

水平スケーリング

# インスタンス数変更
flyctl scale count 2 -a ritsubi-ecommerce

# リージョン追加(将来的)
flyctl regions add osa -a ritsubi-ecommerce  # 大阪リージョン

垂直スケーリング

# VM サイズ変更
flyctl scale vm performance-1x -a ritsubi-ecommerce

# メモリ設定変更
flyctl scale memory 2048 -a ritsubi-ecommerce

Step 13: バックアップ設定

自動バックアップ確認

# PostgreSQL バックアップ(Dockerコンテナのため手動バックアップが必要)
# SSH接続してpg_dumpを実行
flyctl ssh console -a ritsubi-postgres-db
pg_dump -U postgres ritsubi_vendure > /tmp/backup_$(date +%Y%m%d_%H%M%S).sql

# Redis バックアップ確認(Upstash 使用時)
# Upstash コンソールで確認

手動バックアップ

# データベース手動バックアップ
flyctl ssh console -a ritsubi-postgres-db
pg_dump -U postgres ritsubi_vendure > /tmp/backup_$(date +%Y%m%d).sql

# アプリケーションデータエクスポート
flyctl ssh console -a ritsubi-ecommerce
cd /app/apps/vendure-server
npm run export:data

Step 14: CI/CD パイプライン設定

テストワークフロー(.github/workflows/test.yml

ストーリーを含む UI テストまでを自動化するため、GitHub Actions 上で以下の手順を実行します。

  • 環境: ubuntu-latest / Node.js 22 / pnpm 10.17.0
  • 依存サービス: PostgreSQL 17 + PGroonga (CI/テスト環境ではslim版を使用)、Redis 7(いずれもヘルスチェック付き)
  • テスト手順:
  • pnpm run typecheck – Turborepo 経由で各パッケージの TypeScript 型検証
  • pnpm run lint:check – oxlint による一括チェック
  • pnpm run testturbo run test 経由で以下を並列実行
    • apps/storefront: Vitest(vitest run)によるユニット / コンポーネントテスト
    • apps/vendure-server: Vitestによるサーバーユニットテスト
    • 各パッケージの付属テスト(存在する場合)
  • apps/vendure-server 直下で pnpm run test:integration – Vitest + Postgres/PGroonga によるバックエンド統合テスト(事前に docker compose dev を起動)
  • pnpm audit --audit-level high – 高リスク脆弱性の検出
# .github/workflows/test.yml(抜粋)
jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [22]
    services:
      postgres:
        image: groonga/pgroonga:latest-alpine-17-slim
        env:
          POSTGRES_PASSWORD: vendure_test
          POSTGRES_USER: vendure_test
          POSTGRES_DB: vendure_test
      redis:
        image: redis:7-alpine
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v2
        with:
          version: 10.17.0
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
      - run: pnpm install --frozen-lockfile
      - run: pnpm playwright:install # Storefront E2E用
      - run: pnpm run typecheck
      - run: pnpm run lint:check
      - run: pnpm run test
        env:
          DATABASE_URL: postgres://vendure_test:vendure_test@postgres:5432/vendure_test
          REDIS_HOST: redis
      - run: |
          cd apps/vendure-server
          pnpm run test:integration
        # Vendure 統合テストは Postgres/PGroonga を使用(docker compose dev が前提)
      - run: pnpm audit --audit-level high
  • MEMO: Storybook Test Runner は pnpm run test の後段に続けて導入予定ですが、現状の v9.1 系では安定版リリース待ちのため PR 確認では Vitest ベースの検知を優先しています。
  • MEMO: Storybook 上での GraphQL 通信は本番 API と切り離し、createApolloMocks による Apollo Client Mock を利用して擬似レスポンスを返す構成です。これにより UI 検証時も安定したデータセットを再現できます。
  • MEMO: ページ Story 間遷移が必要なケースでは @storybook/addon-links + カスタム StoryLinkInterceptor/cartPages/Cart/Default のように Next.js 内部リンクを対応する Storybook Story へ切り替えています。

デプロイワークフローにおける事前テスト

  • deploy-staging.ymltest ジョブ
  • pnpm run test / pnpm run typecheck / pnpm run lint:check
  • knip は CI から除外し、必要に応じて開発者がローカルまたは手動ジョブで実行
  • deploy-production.yml
  • 本番リリース前に pnpm run test + pnpm run typecheck + pnpm run lint:check
  • Node.js 22 で実行(Fly.io CLI のサポートバージョンに合わせた暫定設定)

補足: 手動での依存関係分析

CI から knip を外したため、依存関係分析は以下のコマンドで任意実行します。

pnpm run knip            # 開発中に未使用依存を調査
pnpm run knip:production # 本番ビルド用エントリで最適化確認

GitHub Secrets 設定

# GitHub リポジトリの Settings > Secrets and variables > Actions で設定:
# FLY_API_TOKEN: Fly.io API トークン

# Fly.io API トークン生成
flyctl auth token

Step 15: ステージング環境設定

ステージング環境デプロイ

# ステージング用アプリ作成(既に存在する場合はスキップ)
flyctl apps create ritsubi-ecommerce-staging

# ステージング用データベース(Dockerコンテナ)
cd /home/genm/Projects/ritsubi/apps/postgres
# fly.toml を staging 用にコピーして設定を変更
flyctl apps create ritsubi-postgres-db-staging --org ritsubi
flyctl volumes create postgres_data_staging --region nrt --size 5 -a ritsubi-postgres-db-staging
flyctl secrets set POSTGRES_PASSWORD="$(openssl rand -base64 32)" -a ritsubi-postgres-db-staging
flyctl deploy -a ritsubi-postgres-db-staging

# ステージング用 Redis(オプション、現在は未使用)

# ステージング環境デプロイ
cd /home/genm/Projects/ritsubi
flyctl deploy --config apps/vendure-server/fly.staging.toml -a ritsubi-ecommerce-staging

運用・メンテナンス

定期メンテナンス

# アプリケーション再起動
flyctl machine restart -a ritsubi-ecommerce

# ローリングアップデート
cd /home/genm/Projects/ritsubi
flyctl deploy --config apps/vendure-server/fly.toml --strategy rolling -a ritsubi-ecommerce

# データベースメンテナンス
flyctl ssh console -a ritsubi-postgres-db
psql -U postgres ritsubi_vendure -c "VACUUM ANALYZE;"

ログローテーション

# Fly.io ログは自動ローテーション
# 長期保存が必要な場合は外部ログサービス使用
# 例: Datadog, CloudWatch Logs, etc.

セキュリティアップデート

# ベースイメージ更新
cd /home/genm/Projects/ritsubi
flyctl deploy --config apps/vendure-server/fly.toml -a ritsubi-ecommerce

# 依存関係更新
pnpm update
pnpm audit fix

トラブルシューティング

よくある問題と解決方法

1. アプリケーション起動失敗

# ログ確認
flyctl logs -a ritsubi-ecommerce

# SSH でコンテナ調査
flyctl ssh console -a ritsubi-ecommerce

# 環境変数確認
env | grep DATABASE_URL

2. データベース接続エラー

# データベース接続テスト
flyctl ssh console -a ritsubi-postgres-db
psql -U postgres ritsubi_vendure

# 接続URL確認
flyctl secrets list -a ritsubi-ecommerce

3. Redis接続エラー

# Redis状態確認(使用している場合)
# flyctl redis status ritsubi-ecommerce-redis

# Redis接続テスト(使用している場合)
# redis-cli -h hostname -p 6379 -a password ping

4. デプロイ失敗

# 前のバージョンにロールバック
flyctl releases list -a ritsubi-ecommerce
flyctl rollback -a ritsubi-ecommerce

# ヘルスチェック確認
curl https://ritsubi-ecommerce.fly.dev/health

緊急時対応

# アプリケーション緊急停止
flyctl machine stop -a ritsubi-ecommerce

# 緊急スケールダウン
flyctl scale count 0 -a ritsubi-ecommerce

# 緊急時バックアップ復元
flyctl ssh console -a ritsubi-postgres-db
psql -U postgres ritsubi_vendure < backup.sql

React Dashboard を Cloudflare Pages で配信する手順

Vendure 本体は Fly.io 上で稼働しつつ、ダッシュボード静的アセットを Cloudflare Pages から配信する構成。API は直接 Fly.io オリジンを呼ぶ(リライト/Workers は使わない)。

  1. ビルド
    Pages で monorepo 全体をビルドしないよう vendure-server のみ対象にする。
corepack enable pnpm &&
pnpm install --frozen-lockfile --filter ritsubi-vendure-server... &&
pnpm -C apps/vendure-server run dashboard:build

出力先: apps/vendure-server/dist/dashboard/
SPA ルーティング用の _redirectspublic/ に追加済み(/dashboard/* -> /dashboard/index.html 200)。

  1. Cloudflare Pages 設定
  2. プロジェクト作成: Framework = “None”
  3. Build command: 上記の3行(pnpm install with filter → dashboard:build)
  4. Build output directory: apps/vendure-server/dist/dashboard
  5. Node バージョン: 開発環境と同一(22 系)を指定

  6. API 接続方式(方式1: 直接 Fly.io オリジンを呼ぶ)

  7. Pages 環境変数に VITE_ADMIN_API_URL=https://ritsubi-ecommerce.fly.dev/admin-api を設定(必要なら VITE_SHOP_API_URL も)。
  8. リライト/Workers は不要。
  9. Fly.io 側の .envCORS_ORIGIN に Pages ドメインを追記して許可。

  10. キャッシュ方針

  11. HTML: no-cache(Pages デフォルトのまま)
  12. /assets/*: Cloudflare CDN でキャッシュ許可。必要に応じて Cache Rules で適用。

  13. デプロイ動作確認

  14. https://<pages-domain>/dashboard/ でトップが表示されること
  15. /dashboard/pdf-templates/:id などダイレクトアクセスが 200 になること(_redirects により SPA フォールバック)
  16. https://<pages-domain>/admin-api に到達し、CORS エラーが出ないこと

  17. 環境変数の分離

  18. Dashboard 用のビルド時環境変数は apps/vendure-server/src/dashboard/.env.example をベースに .env.local などを作成し、Vite が参照する。
  19. Vendure サーバーランタイム用 .env.* とは混在させない(機微情報をフロントに漏らさないため)。
  20. Vite が読むのは VITE_ プレフィックスのみ。Pages の環境変数画面にも同名で設定する。

コスト最適化

リソース監視

# 使用量確認
flyctl billing show

# アプリごとの使用量
flyctl apps list --billing

自動スケーリング設定

# fly.toml の最適化設定
[http_service]
  auto_stop_machines = true
  auto_start_machines = true
  min_machines_running = 1  # 深夜時間帯は最小1台

文書バージョン: 1.0 作成日: 2025年9月17日 メンテナンス: 月次で内容見直し