【モダン開発】Cursor・Vercel・Supabaseで爆速ビルドするClaude 3.5 Sonnet搭載AIアプリ構築ガイド

現在のWebアプリケーション開発は、「AIにコードを書かせ、強力なマネージドサービスを組み合わせて即座にデプロイする」という時代に突入しています。その中心にあるのが、AIネイティブなコードエディターCursor、高速なフロントエンド配信プラットフォームVercel、そして高機能なBaaSであるSupabaseの3つです。

本記事では、これらのモダンな開発ツール群と、最高峰のLLMであるClaude 3.5 Sonnetを組み合わせ、実用的なAIアプリケーションを最短で構築する手順を、具体的なソースコードを交えて徹底的に解説します。


1. システムアーキテクチャと使用ツール

今回構築するアプリケーションは、ユーザーの入力に対してClaude 3.5 Sonnetがリアルタイムに回答を生成し、その履歴をデータベースに保存する「AIチャット・アシスタント」です。アーキテクチャの概要は以下の通りです。

  • フロントエンド / API: Next.js (App Router) + Tailwind CSS
  • AIモデル: Claude 3.5 Sonnet (Anthropic Claude API)
  • データベース: Supabase (PostgreSQL / Row Level Security対応)
  • エディター: Cursor (Composer機能をフル活用)
  • ホスティング: Vercel

Next.jsの公式ドキュメントやベストプラクティスについては、Next.js 公式ドキュメントを適宜参照してください。


2. Supabaseのセットアップとデータベース設計

まずはデータの保存先となるSupabaseのプロジェクトを作成し、データベースの準備を行います。Supabase 公式ドキュメントに沿って、アカウント作成と新規プロジェクトの作成を完了させてください。

2.1. テーブルの作成

プロジェクトが作成できたら、SQL Editorを開き、チャット履歴を保存するための chats テーブルを作成します。以下のSQLを実行してください。

-- チャット履歴を格納するテーブル
create table chats (
  id uuid default gen_random_uuid() primary key,
  user_message text not null,
  ai_response text not null,
  created_at timestamp with time zone default timezone('utc'::text, now()) not null
);

-- セキュリティ用のRow Level Security (RLS)を有効化
alter table chats enable row level security;

-- 簡易的な読み書きポリシー(本番環境では認証ユーザーのみにするなどの制限を推奨)
create policy "Allow public read and write access" on chats
  for all using (true) with check (true);

SQLの実行が完了すると、chats テーブルがデータベース内に構築されます。


3. CursorとClaude 3.5 Sonnetを活用したNext.jsアプリ開発

次に、Cursorを開き、Next.jsプロジェクトをセットアップします。Cursorは、エディター自体にClaude 3.5 Sonnetが組み込まれており、チャット(Ctrl+K または Cmd+K)やComposer(Ctrl+I または Cmd+I)を使って指示を出すだけで、ファイル生成から修正まで自動で行ってくれます。

3.1. プロジェクトの初期化とライブラリ導入

任意のディレクトリで以下のコマンドを実行し、Next.jsアプリを作成します。

npx create-next-app@latest ai-chat-app --typescript --tailwind --app
cd ai-chat-app

次に、必要なパッケージ(SupabaseクライアントとAnthropic SDK)をインストールします。

npm install @supabase/supabase-js @anthropic-ai/sdk

3.2. Supabaseクライアントの設定

Cursorで lib/supabaseClient.ts を新規作成し、以下のコードを記述します。Cursorのチャットに「Supabaseクライアントを初期化するコードを書いて」と指示するだけで、即座に以下と同等のコードが出力されます。

import { createClient } from '@supabase/supabase-js';

const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL || '';
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || '';

if (!supabaseUrl || !supabaseAnonKey) {
  console.warn('Supabase env variables are missing!');
}

export const supabase = createClient(supabaseUrl, supabaseAnonKey);

3.3. Claude 3.5 Sonnetを呼び出すAPI Routeの実装

Next.jsのRoute Handlerを使って、フロントエンドからのリクエストを受け取り、Claude 3.5 Sonnetを呼び出して結果をSupabaseに保存するAPIを作成します。

app/api/chat/route.ts を作成し、以下のコードを記述します。

