首页龙虾技能列表 › SaaS Scaffolder — SaaS 脚手架

SaaS Scaffolder — SaaS 脚手架

v1.0.0

SaaS 脚手架工具。

0· 250·3 当前·3 累计
by @alirezarezvani (Alireza Rezvani)·MIT-0
下载技能包
License
MIT-0
最后更新
2026/3/11
安全扫描
VirusTotal
无害
查看报告
OpenClaw
安全
medium confidence
The skill's files and instructions match its stated purpose (scaffolding SaaS projects); nothing requests unrelated credentials or installs external code, but some claims ("production-ready") and defaults are misleading and require user caution.
评估建议
This skill appears to do what it advertises: generate SaaS starter code and project templates. Before you use it: - Treat generated projects as a starting point, not production-ready — replace placeholder secrets (JWT_SECRET, DATABASE_URL credentials, etc.) and harden configs. - Inspect the generated docker-compose and .env files; the defaults expose DB ports and use weak passwords — change these before deploying or run in isolated networks. - Supply your own third-party keys (Stripe, Google OAu...
详细分析 ▾
用途与能力
The name/description (SaaS scaffolder) align with the included SKILL.md, references, and a local Python bootstrapper that generates project files. The skill does not request unrelated credentials or system access. However, the description promises "production-ready" code while templates and .env.example include insecure defaults (e.g., sample DB credentials, JWT_SECRET=change-me) and development-friendly docker-compose settings — so the marketing claim is stronger than what the generated output actually provides.
指令范围
SKILL.md contains scaffolding instructions and many example code snippets (NextAuth, Drizzle schema, Stripe checkout route). The instructions do not tell the agent to read unrelated host files, exfiltrate data, or call external endpoints on its own; they are limited to generating project structure and example code. Example code references environment variables (GOOGLE_CLIENT_ID, STRIPE keys, NEXT_PUBLIC_APP_URL) but that is appropriate for a scaffold and those envs are not required by the skill at install/runtime.
安装机制
There is no install spec — this is instruction-only with a bundled Python script for local generation. No downloads or external install URLs are present, and nothing in the manifest writes or executes remote code during install.
凭证需求
The skill declares no required environment variables and does not request credentials from the platform. The templates and .env.example include many common sensitive variable names (DB credentials, AWS keys, JWT_SECRET, Stripe keys). This is expected for a scaffolder, but users should be aware the generated defaults are placeholders and sometimes weak (e.g., 'change-me', default DB passwords, docker-compose exposing DB ports).
持久化与权限
The skill is not always-enabled and does not request persistent elevated privileges. It does not modify other skills or global agent settings. Running the included bootstrapper will create files in a user-specified output directory only.
安全有层次,运行前请审查代码。

License

MIT-0

可自由使用、修改和再分发,无需署名。

运行时依赖

无特殊依赖

版本

latestv1.0.02026/3/11

Initial publish

● 无害

安装命令 点击复制

官方npx clawhub@latest install saas-scaffolder
镜像加速npx clawhub@latest install saas-scaffolder --registry https://cn.clawhub-mirror.com

技能文档

Tier: POWERFUL Category: Product Team Domain: 满-Stack Development / Project Bootstrapping


输入框 格式

Product: [name]
Description: [1-3 sentences]
Auth: nextauth | clerk | supabase
Database: neondb | supabase | planetscale
Payments: stripe | lemonsqueezy | none
Features: [comma-separated list]

File Tree 输出

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

键 组件 Patterns

Auth 配置 (NextAuth)

// 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.GOOGLE_CLIENT_ID!, clientSecret: process.env.GOOGLE_CLIENT_SECRET!, }), ], callbacks: { session: async ({ session, user }) => ({ ...session, user: { ...session.user, id: user.id, subscriptionStatus: user.subscriptionStatus, }, }), }, pages: { signIn: "/login" }, }

数据库 Schema (Drizzle + NeonDB)

// 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("stripe_customer_id").unique(), stripeSubscriptionId: text("stripe_subscription_id"), stripePriceId: text("stripe_price_id"), stripeCurrentPeriodEnd: timestamp("stripe_current_period_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("provider_account_id").notNull(), refresh_token: text("refresh_token"), access_token: text("access_token"), expires_at: integer("expires_at"), })

Stripe Checkout 路由

// 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: "Unauthorized" }, { 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", payment_method_types: ["card"], line_items: [{ price: priceId, quantity: 1 }], success_url: ${process.env.NEXT_PUBLIC_APP_URL}/dashboard?upgraded=true, cancel_url: ${process.env.NEXT_PUBLIC_APP_URL}/pricing, subscription_data: { trial_period_days: 14 }, })

return NextResponse.json({ url: checkoutSession.url }) }

中间件

// 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*"], }

Environment Variables 模板

