一句話:多租戶前台的模板制 —— 內容頁每模板一套版型、交易鏈共構換 token、內容槽 per-tenant 編輯,取代寫死荒野的單一前台。
原 (public) 前台是為單一租戶寫死的門面,接第二個客戶時無法複用。目標:租戶從四個基礎模板(首波)選一個,換上自己的品牌內容即可開站;設計品質由模板保證(各模板有獨立的版型、palette 與字體性格),不開放租戶亂調視覺。
範圍切分:
四個基礎模板,code-level registry(typed,非 DB 資料):
| key | 定位 | 備註 |
|---|---|---|
outdoor | 戶外探險(大圖 hero、難度分級、梯次日曆) | 荒野的新家,第一個落地 |
resort | 旅宿度假(房型展示、訂房入口優先) | 房型區塊吃 lodging 資料;租戶無訂房模組時該區塊隱藏 |
minimal | 極簡通用 | 新租戶預設(tenant create --template,缺省 minimal);也是未知 key 的 fallback,永不可下架 |
voyage | 經典旅行社(目的地分類、行程表重點展示) |
每個模板宣告三樣東西:
模板與模組正交:模板不得假設任何模組(登山/海外/訂房)啟用,模組未授權時對應區塊靜默隱藏。
tenant_settings.storefront_template:text,模板 key。
值對不上 registry(打錯、模板改名/下架)時前台 fallback minimal 並記 log —— 門面降級不是整站 500,這裡刻意不 fail-closed(租戶身分解析仍 fail-closed,不受影響)。storefront_contents:窄表,per-tenant 內容槽值(slot_key text PK、value jsonb、updated_at)。只存租戶覆蓋值;預設值住在模板定義(code),讀取時 merge。
slot key 語意:全域命名空間、跨模板共用(hero_title 在任何模板都是同一格值);value 形狀由 slot 型別(短文 / 長文 / 圖片 URL…)定義、不隨模板而異,模板只決定用哪些 slot 與預設值;換模板保留既有值,日後換回仍在。tenant_settings 既有 company_name / logo_url / site_tagline / seo_default_description,不另建第二套。seo_default_description → 模板槽預設。模板槽預設恆非空,直接吃 merge 後槽值會讓站台級 SEO 預設永遠輪不到 —— 只有租戶真的填過該槽才優先。圖庫與物件儲存已落地,模型的 SSOT 在 content-authoring §5,此處不重複。本功能只疊加:
image.read、寫入(上傳)image.manage。刻意不做(等真實需求):裁切、容量配額、孤兒檔清理、引用計數、獨立媒體管理頁(/admin/images 既有頁即管理入口)。
/admin/settings 新增「店面(storefront)」tab(「外觀 appearance」已被後台色彩模式占用):選模板(儲存前可預覽)、編輯內容槽(圖片欄位走 picker)。isAdmin 二次守門),write action 掛 role.manage(同其他敏感 tab 慣例)。tab 清單與權限矩陣的 SSOT 在 settings §4。draftMode())而非公開路由參數,且不得寫進公開 cache。(public) 路由 request-dynamic、無快取層;日後若導入 storefront cache,切換模板/改內容槽需連帶失效。tenant create --template <key> 指定初始模板。apps/web (public) 內,不拆 storefront service(遵守 app-topology Phase 3 不提早拆的拍板)。主色/字型自訂(模板 palette 定死,ADR 0009)、section 組合式 page builder、媒體庫管理頁、storefront 獨立 service。
已定案(#75 從 outdoor 反推最小集):模板 palette 直接供應公開站 @theme 的
--color-* 變數(brand/bg/fg/line 三族+hover/alt/soft/muted 變體;狀態語意色
success/warning/danger 跨模板固定、不在集內),由 (public) layout 以 inline style
注入整棵樹 —— 內容頁與交易鏈同一個 seam,交易鏈不換結構只換視覺。具體集合與各模板
值住 code registry(STOREFRONT_THEME_TOKENS,registry 測試守門完整性);注入方式的
決策理由見 ADR 0010。
(slot 目錄與各模板選用清單已定案於 code registry —— code is truth,此處不重複。)