最近更新 API

這份文件只記錄近期更新或需要切換確認的 API 摘要,方便前後端、QA 與 LB 切換時快速對照。

完整 legacy parity、DB side effect、測試結果與切換驗證細節,仍以各 API detail 文件為準。

新的調整一律追加在文件最下面,避免改動既有排序造成 review 時難以判斷新增內容。

POST /quote_bids/want_to_contact_provider/{quote_bid_id}.json

功能說明

消費者在報價列表點選「立即回覆」,進入單一報價頁後,再點選「開始洽談」並選擇快速回覆時,會呼叫此 API。

操作路徑

  1. 消費者在首頁點選「查看需求」
  2. 進入報價列表頁:/dashboard/projects/quotelist/21874
  3. 點選專家的「立即回覆」
  4. 進入報價詳情頁:/dashboard/projects/quote/21874/2147688065
  5. 點選「開始洽談」
  6. 選擇快速回覆
  7. 呼叫 API:POST /quote_bids/want_to_contact_provider/{quote_bid_id}.json

備註

更新時間:2026-05-20 11:05

POST /quote_bids/consumer_want_provider_quote/{quote_bid_id}.json

功能說明

消費者在新客源 / narrow match 卡片邀請指定專家報價時,會呼叫此 API。

成功後,同一筆 quote bid 會進入 waiting invitation 狀態,並建立 WantProviderQuote activity。

操作路徑

備註

更新時間:2026-05-19

POST /quote_bids/provider_accept_narrow_match/{quote_bid_id}.json

功能說明

專家回應消費者送出的 narrow match invitation 時,會呼叫此 API。

接受邀請時,會把 bid 轉進聯絡 / 扣款主線;拒絕邀請時,會更新 narrow match 狀態並寫對應 activity。

操作路徑

備註

更新時間:2026-05-07

POST /quote_bids/change_status/reviews/{quote_bid_id}.json

功能說明

消費者對已聯絡的專家送出評價時,會呼叫此 API。

一般 review 流程已補齊。completed / closed 狀態流仍拆在另一份文件追蹤,不和一般 reviews 混在一起。

操作路徑

備註

更新時間:2026-05-13

POST /quote_bids/change_status/rating/{quote_bid_id}.json

功能說明

專家送出報價或處理 contact charge / 手動報價付款流程時,會呼叫此 API。

這支是 change_status 裡付款與通知 side effect 較重的 API。

操作路徑

備註

更新時間:2026-05-13

POST /quote_bids/change_status/self_hire/{quote_bid_id}.json

功能說明

專家在已聯絡且進行中的案件中,自行標記已接案時,會呼叫此 API。

操作路徑

備註

更新時間:2026-05-13

POST /quote_requests/copy/{quote_request_id}.json

功能說明

消費者複製既有需求時,會呼叫此 API。

這不是單純複製 quote_requests row,而是拿舊 request 當來源,重新跑一輪建單、fee、summary、異常掃描與配對後處理。

操作路徑

備註

更新時間:2026-04-27

GET /quote_bids/preview_quote_fee/{quote_bid_id}/is_auto_quote:{is_auto_quote}.json

功能說明

專家在送出報價或聯絡前,預覽本次需要支付的費用時,會呼叫此 API。

這支 API 會依照 quote bid、quote request、報價類型與可用折扣,回傳原始費用、實際費用、費用原因與 contact charge 資訊;只做費用預覽,不會扣款,也不會送出報價。

操作路徑

  1. 專家進入案件列表或案件詳情頁
  2. 在尚未正式送出報價 / 聯絡前,前端呼叫 API:GET /quote_bids/preview_quote_fee/{quote_bid_id}/is_auto_quote:{is_auto_quote}.json

備註

手動報價 is_auto_quote:0 時,費用主要來自 quote_requests.manual_fee,並會套用 quote_requests.manual_fee_discount

manual_fee_discount = 1.0000 代表無折扣;0.8000 代表 8 折;0.6000 代表 6 折。

更新時間:2026-05-22

POST /quote_requests/edit.json

功能說明

消費者在需求成立後,修改「電話可聯絡時間」時,會呼叫此 API。

這支 API 會依照 quote request owner、quote_request_id 與 fields.phone_available_time,更新需求上的電話可聯絡時間,並同步控制是否將電話資訊顯示給 provider;只處理電話可聯絡時間,不會修改需求表單答案、需求摘要、費用、activity 或 notification。

操作路徑

  1. 消費者進入需求管理或需求詳情頁。
  2. 在修改電話可聯絡時間後,前端呼叫 API:POST /quote_requests/edit.json

備註

fields[phone_available_time] 非空時,會寫入 quote_requests.phone_available_time,並設定 quote_requests.is_show_phone_to_providers = 1

fields[phone_available_time] 為空字串或 trim 後為空時,會寫入原字串,並設定 quote_requests.is_show_phone_to_providers = 0

成功 response:

{"error":0,"message":"success"}

只有香港環境 area = hkquote_requests.match_type in (Multiple, Authorize) 時,才會透過 Redis 60 秒去重後寫入 newQuoteRequest queue;台灣 / local TW 環境不會因這支 API 寫 queue。

更新時間:2026-05-25

POST /quote_bids/want_to_contact_provider_for_call_jwt

POST /quote_bids/call_fee_jwt

功能說明

電話聯絡流程在通話有接通或進入可收費條件後,會由 Twilio / Infobip callback 內部呼叫這兩支 API。

want_to_contact_provider_for_call_jwt 用來保證電話聯絡成功後,仍會進入聯絡 provider 的扣款與 contact side effect 主線。

call_fee_jwt 用來在通話超過免費秒數後,補收電話接通服務費;它只處理電話費 transaction,不直接建立通話狀態。

操作路徑

  1. consumer 發起電話聯絡。
  2. Twilio / Infobip callback 更新 quote_bid_calls
  3. 通話接通且 DialCallDuration > 0 時,callback 呼叫 POST /quote_bids/want_to_contact_provider_for_call_jwt
  4. 通話超過 180 秒時,callback 計算 call fee 後呼叫 POST /quote_bids/call_fee_jwt

備註

Load Balancer 要新增兩條精準 path 並切到 PHP 8.2 / pro360_api_82 target group:

/quote_bids/want_to_contact_provider_for_call_jwt
/quote_bids/call_fee_jwt

