跳到內容

hotel-cms 管理後台

飯店內部管理後台(多租戶 SaaS)。賣給多家飯店,每家登入只看到自己的資料。 是整個套裝的整合面:把 omni-bot(館內 bot)、travelplus-chatbot(網站 AI 客服)、 topreview-hotel(評論情報)接在一起,讓飯店 admin 在一個後台管理。

來源:hotel-cms/CLAUDE.md §0。

技術棧:Cloudflare Pages(Astro 6 SSR)+ Hono API routes + Svelte 5 + Drizzle(D1)+ KV(session)+ Logto 登入。

來源:hotel-cms/CLAUDE.md §1。

本頁是人類操作手冊。完整 step-by-step runbook 在 hotel-cms/documentation/deployment.md(D35); LLM/agent 工作合約在 hotel-cms/CLAUDE.md + 01-CLAUDE.md。本頁只引用,不重寫。


角色 看得到的範圍 授權真源
platform_admin(superadmin) 跨店,列全部飯店 requirePlatformAdmin / isPlatformAdmin(platform API)
manager / staff 只看 user_hotels 裡的店 resolveHotelOwner(admin API,session→user→hotel+bots)
  • 多租戶鐵則:所有 DB 查詢 WHERE 必含 hotelId/slug 過濾;無 hotelId 的查詢在 UI 即擋。

來源:hotel-cms/CLAUDE.md §2、§4。

  • ⚠️ superadmin 偵測走 Logto User role → id_token roles claim(roles: ["superadmin"]);動 platform 授權前 [MUST] 先讀 hotel-cms/CLAUDE.md §9 + TODO.md(雙路徑真源 src/lib/platform-org.ts)。

hotel-cms 採兩 checkout 完全隔離:單一真源 = origin/main,push 只在 dev checkout,prod checkout 只 pull→review→ship

環境 checkout CF 帳號 Pages URL 隔離
dev /home/peter/Code/hotel-cms-dev/ 獨立 dev 帳號 hotel-cms-dev.pages.dev 獨立帳號/D1/KV/Logto dev app
prod /home/peter/Code/hotel-cms/ prod 帳號 cms.h-ok.com 獨立帳號/D1/KV/Logto prod app
  • wrangler.tomlper-checkout gitignored(dev/prod 不同帳號 → 不同 D1/KV ID),由 ./scripts/ship.sh setup.env + wrangler.toml.example 生成;committed 只留模板。

來源:hotel-cms/documentation/deployment.md〈環境矩陣〉、hotel-cms/scripts/ship.sh


完整 step-by-step:hotel-cms/documentation/deployment.md〈部署指令〉。

Terminal window
# 首次 / fresh clone:生成 gitignored wrangler.toml + wrangler types + 裝 git hooks
./scripts/ship.sh setup # 需 .env 有 PAGES_PROJECT / D1_DATABASE_NAME/ID / KV_NAMESPACE_ID
# dev(checkout: ~/Code/hotel-cms-dev/)——不要求 main+clean
cd /home/peter/Code/hotel-cms-dev
./scripts/ship.sh dev # tsc→astro-check→lint→test→build→部署 hotel-cms-dev.pages.dev
# prod(checkout: ~/Code/hotel-cms/)——require main+clean + 全套 gate
cd /home/peter/Code/hotel-cms
git pull --ff-only origin main # ahead>0 = 有 prod-only commit,停下查
./scripts/ship.sh prod # → 部署 cms.h-ok.com

ship.sh 的 gate(checks())= tsc --noEmitastro checklinttest,任一失敗即停。

來源:hotel-cms/scripts/ship.shhotel-cms/documentation/deployment.md〈部署指令〉。

全域政策(2026-07-17 鬆綁):直接 npm run deploy / wrangler pages deploy 也是允許路徑;ship.sh 是可選保險(內建 gate),重大變更建議走。


完整表:hotel-cms/documentation/deployment.md〈Secrets 與變數〉;變數交叉一致見 hotel-cms/documentation/variables.md

Secrets(wrangler pages secret put,只 server via @/lib/runtime):

Secret 用途 輪換
SESSION_SECRET KV session cookie 簽章 定期
OMNIBOT_ADMIN_TOKEN 呼叫 omni-bot admin API 的 Bearer 與 omni-bot 同步
TPH_PROVISION_TOKEN 呼叫 topreview-hotel provision 與 topreview 同步
DEEPSEEK_API_KEY DeepSeek AI 文案/標籤 依 DeepSeek
SERVICE_TOKEN / PLATFORM_TOKEN provision / platform 內部 service-token 閘 定期
LOGTO_APP_ID/_SECRET OIDC Traditional Web app 憑證 與 Logto app 同步
LOGTO_M2M_ID/_SECRET Logto Mgmt API(成員邀請/預建帳號) 與 Logto M2M 同步
LOGTO_WEBHOOK_SECRET inbound Logto webhook HMAC 與 webhook 同步

