September Memo:從熟悉技術,到開始理解一個系統

今年的九月對我來說是一個滿特別的月份,因為加入新的工作環境,我開始接觸一套自己並不熟悉的系統;雖然 C#、ASP.NET、SQL、Web API 這些技術本身並不陌生,但真正需要花時間的,其實不是重新學習這些技術,而是要在有限的時間裡,快速理解一個已經運作中的系統。 回頭看這一個月,做的事情其實滿分散的:分析系統架構與流程、整理文件、研究程式碼效能和雲端成本、進行壓力測試、SQL 移轉 Stored Procedure、補上參數驗證與一致性測試,以及研究 Stored Procedure 的版本控管與 CI/CD;如果單獨看每一件事情,好像彼此之間沒有太大的關係,但把它們串起來之後,這些工作都在做同一件事情:讓自己盡快建立起對這套系統的完整理解,從一個剛加入團隊、還在摸索系統的人,慢慢變成一個可以開始參與改善的人。 剛開始接觸系統時,我花了不少時間去追 API 的執行流程,從 Web API 的入口一路往下看,理解不同 Layer 之間的關係,以及商業邏輯、資料存取和資料庫之間是怎麼串起來的,這個過程也讓我再次感受到,「看懂程式碼」和「理解一個系統」其實是兩件不同的事情;單純知道某個 Method 做什麼,並不代表知道它為什麼會這樣設計,也不代表知道它和其他功能之間有什麼關係,所以這次我比較在意的,不只是把單一功能看懂,而是試著建立整個系統的心智模型:資料從哪裡進來、經過哪些處理、最後流向哪裡,以及不同元件之間是怎麼互相影響的。 在這個過程中,我也開始整理系統架構與流程文件,對我來說文件不只是提供給其他人看的東西,也是一種驗證自己理解是否正確的方法;當我必須把一個複雜的流程整理成可以說明的架構時,往往也會發現自己其實還有一些地方沒有真正理解,也因此這個過程並不是單純把程式碼看過一遍,而是透過整理和描述,把原本零散的資訊慢慢組合成比較完整的系統觀。 從程式碼往外看,開始理解系統的另一面 當對系統有了基本理解之後,我開始關注的不再只是「這段程式碼能不能正常運作」,而是它實際執行時會產生什麼影響,某些程式碼的執行效率會影響 CPU、Memory、Database、I/O 或 Network 的資源使用,而當系統運行在 Cloud 環境時,這些資源消耗最後也可能反映在雲端成本上;這讓我開始用不同的角度看程式碼:如果這段程式碼的執行效率不好,在系統規模變大之後會發生什麼?如果 Request 數量增加,資源消耗會怎麼變化?這些變化最後又會不會轉化成實際的營運成本? 也就是在這個階段,我開始把原本比較單純的「程式碼 → 功能」,慢慢延伸成「程式碼 → 執行效率 → 資源消耗 → 系統運作 → 雲端成本」;這種思考方式和單純看程式碼本身不太一樣,因為開始需要把 Application、Database 和 Infrastructure 放在同一個脈絡裡看。 除了分析程式碼和架構之外,這個月也開始接觸壓力測試,這對我來說也是一個滿有意思的轉變,因為在看程式碼時,我們很容易根據邏輯去推測系統應該會怎麼運作,但真正把系統放到一定的負載下之後,才會知道原本的假設是不是成立;透過壓力測試,我開始關注 Response Time、Throughput、Concurrency、Resource Utilization,以及系統在高負載下的行為:哪些地方會成為 Bottleneck?當同時處理的 Request 增加之後,哪一層會先出現問題?資源使用量和效能之間又是什麼關係? 這也讓我更加確定,寫出一個「可以正常運作」的系統,和真正知道它「在壓力下會怎麼運作」,是兩件不同的事情;前者比較像是確認功能正確,後者則開始涉及系統實際運作時的行為,而這也是我以前比較少從這個角度去思考的事情。 從 SQL Migration 開始,看見更多工程問題 這個月另一個比較有感的工作,是把原本由應用程式組合 SQL Command 的方式,逐步移轉到 Stored Procedure;一開始看起來只是一個 SQL Migration,但實際做下去之後,很快就會牽涉到更多問題:原本的行為能不能完整保留?Parameter 要怎麼處理?缺少 Parameter 時應該怎麼驗證?修改之後又要怎麼確定新舊實作的結果一致? ...