import { NextResponse } from 'next/server';
import Anthropic from '@anthropic-ai/sdk';
import { supabase } from '@/lib/supabaseClient';

const anthropic = new Anthropic({
  apiKey: process.env.ANTHROPIC_API_KEY || '',
});

export async function POST(request: Request) {
  try {
    const { message } = await request.json();

    if (!message) {
      return NextResponse.json({ error: 'Message is required' }, { status: 400 });
    }

    // 1. Claude 3.5 Sonnet API を呼び出し
    const response = await anthropic.messages.create({
      model: 'claude-3-5-sonnet-20240620',
      max_tokens: 1024,
      messages: [{ role: 'user', content: message }],
    });

    // 安全にレスポンスのテキストを取り出す
    const aiResponseText = response.content[0].type === 'text' 
      ? response.content[0].text 
      : '応答の取得に失敗しました。';

    // 2. 結果をSupabaseに保存
    const { error: dbError } = await supabase
      .from('chats')
      .insert([{ user_message: message, ai_response: aiResponseText }]);

    if (dbError) {
      console.error('Database save error:', dbError);
      // DB保存失敗でもAI応答は返すためにエラーはスローしない
    }

    return NextResponse.json({ response: aiResponseText });
  } catch (error: any) {
    console.error('API Error:', error);
    return NextResponse.json({ error: error.message || 'Internal Server Error' }, { status: 500 });
  }
}

3.4. フロントエンド(UI)の実装

app/page.tsx を修正し、簡単なチャットUIを構築します。この時も、CursorのComposer機能で「入力フォームがあり、回答をストックし、過去のチャット履歴もSupabaseから取得して表示する美しい Tailwind CSS のUIを作って」と依頼すれば、Claude 3.5 Sonnetが完璧なコードを瞬時に出力してくれます。

'use client';

import { useState, useEffect } from 'react';
import { supabase } from '@/lib/supabaseClient';

export default function Home() {
  const [message, setMessage] = useState('');
  const [loading, setLoading] = useState(false);
  const [history, setHistory] = useState<any[]>([]);

  // 履歴の読み込み
  const fetchHistory = async () => {
    const { data, error } = await supabase
      .from('chats')
      .select('*')
      .order('created_at', { ascending: false });
    if (!error && data) {
      setHistory(data);
    }
  };

  useEffect(() => {
    fetchHistory();
  }, []);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!message.trim()) return;

    setLoading(true);
    try {
      const res = await fetch('/api/chat', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ message }),
      });
      const data = await res.json();
      if (data.response) {
        setMessage('');
        fetchHistory(); // 履歴を再ロード
      } else {
        alert('エラーが発生しました: ' + data.error);
      }
    } catch (err) {
      console.error(err);
    } finally {
      setLoading(false);
    }
  };

  return (
    <main className="max-w-3xl mx-auto p-6">
      <h1 className="text-3xl font-bold mb-6 text-center text-gray-800">Claude 3.5 Chat App</h1>
      
      <form onSubmit={handleSubmit} className="mb-8 flex gap-2">
        <input
          type="text"
          className="border rounded p-3 w-full focus:outline-none focus:ring-2 focus:ring-blue-500 text-black"
          placeholder="AIに質問する..."
          value={message}
          onChange={(e) => setMessage(e.target.value)}
          disabled={loading}
        />
        <button
          type="submit"
          className="bg-blue-600 text-white px-6 py-3 rounded hover:bg-blue-700 transition disabled:bg-blue-300"
          disabled={loading}
        >
          {loading ? '送信中...' : '送信'}
        </button>
      </form>

      <div className="space-y-4">
        <h2 className="text-xl font-semibold border-b pb-2 text-gray-700">チャット履歴</h2>
        {history.length === 0 ? (
          <p className="text-gray-500 text-center py-4">履歴はありません</p>
        ) : (
          history.map((item) => (
            <div key={item.id} className="p-4 bg-gray-50 rounded-lg shadow-sm border border-gray-100">
              <p className="font-bold text-blue-600">Q: {item.user_message}</p>
              <p className="mt-2 text-gray-800 whitespace-pre-wrap">A: {item.ai_response}</p>
            </div>
          ))
        )}
      </div>
    </main>
  );
}

4. 開発をさらに強化するインフラの選択肢

