mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-05-18 23:03:06 +08:00
Add remaining files to match zh-CN documentation structure: - hooks/README.md — hooks architecture and customization guide - examples/ — 8 project CLAUDE.md templates (general, user, django, go, harmonyos, laravel, rust, saas-nextjs) - CHANGELOG.md — version history - the-openclaw-guide.md — OpenClaw guide (471 lines) Total: 11 files, 2362 insertions ja-JP now has full parity with zh-CN directory structure.
6.1 KiB
6.1 KiB
SaaSアプリケーション — プロジェクト CLAUDE.md
Next.js + Supabase + Stripe SaaSアプリケーションの実世界サンプル。 これをプロジェクトのルートにコピーしてスタックに合わせてカスタマイズしてください。
プロジェクト概要
スタック: Next.js 15(App Router), TypeScript, Supabase(認証 + DB), Stripe(課金), Tailwind CSS, Playwright(E2E)
アーキテクチャ: デフォルトでサーバーコンポーネント。クライアントコンポーネントはインタラクティビティのみ。ウェブフックにはAPIルート、ミューテーションにはサーバーアクションを使用。
重要なルール
データベース
- すべてのクエリはRLSを有効にしたSupabaseクライアントを使用 — RLSを決してバイパスしない
- マイグレーションは
supabase/migrations/に記述 — データベースを直接変更しない select('*')ではなく明示的なカラムリストでselect()を使用する- すべてのユーザー向けクエリには
.limit()を含めて無制限の結果を防ぐ
認証
- サーバーコンポーネントでは
@supabase/ssrのcreateServerClient()を使用 - クライアントコンポーネントでは
@supabase/ssrのcreateBrowserClient()を使用 - 保護されたルートは
getUser()を確認 — 認証にgetSession()のみを信頼しない middleware.tsのミドルウェアはすべてのリクエストで認証トークンを更新する
課金
- Stripeウェブフックハンドラーは
app/api/webhooks/stripe/route.tsに配置 - クライアントサイドの価格データを信頼しない — 常にStripeサーバーサイドから取得する
- サブスクリプションステータスはウェブフックにより同期される
subscription_statusカラムで確認 - 無料ティアユーザー: プロジェクト3件、APIコール100件/日
コードスタイル
- コードやコメントに絵文字を使用しない
- イミュータブルパターンのみ — スプレッド演算子を使用し、変更しない
- サーバーコンポーネント:
'use client'ディレクティブなし、useState/useEffectなし - クライアントコンポーネント: 先頭に
'use client'、最小限に保つ — ロジックはフックに抽出する - APIルート、フォーム、環境変数のすべての入力バリデーションにZodスキーマを優先する
ファイル構成
src/
app/
(auth)/ # 認証ページ(ログイン、サインアップ、パスワード忘れ)
(dashboard)/ # 保護されたダッシュボードページ
api/
webhooks/ # Stripe、Supabaseウェブフック
layout.tsx # プロバイダー付きルートレイアウト
components/
ui/ # Shadcn/uiコンポーネント
forms/ # バリデーション付きフォームコンポーネント
dashboard/ # ダッシュボード固有のコンポーネント
hooks/ # カスタム Reactフック
lib/
supabase/ # Supabaseクライアントファクトリー
stripe/ # Stripeクライアントとヘルパー
utils.ts # 汎用ユーティリティ
types/ # 共有TypeScript型
supabase/
migrations/ # データベースマイグレーション
seed.sql # 開発用シードデータ
主要なパターン
APIレスポンス形式
type ApiResponse<T> =
| { success: true; data: T }
| { success: false; error: string; code?: string }
サーバーアクションパターン
'use server'
import { z } from 'zod'
import { createServerClient } from '@/lib/supabase/server'
const schema = z.object({
name: z.string().min(1).max(100),
})
export async function createProject(formData: FormData) {
const parsed = schema.safeParse({ name: formData.get('name') })
if (!parsed.success) {
return { success: false, error: parsed.error.flatten() }
}
const supabase = await createServerClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) return { success: false, error: 'Unauthorized' }
const { data, error } = await supabase
.from('projects')
.insert({ name: parsed.data.name, user_id: user.id })
.select('id, name, created_at')
.single()
if (error) return { success: false, error: 'Failed to create project' }
return { success: true, data }
}
環境変数
# Supabase
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=
SUPABASE_SERVICE_ROLE_KEY= # サーバーのみ、クライアントに公開しない
# Stripe
STRIPE_SECRET_KEY=
STRIPE_WEBHOOK_SECRET=
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=
# アプリ
NEXT_PUBLIC_APP_URL=http://localhost:3000
テスト戦略
/tdd # 新機能のユニット + 統合テスト
/e2e # 認証フロー、課金、ダッシュボードのPlaywrightテスト
/test-coverage # 80%以上のカバレッジを確認
重要なE2Eフロー
- サインアップ → メール認証 → 最初のプロジェクト作成
- ログイン → ダッシュボード → CRUD操作
- プランのアップグレード → Stripeチェックアウト → サブスクリプション有効
- ウェブフック: サブスクリプションのキャンセル → 無料ティアへのダウングレード
ECCワークフロー
# 機能の計画
/plan "Add team invitations with email notifications"
# TDDによる開発
/tdd
# コミット前
/code-review
/security-scan
# リリース前
/e2e
/test-coverage
Git ワークフロー
feat:新機能、fix:バグ修正、refactor:コード変更mainからフィーチャーブランチを切り、PRが必要- CIで実行: リント、型チェック、ユニットテスト、E2Eテスト
- デプロイ: PRのVercelプレビュー、
mainへのマージで本番環境