diff --git a/apps/web/src/app/traffic/page.tsx b/apps/web/src/app/traffic/page.tsx index 1ebc22f..914fd3e 100644 --- a/apps/web/src/app/traffic/page.tsx +++ b/apps/web/src/app/traffic/page.tsx @@ -8,21 +8,21 @@ export const dynamic = "force-dynamic"; const MONITOR_TOKEN = process.env.TRAFFIC_MONITOR_TOKEN; const EVENT_LABELS: Record = { - EXTERNAL_LIST_OPEN_TASKS: "外部公開流量頁讀取 open tasks", - EXTERNAL_A2A_ONBOARDING_VIEW: "外部 Agent 讀取 onboarding contract", - PUBLIC_A2A_ONBOARDING_VIEW: "公開 A2A onboarding 被讀取", - EXTERNAL_A2A_DEMAND_CAMPAIGN_KIT_ISSUED: "外部 Agent 領取需求 campaign kit", - EXTERNAL_A2A_INTEGRATION_CATALOG_VIEW: "外部 Agent 讀取 A2A 整合目錄", - EXTERNAL_A2A_GROWTH_KIT_ISSUED: "外部 Agent 領取 growth kit", - EXTERNAL_A2A_REFERRAL_TOUCHPOINT_RECORDED: "外部 Agent 回報導流 touchpoint", - EXTERNAL_A2A_REFERRAL_STATUS_VIEW: "外部 Agent 查詢 referral 狀態", + EXTERNAL_LIST_OPEN_TASKS: "外部查看可接需求", + EXTERNAL_A2A_ONBOARDING_VIEW: "外部讀取合作說明", + PUBLIC_A2A_ONBOARDING_VIEW: "公開合作說明被讀取", + EXTERNAL_A2A_DEMAND_CAMPAIGN_KIT_ISSUED: "外部領取需求導流素材", + EXTERNAL_A2A_INTEGRATION_CATALOG_VIEW: "外部查看整合目錄", + EXTERNAL_A2A_GROWTH_KIT_ISSUED: "外部領取成長導流素材", + EXTERNAL_A2A_REFERRAL_TOUCHPOINT_RECORDED: "外部引薦紀錄", + EXTERNAL_A2A_REFERRAL_STATUS_VIEW: "外部查詢引薦狀態", EXTERNAL_DEMAND_PROPOSAL_VIEW: "外部導流需求方查看提案頁", EXTERNAL_DEMAND_PROPOSAL_INTAKE_CREATED: "外部導流需求方建立提案", - EXTERNAL_DEMAND_PROPOSAL_CHECKOUT_STARTED: "外部導流需求方開始 Stripe 結帳", + EXTERNAL_DEMAND_PROPOSAL_CHECKOUT_STARTED: "外部導流需求方開始線上結帳", EXTERNAL_DEMAND_PROPOSAL_WALLET_PAYMENT_PENDING: "外部導流需求方取得錢包付款指示", EXTERNAL_DEMAND_PROPOSAL_FEE_CAPTURED: "外部導流提案費付款成功", EXTERNAL_LIST_OPEN_TASKS_SURGE: "外部公開流量突增告警", - EXTERNAL_LIST_OPEN_TASKS_MCP: "外部 MCP 入口讀取 open tasks", + EXTERNAL_LIST_OPEN_TASKS_MCP: "外部整合入口查看可接需求", EXTERNAL_LIST_OPEN_TASKS_MCP_SURGE: "外部 MCP 流量突增告警", EXTERNAL_CLAIM_TASK_SUCCESS: "外部 AI 成功接單", EXTERNAL_SUBMIT_SOLUTION_SUCCESS: "外部 AI 提交解法", @@ -32,7 +32,7 @@ const EVENT_LABELS: Record = { EXTERNAL_LIST_OPEN_TASKS_MCP_ERROR: "外部 MCP 流量端點錯誤", EXTERNAL_FUNNEL_CLAIM_STALL: "外部曝光後未接案", EXTERNAL_FUNNEL_SUBMIT_STALL: "外部接案後未提交", - EXTERNAL_FUNNEL_PASS_STALL: "外部提交後未 PASS", + EXTERNAL_FUNNEL_PASS_STALL: "外部提交後未通過", EXTERNAL_FUNNEL_PAYOUT_STALL: "PASS 後未出金", JUDGE_COMPLETE: "AI 交件判定完成", }; @@ -95,11 +95,6 @@ function isAuthorizedToken(token: string | undefined, tokenHeader: string | unde return tokenHeader === token; } -function eventDirection(action: string) { - if (action.startsWith("EXTERNAL_")) return "外部"; - return "內部"; -} - function explainAction(action: string) { return EVENT_LABELS[action] || action; } @@ -617,15 +612,15 @@ function buildConversionTips(summary: { const steps: string[] = []; if (conversionSummary.discovery_events > 0 && conversionSummary.referral_touchpoint_events === 0) { - steps.push("A2A 曝光已有資料但外部 Agent touchpoint 為零:優先確認 campaign kit 是否要求回報 /api/a2a/referrals/touch。"); + steps.push("已有曝光但沒有引薦紀錄:請確認對外素材是否已更新,並檢查引薦連結是否正常帶入。"); } if (conversionSummary.referral_touchpoint_events > 0 && conversionSummary.proposal_view_events === 0) { - steps.push("外部 Agent 已回報導流 touchpoint 但提案頁查看為零:優先檢查送出的 proposal_url、prefilled_proposal_url 與 vibework.wooo.work 代理。"); + steps.push("已有引薦紀錄但未進入提案頁:請檢查對外連結是否指向正式提案入口。"); } if (conversionSummary.discovery_events > 0 && conversionSummary.proposal_view_events === 0) { - steps.push("A2A 曝光已有資料但提案頁查看為零:優先確認 growth kit referral_url、touchpoint 回傳 URL、外部貼文 CTA 與 /propose 代理。"); + steps.push("已有曝光但沒有提案頁查看:請檢查對外 CTA、提案入口與正式網域代理狀態。"); } if (conversionSummary.proposal_view_events > 0 && conversionSummary.proposal_created_events === 0) { @@ -633,11 +628,11 @@ function buildConversionTips(summary: { } if (conversionSummary.proposal_created_events > 0 && conversionSummary.proposal_paid_events === 0) { - steps.push("已有提案但尚未付款成功:分流檢查 Stripe checkout 與 USDC wallet receipt verification。"); + steps.push("已有提案但尚未付款成功:請分別檢查線上結帳與錢包收款確認流程。"); } if (conversionSummary.discovery_events > 0 && conversionSummary.claim_events === 0) { - steps.push("曝光高但接單為零:請先檢查 open-tasks 回傳任務文案是否足夠明確,是否包含 npx 指令與標準格式。"); + steps.push("曝光高但接單為零:請先檢查任務標題、酬金、驗收條件與交付格式是否足夠明確。"); } if (conversionSummary.claim_events > 0 && conversionSummary.submit_events === 0) { @@ -645,7 +640,7 @@ function buildConversionTips(summary: { } if (conversionSummary.submit_events > 0 && conversionSummary.judge_pass_events === 0) { - steps.push("有提交但無 PASS:先人工檢查提交格式、sandbox 測試、deliverable 欄位是否可被執行。"); + steps.push("有提交但未通過:先檢查交付格式、測試結果與驗收條件是否可被系統判讀。"); } if (conversionSummary.judge_pass_events > 0 && conversionSummary.payout_captured === 0) { @@ -657,7 +652,7 @@ function buildConversionTips(summary: { } if (summary.pass_rate < 35 && conversionSummary.submit_events > 20) { - steps.push("PASS 率偏低:提高指令兼容度,改用可判讀的輸出欄位與固定檔名。"); + steps.push("通過率偏低:提高指令兼容度,改用可判讀的輸出欄位與固定檔名。"); } if (steps.length === 0) { @@ -683,8 +678,13 @@ export default async function TrafficDashboard({

VibeWork 流量監控

-

請輸入正確的監控 Token 才能查看此頁。

-

範例:/traffic?token=YOUR_TOKEN&minutes=60

+

此頁需要管理權限。請先登入管理入口後查看。

+ + 前往管理登入 +
); @@ -701,14 +701,14 @@ export default async function TrafficDashboard({
-

VibeWork 流量監控(轉化導向)

+

VibeWork 流量監控

← 回首頁
- 觀測區間:最近 {summary.periodMinutes} 分鐘(外部事件=`EXTERNAL_*`) + 觀測區間:最近 {summary.periodMinutes} 分鐘
@@ -725,7 +725,7 @@ export default async function TrafficDashboard({
{conversionSummary.discovery_events}
-
Agent 導流回報
+
引薦紀錄
{conversionSummary.referral_touchpoint_events}
@@ -764,17 +764,17 @@ export default async function TrafficDashboard({
平均需求清晰度{demandSupply.avgScopeClarity === null ? "n/a" : `${Number(demandSupply.avgScopeClarity).toFixed(2)}`}
- 來源條件:Task.status = OPEN 且 title 不以 GitHub Issue: 開頭。 + 統計已排除工程同步任務,保留可直接對外承接的需求。
-

外部未接案自動化排查

+

需求供給檢查

    -
  • 1) 先確認需求池:若 {demandSupply.openTaskCount} 筆,請先確認任務文案是否有可執行 step。
  • -
  • 2) 重試建議:再打 /api/open-tasks 3 次(每次間隔 30~60 秒)確認回傳一致。
  • -
  • 3) 直接驗證任務描述摘要,避免只用含「GitHub Issue:」字頭(現已過濾)。
  • -
  • 4) 若仍未有接單:將任務 reward、required_stack 與 developer_wallet 指引補齊為固定欄位範例。
  • +
  • 先確認需求池仍有 {demandSupply.openTaskCount} 筆可承接需求。
  • +
  • 若曝光高但接單低,優先補強任務標題、酬金、交付格式與驗收條件。
  • +
  • 若需求清晰度偏低,先拆成較小的可交付項目,再重新對外發布。
  • +
  • 若外部流量已進來,請同步檢查提案入口與付款路徑是否保持可用。
@@ -784,7 +784,7 @@ export default async function TrafficDashboard({

外部流量轉化漏斗

- A2A曝光→Agent導流回報 + A2A曝光→引薦 {fmtPercent(conversionRates.touchpoint_rate)}
@@ -794,7 +794,7 @@ export default async function TrafficDashboard({ />
- Agent導流回報→提案頁 + 引薦→提案頁 {fmtPercent(conversionRates.touchpoint_to_proposal_view_rate)}
@@ -854,7 +854,7 @@ export default async function TrafficDashboard({ />
- 提交→PASS + 提交→通過 {fmtPercent(conversionRates.pass_rate)}
@@ -864,7 +864,7 @@ export default async function TrafficDashboard({ />
- PASS→收款成功 + 通過→收款成功 {fmtPercent(conversionRates.payout_rate)}
@@ -875,31 +875,31 @@ export default async function TrafficDashboard({
-
Stripe checkout 開始{conversionSummary.proposal_checkout_events}
+
線上結帳開始{conversionSummary.proposal_checkout_events}
錢包付款待確認{conversionSummary.proposal_wallet_pending_events}
-
PASS 任務{conversionSummary.judge_pass_events}
-
FAIL 任務{conversionSummary.judge_fail_events}
+
通過任務{conversionSummary.judge_pass_events}
+
未通過任務{conversionSummary.judge_fail_events}
已出金{conversionSummary.payout_captured}
已退費{conversionSummary.payout_released}
-

轉化流程與使用者後續處理(你現在該做什麼)

+

轉化流程

    -
  1. 曝光端流量先判斷:從 open-tasks / MCP 的呼叫量,看是否有可感知的外部探索流。
  2. -
  3. 接案事件代表 AI 真的把任務當作可接單:EXTERNAL_CLAIM_TASK_SUCCESS。
  4. -
  5. 提交事件代表 AI 真的開始交件:EXTERNAL_SUBMIT_SOLUTION_SUCCESS。
  6. -
  7. 系統 PASS 才有收款機會:JUDGE_COMPLETE + overall_result=PASS,接著做 CAPTURE。
  8. -
  9. 你要追的是「曝光→接案→提交→PASS→收款」連續率,而不是單一事件數量。
  10. +
  11. 先看外部探索流量,確認合作入口是否真的被外部系統讀取。
  12. +
  13. 接案代表外部 AI 已把任務判斷為可承接。
  14. +
  15. 提交代表外部 AI 已開始交付結果。
  16. +
  17. 交付通過後才進入收款與出金流程。
  18. +
  19. 核心指標是「曝光→接案→提交→通過→收款」連續率,而不是單一事件數量。
{hasClaimStall && demandSupply.openTaskCount > 0 ? (
- 本輪有 EXTERNAL_FUNNEL_CLAIM_STALL 告警。可直接採取: + 本輪偵測到曝光後未接案。可直接採取:
    -
  • 先取一筆最新 OPEN 任務,核對 `scope_clarity_score` 與 reward 欄位。
  • -
  • 發送 1 次固定模板 `claim_task` 試探,若失敗 403 則先修正 API Key/權限。
  • -
  • 若返回 200 仍無接案,調整任務文案再行發佈,讓外部判斷標準更明確。
  • +
  • 先抽查最新可接需求,核對酬金、交付範圍與驗收條件。
  • +
  • 確認外部入口仍能讀到需求列表,且需求描述不是只有同步標題。
  • +
  • 若入口可用但仍無接案,請先縮小任務範圍再重新發布。
) : null} @@ -957,19 +957,19 @@ export default async function TrafficDashboard({
-

外部 Actor 行為追蹤(可追溯)

+

外部來源行為追蹤

- + - - + + @@ -977,7 +977,7 @@ export default async function TrafficDashboard({ {summary.externalActorActivities.length === 0 ? ( ) : ( @@ -987,8 +987,7 @@ export default async function TrafficDashboard({ @@ -997,7 +996,6 @@ export default async function TrafficDashboard({ )) @@ -1008,7 +1006,7 @@ export default async function TrafficDashboard({
-

外部事件說明(可讀)

+

外部事件摘要

{Object.entries(summary.actionSummary) .filter(([action]) => action.startsWith("EXTERNAL_")) @@ -1016,22 +1014,11 @@ export default async function TrafficDashboard({ .slice(0, 14) .map(([action, count]) => (
- {explainAction(action)} ({action}) + {explainAction(action)} {count}
))}
-
-

事件方向:

- {Object.entries(summary.actionSummary) - .filter(([action]) => action.startsWith("EXTERNAL_")) - .map(([action, count]) => ( -
- {eventDirection(action)}{action} - {count} -
- ))} -
@@ -1043,13 +1030,13 @@ export default async function TrafficDashboard({ {summary.externalErrors.length > 0 ? (
- 注意:目前已偵測到 {summary.externalErrors.length} 種外部錯誤事件({summary.externalErrors.join(", ")}),請優先回查 API payload 與 auth policy。 + 注意:目前已偵測到 {summary.externalErrors.length} 種外部錯誤事件({summary.externalErrors.map(explainAction).join("、")}),請優先回查對外入口與權限設定。
) : null}
-

最近外部事件(top 120)

+

最近外部事件

{summary.recentExternalEvents.length === 0 ? (

目前區間內尚無外部事件。

@@ -1058,19 +1045,13 @@ export default async function TrafficDashboard({ const ts = toLocalTime(event.createdAt); return (
-
{event.action}
+
{explainAction(event.action)}
- actor={event.actorType}:{event.actorId || "unknown"} | 類別={actorClassLabel((event as { actor_class?: TrafficActorClass }).actor_class || "other_external")} | entity={event.entityType}/{event.entityId} | surface={String(event.surface || "-")} | {ts} + 來源:{event.actorId || "unknown"}|類別:{actorClassLabel((event as { actor_class?: TrafficActorClass }).actor_class || "other_external")}|任務:{event.entityId || "-"}|時間:{ts}
- response={event.response_status ?? "n/a"} / summary={event.response_summary} + 回應:{event.response_status ?? "n/a"} / {event.response_summary}
- {event.reason ?
{event.reason}
: null} - {event.metadata ? ( -
-                        {JSON.stringify(event.metadata, null, 2)}
-                      
- ) : null}
); }) diff --git a/apps/web/src/middleware.ts b/apps/web/src/middleware.ts index 4ad32c2..fb16093 100644 --- a/apps/web/src/middleware.ts +++ b/apps/web/src/middleware.ts @@ -10,8 +10,15 @@ import { export function middleware(request: NextRequest) { const url = request.nextUrl; const isAdminPath = url.pathname.startsWith("/admin"); + const isTrafficDashboard = url.pathname === "/traffic"; const strippedHeaders = stripClientAdminHeaders(request); + if (isTrafficDashboard && !url.searchParams.get("token")) { + const adminTrafficUrl = url.clone(); + adminTrafficUrl.pathname = "/admin/traffic"; + return NextResponse.redirect(adminTrafficUrl); + } + if (isAdminPath) { if (!isAdminRequestAuthorized(request)) { return adminUnauthorizedResponse();
來源類型Actor來源 事件 最新行為 任務 來源 IPUser-AgentRequest-Id來源識別追蹤 ID 最新回應
- 尚無可追蹤的外部 AGENT 行為,可能目前仍未有 AGENT 類型入口流量。 + 尚無可追蹤的外部 AI 行為,可能目前仍未有外部入口流量。
{actor.actorId} {actor.events} -
{actor.latestAction}
-
{actor.latestSurface}
+
{explainAction(actor.latestAction)}
{actor.latestTaskId} {actor.latestSourceIp}
{actor.latestResponseStatus ?? "n/a"}
{actor.latestResponseSummary}
-
{actor.latestPayloadSummary}