Turborepo + Next.js(App Router) + Turso + Drizzle + Better Auth + Stripe のモノレポテンプレート。
📚 クイックスタート: すぐに始めたい方は QUICKSTART.md をご覧ください。
- 🏗️ Turborepo: モノレポ管理とタスクオーケストレーション
- ⚡ Next.js 15 + Turbopack: 高速な開発体験
- 💾 Turso + Drizzle ORM: エッジ対応のSQLiteデータベース
- 🔐 Better Auth: Email/Password + OAuth(Google/GitHub)認証
- 💳 Stripe: サブスクリプション + 都度課金
- 🎨 shadcn/ui: モダンなUIコンポーネント
- 📦 pnpm: 高速で効率的なパッケージ管理
template-turso-mono/
├── apps/
│ └── web/ # Next.jsアプリケーション
├── packages/
│ ├── db/ # Turso + Drizzle(スキーマ、マイグレーション)
│ ├── auth/ # Better Auth設定
│ ├── stripe/ # Stripe決済ロジック
│ ├── ui/ # 共有UIコンポーネント(shadcn/ui)
│ ├── eslint-config/ # 共有ESLint設定
│ └── typescript-config/# 共有TypeScript設定
└── turbo.json # Turborepo設定
pnpm install# Turso CLIのインストール
curl -sSfL https://get.tur.so/install.sh | bash
# データベース作成
turso db create template-turso-mono
# データベース情報取得
turso db show template-turso-mono
# 認証トークン作成
turso db tokens create template-turso-mono.env.example をコピーして .env.local を作成し、必要な値を設定します。
# ルートディレクトリ
cp .env.example .env.local
# apps/web
cp apps/web/.env.example apps/web/.env.local
# packages/db
cp packages/db/.env.example packages/db/.env.localTurso:
TURSO_DATABASE_URL: TursoデータベースのエンドポイントTURSO_AUTH_TOKEN: Turso認証トークン
Better Auth:
AUTH_SECRET: 32文字以上のランダムな文字列(openssl rand -base64 32で生成)NEXT_PUBLIC_APP_URL: アプリケーションのURL(開発時はhttp://localhost:3000)
Stripe:
STRIPE_SECRET_KEY: StripeシークレットキーSTRIPE_WEBHOOK_SECRET: Stripe WebhookシークレットNEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: Stripe公開可能キーNEXT_PUBLIC_STRIPE_PRICE_ID_MONTHLY: 月額プランの価格IDNEXT_PUBLIC_STRIPE_PRICE_ID_YEARLY: 年額プランの価格IDNEXT_PUBLIC_STRIPE_PRICE_ID_ONETIME: 都度課金の価格ID
OAuth(オプション):
OAUTH_GOOGLE_CLIENT_ID/OAUTH_GOOGLE_CLIENT_SECRETOAUTH_GITHUB_CLIENT_ID/OAUTH_GITHUB_CLIENT_SECRET
# マイグレーションファイル生成
pnpm db:generate
# マイグレーション実行
pnpm db:migrate
# または開発時はプッシュ
pnpm db:push詳細な手順は STRIPE_SETUP.md を参照してください。
クイックスタート:
- Stripe Dashboardでテストモードに切り替え
- 製品と価格を作成(月額/年額/都度課金)
- 価格IDを環境変数に設定
- Stripe CLIをインストール:
brew install stripe/stripe-cli/stripe - ローカル開発用にWebhook転送を起動:
stripe listen --forward-to http://localhost:3000/api/stripe/webhook
- 出力されたWebhook Secretを環境変数に設定
本番環境:
- Webhookエンドポイントを設定:
https://your-domain.com/api/stripe/webhook - 以下のイベントを選択:
product.created,product.updatedprice.created,price.updatedcheckout.session.completedcustomer.subscription.created,customer.subscription.updated,customer.subscription.deletedinvoice.payment_succeededpayment_intent.succeeded
詳細な手順は docs/OAUTH_SETUP.md を参照してください。
Google:
- Google Cloud Consoleでプロジェクト作成
- OAuth 2.0クライアントIDを作成
- リダイレクトURIに
http://localhost:3000/api/auth/callback/googleを追加
GitHub:
- GitHub SettingsでOAuth Appを作成
- Authorization callback URLに
http://localhost:3000/api/auth/callback/githubを設定
💡 重要: サインアップページとサインインページの両方でGoogle/GitHub認証が利用可能です。
# 開発サーバー起動
pnpm dev
# ビルド
pnpm build
# リント
pnpm lint
# Drizzle Studio起動(データベースGUI)
pnpm db:studiopnpm dev: 開発サーバー起動pnpm build: プロダクションビルドpnpm lint: リント実行pnpm test: テスト実行pnpm db:generate: マイグレーションファイル生成pnpm db:migrate: マイグレーション実行pnpm db:push: スキーマを直接プッシュ(開発用)pnpm db:studio: Drizzle Studio起動
shadcn/uiコンポーネントを追加する場合:
pnpm dlx shadcn@latest add button -c apps/webコンポーネントは packages/ui/src/components に配置されます。
// クライアントサイド
import { useSession, signIn, signOut } from "@workspace/auth/client";
function MyComponent() {
const { data: session } = useSession();
return (
<div>
{session ? (
<button onClick={() => signOut()}>Sign Out</button>
) : (
<button onClick={() => signIn.email({ email, password })}>Sign In</button>
)}
</div>
);
}
// サーバーサイド
import { auth } from "@workspace/auth";
const session = await auth.api.getSession({ headers: request.headers });import { db } from "@workspace/db/client";
import { user } from "@workspace/db/schema";
import { eq } from "drizzle-orm";
// ユーザー取得
const users = await db.select().from(user).where(eq(user.email, "[email protected]"));
// ユーザー作成
await db.insert(user).values({
id: "user_id",
name: "John Doe",
email: "[email protected]",
});// Checkout Session作成
const response = await fetch("/api/stripe/create-checkout-session", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
priceId: "price_xxx",
mode: "subscription", // または "payment"
}),
});
const { url } = await response.json();
window.location.href = url;
// 顧客ポータル
const response = await fetch("/api/stripe/portal", { method: "POST" });
const { url } = await response.json();
window.location.href = url;- GitHubリポジトリをVercelに接続
- 環境変数を設定
- デプロイ
pnpm buildでビルドapps/web/.nextをデプロイ- 環境変数を設定
MIT