/saas — 全端 SaaS 建構器
觸發方式: /saas [想法] 或只輸入 /saas(會提示輸入想法)
輸出結果: 一個完整部署、可上線的 SaaS 產品,位於 Vercel URL。包含運作中的身份驗證、真實後端、即時資料、美觀的 UI。不是展示品,不是骨架,而是真正的產品。
管線總覽
需求確認 → 研究(平行)→ 規劃 → 釐清 → 建構 → 測試 → 審查 → 部署
每個階段都會閘控下一個階段。沒有捷徑,不可跳過。
階段 1 — 需求確認
如果使用者執行了 /saas [想法],則從指令中提取想法。
如果使用者只執行了 /saas 且沒有參數,則詢問:
SaaS 點子是什麼?用 1-3 句話描述。包括:
- 它做什麼
- 目標使用者是誰
- 解決什麼問題
儲存為 IDEA。在繼續之前,用一句話向使用者確認。
階段 2 — 平行研究
同時使用 Agent 工具啟動兩個研究軌道。不要等待其中一個完成才開始另一個。
軌道 A — 市場情報
使用以下提示生成一個 general-purpose agent:
針對以下點子研究 SaaS 市場:[IDEA]
提供一份結構化報告,涵蓋:
1. 現有競爭對手(5-8 家)
- 名稱、網址、定價等級、市場定位
- 他們的優勢與不足
- 若有估計年經常性收入(ARR)資料
2. 市場規模與需求
- 類別(CRM、專案管理、分析等)
- 市場規模估計
- 成長趨勢(成長中/持平/衰退)
- 需求證據(Reddit 討論串、ProductHunt 讚數、職缺)
3. 定價基準
- 免費增值 vs 純付費 vs 試用
- 典型價格點($/使用者/月、固定費、用量計費)
- 此類別中哪種模式勝出
4. 功能對照表
- 列出競爭對手最常見的 10 項功能
- 標註哪些是基本必備功能,哪些是差異化功能
5. 空白機會
- 競爭對手**沒有**在做什麼?
- 使用者在哪裡抱怨?(查看 G2、Capterra、Reddit)
- 切入機會是什麼?
回傳結構化 markdown。要具體,不要廢話。
軌道 B — 技術模式研究
生成第二個 general-purpose agent:
針對這類 SaaS 研究技術實作模式:[IDEA]
提供:
1. 資料模型模式
- 此類應用通常需要哪些資料表/實體?
- 關鍵關係與約束
- 多租戶方案(基於列的 org_id vs 獨立 schema)
2. 認證模式
- 此類應用需要社群登入嗎?魔法連結?SSO?
- 僅限邀請 vs 開放註冊?
- 角色模式(管理員/成員/檢視者是否典型?)
3. 計費模式
- 按席位、用量、或固定費?
- 在此領域有效的免費方案策略?
4. 整合需求
- 此類應用通常整合哪些服務?
- Webhook、Zapier、API 金鑰?
5. 技術風險
- 此類別中什麼最難建構?
- 團隊常犯什麼錯誤?
- 效能/規模考量
回傳結構化 markdown。要具體。
等待兩個軌道都完成後再繼續。
階段 3 — 架構規劃
使用兩個研究的產出,製作一份結構化的建構計畫。寫入 .saas-workspace/[專案縮寫]/PLAN.md。
計畫必須包含:
3.1 產品定義
## 產品
名稱:[從點子衍伸,可更改]
標語:[一句話]
核心價值主張:[一句話]
目標使用者:[具體人物誌]
## MVP 功能集(今天要建構的)
- [功能 1] — [為什麼在範圍內]
- [功能 2] — [為什麼在範圍內]
...
## 非本次範圍(v1 之後)
- [功能] — [延後到 v2 因為...]
3.2 資料模型
設計完整的 Postgres schema。每個資料表需包含:
- 資料表名稱、用途
- 所有欄位,包含型別、約束、預設值
- 外鍵關聯
- 所需的 RLS 策略
- 索引
從這些必要資料表開始:
-- 始終包含:
profiles(擴充 auth.users)
organizations(如果是多租戶)
organization_members(如果是多租戶)
subscriptions(如果需要計費)
然後為產品新增領域特定的資料表。
3.3 路由地圖
登陸頁面: /
認證: /login /signup /auth/callback
應用程式殼層: /app(需登入)
核心功能: /app/[功能](每個 MVP 功能一個)
設定: /app/settings
API 路由: /api/...(列出每個)
3.4 技術棧確認
框架: Next.js 15(App Router, TypeScript)
資料庫: Supabase(Postgres + Auth + RLS)
樣式: Tailwind CSS v4 + shadcn/ui
電子郵件: Resend(交易型)
部署: Vercel
付款: Stripe(如果需要計費)
3.5 建構順序
列出精確順序:遷移 → 認證 → API 路由 → 應用程式殼層 → 功能 → 登陸頁面 → 電子郵件範本 → 測試。
階段 4 — 釐清問題
在撰寫任何程式碼之前,先找出缺口。使用 AskUserQuestion 提出以下問題(每次呼叫最多分組 4 個問題):
第一輪 — 產品範圍:
- 確認名稱(從點子衍伸 3 個選項)
- 多租戶(團隊/組織)還是單一使用者帳號?
- v1 是否需要付款/計費,還是建置期間免費?
- 研究中是否有任何特定功能是必備功能 vs 加分功能?
**第二輪 — 設計與部署(僅當第一輪答案引發新問題時才問):
- 網域?(或暫時使用 Vercel 子網域)
- 有品牌顏色/偏好嗎?(預設:Rawgrowth 深綠系統)
- Resend 的寄件者電子郵件地址?
在繼續之前,將答案納入 PLAN.md。
階段 5 — 建構
建構前設定
在撰寫任何程式碼之前,載入這些技能:
frontend-theme— 注入完整的 Rawgrowth 設計系統ui-ux-pro-max— 設計決策、調色盤、字體- 呼叫 Magic MCP(
@21st-dev/magic)處理任何複雜元件
專案位置: 建立在 ~/saas-projects/[專案縮寫]/
Scaffold 指令:
cd ~/saas-projects
npx create-next-app@latest [專案縮寫] \
--typescript \
--tailwind \
--eslint \
--app \
--src-dir \
--import-alias "@/*" \
--no-git
cd [專案縮寫]
安裝相依套件:
npm install @supabase/supabase-js @supabase/ssr \
resend \
@radix-ui/react-icons \
lucide-react \
class-variance-authority clsx tailwind-merge \
zod \
@hookform/resolvers react-hook-form
# shadcn/ui 初始化
npx shadcn@latest init --defaults
# 新增 shadcn 元件
npx shadcn@latest add button input label card \
dropdown-menu avatar badge separator toast \
dialog sheet tabs form
Tailwind v4 設定 — 將 frontend-theme tokens 套用到 src/app/globals.css。
5.1 資料庫與遷移
每個遷移使用 add-migration 技能。
遷移 1:核心 schema
-- 在所有面向使用者的資料表上啟用 RLS
-- profiles:擴充 auth.users
CREATE TABLE profiles (
id UUID REFERENCES auth.users(id) ON DELETE CASCADE PRIMARY KEY,
email TEXT NOT NULL,
full_name TEXT,
avatar_url TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
CREATE POLICY "使用者可以檢視自己的設定檔"
ON profiles FOR SELECT USING (auth.uid() = id);
CREATE POLICY "使用者可以更新自己的設定檔"
ON profiles FOR UPDATE USING (auth.uid() = id);
-- 註冊時自動建立設定檔
CREATE OR REPLACE FUNCTION public.handle_new_user()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO public.profiles (id, email, full_name, avatar_url)
VALUES (
NEW.id,
NEW.email,
NEW.raw_user_meta_data->>'full_name',
NEW.raw_user_meta_data->>'avatar_url'
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW EXECUTE FUNCTION public.handle_new_user();
遷移 2:組織(如果是多租戶)
CREATE TABLE organizations (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
name TEXT NOT NULL,
slug TEXT UNIQUE NOT NULL,
owner_id UUID REFERENCES profiles(id) ON DELETE CASCADE NOT NULL,
plan TEXT DEFAULT 'free',
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE organization_members (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
org_id UUID REFERENCES organizations(id) ON DELETE CASCADE NOT NULL,
user_id UUID REFERENCES profiles(id) ON DELETE CASCADE NOT NULL,
role TEXT NOT NULL DEFAULT 'member' CHECK (role IN ('owner', 'admin', 'member')),
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(org_id, user_id)
);
ALTER TABLE organizations ENABLE ROW LEVEL SECURITY;
ALTER TABLE organization_members ENABLE ROW LEVEL SECURITY;
CREATE POLICY "成員可以檢視自己的組織"
ON organizations FOR SELECT
USING (id IN (
SELECT org_id FROM organization_members WHERE user_id = auth.uid()
));
CREATE POLICY "成員可以檢視組織成員"
ON organization_members FOR SELECT
USING (org_id IN (
SELECT org_id FROM organization_members WHERE user_id = auth.uid()
));
遷移 3+:領域資料表 — 根據 PLAN.md 中的資料模型建立產品特定資料表。對每個資料表套用 RLS。
5.2 Supabase Client 設定
src/lib/supabase/client.ts:
import { createBrowserClient } from '@supabase/ssr'
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
}
src/lib/supabase/server.ts:
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'
export async function createClient() {
const cookieStore = await cookies()
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() { return cookieStore.getAll() },
setAll(cookiesToSet) {
try {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
)
} catch {}
},
},
}
)
}
src/middleware.ts — 保護所有 /app/* 路由,將未登入使用者重新導向到 /login。
5.3 認證頁面
將 /login 和 /signup 建構成完整頁面(非彈窗)。套用 frontend-theme:
- 深色背景(#060B08)
- 置中卡片,帶邊框(rgba(255,255,255,0.06))
- 綠色 CTA 按鈕(#0CBF6A)
- 電子郵件 + 密碼欄位(+ 如有設定社群登入)
- 「忘記密碼」連結
- 無表情符號。簡潔、高級、極簡。
src/app/(auth)/login/page.tsx — 使用 Supabase Auth 的登入表單
src/app/(auth)/signup/page.tsx — 包含電子郵件確認流程的註冊表單
src/app/auth/callback/route.ts — OAuth/魔法連結回呼處理器
電子郵件確認流程:
- 註冊後 → Supabase 發送確認電子郵件(透過 Resend SMTP)
- 回呼路由交換 code 換取 session
- 成功後重新導向到
/app/dashboard
5.4 應用程式殼層
src/app/(app)/layout.tsx — 已認證的佈局,包含:
- 側邊欄(在手機上可收合)
- 頂部導覽列,包含使用者頭像 + 下拉選單(設定檔、設定、登出)
- 麵包屑
- Toast 通知容器
側邊欄項目來自 PLAN.md 中的路由地圖。
使用 Magic MCP 取得側邊欄元件:搜尋「dashboard sidebar dark」並調整為 frontend-theme tokens。
5.5 核心功能頁面
對於 MVP 功能集中的每個功能(來自 PLAN.md):
- 先設計 — 向 Magic MCP 查詢相關元件模式
- 資料層 — 伺服器元件直接從 Supabase 擷取資料
- 資料變更 — 使用 Zod 驗證的 Server Actions
- 錯誤狀態 — 每個表單都有驗證錯誤、載入狀態、空狀態
- 無
any型別 — 從 Supabase schema 產生 TypeScript 型別
資料擷取伺服器元件的模式:
import { createClient } from '@/lib/supabase/server'
import { redirect } f