今回はフロントエンドと簡単なバックエンドAPIをVercelに集約してデプロイしますが、システムが拡大するにつれて、長時間の非同期ジョブ、定期的なスクレイピング、バックグラウンドでのAIエージェントの常時駆動などが必要になってきます。

そのような場合は、Vercelのサーバーレス関数の実行制限(タイムアウト)を回避するため、専用のVPS上でDockerや自作AIエージェントをデプロイ・稼働させるアプローチが非常に有効です。

ConoHa WINGでブログを立ち上げる

⚡ 初期費用無料・ドメインが2個無料

例えば、ConoHa VPSなどの高速でスケールしやすい仮想専用サーバーを活用すれば、自作のエージェントプログラムを24時間低コストで安定運用させることができます。詳しいVPS上での常時稼働エージェント構築手順については、以下の記事も参考にしてください。


5. Vercelへのデプロイと環境変数の設定

開発したNext.jsプロジェクトをGitHubにプッシュし、Vercelと連携させます。

  1. GitHubリポジトリを作成し、ローカルコードをコミット&プッシュします。
  2. Vercelにログインし、「Add New」>「Project」から該当のGitHubリポジトリを選択します。
  3. Environment Variables(環境変数) に、以下の3つの変数を追加します。
    • NEXT_PUBLIC_SUPABASE_URL: SupabaseのProject URL
    • NEXT_PUBLIC_SUPABASE_ANON_KEY: SupabaseのAPIキー(anon / public)
    • ANTHROPIC_API_KEY: Anthropicのダッシュボードから取得したClaude APIキー
  4. 「Deploy」ボタンをクリックすれば、わずか数分でインターネット上に独自のAIアプリが公開されます。

6. よくあるエラーとトラブルシューティング

CursorやVercelを用いた開発において、初学者が直面しやすい代表的なエラーと解決策を解説します。

6.1. SupabaseのRLSによる「New row violates row-level security policy」エラー

  • 原因: SupabaseのテーブルでRow Level Security(RLS)が有効化されているにもかかわらず、データを挿入するための適切な「ポリシー(Policy)」が設定されていない場合に発生します。
  • 解決方法: Supabaseの管理画面(Dashboard) -> Database -> Policies に移動し、chats テーブルに対して「挿入(Insert)」「参照(Select)」を許可するポリシーが正しく作成されているか確認してください。開発段階では、すべてのユーザー(Public)に対して許可する設定を追加することで解消できます(本番環境では適切に制限してください)。

6.2. Vercelでのデプロイ時の「TypeScript Error (Build Failed)」

  • 原因: Cursorが自動生成したコードの中で、型定義が曖昧な部分(例: any 型の多用や、環境変数が undefined になる可能性の考慮漏れ)があり、Next.jsのビルドプロセスでTypeScriptのチェックに引っかかるためです。
  • 解決方法: 環境変数を読み込む部分で || '' のようにデフォルトの空文字列を設定するか、next.config.js でビルド時のTSチェックを一時的にバイパスさせる(非推奨)か、Cursorに「TypeScriptの型エラーが出ているので修正して」と該当ファイルを渡して修正指示を出すことで解決します。

6.3. APIの「504 Gateway Timeout」エラー(Vercel)

  • 原因: Vercelの無料プラン(Hobby)では、サーバーレス関数の実行制限時間が最大10秒に制限されています。Claude 3.5 Sonnetの応答生成がこの10秒を超えると、Vercel側からタイムアウトエラーが返されます。
  • 解決方法: Next.jsのRoute Handlerで Streaming(ストリーミングレスポンス) を実装するか、長時間の処理が避けられない場合は前述のようにVercelの関数ではなくVPS等の常時稼働サーバーへバックエンドをオフロードすることを検討してください。

7. まとめ

Cursor、Vercel、Supabase、そしてClaude 3.5 Sonnetの組み合わせは、個人開発者からスタートアップのプロトタイピングまで、現代における最も強力かつ高速な開発スタックの1つです。

Cursorを使うことでコーディングの摩擦は極限まで減少し、Supabaseによってバックエンドの実装コストがほぼゼロになり、Vercelがデプロイと運用の手間を最小化してくれます。ぜひこのスタックを活用し、あなたのアイデアを形にしてみてください!