2026年10月4日

支付對帳系統設計之二:資料庫 Schema 與 .NET

上篇說明了對帳系統的概念模型:三本帳的關係、以結算日為基準的決策、日終對帳的五個步驟、軋差計算與差異單的分類處理,這些概念是設計實作的地基,這篇則著重於如何把地基變成可以執行的系統;本篇的重心有以下四個:對帳系統需要的核心資料表、確保批次作業可以安全重跑的冪等性設計、完整的比對與軋差驗算邏輯,以及多閘道報表匯入的介面抽象。 核心資料表設計 orders 和 refunds 表負責提供系統帳的資料來源,對帳系統在此之上還需要建立四張專屬資料表。 gateway_transactions(閘道交易記錄) 這張表儲存從閘道報表匯入的原始交易資料,是串聯系統帳和銀行帳的橋樑: 1CREATE TABLE gateway_transactions ( 2 id UUID PRIMARY KEY DEFAULT gen_random_uuid(), 3 gateway_name VARCHAR(50) NOT NULL, -- 'stripe', 'tappay', 'jkopay' 4 gateway_txn_id VARCHAR(100) NOT NULL, 5 order_id UUID REFERENCES orders(id), 6 amount DECIMAL(12,2) NOT NULL, 7 fee DECIMAL(12,2) NOT NULL DEFAULT 0, 8 net_amount DECIMAL(12,2) NOT NULL, -- amount - fee 9 txn_type VARCHAR(20) NOT NULL, -- 'payment', 'refund', 'chargeback' 10 settlement_date DATE NOT NULL, 11 imported_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), 12 UNIQUE (gateway_name, gateway_txn_id) -- 防止重複匯入 13); settlement_date 是這張表最重要的欄位,比對邏輯和軋差計算都以它為基準,對應上篇說明的「以結算日為基準」決策;UNIQUE (gateway_name, gateway_txn_id) 則確保同一筆閘道交易不會被重複匯入,給匯入流程天然的冪等性保障。 ...

2026年7月12日

支付對帳系統設計之一:概念模型、日終流程與差異分類

支付系統有一條不成文的鐵律:技術再先進,最終商家在意的只有錢有沒有進來、以及進來的金額對不對;對帳系統(Reconciliation System)就是回答這兩個問題的機制,它的工作不是處理付款,而是在每筆付款完成後,持續驗證「系統認為發生的事」和「銀行認為發生的事」是否一致;任何一筆不一致,都是潛在的帳務問題,可能是系統 bug、可能是閘道錯誤、也可能是真實的資金損失。 本文是對帳系統設計的上篇,從三本帳的概念模型出發,說明以結算日為基準的關鍵決策、日終對帳的五個步驟、軋差的計算邏輯,以及差異單的分類與處理方式,下篇則進入資料庫 Schema 設計與 .NET 實作骨架。 三本帳:對帳的概念模型 對帳的本質是核對三個來源的數字,確保它們指向同一個現實。 系統帳(Internal Ledger) 系統帳是自己的資料庫,以訂單視角記錄每一筆交易,核心資料來自 orders 表和 refunds 表,記錄的是「系統認為發生了什麼」:哪些訂單已結算、結算金額是多少、退款了多少。 閘道報表(Gateway Settlement Report) 閘道報表由支付閘道或電子支付平台提供,通常是 CSV 格式或 API 回應,以交易視角記錄「閘道認為發生了什麼」:哪些交易已完成、手續費扣了多少、淨額是多少;不同閘道的報表格式差異很大,Stripe 有 API 可以即時拉取,有些則是 SFTP 上的 CSV 檔案,需要個別處理。 銀行帳(Bank Statement) 銀行帳是公司銀行帳戶的對帳單,以資金視角記錄「銀行認為發生了什麼」:哪一天入帳了多少、哪一天被扣了多少,銀行帳通常透過銀行 API 或每日 SFTP 傳送取得。 為什麼三本帳的數字不一樣? 一筆 NT$1,000 的刷卡,三本帳的數字各自不同:系統帳記錄 NT$1,000(訂單金額)、閘道報表顯示 NT$985(扣除 MDR 1.5% 後的淨額)、銀行帳入帳 NT$985(和閘道報表一致,但時間晚 T+1);這三個數字都是正確的,只是視角不同,對帳系統的工作是理解這些差異是否在預期內,像是 MDR 費率是否符合合約、時間差是否合理,還是有一筆錢真的消失了。 以結算日為基準的關鍵決策 對帳系統最重要的設計決策之一,是選擇以 結算日(Settlement Date) 為基準,而不是訂單建立日,原因在於閘道報表的組織方式:閘道不是按照「消費者刷卡的時間」整理報表,而是按照「資金批次結算的日期」去整理;一筆週五下午的訂單,可能要到週一才進入閘道的結算批次(跨週末無結算),如果對帳系統用訂單建立日去比對閘道報表,週五的訂單永遠在週五找不到配對,就會產生大量的假差異單。 這個決策影響兩個地方: orders 表需要有 settled_date 欄位,在收到結算 Webhook 時寫入,而不是使用 created_at。 gateway_transactions 的 settlement_date 來自閘道報表本身,不是匯入時間。 日終對帳的完整流程 對帳通常排程在市場收盤後、次日開盤前的深夜窗口執行,依序走完以下五個步驟。 ...

