已修复的 Bugs

Bug 20: Google OAuth Client Secret 輪換導致登入失敗 (2026-05-29)

  • 根因: Google 自動輪換 OAuth client secret,Drive 上的 JSON 檔案未更新
  • 修復: 從 Drive JSON 更新 GOOGLE_CLIENT_SECRET env var 為 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
  • 注意: 若再出現 invalid_client,去 Google Cloud Console 下載最新 JSON

Bug 19: AI Rate Limit 跨 Worker fetch 失敗 (2026-05-29)

  • 根因: quotation-saas Worker fetch ai.hsdesign.biz 返回 1016(Worker-to-Worker 路由問題)
  • 修復: 改為直接呼叫 DeepSeek API(加入 DEEPSEEK_KEY env var),不經 renovation-ai Worker
  • AI 上限: Free/Plus/Pro = 0,Pro Max = 999(無限)

Bug 18: Dashboard 被 chat-widget script 搞壞 (2026-05-29)

  • 根因: 嘗試嵌入式 chat HTML/JS 時,模板字面量的 \' 在 JavaScript 中是非法的 escape sequence
  • 修復: 將 chat widget HTML 上傳至 GitHub chat-widget.html,Worker 執行時 fetch 注入

Bug 17: Markup 公式錯誤 x0.28 非 x1.28 (2026-05-29)

  • 根因: const sell = ct * mk 中 mk = 28/100 = 0.28,應為 ct * (1 + mk)
  • 修復: GitHub quote-app.js 改為 ct * (1 + mk)(per-item + applyMarkupAll 都修)

Bug 16: Dashboard 顯示錯誤 plan badge (2026-05-29)

  • 根因: 最小化 post script 移除 account fetch,plan badge 只從 JWT 讀取(過期值)
  • 修復: post script 加入 fetch("/api/account"),從 D1 讀取實際 plan,更新 badge/avatar/dropdown/quota
  • 驗證: Playwright 測試三個方案帳號全部顯示正確方案 ✅

Bug 15: Pricing 頁讀 JWT 而非 D1 (2026-05-29)

  • 根因: Pricing script 從 JWT plan 欄位讀取方案,但 JWT 不會在 Stripe 升級後自動更新
  • 修復: Pricing script 改為呼叫 /api/account 從 D1 讀取實際 plan
  • 驗證: Playwright 測試 Plus/Pro/Pro Max 全部顯示 Current Plan ✅

Bug 14: Dashboard 空白 — post script 被截斷 + 重複宣告 (2026-05-29)

  • 根因: 多次 -e 修補導致 var post = 被截斷至第一個 ;,且後續 patched.replace 程式碼被移除
  • 修復: 清除重複的 var post = 宣告,重建單一乾淨 post script
  • 教訓: 不要在 Worker 代碼中用 -e 做複雜字串操作,改用檔案

Bug 13: Stripe Live Key 失效 (2026-05-29)

  • 根因: 原 sk_live key 被 Stripe 撤銷(可能因暴露在程式碼中被自動輪換)
  • 修復: 換為 rk_live restricted key(使用者從 Stripe Dashboard 手動產生),設定為 Cloudflare env var
  • 筆記: 所有 secrets 已從 Worker 代碼移到 env var,之後如需更換 key → CF Workers → quotation-saas → Variables
  • Price IDs (live):
    • plusprice_1Tbt7S17t9NNR8bpw5uQ8Id8
    • proprice_1Tbt7T17t9NNR8bpaCv1XOQV
    • promaxprice_1Tbt7U17t9NNR8bpuMWIrrrt

Bug 12: Pricing 頁方案高亮不生效 — Script 在 DOM 載入前執行 (2026-05-29)

  • 根因: Pricing script 放在 <head>querySelectorAll("a") 執行時 DOM 還沒解析 → 找到空 NodeList → 什麼都不做
  • 修復: Script 包裹在 setTimeout(function(){...}, 100) 確保 DOM 就緒才執行
  • 匹配邏輯: 透過 onclick="checkout('X')" 屬性提取方案名稱,與 JWT plan 欄位比對

