This is an automated email from the ASF dual-hosted git repository.

wu-sheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-horizon-ui.git


The following commit(s) were added to refs/heads/main by this push:
     new 7fb2851  docs: add BFF + UI layering principles to CLAUDE.md
7fb2851 is described below

commit 7fb285171108915fb8306333064e4a4315d18e55
Author: Wu Sheng <[email protected]>
AuthorDate: Sat May 16 23:07:40 2026 +0800

    docs: add BFF + UI layering principles to CLAUDE.md
    
    Codifies the structure the bff/ and ui/ refactors just landed:
    
      BFF: http -> logic -> client -> OAP. http/ holds Fastify handlers
           only (sub-folders for query / config / admin); logic/ owns
           orchestration + timers; client/ is the only place that talks
           to OAP; util/ is pure helpers; user/ + rbac/ enforce auth at
           the edge.
    
      UI:  shell / cross-cutting state / api facade / composables /
           static feature pages / configurable render / primitives.
           Pages subscribe to global state, never own it. bff.<scope>.X()
           is the only path to the BFF. Templates drive configurable
           dashboards, not hand-rolled Vue layouts.
---
 CLAUDE.md | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/CLAUDE.md b/CLAUDE.md
index ccfc2c4..183fdbf 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -67,6 +67,21 @@ Design tokens have been lifted into the runtime token CSS — 
that copy is canon
 - **MQE is a core capability**, not a config-screen afterthought. 
User-editable, syntax-highlighted, debuggable.
 - **Admin views use the same look.** LDAP/RBAC/admin are dark, dense, 
design-tokens — not a separate "settings" UI. Alarms are read-only on the UI 
side; recovery is backend-automatic (no acknowledge/close/silence actions).
 - **Comments earn their keep.** Only write a comment when it does one of two 
things: (1) introduces an API — what a module / component / exported function 
is for and how callers should think about it; (2) highlights a non-obvious 
gotcha — a hidden invariant, a workaround for a specific upstream quirk, a 
subtle scope/timing constraint. Do **not** write comments that paraphrase the 
code (`// loop over layers`, `// click handler — toggles open state`, `// 
returns true when active`). Do **no [...]
+- **Layering — BFF.** `apps/bff/src/` is grouped by role, and the flow is 
one-directional: `http → logic → client → OAP`.
+  - `http/{query,config,admin}/` — Fastify route handlers only. Thin: parse, 
dispatch to logic, shape the reply. No OAP I/O directly.
+  - `logic/<domain>/` — domain orchestration + background timers (alarms 
store, layer/overview/setup loaders, preflight status check, inspect parsers, 
dashboard defaults). No HTTP framework, no OAP fetch detail.
+  - `client/` — the only place that talks to OAP (GraphQL + admin REST + 
Zipkin + cluster fan-out). Wrap upstream errors into typed envelopes here.
+  - `util/` — pure helpers used anywhere (time formatting, MQE target/catalog 
cache, trace-protocol cache).
+  - `user/` + `rbac/` — session/auth + verb policy, enforced at the http edge.
+  Don't import `client/` from `http/` directly; route through `logic/` so the 
orchestration layer stays the seam.
+- **Layering — UI.** `apps/ui/src/` follows the same role-based grouping. When 
adding code, decide which layer it belongs in *before* picking a file name. A 
file mixing two layers means it should be split.
+  - **Shell / framework** — `components/shell/`, `router/`, `App.vue`. Chrome 
that every page lives inside (sidebar, topbar, breadcrumbs, layer-tab strip). 
Knows about layers and routes, never about specific feature data.
+  - **Cross-cutting state** — `stores/timeRange.ts`, the auto-refresh ticker, 
`stores/auth.ts`, `composables/useClientId.ts`. Lives above pages; pages 
subscribe, never own.
+  - **API client** — `apps/ui/src/api/`. Façade `bff.<scope>.<method>()` is 
the only path to the BFF; no `fetch()` calls anywhere else.
+  - **Composables** — `composables/`. Reactive data fetchers + business state 
(one composable per query family); pages compose them rather than inlining 
`useQuery` inside a view.
+  - **Static feature pages** — `views/operate/{inspect,dsl,live-debug}/`, 
`views/alarms/`, `views/auth/`, `views/setup/`. Bespoke layouts (not 
template-driven). Own their page-local components but reuse primitives + charts.
+  - **Configurable render** — `views/overview/`, `views/layer/Layer*View.vue` 
widget grids. Layout + widget set come from JSON templates served by the BFF; 
the page is a generic renderer driven by config. New dashboards mean new 
templates, not new Vue files.
+  - **Primitives + shared visuals** — `components/primitives/`, 
`components/charts/`, `components/icons/`. Stateless, no business logic. If a 
primitive needs feature data, it's in the wrong layer.
 
 ## Commits & PRs
 

Reply via email to