題幹與適用場景
訂單系統每天產生 2 億筆交易。內部帳本記錄訂單、支付、退款和手續費;支付服務商按結算批次提供報告;銀行提供實際入帳流水。請設計一條 T+1 對帳管道,在次日 6 點前完成前一日資料,識別漏記、重複、金額、手續費和幣別差異,支援重跑、人工覆核、退款、多幣種和稽核留痕。
題目預設內部帳本是業務事實來源,支付商和銀行是外部事實來源。對帳結果不能直接覆蓋帳本,也不能因為總額相等就隱藏單筆差異。金額、幣別、結算日、批次和證據鏈必須可追溯。
面試官考察點
第一項是能否先定義事實、時間和不變條件。候選人應區分交易發生日、入帳日、結算日和銀行價值日,並明確金額使用最小貨幣單位、幣別不可省略、同一外部流水可重複匯入。
第二項是能否把匹配從「全表 join」變成分層策略。先用支付商交易 ID、批次 ID 等強鍵匹配,再用受限的訂單號、金額、幣別和時間窗口匹配;模糊匹配必須進入人工佇列,不能靜默自動確認。
第三項是能否設計差異閉環。差異要有類型、嚴重級別、證據、負責人、狀態、截止時間和修復動作;修復後仍要保留原始差異與新的對帳版本。
回答前需要澄清的問題
- 對帳邊界是什麼? 是支付授權、捕獲、退款、手續費、出金,還是銀行入帳全部涵蓋?
- 6 點截止按哪個時區? 結算日和報告生成日是否跨越夏令時間或假日?
- 外部報告是否可增量取得? 是否有穩定檔名、游標、版本號和重試下載介面?
- 允許自動調整帳本嗎? 預設只產生待處理調整單,由有權限的流程核准後入帳。
- 多幣別按什麼匯率? 交易幣別、結算幣別和銀行入帳幣別是否都要保留,匯率來源和精度是什麼?
- 差異多久必須解決? 需要定義高金額、法遵和客戶影響差異的升級路徑。
30 秒回答框架
「我先把三方事實保存為不可變原始層,再統一金額、幣別、時間和外部 ID。管道按報告版本冪等匯入,先用強鍵匹配,再用受限組合鍵匹配,任何不確定結果進入人工佇列。每個批次同時做行級、分組和總額校驗,差異以可稽核狀態機管理,修復透過核准後的調整單完成。排程上按截止時間倒推,監控檔案完整性、延遲、匹配率、未決金額和重跑次數,並用重複檔案、晚到退款、部分結算和匯率變化做演練。」
分步驟深入解答
第一步:定義事實模型和帳期
建立 internalentry、providerentry、bank_entry 三類不可變事實,統一保留原始檔案雜湊、行號、來源、抓取時間、報告版本、業務日期和結算日期。金額使用整數最小貨幣單位,禁止用浮點數;幣別作為必填欄位。內部帳本的訂單狀態與資金狀態分開,避免把「支付成功」誤當成「已入帳」。
第二步:按來源版本冪等接收
下載任務先寫入物件儲存,再校驗檔案大小、雜湊、簽章和預期行數。以 source + reportid + version + rownumber 建立唯一鍵,重複下載只增加接收記錄,不重複記帳。供應商提供的報告版本變化要保留舊版本,並記錄替換關係,禁止原地覆蓋。
unique_key = source + report_id + version + row_number
if unique_key already exists: record_duplicate_download()
else: persist_raw_row()第三步:建立可重跑的標準化層
標準化層將狀態、金額符號、時區、手續費類型和外部 ID 映射到版本化字典。每次轉換寫入 normalizationrunid,輸入快照和規則版本固定後可以重跑。無法識別的狀態、負金額語意或未知幣別進入隔離區,不應被預設轉成零。
第四步:採用分層匹配策略
第一層使用支付商交易 ID、退款 ID、出金 ID 等穩定強鍵。第二層在同一商戶、幣別和結算日內使用訂單號、金額和允許的時間窗口。第三層只產生候選對,不自動確認;金額相同但幣別不同、一筆內部單對應多筆外部單,或一筆外部單拆成多次結算,都進入人工覆核。
第五步:用三層控制證明結果
行級控制檢查每條事實是否最多匹配一次。分組控制按批次、幣別、結算日和手續費類型比較筆數與金額。總額控制比較內部帳本、支付商報告和銀行入帳的期初、流入、流出、手續費、退款與期末餘額。三層不一致時保留各層證據,不能只展示一個「通過」標記。
第六步:把差異做成狀態機
差異類型至少包括缺失、重複、金額不符、手續費不符、幣別或匯率不符、日期錯位和未知外部狀態。狀態可以是 open、investigating、adjustment_pending、resolved、accepted,每次變更記錄操作者、理由、證據和時間。高金額或法遵差異需要雙人核准,自動任務只能建立調整建議。
第七步:處理晚到、退款和部分結算
報告晚到時先關閉已收到範圍,保留批次為未完成,不能把暫時缺失當成永久漏記。退款和爭議可能在原交易日之後出現,要透過事件日期與結算日期分別入帳。部分結算要保留外部批次與內部交易的一對多關係,餘額相等也不能抹掉未匹配行。
第八步:安排恢復、重跑和稽核
每個執行保存輸入檔案清單、快照時間、規則版本、匹配結果和輸出差異。失敗後從最後一個成功階段重跑,重跑結果透過執行 ID 隔離,再以唯一鍵合併。保留原始檔案、雜湊、報告版本、人工決定和調整憑證,支援按批次、交易和差異追溯。Stripe 的報告也將餘額、交易和 payout 分開,並建議使用 payout ID 關聯其中的 balance transactions,這說明外部結算批次不能被簡化成一個總金額。
設計取捨與邊界
取捨一:強鍵優先還是更高匹配率
強鍵匹配的自動化率可能較低,但誤配成本可控。擴大金額和時間窗口會提高匹配率,也會增加把兩筆相似交易錯誤合併的風險。應把閾值、窗口和回退規則配置化並版本化,所有非確定匹配進入人工佇列。
取捨二:每日批處理還是準即時
T+1 批處理更容易重現和稽核;準即時流可以更早發現高金額差異,卻需要處理報告版本變化、晚到資料和重複事件。可以先用批處理作為帳務結論,再用流做預警,避免把預警當成最終對帳結果。
取捨三:自動調整還是人工核准
小額、規則明確且可逆的差異可以進入受限自動調整;高金額、幣別異常、重複扣款和法遵相關差異必須人工核准。無論哪種路徑,都保留原始事實和調整憑證,不修改歷史行。
失敗演練與演進計畫
演練一:重複檔案和重複行
連續投遞同一報告三次,驗證檔案雜湊、報告版本和行唯一鍵不會產生重複帳。再讓同一交易出現在兩個版本,驗證版本關係和最終選用規則可解釋。
演練二:晚到退款與部分結算
讓退款在結算日後兩天到達,並把一筆訂單拆到兩個 payout。驗證交易日、結算日和入帳日分別統計,差異在新執行中關閉而歷史執行保持不變。
演練三:報告缺頁和錯誤匯率
刪除一頁報告或替換匯率表,驗證行數、雜湊、總額和幣別控制會阻斷發布,並把批次標記為待補數,而不是產生「已對帳」。
常見誤區與追問
誤區一:只比較三方總額
總額相等時仍可能存在一筆漏記和一筆重複。必須保留行級匹配、分組控制和總額控制。
誤區二:用浮點數存金額
浮點誤差會製造虛假差異。金額應使用整數最小單位或定點數,並同時記錄幣別。
誤區三:覆蓋舊報告
覆蓋會破壞稽核和重跑依據。報告應不可變保存,以版本關係表達更正。
誤區四:模糊匹配自動入帳
相同金額和相近時間不等於同一交易。模糊結果應進入人工覆核,並顯示候選證據。
誤區五:把支付成功當成銀行入帳
支付狀態、支付商結算和銀行入帳是不同事實,必須分別建模並用批次關係連接。
誤區六:忽略報告生成和時區
報告可能在結算日後才可用,跨時區和假日會造成假性漏記。排程應使用來源承諾時間,並顯式保存時區。
誤區七:修復時直接改歷史帳
直接改歷史會失去原始證據。修復應透過核准後的調整單,並關聯原差異和新執行。