會員系統遷就第三方登入,健身工作室連鎖平臺差點集體停權
一家連鎖健身工作室導入LINE快速登入後,會員陸續被系統誤判停權。我們拆開追蹤程式碼才發現,問題不在LINE,而在一段從沒被測過的舊邏輯。
- 同一份會員資料被多個Repository各自用一個DbContext追蹤,跨層指派物件會汙染變更追蹤,炸出意料之外的例外
- 新會員預設狀態欄位被寫死,中間任何一步出錯就會靜默卡在未開通,直到下次登入才爆炸
- 舊帳號的姓名、手機是暱稱與佔位值,單值比對的搜尋欄位讓合併功能形同虛設

一家連鎖健身工作室的會員平臺,上線LINE快速登入的第一天,客服就接到電話:會員說自己明明綁定過LINE,一登入卻被當成停用帳戶擋在門外。工程師第一反應是懷疑LINE那邊出包,查了半天才發現,問題出在自己家裡。
帳號建立成功,卻被自己的系統關起來
新會員用LINE登入時,系統背後會建立一筆帳號,正常流程是建立後立刻寫入「已開通」狀態。但程式裡有一段共用邏輯,不管呼叫端傳什麼值,一律先寫「未開通」,等後續寄送驗證信的收尾步驟跑完才補上開通狀態。這段收尾包在一個沒設保護的例外處理裡,只要中間有任何一步出錯,帳號就會靜靜卡在未開通,畫面上完全看不出異常,直到下次登入才被系統擋下來,判定成停用帳戶。
這種踩雷不會在測試環境出現,因為測試流程通常一路順到底,不會剛好卡在那個容易失敗的步驟。只有真實流量夠大、環境夠雜的正式站,才會把這種機率性錯誤逼出來。
三個Repository各自為政,資料互相汙染
再往下查,發現另一個更隱晦的問題。系統裡管理會員資料的三個模組,各自用獨立的資料庫連線在追蹤變更。有一段程式為了方便,把其中一個模組查出來的物件,直接塞進另一個模組正在追蹤的物件裡。這在小型測試裡完全看不出異狀,但只要這筆資料剛好排在某個更新流程之前執行,系統會在做變更偵測時,發現資料被跨連線汙染,直接丟出完整性例外。
程式碼看起來能動,跟它真的沒問題,中間隔著一整條沒被踩過的正式站流量。
搜尋欄位是單值比對,合併功能形同擺設
更麻煩的是善後。第三方登入建立的帳號,姓名欄位存的是暱稱、手機欄位是系統塞的佔位值,跟會員原本手動填寫的資料對不起來。這類重複帳號理論上可以在後臺合併,但搜尋欄位是單值比對,要兩筆帳號同時符合姓名、信箱、手機才會一起出現在結果裡,形同要求兩把長得完全不同的鑰匙開同一把鎖。工程師動手把搜尋欄位改成支援多值查詢,同一個欄位用逗號分隔可以查多個值,跨欄位維持交集,客服才總算能把這些卡住的帳號一筆一筆挑出來手動合併。
我們在這個案子學到的事
- 共用的資料寫入邏輯,不能為了方便寫死預設值,呼叫端的意圖要被尊重,不然遲早有一支流程被犧牲
- 跨模組操作資料庫物件時,不要圖方便互相指派,寧可多查一次,也不要讓變更追蹤互相打架
- 後臺管理工具的搜尋條件要照著真實資料的長相設計,不能假設每個來源填的資料都乾淨、都齊全
系統上線那天最怕的不是流量,是那些從沒被真實資料逼過一次的分支。