SearchAdd Actor Resolution
更新日期:2026-08-10
狀態:partial(LINE actor / 綁定已由 fb8897d7 完成並推到 feature branch;session / device 規則仍有差異)
完整 NewStaging 稽核見 newstaging_delta_audit_2026-08-05.md。
快速結論
建單前必須先得到 consumer actor。PHP 8 feature branch 已接上 LINE actor、既有帳號綁定與 auto signup link;device-only 與 search_add session side effect 尚未對齊 Current Legacy。LINE commit 目前只在 origin/NewStagingForPHP82_search_add,尚未進入 NewStagingForPHP82 / staging。
LINE actor / 綁定流程
flowchart TD A["前端完成 LINE 登入"] --> B["取得 line_id_token"] B --> C["呼叫 search_add"] C --> D["依 token 查 line_verify_logs"] D --> E{"找到 LINE 身分?"} E -- 否 --> X["無法成立 LINE actor<br/>走原本 actor / signup 流程"] E -- 是 --> F["取得 LINE sub、email、name"] F --> G{"line_users 已有綁定?"} G -- 是 --> H["取得已綁定的 PRO360 user"] G -- 否 --> I{"LINE email 對應既有 user?"} I -- 是 --> J["寫入 line_users 綁定"] I -- 否 --> K{"符合新帳號註冊條件?"} K -- 是 --> L["建立 PRO360 user"] L --> J K -- 否 --> Y["回傳原本的 actor / signup error"] J --> M["使用該 PRO360 user"] H --> M M --> N["建立 QuoteRequest 需求"]
這張圖只描述 LINE actor 與帳號綁定。LINE token 不會替 request 補 email;search_add 也不會再次呼叫 LINE verify API。
SearchAddHandler::handle()
-> ActorResolver::resolveFromSession()
-> CredentialActorResolver::resolve()
-> AutoSignupService::signup()新舊程式對應
Legacy NewStaging
主要入口:
/Users/mattsu/Documents/Site/get-lancer-docker-2/get-lancer/app/Plugin/Quotes/Controller/QuoteRequestsController.php::search_add()| Legacy 位置 | 職責 |
|---|---|
QuoteRequestsController.php:1815-1826 | API session actor 與 request log。 |
QuoteRequestsController.php:2024-2111 | request user input 與 social identity;優先序為 Google → Facebook → Facebook limited → Apple → LINE。 |
QuoteRequestsController.php:2122-2188 | social/email actor、password、device、LINE same-email 綁定。 |
QuoteRequestsController.php:2206-2347 | auto signup、LINE link、profile、login、session reuse。 |
QuoteRequestsController.php:2355-2378 | actor failure response。 |
QuoteRequestsController.php:3147-3152 | session 不存在時建立。 |
LineVerifyLog.php:13-17 | 依完整 id token 查 verify log。 |
LineUser.php:13-52 | sub 找 user、判斷 user 是否已綁、建立 link。 |
ApiSession.php:20-25,34-80,102-140 | search_add 先 reuse;只有缺 row 才 insert / login log。 |
PHP 8.2
| Current 位置 | 職責 / 差異 |
|---|---|
SearchAddHandler.php:142-198 | session → credential → signup。 |
ActorResolver.php:10-30 | session actor。 |
SearchAddInput.php:318-335 | 讀 User[line_id_token],並依 Legacy input chain 決定是否處理 LINE。 |
CredentialActorResolver.php:23-155,259-275,407-425,467-492 | LINE actor、same-email actor、email mismatch 與既有帳號 link;device match 仍成功。 |
SearchAddLineIdentityRepository.php:15-109 | 精確查 line_verify_logs.id_token、依 line_users.line_user_id 找 user、依 Legacy allowlist 建 link。 |
AutoSignupService.php:29-115,451-467 | auto signup 建 user 後寫 line_users。 |
ApiSession.php:66-140 | shared upsert;依 user/device/API key 取代同 app session,仍不是 Legacy search_add 的 existing-token reuse。 |
Endpoint/V1/Line.php:27-190 | LINE OAuth 與 line_verify_logs owner;search_add 只讀既有 verify log。 |
LINE Legacy contract
Input / guard
- input:
User[line_id_token]。 - 只有 Google、Facebook access、Facebook limited、Apple 都沒有命中 input 時才處理 LINE。
- 查
line_verify_logs.id_token = input;沒有 expiry、consumed、status、order guard。 - LINE token 不替 request 補 email;request 沒有
User[email]時仍回error=11。 - LINE linked user lookup 沒有
users.is_active=1條件,不可自行新增。
Actor matrix
| 情境 | Legacy 結果 |
|---|---|
| sub 已綁 user,request email 相同 | 信任 linked user。 |
| sub 已綁 user,request email 不同 | 無 password 回 error=11;有 password 回 error=3。 |
| sub 未綁,但 token email = 既有 user email | 不需 password/device,採用該 user;該 user 尚未綁 LINE 才新增 link。 |
| email 不存在,phone / verify_code 有提供 | 走 auto signup,取得 user id 後寫 LINE link。 |
| invalid token | 不產生 LINE 專屬 error;最後走一般 actor failure。 |
| request 沒 email | 即使 token 有 email,也回 error=11。 |
line_users insert allowlist
| 欄位 | 來源 |
|---|---|
created | 當下時間,對齊 Cake timestamp callback。 |
user_id | actor / new user id。 |
line_user_id | line_verify_logs.sub。 |
name | line_verify_logs.name。 |
email | line_verify_logs.email。 |
Legacy 不寫 refresh_token。本地 schema 沒有 sub / user unique index;仍須維持 Legacy 的先查再寫行為。
Device-only gap
Current Legacy QuoteRequestsController.php:2169-2177 在 device 相同時只設 $device_id_login_success,不再設定 $user_id,最後於 2355-2378 回 error=2。
PHP 8 CredentialActorResolver.php:116-130 仍允許 device-only actor。依 parity 預設應調整;若保留 current 行為,必須先記錄 reviewer 接受的 migration decision。
Session gap
| 情境 | Legacy | PHP 8 current |
|---|---|---|
| user/device 已有 row | token 原樣 reuse;不更新、不寫 DB log | shared upsert 依 API key 寫 exist_logout、刪除舊 token,再建立新 token並寫 login |
| user/device 沒有 row | insert session,並寫 api_session_logs.action=login | shared upsert 已 insert session 並寫 action=login |
剩餘差異是 existing-token reuse。需新增 search_add scoped find-or-create method,不能改 shared upsert,也不能把任何 rotate 行為直接給 search_add。
api_session_logs 新 row 欄位為 created/user_id/params/session_id/device_id/api_key/action;action 固定 login,admin_user_id 維持 Legacy default。
Response / side effects
- LINE 不增加 response 欄位;success contract仍是
error/message/user_id/username/session_id/QuoteRequest/QuoteBid。 - 可能寫入:
users、user_profiles、line_users、api_sessions、api_session_logs、user_logins與既有 signup side effects。 - 既有 session reuse 不應產生額外 DB write。
Verification
Core
- linked LINE user + matching email。
- unlinked LINE sub + existing same-email user,新增 link。
- LINE auto signup +
line_users+ new session login log。 - existing session 原 token reuse,session row 不更新。
Other
- invalid / missing token、missing request email、email mismatch。
- duplicate sub、user 已有其他 LINE link。
- social credential precedence。
- device-only 回
error=2。 - success / error response value 與 JSON type。
2026-08-10 複核結果:
SearchAddInputTest.php:OK (9 tests, 24 assertions)。CredentialActorResolverTest.php:OK (12 tests, 62 assertions);所有成功 actor 的user_id均以 string 驗證。SearchAddLineIdentityRepositoryIntegrationTest.php:OK (2 tests, 20 assertions)。php -d output_buffering=4096 ... SearchAddStep8IntegrationTest.php:OK (9 tests, 93 assertions)。
LINE 專屬 actor / link 已有測試,但 device-only 與 scoped session reuse/login-log 尚未實作,因此本頁仍不可標 verified。
merge 後的 shared ApiSession::upsert() 在一般 PHPUnit CLI 沒有 output buffering 時會因 session header warning 回 null;同一組 Step8 測試不加 buffering 時有 1 error。這是目前測試執行相容性待處理項目。
Log / config 風險
- Legacy request info log 會包含完整
line_id_token;PHP 8 Router 目前也只過濾 password key。是否增加 token filter 必須先由 reviewer做 migration decision。 - search_add 本身不讀 LINE client config;end-to-end OAuth 依賴
LINE_LOGIN_CLIENT_ID、LINE_LOGIN_SECRET、api.url、site.url。 - 本地 CLI 兩個 LINE constants 未定義;staging / production 實際值與 callback allowlist 待確認。
Endpoint/V1/Line.php:58,351仍有 staging redirect hardcode;client config 使用處位於51-52,82-83,95-96,368-369,382-383,production 上線前必須確認部署設定。