diff --git a/.env.example b/.env.example index 3a37b15..48a7ecc 100644 --- a/.env.example +++ b/.env.example @@ -52,16 +52,18 @@ NGROK_AUTH_TOKEN=your_ngrok_auth_token # ========================================== # [預設 true] 啟用 momo-pro 全站 shell 載入自架 Webcrumbs runtime WEBCRUMBS_ENABLED=true -# [預設] 110 Gateway / Nginx 上的共用 Webcrumbs 入口 +# [預設] 共用 Webcrumbs/Open Design 工具入口;正式頁面載入不直接依賴此跨域 TLS WEBCRUMBS_BASE_URL=https://webcrumbs.wooo.work -# [預設 @v0.1.5] 生產環境必須固定版本,不使用官方 @latest -WEBCRUMBS_RUNTIME_VERSION=@v0.1.5 -# [預設 /runtime/@v0.1.5] 若部署成 CDN 相容根路徑,可改為 /@v0.1.5 -WEBCRUMBS_RUNTIME_PATH=/runtime/@v0.1.5 -# [選填] 若實際 runtime URL 與 BASE_URL + RUNTIME_PATH 不同,用此欄位直接覆寫 +# [預設 shared-ui-poc-0.1.0] 生產環境必須固定版本,不使用官方 @latest +WEBCRUMBS_RUNTIME_VERSION=shared-ui-poc-0.1.0 +# [預設] momo-pro 同源 asset proxy,避免跨域憑證/Basic Auth 影響正式頁面 +WEBCRUMBS_RUNTIME_PATH=/webcrumbs-assets/loader/webcrumbs-compatible-loader.js +# [選填] 若實際 runtime URL 與 RUNTIME_PATH 不同,用此欄位直接覆寫 WEBCRUMBS_RUNTIME_URL= -# [預設] momo-pro 專用 plugin namespace;各 plugin 應使用版本化子目錄 -WEBCRUMBS_PLUGIN_BASE_URL=https://webcrumbs.wooo.work/plugins/momo-pro +# [預設] 共用 plugin base;各 plugin 應使用版本化子目錄 +WEBCRUMBS_PLUGIN_BASE_URL=/webcrumbs-assets/plugins +# [預設] 188 user-space Shared UI Hub,只允許 proxy loader/plugins/demo +WEBCRUMBS_ASSET_UPSTREAM_URL=http://192.168.0.188:18088 # ========================================== # Image / Release Tag(docker-compose*.yml) diff --git a/TODO_NEXT_STEPS.txt b/TODO_NEXT_STEPS.txt index 88067db..df98e37 100644 --- a/TODO_NEXT_STEPS.txt +++ b/TODO_NEXT_STEPS.txt @@ -4,6 +4,8 @@ ================================================================================ 【已完成】 + - V10.509 新增市場情報 MCP Fetch Candidate Queue Writer Review Decision Approval Writer Preflight 安全預覽 gate:只審核 human approval 通過後由操作員貼回的 writer preflight 摘要,確認 approval identity、writer_preflight_id、row count、dedupe keys、approved decision 到 target review_state 的逐列映射、decision/approval/preflight evidence refs、exact identity / variant / overwrite guard 與 operator boundary;API 不讀 token、不執行 CLI、不開 DB、不寫 preflight/approval/decision/match、不更新 review_state、不補 queue、不掛 scheduler,只放行到後續 CLI review / run package 設計。 + - V10.508 Webcrumbs 轉為 momo-pro 同源 asset proxy:`WEBCRUMBS_RUNTIME_URL` 預設改為 `/webcrumbs-assets/loader/webcrumbs-compatible-loader.js`,新增 allowlist proxy 只代理 188 Shared UI Hub 的 `loader/`、`plugins/`、`demo/`,避免 `webcrumbs.wooo.work` 公網 TLS / Basic Auth 尚未收斂時影響正式頁面載入;`/webcrumbs` 診斷頁同步顯示 asset upstream。 - V10.507 接入 Webcrumbs 共用 UI Runtime:新增 `WEBCRUMBS_*` 環境設定與 `/webcrumbs` 診斷入口,`ewoooc_base.html` 會在 runtime 啟用且 URL 有效時載入自架 Webcrumbs script;側欄新增 Webcrumbs 入口,並補 `docs/guides/webcrumbs_shared_runtime.md` 作為跨專案接入手冊。生產仍需固定版本與自架 plugin URI,不使用官方 `@latest`。 - V10.506 新增市場情報 MCP Fetch Candidate Queue Writer Review Decision Approval 安全預覽 gate:只審核 review decision 通過後由操作員貼回的人工 approval 摘要,確認 approval identity、row count、dedupe keys、approved decision、evidence refs、exact identity / variant / overwrite guard 與 operator boundary;API 不讀 token、不執行 CLI、不開 DB、不寫 approval/decision/match、不更新 review_state、不補 queue、不掛 scheduler,只放行到後續人工 approval writer preflight 設計。 - V10.505 新增市場情報 MCP Fetch Candidate Queue Writer Review Decision 安全預覽 gate:只審核 review inventory 通過後由操作員貼回的人工 candidate queue review decision 摘要,確認 decision identity、target table、row count、dedupe keys、`needs_review` 現態、允許決策集合、evidence refs、matched row exact-identity/variant/overwrite guard、operator confirmation 與 forbidden API actions;API 不讀 token、不執行 CLI、不開 DB、不寫 decision record、不更新 review_state、不寫 match result、不補 queue、不掛 scheduler。UI 同步新增 Decision gates / Inventory link / Decision summary / Decision rows / Boundary next 預覽區。 diff --git a/app.py b/app.py index 09eae9c..61fafd9 100644 --- a/app.py +++ b/app.py @@ -62,6 +62,7 @@ from config import ( SYSTEM_VERSION, WEBCRUMBS_BASE_URL, WEBCRUMBS_ENABLED, + WEBCRUMBS_ASSET_UPSTREAM_URL, WEBCRUMBS_PLUGIN_BASE_URL, WEBCRUMBS_RUNTIME_URL, WEBCRUMBS_RUNTIME_VERSION, @@ -448,6 +449,7 @@ def inject_global_vars(): 'runtime_url': WEBCRUMBS_RUNTIME_URL, 'runtime_version': WEBCRUMBS_RUNTIME_VERSION, 'plugin_base_url': WEBCRUMBS_PLUGIN_BASE_URL, + 'asset_upstream_url': WEBCRUMBS_ASSET_UPSTREAM_URL, }, } diff --git a/config.py b/config.py index 1feca64..1f0bc2e 100644 --- a/config.py +++ b/config.py @@ -118,7 +118,7 @@ def _env_bool(name: str, default: str = 'false') -> bool: def _safe_public_http_url(value: str) -> str: - """只接受公開 http(s) URL,避免模板把 javascript/data URI 輸出成 script src。""" + """只接受 http(s) URL,避免模板把 javascript/data URI 輸出成 script src。""" candidate = (value or '').strip().rstrip('/') if not candidate: return '' @@ -128,29 +128,40 @@ def _safe_public_http_url(value: str) -> str: return candidate +def _safe_webcrumbs_reference(value: str) -> str: + """允許 http(s) URL 或 momo-pro 同源絕對路徑,供 script/plugin URL 使用。""" + candidate = (value or '').strip().rstrip('/') + if not candidate: + return '' + if candidate.startswith('/') and not candidate.startswith('//') and '\\' not in candidate: + return candidate + return _safe_public_http_url(candidate) + + # Webcrumbs 共用 microfrontend runtime。 -# 預設接 110 Gateway 上的內部部署;實際路徑不同時可用 WEBCRUMBS_RUNTIME_URL 直接覆寫。 +# 預設透過 momo-pro 同源 proxy 讀 188 Shared UI Hub,避免正式頁面被跨域 TLS 狀態卡住。 WEBCRUMBS_ENABLED = _env_bool('WEBCRUMBS_ENABLED', 'true') WEBCRUMBS_BASE_URL = _safe_public_http_url( os.getenv('WEBCRUMBS_BASE_URL', 'https://webcrumbs.wooo.work') ) -WEBCRUMBS_RUNTIME_VERSION = os.getenv('WEBCRUMBS_RUNTIME_VERSION', '@v0.1.5').strip().strip('/') +WEBCRUMBS_RUNTIME_VERSION = os.getenv('WEBCRUMBS_RUNTIME_VERSION', 'shared-ui-poc-0.1.0').strip().strip('/') WEBCRUMBS_RUNTIME_PATH = os.getenv( 'WEBCRUMBS_RUNTIME_PATH', - f'/runtime/{WEBCRUMBS_RUNTIME_VERSION}' if WEBCRUMBS_RUNTIME_VERSION else '/runtime/@v0.1.5', + '/webcrumbs-assets/loader/webcrumbs-compatible-loader.js', ).strip() _webcrumbs_runtime_url = os.getenv('WEBCRUMBS_RUNTIME_URL', '').strip() -WEBCRUMBS_RUNTIME_URL = _safe_public_http_url(_webcrumbs_runtime_url) -if not WEBCRUMBS_RUNTIME_URL and WEBCRUMBS_BASE_URL: - WEBCRUMBS_RUNTIME_URL = _safe_public_http_url( - f"{WEBCRUMBS_BASE_URL}/{WEBCRUMBS_RUNTIME_PATH.lstrip('/')}" - ) -WEBCRUMBS_PLUGIN_BASE_URL = _safe_public_http_url( +WEBCRUMBS_RUNTIME_URL = _safe_webcrumbs_reference(_webcrumbs_runtime_url) +if not WEBCRUMBS_RUNTIME_URL: + WEBCRUMBS_RUNTIME_URL = _safe_webcrumbs_reference(WEBCRUMBS_RUNTIME_PATH) +WEBCRUMBS_PLUGIN_BASE_URL = _safe_webcrumbs_reference( os.getenv( 'WEBCRUMBS_PLUGIN_BASE_URL', - f'{WEBCRUMBS_BASE_URL}/plugins/momo-pro' if WEBCRUMBS_BASE_URL else '', + '/webcrumbs-assets/plugins', ) ) +WEBCRUMBS_ASSET_UPSTREAM_URL = _safe_public_http_url( + os.getenv('WEBCRUMBS_ASSET_UPSTREAM_URL', 'http://192.168.0.188:18088') +) # ========================================== # 市場情報模組設定(預設全部關閉) @@ -391,7 +402,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '') # ========================================== # 系統版本與路徑 # ========================================== -SYSTEM_VERSION = "V10.507" +SYSTEM_VERSION = "V10.509" LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log') public_url = PUBLIC_URL # 用於模板顯示 @@ -404,4 +415,6 @@ def validate_critical_config(): warnings.append(f"[Config] 選用設定 {var} 未設,部分功能可能停用") if WEBCRUMBS_ENABLED and not WEBCRUMBS_RUNTIME_URL: warnings.append("[Config] WEBCRUMBS_ENABLED=true 但 WEBCRUMBS_RUNTIME_URL 無效,Webcrumbs runtime 將不會載入") + if WEBCRUMBS_ENABLED and WEBCRUMBS_RUNTIME_URL.startswith('/webcrumbs-assets/') and not WEBCRUMBS_ASSET_UPSTREAM_URL: + warnings.append("[Config] Webcrumbs 使用同源 asset proxy,但 WEBCRUMBS_ASSET_UPSTREAM_URL 無效") return warnings diff --git a/docs/adr/ADR-035-cross-platform-market-campaign-intelligence.md b/docs/adr/ADR-035-cross-platform-market-campaign-intelligence.md index 231af33..70842e3 100644 --- a/docs/adr/ADR-035-cross-platform-market-campaign-intelligence.md +++ b/docs/adr/ADR-035-cross-platform-market-campaign-intelligence.md @@ -177,6 +177,7 @@ EwoooC 目前已有 MOMO EDM / 節慶活動資料、`promo_products`、PChome - 2026-05-31 追加 MCP fetch candidate queue writer review inventory gate:`services.market_intel.mcp_fetch_candidate_queue_writer_review_inventory`、`services.market_intel.mcp_fetch_candidate_queue_writer_review_inventory_gates`、`services.market_intel.mcp_fetch_candidate_queue_writer_review_inventory_sample` 與 `/api/market_intel/mcp_fetch_candidate_queue_writer_review_inventory` 在 writer review handoff 通過後審核 operator read-only candidate queue inventory 摘要,檢查 handoff identity、target table、row count、dedupe keys、review_state、artifact paths、read-only query result、missing/duplicate rows 與 operator confirmations;API/UI 不讀 approval token、不執行 CLI、不開 DB、不寫 queue、不更新 review_state、不做 inventory query、不掛 scheduler,只放行到後續人工 candidate queue review。 - 2026-05-31 追加 MCP fetch candidate queue writer review decision gate:`services.market_intel.mcp_fetch_candidate_queue_writer_review_decision`、`services.market_intel.mcp_fetch_candidate_queue_writer_review_decision_gates`、`services.market_intel.mcp_fetch_candidate_queue_writer_review_decision_sample` 與 `/api/market_intel/mcp_fetch_candidate_queue_writer_review_decision` 在 review inventory 通過後審核 operator candidate queue review decision 摘要,檢查 decision identity、target table、row count、dedupe keys、`needs_review` 現態、允許決策集合、evidence refs、matched row exact-identity/variant/overwrite guard、operator confirmations 與 forbidden API actions;API/UI 不讀 approval token、不執行 CLI、不開 DB、不寫 decision record、不更新 review_state、不寫 match result、不補 queue、不掛 scheduler,只放行到 decision approval / writer preflight 設計。 - 2026-05-31 追加 MCP fetch candidate queue writer review decision approval gate:`services.market_intel.mcp_fetch_candidate_queue_writer_review_decision_approval`、`services.market_intel.mcp_fetch_candidate_queue_writer_review_decision_approval_gates`、`services.market_intel.mcp_fetch_candidate_queue_writer_review_decision_approval_sample` 與 `/api/market_intel/mcp_fetch_candidate_queue_writer_review_decision_approval` 在 review decision 通過後只審核 operator human approval 摘要,確認 decision linkage、approval identity、target table、row count、dedupe keys、`approved_for_writer_preflight` approval result、decision/approval evidence refs、artifact paths、matched row exact-identity/variant/overwrite guard、operator confirmations 與 forbidden API actions;API/UI 不讀 approval token、不執行 CLI、不開 DB、不寫 approval record、不寫 decision record、不更新 review_state、不寫 match result、不補 queue、不掛 scheduler,只放行到後續 writer preflight 設計。此 endpoint 已拆入 `routes.market_intel_mcp_review_routes`,避免 `routes.market_intel_mcp_run_routes` 超過 800 行治理門檻。 +- 2026-05-31 追加 MCP fetch candidate queue writer review decision approval writer preflight gate:`services.market_intel.mcp_fetch_candidate_queue_writer_review_decision_approval_writer_preflight`、對應 gates/sample 與 `/api/market_intel/mcp_fetch_candidate_queue_writer_review_decision_approval_writer_preflight` 在 human approval 通過後只審核 operator writer preflight 摘要,確認 approval linkage、writer_preflight_id、target operation、row count、dedupe keys、approved decision 到 target review_state 的逐列映射、decision/approval/preflight evidence refs、matched row exact-identity/variant/overwrite guard 與 operator boundary;API/UI 不讀 approval token、不執行 CLI、不開 DB、不寫 preflight/approval/decision/match、不更新 review_state、不補 queue、不掛 scheduler,只放行到後續 CLI review / run package 設計。 - 2026-05-18 追加 scheduler attach plan preview:`services.market_intel.scheduler_plan` 與 `/api/market_intel/scheduler_plan` 描述未來 `campaign_discovery_daily`、`campaign_product_probe`、`product_match_review_seed` 三個 job 的 cadence、gate、fallback 與安全邊界。此階段不註冊 scheduler job、不啟動 crawler、不連外、不寫 DB;排程掛載必須等 migration、seed、MCP fetch gate、manual sample 與人工批准全過。 - 2026-05-18 追加 match review plan preview:`services.market_intel.match_review_plan` 與 `/api/market_intel/match_review_plan` 定義商品比對訊號、分數門檻、`needs_review → confirmed/rejected` HITL 流程與安全邊界。此階段不建立 review queue、不自動 confirmed、不寫 `market_product_matches`、不呼叫 MCP;價格只能作為輔助訊號,不能單獨決定同品比對。 - 2026-05-18 追加 opportunity plan preview:`services.market_intel.opportunity_plan` 與 `/api/market_intel/opportunity_plan` 定義競品低價威脅、促銷缺口、深折重疊、活動即將結束四類規則與分級策略。此階段不建立 opportunity queue、不派送 Telegram、不產生 AI 摘要、不寫 DB;高風險項必須先有 confirmed match 與 DB evidence 才能升級。 diff --git a/docs/adr/ADR-037-webcrumbs-shared-ui-runtime.md b/docs/adr/ADR-037-webcrumbs-shared-ui-runtime.md index d87070b..54b19a1 100644 --- a/docs/adr/ADR-037-webcrumbs-shared-ui-runtime.md +++ b/docs/adr/ADR-037-webcrumbs-shared-ui-runtime.md @@ -15,12 +15,13 @@ Webcrumbs 在 momo-pro 中只作為「自架、固定版本、可診斷」的共 採用以下規則: -1. runtime 由 `WEBCRUMBS_*` 環境變數設定,預設指向 `https://webcrumbs.wooo.work/runtime/@v0.1.5`。 -2. `ewoooc_base.html` 只在 `WEBCRUMBS_ENABLED=true` 且 runtime URL 通過 http(s) 檢查時輸出 script。 -3. 新增 `/webcrumbs` 診斷入口,只顯示 runtime URL、版本與 plugin base 狀態,不連到外部官方站作為正式入口。 -4. Webcrumbs plugin 必須使用自架且版本化 URI,例如 `https://webcrumbs.wooo.work/plugins/momo-pro///`。 -5. 禁止在生產使用官方 `@latest`、`app.webcrumbs.ai` 或未固定版本的官方 CDN。 -6. 不把 Webcrumbs 上游 repo 整包納入 momo-pro 主服務;若修改 runtime 本體,需另外處理 AGPL-3.0 授權義務。 +1. runtime 由 `WEBCRUMBS_*` 環境變數設定,正式頁面預設指向 momo-pro 同源 `/webcrumbs-assets/loader/webcrumbs-compatible-loader.js`。 +2. `/webcrumbs-assets/` 只代理 allowlist prefix:`loader/`、`plugins/`、`demo/`,上游預設為 188 user-space Shared UI Hub `http://192.168.0.188:18088`。 +3. `ewoooc_base.html` 只在 `WEBCRUMBS_ENABLED=true` 且 runtime URL 通過 http(s) 或同源絕對路徑檢查時輸出 script。 +4. 新增 `/webcrumbs` 診斷入口,顯示 runtime URL、版本、plugin base 與 asset upstream 狀態。 +5. Webcrumbs plugin 必須使用自架且版本化 URI,例如 `/webcrumbs-assets/plugins///`。 +6. 禁止在生產使用官方 `@latest`、`app.webcrumbs.ai` 或未固定版本的官方 CDN。 +7. 不把 Webcrumbs 上游 repo 整包納入 momo-pro 主服務;若修改 runtime 本體,需另外處理 AGPL-3.0 授權義務。 ## Alternatives Considered @@ -39,6 +40,6 @@ Webcrumbs 在 momo-pro 中只作為「自架、固定版本、可診斷」的共 ## Consequences - momo-pro 可在不替換 Flask/Jinja 的前提下,逐步嵌入自架 UI plugin。 -- 生產部署需同步管理 `WEBCRUMBS_*` 變數與 110 Gateway runtime 路徑。 +- 生產部署需同步管理 `WEBCRUMBS_*` 變數與 Shared UI Hub asset upstream。 - 後續任何 Webcrumbs plugin 上線前,仍需通過真實資料、權限、RWD、效能與 fallback 檢查。 - 若 runtime URL 無效,系統只會跳過 script 載入並在 config warning / `/webcrumbs` 顯示狀態,不應阻斷主站。 diff --git a/docs/guides/webcrumbs_shared_runtime.md b/docs/guides/webcrumbs_shared_runtime.md index 57cfbbe..1bef47f 100644 --- a/docs/guides/webcrumbs_shared_runtime.md +++ b/docs/guides/webcrumbs_shared_runtime.md @@ -16,22 +16,24 @@ ```env WEBCRUMBS_ENABLED=true WEBCRUMBS_BASE_URL=https://webcrumbs.wooo.work -WEBCRUMBS_RUNTIME_VERSION=@v0.1.5 -WEBCRUMBS_RUNTIME_PATH=/runtime/@v0.1.5 +WEBCRUMBS_RUNTIME_VERSION=shared-ui-poc-0.1.0 +WEBCRUMBS_RUNTIME_PATH=/webcrumbs-assets/loader/webcrumbs-compatible-loader.js WEBCRUMBS_RUNTIME_URL= -WEBCRUMBS_PLUGIN_BASE_URL=https://webcrumbs.wooo.work/plugins/momo-pro +WEBCRUMBS_PLUGIN_BASE_URL=/webcrumbs-assets/plugins +WEBCRUMBS_ASSET_UPSTREAM_URL=http://192.168.0.188:18088 ``` -若實際部署成 CDN 相容路徑,例如 `https://webcrumbs.wooo.work/@v0.1.5`,請改用: +目前正式頁面預設走 momo-pro 同源 asset proxy: + +- `/webcrumbs-assets/loader/...` +- `/webcrumbs-assets/plugins/...` +- `/webcrumbs-assets/demo/...` + +這樣即使 `webcrumbs.wooo.work` 的公網 TLS 或 Basic Auth 尚未完全收斂,momo-pro 頁面仍可用 `mo.wooo.work` 同源載入 loader 與 plugin。若日後要改回獨立 Webcrumbs CDN,直接設定: ```env -WEBCRUMBS_RUNTIME_PATH=/@v0.1.5 -``` - -若部署路徑完全不同,直接設定: - -```env -WEBCRUMBS_RUNTIME_URL=https://webcrumbs.wooo.work/custom/runtime.js +WEBCRUMBS_RUNTIME_URL=https://webcrumbs.wooo.work/shared-ui/loader/webcrumbs-compatible-loader.js +WEBCRUMBS_PLUGIN_BASE_URL=https://webcrumbs.wooo.work/shared-ui/plugins ``` ## 頁面嵌入方式 @@ -39,7 +41,7 @@ WEBCRUMBS_RUNTIME_URL=https://webcrumbs.wooo.work/custom/runtime.js 全站 runtime 由 `templates/ewoooc_base.html` 載入。頁面只需要放 plugin tag: ```html - + ``` Plugin 目錄至少應提供: @@ -52,6 +54,7 @@ style.css ## 治理規則 - Plugin URI 必須使用自架 domain。 +- 在 momo-pro 正式頁面,優先使用同源 `/webcrumbs-assets/` URI。 - Plugin 目錄必須版本化,不使用浮動 `latest`。 - Plugin 不得包含 secret、token、內部 API key。 - Plugin 若需要正式資料,必須讀 momo-pro 既有 API,不得自行打 DB。 @@ -60,5 +63,6 @@ style.css ## 驗收 - `/webcrumbs` 顯示 runtime URL、版本與 plugin base。 +- `/webcrumbs-assets/loader/webcrumbs-compatible-loader.js` 回 200 且 content type 是 JavaScript。 - `ewoooc_base.html` 在 `WEBCRUMBS_ENABLED=true` 且 runtime URL 有效時輸出 `