Migration Review Checklist
這份清單用於 review legacy API 搬移到 pro360_api_82 的程式與文件。重點不是只看 response 是否成功,而是確認 input、DB write、side effect、error path 與 legacy 行為一致。
先決檢查
- 先確認目前查的是正確分支、正確環境與同一套 DB。
- 先看對應 API detail doc;若文件沒有 legacy 行號、new 行號、side effect 與實測結果,先補文件再下結論。
- 查 DB 前先查 schema,不猜欄位。
- 若 API 已在新專案長期正式上線,文件要標明「以現行新專案為準」,不要再用 legacy 差異反推錯誤。
新資料列與 DB 寫入
- 新增資料列不可用
SELECT * FROM <table> ... LIMIT 1抓舊 row 當 insert template。必須用 explicit allowlist,逐欄確認值來自 legacy 指派或 schema default。 - 新增 / auto-signup / insert 類 API 在寫程式前,detail doc 必須先有「欄位分類表」。每個 insert 欄位只能屬於以下四類之一:
- legacy controller / model 明確指派
- legacy model callback / helper 明確補值
- schema default 或非 strict MySQL implicit value,且文件寫明來源
- 新專案刻意不同的 migration decision,需先標
待確認並取得 reviewer 接受
- 不在欄位分類表內的欄位不得進 explicit insert allowlist。不要把其他註冊流程、其他 endpoint、現有 sample data 或語意推測帶進本 API。
- 大表如
users、quote_services、quote_requests、quote_bids要補 negative test:legacy 沒指定且高風險的欄位,要 assert 不在 insert data 或維持 legacy default。例如 token/hash、wallet、counter、status、security、app timestamp、payment 欄位。 - 檢查是否有把舊 row 的 wallet、counter、status flag、profile 殘值帶進新資料。
- 檢查
null、空字串、0、"0"的寫入是否與 legacy 一致。 - 檢查時間欄位是否一致,例如
created、modified、queue 時間與時區。 - 檢查 counter cache 是否同步,例如 service count、bid count、message count、review count。
- guard fail 或 error path 不應先寫入部分 DB;若 legacy 會在 error path 寫 log / activity,new 也要明確對齊。
Input / Guard / Response
- 每個 request input 都要追到最終 side effect,不只確認「有傳到下一層」。
- 特殊 input 要確認語意,例如
prime是 TapPay token,不是 boolean flag;reason可能同時影響欄位、activity 與訊息。 - owner guard、session guard、REST API key guard、id 不存在、非 owner、未登入都要確認。
- response 要確認
errorcode、status大小寫、message、額外欄位與 legacy 是否一致。 - CakePHP style path 要精準對齊,例如
quote_bid_id:123.json、.json、query string、page / limit。 - 瀏覽器會先打 OPTIONS;curl POST 成功不代表前端一定可用。
Side Effect
- controller 不是完整行為,必須追到 model、helper、payment、queue、notification、activity、log。
- legacy 的
CakeLog、LogHelper、debug channel、full request dump 都算 side effect。若 new 不 1:1 保留,必須先在 detail doc 標待確認並和 reviewer 確認;不可自行用安全性、可讀性或「看起來只是 debug」理由省略。 - request info log 預設仍要對齊 legacy。若
RouterV3generic request log 已涵蓋同一份 request,或 legacy full request dump 會寫入敏感欄位,先在 detail doc 標待確認,列出 legacy channel / context shape / 風險,再取得 reviewer 接受;不可自行省略。若 reviewer 接受只保留 generic log 或加 scoped 過濾,detail doc 要標 migration decision,並測試保留 log 的 channel / context shape。credential 欄位至少要確認password/passwd已被過濾。 - payment / contact provider / transaction 類 API 必須追完整鏈:controller -> domain method -> charge helper -> wallet/card/TapPay/Stripe -> transaction -> application log -> response mapping。
- transaction 與 subscription log 不可混用;外鍵要指到正確 table。
- queue / event 驗證要同時查原 queue 與 log。
event_queue要查event_queue_log_1到event_queue_log_4;task_event_queue要查task_event_queue_log。 - worker 可能已搬走 queue row,不可把 queue 表查不到直接判定為沒送。
- notification 不只看 event key,也要看 payload、template replace content、MoEngage attributes、mail / SMS config key。
- 外部服務如短網址、TapPay、Stripe、Email、SMS,測試應 mock 或使用既有 fixture;實際部署仍要確認 config 與連線。
Existing Method / Shared Code
搬移 API 若直接呼叫新專案既有 model / helper / util,不可因為「現有方法已存在」就視為已和 legacy 一致。
- 每個直接呼叫的既有 method 都要記錄:new method、legacy 對應 method / 行號、現有 caller、side effect、差異判斷。
- 先用
rg或 IDE call graph 確認現有 caller;不要只看本次 API。 - 如果既有 method 與 legacy 不一致,而且只有本次 API 使用,可考慮把該 method 調整成 legacy parity,但要先說明差異、風險與測試。
- 如果既有 method 有其他 API / worker / 後台共用,不要直接改 shared behavior;新增 legacy-compatible wrapper / option / 專用 method 給本次 API。
- 如果新專案行為已是其他流程的 canonical behavior,不要硬改成 legacy;detail doc 要標成 migration decision,等待 reviewer 確認接受新行為或建立相容層。
- 改任何 shared method 前,先在 detail doc 或回覆中列出「誰在用、legacy 差異、打算改哪裡、可能影響」,確認後再改。
- 若只做 PHP 8.2 type guard / warning 修正,也要確認 response shape 與 DB side effect 不變,並記錄不是商業邏輯改動。
Legacy / PHP 8.2 差異
legacy 是 PHP 5.6 / CakePHP,new 是 PHP 8.2;review 時要把 runtime 差異當成必查項,不可只看商業邏輯是否相似。
- PHP 5.6 可容忍的 notice / warning,在 PHP 8.2 可能變 deprecated warning、TypeError 或 999;缺 key、缺關聯資料、
null參數要明確處理。 - PHP 8.2 內建函式型別更嚴格;例如
rawurldecode(null)、trim(null)、count(null)、in_array()參數型別錯誤,都可能從 legacy warning 變成新專案 log / exception。 isset()、empty()、array_key_exists()、!$value的語意不可混用;特別注意null、空字串、"0"、0、空 array 的分支。- PHP 8.2 不應依賴未定義 index / property;legacy 若靠 CakePHP 自動補空值,new 要明確 nullable fallback 或 guard。
- legacy CakePHP
recursive、contain、fields、save()寬鬆行為要對到 new DB helper / DataObject 實際寫入。 - CakePHP legacy
save()可能只更新 dirty fields,也可能因 model callback 產生額外 side effect;new 若直接 SQL update,要確認 callback / modified / validation 差異。 - PHP 5.6 常見弱型別比較在 PHP 8.2 雖仍多數可用,但資料來源若改成 int / bool / null,可能讓
==、empty()、array key 判斷走到不同分支。 - response 欄位型別要留意;legacy 常把 id、flag、金額回字串,new 若回 int / bool 可能造成前端或 app 差異。
- JSON encode / decode 差異要確認;legacy array、object、空 array、空 object、numeric string 的輸出 shape 可能與 new 不同。
- legacy 常數不可用語意猜,需對
Const*值,例如 activity type、status id、transaction type、queue action、error code。
Config / 部署環境
- legacy 若讀
Configure::read()、settings、mail / SMS / notification template、URL、icon、fee threshold、payment threshold,不可只看本地 legacy checkout。 - 必須確認 staging / production 實際部署設定;若 new 缺 key,要補到
ProConfig或對應部署 config。 - 若
Configuration.php被.gitignore忽略,文件要寫清楚部署環境也要同步。 - route / LB rule 要精準設定,不可用過寬 pattern 誤切其他 API。
Query / Pagination / Response Shape
- 查詢條件、排序、分頁起算、limit 預設值與最大值要對齊 legacy。
- CakePHP response shape 要確認外層 key、關聯 key、空 array / empty object / null 是否一致。
- hidden fields、contain fields、join fields 要確認,不可多曝敏感欄位或少回前端依賴欄位。
- web / iOS / Android 可能送不同欄位;若正式流量含 app user agent,要用 app 參數一起驗。
測試與實測
- 不只測 happy path;至少列出 owner / non-owner、missing input、invalid id、重複呼叫、主要 error path。
- wallet / payment 類需覆蓋 wallet 足夠、wallet 不足無 token、wallet 不足有 token、gateway fail、重複成功後再呼叫。
- 測試若使用共用 user,必須 snapshot / restore 所有 touched 欄位,尤其 wallet、onboard、phone、counter、session。
- 實測前先知道會寫哪些資料;測後用 DB 查主表、activity、transaction、queue/log、application log,必要時制定清理方式。
- 重複呼叫行為要對齊 legacy:是 success、guard error、只寫 activity,或被 Redis / lock 擋 side effect。
文件回填
- 每次實測發現 legacy 行為,要回填到對應 detail doc,不只改程式。
- detail doc 要記錄環境、日期、request id / bid id / service id、response、DB side effect、queue/log 結果。
- 不確定的項目標
待確認,不要寫成已驗證結論。 - umbrella endpoint 要拆到實際 action / filter / routing key 文件;總覽只放索引與狀態。