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-1826API session actor 與 request log。
QuoteRequestsController.php:2024-2111request user input 與 social identity;優先序為 Google → Facebook → Facebook limited → Apple → LINE。
QuoteRequestsController.php:2122-2188social/email actor、password、device、LINE same-email 綁定。
QuoteRequestsController.php:2206-2347auto signup、LINE link、profile、login、session reuse。
QuoteRequestsController.php:2355-2378actor failure response。
QuoteRequestsController.php:3147-3152session 不存在時建立。
LineVerifyLog.php:13-17依完整 id token 查 verify log。
LineUser.php:13-52sub 找 user、判斷 user 是否已綁、建立 link。
ApiSession.php:20-25,34-80,102-140search_add 先 reuse;只有缺 row 才 insert / login log。

PHP 8.2

Current 位置職責 / 差異
SearchAddHandler.php:142-198session → credential → signup。
ActorResolver.php:10-30session actor。
SearchAddInput.php:318-335User[line_id_token],並依 Legacy input chain 決定是否處理 LINE。
CredentialActorResolver.php:23-155,259-275,407-425,467-492LINE 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-467auto signup 建 user 後寫 line_users
ApiSession.php:66-140shared upsert;依 user/device/API key 取代同 app session,仍不是 Legacy search_add 的 existing-token reuse。
Endpoint/V1/Line.php:27-190LINE 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_idactor / new user id。
line_user_idline_verify_logs.sub
nameline_verify_logs.name
emailline_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-2378error=2

PHP 8 CredentialActorResolver.php:116-130 仍允許 device-only actor。依 parity 預設應調整;若保留 current 行為,必須先記錄 reviewer 接受的 migration decision。

Session gap

情境LegacyPHP 8 current
user/device 已有 rowtoken 原樣 reuse;不更新、不寫 DB logshared upsert 依 API key 寫 exist_logout、刪除舊 token,再建立新 token並寫 login
user/device 沒有 rowinsert session,並寫 api_session_logs.action=loginshared 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/actionaction 固定 loginadmin_user_id 維持 Legacy default。

Response / side effects

  • LINE 不增加 response 欄位;success contract仍是 error/message/user_id/username/session_id/QuoteRequest/QuoteBid
  • 可能寫入:usersuser_profilesline_usersapi_sessionsapi_session_logsuser_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.phpOK (9 tests, 24 assertions)
  • CredentialActorResolverTest.phpOK (12 tests, 62 assertions);所有成功 actor 的 user_id 均以 string 驗證。
  • SearchAddLineIdentityRepositoryIntegrationTest.phpOK (2 tests, 20 assertions)
  • php -d output_buffering=4096 ... SearchAddStep8IntegrationTest.phpOK (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_IDLINE_LOGIN_SECRETapi.urlsite.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 上線前必須確認部署設定。