SaaS 客戶擴張 SOP — 預約系統新客戶 Onboarding
最後更新:2026-06-08(v1.1 早期維護複查) 文件狀態:有效 負責部門:開發部(DEV)— SOP 主檔;法務部(LEG)— 服務協議與 DPA;策略部(STR)— 商業條款 適用範圍:預約系統 SaaS(shoppy09/my-booking-system)為新客戶在 Northflank 部署獨立實例的完整流程 參考實作:Tim 自用實例 www.careerssl.com/booking(C-Light 整合 2026-05-19;前身 booking.careerssl.com,Northflank 遷移 2026-04-20,見
dev/deploy-verify/SYS-04-2026-04-20.md)
一、觸發條件
以下任一情境觸發本 SOP:
- 新付費客戶完成簽約(SaaS 服務協議 + DPA)
- 合作客戶申請使用(如姐姐-01 模式,免費或內部成本)
- 試用申請通過後(試用 14 天,到期需轉付費)
不觸發本 SOP 的情境:
- Tim 自用實例已部署完畢,無需重做
- 客戶僅諮詢未簽約 → 走業務部外展流程
- 程式碼異動部署 → 走既有 deploy SKILL(
預約系統/.claude/skills/deploy/SKILL.md),客戶實例自動跟進
二、前置條件清單(8 項全達才啟動)
執行 SOP 前 Tim 必須確認:
- ① 合約簽署:SaaS 服務協議已簽(模板:
legal/saas-service-agreement-template.md,v1.0 2026-05-01 建立,14 章 + 2 附錄;⚠️ 正式簽約前建議律師審查) - ② DPA 簽署:資料處理協議已簽(若 MongoDB 採方案 A 同帳號,Tim = 資料處理者必簽 DPA;模板:
legal/dpa-template.md,v1.0 2026-05-01 建立) - ③ 客戶資料齊備:第三章「客戶資訊收集表」7 欄全填
- ④ 預算確認:客戶承擔費用 vs Tim 吸收費用已書面確認(包含 Northflank 月費 + MongoDB 升級可能 + Cloudinary 流量等)
- ⑤ 技術可行性確認:Northflank Sandbox 額度 / MongoDB 容量 / Cloudinary 流量等預估在限制內,無立即超量
- ⑥ 實例計費歸屬:Northflank service 費用走 Tim 帳號(含於服務費)vs 客戶自有 Northflank 帳號
- ⑦ ⛔ 禁止業務類型確認:客戶業務性質不屬於:博弈 / 色情 / 詐騙 / 未授權醫療 / 政治宣傳 / 侵權商品 / 加密貨幣交易 / 任何違反台灣法律之業務
- ⑧ ⛔ 客戶地理範圍:目前僅服務台灣境內客戶;境外客戶(GDPR 適用)需 LEG 額外審查 + GDPR Article 28 合約 + 跨境傳輸告知
WHY 8 項全達標準:任何一項缺失都可能導致法律糾紛、技術超量或商業誤解。前置條件比實作更重要。
三、客戶資訊收集表
執行此表後 Tim 應有完整的環境變數來源資料:
| # | 欄位 | 範例值 | 歸屬規則 |
|---|---|---|---|
| 1 | 客戶代號 | client-shoppyA01 |
Tim 命名(建議 client- 前綴) |
| 2 | 店名 SHOP_NAME |
「美甲沙龍 OOO」 | 客戶提供 |
| 3 | 主題色 HEX THEME_PRIMARY_COLOR |
#C4622D |
客戶提供(可附 brand guideline) |
| 4 | 管理員帳密 ADMIN_USER / ADMIN_PASS |
Tim 生成隨機強密碼 | Tim 生成 → 客戶首次登入後自改 |
| 5 | MongoDB 隔離方式 | A 同 Atlas / B 客戶自有 / C Tim Atlas 升級 | 詳見第四章決策樹 |
| 6 | LINE OA 整合 | LINE Channel Access Token | ⛔ 客戶必有(不可共用 Tim 帳號) |
| 7 | 金流(ECPay 等) | ECPay 商家帳號 + HashKey + HashIV | ⛔ 客戶必有(金流必須走客戶名義,不可掛 Tim 帳號) |
| 8 | SMTP 通知信 | EMAIL_USER / EMAIL_PASS | 可選:Tim 共用 Gmail / 客戶自有 |
| 9 | Cloudinary 圖片上傳 | Cloud name / API key / API secret | 可選:Tim 共用(Tim 吸收流量成本)/ 客戶自有 |
| 10 | 域名選擇 | A [name].careerssl.com / B 客戶自有 |
詳見第六章 |
| 11 | 是否接入 HQ 財務 | 是(合作關係,需 DPA)/ 否(純付費客戶資料隔離) | 詳見第九章金流邊界 |
⛔ 必須客戶自有(不可妥協)
- LINE Channel Access Token:一個 LINE OA 一個 token,technically 不可共用;commercially 訊息發送名義必須是客戶自身
- ECPay / 任何金流商家帳號:金流走客戶名義,否則税務、糾紛、洗錢防制責任歸 Tim 不可
⚠️ 可選共用(記錄成本歸屬)
- SMTP(共用 Tim Gmail):Tim 吸收流量;建議客戶量 ≥ 5 時轉付費 SMTP(如 SendGrid)
- Cloudinary(共用 Tim 帳號):Tim 吸收 25GB/月免費額度;超量需升 $99/月
四、MongoDB 設定決策(A/B/C 三方案)
| 方案 | 適用情境 | 優點 | 缺點 | 法律意涵 |
|---|---|---|---|---|
| A 同 Tim Atlas + 不同 db | 合作關係(如姐姐)/ 試用客戶 | 成本 0 / 設定快(5 min) | Tim 技術可看資料 / M0 共用 512MB(3 客戶後撞牆)/ 無自動備份 | ⛔ Tim = 資料處理者,必簽 DPA |
| B 客戶自有 Atlas | 付費客戶(隱私敏感業務) | 資料完全隔離 / 客戶自負容量 / Tim 法律責任最低 | 客戶需自設 Atlas / 客戶須付 Atlas 費用 | ✅ 客戶自為控制者 + 處理者,無 DPA 需求 |
| C Tim Atlas M10+ 付費 | Tim 客戶數 ≥ 3 | 含自動備份 / 大容量(10GB+)/ 集中管理 | Tim 月費 $57+ 起跳 / 仍需 DPA | ⛔ Tim = 資料處理者,必簽 DPA;建議費用攤入服務費 |
容量觸發點
- 方案 A:客戶 ≥ 3 → 強烈建議轉 B 或 C(M0 512MB 不足)
- 方案 C:每月監控 Atlas 用量,達 80% 規劃升級
五、Northflank 部署 10 步驟
⚠️ 接入前必查 Northflank 當下定價政策(Sandbox 免費額度可能變動,不寫死數字)
Step 5.1:登入 Northflank → 建立 Service
- 登入 https://app.northflank.com
- 選擇 Project(建議用
tzlth-saas統一管理 / 或客戶自有 project) - New Service → Combined service(同 Tim 自用實例設定)
- Source:GitHub
shoppy09/my-booking-system - Branch:
main - Build type:Buildpack 或 Dockerfile(依 repo 設定)
- Plan:
nf-compute-10(Sandbox 免費,0.1 vCPU + 256MB)
Step 5.2:⛔ 啟用 GitHub auto-deploy on main 分支
- Source 設定欄勾選「Auto-deploy on push to main」
- WHY:未來 repo 異動時客戶實例自動跟進,避免「靜默漂移」
Step 5.3:環境變數設定(依 .env.example 20+ 變數,詳見附錄 A)
強制每實例獨立:
- ⛔
JWT_SECRET:必獨立!生成指令:
WHY:跨實例共用 JWT_SECRET = token 互通 = 安全漏洞node -e "console.log(require('crypto').randomBytes(64).toString('hex'))" - ⛔
ADMIN_USER/ADMIN_PASS:必獨立 MONGODB_URI:依方案 A/B/C 不同BASE_URL/APP_URL:填 Northflank 給的暫時 URL(後續改 custom domain)SHOP_NAME/THEME_*:依客戶資料
可共用(看歸屬決策):
- SMTP / Cloudinary 變數
詳見附錄 A 環境變數對照表
Step 5.4:首次部署 → 等 build 完成(約 3-5 分鐘)
Step 5.5:驗證 ping endpoint
curl https://<northflank-url>/api/ping→ 預期{"status":"ok"}
Step 5.6:驗證 stats endpoint
curl https://<northflank-url>/api/stats→ 預期{total: 0, thisWeek: 0, thisMonth: 0}(新客戶為 0)
Step 5.7:自訂域名綁定(見第六章)
Step 5.8:SSL 自動申請(Let's Encrypt 自動,等 5-10 min)
Step 5.9:健康檢查設定
- Northflank service → Health checks → /api/ping path → 30s interval
Step 5.10:UptimeRobot 監控加入
- 加入 Tim 既有 UptimeRobot 帳號 → URL:
https://<custom-domain>/api/ping - 告警:Tim 為主 + 客戶為副(Email + LINE)
Step 5.11:Google Calendar 整合(選填,推薦開啟)
⚠️ 若不設此兩個 env var,Calendar 同步功能靜默失敗(無錯誤訊息),客戶後台手動新增預約不會同步至 Google Calendar
- Google Cloud Console → 建立 Service Account → 下載 JSON 金鑰
- 把 JSON 轉為單行(所有換行符 →
\n) - 客戶的 Google Calendar → 設定 → 與特定使用者共用 → 加入 Service Account email → 權限「編輯事件」
- Northflank env var 填入:
GOOGLE_CALENDAR_ID:行事曆 ID(格式:xxx@group.calendar.google.com或 Gmail 地址)GOOGLE_SERVICE_ACCOUNT_JSON:整個 JSON 字串(單行,含\n)
- Northflank service → Redeploy → 建立一筆測試預約 → 確認 Google Calendar 出現含 Google Meet 連結的事件
六、域名設定(A 子域名 / B 客戶自有)
方案 A:[name].careerssl.com 子域名
- 確認 careerssl.com DNS 託管方:⚠️ 首次執行此 SOP 的 Tim 必須在此填入並提交 PR 更新本 SOP(Cloudflare / Vercel DNS / 中華電信 / GoDaddy / 其他:____)
- DNS 託管後台 → 加 CNAME:
Type: CNAME Name: [client-name] (例:shoppyA01) Target: site--my-booking-system--xxx.code.run (Northflank service URL) TTL: Auto / 3600 - Northflank → service → Domains → Add custom domain →
shoppyA01.careerssl.com - 等 DNS 傳播(5-30 min)+ SSL 自動申請
方案 B:客戶自有域名
- 客戶 DNS 後台 → 加 CNAME:
Name: booking (or @ for root) Target: site--my-booking-system--xxx.code.run - Northflank custom domain 加客戶域名
- SSL 自動申請
域名選擇權衡
| 維度 | 方案 A 子域名 | 方案 B 客戶自有 |
|---|---|---|
| 設定難度 | 低(Tim 全處理) | 中(需客戶配合 DNS) |
| 品牌 | careerssl 主品牌污染風險 | 客戶獨立品牌 |
| SEO | careerssl 整體 SEO 受影響 | 客戶自有 SEO |
| 成本 | 0 | 客戶自有域名年費 |
| 推薦 | 試用客戶 / 合作關係 | 付費客戶 / 重視品牌獨立 |
七、驗收清單(10 項全打勾才交付)
- 主頁載入正常(前台 / 客戶域名 / SSL 綠鎖)
- 後台登入正常(管理員帳密可登入)
- 預約完整流程跑通(選方案 → 選時段 → 填資料 → 收 Email 確認)
- SSL 有效(
/api/pingHTTPS 200) - 主題色正確顯示(依
THEME_*env var) - SMTP 寄信成功(測試預約後收到通知信)
- LINE OA 設定(如有):webhook URL 已更新為
https://<domain>/api/line-webhook - 評價邀請信流程(如有開啟)
- 付款流程(ECPay / 銀行匯款,如有)
- UptimeRobot 監控已加入並收到首次 OK 訊號
- Google Calendar 整合(如有設定):建立測試預約 → 確認 Google Calendar 出現含 Google Meet 連結的事件
任一項失敗 → 不可交付,先排除問題(見第十章故障處理)
八、客戶交付包
交付給客戶的 5 項物件
- 前台 URL:
https://[domain]/(讓客戶分享給其顧客) - 後台 URL:
https://[domain]/admin - 管理員帳密:⛔ 透過安全管道交付(建議 1Password / Bitwarden 共享庫;不建議 LINE 訊息明文;客戶首次登入後強制自改密碼)
- 操作手冊連結:建議建立
knowledge/operations/booking-system-user-manual.md(待補 P3) - 緊急聯絡方式:Tim LINE / Email / 預約系統管理員聯絡資訊
交付後 Tim 留檔
- 客戶代號 / 域名 / Northflank service ID / MongoDB 方案 → 寫入
business/saas-clients-registry.md(待建) - onboard 日期 / 預估月費 / 服務費起算日 → 同上
- 簽妥的 SaaS 協議 + DPA →
legal/signed/[client-code]-YYYY-MM-DD.pdf
九、計費、權責、金流邊界
9.1 Northflank 費用
⚠️ 執行 SOP 前必查當下 Northflank 定價(https://northflank.com/pricing)
當前已知(2026-04-30,可能變動):
- Sandbox
nf-compute-10:免費(限額度,達上限後新增 service 需付費或升級) - 生產級 plan:依 vCPU / RAM / 流量計費
9.2 Tim 服務費結構(建議)
| 模式 | 月費(建議) | 涵蓋 |
|---|---|---|
| 試用 | 0 | 14 天試用,超過轉付費 |
| 基礎 | NT$1,500-2,500 / 月 | 基本部署 + 維運 + 程式碼自動更新 |
| 進階 | NT$3,000-5,000 / 月 | 基礎 + MongoDB 升級攤分 + 客製主題 + 優先支援 |
| 一次性建置費 | NT$5,000-10,000 | 首次 onboard 工時費(含資料遷移、客製化) |
數字為起跳建議,Tim 依客戶業務規模調整
9.3 ⛔ 金流邊界(FINANCE_SYNC_TOKENS 安全分流)
預約系統 server.js L286-298 已實作 multi-tenant token 機制(FINANCE_SYNC_TOKENS 環境變數):
| 客戶類型 | FINANCE_SYNC_TOKENS 是否加 entry | 理由 |
|---|---|---|
| 付費 SaaS 客戶 | ⛔ 不加 | Tim 不應看到客戶業務數據(違反 DPA);客戶收入歸客戶 |
| 合作關係客戶(如姐姐) | ✅ 可加(需簽 DPA) | 數據回流 HQ 財務系統,便於 Tim 看到家族整體 |
| Tim 自用實例 | ✅ 加(既有) | 自家數據歸自家 |
9.4 客戶端金流(ECPay 等)權責
- 客戶實例的金流走客戶 ECPay 商家帳號,款項直接入客戶銀行
- Tim 的 SaaS 服務費另開發票收取,不從客戶業務金流抽成
- 此分流避免:① 洗錢防制法責任 ② 統一發票稅務責任 ③ 客戶資金安全
十、回滾與故障處理
常見問題排查
| # | 故障 | 排查順序 |
|---|---|---|
| 1 | 部署失敗(Northflank build 紅燈) | ① 看 build log → ② 確認 Node 版本(package.json engines)→ ③ 確認所有必填 env var 已設 |
| 2 | DNS 不傳播(SSL 卡住) | ① dig +short [domain] 確認 CNAME ② 等 30 min(部分 DNS 需更久)③ Northflank custom domain 重新 verify |
| 3 | SSL 申請失敗 | ① 確認 DNS 已正確指向 ② Northflank Domains → 重新 issue certificate ③ 24h 後仍失敗 → 聯絡 Northflank support |
| 4 | MongoDB 連線錯(後台 stats 為空 / 預約失敗) | ① 確認 MONGODB_URI 正確 ② Atlas Network Access → IP whitelist 加 0.0.0.0/0(或 Northflank egress IP)③ 確認 db user 權限 |
回滾流程
- 部署失敗無法修 → Northflank rollback to last known good revision
- 客戶域名綁錯 → 移除 custom domain → 重設定
- 環境變數錯 → service settings → variables → 修正 → redeploy
十一、客戶解約與終止流程
觸發條件
- 客戶到期不續費(試用未轉付費 / 付費不續)
- 雙方協議終止
- 客戶違反禁止業務條款(觸發強制終止)
Step 11.1:暫停期(30 天,資料保留)
- Northflank service → Pause(不刪除)
- DNS CNAME 不釋放(保留 30 天,給客戶反悔空間)
- 通知客戶:暫停日期 + 30 天後永久刪除 + 資料導出選項
Step 11.2:資料導出(客戶要求才執行)
- 從 MongoDB 匯出該客戶 db → JSON / CSV
- 加密傳輸給客戶(密碼另管道告知)
- 30 天後 Tim 端自有副本刪除
Step 11.3:30 天後永久終止
- Northflank service → Delete
- DNS CNAME 移除
- MongoDB db drop(方案 A 同帳號)/ 通知客戶自行 Atlas 終止(方案 B/C)
- UptimeRobot 監控移除
business/saas-clients-registry.md標記 status: terminated + 終止日期
Step 11.4:終止確認文件
- 雙方簽署終止確認書
- 存檔
legal/signed/[client-code]-termination-YYYY-MM-DD.pdf
違反禁止業務條款的特殊終止
- 立即暫停 service(不給 30 天緩衝)
- 通知客戶 + 法務行動準備
- 資料保留待法務指示
十二、SLA 草案 + 異動通知 SOP
SLA(best-effort,正式約定見 SaaS 服務協議)
| 項目 | 標準 |
|---|---|
| 系統可用性 | 99% / 月(best-effort,依 Northflank Sandbox 性能) |
| 故障回應時效 | 工作日 4h / 假日 24h |
| 故障修復時效 | 一般 24h / 重大 72h |
| 計畫性停機 | 提前 7 天通知 |
異動通知 SOP(程式碼異動觸發)
| 異動性質 | 通知時效 | 通知管道 |
|---|---|---|
| 一般 patch(bug fix / 小功能) | 不通知(滾動部署) | 無 |
| breaking change(API 變更 / 重大功能) | 提前 7 天 | LINE / Email |
| 重大停機(DB 遷移 / 架構變更) | 提前 14 天 | LINE / Email + 確認回覆 |
客戶端的「滾動部署」期待管理
- 一般客戶不需知曉每個 patch(採用 SaaS 即接受持續演進)
- 但 breaking change 必須通知,避免客戶端整合斷裂
十三、SOP 維護週期
觸發複查
- 每 6 個月(2026-10-30 觸發首次複查)
- 每次新客戶 onboard 時 Claude 主動驗證 SOP 是否需更新(執行此 SOP 時順便複查)
- Northflank / MongoDB Atlas / Cloudinary 政策有重大變動時
複查內容
- Northflank 定價是否變動?
- MongoDB Atlas M0 限制是否變動?
- 預約系統
.env.example是否新增變數? - 既有客戶是否反映哪一步驟難用 / 不清楚?
- 法律環境是否變動(GDPR / 個資法修訂)?
維護紀錄
| 版本 | 日期 | 變更內容 |
|---|---|---|
| v1.0 | 2026-04-30 | 首次建立(從 Tim 自用實例 2026-04-20 經驗 + 三輪查照盲點補正萃取) |
| v1.1 | 2026-06-08 | 早期維護複查(觸發:Calendar 整合 + C-Light URL 更新):§十三 五項複查清單全評估;Appendix A 新增 7 個 env var(GOOGLE_CALENDAR_ID / GOOGLE_SERVICE_ACCOUNT_JSON / LINE_FRIEND_URL / ADMIN_EMAIL / BANK_ACCOUNT_NAME / TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID);§五 新增 Step 5.11(Google Calendar 整合);§七 驗收清單補 Calendar 驗收項;§一 Tim 自用 URL 更新 booking.careerssl.com → www.careerssl.com/booking;相關文件 11+→20+;Northflank/MongoDB M0/個資法 2026 現況確認 |
附錄 A:環境變數對照表(每實例獨立 vs 共用)
| 變數 | 必填 | 獨立性 | 來源 | 備註 |
|---|---|---|---|---|
MONGODB_URI |
✅ | 每實例獨立(A: db name 不同;B/C: connection string 不同) | 依方案 A/B/C | 包含敏感帳密 |
JWT_SECRET |
✅ | ⛔ 強制獨立 | crypto.randomBytes(64).toString('hex') |
共用 = 安全漏洞 |
ADMIN_USER |
✅ | 強制獨立 | Tim 設定(建議客戶代號) | - |
ADMIN_PASS |
✅ | 強制獨立 | 隨機強密碼 | 客戶首次登入後自改 |
EMAIL_USER / EMAIL_PASS |
✅ | 可共用 / 客戶自有 | 依客戶選擇 | 共用 Tim Gmail 需注意流量 |
SHOP_NAME |
✅ | 每實例獨立 | 客戶提供 | - |
BASE_URL / APP_URL |
✅ | 每實例獨立 | 客戶域名 | - |
BANK_NAME / BANK_CODE / BANK_ACCOUNT |
選 | 每實例獨立 | 客戶銀行 | - |
THEME_PRIMARY_COLOR 等 |
選 | 每實例獨立 | 客戶 brand | - |
LINE_CHANNEL_ACCESS_TOKEN |
選 | ⛔ 客戶必有 | 客戶 LINE OA | 不可共用 |
LINE_ADMIN_USER_ID |
選 | ⛔ 客戶必有 | 客戶端管理員 LINE ID | - |
ECPAY_* |
選 | ⛔ 客戶必有 | 客戶 ECPay 商家 | 金流必須走客戶名義 |
CLOUDINARY_* |
選 | 可共用 / 客戶自有 | 依客戶選擇 | 共用 Tim 帳號需 25GB/月留意 |
GOOGLE_CALENDAR_ID |
選 | 每實例獨立 | Google Calendar 行事曆 ID | 格式:xxx@group.calendar.google.com;不填 = Calendar 整合靜默失敗 |
GOOGLE_SERVICE_ACCOUNT_JSON |
選 | 每實例獨立 | GCP Service Account JSON(單行) | 需先建立 Service Account + 共享日曆編輯權限;見 §五 Step 5.11 |
LINE_FRIEND_URL |
選 | 每實例獨立 | LINE 加好友連結(顯示在確認信中) | 格式:https://lin.ee/xxx |
ADMIN_EMAIL |
選 | 每實例獨立 | 管理員信箱(接收系統錯誤通知) | 與 ADMIN_USER 可不同 |
BANK_ACCOUNT_NAME |
選 | 每實例獨立 | 銀行帳戶名稱(匯款資訊) | 搭配 BANK_NAME / BANK_CODE / BANK_ACCOUNT 使用 |
TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID |
選 | 每實例獨立 | Telegram 通知(LINE 替代方案) | 客戶無 LINE OA 時可用 |
FINANCE_SYNC_TOKENS |
選 | ⛔ 不對付費客戶開放 | 僅 Tim 自用 + 合作客戶 | 詳見第 9.3 |
BOOKING_STATS_URL |
選 | 不適用客戶實例 | 僅 HQ 儀表板用 | 客戶實例不需設此 |
附錄 B:監控告警分流設定
| 監控項目 | 主收人 | 副收人 |
|---|---|---|
UptimeRobot /api/ping |
Tim Email + LINE | 客戶 Email |
| Northflank service 狀態 | Tim(Northflank 介面) | - |
| MongoDB Atlas 容量告警 | Tim Email(方案 A/C)/ 客戶(方案 B) | - |
| SSL 即將過期(30 天內) | Tim Email | - |
| 月度檢視會議 | 每月與客戶 30 min review(電話 / LINE) | - |
相關文件
- 預約系統 CLAUDE.md L66-90「多客戶架構」(
C:\Users\USER\Desktop\CLAUDE寫工具\給別人\預約系統\CLAUDE.md) - 預約系統
.env.example(20+ 變數完整清單) - Tim 自用實例參考:
dev/deploy-verify/SYS-04-2026-04-20.md - 法務模板(待建):
legal/saas-service-agreement-template.md/legal/dpa-template.md - 客戶登錄表(待建):
business/saas-clients-registry.md - 既有 deploy SKILL(程式碼異動,非 onboarding):
預約系統/.claude/skills/deploy/SKILL.md - RCF-009 daily-revenue API SaaS 擴張前置設計:
knowledge/decisions/RCF-009-finance-architecture.md