2026年7月11日

支付狀態機設計之三:退款設計、Webhook 冪等性與多支付方式整合

前兩篇分別建立了狀態機的規則骨架(第一篇)和防護機制(第二篇),這篇文章則要回答最後一個問題:這套狀態機在實際的工程場景中怎麼被使用? 三個最常見的應用場景是退款、Webhook 事件觸發以及多支付方式的整合,這三者也是支付後端工程師日常工作中最頻繁接觸的部分,也是本系列的最後一篇。 退款記錄的資料庫設計 如第一篇所說,退款不應覆蓋原訂單,應在獨立的 refunds 表建立記錄,這個設計有以下幾個考量點: 1CREATE TABLE refunds ( 2 id UUID PRIMARY KEY DEFAULT gen_random_uuid(), 3 order_id UUID NOT NULL REFERENCES orders(id), 4 amount DECIMAL(12, 2) NOT NULL, 5 reason VARCHAR(255), 6 status VARCHAR(20) NOT NULL 7 CHECK (status IN ('pending', 'succeeded', 'failed')), 8 gateway_refund_id VARCHAR(100), -- 支付閘道回傳的退款 ID 9 idempotency_key VARCHAR(100) NOT NULL, -- 防止重複發起退款 10 initiated_by VARCHAR(50), -- 'merchant' 或 'customer' 11 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), 12 settled_at TIMESTAMPTZ, -- 退款實際入帳時間 13 UNIQUE (idempotency_key) 14); 使用這個結構,可以很容易查詢「一筆訂單的累積退款金額是否超過訂單金額」,這是防止退款超額的重要防護: ...

2026年7月5日

支付狀態機設計之二:電子支付差異與三層防護架構

上一篇定義了信用卡訂單的完整狀態集合、每條合法轉換的觸發條件,以及五種常見的非法轉換;這些規則若只停留在文件或口頭共識,實務上很容易被繞過,一個急著修 bug 的工程師可能直接在資料庫改一筆 status,或是漏掉某個 edge case 的檢查。 本文接續上一篇,先說明電子支付的狀態機和信用卡有哪些關鍵差異,再進入這個系列最核心的工程主題:如何在 Domain 層、資料庫層、併發控制三個層次,把規則做成物理上無法繞過的防護。 電子支付的狀態機差異 電子支付(街口、LINE Pay、全支付等)的狀態機比信用卡簡潔,因為「授權即扣款」不存在分開的 Capture 步驟;但這個簡潔性會帶來另一個複雜性:不同的付款模式有不同的狀態流轉。 錢包餘額或綁信用卡模式 使用者確認付款後,平台內部立即扣減餘額或發出信用卡授權請求,結果幾乎是即時的。這個模式下的狀態流轉是: INITIATED → PAID → SETTLED → REFUNDED PAID 等同信用卡的 CAPTURED,但因為授權和扣款是同一個動作,AUTHORIZED 這個中間狀態不存在。 綁定銀行帳戶模式 當使用者綁定的是銀行帳戶(而非信用卡),扣款請求需要送到銀行處理,而銀行的確認可能是非同步的,也就是平台送出扣款請求後,可能要等幾分鐘到幾個小時才能確認結果。這個模式下需要一個額外的中間狀態: INITIATED → PENDING → PAID → SETTLED → REFUNDED ↘ FAILED PENDING 代表扣款請求已送出,但尚未收到銀行確認,系統收到的第一個 Webhook 可能是「扣款請求已受理」,而不是「扣款成功」;這個細節如果沒處理好,很容易在業務上造成誤會:商家以為錢進來了,但其實銀行還沒確認。 工程師視角的關鍵差異 電子支付最重要的工程差異不是狀態數量,而是狀態轉換的觸發方式;信用卡的許多轉換(Capture、Void)是商家主動發起的,電子支付的多數轉換是由平台 Webhook 被動觸發的,這代表系統設計重心要從「主動呼叫 API」轉向「可靠地接收和處理 Webhook 事件」。 三層防護架構 不論是信用卡還是電子支付都同樣適用三層防護原則,雖然狀態轉換的觸發方式不同,但防止非法轉換的機制是一致的;狀態機的設計不能只停在「寫 if/else 判斷」,而是要在三個層次都建立防護。 Domain 層(Rich Domain Model) 把狀態轉換的邏輯封裝在 Order 這個 Domain 物件裡,而不是散落在各個 Service 方法中,這個做法叫 Rich Domain Model,好處是非法轉換在呼叫當下就拋出例外,不需要每個 Service 方法都寫一遍防護邏輯。 ...

