sitero-booking
v0.0.3
Published
`BookingPage` 與 `BookingManagementPage` 僅提供頁面內容,不含品牌 header 或網站外框。Consumer 請於 `app/booking/layout.tsx` 統一加入外框與樣式,讓 `/booking` 和 `/booking/manage` 共用 logo、名稱、背景與內容寬度。
Readme
sitero-booking
前台外框由 consumer 管理
BookingPage 與 BookingManagementPage 僅提供頁面內容,不含品牌 header 或網站外框。Consumer 請於 app/booking/layout.tsx 統一加入外框與樣式,讓 /booking 和 /booking/manage 共用 logo、名稱、背景與內容寬度。
Service description 增量
服務新增選填的純文字說明(最多 2,000 字),後台新增/編輯/詳情及前台服務選擇皆可使用。清空內容會保存為 null;舊呼叫未傳 description 時,更新保留原說明。既有預約快照不變。
部署本次程式前,請在 consumer 合併 BookingService.description String? 並建立 migration,或執行 增量 SQL,再重新產生 consumer Prisma client。套件不會自動修改資料庫。
Sitero Booking 的第一階段底層實作,尚未開放發布(private: true)。
一個套件內保留 domain / application / composition 邊界,重用
sitero-server 的 operation、executor、授權與結果契約。
已完成
- 每日 00:00–24:00 時段、每週生效版本與完整日期 override 解析。
- 真實時間區間的相接合併、半開區間衝突、兩種結束模式。
- 明確設定 buffer 與是否納入嚴格結束限制,不提供營運預設值。
createBookingServer:features.availability.check與resources.booking.create,目前都只接受可信的 admin context。- 建立時重新讀取排程資料、指定/自動選擇員工、保存 Service/取消政策 snapshot、計算 endAt/取消截止。
SchedulingQueryPort/SchedulingWritePort的隔離邊界。
Public entry points
sitero-booking:client-safe 型別與純排程函式。sitero-booking/server:操作 factories、ports、input/result 型別與 facade。
createBookingServer 必須注入兩個 scheduling ports 與明確的 adminRoles;空角色清單拒絕全部角色。省略 allocateStaff 時,未指定師傅的建立會透過 write session 的 loadDailyWorkload 使用當日最少服務分鐘數政策;Prisma adapter 已提供此能力。同分依 Staff ID 固定排序,指定師傅不改派。既有 allocateStaff 注入仍可用,供舊 consumer 相容;沒有工作量 port 也沒有注入策略時會拒絕自動分配。
Allocation 必須返回可用名單內的 ID,操作會再檢查;不設定隱藏的預設順序。
SchedulingSnapshot.policy 每個欄位都必須提供,包括明確的零 buffer。
時間與資料責任
resolveDailySchedule 處理當地日曆日期與 minute,沒有替店家選時區。
週五 18:00–24:00 和週六 00:00–02:00 分別解析後,必須由正式 time adapter
轉成實際時間,才能交給區間判斷。日曆日期驗證使用 UTC Date 只是日期運算,
不代表預設店家時區是 UTC。
Query port 必須提供完整服務與 buffer 範圍的有效工作區間、不可服務區間
以及所有占用(含 completed / no_show,排除 cancelled)。不能只讀開始日。
allowsStart 是可信資料來源根據 slot、advance、截止規則計算的決定;
caller 不能提交這個欄位。寫入時要在一致性範圍內重新計算,不能重用舊查詢。
候選開始時間的產生與以上營運規則實作尚待接入,目前 query 是單一開始時間檢查。
一致性與目前限制
SchedulingWritePort.run 必須包住最新資料讀取及寫入,且所有會影響
排程的其他操作遵守相同保護協定;成功提交、丟出錯誤回滾。
session.create 的正式 adapter 必須同時保存異動紀錄與通知意圖。
不在 transaction callback 寄信或執行其他外部效果。
已新增 PostgreSQL scheduling adapter,使用 SHOP advisory transaction lock,並以兩個 consumer Prisma client 驗證競爭與回滾。test-only serial in-memory adapter 仍用於單元測試。其他排程寫入操作與正式時間/接單 adapters 尚未完成,因此還不是完整 production persistence。 沒有提供可直接啟用的公開下單入口。
尚未實作:完整排程 writer 保護、正式時區與 slot 產生器、 Staff / Service 管理操作、改期與狀態操作、提交去重、管理 token、Email 投遞、 CMS / Web bridges 與 UI。因此不能直接部署成完整預約系統。
驗證
從 repository root 執行(需先有 sitero-server / sitero-domain 建置產物):
pnpm --filter sitero-booking type
pnpm --filter sitero-booking test
pnpm --filter sitero-booking build
pnpm --filter sitero-booking build:types
pnpm exec eslint packages/sitero-booking2026-09-22 已更新 workspace lockfile 並通過 frozen install(ignore-scripts)。 若 consumer 複製自其他目錄,請先安裝 workspace 依賴,避免沿用失效的 node_modules 連結。
Prisma schema
prisma/schema/ 包含從 sitero/prisma/schema/ 原樣複製的完整基礎模型,
新增模型集中在 Booking/,可用同一個 client 同時存取 Sitero 與 Booking。
prisma.config.ts 與既有 Sitero 使用同樣的多檔 schema 目錄方式。
新增資料:BookingStaff、BookingService、週班表版本/時段、日期 override/時段、 BookingBlockedInterval、BookingSettings、Booking。 Staff 不關聯 Admin;Booking 不新增會員或 Store 模型。
- 日期欄位用
@db.Date表達店家日曆日期,adapter 須映射成 YYYY-MM-DD。 - 實際預約與 block 用
@db.Timestamptz(3),工作時段用當日分鐘數。 - Snapshot 使用明確 scalar 欄位,adapter 再映射到 domain 的巢狀物件。
- EndBoundaryMode 的 Prisma enum 與 domain 字串需顯式映射。
- BookingSettings 僅有 SHOP scope;營運值不設隱藏預設。
- 索引與外鍵不等於防撞保證。分鐘範圍、正 duration、時間先後、週版本不可變、 排程重疊與並行寫入,仍須在 adapter/migration 的一致性設計完成。
- 已加入 BookingChangeRecord 與 BookingNotification;建立預約時與 Booking 一起保存。Token 與提交去重表尚未加入;通知投遞尚未實作。
pnpm --filter sitero-booking prisma:validate
pnpm --filter sitero-booking prisma:generateClient 產生在 prisma/generated/(gitignored),不作為前端或 domain 匯出。
目前未建立/執行 migration,也未連接資料庫。
套件 files 清單包含 schema,尚未發布。既有 consumer 只需合併 Booking 模型, 不要再次加入重複的 Sitero 基礎模型或 generator;最終 migration 由 consumer 管理。 基礎 schema 副本後續應隨 Sitero 版本同步,而非獨立修改成不同的核心模型。
2026-09-22 建立流程增量
- 單筆約定時長、buffer snapshot、電話選填;自訂時長與班表例外須提供原因。
- 新增
/core/server公開 PostgreSQL adapter 與結構化 Prisma client capability,型別不依賴套件生成的 client。 apps/sitero-base-2加入 schema、consumer client 型別驗證與隔離 DB integration script。- adapter 同交易寫入 Booking、異動紀錄與通知意圖,不在交易內寄信。
- 正式 admission/time adapter、其他排程 writer、CMS bridge 與 UI 尚未完成。
完整里程碑與限制見 實作進度。
最小 CMS 驗收介面
CMS sidebar 擴充:從 sitero-booking/cms/client 取得 useBookingNavItems,將回傳的 navItems 傳入既有 NavMain。Consumer 決定呈現位置;目前提供 Booking 分區與預約管理入口。從 sitero-booking/cms/i18n 匯入 bookingCmsMessages,透過 createCmsClientIntorConfig({ appName, messages: bookingCmsMessages }) 加入繁中、英文與越南文(vi-VN)翻譯;若 consumer 已有自訂 messages,需先合併再傳入。導覽沿用 sitero/cms/client/components 公開的 NavItem 型別,不代表操作授權。
新增 /cms/client 的 BookingDashboard 與 /cms/server 的 createBookingDashboardActions;consumer 只注入 actions,UI 不引用 Prisma 或 server facade。/core/server 提供明確時區轉換與列表 adapter。
apps/sitero-base-2 的 /cms/dashboard/booking-management/booking 已接共用 session。須明確設定 BOOKING_ACCEPTANCE_ADMIN_ROLES 並初始化確認可寫入的測試 DB;未設定時拒絕操作。步驟、資料與限制見 UI 驗收說明。初始化腳本尚未對 consumer 實際資料庫執行。
後台建立去重
CMS create action 要求 submissionId UUID,BookingDashboard 自動管理。核心 create command 為舊 consumer 保留選填,但省略時不提供去重保證;自訂 write adapter 若接受識別,須實作同交易 submissions.find/save。Prisma adapter 已提供,需新增 booking_submissions 表,見 增量 SQL。相同 actor/UUID/內容回原成立快照,回 replayed=true;不是目前預約狀態,也不取代查詳情或管理 token。成功紀錄隨 Booking 保留,失敗交易不留紀錄。
客人管理連結
選配 bookingLinkPort 提供 features.bookingManagement.issue/view/cancel。Prisma adapter 的 managementLinks 設定須一致注入建立與整合調整,確保政策快照、恢復撤銷與核發同交易完成;缺少已啟用連結的恢復設定時拒絕。Consumer 以 BOOKING_MANAGEMENT_SECRET 注入 64 位 hex 專用金鑰,效期採每筆 168 小時快照。新增 /web/client 的 BookingManagementPage 與 /web/server 的 createBookingPublicManagementActions;view/cancel 不要求 CMS session,但一定驗證憑證。新增資料表、金鑰與操作步驟見 驗收文件。公開建立與寄信仍未開放。
CMS 語系範圍
bookingCmsMessages 提供 zh-TW、en-US、vi-VN,沿用既有 booking.* key。
涵蓋後台預約建立、列表/篩選、時段查詢、管理連結、人員、服務、班表、
休息時段與預約狀態操作。帶有編號、人名、分鐘數或時區的訊息使用參數,
不在元件內拼接固定語序。日期時間的顯示語言跟隨 CMS,計算與輸入仍使用店家時區。
服務名稱、人員姓名與客人輸入屬於業務資料,維持原值。
Consumer 須將完整 bookingCmsMessages 合併到 CMS Intor 設定,並重新生成
consumer 的 Intor 型別。這些字典不會自動加入 Sitero 核心字典。
本次僅處理 CMS;顧客預約前台與 email catalog 維持各自的語系政策。
