diff --git a/apps/api/src/services/platform_operator_service.py b/apps/api/src/services/platform_operator_service.py index 42528d06d..a2a3f07eb 100644 --- a/apps/api/src/services/platform_operator_service.py +++ b/apps/api/src/services/platform_operator_service.py @@ -151,11 +151,46 @@ _DOMAIN_PRODUCT_OVERRIDES: dict[str, dict[str, str]] = { "product_name": "AWOOOI / AwoooP / IwoooS", "category": "core_platform", }, + "api.awoooi.wooo.work": { + "product_id": "awoooi", + "product_name": "AWOOOI / AwoooP / IwoooS", + "category": "core_platform", + }, + "app.awoooi.wooo.work": { + "product_id": "awoooi", + "product_name": "AWOOOI / AwoooP / IwoooS", + "category": "core_platform", + }, + "api.aiops.wooo.work": { + "product_id": "awoooi", + "product_name": "AWOOOI / AwoooP / IwoooS", + "category": "core_platform", + }, + "clawbot.aiops.wooo.work": { + "product_id": "awoooi", + "product_name": "AWOOOI / AwoooP / IwoooS", + "category": "core_platform", + }, + "command.aiops.wooo.work": { + "product_id": "awoooi", + "product_name": "AWOOOI / AwoooP / IwoooS", + "category": "core_platform", + }, + "security.wooo.work": { + "product_id": "awoooi", + "product_name": "AWOOOI / AwoooP / IwoooS", + "category": "core_platform", + }, "mo.wooo.work": { "product_id": "ewoooc", "product_name": "EwoooC / Mo", "category": "business_product", }, + "2026fifa.wooo.work": { + "product_id": "2026-fifa-world-cup", + "product_name": "2026 FIFA World Cup", + "category": "business_product", + }, "vibework.wooo.work": { "product_id": "vibework", "product_name": "VibeWork", @@ -186,11 +221,41 @@ _DOMAIN_PRODUCT_OVERRIDES: dict[str, dict[str, str]] = { "product_name": "TsenYang Website", "category": "public_site", }, + "tsenyang.wooo.work": { + "product_id": "tsenyang-website", + "product_name": "TsenYang Website", + "category": "public_site", + }, "vtuber.wooo.work": { "product_id": "vtuber", "product_name": "VTuber", "category": "public_site", }, + "design.wooo.work": { + "product_id": "wooo-open-design", + "product_name": "WOOO Open Design", + "category": "platform_tool", + }, + "grist.wooo.work": { + "product_id": "data-workspace", + "product_name": "Data Workspace / Grist", + "category": "platform_tool", + }, + "n8n.wooo.work": { + "product_id": "workflow-automation", + "product_name": "Workflow Automation / n8n", + "category": "platform_tool", + }, + "vault.wooo.work": { + "product_id": "security-secrets-platform", + "product_name": "Security / Vault", + "category": "platform_tool", + }, + "ollama.wooo.work": { + "product_id": "ai-model-gateway", + "product_name": "AI Model Gateway / Ollama", + "category": "platform_tool", + }, "gitea.wooo.work": { "product_id": "source-control", "product_name": "Source Control / DevOps", @@ -226,6 +291,11 @@ _DOMAIN_PRODUCT_OVERRIDES: dict[str, dict[str, str]] = { "product_name": "Observability / LLMOps", "category": "platform_tool", }, + "monitor.wooo.work": { + "product_id": "observability-tooling", + "product_name": "Observability / LLMOps", + "category": "platform_tool", + }, } _CANONICAL_PRODUCT_SURFACES: tuple[dict[str, Any], ...] = ( @@ -237,7 +307,16 @@ _CANONICAL_PRODUCT_SURFACES: tuple[dict[str, Any], ...] = ( "surface_kind": "platform_product", "owner_lane": "S4.9-S4.13", "coverage_status": "read_only_visible", - "public_routes": ["awoooi.wooo.work", "aiops.wooo.work"], + "public_routes": [ + "awoooi.wooo.work", + "aiops.wooo.work", + "api.awoooi.wooo.work", + "app.awoooi.wooo.work", + "api.aiops.wooo.work", + "clawbot.aiops.wooo.work", + "command.aiops.wooo.work", + "security.wooo.work", + ], "source_keys": ["wooo/awoooi"], }, { @@ -251,6 +330,17 @@ _CANONICAL_PRODUCT_SURFACES: tuple[dict[str, Any], ...] = ( "public_routes": ["mo.wooo.work"], "source_keys": ["wooo/ewoooc / root/momo-pro-system / momo working trees"], }, + { + "product_id": "2026-fifa-world-cup", + "product_name": "2026 FIFA World Cup", + "project_id": "2026FIFAWorldCup", + "category": "business_product", + "surface_kind": "product_site", + "owner_lane": "product_onboarding", + "coverage_status": "owner_response_required", + "public_routes": ["2026fifa.wooo.work"], + "source_keys": ["2026FIFAWorldCup"], + }, { "product_id": "vibework", "product_name": "VibeWork", @@ -303,7 +393,7 @@ _CANONICAL_PRODUCT_SURFACES: tuple[dict[str, Any], ...] = ( "surface_kind": "public_site", "owner_lane": "S4.10", "coverage_status": "owner_response_required", - "public_routes": ["tsenyang.com", "www.tsenyang.com"], + "public_routes": ["tsenyang.com", "www.tsenyang.com", "tsenyang.wooo.work"], "source_keys": ["tsenyang-website"], }, { @@ -317,6 +407,61 @@ _CANONICAL_PRODUCT_SURFACES: tuple[dict[str, Any], ...] = ( "public_routes": ["vtuber.wooo.work"], "source_keys": [], }, + { + "product_id": "wooo-open-design", + "product_name": "WOOO Open Design", + "project_id": "open-design", + "category": "platform_tool", + "surface_kind": "design_system", + "owner_lane": "S4.10", + "coverage_status": "read_only_visible", + "public_routes": ["design.wooo.work"], + "source_keys": ["open-design"], + }, + { + "product_id": "workflow-automation", + "product_name": "Workflow Automation / n8n", + "project_id": "__platform__", + "category": "platform_tool", + "surface_kind": "automation_tool", + "owner_lane": "observability_tooling", + "coverage_status": "read_only_candidate", + "public_routes": ["n8n.wooo.work"], + "source_keys": [], + }, + { + "product_id": "data-workspace", + "product_name": "Data Workspace / Grist", + "project_id": "__platform__", + "category": "platform_tool", + "surface_kind": "data_tool", + "owner_lane": "observability_tooling", + "coverage_status": "read_only_candidate", + "public_routes": ["grist.wooo.work"], + "source_keys": [], + }, + { + "product_id": "security-secrets-platform", + "product_name": "Security / Vault", + "project_id": "__platform__", + "category": "platform_tool", + "surface_kind": "security_tool", + "owner_lane": "S4.12", + "coverage_status": "read_only_candidate", + "public_routes": ["vault.wooo.work"], + "source_keys": [], + }, + { + "product_id": "ai-model-gateway", + "product_name": "AI Model Gateway / Ollama", + "project_id": "__platform__", + "category": "platform_tool", + "surface_kind": "ai_provider_tool", + "owner_lane": "P1-004", + "coverage_status": "read_only_candidate", + "public_routes": ["ollama.wooo.work"], + "source_keys": [], + }, { "product_id": "source-control", "product_name": "Source Control / DevOps", @@ -341,7 +486,12 @@ _CANONICAL_PRODUCT_SURFACES: tuple[dict[str, Any], ...] = ( "surface_kind": "tooling", "owner_lane": "P1-003", "coverage_status": "read_only_visible", - "public_routes": ["sentry.wooo.work", "signoz.wooo.work", "langfuse.wooo.work"], + "public_routes": [ + "sentry.wooo.work", + "signoz.wooo.work", + "langfuse.wooo.work", + "monitor.wooo.work", + ], "source_keys": [], }, ) @@ -352,6 +502,41 @@ _ADDITIONAL_PUBLIC_ROUTES: tuple[dict[str, Any], ...] = ( "coverage_status": "read_only_visible", "source": "awoooi_canonical_route", }, + { + "domain": "api.awoooi.wooo.work", + "coverage_status": "read_only_candidate", + "source": "repo_domain_scan_candidate", + }, + { + "domain": "app.awoooi.wooo.work", + "coverage_status": "read_only_candidate", + "source": "repo_domain_scan_candidate", + }, + { + "domain": "api.aiops.wooo.work", + "coverage_status": "read_only_candidate", + "source": "repo_domain_scan_candidate", + }, + { + "domain": "clawbot.aiops.wooo.work", + "coverage_status": "read_only_candidate", + "source": "repo_domain_scan_candidate", + }, + { + "domain": "command.aiops.wooo.work", + "coverage_status": "read_only_candidate", + "source": "repo_domain_scan_candidate", + }, + { + "domain": "security.wooo.work", + "coverage_status": "read_only_candidate", + "source": "repo_domain_scan_candidate", + }, + { + "domain": "2026fifa.wooo.work", + "coverage_status": "owner_response_required", + "source": "cross_workspace_product_candidate", + }, { "domain": "vibework.wooo.work", "coverage_status": "owner_response_required", @@ -362,6 +547,41 @@ _ADDITIONAL_PUBLIC_ROUTES: tuple[dict[str, Any], ...] = ( "coverage_status": "owner_response_required", "source": "agent_bounty_onboarding_handoff", }, + { + "domain": "tsenyang.wooo.work", + "coverage_status": "owner_response_required", + "source": "repo_domain_scan_candidate", + }, + { + "domain": "design.wooo.work", + "coverage_status": "read_only_visible", + "source": "open_design_route_candidate", + }, + { + "domain": "grist.wooo.work", + "coverage_status": "read_only_candidate", + "source": "repo_domain_scan_candidate", + }, + { + "domain": "n8n.wooo.work", + "coverage_status": "read_only_candidate", + "source": "repo_domain_scan_candidate", + }, + { + "domain": "vault.wooo.work", + "coverage_status": "read_only_candidate", + "source": "repo_domain_scan_candidate", + }, + { + "domain": "ollama.wooo.work", + "coverage_status": "read_only_candidate", + "source": "repo_domain_scan_candidate", + }, + { + "domain": "monitor.wooo.work", + "coverage_status": "read_only_candidate", + "source": "repo_domain_scan_candidate", + }, ) diff --git a/apps/api/tests/test_awooop_tenant_asset_inventory.py b/apps/api/tests/test_awooop_tenant_asset_inventory.py index 49288fa54..45e422d2e 100644 --- a/apps/api/tests/test_awooop_tenant_asset_inventory.py +++ b/apps/api/tests/test_awooop_tenant_asset_inventory.py @@ -21,8 +21,8 @@ def test_tenant_asset_inventory_merges_products_routes_and_repos() -> None: assert inventory["schema_version"] == "awooop_tenant_asset_inventory_v1" assert summary["tenant_table_count"] == 1 - assert summary["product_surface_count"] >= 10 - assert summary["public_route_count"] >= 17 + assert summary["product_surface_count"] >= 16 + assert summary["public_route_count"] >= 31 assert summary["source_candidate_repo_count"] == 10 assert summary["source_in_scope_repo_count"] == 9 assert summary["source_primary_ready_count"] == 0 @@ -36,9 +36,15 @@ def test_tenant_asset_inventory_merges_products_routes_and_repos() -> None: "ewoooc", "vibework", "agent-bounty-protocol", + "2026-fifa-world-cup", "stockplatform", "bitan-pharmacy", "tsenyang-website", + "wooo-open-design", + "workflow-automation", + "data-workspace", + "security-secrets-platform", + "ai-model-gateway", }.issubset(product_ids) route_domains = {item["domain"] for item in inventory["public_routes"]} @@ -49,14 +55,23 @@ def test_tenant_asset_inventory_merges_products_routes_and_repos() -> None: "mo.wooo.work", "vibework.wooo.work", "agent.wooo.work", + "2026fifa.wooo.work", + "design.wooo.work", + "n8n.wooo.work", + "grist.wooo.work", + "vault.wooo.work", + "ollama.wooo.work", "tsenyang.com", + "tsenyang.wooo.work", }.issubset(route_domains) source_repos = {item["github_repo"] for item in inventory["source_repos"]} assert "owenhytsai/VibeWork" in source_repos assert "owenhytsai/agent-bounty-protocol" in source_repos + assert "nexu-io/open-design" in source_repos assert all(item["runtime_gate_count"] == 0 for item in inventory["source_repos"]) assert all(item["action_button_count"] == 0 for item in inventory["public_routes"]) + assert all(item["runtime_gate_count"] == 0 for item in inventory["products"]) def test_tenant_response_model_keeps_asset_inventory_contract() -> None: @@ -78,6 +93,6 @@ def test_tenant_response_model_keeps_asset_inventory_contract() -> None: } ) - assert response.asset_inventory.summary.product_surface_count >= 10 + assert response.asset_inventory.summary.product_surface_count >= 16 assert response.asset_inventory.summary.runtime_gate_count == 0 assert response.asset_inventory.products[0].runtime_gate_count == 0 diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index 0443757a3..ec3c60d79 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -8554,8 +8554,8 @@ "tenants": { "globalAssets": { "eyebrow": "全域納管", - "title": "所有產品、網站與專案覆蓋盤", - "subtitle": "把租戶資料表、正式網站入口、前後台產品、平台工具與原始碼管控候選合併到同一個只讀視圖;這不是建立專案庫、改路由、部署、掃描或執行期授權。", + "title": "全域產品資產台帳", + "subtitle": "把租戶資料表、正式網站入口、前後台產品、平台工具、設計系統、AI 工具與原始碼管控候選合併到同一個只讀視圖;這不是建立專案庫、改路由、部署、掃描或執行期授權。", "loading": "讀取資產盤", "itemsUnit": "項", "productsTitle": "產品 / 專案納管", @@ -8566,7 +8566,7 @@ "metrics": { "products": { "label": "產品 / 專案", - "detail": "核心平台、公開網站、工具與新納管產品都列入同一張覆蓋盤。" + "detail": "核心平台、公開網站、平台工具、設計系統與新納管產品都列入同一張台帳。" }, "routes": { "label": "網站入口", @@ -8615,6 +8615,7 @@ "statuses": { "verified": "已驗證", "readOnlyVisible": "只讀可見", + "readOnlyCandidate": "只讀候選", "readOnlyPendingSmoke": "待 smoke 證據", "ownerResponseRequired": "待負責人回覆", "unknown": "待分類" diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index 0443757a3..ec3c60d79 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -8554,8 +8554,8 @@ "tenants": { "globalAssets": { "eyebrow": "全域納管", - "title": "所有產品、網站與專案覆蓋盤", - "subtitle": "把租戶資料表、正式網站入口、前後台產品、平台工具與原始碼管控候選合併到同一個只讀視圖;這不是建立專案庫、改路由、部署、掃描或執行期授權。", + "title": "全域產品資產台帳", + "subtitle": "把租戶資料表、正式網站入口、前後台產品、平台工具、設計系統、AI 工具與原始碼管控候選合併到同一個只讀視圖;這不是建立專案庫、改路由、部署、掃描或執行期授權。", "loading": "讀取資產盤", "itemsUnit": "項", "productsTitle": "產品 / 專案納管", @@ -8566,7 +8566,7 @@ "metrics": { "products": { "label": "產品 / 專案", - "detail": "核心平台、公開網站、工具與新納管產品都列入同一張覆蓋盤。" + "detail": "核心平台、公開網站、平台工具、設計系統與新納管產品都列入同一張台帳。" }, "routes": { "label": "網站入口", @@ -8615,6 +8615,7 @@ "statuses": { "verified": "已驗證", "readOnlyVisible": "只讀可見", + "readOnlyCandidate": "只讀候選", "readOnlyPendingSmoke": "待 smoke 證據", "ownerResponseRequired": "待負責人回覆", "unknown": "待分類" diff --git a/apps/web/src/app/[locale]/awooop/tenants/page.tsx b/apps/web/src/app/[locale]/awooop/tenants/page.tsx index b9186edf6..cf8eaec5e 100644 --- a/apps/web/src/app/[locale]/awooop/tenants/page.tsx +++ b/apps/web/src/app/[locale]/awooop/tenants/page.tsx @@ -244,6 +244,7 @@ const ownerResponseValidationTenantBoundaries = [ const ASSET_STATUS_TONES: Record = { verified: "steady", read_only_visible: "steady", + read_only_candidate: "warn", read_only_pending_smoke: "warn", owner_response_required: "warn", }; @@ -260,6 +261,7 @@ const ASSET_CATEGORY_KEYS: Record = { const ASSET_STATUS_KEYS: Record = { verified: "verified", read_only_visible: "readOnlyVisible", + read_only_candidate: "readOnlyCandidate", read_only_pending_smoke: "readOnlyPendingSmoke", owner_response_required: "ownerResponseRequired", };