2026年7月4日

支付狀態機設計之一:狀態定義與轉換規則

一般的業務系統,狀態管理出錯頂多造成資料不一致,花時間修復就好;支付系統則不同,一個非法的狀態轉換,可能造成持卡人被重複扣款、退款金額錯誤、帳務無法對帳,甚至觸發監管機關的調查。 這就是為什麼金流支付產業的工程師對「狀態機」的要求,比其他後端工程師嚴格許多;不是寫個 if/else 判斷 status 就算數,而是要在 Domain 層、應用層、資料庫層三個層次都建立防護,讓非法轉換在物理上無法發生。 本文從信用卡交易出發,完整拆解一筆訂單從建立到結算的所有狀態,說明每條轉換背後的業務邏輯,並延伸到電子支付的狀態差異、非法轉換的防護設計,以及可以直接套用的 .NET 實作骨架。 本文是狀態機系列的第一篇,聚焦在信用卡訂單的完整狀態集合、每條合法轉換背後的業務觸發條件;三層防護的實作細節和電子支付的狀態機差異,則留到第二篇展開。 信用卡訂單的完整狀態集合 在開始探討轉換圖之前,我們先把每個狀態的語義定義清楚,這會比記憶狀態名稱更重要,因為面試官不會在意面試者使用了什麼英文單字,而是在意的是是否理解每個狀態代表的業務意涵。 INITIATED(已建立) 訂單剛建立,使用者已按下「確認付款」,系統已準備好發出授權請求,但尚未收到任何回應,這是所有訂單的起始狀態;在這個狀態下,資料庫應已記錄訂單金額、商品資訊、使用者 ID、時間戳記,但 authorization_code、gateway_transaction_id 這些欄位尚為空值。 AUTHORIZED(已授權) 發卡行(Issuer)回傳核准碼(Approval Code),確認持卡人的卡片有效、額度足夠,此時系統應將授權碼、授權金額、授權時間存入資料庫;AUTHORIZED是一個容易產生誤解的狀態,其代表額度被凍結但資金尚未移動,持卡人的帳戶在這個瞬間沒有任何資金流出,只是有一筆「保留額度」;這就是為什麼飯店可以先凍結 5,000 元押金,退房後才根據實際消費金額請款。 CAPTURED(已請款) 商家確認可以請款(商品出貨、服務交付),發出 Capture 請求,這一步才是正式告訴銀行「我要這筆錢」;Capture 金額的關鍵規則是可以小於或等於授權金額,但不可以超過,超過授權金額的 Capture 請求會被收單行(Acquirer)拒絕,且可能觸發持卡人的詐欺警示。 SETTLED(已結算) 收單行完成日終批次清算後,資金在 T+1 或 T+2 工作天實際從發卡行撥到收單行、再撥到商家帳戶,這是資金真正移動的時刻。 FAILED(失敗) 授權請求被發卡行拒絕(額度不足、風控攔截、卡片過期等),或在授權過程中發生技術錯誤;FAILED 是一個終止狀態,代表失敗的訂單不應在原訂單上重試,而應建立新的訂單記錄,以保持完整的稽核軌跡。 VOIDED(已取消) 在 CAPTURED 之前商家主動取消授權,Void 操作的特點是:持卡人的凍結額度立即解除,且完全沒有資金移動,這和退款有根本的差異。 REFUNDED(已退款) 在 SETTLED 之後商家對持卡人執行退款,退款是反向資金流:錢從商家帳戶流回持卡人,通常需要 3 到 5 個工作天才能出現在持卡人的帳單上。 DISPUTED(爭議中) 持卡人向發卡行申訴,主張這筆交易有問題(未收到商品、遭到詐騙、對交易不認識等);發卡行審查後,會透過卡組織通知收單行,收單行再以 Webhook 通知商家系統;進入 DISPUTED 狀態後,對應金額可能被暫時凍結,商家需在限期內提交舉證資料。 合法的狀態轉換與業務觸發條件 INITIATED → AUTHORIZED 觸發條件:發卡行回傳成功的授權碼(Response Code 00);系統在這個轉換發生時,必須同時儲存以下資料: authorization_code // 發卡行核准碼,後續 Capture 必須帶上 authorized_amount // 授權金額(可能和訂單金額不同) authorized_at // 授權時間戳(計算授權有效期的基準) acquirer_reference // 收單行參考號 card_bin // 卡號前 8 碼(用於費率計算和對帳) 授權有效期的工程含義:授權通常有 7 天的有效期(部分產業如預訂、住宿可達 30 天),系統需要一支背景排程任務,定期掃描「AUTHORIZED 超過有效期且未 Capture」的訂單,主動發出 Void 請求並更新狀態,否則持卡人的額度會被無限期佔用。 ...

