線稿索引所有 spec最後更新 2026-06-24
specs/departure-prep.md

出團前置作業

一句話:每梯次的出團備辦工作台(/admin/control/[depId]/departure-prep)—— 行前總檢查 / 證件追蹤 / 領隊協作 / 裝備需求調查 + 四軸營運作業(對款 · 派車 · 餐食 · 投保)。核心骨幹(對款 / 派車 / 餐食 / 投保 / 換領隊 / 行前檢查)不受任何模組 gate;只有入山/入園/山屋/登山險 deadline + 許可證文件 + 人頭使用次數限制屬登山專屬子集,受 模組化 的「登山」開關 gate。

  • 關聯:證件效期提醒(只做護照效期,海外模組;與本檔互補不重疊)· 出團名單 / 旅客 · 裝備庫存彙總(裝備需求調查 = 本檔「裝備」軸)· 內外帳(成本登記入口,本檔對款 tab 只唯讀派生)· 團控財務(departure_costs / payables)
  • 動機來源:GS「總表」deadline 警戒 + 「0501玉山」單梯次出團前準備工作表(對款 / 領隊異動 / 入山入園證 / 訂餐 / 投保旅平·旅責 / 車資 / 住宿對款)。

1. 核心骨幹 vs 登山專屬子集(gate 分界)

2026-06-23 user 裁決「登山是獨立可拆模組」:抽掉登山模組,出團準備的核心骨幹照常可用。本檔把功能切成兩半:

區塊屬性gate
行前總檢查 checklist(8 項)核心無
領隊協作 / 換領隊(roster)核心無
對款(團費收齊 + 供應商 / 裝備住宿對款,唯讀派生)核心無
派車(台鐵 / 接駁 / 車資營運資訊)核心無
餐食(訂餐 / 供應商 / 飲食禁忌)核心無
投保(旅平險 per-head + 旅責險 per-梯次)核心無
證件追蹤(入山證 / 入園證 / 床位核准證 / 營位核准證)登山專屬登山 gate
deadline 警戒(入山申請 / 入山下載 / 登山險 / 旅責險工作天倒數)登山專屬登山 gate
人頭使用次數限制(國家公園 permit 配額,以身分證計次)登山專屬登山 gate(enforcement 隨 climbing/lottery epic)
裝備需求調查 + 跨梯次彙總登山專屬登山 gate(見 equipment-inventory)

旅責險本身是所有出團團都要的(per-梯次旅行業責任險),故「投保」軸屬核心;登山險(per-head 山域意外險)的 deadline 警戒才屬登山子集。投保軸的 departure_insurance 二類(旅平 / 旅責)核心永遠在;登山團多一條登山險 deadline。

2. 落地資料模型

行前檢查 / 證件 / 裝備需求三表 + 四軸營運資訊表皆已落地(schema 在 packages/core/src/schema/business.ts,repo 在 packages/core/src/departure-prep/repo.ts)。

2.1 行前總檢查 departure_prep_checklist

8 固定檢查項(CHECKLIST_ITEM_KEYS):payment / leader / transport / meal / insurance / documents / equipment / roster。toggle 勾 / 取消勾(upsert,UNIQUE departure_id + item_key);勾起記 checked_at + checked_by_user_id。

2.2 證件追蹤 departure_documents(登山子集)

4 種證件(DOCUMENT_TYPES):入山證 / 入園證 / 床位核准證 / 營位核准證。每種一列(upsert,UNIQUE departure_id + doc_type),追蹤申請狀態 apply_status(todo / applying / approved,時間戳只前進不回退、且只在有帶 status 時觸碰)、file_ready / uploaded_to_cloud / file_uri(Drive 連結)/ note。upsertDocument 是真部分更新:undefined = 該欄不動(ON CONFLICT 的 SET 逐欄 dynamic,未帶欄保留既有值)、null = 顯式清空——API / CLI 只更新單一欄位不會抹掉其他欄。

2.3 裝備需求調查 departure_equipment_needs(登山子集)

見 equipment-inventory §4:per-departure 需求列 + summarizeEquipmentDemand 跨梯次彙總(surplus / shortage / 剩餘≤2 lowStock)。

2.4 四軸營運作業(核心,皆 per-departure「營運資訊」,不存成本)

成本一律走 departure_costs(登記在團控成本頁 / 嚮導 portal,分析在內外帳 nav),這三表只記營運欄位與完成狀態 —— *_note 是純文字備註,不是金額成本欄。

  • 投保 departure_insurance:kind(travel_accident 旅平險 / liability 旅責險)、insurer、policy_no、status(pending → done)、note。被保人身分證走既有 traveler reveal + audit,不在此表存 PII。保費成本走 departure_costs(category='保險',見 internal-external-ledger 的旅平 / 旅責 insurance 維度)。
  • 派車 departure_transport:description(上下車 / 路段)、driver_name、vehicle_info、fare_note(純文字車資備註)、status(pending → arranged)。車資成本走 departure_costs(category='交通')。
  • 餐食 departure_catering:supplier、meal_plan、headcount_note、status(pending → arranged)。飲食禁忌仍在 travelers 備註,不在此表。餐費成本走 departure_costs(category='餐飲')。

2.5 對款(唯讀派生,核心)

