- Vercelを使用してMVPを本番環境のURLにデプロイする
- APIルートを悪用から保護するためのレート制限を追加する
- AI機能のリリース後、構造化ロギングを設定して監視する
- DevToolsを使用してアプリのセキュリティを確認する
- アプリの本番環境対応度を、リリース前チェックリストを用いて評価する
- ライブ制作アプリ:誰でもアクセス可能な公開HTTPS URLにデプロイされたあなたのMVP
- デバッグ済みでテスト済みのMVPをGitHubリポジトリに
- ログイン、サインアップ、およびAPIルートの保護によるユーザー認証
- ストレージが設定されたSupabaseプロジェクト
- ユーザーテストのフィードバックをアプリに反映
MVPから本番環境へ
アプリは動作します。テストも済み、バグも修正し、ユーザー認証も追加しました。しかし現時点では、Codespacesのプレビューリンクを持っている人だけが利用でき、そのリンクはCodespaceの実行が停止すると消えてしまいます。
このユニットでは、MVPアプリを「自分のコンピューターで動作する」状態から「インターネット上の誰でも使用できる」状態へと進化させます。
このユニットでは、他のレッスンでも使用した家庭教師推薦アプリ「TutorMatch」をガイド例として使用します。Codespaces上での実行から誰でもアクセス可能なライブURLへの移行過程を学び、各ステップを自身のMVPに適応させていきます。
アプリがCodespacesから公開URLに移動すると、次の3点が変更されます:
可視性
アプリはURLを通じて公開されます。チームメンバーだけでなく、URLを発見または受け取った誰でも利用を試みることができます。
持続性
アプリは手動で起動しなくても実行され続ける必要があります。Codespacesではテスト時にサーバーを手動で起動していましたが、本番環境では実際のユーザーが利用する際に、ホスティングプラットフォームが自動的にアプリを稼働させ続けます。
費用
AI APIの呼び出しには毎回費用がかかります。Codespacesでは、アプリの利用者を制御できました(主に自身のみ)。公開URLでは、ユーザー認証やAPI認証を実施していても、悪用に対する追加の保護策が必要です。
デプロイメントプラットフォームの選択
あなたはCodespaces(あなただけがアクセスできる開発環境)でアプリを実行してきました。このアクティビティでは、それを Vercelにデプロイします。Vercelはウェブアプリケーションをホストし、永続的な公開URLを提供するプラットフォームです。
Webアプリケーションのデプロイ方法は数多く存在します。MVPをデプロイする際に最も一般的な選択肢を比較すると以下の通りです:
プラットフォーム
設定の複雑さ
無料プラン
最適
Vercel
シンプル(GitHubに接続)
100GBの帯域幅、100時間のサーバーレス
React/Next.js アプリケーションと API ルート
Google AI Studio デプロイ
非常に簡単(ワンクリック)
Google Cloudの請求が必要(新規ユーザーは300ドル分の無料クレジット付き)
AI Studioで完全に構築されたアプリ
愛すべき / ボルト
シンプル(組み込みホスティング)
限定、プラットフォームによって異なります
GitHubを使わない素早いプロトタイプ作成
Netlify
シンプル(GitHubに接続)
100GBの帯域幅
静的サイト、よりシンプルなバックエンド
鉄道/レンダリング
中
限定無料プラン
データベースを備えたフルスタックアプリケーション
このプログラムでは、Vercelを使用します。その理由は以下の通りです:
多くの場合、youappにはバックエンドが存在し、Vercelはそれを適切に処理します。MVPは単なる静的ページ群ではなく、Groqやその他のLLM APIを呼び出し、Supabaseに接続し、場合によっては他のAPIを呼び出すサーバーサイドAPIルートを備えています。Vercelのサーバーレス関数はバックエンドコードを自動的に処理します。Netlifyのようなプラットフォームはシンプルなアプリには適していますが、サーバーサイドロジックにはより多くの設定が必要です。
GitHubに直接接続します。コードは既にGitHub上に存在しています。Vercelはリポジトリをインポートし、変更をプッシュするたびに自動的に再デプロイします。このプログラム全体で使用してきたのと同じGitワークフローです。
クレジットカードは不要です。Vercelの無料プランでは、既に持っているGitHubアカウント以外に何も必要ありません。
Vercelは本番環境のセットアップとセキュリティを自動的に処理します。デプロイメントには多くの面で大幅な設定が必要ですが、Vercelはこれらの設定要件の大部分を自動的に処理します。
Netlifyは僅差の2位であり 別のプラットフォームを試したい場合に、確かな代替手段となる。VercelもNetlifyもGitHubと連携し、プッシュ時に自動デプロイされ、充実した無料プランを提供する。違いは、VercelがバックエンドAPIルートを標準で処理するのに対し、Netlifyではサーバーコードを独自の「Netlify Functions」形式に再構築する必要がある点だ。MVPアプリには、Vercelの方がよりシンプルで包括的な選択肢となる。
もし私のアプリが他のフレームワークを使用している場合はどうなりますか?
Next.js:アプリがNext.jsプロジェクトの場合、VercelはNext.jsの開発者によって構築されたため、依然として優れた選択肢です。
愛すべきか、それとも逃げるか:これらのプラットフォームは独自のホスティングとデプロイ機能を備えています。あなたのアプリは既にそのインフラ上で稼働しているかもしれません。Vercelへの移行か、プラットフォームの組み込みホスティングの継続かについては、コーチに相談してください。
Python (Flask, Streamlit, FastAPI): Vercelの無料プランは Pythonバックエンドをサポートしていません。代替プラットフォームとしてRailwayまたはRenderについてコーチに相談してください。Railway (railway.app) はPythonをサポートする無料プランを提供しています。GitHubリポジトリを接続すれば、Railwayが残りの処理を代行します。このユニットの概念(環境変数、監視、エラー処理)は依然として適用されますが、プラットフォーム固有の手順は異なります。
Vercelが扱うもの
Vercelは多くのインフラ関連の面倒な作業を自動的に処理します。責任範囲の分担は以下の通りです:
VERCEL
- HTTPS(暗号化された接続)でアプリのセキュリティを確保する
- 悪意のあるトラフィックがアプリに到達する前にブロックする
- 世界中のユーザー向けにアプリの高速化を実現する
- アプリを手動で起動しなくても、24時間365日稼働し続ける
あなた
- AI機能の利用頻度を制限する。制限がない場合、1人のユーザーが高額なAI呼び出しを数百回も発生させる可能性がある
- フレンドリーなエラーメッセージを表示します。これを設定しないと、何かが壊れた際にユーザーは混乱を招く技術的なエラーを目にしてしまいます。
In Codespacesでは、フロントエンドとバックエンドを別々のプロセスとして実行している可能性があります:
- フロントエンドサーバー、おそらくReact
- バックエンドサーバー、おそらくExpress
これはビルドとデバッグに最適な標準的な開発環境です。
しかしながら、 Vercel はGitHub Codespacesとは動作が異なります。永続的なExpressサーバーを実行しません。代わりに、次の2つのことを行います:
- フロントエンドファイル(npm run buildで生成されるHTML、CSS、JavaScript)は、VercelのグローバルCDNによって配信されます。 CDN(コンテンツ配信ネットワーク) とは、世界中に分散したサーバー群のネットワークであり、アプリの静的ファイル(HTML、CSS、JavaScript、画像)のコピーを保存します。
Vercelはビルド出力ディレクトリ(dist/など)でこれらを探します。Vite開発サーバーやexpress.static()コードは本番環境では使用されません。VercelのCDNが完全に置き換えます。これは正常かつ想定された動作です。
- APIルート(例: /api/recommendations)は、各リクエストごとに新規に起動するサーバーレス関数として実行されます。
これを機能させるには、VercelがExpressアプリをファイルからエクスポートし、Vercelが認識できる場所に配置する必要があります。最初のアクティビティで簡単な設定手順を通じてこれを設定します。
既存のコードに大幅な変更は必要ありませんので、ご心配なく。アプリを書き換えるのではなく、デプロイ構成レイヤーを追加するだけです。
最終的には、友人や家族、さらには潜在的な顧客と共有できるライブURLが手に入ります。
アクティビティ1
Vercelでアプリを公開する準備を整えましょう
所要時間:30分
1. Codespacesでプロジェクトを開く
- GitHubにアクセスし、MVPリポジトリに移動してください。
- デプロイ前に、過去のユニットの作業をすべてメインブランチにマージしておく必要があります。コミット済みの未マージブランチはすべてマージしてください。
- メインブランチにいることを確認してください。
- クリック コードをクリックし、次に メインブランチにコードスペースを作成 をクリックします。他のブランチ用に既存のコードスペースがある場合でも、メインブランチから新しいコードスペースを開いてください。
- Codespace環境の読み込みを待ちます。
注記:これまで、リポジトリの更新は常に新規ブランチで行ってきました。今回はメインブランチを更新していますが、これは意図的な措置です。Vercelが自動デプロイ用にメインブランチを監視しているためであり、アプリロジックを変更せず設定ファイルを追加するのみである本ケースにおいては、メインブランチへの直接的な事前作業が許容されるためです。
2. JavaScriptの標準を確認する
JavaScriptには、ファイル間でコードを共有するための2つの異なるシステム、CommonJSとES Modulesがあります。 CommonJS はより古いシステムで、JavaScriptがサーバー上でのみ動作していた時代にNode.js向けに構築されました。 ES Modules は新しい標準であり、ブラウザとNode.jsの両方で動作し、現在推奨されるアプローチです。
Expressサーバー内のexportコードは、プロジェクトが使用するシステムと一致させる必要があります——ES Modulesの場合はexport default app、CommonJSの場合はmodule.exports = appです。間違った方法を使用するとデプロイが失敗します。
このことを理解しておくことで、Copilotにコードの更新を促す際のヒントになります。
見分ける方法は次の通りです:
- package.json を確認してください このフィールドの にこのフィールドがあるか確認してください:json”type”: “module”
この行があれば、ESモジュールを使用しています。 - 欠落しているか「type: commonjs」と記載されている場合、CommonJSを使用しています。
- 別の確認方法は、ファイルの先頭にあるインポート文です。 server.js.
- ESモジュールは以下のようになります:
import express from 'express'
import dotenv from 'dotenv' - CommonJSは次のようになります:
const express = require(‘express’)
const dotenv = require(‘dotenv’)
- ESモジュールは以下のようになります:
- おそらくコードの末尾にもexport文があるでしょう:
- ESモジュール:
export default app
CommonJS:
module.exports = app
- ESモジュール:
使用している規格を確認し、記録してください。
3. アプリのデプロイ準備
おそらくGitHub Codespace環境でアプリを実行しているため、フロントエンドとバックエンド用に2つの別々のプロセスが存在するでしょう。
Reactフロントエンド(Vite)用とExpressバックエンド用の2つ。
Vercelには異なる構造が必要です。
- 構築したフロントエンドファイルをCDNから提供します。
- Express API ルートをサーバーレス関数として実行します。
良いニュースは、この移行作業が主に設定ファイルの追加と数行のコード変更で済むことです。既存のアプリロジックはそのまま維持されます。
CodespaceでCopilot Chatを開き、次のようなプロンプトを使用してください:
あなたは私のExpress.js + ReactアプリをVercelにデプロイするための準備を手伝ってくれています。
目標: プロジェクトを設定し、Vercelがフロントエンドを提供し、バックエンドAPIルートをサーバーレス関数として実行できるようにする。
私のアプリは現在、Codespaces内で2つの別々のプロセスとして実行されています。
ターミナル1はViteでReactフロントエンドを実行します(npm run dev)。ターミナル2は別のポートでExpressバックエンドを実行します(npm run dev)。
私はVercelにデプロイしています。Vercelはビルド出力から静的ファイルを提供し、Expressをサーバーレス関数に変換します。
以下の変更を行ってください:
- サーバーファイル: Expressサーバーファイル(server.jsなど)をapi/ディレクトリに移動し、必要に応じてindex.jsにリネームしてください。ファイル末尾に以下を追加: [if ES_MODULES: export default app or COMMONJS: module.exports = app]。ローカル開発用に既存のapp.listen()は維持してください。
- VERCEL CONFIG: プロジェクトルートに以下の内容で vercel.json ファイルを作成します:
{
「書き換え」: [
{ “source”: “/api/(.*)”, “destination”: “/api” }
]
}
- PACKAGE.JSON: 以下のスクリプトが存在することを確認してください:
- 「dev」はローカル開発においてフロントエンドとバックエンドの両方を実行すべきです(concurrentlyの使用は問題ありません)
- “build”: “vite build” (compiles the React frontend into /dist)
Add an “engines” field: { “node”: “>=18.0.0” }
Make sure all backend dependencies (express, cors, dotenv, [your AI SDK]) are in the root package.json, not in a separate server package.json.
- URLチェック: すべてのフロントエンドファイルにおいて、localhost、github.dev、または127.0.0.1を含むハードコードされたURLを検索します。http://localhost:3000/api/recommendations の代わりに /api/recommendations のような相対パスに置き換えてください。
- VITE プロキシ: `vite.config.ts`(または `vite.config.js`)にプロキシを追加し、ローカル開発で相対URLが引き続き機能するようにします:
server: {
proxy: {
‘/api’: { target: ‘http://localhost:3001’, changeOrigin: true }
}
}
更新ごとに、変更箇所を表示してください。
4. 更新内容を確認する
- コパイロットが生成した内容をレビューしてください。各変更点とその重要性について説明します。
api/ディレクトリとエクスポート
Vercelはapi/api/api/api/api/api/api/api/api/api/api/api/api/api/api/api/api/api/api/api/api/api/api/ api/ディレクトリ内でサーバーレス関数を探します。Expressサーバーをこのディレクトリに移動し、export default app ディレクトリ内でサーバーレス関数を探します。Expressサーバーをこのディレクトリに移動し、`export default app`(または`module.exports = app`)を追加することで、VercelはExpressアプリをインポートし、サーバーレス関数として実行できるようになります。
app.listen()行は残しておいてください — Vercel は本番環境ではこれを無視しますが、Codespaces でのローカル開発には依然として必要です。
サーバーファイルは以下のような内容で終わる必要があります:
// Local development — Vercel ignores this in production
app.listen(process.env.PORT || 3000, () => {
console.log(`Server running on http://localhost:${process.env.PORT || 3000}`);
});
// Export for Vercel serverless deployment
export default app;
vercel.json ファイル
この小さな設定ファイルは、リクエストのルーティング方法をVercelに指示します。 /api/* はExpressアプリに送信され、それ以外はビルドされたフロントエンドファイルに送信されます。ファイル全体はわずか5行です。
{
"rewrites": [
{ "source": "/api/(.*)", "destination": "/api" }
]
}
相対URL
フロントエンドで`fetch('http://localhost:3000/api/recommendations')` を使用している場合、Vercelでは `localhost:3000` が存在しないため動作しません。
コパイロットはこれを相対パス(例:fetch('/api/recommendations'))に変更すべきです。ブラウザは、ページをホストしているドメイン(Codespaces または本番環境の .vercel.app URL)に対してパスを解決します。
Viteプロキシ
フロントエンドで相対URLを使用する場合、ローカル開発中に/apiリクエストをExpressサーバーに転送する手段が必要です。Viteプロキシはこれを自動的に行います。
- フロントエンドがapi/recommendations にリクエストを送信すると、Vite はそれを Express サーバーが稼働しているhttp://localhost:3000/api/recommendationsに転送します。
- Vercelでの本番環境では、代わりにvercel.jsonのリライトがこれを処理します。
package.jsonファイル
package.jsonファイルにはいくつかの変更が必要です。
- スクリプト— サーバー スクリプトのパスは server/server.js から api/index.jsに変更され、開発用スクリプトも新しいパスを反映するよう更新される可能性があります
- 依存関係— 以前 server/package.json はすべて ルートパッケージの `package.json` に移動する必要があります に移す必要があります。
- 「type」: 「module」— 追加されたか、既に存在していた可能性があります
- “engines” — { “node”: “>=18.0.0” } added for Vercel compatibility
たとえば、スクリプトセクションは次のようになります:
"scripts": {
"dev": "concurrently \"vite\" \"node api/index.js\"",
"build": "vite build",
"preview": "vite preview",
"server": "node api/index.js"
},
「build:」行に注意してください。これは設定に応じて変更可能です:
- React + Vite(Copilotで最も一般的な組み合わせ) –「ビルド」: 「vite build」
- React with Create React App –“build”: “react-scripts build”
- Vanilla JS(フレームワークなし) –ビルドステップ不要
これがGitHub Copilotが私たちに示したその動作です:
Express.js + ReactアプリをVercelにデプロイできるよう準備をお手伝いします。まずはプロジェクト構造を確認し、現在の設定を理解することから始めましょう。
完璧です!tutormatch-app-gemini-auth-workingのプロジェクト構造を確認しました。朗報です:アプリはすでにVercelデプロイ用に完全に設定済みです。必要な変更5点すべてが既に適用されています!
現在の設定の概要 ✅
1. サーバーファイル ✅
index.js は正しく設定されています:
- Vercelの要件に従い、api/ディレクトリ内に配置されています
- 既にアプリをエクスポートしています(デフォルトアプリとしてエクスポート、ESモジュール)
- ローカル開発用にポート3001で動作するapp.listen(PORT)を含みます
- すべてのExpressルート(/api/recommendationsおよび/api/healthを含む)が設定済みです
2. VERCEL CONFIG ✅
あなたのvercel.jsonは正しく設定されています:
これにより、すべての /api/* リクエストをサーバーレス関数にルーティングするよう Vercel に指示します。
3. PACKAGE.JSON ✅
package.jsonには必要なスクリプトと設定がすべて含まれています:
- ✅ 「dev」スクリプトはバックエンドとフロントエンドの両方を同時に実行するために並列処理を使用します
- ✅ Reactフロントエンドの「ビルド」は「vite build」に設定されています
- ✅ 「engines」フィールドには Node.js バージョン 18.0.0 以上が必要です
- ✅ すべてのバックエンド依存関係(express、cors、dotenv、@google/genai)はルートパッケージのpackage.jsonにあります。
- ✅ concurrently はnpm run serverと npm run client を同時に実行するよう適切に設定されている
4. URLチェック ✅
ハードコードされたURLは見つかりませんでした。フロントエンドは正しく以下を使用しています:
- 相対パス:App.tsx内のfetch('/api/recommendations', …)
- これはローカル開発環境(プロキシ経由)と本番環境(Vercelサーバーレス)の両方で動作します
5. VITE プロキシ ✅
vite.config.ts にはプロキシが設定されています:
これにより、ローカル開発時に `npm run dev` を実行している間、`/api` へのリクエストは Express バックエンドにプロキシされます。
これが意味すること
プロジェクトは今すぐVercelにデプロイ可能です!Vercelにプッシュすると:
- ViteはReactフロントエンドを/distにビルドします
- Vercelが静的ファイルを提供します
- すべての /api/* リクエストは、index.js内の Express 関数によって処理されます。
- Supabaseの認証とGemini API呼び出しはシームレスに動作します
ローカル開発: `npm run dev` を実行すると、フロントエンド(ポート 5173)とバックエンド(ポート 3000)が自動的に起動し、Vite プロキシが API 呼び出しを処理します。
5. フロントエンド環境変数の追加
メインブランチから直接新しいコードスペースを実行する可能性があるため、 .env ファイルが失われている可能性があります。このファイルは各コードスペースにローカルに存在します。これらの環境変数はルートディレクトリの .env ファイルに設定する必要があります。
- すべてのVITE変数についてコードを確認してください。これらはルートディレクトリの .env ファイルに記述されていたはずです。
- .env に .env ファイルをルートフォルダに追加し、それらを再度追加してください。私たちの場合、それらは以下の通りでした:
VITE_SUPABASE_URL=
VITE_SUPABASE_KEY=
VITE_DEVELOPMENT_URL=
VITE_DEVELOPMENT_URL は、テスト用にコードスペースの github.dev URL に設定してください。Vercel の設定時に、ご自身の Vercel アプリ URL に更新します。
- すべてのバックエンド環境変数がCodespaceのシークレットに含まれていることを確認してください。ルートに追加することはできません .env フォルダに追加しないでください。公開されてしまいます。
6. デプロイ前にCodespacesでテストする
- 依存関係をインストール:npm install(同時依存関係とバックエンド依存関係をインストールします)
- npm run devを実行すると、フロントエンドサーバーとバックエンドサーバーの両方が起動します。
- テスト:
- ページ読み込み
- ログインは機能します
- AI機能が応答します
- ローカル環境ですべてが正常に動作すれば、デプロイの準備が整っています。
- LLMと連携を続け、Vercelデプロイの準備が整っていることを確認してください。
6. 変更をコミットする
- 変更をコミットし、メインブランチにプッシュしてください。
- GitHubでメインブランチを最新の状態にするため、すべての変更をマージしてください。
コードをVercelプラットフォームで動作するように更新したところで、いよいよデプロイです!
アクティビティ2
アプリをVercelにデプロイする
所要時間:30分
1. 無料のVercelアカウントを作成する
- vercel.comにアクセスしてください。
- 「サインアップ」をクリックしてください。
- 「GitHubで続ける」を選択してください。これにより、VercelがMVPコードが存在する同じGitHubアカウントに接続されます。
- Vercel が GitHub リポジトリにアクセスすることを許可してください。
クレジットカードは不要です。無料のホビープランでMVPには十分すぎるほどです。
2. GitHubリポジトリのインポート
- Vercelダッシュボードから、[新規追加] → [プロジェクト] をクリックします
- リストからMVPリポジトリを見つけて「インポート」をクリックしてください。
GitHubをまだ適切に接続していない場合は、Vercelのドキュメント「GitHubプロジェクトのデプロイ」に記載されている手順に従ってください。
Vercelはプロジェクトタイプを自動検出し、ビルド設定を自動的に入力します
- Vercelは通常正しいですが、設定がプロジェクトと一致していることを確認してください。
もしあなたのプロジェクトに…
フレームワークプリセット
ビルドコマンド
出力ディレクトリ
vite.config.ts または vite.config.js
vite.config.ts または vite.config.js
vite ビルド
dist
next.config.js または next.config.ts
Next.js
次のビルド
.次
server.js + public/フォルダ
その他
(空またはカスタム)
公開
package.json内のreact-scripts
Create React App
react-scripts ビルド
ビルド
これが当社のTutorMatchアプリの外観です:
- Vercelが誤ったフレームワークを検出した場合は、[ビルドと出力設定]をクリックして上書きしてください。
ビルドコマンドと 出力ディレクトリが最も重要な2つの項目です。不明な場合は、npm run buildを実行した際にローカルで生成される内容を確認してください。実行後にdist/、build/、または.next/フォルダが存在するか確認します。
3. 環境変数の設定
これが最も重要なステップです。アプリが機能するにはAPIキーが必要であり、それらはコード内ではなくVercelで設定する必要があります。
- プロジェクト設定画面で、環境変数をクリックします。
- 次の2つの選択肢があります:
- .envファイルのインポート – 「.envファイルをインポート」 をクリックし 、ローカルの.envファイルを選択してください。Vercelが自動的にすべてのキーと値のペアを読み込みます。
- 手動で追加 –各キー名をタイプし、その値を1つずつ貼り付けます。
- アプリに必要なすべてのキーを、フロントエンドとバックエンドの両方の環境変数に追加してください!
Codespacesでは、キーは .env またはGitHub Secretsに保存されていました。本番環境では、Vercelの環境変数設定に保存されます。これは同じ概念ですが、保存場所が異なるだけです。
これが私たちにとっての見え方です:
注:後続のユニットで支払い追加方法を学習する際、Stripeキーを追加するためにこの画面に戻ってくる必要があります。現時点では、開発中に追加したキーのみで十分です。
4. デプロイ
- デプロイをクリックしてください。
VercelがGitHubからコードを取得し、依存関係をインストール、アプリをビルドし、URLを割り当てます。この処理には1~3分かかります。ビルドログをリアルタイムで確認できます。
完了すると、Vercel は確認画面を表示し、Vercel ダッシュボードに移動するためのリンクが表示される場合があります。
どうぞ。ここでは、アプリの詳細情報(例:
- あなたのURL
- 後続のステップで説明するベストプラクティスの推奨事項を、今すぐ始められるチェックリスト
- 後ほど説明する可観測性パネル
- 後ほど説明するアナリティクスパネル
このURLは本番環境のURLです。GitHub Codespaces上のMVPアプリのようにURLが変更されるのとは異なり、VercelではURLは静的であり、コンピューターの電源がオンでもオフでも常に有効です。
本番環境のURLはどこでも開けますので、スマートフォンで開いてアプリがインターネット上に公開されていることを確認してください。アプリがインターネット上に公開されていることを確認してください!
Congratulations!
5. SupabaseにリダイレクトURLを追加する
アプリをVercelにデプロイしたら、VercelのURLが信頼できるリダイレクト先であることをSupabaseに通知する必要があります。そうしないと、認証のコールバックが失敗してしまいます。GitHubの開発用リダイレクトはすでに追加済みですが、今度はVercelのURLもリダイレクト先として追加する必要があります。
- [自分の]へ移動してください Supabase ダッシュボード → 認証 → URL 設定 すると、2つの入力欄が表示されます:
- サイトのURL— ここにはVercelの本番環境のURLを設定してください:https://your-app.vercel.app
- リダイレクト URL— Vercel の URL と Codespaces の URL の両方を追加してください。Codespaces の URL はすでにお持ちのはずです。これを「github.dev」のワイルドカードに置き換えることで、新しい Codespace でも正常に動作するようになります。既存の URL を削除し、以下の URL を追加してください:
https://your-app.vercel.app
**https://*.github.dev/**
末尾のワイルドカード 「/**」は重要です。これによりすべてのルートが対象となり、決済機能を追加する際に必要となります。
6. Supabaseでメール確認機能を有効にする
Supabaseにユーザー認証機能を追加した際、Supabaseのメール通知機能を無効にしていました。今回、本番環境向けにこの機能を再び有効にしたいと考えています。
- Supabaseのダッシュボード → 「認証」 → 「サインイン/プロバイダー」に移動します。
- 「メールの確認」スイッチを「ON」に切り替えてください。
6. デプロイが正常に動作することを確認する
ライブURLにアクセスしてテストしてください:
- ページは正しく読み込まれていますか?(ログインページが表示されているはずです)
- 新しいアカウントを作成してログインできますか?
- ログイン後、AI機能をテストしてください。反応しますか?
動作しない場合は、以下のトラブルシューティングセクションを確認してください。ビルドエラーは初回デプロイ時によく発生します。
7. 別の端末からテストする
- URLをチームメイトや友人と共有してください。
- 彼らに、スマートフォンやコンピューターでURLを開いてもらい、アカウントを作成し、アプリの機能の一つを使ってみるよう依頼してください。
Codespacesを実行せずにアプリにアクセスしたのは今回が初めてです。 正常に動作すれば、アプリは公開されています。
カスタムドメインをご希望ですか?デフォルトでは、アプリのURLは自動的に生成され、your-app-name.vercel.app のようになります。しかし、tutormatch.app のようなブランド化されたURLをご希望の場合は、最後のオプションのチャレンジで、その方法を段階的に説明するガイドをご覧ください。デプロイメントチェックリストにあるVercelのガイドを使って、ご自身で試してみることもできます。
トラブルシューティング
以下の各問題をクリックすると、考えられる解決策が表示されます。
ビルドがVercelで失敗しました
失敗したデプロイをクリックし、ビルドログを確認してください。
主な原因:
- package.json に依存関係が不足しています package.json
- インポートパスのタイプミス
- 不足しているビルドスクリプト。
まずCodespacesで`npm run build`を実行してください。ローカル環境で失敗した場合、Vercelでも失敗します。
サーバーレス関数がクラッシュした、またはAPIルートが500を返す
おそらくサーバーファイルがExpressアプリをエクスポートしていません。
追加:
- export default app;for (ESモジュール) または
- module.exports = app;for (CommonJS)
api/ api/ ディレクトリの末尾に追加してください。
これが最も一般的なデプロイメントの問題です。
環境変数が読み込まれない
- Vercelプロジェクト → 設定 → 環境変数 に移動します。
- すべてのキー名がコードの期待値と完全に一致していることを確認してください(大文字小文字を区別します)。
注意:VITE_で始まる変数はフロントエンドコード専用です。
GEMINI_API_KEYやGROQ_API_KEYなどのバックエンドAPIキーにはVITE_プレフィックスを付けてはいけません。
ページは読み込まれるが、AI機能がエラーを返す
- Vercelのログタブを確認してください(デプロイメント → デプロイメントをクリック → 関数ログ)。
- 「API_KEY が定義されていません」または類似のエラーを探してください。
- 見つかった場合、Vercelの環境変数に不足しているキーを追加してください。
- ローカル(コードスペース)を確認してください .env ファイルをローカルで確認し、アプリがどのキーを期待しているかを確認してください。
すべてのページで502または500エラーが発生しています
Expressサーバーのポートが固定設定されている可能性があります。
app.listen(3000)をapp.listen(process.env.PORT)に変更し、PORT が環境変数に含まれていることを確認してください。
ブラウザコンソールにおけるCORSエラー
フロントエンドにハードコードされたURLが存在します(例:http://localhost:3001/api/…)。
それらを相対パス(/api/…)に変更してください。
相対パスはCORS問題を完全に回避します。
CSS、画像、または静的ファイルが見つかりません
Vercelは本番環境においてexpress.static()を無視し、ビルド出力ディレクトリから静的ファイルを提供します。
CSSや画像が欠落している場合は、それらが dist/ フォルダに含まれていることを確認してください。
画像については、必ず public/ フォルダ内にあるか、Reactコード内でインポートされていることを確認してください。
モジュールが見つかりませんエラー
package.json から依存関係が欠落しています package.jsonから依存関係が欠落しています。
Codespacesでnpm installを実行し、更新されたpackage-lock.jsonをメインブランチにプッシュしてください。
ログインページが表示されない
Supabase認証のリダイレクトURLに新しいVercel URLが含まれていることを確認してください。
Supabaseダッシュボード → 認証 → URL設定 に移動し、.vercel.app URLを追加してください。
認証リダイレクトはCodespacesのURLまたはlocalhostに遷移します
Supabase認証設定内のサイトURLとリダイレクトURLを、ご自身のVercel URLに更新してください。
開発が正常に動作するよう、リストにCodespacesのURLを保持してください。
デプロイは成功したが、アプリは空白ページを表示する
Vercel設定のビルド出力ディレクトリが、npm run buildがファイルを配置する場所と一致していません。
確認:
- Viteは dist/,
- Create React Appは build/.
Vercelのビルド&出力設定で出力ディレクトリを更新してください。
Vercelはあなたのフレームワークを検出できません
必ず vercel.json ファイルがプロジェクトルートに存在することを確認してください(アクティビティ1で作成したものです)。
APIルートがまだ動作しない場合は、buildsセクションを追加してみてください:
{
"builds": [{
"src": "api/index.js"
"use": "@vercel/node"
}],
"rewrites": [{
"source": "/api/(.*)",
"destination": "/api"
}]
}
Vercel関数がタイムアウトしました
Fluid Compute(新規プロジェクトではデフォルトで有効)により、Hobbyプランでは関数を最大300秒(5分)実行できます。
Fluid Compute を使用しない場合、制限は60秒です。
AIの応答がタイムアウトする場合は、プロンプトを簡略化するか、ユーザー向けにローディングインジケーターとタイムアウトメッセージを追加することを検討してください。
自動デプロイ
GitHubでMVPを構築する過程で、作業を整理するためのブランチについて学びました。今やブランチには実際の影響が生じます: プッシュ先 main へのプッシュは、本番環境のアプリが即座に変更されることを意味します。
GitHubにおける一般的な本番環境のワークフローは以下の通りです:
- メインブランチ = プロダクション環境。Vercelに接続。プッシュするたびに自動デプロイされます。
- 機能ブランチ = 新規作業のための安全な領域。ここで実験してください。
テストされていないコードを直接 メインブランチにプッシュしないでください に直接プッシュしないでください。
不適切なプッシュは、すべてのユーザーに対してライブアプリを壊します。
アクティビティ3
テスト自動デプロイ
所要時間:15分
1. 新しいブランチとコードスペースを作成する
- GitHubにアクセスし、MVPリポジトリに移動してください
- リポジトリの左上にあるメインのドロップダウンをクリックし、すべてのブランチを表示します。
- 新しいブランチを作成する。
- 名前は自由です:test-auto-deploy
- このブランチ用の新しいCodespaceを作成し、開きます。
2. アプリに小さな変更を加える
- 見出しやボタンのテキストを更新するなど、小さな目に見える変更を加えて、それが機能したかどうかを簡単にテストできるようにしてください。
ページタイトルを「TutorMatch」から「TutorMatch – 自動デプロイのテスト」に変更します。
私たちはそれを App.jsx ファイルで見つけました。
3. 変更をコミットする
- Codepsaceで変更をコミットし、説明的なメッセージを添えてテスト自動デプロイブランチにプッシュしてください。
- GitHubに戻ってください。プッシュが行われたことを示すボタンが表示されているはずです。
- プルリクエストを作成するにはボタンをクリックするか、プルリクエストタブに移動してください。
- タイトルと説明を追加する
- プルリクエストを作成をクリックしてください。
- 「プルリクエストをマージ」をクリックし、確認します。
GitHubでマージを確認すると、以下が表示されるはずです
- 歴史
- Vercelに関する詳細情報これはVercelの統合により追加されました。
うまくいけば競合が発生せず、プルリクエストを正常にマージできるでしょう。
4. Vercelで更新を確認する
- Vercelのダッシュボードにアクセスしてください。
- プロジェクトの「デプロイ」をクリックしてください。
2つの新しい行が表示されるはずです:
- 変更をプレビューする機能
- 本番ビルド用です。本番ビルドのステータスは「ビルド中」または「準備完了」となります。
「準備完了」になったら、指定のURLにアクセスして変更内容を確認できます。
- 完了したら、ライブURLを更新して変更を確認してください
4. 変更を元に戻すために再度更新する
「TESTING DEPLOYMENT」というタイトルは避けたいところです。Vercelにはロールバック機能がありますが、それでもGitHubリポジトリを参照して現在のメインブランチを取得するため、変更を元に戻すには同じ手順を踏む必要があります。
- Codespaceに戻り、タイトルを元に戻してください。
- 変更をコミットしてプッシュする。
- プルリクエストを作成し、マージしてください。
- Vercelでタイトルが元の状態に戻っていることを再度確認してください。
本番環境向けのアプリを保護する
プログラムを通じて、アプリに段階的にセキュリティを構築してきました。例えば:
- GitHub SecretsへのAPIキーの保存(コードやコミット履歴から除外する)
- サーバーサイドでのAPI呼び出し(キーを完全にブラウザ外に保持する)
- Supabaseを使用したユーザー認証を追加し、ログインしたユーザーのみがアプリにアクセスできるようにする
- APIミドルウェアのセキュリティを追加し、あなたのアプリ以外がAPI呼び出しを行えないようにしました。
これらは重要な保護策ですが、すべてをカバーしているわけではありません。
認証済みアプリユーザーであっても、1分間に500回もAI機能を呼び出すスクリプトを作成し、Groq/Gemini/Hugging Face APIのクレジットを全て使い切ったり、さらに悪い場合には多額の費用を発生させたりする可能性があります。
あるいはAPIキーが期限切れになる可能性があり、安全なエラー処理がなければ、ユーザーは有益なメッセージではなく非常に技術的な生のメッセージを目にしてしまうでしょう。
Vercelはインフラストラクチャレベルでアプリケーションを保護し、分散型攻撃、ネットワークフラッド、基本的なWeb脅威などから守ります。これらは自動的にブロックされます。
しかしVercelは、あなたのAI APIが呼び出しごとに課金されることや、エラー応答に内部詳細が含まれていることを知りません。これらはアプリケーションレベルの問題であり、あなただけが把握し対処できるものです。
次の操作では、さらに2つの保護層を追加します:
- レート制限: 各ユーザーが発行できるリクエスト数に制限を設けること
- 安全なエラー処理: 技術的なエラーをユーザーフレンドリーなメッセージに置き換える
レート制限を追加する方法はいくつかあります。以下にそれらの比較を示します:
アプローチ
仕組み
トレードオフ
インメモリ(エクスプレスレート制限)
ストアはサーバーのメモリ内で要求数を保持します
設定が簡単。サーバーレス関数が再起動するとリセットされます。連発攻撃を捕捉します。
外部ストア(データベースなど)
再起動後も永続化する別のデータベースにカウントを保存する
トラフィックが集中している状況下でもより信頼性が高いが、追加サービスの設定と料金支払いが必要となる。
最も複雑ではありますが、ユーザー数が増えた際には強くお勧めします。
エッジミドルウェア
リクエストがコードに到達する前に、Vercelのネットワークエッジでブロックします
最速のレスポンスを実現しますが、別のコーディングパターン(Vercel Edge Runtime)の習得が必要です
MVP向けに、 インメモリレート制限 が現実的な選択肢です。最小限の設定で、最も一般的な不正利用パターン(AIボタンを繰り返しクリックするユーザーや、スクリプトによる高速リクエスト)を捕捉します。競合他社を凌駕する規模に成長し、リセットされないレート制限が必要になった場合、データベースストレージへのアップグレードが自然な安全策となります。
アクティビティ4
レート制限と安全なエラー処理を追加する
所要時間:20分
1. 新しいブランチとコードスペースを作成する
- GitHubにアクセスし、MVPリポジトリに移動してください
- リポジトリの左上にあるメインのドロップダウンをクリックし、すべてのブランチを表示します。
- 新しいブランチを作成する。
- 任意の名前を付けられます:add-security(または別の説明的な名前)。
- このブランチ用の新しいCodespaceを作成し、開きます。
2. APIルートにレート制限を追加する
本番環境では、URLを発見した誰でもリクエストを送信できます。これには1分間に数百回のAI呼び出しを実行するスクリプトも含まれます。レート制限により、各ユーザーが送信できるリクエスト数に上限が設けられます。
- CodespaceでCopilot Chatを開き、次のプロンプトを使用してください:
役割: あなたは、私のExpress.jsアプリケーションを本番環境デプロイ向けにセキュアにするのを支援しています。
目標:APIの不正利用を防ぐため、ルートにレート制限を追加する。
コンテキスト: 私のアプリはExpress.jsを使用し、APIルートは/api/配下に配置されています。アプリは既にVercelを使用してデプロイ済みです。
ユーザーごとのAPI制限: ユーザーあたり1分間に5リクエストまでとします。ステータスコード429を返し、「リクエストが多すぎます。しばらくお待ちください。」と表示します。
ストレージ: 要求を追跡するためにインメモリストレージを使用する。
- 生成されたコードを確認してください。これが私たちの index.js ファイルに生成された内容です。
const RATE_LIMIT_WINDOW_MS = 60 * 1000
const RATE_LIMIT_MAX_REQUESTS = 5
const requestLog = new Map()
const getUserKey = (req) => {
const forwardedFor = req.headers['x-forwarded-for']
if (typeof forwardedFor === 'string' && forwardedFor.length > 0) {
return forwardedFor.split(',')[0].trim()
}
return req.ip || req.socket?.remoteAddress || 'unknown-user'
}
const apiRateLimiter = (req, res, next) => {
const now = Date.now()
const userKey = getUserKey(req)
const userTimestamps = requestLog.get(userKey) || []
const validTimestamps = userTimestamps.filter(
(timestamp) => now - timestamp < RATE_LIMIT_WINDOW_MS
)
if (validTimestamps.length >= RATE_LIMIT_MAX_REQUESTS) {
const oldestTimestamp = validTimestamps[0]
const retryAfterSeconds = Math.max(
1,
Math.ceil((RATE_LIMIT_WINDOW_MS - (now - oldestTimestamp)) / 1000)
)
return res
.status(429)
.set('Retry-After', String(retryAfterSeconds))
.json({ error: 'Too many requests. Please wait a moment.' })
}
validTimestamps.push(now)
requestLog.set(userKey, validTimestamps)
next()
}
// Middleware
app.use(cors())
app.use(express.json())
app.use('/api', apiRateLimiter)
Copilotによって追加されたいくつかの重要な部分が見えるはずです。正確な変数名は異なるかもしれませんが、以下のようなものがあるはずです:
- WINDOW_MS変数: 時間窓の持続時間を制御するため: 60*1000 = 60,000ミリ秒(1分)
- MAX_REQUESTS変数: 1つのウィンドウで許可されるリクエスト数を制御します。当アプリでは = 5
CopilotはExpressのバージョンに応じてこれらの変数をlimitまたはmaxとして生成する場合がありますが、どちらでも動作するはずです。 - 制限に達した際のメッセージ。当社のアプリの場合 = 「リクエストが多すぎます。しばらくお待ちください」
3. Codespaceでのレート制限のテスト
レート制限は、Codespacesでテストするか、コードをマージして本番環境でテストすることができます。現在この機能を検証中であるため、 Codespacesでのテストが望ましいです。
- Codespacesでアプリを起動し(npm run dev)、ブラウザタブでプレビューします。
- ログインして、AI機能に移動してください。
- AI機能ボタンを20回以上素早く連続してクリックしてください。
- 制限に達すると「リクエストが多すぎます。しばらくお待ちください。」と表示されるはずです。
- しばらくお待ちいただき、再度お試しください。正常に動作するはずです。
メッセージが表示されない場合は、Copilotでデバッグできます。
注記:Vercel はバックエンドをサーバーレス関数として実行するため、インスタンスが再起動するとインメモリのレートリミッターがリセットされます。これは MVP のトラフィックには問題ありません。ボタンを 50 回クリックするといった高速連打の不正利用は捕捉できます。
4. 安全なエラー処理を追加する
Codespacesでは、詳細なエラーメッセージがデバッグを支援します。本番環境では、それらの詳細が攻撃者にコードの構造を明かしてしまいます。
安全なエラー処理では、ユーザーには親切なメッセージを表示しつつ、サーバー側で技術的な詳細を記録します。エラーメッセージを削除するのではなく、攻撃者が閲覧できないよう転送しているだけです。
- Copilotにtry/catch例外処理を追加するよう指示してください。サンプルプロンプトは以下の通りです:
Express.js APIに本番環境対応のエラー処理を追加する方法を教えてください。
生のエラーメッセージを安全でユーザーフレンドリーな応答に置き換える。
コンテキスト: 私のアプリはExpressのルートからGroq APIを呼び出します。本番環境では、ユーザーにスタックトレースや内部の詳細が表示されないようにしたいです。
ルートハンドラーをtry/catchで囲む。サーバーサイドではconsole.error()で完全なエラーをログに記録する。ユーザーには「問題が発生しました。もう一度お試しください」というメッセージを送信する。Groq APIエラーは内部詳細を表示せず、ユーザーにとって有益な形で保持する。
- 生成されたコードを確認してください。
try/catchブロックを確認してください。catchでは以下の方法で完全なエラーをログに記録します:
- console.error()(サーバーサイド専用)
- ユーザーへの一般的なメッセージ。
GroqやGemini APIの障害といった既知のエラーについては、代わりに具体的かつ有益なメッセージが表示されます。
5. エラー処理のテスト
すべてのAPIキーにCodepsaceシークレットを使用しているため、コードを直接編集します。
- Groq(またはその他のLLM)APIを呼び出しているサーバーコードを見つけます。
- GROQ_API_KEY(または同等の変数)をGROQ_APIKEY に変更してください。
- AI機能を試してみてください。
- APIが失敗した旨のエラーメッセージが表示されるはずです。スタックトレースは表示されないはずです。
- ターミナルを確認してください。完全なエラーの詳細がそこに記録されているはずです。
- コードをGROQ_API_KEYに戻し、再度動作することを確認してください。
6. 変更をコミットしてデプロイする
- コードスペースで、レート制限とエラー処理の変更を、説明的なメッセージと共にコミットしてください。
- add-securityブランチにプッシュしてください。
- GitHubにアクセスしてください。プルリクエストの作成を促すバナーが表示されるはずです。
- 比較してプルリクエストを作成
- 変更内容を説明するタイトルを追加してください(例:「レート制限と安全なエラー処理の追加」)。
- プルリクエストを作成をクリックしてください。
- 変更内容を確認し、「プルリクエストをマージ」をクリックして確定してください。
- Vercelのダッシュボードに移動してください。新しいデプロイメントが自動的にビルドされているはずです。
7. アプリで確認する
デプロイが完了したら、本番環境のURLで確認してください。
- ログインして、AI機能を通常通りご利用ください。正常に動作するはずです。
- AI機能を20回以上素早くクリックしてください。やがて「リクエストが多すぎます」と表示されるはずです。
- ちょっと待って、もう一度試してみて。正常に動作するはずだよ。
トラブルシューティング
アプリにセキュリティを追加する際に発生する可能性のある問題については、以下を確認してください。各問題をクリックすると、解決方法を確認できます。
レート制限はトリガーされない
ミドルウェアが静的ファイルのルートだけでなく、APIルートにも適用されていることを確認してください。express-rate-limitミドルウェアは、ルートハンドラーの前に追加する必要があります。
express-rate-limit は定義されていません
Codespaceのターミナルで`npm install express-rate-limit`を実行し、更新された`package.json`と`package-lock.json`をプッシュしてください。
レート制限はローカルでは機能するが、Vercelでは機能しない
サーバーレス関数はリクエスト間で再起動する場合があります。レートリミッターは、短時間に集中して送信される大量のリクエスト(連射攻撃)に対しては引き続き機能します。これはMVPにおける想定動作です。
エラーメッセージには依然としてスタックトレースが表示される
キャッチブロックがres.json()に汎用メッセージを送信し、console.error()で完全なエラーをログ出力することを確認してください。他のエラーハンドラーがこれを上書きしていないか確認してください。
アプリの監視
アプリはデプロイされ、セキュリティ対策が施されています。URLを世界に公開する前に、あと2つの作業が必要です:
- ローンチ後の状況を把握できるよう、モニタリングを設定してください
- セキュリティが実際に機能していることを確認してください。単に機能していると仮定してはいけません。
AIコールは通常のAPIリクエストとは異なり、コールごとに課金され、所要時間が変動し、予期せぬ出力を生成する可能性があります。標準的な「リクエスト成功」ログでは、AI応答が有用だったか、ユーザーがどれほど待ったか、コールにどれほどのコストがかかったかといった情報は得られません。構造化ログはこれらの詳細を記録するため、Vercelダッシュボードからこれらの疑問に答えられます。
Vercel ダッシュボード
Vercelダッシュボードは、本番環境におけるアプリのパフォーマンスを把握するための窓口です。vercel.comでプロジェクトに移動し、以下の3つの領域を確認してください。
すべてのデプロイメントはタイムスタンプとステータス(成功または失敗)と共に一覧表示されます。任意のデプロイメントをクリックすると、完全なビルドログを確認できます。デプロイメントの失敗をデバッグする場所です。ビルドが失敗した場合、ログがその理由を示します。
サーバーサイドのログはここにリアルタイムで表示されます。これらはAPIルートへのリクエスト(コンソール出力やエラーを含む)を示します。
ログエントリをクリックすると詳細が表示されます:リクエストURL、レスポンスステータスコード、実行時間。左側のフィルターを使用して、ステータスコード(500エラーをすべて検索)、ルート(AIリクエストのみを表示)、または時間範囲で絞り込みます。
「ライブ」トグルをクリックすると、ログをリアルタイムでストリーミング表示できます。アプリをテスト中にクリック操作とサーバー側の動作を同時に確認したい場合に便利です。
ログの保持期間:2026年2月現在、Hobby(無料)プランでは実行時ログは約1時間保持されます。テストやデバッグには十分な期間ですが、翌日まで残ることはありません。AI機能をテストした後は、速やかに「ログ」タブを確認してください。
可観測性セクションは個々のログを超え、すべてのリクエストにわたるパターンを示します。どのルートが最も遅いか、どのルートが最も高いエラー率を示しているか、そして関数のパフォーマンスが時間とともにどのように変化するかを確認できます。
このタブは、無料のホビープランを含むすべてのプランで利用可能です。
Observability ProおよびPlusプランではカスタムクエリと異常アラートが利用可能になります。
MVPには必要ありません。デフォルトのビューで十分です。
Vercelは、可観測性のために以下のイベントタイプを追跡します:
- エッジリクエスト
- Vercel関数呼び出し
- 外部APIリクエスト
- ミドルウェア呼び出しのルーティング
- AIゲートウェイリクエスト
アクティビティ5
監視、検証、そして起動
所要時間:25分
1. 新しいブランチとコードスペースを作成する
- GitHubにアクセスし、MVPリポジトリに移動してください
- リポジトリの左上にあるメインのドロップダウンをクリックし、すべてのブランチを表示します。
- 新しいブランチを作成する。
- 任意の名前を付けられます:add-monitoring(または別の説明的な名前)。
- このブランチ用の新しいCodespaceを作成し、開きます。
2. AIルートにタイミングラッパーを追加する
本番環境でのAIコールについてまず知りたいのは、その所要時間です。ユーザーが15秒待たされると、アプリが故障していると誤解する可能性があります。
コパイロットにタイミングラッパーの追加を手伝ってもらう
Express.jsのAIルートに監視を追加したい。
本番環境における各Groq API呼び出しの所要時間を追跡したい。
私のAIルートは[index.js]にあり、Groq APIを呼び出します。Vercelにデプロイしています。
AI呼び出しの前後にDate.now()を記録する。応答時間をミリ秒単位で計算する。ルート名を含めてconsole.log()でログ出力する。
3. Codespaceにおけるテストタイミングのログ記録
- Codespacesでアプリを起動し、AIコールをトリガーします。
- ターミナルの出力で応答時間ログを確認してください。
- まだデプロイしないでください。次のステップでログを追加し、一度だけデプロイします。
4. 構造化JSONロギングへの拡張
タイミングコードを拡張して全体像を捕捉しましょう。構造化ログはJSON形式を使用するため、Vercelのダッシュボードで検索やフィルタリングが可能です。必要なコードを生成するようCopilotに指示してください。
基本的な console.log を、Vercel のダッシュボードで検索可能な構造化された JSON ログに置き換える。
Groq API呼び出しの応答時間を計測するタイミングラッパーは既に用意済みです。
AI呼び出しごとに1つのJSONオブジェクトをコンソール出力(`console.log(JSON.stringify(data))`)で記録する。記録項目:
タイムスタンプ(ISO形式)
アクション名
inputLength(文字数、内容ではない)
responseTime(ミリ秒)
success(true/false)
error(エラーメッセージまたはnull)
例(TutorMatch向け):
生徒が家庭教師の推薦を検索すると、ログは以下のような内容になる可能性があります。アプリによってアクション名は異なります。AI機能の動作に合わせて適宜調整してください。
{
"timestamp": "2026-02-16T14:32:01Z",
"action": "get_tutor_recommendations",
"inputLength": 145,
"responseTime": 2340,
"success": true,
"error": null
}
各フィールドは特定の目的を果たします:
- タイムスタンプ– ユーザーから報告された問題(「午後3時に壊れた」)とログ上の事象を関連付けることができます
- アクション– どのAI機能が最も使用され、どの機能が無視されているかを示す
- inputLength– 異常なほど大きな入力は不正利用を示唆する可能性があります。ログ記録は内容ではなく長さを対象とし、ユーザーのプライバシーを保護します
- 応答時間– ユーザーからの苦情が発生する前にパフォーマンスの問題を発見するのに役立ちます。10秒を超える時間が継続的に発生している場合は注意が必要です
- 成功– AIの失敗率を一目で確認できます。5%が正常、50%は危機的状況です
- エラー– 呼び出しが失敗した場合、エラーメッセージは問題を再現する必要なくその理由を伝えます
5. 拡張ログのテスト
- Codespaceでアプリを再度実行してください。
- AIコールをトリガーする。
- ターミナルでJSONログを確認してください。
6. 変更をコミットしてデプロイする
タイミング変更と構造化ロギング変更の両方をまとめてコミットしデプロイしてください:
- 説明的なメッセージと共にロギングの変更をコミットしてください。
- 追加監視ブランチにプッシュしてください。
- GitHubにアクセスしてください。プルリクエストの作成を促すバナーが表示されるはずです。
- 比較してプルリクエストを作成
- 変更内容を説明するタイトルを追加してください。
- プルリクエストを作成をクリックしてください。
- 変更内容を確認し、「プルリクエストをマージ」をクリックして確定してください。
- Vercelダッシュボードに移動し、[Deployments]タブで新しいデプロイが開始されていることを確認してください。
- デプロイが完了したら、本番アプリを開き、ログインして、2~3回のAI呼び出しを実行してください。
- Vercel → ログに移動し、構造化されたJSONエントリを探してください
- タイムスタンプ、アクション、応答時間、および成功フィールドが正しく表示されることを確認してください
- 各ログエントリは行として表示されます。矢印をクリックして展開し、JSONフィールドを確認してください。
- JSONの代わりに[Object object]が表示される場合は、console . log(logData)の代わりにconsole.log( JSON.stringify(logData))を使用するようにコードを更新してください。
無料プランではログは約1時間しか利用できないため、テスト後すぐに確認してください。
7. Web解析を有効にする
Vercelはページビューや訪問者データを追跡する無料のWeb解析ツールを提供しています。設定は数分で完了し、プロジェクト提案時に参照できる実際の訪問者メトリクスを提供します。
- Vercelプロジェクトのダッシュボードに移動してください
- アナリティクスタブをクリックしてください。
- Web Analyticsを有効にするをクリックしてください。
7. Codespaceにアナリティクスを追加する
- 追加監視ブランチが残っている場合は、関連するコードスペースを開いてください。そうでない場合は、リポジトリ用の新しいブランチを作成し、新しいコードスペースを開いてください。
- コードスペースで、ターミナルで `npm install @vercel/analytics` を実行してアナリティクスパッケージをインストールしてください。
- アプリに分析コンポーネントを追加してください。
- もしあなたが使用しているなら React または Next.js
- App.jsx に次のインポートを追加:import { Analytics } from '@vercel/analytics/react'
- Add <Analytics /> as a component inside your App.jsx return, typically just before the closing tag.
- プレーンなHTML/JSアプリの場合、Vercelが「
Commitを 有効にする」をクリックした後に表示する指示に従ってください。
- もしあなたが使用しているなら React または Next.js
- 変更をコミット、プッシュ、マージしてください。次のデプロイメントでデータ収集が開始されます。
注意:ダッシュボードでアナリティクスを有効にするだけでは不十分です。データが流れるようにするには、コード内に@vercel/analytics パッケージも 必要です。手順 3 と 4 を省略すると、アナリティクスタブは空のままになります。
ホビープランでは、月額2,500イベントまで無料で利用可能です(2026年2月現在)。これは最小限の機能(MVP)を実現するには十分な数です。設定後、アプリへの訪問者数、閲覧ページ、訪問元の情報を確認できます。
8. DevToolsでセキュリティを確認する
開発者ツールを使用して、本番環境のアプリが実際に安全であることを確認してください。安全だと決めつけないでください。
- デプロイしたアプリ(.vercel.app URL、Codespaceではありません)をブラウザで開いてください。
- F12キーを押して開発者ツールを開く(または右クリックして「要素を検査」を選択)。
- ネットワークタブに切り替えます。
- ネットワークログをクリア(クリアアイコンをクリック)。
- アプリにログインして、AI機能をご利用ください。
- ネットワークリクエストが表示されるのを見てください。
以下の各項目を点検してください。これらは、デプロイされたすべてのアプリが通過すべき3つのセキュリティチェックです。
チェック1: APIキーは隠されていますか?
AI機能を起動するリクエストをクリックしてください。
- リクエストURLは、お客様のバックエンド(https://your-app.vercel.app/api/ai-query)に送信される必要があります。api.groq.comや外部APIに直接送信しないでください。直接送信した場合、フロントエンドがAI APIを直接呼び出している状態となり、APIキーが漏洩する可能性があります。
- [ヘッダー]タブをクリックし、リクエストヘッダーを確認してください。Groq APIキーはどのヘッダーにも表示されてはいけません。バックエンドがサーバーサイドで外部呼び出しを行います。ブラウザがキーを認識することはありません。
- URLのクエリパラメータを確認してください。URLに「?key=AIza…」が含まれてはいけません。
APIキーがブラウザリクエストのどこかに表示されている場合、 停止してください。キーが公開されており、サイトを調査する誰でもそれを盗むことができます。コードに戻り、すべての外部API呼び出しがサーバー側で行われることを確認してください。
チェック2: 認証トークンは送信されていますか?
同じリクエストについて、再度リクエストヘッダーを確認してください。以下が表示されるはずです:
認証: Bearer eyJhbGciOiJIUzI1NiIs…
これはフロントエンドが送信するSupabaseのセッショントークンです。リクエストがログイン済みユーザーから送信されたことを証明します。長い文字列はJSON Web Token(JWT)であり、認証情報を安全に伝送するための標準フォーマットです。
Authorizationヘッダーが欠落している場合、認証コードを確認し、フロントエンドがgetSession()を呼び出し、各APIリクエストにトークンを含めていることを確認してください。
チェック3:レート制限は本番環境で機能しているか?
- ネットワークタブで開発者ツールを開いたままにしておく。
- AI機能ボタンを10回以上素早くクリックしてください。
- ネットワークタブを確認してください:最初の数リクエストはステータス200(成功)を返すはずです。
- 制限に達した場合、リクエストはステータス429(リクエストが多すぎます)を返す必要があります。
- アプリは「リクエストが多すぎます。しばらくお待ちください。」というメッセージを表示する必要があります。
20件以上のリクエスト全てがレート制限なしで200を返す場合、リクエスト間でサーバーレス関数が再起動した可能性があります。クリック速度を速めてください。レート制限は連続した高速リクエストに対して最も効果を発揮します。MVP(最小限の機能を持つ製品)においては、このレベルの保護が適切です。
生産コストの見直し
アプリは無料プランに制限があるサービスを利用しています。制限を把握することで予期せぬ請求を防げます。
利用可能な場合は請求アラートを設定してください。一部の無料プランでは、有料プランに移行するまでアラートを設定できません。
Vercel
無料プラン – 100GBの帯域幅、4時間のアクティブCPU、月間100万回の関数呼び出し
コスト – 帯域幅または機能制限を超過した場合
確認場所 – Vercelダッシュボード → 使用状況
請求アラート – プロジェクト → 設定 → 使用状況。ホビーティアの制限を確認してください。制限に近づくとVercelから通知が届きます。
Supabase
無料プラン – 500MBのデータベース、1GBのファイルストレージ、月間50,000人のアクティブユーザー
コスト – ストレージまたはユーザー制限を超過した場合
確認場所 – Supabaseダッシュボード → 設定 → 請求
請求アラート –設定 → 請求に移動してください。データベースとストレージの使用量アラートを設定します。
Groq API
無料プラン – レート制限付きの無料プラン(モデルによって異なります)
コスト – 無料枠を超える大量のAPI呼び出し
確認場所 – Groqダッシュボード → 利用状況
請求アラート – Groqコンソールで、設定 → 請求 → 制限 に移動してください。
ローンチ前チェックリスト
アプリを公開する前に、このチェックリストを確認してください。内容は3つのグループに分かれています:アプリは正常に動作するか、安全か、公開後の状況を把握できるか。
✅ 動作しますか?
- ライブURLは正しく読み込まれます
- ログインとサインアップ機能(アカウント作成、ログイン、ログアウト)
- AI機能はログイン後に本番環境で動作します
- アプリは別のデバイスやブラウザで動作します(チームメイトとURLを共有して再確認してください)
✅ 安全ですか?
- APIキーはDevToolsのネットワークタブには表示されません
- APIリクエストにAuthorizationヘッダーが含まれています
- 高速リクエスト後のレート制限トリガー
- 環境変数はVercelで設定され、コードにハードコードされるものではありません
✅ 何が起きているか分かりますか?
- 構造化されたJSONログは、AI呼び出しをトリガーした際にVercelのログタブに表示されます
- ウェブ解析機能有効
- Vercel、Supabase、Groqのコストダッシュボードを確認済み
いずれかの項目が失敗した場合、URLを共有する前に修正してください。
すべての項目が合格した場合、アプリは共有可能な状態です。
トラブルシューティング
ログがVercelに表示されていません
サーバーサイドのAPIルートでは、必ずconsole.log()を使用してください。クライアントサイドのコードでは使用しないでください。クライアントサイドのログはブラウザに表示され、Vercelには表示されません。
構造化ログは [オブジェクト オブジェクト] の形式で表示されます
console.log (logData)の代わりにconsole.log( JSON.stringify( logData ) )を使用してください。
AIコールは本番環境では遅い
ログの応答時間を確認してください。10秒を超える場合が継続的に発生しているなら、読み込み中のメッセージの追加とリクエストの分割を検討してください。
Vercel関数がタイムアウトしました
Fluid Compute(新規プロジェクトではデフォルトで有効)を使用すると、Hobbyプランでは関数を最大300秒(5分)実行できます。Fluid Computeを使用しない場合、制限は60秒です。AI呼び出しがタイムアウトする場合は、ユーザー向けにローディングインジケーターとタイムアウトメッセージを追加してください。
APIキーがブラウザのリクエストに表示される
フロントエンドがバックエンドを経由せずに外部APIを直接呼び出しています。フロントエンドを更新し、Expressルート(例: /api/ai-query)を呼び出すようにしてください。
ウェブ解析ツールでデータが表示されない
データは次のデプロイと数回のページ訪問後に表示されます。有効化後、サイトにアクセスしてから数分お待ちください。
アプリはyour-app-name.vercel.app で公開中です。これはコンテストやユーザーテスト、ピッチには有効です。しかし、アプリを本格的なビジネスとして感じさせたいなら、カスタムドメインが違いを生みます。tutormatch.app は tutormatch-mvp.vercel.appでは伝えられないプロフェッショナリズムを伝えます。
Vercelの無料プランでは、追加料金なしでカスタムドメインをサポートします(プロジェクトあたり最大50個、自動HTTPS対応)。費用がかかるのはドメイン名そのもののみです。
アクティビティ6
(オプション) - カスタムドメインを接続する
所要時間:15分
1. ドメイン名を取得する
以下のいずれかのオプションを選択して、ご自身のドメインを取得してください。
オプション
費用
プロセス
GitHub 学生開発者パック
ドメイン登録業者
学校用メールアドレスをお持ちの場合、GitHubアカウントで登録できます。教育向けGitHub Packは education.github.com/pack からお申し込みください。Namecheap (.me) やName.com(.live, .studio, .app, .dev など20種類以上) の無料ドメイン、および .tech ドメインが含まれます。
GitHub 学生開発者パック
年間10~15米ドル
Namecheap、Cloudflare、またはGoogle Domainsから購入してください。価格は拡張子によって異なります。.comは.siteや.techよりも高くなります。
Namecheap、Cloudflare、またはGoogle Domainsから購入してください。価格は拡張子によって異なります。.comは.siteや.techよりも高くなります。
~年間10~20米ドル
Vercelダッシュボード(設定 → ドメイン)から直接検索・購入できます。Vercelが自動的にDNSを設定します。有料でも構わない場合、最も簡単な選択肢です。
2. ドメインをVercelに接続する
- Vercelプロジェクトに移動 →設定→ドメイン
- 「ドメインを追加」をクリックし、ドメイン名(例:tutormatch.app)を入力してください
- Vercelは必要なDNSレコードを表示します。以下のいずれかが表示されます:
- VercelのIPアドレスを指すAレコード(tutormatch.appのようなルートドメイン用)。
- cname.vercel-dns.com を指すCNAME レコード(www.tutormatch.app などのサブドメイン用)。
- ドメイン登録業者のDNS設定に移動し、Vercelが提供したレコードを追加してください。
- DNSの伝播を待ちます。通常は30分未満ですが、最大48時間かかる場合があります。
3. Supabase認証設定を更新する
この手順を飛ばさないでください。飛ばすと、カスタムドメインでのログインが機能しなくなります。
- Supabaseダッシュボード → 認証 → URL設定 に移動してください。
- カスタムドメインURL(例:https://tutormatch.app)を、サイトURLと リダイレクトURLの両方に追加してください。
- .vercel.app の URL もリストに含めておいてください。バックアップとしてまだ機能します。
4. すべてが正常に動作することを確認する
- ブラウザでカスタムドメインにアクセスしてください。アプリはHTTPSで読み込まれるはずです(鍵のアイコンを確認してください)。
- ログインを試みてください。もしCodespacesのURLまたは.vercel.appのURLにリダイレクトされる場合は、ステップ3を完了していません。
- AI機能(およびその他のAPI統合)をテストし、エンドツーエンドで全てが正常に動作することを確認してください。
トラブルシューティング
ドメインに「DNSが設定されていません」と表示されます
レジストラのDNS設定でAレコードまたはCNAMEレコードを再確認してください。Vercelから正確に値をコピーしたことを確認してください。
SSL証明書が機能していません
待ってください。VercelはDNSの伝播が完了すると自動的にSSLをプロビジョニングしますが、これには最大1時間かかる場合があります。
ログイン時に誤ったURLへリダイレクトされる
Supabase認証のリダイレクトURLを更新し、カスタムドメインを含めてください。リストには.vercel.appとカスタムドメインの両方のURLを保持してください。
リフレクション
さあ、やり遂げましたね!アプリがデプロイされ、公開されました!おめでとうございます!少し時間を取って、以下の質問について考えてみてください:
Monitoring
The Journey
次のステップ
主要用語
- デプロイ:アプリをインターネット上で恒久的なURLで利用可能にすること。プレビューリンクとは異なり、デプロイされたアプリはコンピュータの電源が切れていても稼働し続けます。
- 本番環境:実際のユーザーが操作するアプリの稼働版。コードの記述やテストを行う開発環境とは対照的な環境。
- 環境変数(本番環境):APIキーとシークレットはコード内ではなく、ホスティングプラットフォームの設定に保存します。Vercelでは、プロジェクトダッシュボードで設定します。
- 自動デプロイ:GitHubのメインブランチにコードをプッシュするたびに、Vercelが自動的にアプリを再ビルドし、再デプロイします。
- レート制限:ユーザーが一定期間内に送信できるリクエスト数を制限すること。不正利用を防止し、APIコストを管理します。
- 安全なエラー処理:ユーザーには汎用的で分かりやすいエラーメッセージを返しつつ、サーバー側では完全な技術的詳細を記録する。これにより、内部情報が潜在的な攻撃者に晒されるのを防ぎます。
- 構造化ロギング:アプリ内のイベントをプレーンテキストではなく、整理されたJSONデータとして記録します。本番環境で発生した事象の検索、フィルタリング、分析を可能にします。
- 可観測性:ログ、メトリクス、監視ダッシュボードを通じて、外部から実行中のアプリケーション内部で何が起きているかを把握する能力。
- サーバーレス関数:サーバーを管理することなく、リクエストに応じてオンデマンドで実行されるバックエンドコードです。VercelはExpress.js APIルートを自動的にサーバーレス関数に変換します。
- カスタムドメイン:所有する独自のウェブアドレス(例:tutormatch.app)で、デフォルトの.vercel.app URLに代わり、Vercelデプロイ先を指すように設定します。
- DNS(ドメインネームシステム):ドメイン名(例:tutormatch.app)を、コンピューターがサーバーを見つけるために使用するIPアドレスに変換するシステムです。カスタムドメインを接続する際には、DNSレコードを設定してVercelを指すようにします。
その他のリソース
展開
- Vercel ドキュメント: はじめに、環境変数、デプロイ設定
- Vercel 環境変数ガイド:本番環境向けシークレットの設定方法
- カスタムドメインの追加: Vercelプロジェクトに独自のドメインを接続する
セキュリティ
- express-rate-limit: Express.js用レート制限ミドルウェア
- Vercel Firewall ドキュメント: 組み込みの DDoS および WAF 保護機能
監視
- Vercel ランタイムログ:関数ログとランタイム出力の理解
- Vercel Observability: パフォーマンスとエラーを監視するためのダッシュボード
- Vercel Web Analytics: ページビューと訪問者データを追跡
コスト管理
- Groq API: APIの価格設定
- Supabaseの料金プラン:無料プランの詳細と制限事項
- Vercelの料金プラン:無料プランの詳細と制限事項