2026年7月3日

一筆付款的旅程:電子支付交易完整生命週期

用街口掃碼結帳,確認付款,畫面顯示成功,整個過程不到兩秒,而且幾乎是即時扣款;這和信用卡的「三秒體驗、兩天資金流」截然不同,電子支付的即時感不是介面設計的錯覺,而是底層架構決定的;電子支付平台同時扮演發帳戶、處理交易、直接對商家結算三個角色,整條鏈路由單一平台控制,不需要在多個金融機構之間等待批次處理。 這種架構稱為 Closed Loop(閉環),對應信用卡的 Open Loop(開放迴路)四方模型,兩者在交易觸發方式、狀態機設計、Webhook 處理、對帳複雜度上都有根本差異;本文聚焦在電子支付的完整生命週期,拆解三種主要的付款模式,說明每種模式的狀態流轉,並補充 Webhook 可靠性設計的工程細節。 核心架構特點 電子支付平台在一個生態系中同時扮演三個角色:自己發行帳戶或錢包給用戶(等同 Issuer)、自建清算和風控系統(等同 Card Network)、直接與商家簽約收取服務費(等同 Acquirer);這三個角色的整合,帶來了幾個和信用卡截然不同的特性。 授權與扣款通常合一:信用卡是先授權(凍結額度)、再 Capture(正式請款)的兩步流程;電子支付的錢包模式通常是確認付款後直接扣款,不存在分開的 Capture 步驟。 資金到帳更快:信用卡走 T+1 到 T+2 的批次結算;電子支付的平台內部帳務操作在秒內完成,商家的平台帳戶餘額立即更新,撥款至銀行帳戶視平台週期而定,通常是 T+0 到 T+1。 全鏈路數據自己掌握:信用卡的消費資料分散在各 Issuer,Card Network 只看到交易流;電子支付平台能看到用戶在哪家店、買了什麼、什麼時間、搭配什麼優惠,這個數據優勢在精準行銷和反詐欺上非常關鍵。 不存在 Interchange:電子支付是閉環系統,發帳戶和收單是同一家平台,不需要 Interchange 這個跨機構的費用補貼機制,費用結構相對透明。 三種主要付款模式 電子支付的「電子支付」四個字包含了三種底層完全不同的付款方式,每種模式的交易流程和狀態機設計都不一樣。 模式一:錢包餘額付款(如街口錢包、全支付) 用戶預先儲值到平台錢包,付款時直接扣減餘額,這是速度快且架構簡單的模式。 交易流程 Step 1:用戶確認付款 Step 2:電支平台驗證用戶身份(PIN / 生物辨識) Step 3:平台內部扣減用戶錢包餘額(帳務分錄) Step 4:平台更新商家的收款帳戶餘額(帳務分錄) Step 5:回傳付款成功通知(Webhook)給商家系統 Step 6:平台依週期結算,將商家餘額撥款至銀行帳戶 Step 2 到 Step 5 是平台內部的帳務操作,不需要外部銀行參與,速度極快(通常在一秒內完成)。 帳務邏輯(複式記帳) 借:用戶錢包帳戶 NT$500 貸:商家收款帳戶 NT$500 平台內部維持帳務平衡,所有的錢都存放在平台向主管機關申報的備付金帳戶裡,帳務分錄只是改變了餘額的歸屬,不涉及實際的銀行資金移動。 狀態機 INITIATED → PAID → SETTLED → REFUNDED(部分或全額) ↘ FAILED 這個模式沒有 AUTHORIZED 和 CAPTURED 兩個中間狀態,因為授權與扣款是同一個動作。 ...