對款 tab 不寫任何成本 / charge,純讀的對帳檢查視圖:團費收齊度(getDepartureFinanceSummary 派生自金流模型)+ 供應商 / 裝備住宿應付未付(listDepartureCostRecon 把 departure_costs 與其轉出 payables 核付狀態 join,派生每列 paidState:paid(payable 已核付)/ billed(已轉未付)/ unbilled(未轉),彙總已付 / 未付)。成本的登記 / 編輯入口在團控成本登記頁(/admin/control/[depId]/costs,departure_cost.create)與嚮導 portal(2026-06-24 決策反轉「成本只在內外帳 nav」,見 internal-external-ledger §4);對款 tab 仍維持唯讀對帳,不重做成本 CRUD(避免兩入口打架)。淨利分析 / 證明單核簽仍在內外帳 nav(admin / accountant)。

2.6 deadline 警戒(登山子集)

GS「總表」對每團每類期限用 NETWORKDAYS.INTL(TODAY(), 期限, 假日表) 算工作天倒數,輸出醒目色狀態。

期限已 per-tenant 目錄化(原 departures 上寫死荒野模式的四根 deadline 欄已移除,違反多租戶開放性):

  • departure_deadline_types(per-tenant 期限目錄):key PK / label / sort_order / is_active。租戶自定自己的期限種類(荒野的「入山申請 / 入山證下載 / 登山險 / 旅責險」只是 seed 範例,非平台枚舉);新增期限種類零 ALTER。
  • departure_deadlines:composite PK (departure_id, type_key)(每梯每類一列),type_key FK → 目錄(restrict)、deadline_date。
  • 部分更新語意:setDepartureDeadlines 只動有帶的 key(未帶不動、null 清除)。
  • 停用規則:目錄停用(is_active=false)不刪既有 deadline 列;停用類型不可新指派(INACTIVE_DEADLINE_TYPE)但既有列可覆寫 / 清除;倒數列表顯示「啟用中類型 ∪ 已有日期的類型」。刪除類型被引用時擋 IN_USE(FK restrict 兜底),改走停用。

工作天倒數查詢時計算(getDepartureDeadlineCountdowns,不落 DB,對齊證件效期),底層純函式 workingDaysUntil(packages/core/src/workdays.ts:扣週末 + 國定假日、補班日照算,4000 天防呆上限);今天用 Asia/Taipei 牆鐘日;色階門檻 deadlineTone:< 0 逾期 / ≤ 3 緊迫 / ≤ 7 注意 / 其餘充裕。團控「期限警戒」tab(prep-tabs.tsx,只在 climbingActiveFor 渲染 TabsTrigger + TabsContent)顯示倒數表 + 逾期/緊迫 Alert + 「設定期限」dialog(setDepartureDeadlinesAction,departure_prep.manage + requireClimbingModule 雙閘)。國定假日 / 補班來源見 §2.7。

2.7 國定假日 / 補班表 public_holidays(deadline 倒數的資料源)

per-tenant 表(date 自然鍵 / name / is_workday):is_workday=false 國定假日(不計工作天,即使平日)、true 補班日(彈性放假補上班的週末,照常計入工作天)。維護在獨立頁 /admin/holidays(跨梯次參考資料,比照團號對照表走獨立 nav,requiresClimbing 登山 gate 隱藏;public_holiday.read 檢視、public_holiday.manage〔op / admin〕維護,寫入 action 另過 requireClimbingModule)。資料源為荒野現行 GS「小編用」分頁,小編每年初匯入;未維護的年度 → 倒數僅扣週末(保守,不誤報)。repo:listPublicHolidays / getHolidayYearStats / upsertPublicHoliday(date upsert 覆寫)/ deletePublicHoliday / loadHolidayCalendar。

3. 角色 / 權限

  • 工作台 read 閘 departure_prep.read;四軸 / checklist / 證件 / 裝備需求寫入走對應 departure_prep.* action(requirePermission(resource.action))。
  • 對款 tab 唯讀 —— 成本寫入(order.adjust / departure_costs CRUD)只在內外帳 nav,accountant 唯讀、sales 無、admin / op 可寫(見 control-finance §3)。
  • audit 由 action 層寫(比照 departure-costs / equipment)。

4. UI

UI 真相在 apps/wireframes/app/admin/control/page.tsx + /admin/control/[depId]/departure-prep。Tab 結構:核心永遠列(名單 & 總檢查 / 領隊 & 協作 / 對款 / 派車 / 餐食 / 投保),登山專屬僅 climbingActiveFor 時列(證件追蹤 / 裝備 & 住宿)。行前總檢查的 documents / equipment 兩項(入山證 / 登山裝備)同樣只在登山生效時納入分母。對款 / 派車 / 餐食 / 投保 / 證件四軸的 CRUD 走 requirePermission('departure_prep.manage'/.read)(對款唯讀)。per-departure 批次處理一律從 /admin/control 進,不開獨立 sidebar nav。

5. 連結

  • 來源:legacy-gs-gap §2.2(deadline 警戒)· §2.4(許可證文件)· GS 結構盤點 §11(0501玉山工作表)
  • 互補:document-expiry(護照效期,海外模組,不重疊)
  • 成本 / 對款:internal-external-ledger、control-finance
  • 裝備:equipment-inventory
  • gate:modules §2 / §3.3(核心骨幹不 gate,登山子集過登山閘)
  • 輔助資料:GS 小編用(假日表)—— 已建可編輯 public_holidays 表 + /admin/holidays 維護頁(§2.7);小編每年初匯入官方國定假日 / 補班