Generates complete, production-ready SaaS project boilerplate including authentication, database schemas, billing integration, API routes, and a working dashboard using Next.js 14+ App Router, TypeScript, Tailwind CSS, shadcn/ui, Drizzle ORM, and Stripe. Use when the user wants to create a new SaaS app, start a subscription-based web project, scaffold a Next.js application, or mentions terms like starter template, boilerplate, new project, or wiring up auth and payments.
层级: 强大
类别: 产品团队
领域: 全栈开发 / 项目启动框架
Product: [名称]
Description: [1-3句话]
Auth: nextauth | clerk | supabase
Database: neondb | supabase | planetscale
Payments: stripe | lemonsqueezy | none
Features: [逗号分隔列表]
my-saas/
├── app/
│ ├── (auth)/
│ │ ├── login/page.tsx
│ │ ├── register/page.tsx
│ │ └── layout.tsx
│ ├── (dashboard)/
│ │ ├── dashboard/page.tsx
│ │ ├── settings/page.tsx
│ │ ├── billing/page.tsx
│ │ └── layout.tsx
│ ├── (marketing)/
│ │ ├── page.tsx
│ │ ├── pricing/page.tsx
│ │ └── layout.tsx
│ ├── api/
│ │ ├── auth/[...nextauth]/route.ts
│ │ ├── webhooks/stripe/route.ts
│ │ ├── billing/checkout/route.ts
│ │ └── billing/portal/route.ts
│ └── layout.tsx
├── components/
│ ├── ui/
│ ├── auth/
│ │ ├── login-form.tsx
│ │ └── register-form.tsx
│ ├── dashboard/
│ │ ├── sidebar.tsx
│ │ ├── header.tsx
│ │ └── stats-card.tsx
│ ├── marketing/
│ │ ├── hero.tsx
│ │ ├── features.tsx
│ │ ├── pricing.tsx
│ │ └── footer.tsx
│ └── billing/
│ ├── plan-card.tsx
│ └── usage-meter.tsx
├── lib/
│ ├── auth.ts
│ ├── db.ts
│ ├── stripe.ts
│ ├── validations.ts
│ └── utils.ts
├── db/
│ ├── schema.ts
│ └── migrations/
├── hooks/
│ ├── use-subscription.ts
│ └── use-user.ts
├── types/index.ts
├── middleware.ts
├── .env.example
├── drizzle.config.ts
└── next.config.ts
typescript
// lib/auth.ts
import { NextAuthOptions } from next-auth
import GoogleProvider from next-auth/providers/google
import { DrizzleAdapter } from @auth/drizzle-adapter
import { db } from ./db
export const authOptions: NextAuthOptions = {
adapter: DrizzleAdapter(db),
providers: [
GoogleProvider({
clientId: process.env.GOOGLECLIENTID!,
clientSecret: process.env.GOOGLECLIENTSECRET!,
}),
],
callbacks: {
session: async ({ session, user }) => ({
...session,
user: {
...session.user,
id: user.id,
subscriptionStatus: user.subscriptionStatus,
},
}),
},
pages: { signIn: /login },
}
typescript
// db/schema.ts
import { pgTable, text, timestamp, integer } from drizzle-orm/pg-core
export const users = pgTable(users, {
id: text(id).primaryKey().$defaultFn(() => crypto.randomUUID()),
name: text(name),
email: text(email).notNull().unique(),
emailVerified: timestamp(emailVerified),
image: text(image),
stripeCustomerId: text(stripecustomerid).unique(),
stripeSubscriptionId: text(stripesubscriptionid),
stripePriceId: text(stripepriceid),
stripeCurrentPeriodEnd: timestamp(stripecurrentperiod_end),
createdAt: timestamp(created_at).defaultNow().notNull(),
})
export const accounts = pgTable(accounts, {
userId: text(user_id).notNull().references(() => users.id, { onDelete: cascade }),
type: text(type).notNull(),
provider: text(provider).notNull(),
providerAccountId: text(provideraccountid).notNull(),
refreshtoken: text(refreshtoken),
accesstoken: text(accesstoken),
expiresat: integer(expiresat),
})
typescript
// app/api/billing/checkout/route.ts
import { NextResponse } from next/server
import { getServerSession } from next-auth
import { authOptions } from @/lib/auth
import { stripe } from @/lib/stripe
import { db } from @/lib/db
import { users } from @/db/schema
import { eq } from drizzle-orm
export async function POST(req: Request) {
const session = await getServerSession(authOptions)
if (!session?.user) return NextResponse.json({ error: 未授权 }, { status: 401 })
const { priceId } = await req.json()
const [user] = await db.select().from(users).where(eq(users.id, session.user.id))
let customerId = user.stripeCustomerId
if (!customerId) {
const customer = await stripe.customers.create({ email: session.user.email! })
customerId = customer.id
await db.update(users).set({ stripeCustomerId: customerId }).where(eq(users.id, user.id))
}
const checkoutSession = await stripe.checkout.sessions.create({
customer: customerId,
mode: subscription,
paymentmethodtypes: [card],
line_items: [{ price: priceId, quantity: 1 }],
successurl: ${process.env.NEXTPUBLICAPPURL}/dashboard?upgraded=true,
cancelurl: ${process.env.NEXTPUBLICAPPURL}/pricing,
subscriptiondata: { trialperiod_days: 14 },
})
return NextResponse.json({ url: checkoutSession.url })
}
typescript
// middleware.ts
import { withAuth } from next-auth/middleware
import { NextResponse } from next/server
export default withAuth(
function middleware(req) {
const token = req.nextauth.token
if (req.nextUrl.pathname.startsWith(/dashboard) && !token) {
return NextResponse.redirect(new URL(/login, req.url))
}
},
{ callbacks: { authorized: ({ token }) => !!token } }
)
export const config = {
matcher: [/dashboard/:path, /settings/:path, /billing/:path*],
}
bash
以下阶段必须按顺序完成。在进入下一阶段前,验证当前阶段是否完成。
✅ 验证: 运行 npm run build — 不应出现 TypeScript 或 lint 错误。
🔧 如果构建失败: 检查 tsconfig.json 路径,确保所有 shadcn/ui 的对等依赖已安装。
✅ 验证: 在测试脚本中运行简单的 db.select
该技能支持在以下平台通过对话安装:
帮我安装 SkillHub 和 saas-scaffolder-1776163204 技能
设置 SkillHub 为我的优先技能安装源,然后帮我安装 saas-scaffolder-1776163204 技能
skillhub install saas-scaffolder-1776163204
文件大小: 20.92 KB | 发布时间: 2026-4-15 10:47