2026年6月28日

一筆付款的旅程:信用卡交易完整生命週期

在電商網站結帳,輸入信用卡號,按下確認,畫面顯示「付款成功」,整個過程大概三秒;但是在這三秒裡,請求穿越了至少五個不同機構的系統,觸發了一連串訊息交換、風控判斷、資料寫入,最後才換來那個綠色勾勾。 而那筆錢,則要再等一到兩個工作天,才會真的從客戶的帳戶移動到商家的帳戶,這個「三秒體驗、兩天資金流」的落差,是支付生命週期的核心,理解它有助於設計出正確的訂單狀態機、對帳邏輯、退款流程。 本文將以信用卡交易(以四方模型為例),完整拆解從授權到結算的每個步驟,並說明 Void、Refund、Chargeback 三種特殊情況的處理方式。 三個階段,五個角色 信用卡交易分三個截然不同的階段,每個階段的時間跨度和參與者都不一樣。 授權(Authorization):幾秒內完成,目的是確認卡片有效、額度足夠,此時資金並未移動,只是凍結對應額度。 清算(Clearing):以當日批次處理,商家正式請款、各方確認金額,資金仍未實際流動。 結算(Settlement):在 T+1 或 T+2 工作天完成,這才是資金在銀行間真正移動的時刻。 參與者共有五個:持卡人(Cardholder)、商家(Merchant)、收單行(Acquirer)、卡組織(Card Network)、發卡行(Issuer)。 階段一:授權(Authorization) 目標:確認這張卡可不可以用、有沒有足夠額度。 完整流程 持卡人在結帳頁面輸入卡號、有效期、CVV,按下確認後: Step 1:商家側加密並送出 POS 機或支付閘道(Payment Gateway)將卡片資訊加密,組成授權請求,送給收單行(Acquirer);線上交易的格式通常是 HTTPS + JSON;實體刷卡走 ISO 8583 訊息格式。 Step 2:Acquirer 路由 收單行接收請求,解析卡號前六到八碼(BIN / IIN),判斷這張卡屬於哪個卡組織(Visa / Mastercard),再將授權請求轉送到對應的 Card Network。 Step 3:Card Network 轉發 Visa 或 Mastercard 依 BIN 找到發卡行,將授權請求轉發給 Issuer。 Step 4:Issuer 審核 這是整個流程中判斷最複雜的一步,發卡行要在短時間內完成: 額度檢查:可用額度是否足夠? 風控判斷:地區是否異常?金額是否超過消費習慣?近期是否有可疑交易? 身份驗證:是否需要觸發 3DS2(線上交易的持卡人驗證)? 卡片狀態:是否已掛失、過期、凍結? Step 5:回傳結果 Issuer 回傳核准碼(Approval Code)或拒絕原因碼(Response Code),沿著原路反向傳回給商家,整個來回通常要在極短時間內完成。 授權成功後的狀態 訂單狀態此時應為 AUTHORIZED,系統需儲存: ...

2026年6月27日

支付四方模型 vs 三方模型之二:工程應用與面試問答