Bug 11: Markup % 改動不影響現有 Items (2026-05-29)

  • 根因: mk-input 變更只影響後續點擊 markup 按鈕,不自動重新計算
  • 修復: 新增 applyMarkupAll() 函式,遍歷所有 items 重新計算 sell = cost * (mk% / 100),綁定到 mk-inputchange/input 事件
  • 涉及: GitHub quote-app.js

Bug 10: Pages frontend 完全消除 — Worker 接管所有路由 (2026-05-28)

  • 根因: /auth/register GET 無 return → fallthrough → Pages frontend 舊版 SPA;PAGES_URL 全站 fallback
  • 修復:
    • /auth/register GET 改為由 Worker fetch GitHub API 的 login.html 直接 serve
    • 移除 PAGES_URL fallback 代碼,unmatched route 改回 404
    • Dashboard 重整時無 token → 檢查 localStorage 後 redirect(不跳到 Pages)
  • 狀態: Pages frontend 完全脫離,所有請求由 Worker handle

Bug 9: 方案名稱 DB/前端不一致 — badge 顯示 “beta” (2026-05-28)

  • 根因: D1 仍存 plan="beta"plan="200"plan="adfree",但 Worker 已換新 key
  • 修復:
    • DB 執行 UPDATE accounts SET plan='promax' WHERE plan='beta'
    • UPDATE accounts SET plan='pro' WHERE plan='200'
    • UPDATE accounts SET plan='plus' WHERE plan='adfree'
    • Worker 端 plan label mapping 統一使用新 key
  • 新方案命名: Free / Plus (RM2) / Pro (RM3) / Pro Max (RM5)
  • 2026-06-01 价格升级: Free / Plus (RM4) / Pro (RM7) / Pro Max (RM10),Free 配额 100→10
  • 详见 projects/quotation-saas-complete.md 订阅方案章节

Bug 8: Markup % 更改不影響 item 計算 (2026-05-28)

  • 根因: applyMarkup() 硬編碼 const sell = ct * 1.25,無視工具列的 % 輸入
  • 修復: GitHub quote-app.js 改為 var mk = parseFloat(document.getElementById("mk-input")?.value||25)/100; const sell = ct * mk;
  • 效果: 改工具列的 % 後點 item markup 按鈕即套用新值

Bug 7: Avatar dropdown 無內容 + 無 Email 顯示 (2026-05-28)

  • 根因: 注入的 post-load script 未找到 dropdown 元素(舊版 mapping script 已改但 dropdown JS 未更新)
  • 修復: 在 loadQuotes() 後注入新的 account fetch JS,同時 fallback qs_token / token
  • 效果: Hover avatar 顯示 Email / 方案 / 推薦碼 / Logout

Bug 6: data.quotation.iddata.id 造成 Network error (2026-05-28)

  • 根因: saveQuote()data.quotation.id,Worker POST 返回 {id, success}(嵌套 quotation 已移除)
  • 修復: GitHub quote-app.js data.quotation.iddata.id
  • 效果: 新建報價 autosave 不再 Network error

Bug 5: 前端 PUT / Worker PATCH 不匹配 (2026-05-28)

  • 根因: saveQuote()method:'PUT',Worker route 只檢查 method === "PATCH"
  • 修復: Worker 端 request.method === "PATCH" || request.method === "PUT"
  • 效果: 編輯已有報價 autosave 不再 404

Bug 4: fmt() 殘留 → 25% 賣價歸零 (2026-05-28)

  • 根因: sellInput.value = fmt(sell) → 三位數以上有逗號 → type=number input 歸零
  • 修復: GitHub quote-app.js sellInput.value = sell.toFixed(2)

Bug 3: quote-app.js 開頭有 CSS 導致 JS 不執行

  • 症狀: Dashboard 點 “+New” 無反應
  • 根因: quote-app.js 前 7 行是 CSS(.section-block{...}),<script> 加載時報 Unexpected token '.'
  • 修復: Worker _app.js route 返回前切掉 // ─── CONFIG 之前的內容

Bug 2: Save 按鈕消失

  • 根因: HTML 硬編碼 style="display:none",gate 移除後沒補
  • 修復: Directly remove Save button (autosave 取代)

