specs/content-authoring.md

內容編輯(MDX)

一句話:內容編輯的 SSOT——後台 MDX 編輯器、public MDX 渲染、journal CRUD、tour 內容元件,以及 consent 內容的共用渲染。狀態看 roadmap,精確路徑看 code。

1. 核心原則

  • 內容模型 = MDX + 受控 component registry。編輯者透過工具列插入結構化區塊,不直接操作任意 React component。
  • Public render 是 server-side。前台只收到渲染結果;不把編輯器或 MDX runtime client JS 帶到公開頁。
  • Trip schema 不為版面細節開欄。itinerary、highlight、includes、difficulty 等內容放在 content_mdx,需要查詢的營運資料才進 schema。
  • Consent 內容集中管理。退改 / 同意文字由 consent template 擁有,tour 內容透過 <CancellationPolicy /> 引用最新有效版本。

2. 編輯管線

後台編輯器是 client island:

  • editor wrapper 負責載入 MDX editor、toolbar、hidden input;
  • prose 模式供 journal / consent;
  • tour 模式加入結構化區塊按鈕;
  • server action 只接收 MDX 字串,做 validation、permission、revalidate。

前台渲染管線:

  • server component compile MDX;
  • 只允許 registry 中的 component;
  • 以 slug / content id 設 cache tag;
  • 更新內容時 revalidate path + tag。

3. Tour 內容元件

Tour detail 支援下列 MDX 元件:

元件用途
Highlight圖文亮點段。
Itinerary / Dayday-by-day 行程。
Difficulty體能、技術、負重、海拔等級。
Includes團費包含 / 不包含。
CancellationPolicy讀取最新退改 / 同意模板。

這些元件是內容呈現,不是價格或營運資料來源。付款、訂金、團費包含的財務語意仍看 trip-pricing 與 order-money-model。

4. Journal

/admin/journal 是跨梯次內容管理,允許獨立 sidebar nav。

Journal 支援:

  • list / create / edit / archive;
  • draft / published / archived;
  • slug、summary、cover image、author guide;
  • public /journal/[slug] 只顯示已發布且到達 published_at 的文章。

權限應有獨立 content / journal resource;若 code 暫沿用其他讀權限,roadmap 應追技術債,不在本檔把 workaround 寫成設計。

5. 圖庫(/admin/images)

後台圖片資料庫,跨行程集中檢視 / 管理所有 trip 圖片(列表 + 行程 / 關鍵字 filter + 新增 / 刪除),權限閘 image.read(寫入 image.manage)。新增圖片支援檔案上傳與 URL 貼法並存:上傳走物件儲存 provider(local / GCS,packages/core/src/storage/),單檔上限+MIME magic-byte 白名單,object prefix 綁 physical db_name。實作在 src/app/(admin)/admin/images/page.tsx、repo packages/core/src/images/admin-repo.ts。共用快速圖片選擇器見 店面模板 §4;MDX 編輯器插圖已接入該 picker(URL 手貼保留為 fallback)。

6. 安全與限制

  • Registry 外的 JSX component 不渲染。
  • URL / image / link 要做 allowlist 或 sanitization。
  • Public render 不執行任意 client code。
  • 內容預覽與正式發布需走相同 render pipeline,避免後台可見但前台壞版。