不要使用 /quote_bids/*/quote_bids/want_to_contact_provider*,避免誤切其他 quote_bids API。

完整 LB rule order、切換前後驗證與本地實測結果見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_bids/call_jwt.md

更新時間:2026-05-27

POST /quote_bids/switch_to_manual_quote/{quote_bid_id}.json

功能說明

provider 在尚未聯絡 consumer 的 auto quote bid 上,選擇改成自己手動送出報價時會呼叫此 API。

成功後,同一筆 bid 會變成一般手動報價已送出且已付款:is_auto_quote = 0is_want_to_contact_provider = 1is_paid_for_subscription = 1is_contact_charge = 0,並依手動報價規則重算 total_site_fee。付款會寫入 transaction / subscription log;後續會建立 SwitchToManualQuote activity、送出 consumer 收到報價通知,並寫入 counter queue。

操作路徑

  1. provider 開啟 auto quote / 保證回覆相關案件。
  2. provider 選擇改用手動報價。
  3. 若 wallet 不足,可能會帶 TapPay prime
  4. 前端呼叫 API:POST /quote_bids/switch_to_manual_quote/{quote_bid_id}.json

備註

2026-05-27 正式機 access log 查到 934 筆,已補 action、routing 與 PHPUnit。

web-app 實際呼叫 path 帶 quote_bid_id,body 是 FormData,只有需要 TapPay 時才帶 prime。目前新專案也保留 request body 帶 quote_bid_id 的 fallback;仍需回填正式流量 path 分布。

2026-05-28 staging 新 code 實測:

POST https://api-staging.pro360.com.tw/quote_bids/switch_to_manual_quote/2147689868.json
body: empty FormData
response: {"status":"success","error":0}

DB 結果符合 legacy:quote_bids.id = 2147689868 已轉成 manual quote,is_auto_quote = 0is_want_to_contact_provider = 1is_contact_charge = 0is_paid_for_subscription = 1is_restore_balance = 1total_site_fee = 160,並寫入 quote_user_subscription_log_id = 20815

付款路徑是「wallet 不足、有有效 auto quote card、但 unpaid auto quote debt 未達刷卡門檻」:本次新增 transactions.id = 36859transaction_type_id = 40amount = 160real_pay_date = NULL,和同 bid 原 auto quote debt 36858 / 176 合計 debt = 336,未達 quote.auto_quote_max_debt 500,因此 success 但不立即刷卡,符合 legacy processCharge() + chargeByCreditCard() threshold 行為。

side effect 已確認:SwitchToManualQuote activity、AutoQuoteRestoreBalance activity、Receive_Quote event log、request_sent_count / request_requestor_read_count task log 都存在。quote_user_subscription_logs.quote_bid_id 因 signed int 上限顯示為 2147483647,驗證時要以 quote_bids.quote_user_subscription_log_id -> quote_user_subscription_logs.id 為準。

完整 legacy rule、DB side effect 與測試結果見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_bids/switch_to_manual_quote.md

更新時間:2026-05-28

POST /quote_bids/provider_receive_phone/{quote_bid_id}.json

功能說明

provider 在已送出手動報價後,主動點開 consumer 電話資訊時會呼叫此 API。

成功後,同一筆 quote_bids.id 會標記 is_provider_received_phone = 1;第一次成功時會建立 ProReceivePhone activity。這支不處理付款,不寫 transaction / subscription log,也不送 queue。

操作路徑

  1. provider 進入案件詳情或 chat。
  2. consumer phone 可顯示,且前端仍判斷 is_provider_received_phone = 0
  3. provider 點開電話資訊。
  4. 前端呼叫 API:POST /quote_bids/provider_receive_phone/{quote_bid_id}.json

備註

2026-05-28 正式機 access log 查到 6246 筆,全部 access log status 200。正式流量與 web-app 都使用 path id:/quote_bids/provider_receive_phone/{quote_bid_id}.json

已補 action、routing 與 PHPUnit,覆蓋 success、idempotent、auto quote guard、closed request guard、refunded guard。staging 已驗證 success response、quote_bids.is_provider_received_phone = 1ProReceivePhone activity。

完整 legacy rule、逐段行數對照與測試結果見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_bids/provider_receive_phone.md

更新時間:2026-05-28

POST /quote_bids/edit/{quote_bid_id}.json

功能說明

provider 在案件列表 / 報價卡片標記或取消標記重要案件時會呼叫此 API。

這支只更新 quote_bids.provider_tag,並建立 UpdateQuoteBid activity、更新 my work unread count;不處理付款、transaction、subscription log 或通知 queue。

操作路徑

  1. provider 進入案件列表或案件詳情。
  2. provider 點擊標記圖示。
  3. 前端送出 FormData provider_tag
  4. 前端呼叫 API:POST /quote_bids/edit/{quote_bid_id}.json

備註

2026-05-28 正式機 access log 查到 POST 200 合計 16569 筆,另有 OPTIONS 200 合計 918 筆。

web-app 目前只會送:

provider_tag=favorite
provider_tag=

legacy 只檢查 isset(provider_tag),不限制值;空字串會寫入空字串,不是 NULL

2026-05-29 staging 觀察到部署前 response 是 {"error":0,"message":"success"};這來自 RouterV3::dispatch() 在 action 沒有明確 $this->json() 時補的預設 response,不是 legacy 行為。legacy 與 web-app 成功判斷都要求 message = "Success",新程式已補明確 response,避免大小寫差異造成前端誤判。

完整 legacy rule、web-app caller、逐段對照與測試結果見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_bids/edit.md

更新時間:2026-05-29

GET /quote_bids/consumer_want_to_see_more_quote/{quote_request_id}/page:{page}/limit:{limit}.json

功能說明

consumer 在邀請更多專家報價時會呼叫此 API。

這支只讀取同一筆 quote_requests.id 底下仍可被 consumer 邀請的 narrow match bid 清單;不更新 bid / request,不建立 activity、queue、transaction 或通知。真正送出邀請的是 POST /quote_bids/consumer_want_provider_quote/{quote_bid_id}.json

操作路徑

  1. consumer 在服務頁或建單後進入「推薦更多專家」流程。
  2. 前端已有部分推薦 bids;若數量不足目標上限,會補撈更多可邀請 bid。
  3. 前端呼叫 API:GET /quote_bids/consumer_want_to_see_more_quote/{quote_request_id}/page:{page}/limit:{limit}.json

備註

2026-05-28 正式機 access log 查到 GET 200 合計 1688 筆,另有 OPTIONS 200 合計 953 筆。

web-app 實際 caller 是 APIManager.getMoreProWithRequest(id, limit = 0, page = 1),path 使用 quote_request_id,不送 body。

legacy 與 new 都只回 narrow match NOT_SEND bids;已用 staging request 22447 對照 legacy response,回傳 bid id、pagination meta 與 nested response id shape 均一致。staging response 對表已完成。

完整 legacy rule、web-app caller、逐段對照、DB 對照與測試結果見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_bids/consumer_want_to_see_more_quote.md

更新時間:2026-06-17

POST /quote_bids/add_consumer_survey/quote_bid_id:{quote_bid_id}.json

功能說明

consumer 在案件後續填寫實際支付 / 預算問卷時呼叫此 API。

這支只新增或覆蓋 quote_consumer_surveys;不更新 bid / request,不建立 activity、queue、transaction 或通知。

操作路徑

  1. consumer 進入案件後續問卷或支付資訊填寫流程。
  2. 前端收集 total_paycommentunit
  3. 前端呼叫 API:POST /quote_bids/add_consumer_survey/quote_bid_id:{quote_bid_id}.json

備註

2026-06-02 正式機 access log 查到 POST 200 合計 598 筆,另有 OPTIONS 200 合計 104 筆。

web-app 實際 caller 是 APIManager.postBudgetSurvey(quoteId, budget, comment, unit),body 是 FormData。legacy 成功 response 是 {"error":0,"status":"success"};bid 不存在回 error=2/status=quote_bid_not_found,不是 request owner 回 error=3/status=not_consumer

已補 action、routing 與 PHPUnit,覆蓋新增、覆蓋同一筆 survey、缺欄位清成 legacy 預設、bid missing、非 request owner、invalid session。完整 legacy rule、DB side effect 與測試結果見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_bids/add_consumer_survey.md

更新時間:2026-06-02

POST /quote_bids/provider_request_review/{quote_bid_id}.json

功能說明

provider 在已聯絡 consumer 的案件中,邀請 consumer 留下評價時會呼叫此 API。

成功後會更新 quote_bids.review_requested_at,建立 ProviderInviteReview activity,並寫入 Request_Review event;若 body 有 invite_info,會同步更新 quote_services.invite_info,沒有則沿用既有邀請文字。

操作路徑

  1. provider 進入已聯絡案件的詳情或 chat。
  2. 前端判斷尚未邀請評價,且未被封鎖。
  3. provider 點選「邀請評價」。
  4. 前端呼叫 API:POST /quote_bids/provider_request_review/{quote_bid_id}.json

備註

2026-06-01 正式機 access log 查到 POST 200 合計 961 筆,另有 OPTIONS 200 合計 41 筆。

web-app 實際 caller 是 APIManager.requestReviewForBid(bid_id, invite_info),body 是 FormDatainvite_info 可省略。若頁面已有 chat room,web-app 會先送 chat message,再呼叫本 API;該 SendChat activity 不屬於本 API side effect。正式流量 caller 包含 iOS app、Android app 與 web。

Config 切換檢查:

  • 觸發條件:notification payload 使用 ##STAR_ICON##
  • 必要 key:mail.icon.star_full
  • legacy 正式機值:https://s3-ap-northeast-1.amazonaws.com/pro360/images/icon/star_full.png
  • new 本地設定:確認 Lib/Common/Configuration.phpProConfig::$config 有同名 key。
  • 部署設定:staging / production 的實際 config 也要同步;Configuration.php.gitignore 忽略,不會隨一般 commit 自動部署。
  • 補 mail icon 時,建議以正式機 mail.icon.* 區塊為準一次補齊,不要只看本地 legacy checkout。

已補 action、routing 與 PHPUnit,覆蓋 success、沿用既有 invite_info、非 bid owner guard、blocked chat guard。完整 legacy rule、side effect 與測試結果見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_bids/provider_request_review.md

2026-06-17 new staging 已用 web-app FormData 實測:

POST /quote_bids/provider_request_review/2147691285.json
response: {"error":0,"status":"Success"}

DB / queue 已確認:

  • quote_bids.review_requested_at 已更新。
  • quote_services.invite_info 已寫入 request body。
  • 已建立 ProviderInviteReview activity 與 quote_activity_consumers
  • 已建立 security_hashes public review hash。
  • Request_Review event 已被 worker 搬到 event_queue_log_3,payload 含 INVITE_INFOSTAR_ICON、public REVIEW_URL,task 包含 MoEngage、push、web push。

同一操作的 SendChat activity 是 web-app 先送 chat message,不屬於本 API side effect。requestor 本次沒有 fetnet_users row,因此沒有 unread counter 可更新。

更新時間:2026-06-17

GET /quote_services/static_fields.json

功能說明

provider 建立 / 編輯服務資料時讀取 static fields。legacy 目前固定回空 StaticFormField,不讀寫 DB。

操作路徑

  1. provider 進入專家加入頁:/pro
  2. 頁面載入 ProQuestionnairePopupContainer
  3. componentDidMount() 呼叫 fetchProQUestionnaire()
  4. 前端呼叫 API:GET /quote_services/static_fields.json

也會在 /pro-signup/:slug/pro-newyear 觸發。這支不是 dashboard 服務編輯頁 /dashboard/profiles... 的主要 API。

備註

2026-06-03 正式機 access log 查到 GET 200 合計 7006 筆,另有 OPTIONS 200 合計 6632 筆。

legacy 成功 response 固定是:

{"StaticFormField":[]}

已補 action、routing 與 PHPUnit。完整 legacy rule、side effect 與測試結果見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_services/static_fields.md

更新時間:2026-06-03

POST /quote_services/change_status/archive/{quote_service_id}.json

功能說明

provider 在前端刪除公司資料時呼叫。前端文案是「刪除公司」,後端實際行為是把 service 標記為 archived,並同步寫 activity 與 task event。

操作路徑

  1. provider 進入 /dashboard/profiles/dashboard/profiles/{quote_service_id}/...
  2. provider 在服務資料編輯頁選擇「刪除公司」。
  3. 前端呼叫 deleteService(),實際送出 API:POST /quote_services/change_status/archive/{quote_service_id}.json

備註

成功 response:

{"error":0,"status":"Success"}

已補 action、routing 與 PHPUnit。完整 legacy rule、DB side effect 與測試結果見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_services/change_status/archive.md

同一個 legacy change_status 入口還有 profile_ready,已另以獨立文件與測試搬移;不可套用 archive 的簡單狀態更新結論。

更新時間:2026-06-03

GET /quote_services/external_review/link/{quote_service_id}.json

功能說明

provider 進入服務資料編輯頁時呼叫,用來預先取得服務評價邀請連結。前端可見入口是「服務評價」;點進該編輯內容後,內部標題顯示為「推薦」。已有 external_review_url 時直接回傳;空值時會建立 security_hashes,產生短網址並寫回 service。

操作路徑

  1. provider 進入 /dashboard/profiles/
  2. 點選新增專家檔案或進入既有服務資料。
  3. 前端進入 /dashboard/profiles/{quote_service_id}/0/dashboard/profiles/{quote_service_id}/...
  4. ServicesContainer.displayServiceWithIndex() dispatch selectService() 後呼叫 getExternalReviewLink()
  5. 服務資料頁「服務評價」入口下的「推薦」內容使用回傳的 short_url,前端 API 為:GET /quote_services/external_review/link/{quote_service_id}.json

正式機流量

2026-06-04 查正式機 access log:

4433 GET     /quote_services/external_review/link/{quote_service_id}.json 200
3568 OPTIONS /quote_services/external_review/link/{quote_service_id}.json 200
 125 POST    /quote_services/external_review/submit.json 200
  82 OPTIONS /quote_services/external_review/submit.json 200

同一流程另有 POST /quote_services/external_review/invite/{quote_service_id}.jsonPOST /quote_services/external_review/submit.json,已各自拆成 detail doc。

備註

成功 response:

{"error":0,"message":"Success","short_url":"..."}

2026-06-04 staging 實測 legacy response 範例:

{"error":0,"message":"Success","short_url":"https://p36.net/sw/NlkXw"}

已補 action、routing 與 PHPUnit。完整 legacy rule、DB side effect 與測試結果見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_services/external_review/link.md

更新時間:2026-06-04

POST /quote_services/external_review/invite/{quote_service_id}.json

功能說明

provider 對外寄送服務評價邀請 email。request 支援單一 email 與多筆 emails;每個收件人各寫一筆 External_Review event queue,template key 是 390 External Review Invite

流量與前端狀態

2026-06-04 正式機 quote_services/external_review 統計只看到 linksubmit,未列出 invite path;web-app 目前也只找到 link / submit caller。仍補 invite 是因為 legacy controller 有完整 invite 分支,且 external_review 已拆成 explicit routes。

Response 與 Side Effect

  • invalid session:{"error":1,"message":"Invalid session"}
  • 有 session 但無收件人:{"error":2,"message":"Invalid data"}
  • success:{"error":0,"message":"Success"}
  • legacy 沒有 service owner guard;新版照 legacy,只要 session 有效就使用 path 的 quote_service_id
  • legacy 會先取得 external review URL,再判斷收件人;因此無收件人時仍可能建立 / 寫回 quote_services.external_review_url
  • success 會寫 External_Review event queue,payload 內含 email task 與 replacement

Config 切換檢查

這支 mail template 直接需要 mail.icon.star_full 作為 ##STAR_ICON##。目前 Lib/Common/Configuration.php:288docker/staging/Configuration.php:279 都有:

https://s3-ap-northeast-1.amazonaws.com/pro360/images/icon/star_full.png

切 staging / production 時要確認實際部署 config 也有同 key;不可只看本地 legacy checkout 判斷設定不存在。

已補 action、routing 與 PHPUnit。完整 legacy rule、event payload 與測試結果見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_services/external_review/invite.md

更新時間:2026-06-04

POST /quote_services/external_review/submit.json

功能說明

consumer 透過外部評價頁提交服務評價時呼叫。此 API 會先 resolve 提交者;有 session 時使用 session user,無 session 時使用 User[...] 欄位登入或自動建立 consumer user。hash owner 不可評價自己。

正式機流量

2026-06-04 查正式機 access log:

125 POST    /quote_services/external_review/submit.json 200
 82 OPTIONS /quote_services/external_review/submit.json 200

Response 與 Side Effect

  • invalid hash:{"error":4,"message":"Invalid hash"}
  • same user:{"error":5,"message":"Cannot review the same user"}
  • success:{"error":0,"message":"Success"};若走無 session 登入 / 註冊路徑,會附 session_id
  • success 會建立 quote_feedbacksmodel = QuoteServiceforeign_id = quote_service_id
  • success 會寫 QuoteService / AddReview activity,param1 為原始 QuoteFeedback JSON

備註

legacy updateUserFeedbackStats() 只統計 model = QuoteBids;外部 service review 仍照 legacy 呼叫此 helper,但不會因此更新 service stats。

已補 action、routing 與 PHPUnit。完整 legacy rule、DB side effect 與測試結果見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_services/external_review/submit.md

更新時間:2026-06-04

POST /quote_services/change_status/profile_ready/{quote_service_id}.json

功能說明

provider 完成 onboarding 服務資料後呼叫。後端會啟用 service、設定 users.onboard_state = 2、更新 quote_services.modified,並寫 ServiceProfileReady activity。

操作路徑

  1. provider 進入 /dashboard/onboarding/{quote_service_id} onboarding 流程;服務資料頁可能由 /dashboard/profiles 導入。
  2. 完成服務資料設定。
  3. 前端 OnboardingContainer.onEndOnboarding() 呼叫 APIManager.markServiceProfileReady()
  4. 實際送出 API:POST /quote_services/change_status/profile_ready/{quote_service_id}.json

備註

成功 response:

{"error":0,"status":"Success"}

這支有舊版免費點數分支。若 user_id > start_identity_free_credit_user_id,只會啟用 service、設 onboard、更新 modified、寫 activity;不排 newQuoteService、不送 Pro_Ready、不改 wallet。若進舊 user 分支,需依 free_credit_events.slug = quote.free_credit_new_providerquote.free_credit_new_provider config 決定 wallet / transaction / event 寫入。

切換前需確認部署環境:

  • start_identity_free_credit_user_id
  • free_credit_eventsquote.free_credit_new_provider system event
  • quote.free_credit_new_provider config fallback

已補 action、routing 與 PHPUnit。完整 legacy rule、DB 寫入、config 檢查與測試結果見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_services/change_status/profile_ready.md

更新時間:2026-06-04

POST /quote_services/add.json

功能說明

provider 新增專家服務檔案時呼叫的 JSON API。已按 legacy QuoteServicesController::add() 搬移,包含 session user、無 session 登入 / 註冊、social path、service 建立、category mapping、external review URL、activity、queue、notification 與 other category report / email。

完整 legacy rule、DB side effect、config 檢查與測試結果見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_services/add.md

前端觸發

主要入口:

  1. provider 進入 https://staging.pro360.com.tw/dashboard/profiles
  2. 點選頁面下方「新增專家檔案」
  3. 完成服務資料表單後,前端送出 POST /quote_services/add.json

相關前端 path:

  • 已登入 provider 新增 service:ServicesContainer / GoogleReservePro
  • 未登入或問卷新增 service:questionnaireActions.submitServiceQuestionnaire();成功後由 ProQuestionnairePopupContainer 將 response session_id 寫入 session_token cookie

流量與範圍

2026-06-12 查正式機 access log:

2209 POST    /quote_services/add.json 200
 887 OPTIONS /quote_services/add.json 200

同次查詢 /quote_services/add/quote_services/add/... legacy HTML path,未看到流量;本次搬移範圍以 JSON API 為準。

legacy HTML page 才用到的 Sudopay payout view state 不在 JSON API response 內,新版 API 不搬這段 view-only state。

對外行為

成功 response:

{"error":0,"service_id":123,"session_id":"...","user_id":456}

Legacy 相容重點

  • QuoteCategory: [""] 是有效 input:會建立 service,但不建立 numeric category mapping;不可改成 category required error。
  • QuoteService[travel_pref] 需支援 legacy web-app 格式:travel_vendor.value / travel_customer.value / remote.value
  • 沒送 QuoteService[address] 時,即使有 zip_code 也保留傳入的 full_address
  • is_not_this_area=1 時保留傳入的 full_address
  • travel_upto 未勾時,service_provider_travels_upto 清成 0
  • City[name/id]State[name/id]、zip-derived city/state、city slug 需維持 legacy 行為。
  • 新 user name fallback、email verification guard、social login path、counter cache、service_update queue 皆已對齊 legacy。
  • sendProviderNeedNewCategoryMail() 目前 new 有 empty email guard,legacy helper 沒有;因為是 shared helper,且前端 add path 未看到送 other|... category,先列為 staging 必查,不直接改 shared behavior。

Side Effect / Logging

  • 建立 quote_services
  • 建立 numeric category mapping;但 QuoteCategory: [""] 不建立 mapping。
  • 產生 external_review_url
  • QuoteService activity。
  • newQuoteService queue。
  • request log:new 不再補 legacy quote_services/add::POST / quote_services_add endpoint duplicate full request log;保留 RouterV3 generic request log,password/passwd key 由 router 層過濾。
  • newServiceScan:失敗只寫 LogHelper,不中斷新增 service 成功流程。

legacy 的 CakeLog::info(...) / $this->log(...) 是 CakePHP file log;new project 沒有 CakePHP file logging,FileLogHandler 目前是 no-op。若要求 literal file-log parity,需另補新專案 file log handler 或指定替代 channel。

Config / 部署檢查

ProConfig 指的是 new 專案 Lib/Common/Configuration.phpclass ProConfig { public static $config = [...] }。要補的 key 就放在這個 array,或放在 staging / production 等效的部署 config。這個檔案可能不在一般 commit 內,切環境時要查實際部署值。

注意:不要在台灣環境補 ProConfig::$config['area'] = 'tw'。這個專案的 area key 是非台灣環境開關,只能在確認為 sg / hk 等非 TW 部署時設定;台灣環境維持未設定 / 空值。sys_area = tw 不能當成要補 area = tw 的依據。

值的來源以 legacy 部署環境為準:優先查正式 / 測試機 /var/www/html/app/Config/settings.yml,再用本地 legacy get-lancer-php56/app/Config/settings.yml 輔助比對。本地 checkout 沒有的 key 不代表不存在,要查部署環境。

必補 / 必查 ProConfig::$config

key用途legacy 值來源
site.urlexternal review long URL、service management URL、email replacementlegacy settings.ymlsite.url
yourls.api_url, yourls.api_key產生 external review 短網址legacy 部署環境 settings.yml 同名 key;本地 checkout 未必有
email.signatureother category provider email replacementlegacy settings.ymlemail.signature
mail.icon.help_center, mail.icon.resume_instructionother category provider email icon replacementlegacy 部署環境 settings.yml 同名 key;本地找不到時仍要查實際環境
EmailTemplate.from_emailemail sender fallbacklegacy settings.ymlEmailTemplate.from_email

實測 / 測試

2026-06-12 legacy staging 實測確認:QuoteCategory[0]="" 會建立 service、不建立 numeric mapping;request 沒有 QuoteService[address] 時保留傳入 full_addressphone_number 未傳時 fallback 到 user_profiles.phone,但不建立 service_update queue。

2026-06-15 new staging 實測確認:從 https://staging.pro360.com.tw/dashboard/profiles 點「新增專家檔案」送出後,response 為 {"error":0,"service_id":13665,"session_id":"...","user_id":8617}。DB 確認 service 建立、空 category 不建 mapping、external review URL 建立、QuoteService activity 與 newQuoteService queue log 存在。

已補 action、routing 與 PHPUnit。

更新時間:2026-07-03

POST /quote_services/edit/{quote_service_id}.json

功能說明

專家在 dashboard 編輯專家檔案時呼叫。這支會更新 quote_services profile 欄位,並處理聯絡方式、logo attachment、照片 / YouTube、內容審核、category mapping、profile score、activity 與 queue。

操作路徑

  1. provider 進入 https://staging.pro360.com.tw/dashboard/profiles
  2. 開啟既有專家檔案編輯畫面
  3. 修改基本資料、服務地區、聯絡方式、照片或公開地址設定
  4. 前端呼叫 POST /quote_services/edit/{quote_service_id}.json

前端主要呼叫:

  • APIManager.updateServiceWithData(id, modified)
  • APIManager.updateServiceProfileVisibility(id, visibility)

Legacy 相容重點

  • 只用 quote_services.id 查原 service,owner guard 在查 row 後比對 user_id;不新增 active / archived guard。
  • 未送 QuoteCategory 時不更新 quote_category_ids,也不重建 mapping。
  • 更新 category 時重建 quote_categories_quote_services,並保留舊 mapping counter 欄位。
  • QuoteServiceContact 是 full sync;沒送的 contact key 會被 inactive,Website / LINE remove 時同步清 website_url / line_id
  • 移除舊 quote_service_categories 時會對齊 legacy side effect:auto quote bid 改 Removed、寫 category log,web / newer iOS pro 會同步刪 nshop service category。
  • logo / 一般照片會依 legacy QuoteUtil::gen_attachment_thumb() 語意產 amazon_s3_thumb_url;YouTube 影片不產縮圖。
  • phone_number key 存在即送 service_update task event。
  • activity param1 會保留 legacy mutate 後的 request JSON,包含 QuoteService.id/user_id/external_review_url
  • business_name 空白回 {"error":1,"message":"專家檔案名稱不可為空白"}
  • 成功 response:{"error":0,"message":"Success"}

實測 / 測試

已補 action、routing、thumbnail parity 與 PHPUnit。

2026-06-16 local container PHP 8.2:

docker exec -w /project-data cd63f9147e8d php vendor/bin/phpunit tests/QuoteServicesEditTest.php
OK (14 tests, 90 assertions)

同日回歸既有 quote_services tests,不含 edit 單檔:

docker exec -w /project-data cd63f9147e8d php vendor/bin/phpunit \
  tests/QuoteServicesAddTest.php \
  tests/QuoteServicesChangeStatusArchiveTest.php \
  tests/QuoteServicesChangeStatusProfileReadyTest.php \
  tests/QuoteServicesExternalReviewInviteTest.php \
  tests/QuoteServicesExternalReviewLinkTest.php \
  tests/QuoteServicesExternalReviewSubmitTest.php \
  tests/QuoteServicesStaticFieldsTest.php
OK (16 tests, 53 assertions)

更新時間:2026-06-16

GET /quote_services/search.json

功能說明

保留 legacy pro search compatibility endpoint,支援:

GET /quote_services/search.json
GET /quote_services/search/tag:{tag}.json
GET /quote_services/search/page:{page}.json

目前 web-app active pro list 已走 /quote_services/pro_list/page_size:{pageSize}/page:{page}/.../sort:hired_count/direction:desc.jsongetServicesWithTag() 仍存在,但 active caller 已註解。本 API 主要處理 legacy / old bundle / external 低流量相容。

Legacy 相容重點

  • response top-level key 固定為 services,total_pages,page
  • 每頁固定 20 筆,排序 QuoteService.id desc
  • tag 有值時才加 is_active = 1is_archived = 0
  • tag 找不到 service id 時,legacy 仍回 active/non-archived list;new 不改成空結果。
  • 沒有 tag 時不加 active / archived filter,維持 legacy no-tag list。
  • keyword query 不做文字搜尋;legacy staging 實測等同 no-tag list。
  • 每筆保留 legacy shape:QuoteServiceAttachmentUserQuoteFaqAnswerQuoteServicePhoto,並把 quote_category_ids 轉成 QuoteService.categories

實測 / 測試

2026-06-17 legacy staging 已測 /search/tag:{tag}、missing tag、search.json?keyword=a&page:1search.json

local container PHP 8.2:

docker exec -w /project-data cd63f9147e8d php vendor/bin/phpunit tests/QuoteServicesSearchTest.php
OK (3 tests, 23 assertions)

更新時間:2026-06-17

2026-06-18 QuoteBids 驗證狀態同步

範圍

  • POST /quote_bids/add_consumer_survey/quote_bid_id:{quote_bid_id}.json
  • POST /quote_bids/change_status/hired/{quote_bid_id}.json
  • completed / is_closed quote bid lifecycle 狀態流

結論

  • add_consumer_survey:staging response / DB 對表已完成;這支只 upsert quote_consumer_surveys,不寫 bid、activity、queue、transaction 或 notification。
  • change_status/hired:staging response / DB baseline 已確認;不再列為待 baseline 項目。
  • completed / is_closed:已確認現況,近期正式流量為 0,且 new 目前沒有獨立 completed route;暫不列下一支 migration 候選。若後續出現流量,再以 quote bid lifecycle 狀態流獨立處理。

完整規則維持在各 detail doc:

  • API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_bids/add_consumer_survey.md
  • API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_bids/change_status/hired.md
  • API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_bids/change_status/completed_closed.md

更新時間:2026-06-18

GET /quote_service_categories/pricing_form/{quote_category_id}.json

功能說明

provider 編輯服務分類 / 報價設定時讀取 pricing form schema。這支會回傳 pricing form fields、平均價格設定、pricing description、pricing unit 與預設週預算;legacy controller 只讀取資料並組 response,沒有業務資料寫入。

操作路徑

staging:進入項目管理頁 https://staging.pro360.com.tw/dashboard/services/9930/159,點「編輯」後再點「價格表」,會觸發 GET /quote_service_categories/pricing_form/159.json

流量與 caller

2026-06-18 查正式機目前保留的 get-lancer_access.log*quote_service_categories/pricing_form/{quote_category_id}.jsonquote_service_categories 系列最高流量候選之一。

高量樣本:

895 GET /quote_service_categories/pricing_form/201.json 200
829 GET /quote_service_categories/pricing_form/206.json 200
397 GET /quote_service_categories/pricing_form/290.json 200
372 GET /quote_service_categories/pricing_form/199.json 200

raw line 樣本主要來自 pro app pro360/6.6.0 ... Alamofire/5.10.2。web-app 也有 caller:APIManager.getQuoteServiceCategoryPricing(categoryID),path 為 /quote_service_categories/pricing_form/${categoryID}.json

同次流量也看到 POST /quote_service_categories/edit/.json 與多個 POST /quote_service_categories/edit/{id}.jsonedit 是寫入型 API,已另開 detail doc:API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_service_categories/edit.md

目前狀態

新專案已有 Endpoint/V1/QuoteServiceCategories.php::pricing_form();2026-06-18 已補 legacy 缺漏欄位並保留新專案既有 response marker:

  • Mapping.php 補 explicit pricing_form/{quote_category_id} route。
  • legacy success top-level 只有 quote_form_fields;new 保留 2022 舊 API 導流時加入的 top-level new = 1,作為 migration decision。
  • legacy 會把 default_weekly_budget_limit 放在 quote_form_fields 內;new 已補 quote_category_suggest_budgets.suggest_budget,無 row fallback 500
  • legacy staging category 159 已確認 top-level shape、pricing_unit = ""default_weekly_budget_limit = 800
  • 本地測試:docker exec -w /project-data cd63f9147e8d vendor/bin/phpunit tests/QuoteServiceCategoriesPricingFormTest.php 通過,OK (2 tests, 13 assertions)

完整 legacy / new 對照、migration decision 與測試結果見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_service_categories/pricing_form.md

更新時間:2026-06-18

POST /quote_service_categories/edit/.json / POST /quote_service_categories/edit/{quote_service_category_id}.json

功能說明

provider 在項目管理頁新增或編輯服務分類設定。這支 API 同時承接新增分類、接案偏好、服務方式 / 地區、價格表、預算、自動報價與直接預約開關。

流量與 caller

2026-06-18 查正式機目前保留的 get-lancer_access.log*,同次 quote_service_categories 統計看到:

561 POST /quote_service_categories/edit/.json 200
494 OPTIONS /quote_service_categories/edit/.json 200
 46 POST /quote_service_categories/edit/1395196.json 200
 38 POST /quote_service_categories/edit/1108340.json 200
 37 POST /quote_service_categories/edit/1382902.json 200

web-app caller 是 APIManager.postQuoteServiceCategoriesSetting(QSC),path 為 /quote_service_categories/edit/${QSC.id || ''}.jsonQSC.id 空值會打 /edit/.json,有 id 會打 /edit/{id}.json

目前狀態

新專案已補:

  • route:Lib/Common/RouterRule/Mapping.php
  • endpoint:Endpoint/V1/QuoteServiceCategories::edit()
  • model:QuoteServiceCategory::checkUserForEdit() / validateSave() / budget / pricing rows / auto quote log helpers

legacy controller 很薄,核心行為在 QuoteServiceCategory::validateSave(),new 已同步主要寫入與 side effect:

  • quote_service_categories
  • quote_categories_quote_services
  • quote_services
  • quote_service_category_logs
  • 條件式寫入 auto_quote_logsauto_quote_price_note_filter_logsquote_service_content_reviewsquote_service_prohibited_logs
  • 每次結尾會重建 pro_search_quote_pricing
  • legacy staging 已補 baseline:description / pricing update / service area / job preference / is_auto_quote_on = 1 success;direct reserve 開啟仍待獨立實測。

本地測試:

docker exec -w /project-data cd63f9147e8d vendor/bin/phpunit tests/QuoteServiceCategoriesEditTest.php
docker exec -w /project-data cd63f9147e8d vendor/bin/phpunit tests/QuoteServiceCategoriesPricingFormTest.php

結果:

tests/QuoteServiceCategoriesEditTest.php: OK (5 tests, 68 assertions)
tests/QuoteServiceCategoriesPricingFormTest.php: OK (2 tests, 13 assertions)

完整欄位分類、legacy side effect、legacy staging baseline 與 new staging 待驗證項目見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_service_categories/edit.md

更新時間:2026-06-22

POST /quote_categories/related.json

功能說明

前端依目前已選分類或 quote_service_id 取得相關分類推薦;主要實測入口是 provider 項目管理的新增服務項目流程。

本次已補 legacy path routing、selected_ids / filter_ids / quote_service_id 分支、association + related mapping、keyword fallback、final fallback 與 legacy response shape。

操作路徑

正式機 2026-06-22 access log 有 POST /quote_categories/related.json 200 共 7672 筆。

已確認專家端新增服務項目會觸發 quote_service_id 分支:

https://staging.pro360.com.tw/dashboard/services/add/{quote_service_id}

例如 quote_service_id=9930 時,前端送 POST /quote_categories/related.json,body 只有 quote_service_id=9930,response 為 {quote_categories: [...]}

公開分類頁 /category/:slug 也有可能透過 selected_ids 呼叫,但實際觸發依分類資料載入流程;不建議拿 https://staging.pro360.com.tw/category/home_repair 當主要驗證點。

備註

完整對照與測試見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_categories/related.md

更新時間:2026-06-23

GET /quote_categories/index/type:tree.json

功能說明

前端取得服務分類樹資料,用於服務管理、案件篩選、分類選擇與相關分類 UI。這支是 read-only API,不新增或編輯分類資料。

legacy response top-level key 是 quote_category_genres;genre 底下掛主分類 quote_categories,子分類掛在父分類 contains

操作路徑

web-app APIManager.getCategoriesTree() 呼叫:

GET /quote_categories/index/type:tree.json

正式機 2026-06-23 access log:

11984 GET /quote_categories/index/type:tree.json 200
 9717 OPTIONS /quote_categories/index/type:tree.json 200

備註

已補 type=tree 專用 branch、QuoteCategory::getTree() 與 PHPUnit;一般 /quote_categories/index.json 仍維持原本 quote_categories response。

2026-06-24 staging diff 後修正:legacy tree category 會帶 Attachment.amazon_s3_original_url,但 genre 查詢未 contain Attachment,因此不回 QuoteCategoryGenre.image_url / header_image_url。新專案已移除這兩個非 legacy 欄位,且 QuoteCategory::getTree() PHP caller 只在 index_tree()

本地測試:

docker exec -w /project-data cd63f9147e8d ./vendor/bin/phpunit tests/QuoteCategoriesIndexTreeTest.php
docker exec -w /project-data cd63f9147e8d ./vendor/bin/phpunit tests/QuoteCategoriesRelatedTest.php

結果:

tests/QuoteCategoriesIndexTreeTest.php: OK (3 tests, 25 assertions)
tests/QuoteCategoriesRelatedTest.php: OK (3 tests, 20 assertions)

完整對照見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_categories/index_tree.md

更新時間:2026-06-23

POST /users/forgot_password.json

功能說明

使用者在忘記密碼流程輸入 email 後,後端查 users.email,若 user 存在則寄出重設密碼 email。

這支 API 不會直接修改密碼;只有在 users.mobile_app_hash 空值時補 hash,已有 hash 時重用舊值。成功後寫入 User_Change_Password event queue,worker 會處理 email。

操作路徑

前端 forgot password form 送出:

POST /users/forgot_password.json

正式機 2026-06-24 access log:

3900 POST    /users/forgot_password.json 200
1226 OPTIONS /users/forgot_password.json 200

備註

已補 Users::forgot_password()、PHPUnit 與 staging/local diff。response 對齊 legacy:

{"error":0,"message":"Reset password email sent"}

legacy JSON path 會進 forgot_password_from_api(),不是頁面版 captcha / validation 流程;new 不加 is_active、session、blacklist、rate limit 等 legacy 沒有的 guard。

queue payload 維持 legacy shape,只含 user_idquote_service_idtasks;不可因 new task DO 多出 public property 就回寫 quote_request_idquote_bid_idshopList

request log 只保留 RouterV3 generic request log;不補 legacy forgot_password_from_api endpoint duplicate full request log。

完整對照見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/users/forgot_password.md

更新時間:2026-07-03

POST /users/sign_up.json

功能說明

Consumer 註冊 API。成功後建立 user、profile、login、session、RequestorSignup activity,非 ibon/qna 流程會寫入 Consumer_Signup event。

操作路徑

POST /users/sign_up.json

正式機 2026-06-24 access log:

894 POST    /users/sign_up.json 200
201 OPTIONS /users/sign_up.json 200

備註

已補 Users::sign_up() 與 PHPUnit。實作只依 legacy UsersController::sign_up() 實際路徑補欄位與 side effect,不沿用其他 auto signup helper。

高風險 legacy parity:

  • email / social existing user lookup 不加 is_active filter。
  • 保留 legacy country_code 雙 prepend 行為。
  • users explicit insert allowlist 不補 legacy 沒指定的 wallet、counter、security、app timestamp 欄位。
  • Consumer_Signup event payload 維持 legacy shape,只含 user_idquote_service_idtasks
  • phone conflict 時,舊 user 有 auto quote service category 才寫 Reset_Phone_Confirm email event。
  • Google token 驗證依賴 google.oauth_client_id* deployment config;但 2026-06-26 已確認 web-app Google 登入走 /users/login.json,不會自然 fallback 呼叫 /users/sign_up.json。台灣環境不補 area=tw
  • request log 只保留 RouterV3 generic request log;不補 legacy sign_up endpoint duplicate full request log。

測試結果:

tests/UsersSignUpTest.php: OK (11 tests, 129 assertions)

2026-06-26 已用 staging is_qna_user=1 curl 確認 response 與 DB side effect;完整對照見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/users/sign_up.md。仍需完整 staging diff 與真實 social token path 實測。

更新時間:2026-07-03

POST /users/login_once.json

功能說明

一次性登入 API。透過 security_hashes 建立 session,成功後會寫 api_sessionssecurity_hash_use_logsuser_logins

備註

2026-06-29 已補 legacy parity guard / fallback 與 PHPUnit:

  • active user guard:hash user 必須 is_active = 1
  • Session hash 14 天前或已 fulfilled 時回 consumed。
  • 已 fulfilled 的 ibonHyperlinkLogin / OrderLoginUrl 直接 consumed。
  • device id fallback:User.device_id -> flat device_id -> my-device-id
  • 只改 Users::login_once(),未改 shared SecurityHash model,避免影響其他 API。

測試結果:

tests/UsersLoginOnceTest.php: OK (5 tests, 50 assertions)
tests/UsersForgotPasswordTest.php: OK (3 tests, 39 assertions)
tests/UsersSignUpTest.php: OK (11 tests, 129 assertions)

2026-06-29 staging 實測:

  • 第一次呼叫 hash = 4f48b7e16e1e8c1420e93be77ffc3bab{"error":0,"session_id":"6h9rmece3ac0pgemn5h4r53sgm"}
  • 第二次同 hash 回 {"error":1,"message":"hash was consumed"}
  • DB 確認 security_hashes.is_fulfilled = 1api_sessions 建立、security_hash_use_logs 寫入、user_logins.channel = 2

完整對照見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/users/login_once.md

更新時間:2026-06-29

POST /users/login.json

操作路徑

https://staging.pro360.com.tw/login

App / web 登入流程會呼叫 POST /users/login.json;Google login 依 User[platform] 對應 google.oauth_client_id*id_token

功能說明

使用者登入 API。已補 legacy JSON path parity,包含 password / social / OTP login、session / cookie、login_logs / user_login_infos 與 legacy response shape。

2026-07-01 staging 驗證 platform=ios 時,new google.oauth_client_id_ios 與 legacy deployment config 不一致;已補 client id mismatch log context,會顯示 expected_config_keyexpected_client_idactual_aud。config 同步為 legacy cvvd... 值後,staging Google login 已正常。

2026-07-21 migration decision:一般 login 成功時,同 user_id + device_id 的舊 token 會先寫入 api_session_logsaction=login_rotate)再刪除,並於同一 transaction 建立新 token。其他 device、失敗登入與其他 ApiSession::upsert() caller 不受影響。本地 UsersLoginTest11 tests, 234 assertions;staging / production 的 api_session_logs schema 與部署後 token rotation 實測待確認。

備註

完整對照見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/users/login.md

更新時間:2026-07-21

POST /users/delete.json

操作路徑

Web 帳號設定刪除帳號會呼叫:

https://staging.pro360.com.tw/dashboard/settings/deactivate

前端確認後送 POST /users/delete.json,body 無必要欄位,需要 valid API key 與 valid user session。

功能說明

使用者刪除帳號 API。成功後會停用 user、釋出 email / phone、清 social 綁定與 session、歸檔 user 的 services / requests,並寫 activity、moengage_erase_usersumsub_deactivate_userDelete_User event。

這支不是單純關閉 users.is_active,也不是物理刪除所有資料;刪除後沒有直接復原 API,一般情境視為重新註冊。

備註

已補 legacy path routing、response shape、user row update、service/request archive、activity、session delete、task/event queue、Life55688 wrapper 與 PHPUnit。DeleteUser activity param1 對齊 legacy DB 實際值 (self);不更新 password、wallet、counter、user_profiles 等 legacy 沒碰的欄位。

request log 只保留 RouterV3 generic request log;不補 legacy RestApiHelper::getUserId() endpoint duplicate full request log。

完整對照與測試結果見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/users/delete.md

更新時間:2026-07-03

POST /users/change_password.json

操作路徑

Web 帳號設定頁點選「變更密碼」會呼叫:

https://staging.pro360.com.tw/dashboard/settings

進入設定頁後點選變更密碼,表單送出後送 POST /users/change_password.json,body 為 current_passwordnew_password,需要 valid API key 與 valid user session。

功能說明

使用者修改或建立密碼 API。legacy JSON path 會從 change_password() 直接轉進 change_password_from_api();成功主流程更新 users.password 並回 {"error":0,"message":"Success"}

這支不會刪 session、不會更新 profile、不會走 web/admin 的 logout 或 email 分支;session helper 仍保留 legacy 的 access 更新,以及超過 180 天回訪專家的 returnedQuoteService 條件式 task queue。

備註

已補 action、routing、legacy session resolver、blocked user、legacy response shape、password verify/update、RouterV3 password/passwd log filter 與 PHPUnit。2026-07-03 已完成新版 staging curl / DB / log 驗證:成功只更新 users.password,產生的 bcrypt $2y$12$ hash 可被 legacy / new 互驗,無新增 activity / queue / error log,request log 只保留 RouterV3 generic log 且 password 欄位已過濾。搬移時不可直接沿用 new UserUtil::change_password(),因為 shared helper 的 8 碼密碼規則與 response shape 不符合 legacy JSON path;legacy/web 前端目前允許 6 碼,且支援 DB password 空值時用空 current password 建立密碼。

完整對照見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/users/change_password.md

更新時間:2026-07-03

POST /users/connect_social/{type}.json

操作路徑

Web 帳號設定頁的「連結帳號」會呼叫:

https://staging.pro360.com.tw/dashboard/settings

支援:

POST /users/connect_social/google.json
POST /users/connect_social/facebook.json
POST /users/connect_social/apple.json

body 走 FormData。Google / Facebook normal login 送 access_token;Facebook limited login 可送 authentication_token;Apple web 送 platform=webcode

功能說明

使用者 social 帳號綁定 API。後端用目前 session user 綁定 Google / Facebook / Apple social id;若 social id 已屬於目前 user,回 success 不更新;若已屬於其他 user,回 error=2;若目前 user 已有不同的同類 social id,legacy 行為是回 success 但不覆蓋。

成功時只更新 users 的 social 欄位,不建立 user、不建立 session、不寫 login log、不寫 payment / wallet / queue。Google connect path 對齊 legacy 實際行為,google_access_token 寫空字串。

備註

已補 action、routing、legacy session resolver、Google / Facebook / Apple verify wrapper、social id conflict、empty-only update、legacy response shape 與 PHPUnit。

2026-07-08 已完成新版 staging Google / Apple 實測:Google success 會更新 users.google_user_id;Google / Apple 若 social id 已綁在其他 user,會回 error=2;Apple success 會寫 apple_verify_logs 並更新 users.apple_user_id。request log 只保留 RouterV3 generic log;文件不記錄完整 token payload。

完整對照見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/users/connect_social.md

更新時間:2026-07-08

GET /users/referrals.json

操作路徑

Web 免費接案金頁的推薦好友區塊會呼叫:

https://staging.pro360.com.tw/dashboard/free-credits/referral

前端 ProReferral mount 後送 GET /users/referrals.json,需要 valid API key 與 valid user session,body 為空。

功能說明

回傳目前 user 近一年內的推薦好友列表,前端用 referred_users.length 顯示累積推薦人數與進度條,並用每筆 UserProfile.first_nameUser.quote_status_idUser.awarded_credits 顯示好友名稱、推薦進度與獎勵金。

這支只讀 referral list,不寄信、不新增 referral、不寫 queue、不做付款;寄推薦信是另一支 POST /users/refer.json

備註

已補 action、routing、legacy session resolver、blocked user、1 年 filter、legacy nested response shape、inactive referred user parity、missing avatar fallback 與 PHPUnit。2026-07-08 legacy staging 空資料實測回 {"referred_users":[],"error":0,"message":"Success"}

完整對照見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/users/referrals.md

更新時間:2026-07-09

POST /users/refer.json

操作路徑

Web 免費接案金頁的推薦好友區塊點「發送Email」會呼叫:

https://staging.pro360.com.tw/dashboard/free-credits/referral

前端送 POST /users/refer.json,body 為 email,需要 valid API key 與 valid user session。

功能說明

寄出推薦好友 email。成功時寫 event_queueInvite_Referral event,template 為 204 Vendor Signup Invitation by Referral,email 內容包含 provider name、referral URL、email signature、provider photo 與 learn-more URL。

這支不新增 user_referrals、不發 referral bonus、不改 wallet / transaction,也不自動補 users.referral_hash;如果目前 user 沒有 referral_hash,legacy 行為仍回 success,但不寫 queue。

備註

已補 action、routing、legacy session resolver、blocked user、legacy response shape、email task payload、provider name fallback、missing email parity、no-referral-hash no-queue parity 與 PHPUnit。legacy 註解掉的 Email Existed 檢查沒有加回。

完整對照見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/users/refer.md

更新時間:2026-07-09

POST /users/verify/{type}/{action}.json

操作路徑

Web 簡訊驗證會先呼叫:

POST /users/verify/phone/preauth.json

body 為 phone、選填的 country_code,登入流程另送 is_login=1。收到 hash 後再呼叫:

POST /users/verify/phone/auth.json

body 為 hash、otp 與選填的 is_login=1。

前端 API 封裝在 web-app/modules/utils/api-manager.js:3287-3323。主要觸發位置是帳號簡訊驗證 PhoneVerificationView.js:107-146、問卷 QuestionnairePopupContainer.js:1167-1193 與 Booking phone login LoginContainer.js:141-159。語音驗證會另外呼叫 POST /users/verify/voice/preauth.json

部署設定

台灣 staging 使用 sms_platform_local=infobip,並需設定 InfoBipUrlInfoBipAPIKey。台灣環境的 ProConfig['area'] 必須維持未設定或 NULL,不可設成 tw

設定位置是 Lib/Common/Configuration.php。此檔被 .gitignore 忽略,本機修改不會進 commit,staging / production 必須另外同步。語音驗證另需確認 sms_platform_voiceInfoBipAPIUrlvoice.verify_message

2026-07-16 已確認 staging 簡訊送達、delivery callback 與 OTP auth 成功;production 設定尚待確認。

更新時間:2026-07-16

POST /quote_service_categories/add…

操作路徑

這支 API 是讓專家新增一個「我可以接這類工作」的服務項目。需 valid API key 與 valid user session,Cake named parameters 傳 quote_service_idquote_category_id;service 必須屬於登入使用者。

新增時會複製 service 的服務地區與郵遞區號,並依 category form fields 建立全部接案偏好與預設服務方式。相同 service/category 重複呼叫會回既有 id,不重複新增。

目前 checkout 的 Web「項目管理 → 新增項目」不呼叫 add,而是呼叫 POST /quote_service_categories/edit/.json。2026-07-22 已確認 iOS pro app legacy 呼叫 /add/quote_service_id:9930/quote_category_id:130.json,並找到同時間 QSC、mapping、QSC log 與完整 request log。2026-07-23 app 切到 new staging 後,以 9930 / 700 建立 QSC 10722;raw response、mapping、QSC log 及 duplicate 無額外寫入均符合預期。

同次 staging 驗證發現專用 Legacy log 因 Nginx rewrite 只記成 quote_service_categories/add.json::POST,Router generic log 則保有完整 named parameters。已改由 Router 提供原始 dispatch path 給專用 logger,保留 client 實際參數順序;本地測試同時覆蓋兩種順序、短 REQUEST_URI 與 invalid-session warning。Add 測試為 17 tests, 147 assertions,完整 QSC regression 為 27 tests, 234 assertions;待部署後複驗專用 channel。

部署設定

沒有新增 API 專用 config key;shared validateSave() 在 HK service area 101 分支會讀 sys_area。本地為 twConfiguration.php.gitignore 忽略;staging / production 實際值仍須在部署前確認。

完整對照見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_service_categories/add.md

更新時間:2026-07-23

GET /quote_feedbacks/sent[/sort:{sort}].json

操作路徑

Web 切到案主/消費者模式後,開啟:

https://staging.pro360.com.tw/dashboard/settings/reviews

進入「帳戶設定 → 評價紀錄」會先呼叫 sort:time;切換排序會呼叫 sort:score_highsort:score_low。專家模式不顯示此選單。

功能說明

回傳目前 session user 送出的案件評價 raw array,包含 service name/photo、feedback 全欄位、bid request id、comments 與 active feedback attachments。Domain query 不寫 feedback / bid / service,也不做付款或 notification;auth cache miss 仍保留 legacy access update 與可能的 returnedQuoteService queue。

備註

已補 action、routing、專用 model query、Redis session cache、legacy info/warning log 與 PHPUnit。保留 legacy 的 LEFT/INNER JOIN、空值與未知 sort fallback、JSON 字串型別、inactive session user 與 cache hit/miss side effects;不新增 abnormal、active、public 或 visibility filter。

2026-07-24 本地 Docker PHP 8.2 測試 10 tests, 76 assertions 全部通過;legacy staging baseline 四種 sort 與本地 output 的 canonical JSON 結構、值、array order 與型別一致。前端觸發截圖已放入 detail doc。new staging 部署後的 raw response、排序與 log 複驗尚待完成。

完整對照見 API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_feedbacks/sent.md

更新時間:2026-07-24

GET /quote_category_subgenres/index/genre_id:{id}.json

本次調整

目前Production以API key條件分流:指定key走PHP 8,其餘走Legacy。最終ALB只保留/quote_category_subgenres/index/genre_id*並全部送PHP 8,因此PHP 8程式內改為:

  • Deployment config精確matching key:維持現有PHP 8完整genre tree及is_skip_pro_search
  • 其他valid key:回Legacy-compatible指定genre subgenre array,不含is_skip_pro_search
  • 其他valid key的unknown genre:HTTP 200、text/html、body Not Found
  • Missing / invalid key:HTTP 401。
  • Config缺少或為空:error 999,禁止部署或切流。

必要config為quote_category_subgenres.existing_php8_api_key。本地/Staging使用Staging DB可通過guard的key;Production使用目前ALB條件值並確認Production DB active。目前本地/Staging matching key為3C3A284DD02A3A6E237E7C44A56A34B4;此值只放部署config,不可寫死在endpoint程式。

本地已通過專用測試13 tests, 85 assertions、相關regression6 tests, 45 assertions,並以實際本地config驗證matching與non-matching雙分支。Colon與slash route都由既有File rule解析,未修改Mapping;request log維持RouterV3既有行為,不新增endpoint專用filter。2026-07-29 reviewer接受unknown genre不搬Legacy全域exception Slack webhook,只保留HTTP 200 Not Found前端行為。

2026-07-29 Staging已新增config並將path導向PHP 8。Matching key、genre_id:1回完整genre object且有is_skip_pro_search;non-matching valid key命中X-PHP-Env: php82-staging-1,HTTP 200回20筆Legacy-compatible subgenre array,欄位與JSON string型別符合預期,且沒有完整genre tree與is_skip_pro_search

Staging curl

curl只取得完整HTTP headers與raw body,結果另外人工比對,不在指令中加入jq或通過條件。

Matching key、有效genre:

curl -i \
  -H 'X-PRO360-Rest-Api-Key: 3C3A284DD02A3A6E237E7C44A56A34B4' \
  'https://api-staging.pro360.com.tw/quote_category_subgenres/index/genre_id:1.json'

Non-matching valid key、有效genre:

curl -i \
  -H 'X-PRO360-Rest-Api-Key: 34F4249749CDF7F8E295F535BC37C3B5' \
  'https://api-staging.pro360.com.tw/quote_category_subgenres/index/genre_id:1.json'

Non-matching valid key、unknown genre:

curl -i \
  -H 'X-PRO360-Rest-Api-Key: 34F4249749CDF7F8E295F535BC37C3B5' \
  'https://api-staging.pro360.com.tw/quote_category_subgenres/index/genre_id:999999.json'

Missing key:

curl -i \
  'https://api-staging.pro360.com.tw/quote_category_subgenres/index/genre_id:1.json'

完整API contract見API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_category_subgenres/index_by_genre.md;config與ALB切流見同目錄deployment_config_and_cutover.md

更新時間:2026-07-29

GET /quote_feedback_tags/index.json

功能與前端入口

回傳啟用中的評價標籤,依分數與顯示順序分組。Web 會在消費者商品訂單的「評價/編輯評價」視窗開啟時呼叫;request 帶有效 API key,不需要 user session。

PHP 8 已維持 Legacy 的 query、排序、翻譯、response shape 與型別:

  • 成功回 HTTP 200、error=0data 以字串分數 key 分組。
  • is_satisfied:{score} 只接受 CakePHP colon named parameter;missing、0 或 invalid value 回全部 active tags。
  • Endpoint 本身不寫 DB,不產生 payment、queue、activity 或 notification。
  • 沒有 endpoint 專用 config;切流前仍需核對部署環境的 use_multi_translationuse_multi_langsdefault_lang 與 PHP session 設定。

驗證狀態

  • 本地 PHP 8:12 tests / 68 assertions 通過。
  • 2026-07-30 Staging raw response 已與 active tag、is_satisfied ASC, display_order ASC 對照一致。
  • Staging 前端 Network 已確認實際 caller 與 HTTP 200,截圖已保存。
  • 該次證據未顯示 x-php-env,因此處理 instance 仍待用 response header 確認;Production 尚未切流。
  • Production 最近 30 天為 26,911 calls,盤點時全部走 Legacy。

完整 contract:API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_feedback_tags/index.md

Staging smoke test:各種API測試/quote_feedback_tags/index.md

更新時間:2026-07-30

quote_feedback_comments/save / delete

POST     /quote_feedback_comments/save/{feedback_id}.json
GET/POST /quote_feedback_comments/delete/id:{comment_id}.json

功能與前端入口

save 新增或更新案件評價回覆;session user 必須是 feedback 雙方之一,更新時還必須是 comment owner。delete 只允許 comment owner hard delete,並維持 Legacy 同時接受 GET 與 POST。

現行 Web 的主要入口是專家登入後進入 /dashboard/works/{bid_id},在消費者案件評價卡片點「回覆評價/修改回覆」並送出。另可從 /dashboard/services/{service_id}/reviews 的「案件評價」進入,但已有 comment 時不顯示回覆按鈕。

注意:

  • 消費者新增評價不呼叫這支 API;商品評價回覆走另一支 Nshop API。
  • Web caller 只送 feedback_id + comment,不送 comment id,所以 UI 只驗證 create;update branch 需用 curl 或其他 client。
  • 現行 web-app 找不到 delete caller;Production 仍有 GET/POST 流量,因此保留兩種 method,Staging 以 curl 驗證。

Route 與 Legacy parity

PHP 8 使用明確且 anchored mapping,並排在 generic File route 前:

^quote_feedback_comments/save/([0-9]+)\.json$
^quote_feedback_comments/delete/id:([0-9]+)\.json$
  • save 成功:{"error":0,"status":"Success"}
  • delete 成功:{"error":0,"message":"success"}
  • save 只寫 quote_feedback_comments;保留原始 comment,不自行 trim、escape 或增加 feedback 狀態 guard。
  • delete 直接 hard delete owner 的 comment,不額外 join feedback。
  • 兩支只接受 .json。2026-07-31 reviewer 已接受不搬 Legacy 的無副檔名 Accept negotiation;錯誤 action 與 route negative test 已補。
  • 沒有 endpoint 專用 config;部署需確認 PHP 8 與 Legacy 共用正確 DB、Redis、API key 與 API session 資料。

驗證狀態

  • 本地 PHP 8 syntax 通過。
  • Core:3 tests / 36 assertions;Other:16 tests / 97 assertions;專用測試合計 19 / 133
  • Regression:quote_feedbacks/sent10 / 76quote_feedback_tags/index12 / 68,全部通過。
  • Production 最近 30 天:save 751 calls、delete 10 calls,盤點時全部走 Legacy。
  • Legacy retained log 的實際 save/delete path 全為 .json;目前是單台 Legacy host 證據,其他 instances/ALB logs 尚待確認。
  • 2026-07-31 Legacy Staging 已完成 save/2286.json create baseline:response 為 success;DB 新增 comment 730,feedback、actor、is_customer、原始 comment 與 timestamp 均符合 Legacy 預期。
  • PHP 8 Staging 的 save create/update、delete、DB side effect 與 x-php-env 尚待 smoke test;完成前不調整 Production ALB。

完整 contract:

  • API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_feedback_comments/save.md
  • API 路由與遷移/API Migration/pro360_api_82/api_migration/details/quote_feedback_comments/delete.md

Staging smoke test:各種API測試/quote_feedback_comments/

更新時間:2026-07-31

POST /quote_requests/search_add.json

同步現況

PHP 8 已承接主要建單、表單、計價、配對、bid、queue 與 response 流程。Current Legacy 以 get-lancer-docker-2/get-lancerNewStaging / e8341ac62 為準;2026-08-10 複核後沒有 2026-08-05 之後的新 search_add commit。

本輪 LINE actor / 帳號綁定已由 PHP 8 commit fb8897d7 完成:讀取 User[line_id_token],從 line_verify_logs 找 LINE 身分,使用或綁定既有 PRO360 user,auto signup 時寫入 line_users。LINE 不增加 response 欄位;user_id 與 DB id / flag 維持 JSON string,error 維持 integer。

相關 PHP 8.2 測試:SearchAddInputTest 9/24、CredentialActorResolverTest 12/62、LINE repository integration 2/20,合計 23 tests, 106 assertions 全部通過。

目前仍有三項 Legacy parity gap:

  1. device-only:PHP 8 仍可成立 actor;Legacy 會回 error=2
  2. existing session:PHP 8 shared upsert 會更換 token;Legacy search_add 沿用原 token。
  3. inner_text:Legacy 另寫 quote_request_inners 並排除一般表單、計價與配對;PHP 8 尚未實作。

部署狀態

fb8897d7 已推到 origin/NewStagingForPHP82_search_add,尚未進入 NewStagingForPHP82 / staging,因此目前不可標成完整 parity,也不可進行全流量切換。

search_add 本身沒有新增 deployment config。LINE end-to-end OAuth 仍依賴 LINE_LOGIN_CLIENT_IDLINE_LOGIN_SECRETapi.urlsite.url 與 callback allowlist;staging / production 實際設定尚待確認。

完整狀態見 API 路由與遷移/API Migration/pro360_api_82/search_add/newstaging_delta_audit_2026-08-05.md

更新時間:2026-08-10