以下のセットアップが完了しています:
- Next.js 15 + TypeScript + Tailwind CSS
- App Router構成
- ESLint設定
{
"@supabase/supabase-js": "^2.86.2",
"@supabase/ssr": "^0.6.0",
"@google/generative-ai": "^0.24.1"
}.env.local.example- 共有用テンプレート.env.local- 実際の設定ファイル(要編集)
supabase/schema.sql- generations テーブル定義
lib/supabase/client.ts- クライアント用lib/supabase/server.ts- サーバー用lib/supabase/middleware.ts- middleware用middleware.ts- Next.js middleware設定
types/database.ts- データベーススキーマの型定義
lib/gemini/client.ts- 画像生成用クライアント
.env.localファイルを編集して、実際の値を設定してください:
# 1. Supabaseプロジェクトを作成
# https://supabase.com/dashboard
# 2. Project Settings → API から取得
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key-here
# 3. Google AI Studio でAPIキーを取得
# https://makersuite.google.com/app/apikey
GEMINI_API_KEY=your-gemini-api-key-here
# 4. (オプション) 使用するモデルを指定
GEMINI_MODEL=gemini-2.0-flash-exp- Supabaseダッシュボードにログイン
- SQL Editorを開く
supabase/schema.sqlの内容を貼り付けて実行
npm run devブラウザで http://localhost:3000 を開いて確認
基本的なページが表示されればセットアップ完了です!
visual-echo/
├── app/ # Next.js App Router
│ ├── layout.tsx # ルートレイアウト
│ ├── page.tsx # ホームページ
│ └── globals.css # グローバルスタイル
├── lib/ # ユーティリティ
│ ├── supabase/ # Supabaseクライアント
│ │ ├── client.ts # クライアント用
│ │ ├── server.ts # サーバー用
│ │ └── middleware.ts # middleware用
│ └── gemini/ # Gemini API
│ └── client.ts # 画像生成クライアント
├── types/ # TypeScript型定義
│ └── database.ts # データベーススキーマ型
├── supabase/ # Supabaseスキーマ
│ └── schema.sql # テーブル定義
├── middleware.ts # Next.js middleware
└── .env.local # 環境変数(要設定)
| カテゴリ | 技術 | バージョン |
|---|---|---|
| Framework | Next.js | 15.1.0 |
| Language | TypeScript | 5.x |
| UI | Tailwind CSS | 3.4.x |
| Database | Supabase (PostgreSQL) | - |
| AI | Google Gemini API | 2.0 |
- Server Components: デフォルト。
lib/supabase/server.tsを使用 - Client Components:
'use client'を追加。lib/supabase/client.tsを使用
全てのSupabaseクエリで型推論が効きます:
import { createClient } from '@/lib/supabase/server';
const supabase = await createClient();
// 型安全なクエリ
const { data, error } = await supabase
.from('generations')
.select('*')
.eq('status', 'completed'); // 型チェックされます