旅客與個資
旅客是掛在訂單下的出行名單,不是帳號;他們的證件號、護照號是受保護的個資——平台只回傳遮罩值,要看明文得另外申請、而且每次都留稽核。
一筆訂單帶一份旅客名單(travelers[])。同一個人可能橫跨多筆訂單、出現為多筆旅客,所以旅客不是會員或客戶的錨點——它只描述「這筆訂單上要出行的這些人」。本篇說明旅客資料模型、增刪改、分房、個資揭露、證件效期與登山審核,以及會員端的 PDPA 自助。
旅客掛在訂單下
旅客沒有獨立資源,一律隨訂單帶出。讀一筆訂單 GET /orders/{id} 就拿到 travelers[],每位旅客包含:
| 欄位(回傳) | 意義 |
|---|---|
id | 旅客 id(在這筆訂單內) |
fullName | 姓名 |
idNumberMask / passportNoMask | 身分證 / 護照號的遮罩值(非明文,見下) |
birthDate | 生日 |
phone / email | 聯絡方式 |
emergencyContactName / emergencyContactPhone | 緊急聯絡人 |
gender | 性別(分房硬約束用) |
roomPreference / roommatePref / roomLabel | 分房偏好與已配房間 |
address | 通訊地址(入山 / 投保名冊用) |
isPrimary | 是否為訂購人本人 |
會員 ≠ 旅客。會員(members)是登入帳號、是訂單的訂購人;旅客是那筆訂單上實際出行的人。一個人可以同時是會員與旅客,但兩者在資料上是分開的——別拿旅客當客戶主檔。
新增、更新、移除旅客
旅客的增刪改都掛在訂單下,且都要求 order.update 權限:
| 操作 | 端點 |
|---|---|
| 新增旅客 | POST /orders/{id}/travelers |
| 更新旅客 | PATCH /orders/{id}/travelers/{travelerId} |
| 移除旅客 | DELETE /orders/{id}/travelers/{travelerId} |
新增 / 更新可帶 fullName、phone、email、birthDate、emergencyContactName、emergencyContactPhone、gender、address,以及 idNumber / passportNo(證件號,寫入即加密保存)。POST 回傳新建的 travelerId。
curl -X POST "https://your-tenant.example.com/api/v1/orders/$ORDER_ID/travelers" \
-H "Authorization: Bearer $CAIRN_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "fullName": "王小明", "birthDate": "1990-05-30", "idNumber": "A123456789" }'
旅客名冊有可改窗口:出發前約一週仍可調整(給入山證、投保名冊留緩衝),逼近出發後修改會被收斂。建檔時平台會逐欄檢查(身分證檢查碼、生日合理性、緊急聯絡人不可是同團隊員等)並把問題標出來,但不會擋存——你可以分次把資料補齊。
分房偏好
分房偏好可在新增 / 更新旅客時一併帶,也可以單獨用 PATCH /orders/{id}/travelers/{travelerId}/rooming(同樣 order.update)只改 roomPreference / roommatePref。gender 是分房的硬約束、roomLabel 則反映實際配到的房間——實際配房作業在團控端進行,這裡只負責表達偏好。
個資的揭露與授權
證件號與護照號是受保護的個資:平台加密保存,列表與訂單詳情一律只回遮罩值(idNumberMask / passportNoMask)。要看明文,得針對該旅客、該欄位單獨申請:
POST /orders/{id}/travelers/{travelerId}/reveal 帶 field(idNumber 或 passportNo),回傳 { field, value }。
揭露明文是 order-scoped 授權 + 留稽核的操作:你只能揭露你看得到的那筆訂單上的旅客,且每一次揭露都會記進稽核軌跡(防止有人靠猜 id 跨訂單撈個資)。reveal 要求 order.read,但它不是免費的讀——把它當成「需要時才申請、會被記錄」的動作,不要批次預先解密整份名單。
證件效期提醒
海外團多數國家要求入境時護照效期還有半年以上。當海外模組啟用時,平台用旅客的護照到期日比對出發日,被動標出「效期不足 / 出發前已過期」,門檻(預設約 180 天)可由租戶調整。
跨梯次想一次撈出「名下有即將出團、且護照效期會出問題」的會員,用 GET /members/expiry-warnings,回傳一組 userIds,再順著會員去查對應訂單與旅客。效期欄位本身隨旅客更新(沿用上面的旅客更新端點),未填到期日視為「未知」、不算警示。
登山審核
當登山模組啟用、且行程標了難度時,建立訂單會自動跑一次資格審核:以客人的登山經歷(自填 + 過往完成的訂單)算出能力分,對照行程難度給出判定。判定不硬擋下單——能力不足只會標記為待人工審核。
訂單上的審核結果有幾種:not_required(行程未評級)、auto_pass(自動通過)、needs_review(待人工)、manual_approved / manual_rejected(人工核可 / 駁回)。needs_review 的單由有權限者用 POST /orders/{id}/review-screening(screening.review)核可或駁回。
審核不擋金流、不擋建單——它是安全把關的提醒,不是付款前置條件。一筆 needs_review 的訂單照樣能收款,由團隊在出團前處理(補經歷、勸退、或改報難度較低的團)。
會員與 PDPA 自助
會員(訂購帳號)這一側透過 members 資源讀取:GET /members 列表、GET /members/{id} 取單一會員(含其訂單、同意書 consents)。回傳欄位含 pdpaSignedAt(同意條款時間)與 anonymizedAt(是否已被匿名化)。
會員享有 PDPA 的兩項基本權利,平台都支援:
- 資料可攜:匯出該會員名下的帳號、訂單、旅客、同意與金流紀錄。
- 終止 / 刪除權:
POST /members/{id}/anonymize(member.update)做真正的匿名化軟刪——抹除可識別 PII(會員與其名下旅客)、封鎖登入、撤銷憑證。
匿名化會保留訂單外殼、金流與請款紀錄、不可竄改的同意書與稽核——這些是法遵與對帳必須留存的軌跡。換句話說:人被去識別化,但帳務與「曾取得同意」的證據完整保留。匿名化不可逆,呼叫前請確認。
下一步
- 訂單與金流模型:旅客所掛的訂單外殼、應收與收款、狀態與退款。
- orders API:旅客子路由(travelers / reveal / rooming)與審核端點的逐欄參數。
- members API:會員列表、明細、效期提醒與匿名化。