feat(web): add homepage operations map
All checks were successful
CD Pipeline / tests (push) Successful in 1m29s
Code Review / ai-code-review (push) Successful in 12s
CD Pipeline / build-and-deploy (push) Successful in 4m53s
CD Pipeline / post-deploy-checks (push) Successful in 1m36s

This commit is contained in:
Your Name
2026-06-02 12:00:01 +08:00
parent 6b56680e6b
commit 91a956b954
4 changed files with 326 additions and 3 deletions

View File

@@ -318,6 +318,32 @@
"km": "KM 健康"
}
},
"homeProductMap": {
"eyebrow": "AWOOOI Operations Map",
"title": "AI Automation Management Console",
"subtitle": "A unified operations map for intake, AI decisions, evidence, approvals, execution, verification, and KM learning, built to show ownership, blockers, and evidence sources at a glance.",
"currentGate": "Current claim state",
"flowTitle": "Incident lifecycle",
"moduleTitle": "Product modules and data sources",
"modules": {
"awooop": {
"module": "AwoooP Run Timeline",
"owns": "Intake, deduplication, workflow stages, Telegram callbacks, and historical evidence."
},
"routing": {
"module": "AI Router / Agent Roles",
"owns": "GCP-A, GCP-B, host 111, Gemini fallback, and Hermes/OpenClaw/ElephantAlpha role routing."
},
"execution": {
"module": "PlayBook / MCP / Ansible",
"owns": "Tool investigation, dry-runs, check-mode, apply gates, and repair evidence."
},
"learning": {
"module": "KM / Governance",
"owns": "Stale KM, owner review, SLOs, postmortem learning, and rule updates."
}
}
},
"automationDelivery": {
"eyebrow": "AI 自動化管理產品面",
"title": "目前完成項與待推進項",

View File

@@ -318,6 +318,32 @@
"km": "KM 健康"
}
},
"homeProductMap": {
"eyebrow": "AWOOOI Operations Map",
"title": "AI 自動化管理介面",
"subtitle": "統一呈現事件從接收、判斷、證據、審批、執行到驗證與學習的狀態,讓營運團隊快速掌握責任、阻塞與證據來源。",
"currentGate": "目前可宣稱狀態",
"flowTitle": "事件生命週期",
"moduleTitle": "產品模組與資料來源",
"modules": {
"awooop": {
"module": "AwoooP Run Timeline",
"owns": "收件、去重、處理階段、Telegram callback、歷史證據"
},
"routing": {
"module": "AI Router / Agent 分工",
"owns": "GCP-A、GCP-B、111、Gemini fallback 與 Hermes/OpenClaw/ElephantAlpha 分工"
},
"execution": {
"module": "PlayBook / MCP / Ansible",
"owns": "工具調查、dry-run、check-mode、apply gate 與修復證據"
},
"learning": {
"module": "KM / Governance",
"owns": "stale KM、owner review、SLO、事後學習與規則更新"
}
}
},
"automationDelivery": {
"eyebrow": "AI 自動化管理產品面",
"title": "目前完成項與待推進項",

View File

@@ -1879,6 +1879,60 @@ export default function Home({ params }: { params: { locale: string } }) {
}),
},
]
const productModuleRows: Array<{
key: string
module: string
owns: string
evidence: string
href: string
tone: HomepageWorkTone
}> = [
{
key: 'awooop',
module: tDashboard('homeProductMap.modules.awooop.module'),
owns: tDashboard('homeProductMap.modules.awooop.owns'),
evidence: tDashboard('automationDiagrams.workspace.liveEvidence.intake.metric', {
runs: formatAutomationNumber(automationBrief.runsList?.total, runsListLoaded),
linked: formatAutomationNumber(recurrenceSummary?.linked_run_total, eventRecurrenceLoaded),
}),
href: `/${locale}/awooop/runs?project_id=awoooi`,
tone: 'live',
},
{
key: 'routing',
module: tDashboard('homeProductMap.modules.routing.module'),
owns: tDashboard('homeProductMap.modules.routing.owns'),
evidence: tDashboard('automationDiagrams.workspace.values.aiRoute', {
lane: aiRouteLaneMode,
provider: aiRouteSelectedProvider,
}),
href: `/${locale}/awooop/work-items?project_id=awoooi`,
tone: hasAiRouteStatus ? 'live' : 'watching',
},
{
key: 'execution',
module: tDashboard('homeProductMap.modules.execution.module'),
owns: tDashboard('homeProductMap.modules.execution.owns'),
evidence: tDashboard('automationDiagrams.workspace.values.ansible', {
checkMode: formatAutomationNumber(executionBackend?.ansible_check_mode_total, automationQualityLoaded),
pending: formatAutomationNumber(executionBackend?.ansible_pending_check_mode_total, automationQualityLoaded),
blocker: ansibleRuntimeBlockerLabel,
}),
href: `/${locale}/automation`,
tone: ansibleRuntime?.can_run_check_mode ? 'live' : automationQualityAvailable ? 'blocked' : 'watching',
},
{
key: 'learning',
module: tDashboard('homeProductMap.modules.learning.module'),
owns: tDashboard('homeProductMap.modules.learning.owns'),
evidence: tDashboard('automationDiagrams.workspace.liveEvidence.verify.metric', {
stale: formatAutomationNumber(kmStaleDisplayCount, kmGovernanceLoaded),
ratio: staleRatioLabel,
}),
href: `/${locale}/knowledge-base`,
tone: typeof kmStaleDisplayCount === 'number' && kmStaleDisplayCount > 0 ? 'progress' : hasKmStaleCandidates ? 'live' : 'watching',
},
]
return (
<AppLayout locale={locale} showBackground={false} fullBleed>
@@ -1894,14 +1948,173 @@ export default function Home({ params }: { params: { locale: string } }) {
<div style={{
display: 'flex',
flexDirection: 'column',
height: 'calc(100vh - 68px)',
minHeight: 'calc(100vh - 68px)',
background: '#f5f4ed',
fontFamily: 'var(--font-body), monospace',
overflowX: 'hidden',
overflowY: 'auto',
overscrollBehavior: 'contain',
overflowY: 'visible',
}}>
<section
data-testid="homepage-product-map"
style={{
margin: primarySectionMargin,
background: '#fff',
borderTop: '0.5px solid #d8d3c7',
borderBottom: '0.5px solid #d8d3c7',
flexShrink: 0,
}}
>
<div style={{
display: 'grid',
gridTemplateColumns: compactViewport ? '1fr' : 'minmax(0, 1.4fr) minmax(260px, 0.6fr)',
gap: compactViewport ? 10 : 18,
padding: compactViewport ? '14px 12px' : '18px 20px',
borderBottom: '0.5px solid #e0ddd4',
background: '#fffdf8',
}}>
<div style={{ minWidth: 0 }}>
<div style={{ fontSize: 11, fontWeight: 850, color: '#1f5b9b', textTransform: 'uppercase', letterSpacing: 0.5 }}>
{tDashboard('homeProductMap.eyebrow')}
</div>
<h1 style={{ margin: '5px 0 0', fontSize: compactViewport ? 22 : 28, lineHeight: 1.1, fontWeight: 900, color: '#141413' }}>
{tDashboard('homeProductMap.title')}
</h1>
<p style={{ margin: '8px 0 0', maxWidth: 820, fontSize: 13, lineHeight: 1.65, color: '#4e4a43' }}>
{tDashboard('homeProductMap.subtitle')}
</p>
</div>
<div style={{
alignSelf: 'stretch',
display: 'grid',
gap: 8,
border: `0.5px solid ${automationDeliveryClaimTone.border}`,
background: automationDeliveryClaimTone.bg,
padding: '11px 12px',
}}>
<div style={{ fontSize: 10, fontWeight: 850, color: automationDeliveryClaimTone.color, textTransform: 'uppercase', letterSpacing: 0.5 }}>
{tDashboard('homeProductMap.currentGate')}
</div>
<div style={{ fontSize: 16, fontWeight: 900, color: '#141413', lineHeight: 1.2 }}>
{automationDeliveryHeadline}
</div>
<div style={{ fontSize: 11, lineHeight: 1.5, color: '#5f5b52' }}>
{automationDeliveryClaimDetail}
</div>
</div>
</div>
<div style={{
display: 'grid',
gridTemplateColumns: compactViewport ? '1fr' : 'minmax(0, 1.35fr) minmax(320px, 0.85fr)',
gap: compactViewport ? 10 : 14,
padding: compactViewport ? 12 : 16,
}}>
<div style={{ minWidth: 0 }}>
<div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 10, marginBottom: 10 }}>
<h2 style={{ margin: 0, fontSize: 15, fontWeight: 900, color: '#141413' }}>
{tDashboard('homeProductMap.flowTitle')}
</h2>
<a href={`/${locale}/awooop/runs?project_id=awoooi`} style={{ fontSize: 11, fontWeight: 800, color: '#1f5b9b', textDecoration: 'none' }}>
{tDashboard('automationDelivery.openRuns')}
</a>
</div>
<div style={{
display: 'grid',
gridTemplateColumns: compactViewport ? '1fr' : 'repeat(4, minmax(0, 1fr))',
gap: 8,
}}>
{automationFlowStages.map((stage, index) => {
const tone = automationWorkToneStyle[stage.tone]
return (
<a
key={`product-map-${stage.key}`}
href={`/${locale}?blueprint_stage=${stage.key}#homepage-ai-command-map`}
onClick={() => setSelectedBlueprintStageKey(stage.key as HomepageBlueprintStageKey)}
style={{
minWidth: 0,
border: `0.5px solid ${tone.border}`,
background: tone.bg,
padding: '9px 10px',
color: 'inherit',
textDecoration: 'none',
}}
>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 }}>
<span style={{ fontSize: 10, fontWeight: 900, color: tone.color, fontFamily: "'JetBrains Mono', monospace" }}>
{String(index + 1).padStart(2, '0')}
</span>
<span style={{ fontSize: 9, fontWeight: 850, color: tone.color, textTransform: 'uppercase', whiteSpace: 'nowrap' }}>
{stage.status}
</span>
</div>
<div style={{ marginTop: 8, fontSize: 12, fontWeight: 900, color: '#141413', lineHeight: 1.25 }}>
{stage.title}
</div>
<div style={{ marginTop: 6, fontSize: 10, lineHeight: 1.45, color: '#5f5b52', minHeight: 30, overflow: 'hidden' }}>
{stage.liveEvidence.metric}
</div>
</a>
)
})}
</div>
</div>
<div style={{ minWidth: 0 }}>
<div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 10, marginBottom: 10 }}>
<h2 style={{ margin: 0, fontSize: 15, fontWeight: 900, color: '#141413' }}>
{tDashboard('homeProductMap.moduleTitle')}
</h2>
<a href={`/${locale}/topology`} style={{ fontSize: 11, fontWeight: 800, color: '#1f5b9b', textDecoration: 'none' }}>
{tDashboard('automationDiagrams.openTopology')}
</a>
</div>
<div style={{ display: 'grid', gap: 1, border: '0.5px solid #e0ddd4', background: '#e0ddd4' }}>
{productModuleRows.map((row) => {
const tone = automationWorkToneStyle[row.tone]
return (
<a
key={row.key}
href={row.href}
style={{
display: 'grid',
gridTemplateColumns: compactViewport ? '1fr' : '0.72fr 1fr',
gap: 8,
padding: '9px 10px',
background: '#fff',
color: 'inherit',
textDecoration: 'none',
}}
>
<div style={{ minWidth: 0 }}>
<div style={{ fontSize: 12, fontWeight: 900, color: '#141413' }}>{row.module}</div>
<div style={{ marginTop: 3, fontSize: 10, lineHeight: 1.4, color: '#5f5b52' }}>{row.owns}</div>
</div>
<div style={{ minWidth: 0 }}>
<div style={{
display: 'inline-flex',
maxWidth: '100%',
border: `0.5px solid ${tone.border}`,
background: tone.bg,
color: tone.color,
padding: '2px 7px',
fontSize: 10,
fontWeight: 850,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
}}>
{row.evidence}
</div>
</div>
</a>
)
})}
</div>
</div>
</div>
</section>
<section style={{
margin: primarySectionMargin,
background: '#fff',

View File

@@ -27696,3 +27696,61 @@ production browser smoke:
- Ansible / PlayBook runtime約 95%;候選 PlayBook 已呈現在 AwoooP但本 incident 尚無 check/apply 紀錄。
- 完整自動修復 production claim約 3.5%Gate 5 projection 是可見性與安全閘,不是自動修復成功。真正提升要完成 executor handoff 並用 24h verified_success 拉高。
- 完整 AI Agent 自動化飛輪:約 63%;監控、告警、審批、證據鏈、前端可視化更完整,但執行成功率與學習閉環仍是主缺口。
## 2026-06-02 — Frontend product UX 12-agent audit + homepage operations map
**背景**
- 使用者指出 production 首頁與 AwoooP/Alerts/Governance 等頁面文字量過大、難以快速判讀流程階段,且首頁無法正常上下滾動。
- 本輪以 12 個 read-only agent 分工盤點IA/navigation、首頁、AwoooP、Alerts、KM/Governance、Observability、Automation/Ansible、Security/IwoooS、i18n、Visual System、Data/API truth、Responsive/A11y。
- 主工作區 `/Users/ogt/awoooi` 仍有大量既有 dirty/untracked 變更;本輪在乾淨 worktree `/private/tmp/awoooi-frontend-product-audit-20260602` 基於最新 `gitea/main` 開發,避免混入無關變更。
**本輪完成**
- 首頁 `/zh-TW` 新增 `homepage-product-map` 首屏區塊:
- 產品化呈現 AI 自動化事件生命週期Alert / Sentry / SigNoz → AwoooP 收件 → OpenClaw / Hermes → MCP 證據 → PlayBook 閘門 → Ansible Check → Approval / Apply → Verify / KM。
- 右側以表格化模組列呈現 AwoooP Run Timeline、AI Router / Agent 分工、PlayBook / MCP / Ansible、KM / Governance 的 owner 與資料來源。
- 不新增假數字,沿用 production truth-chain / homepage brief / quality summary 的既有資料;資料未回應時顯示暫不可用,不宣稱自動修復完成。
- 修正首頁 scroll owner
- 原本 overview 外層 `height: calc(100vh - 68px)` + `overflowY:auto` 造成 document 不是主要 scroll ownerproduction 實測 document height 只有約 1299px、內層 scrollHeight 約 6023px。
- 改為 `minHeight: calc(100vh - 68px)` + `overflowY:visible`,恢復正常 document scroll。
- 補 `zh-TW` / `en` i18n`dashboard.homeProductMap.*`,避免把本輪討論文字硬寫在頁面中。
**12-agent 盤點收斂**
- IA/navigation46 個 route、108 個 TSX component 粗盤;主導航是 8 主入口 + legacy + bottom與「五柱導航」註解不一致。需要下一波收斂孤島頁`/topology``/aiops/timeline``/reports``/alert-operation-logs``/users`
- AwoooPRuns / Work Items / Approvals 資料結構夠完整,但頁面把 incident、recurrence、repair、source correlation、approval、truth-chain 混在同一閱讀面。下一波需要 Run detail flow / evidence table / approval gate drawer。
- Alerts`/incidents` 目前沒有 `alertname/source/fingerprint/hit_count/source_logs` projection前端無法判讀重複告警。需要 incident correlation projection。
- KM/Governance後端已有 `knowledge_degradation` / `kb_stale` governance event但前端 events/query/model 與後端 schema 不完全對齊operator 看到的是告警而不是 workflow。需要 KM Health tab。
- ObservabilityMonitoring/Alerts/APM 仍偏列表文字,缺 severity x hour heatmap、source matrix、routing funnel、host/service heatmap。`MonitoringPanel``/dashboard` payload contract 也需對齊。
- Automation/AnsibleAnsible 不是一級 ActionTypeAutoRepairPanel 只露少量 gate 資訊,未呈現 cooldown / service registry / anti-pattern / verifier / rollback / KM links。需要 AutoRepair gate trace + Ansible coverage table。
- Visual System缺共用 Button / Badge / DataTable / PageHeader / EmptyState / MetricCard primitive導致頁面大量手刻卡片、文字牆與 emoji icon 殘留。
- Data/API truthAIOps mock、首頁/classic static host catalog、CPU/RAM fallback、Code Review 內網 URL、`NEXT_PUBLIC_API_URL ?? ''` catch-to-empty 是 P1 技術債;需 API-backed truth source 與 public/proxy-safe URLs。
- Responsive/A11y首頁 scroll owner 已先修;仍需 mobile drawer shell、FlowPipeline mobile vertical mode、tab semantics、focus-visible、touch target 與 text contrast 修正。
**驗證**
- `node -e "JSON.parse(...zh-TW.json); JSON.parse(...en.json); console.log('json ok')"``json ok`
- `pnpm --filter @awoooi/web typecheck` → success
- Local dev
- `NEXT_PUBLIC_API_URL=https://awoooi.wooo.work pnpm --filter @awoooi/web dev -- --hostname 127.0.0.1 --port 3112`
- Browser DOM`productMapPresent=true``docScrollHeight=5428``bodyScrollHeight=5428``navVisible=true`
- Desktop screenshot layout audit`horizontalOverflow=0``overflowingCount=0`
- Mobile 390px layout audit`productMapPresent=true``horizontalOverflow=0``overflowingCount=0`
- Production build
- `NEXT_PUBLIC_API_URL=https://awoooi.wooo.work NEXT_PRIVATE_BUILD_WORKER_COUNT=1 pnpm --filter @awoooi/web build` → success
- Build size note`/[locale]` 32.5 kB / First Load JS 277 kB`/topology` 492 kB / First Load JS 722 kB後續需另列 performance debt。
**下一波優先順序**
1. AwoooP Run detail / Evidence table / Approval gate drawer讓 operator 一眼知道跑到哪一關、誰負責、缺什麼證據。
2. Incident correlation projection`fingerprint/hit_count/source_logs/Sentry/SigNoz/Telegram/AwoooP run``/incidents` 與 timeline解決重複告警不可判讀。
3. KM Health / Governance workflow`knowledge_degradation` 從告警文字轉成 stale buckets、owner review、dispatch/verify workflow。
4. AutoRepair gate trace + Ansible coverage table把 PlayBook match、dry-run、policy、approval、verify、KM link 與 Ansible check/apply/diff 變成可掃描表格。
5. Frontend primitives / i18n debt建立 Button/Badge/DataTable/PageHeader/EmptyState/MetricCard先改 AwoooP 與 Alerts清 AwoooP/Code Review 硬編文案與內網 URL。
**目前整體進度(本階段完成後)**
- 全站前端 IA / 可讀性盤點:約 100%12 個 read-only agent 已完成並已收斂為 wave。
- 首頁產品化入口:約 78%;已補 Operations Map 與正常 document scroll仍需清舊 static/fallback 區塊與拆大檔。
- AwoooP / HITL 可視化:約 99.2%;本輪未改 executor handoff仍缺 Run detail evidence table 與 legacy duplicate reconciliation。
- Alerts recurrence / source correlation約 68%;問題已定位,需新增 API projection 後前端才能準確呈現重複與來源。
- KM / Governance workflow約 58%;後端事件已有,前端 workflow/health tab 尚未完成。
- Ansible / AutoRepair gate 可視化:約 52%;候選資料與 runbook 已有,尚缺一級 ActionType / coverage table / gate trace。
- Frontend design system / i18n約 46%;盤點完成,但 primitives 與 AwoooP i18n 大掃除尚未實作。
- 完整自動修復 production claim約 3.5%;本輪是 UX/可視化進展,未提高 verified auto-repair execution success。
- 完整 AI Agent 自動化飛輪:約 66%;可視化與產品入口改善,但真正自動執行、驗證、學習閉環仍需下一波 API + executor + governance 工作。