Skip to content

feat: Batch 7 — Landing & Observability v1 (#18) - #39

Merged
ghbvf merged 9 commits into
developfrom
016-b7-landing-observe
Jun 3, 2026
Merged

ghbvf merged 9 commits into
developfrom
016-b7-landing-observe

Conversation

@ghbvf

@ghbvf ghbvf commented Jun 3, 2026

Copy link
Copy Markdown
Owner

Summary

Batch 7 (issue #18): the / Health overview (Landing) and /observe Observability v1, both owned by @gocell/observability (its README scopes it to Landing/Observe). Per the directive, backend gaps are treated as non-blocking — BR-001 (/admin/health/cells), BR-002 (/admin/system), and BR-003 (LGTM) endpoints are unbuilt, so every data path degrades gracefully to an unavailable panel rather than erroring. That degradation is deliverable T703.

Closes #18.

What shipped

  • Landing (/) — polled (30s) cell-health card grid + status rollup, SystemInfoCard, intentional deploys/KPI placeholder cards, degraded banner when BR-001/002 are absent, sr-only aria-live refresh announcement. (T701)
  • Observability v1 (/observe) — accessible roving-tablist with 3 live tabs (Overview / Logs / Traces) + 4 disabled Wave-2 tabs (Anomalies / What changed / Service graph / Slice health) as aria-disabled spans; each tab is store-driven (real data path) and degrades to the unavailable panel while LGTM is absent; the active panel is wrapped in ObservabilityErrorBoundary (onErrorCaptured). Active tab carried in ?tab=. (T702 + T703)
  • @gocell/core i18n gains landing.* + observe.* (zh-CN + en-US; satisfies MessageSchema enforces parity).

Key decisions (confirmed with maintainer)

  1. LGTM transport = @gocell/request BFF proxy paths (/api/v1/observability/{loki,tempo,prometheus}/*, BR-003 §3.4 方案 B) — not bare fetch to LGTM origins (方案 A), which would violate the package-boundary no-fetch rule. Forward-compatible with the prod gateway; degrades by default since the proxy isn't implemented.
  2. Observe tabs = full v1 — real data rendering on the success path (mocked in tests) + degrade fallback, not empty shells.
  3. Promote shared primitives to @gocell/core — useRovingTablist + UnavailablePanel moved from @gocell/devboard into core (business cells can't import each other); all devboard consumers repointed. No back-compat shim.
  4. Landing/Observe are auth-gated only (no PDP requiredAction) — operational dashboards for any authenticated admin. / flips to requiresAuth: true (resolves the standing Batch 7 TODO).
  5. observe nav stays in the Reserved group with pill: 'preview' (LGTM not deployed); no navConfig change.

AI-robust note

Closes the recalled i18n-missing-key blind spot: i18n.spec.ts now deep-compares the landing/observe leaf-key trees across locales and asserts every key the views render resolves to a non-empty string in both locales (vue-i18n is not key-typed, so a typo'd t() key otherwise passes typecheck/test/build and renders raw).

Packages touched

Package Change
@gocell/observability (46 files) new build-out: api (health/system/observe) + lib + stores + components + views + specs
@gocell/core (10) i18n namespaces + spec; promote useRovingTablist + UnavailablePanel
@gocell/devboard (10) repoint to core for the two promoted primitives; delete local copies
apps/web (5) router rewire (/ + /observe), delete HomeView, router/guards specs, e2e/health.spec.ts

packages/contracts/ untouched — no codegen types exist for BR-001/002/003 yet; all backend shapes are local TS types annotated for codegen cutover once the schemas land.

Test plan

  • pnpm -w lint — 0 issues
  • pnpm -w typecheck — clean (all packages)
  • pnpm -w test --run — 1714 passed / 118 files
  • pnpm -F @gocell/web build — succeeds; LandingView/ObserveView chunks emitted (subpath exports resolve)
  • coverage: @gocell/core 99%+ (gate 90%), @gocell/observability 99% stmts / ~90% branches (gate 80%)
  • Playwright e2e/health.spec.ts (degraded/ok health overview, observe tabs, protected /→login redirect) — added + parses; not executed locally (needs server/browsers), runs in CI

Deferred (out of scope, follow-up)

  • Wave-2 observe tabs (Anomalies / What changed / Service graph / Slice health) — disabled per PRD §279.
  • Real LGTM data UI fidelity tightens once BR-003 lands and the proxy exists.

🤖 Generated with Claude Code

ghbvf and others added 9 commits June 3, 2026 10:02
zh-CN + en-US gain `landing.*` (health overview) and `observe.*`
(observability v1) trees; en-US `satisfies MessageSchema` enforces parity
at typecheck. i18n.spec adds a recursive leaf-key cross-locale comparison
plus a frozen REQUIRED_KEYS existence assertion for every key the Batch 7
views render — closing the recalled i18n-missing-key blind spot (a t() on
an absent key otherwise passes typecheck/test/build and renders raw at runtime).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Both were devboard internals; @gocell/observability (Batch 7) needs them but
business cells cannot import each other — only @gocell/core is shared. Move
both (generic signature + role=status panel preserved) into core, export from
the root barrel, and repoint all devboard consumers (CellTabBar, DepsViewBar,
5 tab components) to @gocell/core. No back-compat shim (no external consumers).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
package.json (deps + test scripts + view exports), vitest.config (80% gate).
api/health.ts (BR-001 /admin/health/cells), api/system.ts (BR-002 /admin/system),
api/observe.ts (BR-003 LGTM via @gocell/request BFF proxy paths
/api/v1/observability/* — 方案 B, no bare fetch). Local types annotated for
codegen cutover. lib/ pure helpers: formatUptime, formatBytes, healthStatus
(status→variant + cell rollup). Endpoints 404 until backend lands → callers degrade.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
useHealthStore ('observe.health'): cells/summary/system with independent
health/system load status; refresh() runs both via allSettled; errors degrade
to status='unavailable' + errorKey (toI18nKey), never throw. useObserveStore
('observe.signals'): per-tab overview KPIs / logs / traces load actions over
the LGTM proxy api, RangePreset window via pure rangeFromPreset(preset, now).
useHealthPoll: 30s setInterval refresh, onScopeDispose cleanup. index.ts barrel.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Landing: CellHealthBadge (status→token dot + i18n label), CellHealthCard,
SystemInfoCard (degrades to core UnavailablePanel). Observe: ObserveTabBar
(core useRovingTablist; 3 live tabs + 4 aria-disabled Wave-2 spans),
ObservabilityErrorBoundary (onErrorCaptured → degrade panel + retry; T703 net),
OverviewPanel/LogsPanel/TracesPanel (store-driven, loading/unavailable/empty/
loaded states, all degrade gracefully while LGTM backend is absent).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
LandingView (/): polled (30s) cell-health grid + summary rollup + SystemInfoCard,
degraded banner when BR-001/002 endpoints absent, intentional deploys/KPI
placeholder cards (core UnavailablePanel), sr-only aria-live refresh announcement.
ObserveView (/observe): roving-tablist tab bar (3 live + 4 Wave-2 disabled),
active panel wrapped in ObservabilityErrorBoundary, active tab carried in ?tab=.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`/` now renders @gocell/observability/views/landing (Health overview) and is
auth-gated (resolves the Batch 7 TODO); add `/observe` →
@gocell/observability/views/observe, auth-only (no PDP — operational dashboards).
Delete the HomeView placeholder; add @gocell/observability as a web dep.
router/index + guards specs updated (unauth `/` → /login now asserted);
e2e/health.spec covers degraded + ok health overview, observe tabs, and the
protected-route redirect (the smoke deferred from earlier batches).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Six-dimension review + adversarial verification (18 confirmed / 5 refuted):
- ObservabilityErrorBoundary: keep the h() render-fn (a plain template re-introduces
  the Vue block-patch crash) but move its styles to an unscoped block so they apply
  to h()-created nodes; restore focus to the slot wrapper on retry (WCAG 2.4.3).
- LandingView: render the aria-live region unconditionally (first poll now announced);
  aria-hidden the decorative rollup counts; drop the duplicate system h2 (card owns it);
  font-sizes → tokens (--text-3xl/--text-base/--text-sm).
- core: add --text-3xl: 26px (matches dev-observe KPI value); remove unused observe.range.* keys.
- OverviewPanel KPI value → --text-3xl. CellHealthBadge: hoist KNOWN_STATUSES out of computed.
- useObserveStore: kpis ref → shallowRef (matches logs/traces). observe.ts: coerce Prom timestamp.
- Logs/TracesPanel: drop redundant @click.prevent (form @submit.prevent suffices).
- devboard + observability READMEs corrected; e2e LGTM stub /observe → /observability.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Playwright smoke(CI 阻塞,5→0 失败)
- Batch 7 把 `/` 改为 requiresAuth:true 后,原 smoke/health/auth e2e 仍按公开
  `/` 假设编写:未登录访问 `/` 重定向 login,登录后又 `page.goto` 整页刷新清空
  仅存内存的 Pinia token → 弹回 login。
- 新增 e2e/helpers.ts:stubSetupDone / loginAs(经登录后重定向落到目标路由,不
  二次 page.goto)/ stubHealthEndpoints。health/smoke/auth 改为 SPA 导航 + stub。
- health OK 用例修正:契约为 envelope-less(fetchCellHealth 返回 res.data),
  stub 去掉多余 {data} 信封并补全 CellHealthEntry 形状;system 端点 404 隔离。
- 本地 11/11 e2e 通过。

## 六维度 review Cx1/Cx2(19 条,跨 observability/core/devboard)
- TS:observe.ts 收紧 Loki/Tempo/Prom 类型守卫;PromRawResponse.status 缩窄并在
  非 success 时抛错(不再静默吞成空数据);消除 `?? []` 死码。
- Vue:三面板 idle 态并入 loading 分支(消首帧空态闪烁);v-model 直写 store 改
  setLogsQuery/setTracesService action;LandingView idle/loaded 分支显式化。
- 性能:ObserveView 三面板 defineAsyncComponent 懒加载拆 chunk;useHealthPoll 标签
  页隐藏暂停轮询;useHealthStore fetch 并发去重防竞态;CellHealthCard lastError 改
  O(n) 线性扫描。
- a11y:Wave-2 disabled tab 纳入 roving(core useRovingTablist 新增 disabledIds,
  focus 可达但不激活);LandingView 合并多 role=status live region;错误边界错误时
  程序化移焦 + 恢复 focus-visible 轮廓;Logs/Traces 表格补 sr-only caption。
- 设计:submit/retry 按钮 32→30px 对齐 PRD §4;KPI grid 改 minmax 防窄屏压缩;
  starting 状态从 --accent 改 --ok;删死 i18n key(landing.cell/system.regionLabel)。
- 包边界:observability 补声明 @gocell/contracts;health/system API 加轻量运行时
  形状守卫(缺字段即降级 unavailable);core README 补 UnavailablePanel/useRovingTablist;
  LoadStatus 抽到 lib/loadStatus.ts 单一来源。

校验:pnpm -w lint / typecheck 绿;单测 1752 passed(useTheme 预存并发 flaky,单独
跑通过、本分支未触碰);@gocell/web build 绿;e2e 11/11;contracts git 干净。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ghbvf
ghbvf merged commit 596e8ca into develop Jun 3, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Batch 7] Landing & Observability v1

1 participant