上一篇拆解了四方模型和三方模型的角色結構、資金流向、費用差異;這些概念如果只停在「知道」的層次,對工程師來說價值有限,重要的是理解這兩個模型如何具體影響要寫的程式碼。 本文接續上一篇,說明 API 整合、對帳邏輯、狀態機設計、Chargeback 處理這四個工程面向的差異,最後整理面試中最常見的問法和建議的回答方向。 API 整合:不要假設一致性 四方的 Visa 和三方的 Amex,授權 API 長得不相同: 1// 錯誤做法:針對每家寫死邏輯 2if (cardType == "VISA") { 3 var request = new VisaAuthRequest { ... }; 4 // Visa 特定欄位... 5} else if (cardType == "AMEX") { 6 var request = new AmexAuthRequest { ... }; 7 // Amex 完全不同的欄位... 8} 9 10// 正確做法:抽象 Gateway 介面 11public interface IPaymentGateway { 12 Task<AuthResult> AuthorizeAsync(AuthRequest request); 13 Task<CaptureResult> CaptureAsync(string authCode, decimal amount); 14 Task<RefundResult> RefundAsync(string transactionId, decimal amount); 15 Task<VoidResult> VoidAsync(string authCode); 16} 17 18public class VisaGateway : IPaymentGateway { ... } 19public class AmexGateway : IPaymentGateway { ... } 20public class TapPayGateway : IPaymentGateway { ... } // 本地閉環 這個介面抽象讓你日後新增支付方式時,只需要新增一個實作類別,不動核心邏輯。實務上通常會再搭配一個簡單的工廠(Factory)依卡種或商家設定選擇對應的實作: ...

2026年6月21日

支付四方模型 vs 三方模型之一:角色結構與概念比較

後端工程師在接觸支付系統時,第一關常常卡在「業務語言」上,技術或許沒問題,但和 PM、業務、甚至面試官討論時對不上頻率;四方模型(Four-Party Model)與三方模型(Three-Party Model)是支付產業的基礎架構分類,理解這兩者不只是業務知識,甚至直接影響: 系統設計決策(要不要抽象 Gateway 介面?對帳邏輯怎麼設計?) API 整合策略(Visa 和 Amex 的授權流程根本不一樣) 面試表現(支付公司面試幾乎必問) 本文從角色結構、資金流向、費用分配到工程師視角的實作影響,拆解這兩個模型。 四方模型(Four-Party Model / Open Loop) 五個角色,四段關係 「四方」這個名字略有誤導,實際上有五個實體,只是因為有「四段核心商業關係」才這樣命名: 持卡人(Cardholder):就是你我這樣的消費者,核心職責是發起交易、承擔帳單。 發卡行(Issuer):常見的例子是玉山、台新、花旗,核心職責是核發信用卡、進行授權審核、承擔壞帳風險。 卡組織(Card Network):也就是 Visa、Mastercard,核心職責是負責交易路由、制定清算規則、訂定 Interchange 費率。 收單行(Acquirer):常見的例子是聯合信用卡中心,核心職責是代商家接收款項、撥款給商家。 商家(Merchant):全聯、momo、各電商都是這個角色,核心職責是提供商品或服務、繳交手續費。 Issuer 和 Acquirer 是完全獨立的兩家機構,彼此之間透過 Card Network 溝通;這就是「Open Loop(開放迴路)」名稱的由來,任何 Issuer 發的卡,理論上可以在任何 Acquirer 服務的商家刷卡。 一筆交易的完整資金流 以「用玉山 Visa 在全聯刷 NT$1,000」為例: 階段一:授權(即時) 持卡人 → POS 機(全聯) → 聯合信用卡中心(Acquirer) → Visa 網路(Card Network)→ 玉山銀行(Issuer) 玉山確認額度夠、風控通過,回傳 Approval Code;此時只是凍結額度,資金未動。 階段二:清算(當日批次) 全聯日終把所有刷卡記錄批次送給收單行,收單行整理後送給 Visa,Visa 計算各方應付金額(含 Interchange)。 階段三:結算(T+1 或 T+2) 玉山(Issuer)→ 扣除 Interchange,撥款給 Visa Visa → 扣除 Network fee,撥款給聯合信用卡中心(Acquirer) 聯合信用卡中心 → 扣除 Acquirer Markup,淨額撥給全聯帳戶 最後全聯帳戶實際入帳 NT$985(假設 MDR 1.5%)。 ...

2026年6月20日