Bug 1: 重開網站顯示舊版 Pages frontend dashboard

  • 根因: 無 cookie → redirect /auth/register → Pages frontend → localStorage 有 token → 跳到舊 dashboard
  • 修復: / handler 無 cookie 時返回 localStorage 檢測頁面

Worker 崩潰歷史 (2026-05-28)

多次 -e 修補導致 Worker 損壞,以下功能丟失後重新加回:

  • Stripe webhook handler — 遺失
  • Stripe config vars (STRIPE_SECRET, PRICE_IDS) — 遺失
  • _app.js CSS 裁剪 — 遺失
  • requireAuth2() 函式 — 遺失
  • Pricing page — 遺失
  • /ads.txt route — 遺失
  • 教訓: 用檔案部署,避免 -e 片段修補
  • 症状: Dashboard 点击 “+New” 无反应
  • 根因: quote-app.js 在 GitHub 上前 7 行是 CSS(.section-block{...}),浏览器加载为 <script> 时报 Unexpected token '.' 语法错误,整个 JS 停止
  • 修复: Worker 的 _app.js route 返回前切掉 // ─── CONFIG 之前的内容
  • 涉及文件: Worker _app.js handler → fetch(GITHUB_RAW + "/quote-app.js")

Bug 2: Save 按钮永远 hidden

  • 症状: 编辑报价没有 Save 选项
  • 根因: HTML 硬编码 style="display:none",原版靠 gate 认证后显示,SaaS 版 gate 移除后没补
  • 修复: 既然有 autosave(3s),直接移除 Save 按钮
  • 涉及代码: Dashboard HTML patching

Bug 3: API 返回 data.id 但前端读 data.quotation.id

  • 症状: 新建报价 autosave 后显示 “Network error”
  • 根因: saveQuote()data.quotation.id,但 Worker POST /api/quotations 返回 { id, success: true }(没有 quotation 嵌套)
  • 修复: 在 _app.js 返回前做 string replace

Bug 4: 前端用 PUT 但 Worker 只处理 PATCH

  • 症状: 编辑已保存的报价 autosave 报 404
  • 根因: saveQuote()method: 'PUT',Worker route 只检查 method === "PATCH"
  • 修复: Worker route handler 同时接受 PUT 和 PATCH
  • 涉及代码: Worker quotations route handler

Bug 5: Save 按钮已移除(autosave 取代)

  • 确认 autosave 正常工作(编辑后 3 秒自动保存)
  • 直接从 HTML 中移除了 Save 按钮

新增功能 (2026-05-27)

Stripe 支付集成

  • 创建 Stripe Products/Prices(sandbox): Ad-Free RM2, 200 Quota RM3, Beta RM5
  • POST /api/create-checkout — 创建 Stripe Checkout Session
  • POST /api/webhook/stripe — Webhook 处理付款成功/取消
  • 订阅后自动更新 D1 accounts.plan + subscriptions
  • Price IDs:
    • adfree: price_1Tbg1T06BaZD1u5Pgy3MO5l7
    • quota200: price_1Tbg1U06BaZD1u5PZSMkwQd3
    • beta: price_1Tbg1U06BaZD1u5POR4Ip4as

Pricing 页面

  • /pricing 路由,4 方案卡片对比
  • Upgrade 按钮调用 /api/create-checkout
  • Dashboard 工具栏绿色 Upgrade 按钮(Free 用户显示)

Email 发送报价

  • POST /api/send-quote — 通过 Resend API 发送
  • Dashboard 工具栏 ✉️ Email 按钮
  • 弹出输入框填客户邮箱,自动生成报价 HTML 邮件
  • Resend Key: re_Qr5yUbT5_72JBvNPPskYK5qvEByNHJ6mS

Google AdSense

  • Auto Ads script 添加到所有页面 <head>
  • Publisher ID: ca-pub-8381241232407113
  • 覆盖页面: Dashboard, Pricing, Root (/)
  • 待 Google 审核通过后广告才会显示

推荐码系统

  • GET /api/referral-stats — 返回推荐码、人数、奖励月数
  • Dashboard 工具栏显示 🎯 推荐码 badge
  • 点击弹出分享提示(每 3 人送 1 个月)
  • 注册时支持 referral_code 参数