Vars(wrangler.toml [vars],皆強制 https):OMNIBOT_BASE_URL(必填)、LOGTO_ENDPOINT(https://auth.h-ok.com)、PLATFORM_ORG_ID(必填;未設 → org-based 路徑 fail-closed)、DEEPSEEK_BASE_URLREVIEWS_BASE_URL/TPH_BASE_URL(optional)。

⚠️ secret 輪換後必須 redeploy——舊 deployment 拿不到新綁定。 來源:hotel-cms/documentation/deployment.md〈維運 Runbook〉。


migration 先行於 worker deploy(drizzle/*.sql,目前 0000–0006)。schema 變更後 prod 部署 [MUST] 跑:

Terminal window
npm run db:migrate:all # apply 全部到 remote(prod D1)
# 或單檔:wrangler d1 execute DB --remote --file=./drizzle/<n>.sql --yes
npm run db:migrate:local # local(dev D1)
  • 多數 migration 是 ADD COLUMN / CREATE TABLE IF NOT EXISTS(向前相容)→ code 容忍欄位缺失(shadow 共存不 crash),但功能在 apply 前不生效。

來源:hotel-cms/documentation/deployment.md〈Migration 順序〉〈回滾程序〉。


  • GET / 回 200;GET /api/auth/me(未登入)回 { user: null } 200
  • superadmin 登入 → /api/auth/merole: "platform_admin" + roles: ["superadmin"]
  • /admin 列出飯店清單(platform_admin 列全部)
  • 任一飯店 dashboard 可開、complaint list 可讀
  • Logto PostResetPassword webhook:合法簽章 → 200、錯簽 → 401

⚠️ auth/session 類變更上線後,既有使用者需登出再重新登入(舊 KV session 24h TTL 內不生效)。 來源:hotel-cms/documentation/deployment.md〈部署後驗證〉。


服務 接點 憑證
omni-bot admin API /admin/tenants/:storeId/...;一家飯店 = omni-bot 3 個 storeId(館內/客訴/評論) hotel-cms 持 OMNIBOT_ADMIN_TOKEN(Bearer);omni-bot 憑證不出 omni-bot
topreview-hotel 評論情報 dashboard(獨立部署);provision 走 TPH_BASE_URL TPH_PROVISION_TOKEN
travelplus-chatbot-api 網站 AI 客服(管理 API) (見 hotel-cms/CLAUDE.md §8)
  • content PUT 後清 KV tenant cache(omni-bot admin-worker 負責)。

來源:hotel-cms/CLAUDE.md §8。


  • log:Cloudflare Pages dashboard → project → Functions logs / Real-time logs;或 wrangler pages deployment tail
  • KV session 解析失敗:console.error[session] 前綴;Logto callback JIT 失敗 log [logto callback](只記 sub + errType,不記 PII)。
  • 作廢某 user 全部 session(移除成員/改密碼/緊急):程式 invalidateUserSessions(userId);手動 wrangler kv key delete --binding SESSIONS "session:<sid>"
  • 開新飯店 onboarding:/platform/hotels/new(platform_admin)或 scripts/provision-logto-demo.ts;模式判斷 decideOnboardMode(hotelExists)

來源:hotel-cms/documentation/deployment.md〈維運 Runbook〉。


  1. 🔴 禁 review gating——surveyResponses 設計(≤2 recovery、≥4 review),CMS 編輯守 invariant,不可引導留好評。
  2. 🔴 訂房不歸因——KPI/dashboard 不得出現訂房歸因數字。
  3. 🔴 回覆速度賣服務 SLA,不賴排名因子。
  4. 🔴 多租戶隔離——hotelId 查詢邊界。

來源:hotel-cms/CLAUDE.md §7。


本頁段落 repo 真源
概述/技術棧/架構決策/紅線/整合 hotel-cms/CLAUDE.md
環境矩陣/部署/secrets/migration/驗證/runbook hotel-cms/documentation/deployment.md
變數交叉一致 hotel-cms/documentation/variables.md
ship.sh 三模式 + gate hotel-cms/scripts/ship.sh
快速開始 hotel-cms/README.md

維護者:本頁內容變更時 [MUST] 同步確認上述 repo 檔仍指向正確段落,並更新 last_verified_head。跑 npm run check:cites 驗證。