Files
everything-claude-code/docs/zh-CN/examples/saas-nextjs-CLAUDE.md
2026-03-22 15:39:24 -07:00

167 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SaaS 应用程序 — 项目 CLAUDE.md
> 一个 Next.js + Supabase + Stripe SaaS 应用程序的真实示例。
> 将此复制到您的项目根目录,并根据您的技术栈进行自定义。
## 项目概览
**技术栈:** Next.js 15App Router、TypeScript、Supabase身份验证 + 数据库、Stripe计费、Tailwind CSS、Playwright端到端测试
**架构:** 默认使用服务器组件。仅在需要交互性时使用客户端组件。API 路由用于 Webhook服务器操作用于数据变更。
## 关键规则
### 数据库
* 所有查询均使用启用 RLS 的 Supabase 客户端 — 绝不要绕过 RLS
* 迁移在 `supabase/migrations/` 中 — 绝不要直接修改数据库
* 使用带有明确列列表的 `select()`,而不是 `select('*')`
* 所有面向用户的查询必须包含 `.limit()` 以防止返回无限制的结果
### 身份验证
* 在服务器组件中使用来自 `@supabase/ssr``createServerClient()`
* 在客户端组件中使用来自 `@supabase/ssr``createBrowserClient()`
* 受保护的路由检查 `getUser()` — 绝不要仅依赖 `getSession()` 进行身份验证
* `middleware.ts` 中的中间件会在每个请求上刷新身份验证令牌
### 计费
* Stripe webhook 处理程序在 `app/api/webhooks/stripe/route.ts`
* 绝不要信任客户端的定价数据 — 始终在服务器端从 Stripe 获取
* 通过 `subscription_status` 列检查订阅状态,由 webhook 同步
* 免费层用户3 个项目,每天 100 次 API 调用
### 代码风格
* 代码或注释中不使用表情符号
* 仅使用不可变模式 — 使用展开运算符,永不直接修改
* 服务器组件:不使用 `'use client'` 指令,不使用 `useState`/`useEffect`
* 客户端组件:`'use client'` 放在顶部,保持最小化 — 将逻辑提取到钩子中
* 所有输入验证API 路由、表单、环境变量)优先使用 Zod 模式
## 文件结构
```
src/
app/
(auth)/ # 认证页面(登录、注册、忘记密码)
(dashboard)/ # 受保护的仪表板页面
api/
webhooks/ # Stripe、Supabase webhooks
layout.tsx # 根布局(包含 providers
components/
ui/ # Shadcn/ui 组件
forms/ # 带验证的表单组件
dashboard/ # 仪表板专用组件
hooks/ # 自定义 React hooks
lib/
supabase/ # Supabase 客户端工厂
stripe/ # Stripe 客户端与辅助工具
utils.ts # 通用工具函数
types/ # 共享 TypeScript 类型
supabase/
migrations/ # 数据库迁移
seed.sql # 开发用种子数据
```
## 关键模式
### API 响应格式
```typescript
type ApiResponse<T> =
| { success: true; data: T }
| { success: false; error: string; code?: string }
```
### 服务器操作模式
```typescript
'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 }
}
```
## 环境变量
```bash
# Supabase
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=
SUPABASE_SERVICE_ROLE_KEY= # Server-only, never expose to client
# Stripe
STRIPE_SECRET_KEY=
STRIPE_WEBHOOK_SECRET=
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=
# App
NEXT_PUBLIC_APP_URL=http://localhost:3000
```
## 测试策略
```bash
/tdd # Unit + integration tests for new features
/e2e # Playwright tests for auth flow, billing, dashboard
/test-coverage # Verify 80%+ coverage
```
### 关键的端到端测试流程
1. 注册 → 邮箱验证 → 创建第一个项目
2. 登录 → 仪表盘 → CRUD 操作
3. 升级计划 → Stripe 结账 → 订阅激活
4. Webhook订阅取消 → 降级到免费层
## ECC 工作流
```bash
# Planning a feature
/plan "Add team invitations with email notifications"
# Developing with TDD
/tdd
# Before committing
/code-review
/security-scan
# Before release
/e2e
/test-coverage
```
## Git 工作流
* `feat:` 新功能,`fix:` 错误修复,`refactor:` 代码变更
*`main` 创建功能分支,需要 PR
* CI 运行:代码检查、类型检查、单元测试、端到端测试
* 部署:在 PR 上部署到 Vercel 预览环境,在合并到 `main` 时部署到生产环境