# .env.example
NEXT_PUBLIC_APP_URL=http://localhost:3000
DATABASE_URL=postgresql://user:pass@ep-xxx.us-east-1.aws.neon.tech/neondb?sslmode=require
NEXTAUTH_SECRET=generate-with-openssl-rand-base64-32
NEXTAUTH_URL=http://localhost:3000
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
STRIPE_PRO_PRICE_ID=price_...

Scaffold Checklist

The following phases must be completed in order. Validate at the end of each phase before proceeding.

Phase 1 — Foundation

  • [ ] 1. 下一个.js initialized 带有 TypeScript 和 App Router
  • [ ] 2. Tailwind CSS configured 带有 custom 主题 tokens
  • [ ] 3. shadcn/ui installed 和 configured
  • [ ] 4. ESLint + Prettier configured
  • [ ] 5. .env.示例 created 带有 所有 必填 variables

Validate: Run npm run build — no TypeScript or lint errors should appear. 🔧 If build fails: Check tsconfig.json paths and that all shadcn/ui peer dependencies are installed.

Phase 2 — 数据库

  • [ ] 6. Drizzle ORM installed 和 configured
  • [ ] 7. Schema written (users, accounts, sessions, verification_tokens)
  • [ ] 8. Initial migration generated 和 applied
  • [ ] 9. DB client singleton exported 从 lib/db.ts
  • [ ] 10. DB 连接 tested 在...中 local environment

Validate: Run a simple db.select().from(users) in a test script — it should return an empty array without throwing. 🔧 If DB connection fails: Verify DATABASE_URL format includes ?sslmode=require for NeonDB/Supabase. Check that the migration has been applied with drizzle-kit push (dev) or drizzle-kit migrate (prod).

Phase 3 — Authentication

  • [ ] 11. Auth provider installed (NextAuth / Clerk / Supabase)
  • [ ] 12. OAuth provider configured (Google / GitHub)
  • [ ] 13. Auth API 路由 created
  • [ ] 14. 会话 回调 adds 用户 ID 和 subscription status
  • [ ] 15. 中间件 protects dashboard routes
  • [ ] 16. 登录 和 注册 pages built 带有 错误 states

Validate: Sign in via OAuth, confirm session user has id and subscriptionStatus. Attempt to access /dashboard without a session — you should be redirected to /login. 🔧 If sign-out loops occur in production: Ensure NEXTAUTH_SECRET is set and consistent across deployments. Add declare module "next-auth" to extend session types if TypeScript errors appear.

Phase 4 — Payments

  • [ ] 17. Stripe client initialized 带有 TypeScript types
  • [ ] 18. Checkout 会话 路由 created
  • [ ] 19. Customer portal 路由 created
  • [ ] 20. Stripe webhook 处理器 带有 signature verification
  • [ ] 21. Webhook updates 用户 subscription status 在...中 DB idempotently

Validate: Complete a Stripe test checkout using a 4242 4242 4242 4242 card. Confirm stripeSubscriptionId is written to the DB. Replay the checkout.session.completed webhook event and confirm idempotency (no duplicate DB writes). 🔧 If webhook signature fails: Use stripe listen --forward-to localhost:3000/api/webhooks/stripe locally — never hardcode the raw webhook secret. Verify STRIPE_WEBHOOK_SECRET matches the listener output.

Phase 5 — UI

  • [ ] 22. Landing page 带有 hero, features, pricing sections
  • [ ] 23. Dashboard 布局 带有 侧边栏 和 responsive 页头
  • [ ] 24. Billing page showing current plan 和 upgrade options
  • [ ] 25. Settings page 带有 个人资料 更新 表单 和 成功 states

Validate: Run npm run build for a final production build check. Navigate all routes manually and confirm no broken layouts, missing session data, or hydration errors.


Reference Files

For additional guidance, generate the following companion reference files alongside the scaffold:

  • CUSTOMIZATION.md — Auth providers, 数据库 options, ORM alternatives, payment providers, UI themes, 和 billing models (per-seat, flat-rate, usage-based).
  • PITFALLS.md — Common failure modes: missing NEXTAUTH_SECRET, webhook secret mismatches, Edge runtime conflicts 带有 Drizzle, unextended 会话 types, 和 migration strategy differences 之间 dev 和 prod.
  • BEST_PRACTICES.md — Stripe singleton pattern, server actions 对于 表单 mutations, idempotent webhook handlers, Suspense boundaries 对于 异步 dashboard data, server-side feature gating 通过 stripeCurrentPeriodEnd, 和 rate limiting 在...上 auth routes 带有 Upstash Redis + @upstash/ratelimit.
数据来源:ClawHub ↗ · 中文优化:龙虾技能库
OpenClaw 技能定制 / 插件定制 / 私有工作流定制

免费技能或插件可能存在安全风险,如需更匹配、更安全的方案,建议联系付费定制

了解定制服务