Worker 崩溃修复 (2026-05-28)

多次 -e 修补导致 Worker 代码损坏,以下功能丢失后重新加回:

  • Stripe webhook handler (/api/webhook/stripe) — 丢失
  • Stripe config vars (STRIPE_SECRET, PRICE_IDS) — 丢失
  • _app.js CSS 裁剪(+New 按钮修复)— 丢失
  • requireAuth2() 函数 — 丢失
  • Pricing page (getPricingPage) — 丢失
  • /ads.txt route — 丢失

修复方式: 完整下载 Worker 源码后直接插入缺失代码段,避免 -e 片段修补。

fmt() 殘留: 25% 賣價歸零 (2026-05-28)

  • 根因: sellInput.value = fmt(sell) 在 markup 計算後用 fmt() 設值,超過三位數產出逗號 → type=number input 歸零
  • 修復: GitHub 上改為 sellInput.value = sell.toFixed(2)

Worker PUT → PATCH 對齊 (2026-05-28)

  • 問題: Autosave 顯示 “Network error”
  • 根因: 前端用 method: 'PUT',Worker 只處理 PATCH
  • 修復: Worker PATCH handler 同時接受 PUT

hsdesign.biz landing page (2026-05-28)

  • 原 Cloudflare Pages 项目返回 500,改用 Worker 提供
  • Worker 从 GitHub raw 获取 index.html + 静态文件(图片等)
  • 注入 AdSense meta tag + script + 右上角报价工具链接
  • 将中文 hero 文案从报价营销改为公司介绍

Bug 6: 重开网站显示旧版 Pages frontend dashboard

  • 症状: 关闭浏览器再打开 quotation.hsdesign.biz,看到的是旧版报价工具(非 Worker dashboard)
  • 根因:
    1. 用户通过 token URL 参数登录(无 session cookie)
    2. 重开网站 → Worker 的 / handler 没找到 cookie → 重定向到 /auth/register
    3. /auth/register GET 没有 Worker handler → 落到 Pages frontend
    4. Pages frontend 的 JS 检查 localStorage 发现 token → 跳转到它的旧 dashboard
  • 修复: 修改 Worker 的 / handler,当没有 cookie 时返回一个检测 localStorage 的页面

Bug 21: Dashboard 按钮 onclick 调用缺失函數 — duplicateQuote() / showFeedback() 未定義 (2026-06-27)

  • 症狀: 切換瀏覽器/刷新後 Dashboard 空白 — 瀏覽器報 Uncaught ReferenceError: showFeedback is not definedduplicateQuote is not defined,JS 後續程式碼全部停止執行
  • 根因:
    • Dashboard HTML 模板中有 onclick="showFeedback()"(💬 按鈕)和 onclick="duplicateQuote()"(Duplicate 按鈕)
    • 但 GitHub JakeBilu/Landing-Page/quote-app.js(即 _app.js)缺失這兩個函式的定義
    • 瀏覽器解析到 onclick 時找不到函式 → 拋 ReferenceError → JS 停止 → Dashboard 白屏
  • 調查路徑:
    1. 搜索 _app.js(GitHub)→ 找不到
    2. 搜索 Cloudflare Worker 代碼 → 找不到
    3. 搜索 Dashboard HTML → 找到 onclick 引用,但函式不存在於任何 JS 檔案
    4. 結論:兩個函式從未被寫入 quote-app.js
  • 修復: 在 GitHub quote-app.jsdelQuote() 結束後插入兩個函式:
    • async function duplicateQuote() — 複製當前報價為新報價(POST /api/quotations),自動填入 “(Copy)” 名稱
    • function showFeedback() — prompt 收集用戶反饋,POST /api/feedback
  • Commit: 93cd063fd5b5JakeBilu/Landing-Page repo
  • 驗證:
    • CDN 傳播後 /_app.jsduplicateQuote 存在 ✅ showFeedback 存在
    • Node.js syntax check ✅
    • 瀏覽器登入頁面正常顯示
  • 涉及檔案: GitHub JakeBilu/Landing-Page/quote-app.js