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 fc6d9d5  docs: accuracy pass + concept-first config docs + principles; 
release tooling (#38)
fc6d9d5 is described below

commit fc6d9d5b5233dc424dc878444f4459bd3a31edb0
Author: 吴晟 Wu Sheng <[email protected]>
AuthorDate: Tue Jun 2 10:44:50 2026 +0800

    docs: accuracy pass + concept-first config docs + principles; release 
tooling (#38)
    
    Bring the website docs in line with the current code after the 0.6.0 work,
    restructure the config docs around the UI (JSON as reference), codify the
    doc-writing principles, and make the post-vote finalize script Docker-Hub
    verify-only. CHANGELOG updated under 0.7.0.
    
    Staleness fixes
    - access-control/rbac.md + setup/rbac.md: document the `infra-3d:read` verb.
    - access-control/admin-pages.md: add `/admin/3d-map` (`overview:write`).
    - access-control/audit-log.md: rewrite the recorded-actions table to the
      actually-emitted actions; drop the never-emitted rows; fix the failure
      outcome format (`http_<code>`).
    - operate/inspect.md: correct the BFF routes to `/api/inspect/*`.
    - design-target.md: add the Topology overview widget.
    - customization/layer-templates.md: fix the components example to the real
      flag keys; add the `dependency` dashboard scope.
    - operate/infra-3d-map.md: rewrite Configuration for the redesigned model;
      add the Hierarchy pipeline stage.
    
    Config docs are concept-first
    - infra-3d-map / layer-templates / overview-templates lead with the concept
      and the admin UI; the JSON shape is a reference appendix. No raw-JSON
      editor exists on these pages, so the docs no longer imply one.
    
    Versioning
    - Docs no longer hardcode the Horizon version (the website pins docs per
      release); container-image.md stays as the release-tooling exception.
    
    i18n
    - i18n.md: language x scope coverage matrix.
    - adding-a-new-layer.md: add the "Add translations (i18n)" contributor step.
    
    docs/CLAUDE.md (new)
    - Operator-first, config-UI-first with JSON-as-appendix, no hardcoded
      versions, plus a carve-out for contributor pages.
    
    Release tooling
    - release-finalize.sh: the Docker Hub image is published by CI on `v*` tags;
      Step 5 now verifies the published tags, and the manual local-push fallback
      plus Docker Hub login preflight were removed.
---
 CHANGELOG.md                             | 15 +++++-
 docs/CLAUDE.md                           | 71 +++++++++++++++++++++++++++
 docs/access-control/admin-pages.md       |  1 +
 docs/access-control/audit-log.md         | 24 ++++-----
 docs/access-control/rbac.md              |  3 +-
 docs/customization/adding-a-new-layer.md | 21 +++++++-
 docs/customization/i18n.md               | 17 +++++++
 docs/customization/layer-templates.md    | 25 ++++++----
 docs/customization/overview-templates.md |  8 +--
 docs/design-target.md                    |  1 +
 docs/operate/infra-3d-map.md             | 73 ++++++++++++++++------------
 docs/operate/inspect.md                  |  4 +-
 docs/setup/overview.md                   |  8 +--
 docs/setup/rbac.md                       |  2 +-
 scripts/release-finalize.sh              | 83 +++++++++-----------------------
 15 files changed, 229 insertions(+), 127 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 35509be..921875a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,7 +9,20 @@ packages) plus the BFF's `HORIZON_VERSION` default.
 
 ## 0.7.0
 
-(In development — fill in highlights here before cutting the release.)
+### Documentation & release tooling
+
+- The website docs were brought current with the 0.6.0 build and the
+  configuration pages restructured around the admin UI — the JSON shape is
+  now a reference appendix, not an authoring surface (these admin pages are
+  structured editors, not raw-JSON editors). Accuracy fixes span the RBAC
+  verbs (incl. `infra-3d:read`), the audit-log action set, the Metrics
+  Inspect API paths, the layer-template component flags, and the redesigned
+  3D-map config + loading stages. A new `docs/CLAUDE.md` records the
+  doc-writing principles, and the i18n docs gain a language × scope coverage
+  matrix plus a translation step in the add-a-layer recipe.
+- The container image is published to Docker Hub by CI on every `v*` tag;
+  the post-vote finalize script now only verifies the published tags (the
+  manual local-push fallback and Docker Hub login preflight were removed).
 
 ## 0.6.0
 
diff --git a/docs/CLAUDE.md b/docs/CLAUDE.md
new file mode 100644
index 0000000..bb5c5a6
--- /dev/null
+++ b/docs/CLAUDE.md
@@ -0,0 +1,71 @@
+# CLAUDE.md — Writing the Horizon UI docs
+
+`docs/` is the **public website documentation** for Horizon UI — a flat tree,
+ordered by `menu.yml`, synced to the Apache SkyWalking website. It is written
+for the people who **run and configure** Horizon (operators, dashboard
+authors), not for contributors hacking on the code. These are the principles
+for every page here. For the project-wide rules, see the root
+[CLAUDE.md](../CLAUDE.md).
+
+## 1. Operator perspective first
+
+Document what a feature **does**, how to **configure** it, and how to
+**operate / troubleshoot** it — observable behavior and configuration.
+
+Do **not** document the internals:
+
+- no source-file paths (`apps/bff/src/…`, `apps/ui/src/…`),
+- no internal function / composable / store / route-handler names,
+- no implementation narration ("the BFF then chunks / fans out / probes …"),
+- no step-by-step retelling of the code's algorithm.
+
+If a sentence only makes sense to someone reading the source, it does not
+belong in a doc.
+
+**One carve-out: contributor pages.** A few pages document repo / file-based
+authoring that has no UI path — adding a new layer template, contributing a
+translation catalog or a new locale. These are explicitly contributor-facing
+and may reference repo files, `pnpm` commands, and the dev workflow; keep them
+scoped to that task. Today: `customization/adding-a-new-layer.md` and the
+contributor sections of `customization/i18n.md`. Everything else stays
+operator-facing.
+
+## 2. Config is edited in the UI — lead with that; JSON is an appendix
+
+Almost everything configurable in Horizon (layer dashboards, overview
+templates, the 3D-map config, alarm-page setup, global defaults, translations)
+is edited through a **structured / visual admin page**, on a bundled default →
+local draft → **Check diff & push** to OAP flow. A configuration page should:
+
+- **Start from the concept** — what this configuration is and what it controls.
+- **Then the UI** — which admin page edits it and what the controls do.
+- **Keep the JSON / schema as a reference appendix** at the end, framed as the
+  *stored* format the editor reads and writes (useful for understanding the
+  fields, or authoring as files), **not** as the primary "how to author" path.
+
+There is **no raw-JSON editor on these pages.** Never tell the reader to "edit
+the JSON" on a page — they use the structured controls. The Monaco view that
+appears is a read-only **diff** for review before pushing.
+
+## 3. Don't hardcode the Horizon version
+
+The website serves these docs **pinned per release**, so a version string in
+the body is redundant and silently goes stale on the next release. By default,
+write version-neutral: use a `<version>` placeholder in install commands, or
+phrase around it. State a concrete version only when the content is genuinely
+version-specific (a compatibility note, or a "new in X" call-out you
+deliberately want pinned).
+
+The **one maintained exception** is `setup/container-image.md`: its image tags
+track the current release and are advanced automatically by the release tooling
+— leave them as concrete versions.
+
+## 4. Other house rules
+
+- **Tech terms and proper nouns stay verbatim** — SkyWalking, OAP, MQE, eBPF,
+  Kubernetes, Istio, GraphQL, layer keys (`GENERAL`, `MESH`), scope enums
+  (Service, Endpoint), metric ids. Don't translate or rename them.
+- **Cross-link, don't duplicate.** One canonical page per concept; link to it
+  rather than restating it.
+- **Add new pages to `menu.yml`.** A page that isn't in the menu isn't
+  navigable on the site.
diff --git a/docs/access-control/admin-pages.md 
b/docs/access-control/admin-pages.md
index 350c131..b8b1b41 100644
--- a/docs/access-control/admin-pages.md
+++ b/docs/access-control/admin-pages.md
@@ -114,6 +114,7 @@ Read-only. To change roles, edit `rbac.roles` in 
`horizon.yaml`; hot-reload appl
 | `/operate/inspect` | `inspect:read` | maintainer, operator, admin |
 | `/operate/ttl` | `ttl:read` | maintainer, operator, admin |
 | `/operate/config` | `config:read` | maintainer, operator, admin |
+| `/admin/3d-map` | `overview:write` | operator, admin |
 
 `auth:read`, `user:read`, `role:read` are **not** in any default role. Either 
grant them via a custom role:
 
diff --git a/docs/access-control/audit-log.md b/docs/access-control/audit-log.md
index 125ab14..57008a2 100644
--- a/docs/access-control/audit-log.md
+++ b/docs/access-control/audit-log.md
@@ -10,10 +10,10 @@ Each event has these fields:
 |---|---|
 | `ts` | ISO-8601 timestamp. |
 | `actor` | Username, or `null` for system events. |
-| `action` | Operation name, such as `auth.login` or `rule.addOrUpdate`. |
+| `action` | Operation name, such as `auth.login` or `addOrUpdate`. |
 | `verb` | RBAC verb checked, when applicable. |
 | `target` | Resource id or name, when applicable. |
-| `outcome` | `success`, `failure`, `break-glass`, or the upstream HTTP/OAP 
status. |
+| `outcome` | `success` / `ok` / `break-glass` for normal flows; the OAP 
`applyStatus` or `http_<code>` on an upstream failure. |
 | `details` | Extra context for the operation. |
 | `fromIp` | Requester IP. |
 | `sessionId` | Session id, when a session exists. |
@@ -26,21 +26,22 @@ tail -f horizon-audit.jsonl | jq -c 'select(.action | 
startswith("auth."))'
 
 ## Recorded actions
 
-The recorded set can grow between releases. In 0.5.0:
+The recorded set can grow between releases. The current set:
 
 | Action | Outcome values | Notes |
 |---|---|---|
 | `auth.login` | `success`, `failure` | Standard login. `details.backend` is 
`local` or `ldap`. On success `details.roles` carries the resolved role list. |
 | `auth.login.break-glass` | `break-glass` | Emergency admin login. Logged in 
addition to a WARN application log line. |
 | `auth.logout` | `success` | Explicit logout (cookie cleared). Sessions that 
simply expire are not logged. |
-| `rule.addOrUpdate` | `success`, HTTP status on failure | DSL Management 
create / update. `target` is the rule name; `details` carries the diff summary. 
|
-| `rule.delete` | `success`, HTTP status on failure | DSL Management delete. |
-| `alarm-rule.addOrUpdate` | `success`, HTTP status on failure | Alarm Rule 
editor write. |
-| `setup.write` | `success`, HTTP status on failure | Per-user setup state 
write. |
-| `overview-template.write` | `success` | Overview template admin edits. |
-| `layer-template.write` | `success` | Layer template admin edits. |
+| `addOrUpdate` | OAP `applyStatus`, or `http_<code>` on failure | DSL 
Management — create / update a rule. `target` is the rule name; 
`details.catalog` is the rule catalog (alarm, MAL, OAL, …). |
+| `inactivate` | OAP `applyStatus`, or `http_<code>` | DSL Management — 
deactivate a rule. |
+| `delete` | OAP `applyStatus`, or `http_<code>` | DSL Management — delete a 
rule. `details.mode` is the delete mode. |
+| `alarms.config.save` | `ok`, or an error status on failure | Alarm page 
setup save. |
+| `setup.save` | `success`, or an error status on failure | Per-user setup 
state write (service / instance / endpoint setup). |
+| `debug.start` | `ok`, or an error status on failure | Live Debugger — start 
a session. |
+| `debug.stop` | `ok`, or an error status on failure | Live Debugger — stop a 
session. |
 
-`outcome` is the literal string for normal flows (`success`, `failure`, 
`break-glass`) and a stringified HTTP / OAP status code when the underlying 
call failed. This makes audit-time error correlation straightforward: an entry 
with `outcome: "503"` tells you OAP returned a server error.
+`outcome` is a short literal for normal flows (`success`, `ok`, or 
`break-glass`) and, when the underlying OAP call fails, the OAP `applyStatus` 
value or `http_<code>`. This makes audit-time error correlation 
straightforward: an entry with `outcome: "http_503"` tells you OAP returned a 
server error.
 
 ## Example entries
 
@@ -93,10 +94,11 @@ The recorded set can grow between releases. In 0.5.0:
 {
   "ts": "2026-05-18T15:02:11.004Z",
   "actor": "alice",
-  "action": "rule.addOrUpdate",
+  "action": "addOrUpdate",
   "verb": "rule:write",
   "target": "service_resp_time_rule",
   "outcome": "success",
+  "details": { "catalog": "alarm" },
   "fromIp": "10.0.5.12",
   "sessionId": "k7r..."
 }
diff --git a/docs/access-control/rbac.md b/docs/access-control/rbac.md
index 00e8963..0727d50 100644
--- a/docs/access-control/rbac.md
+++ b/docs/access-control/rbac.md
@@ -26,12 +26,13 @@ Known verbs are grouped into areas:
 | `topology:read` | Topology tab, topology widgets on overviews. |
 | `profile:read` | Profiling tab (results read-only). |
 | `overview:read` | Public overview dashboards. |
+| `infra-3d:read` | 3D Infrastructure Map — the map's config + live traffic 
metrics. |
 
 ### Operate — dashboards, rules, diagnostics
 
 | Verb | Gates |
 |---|---|
-| `overview:write` | Overview templates admin page 
(`/admin/overview-templates`): edit. |
+| `overview:write` | Overview templates (`/admin/overview-templates`) and the 
3D-map config (`/admin/3d-map`): edit / publish. |
 | `dashboard:read` / `dashboard:write` | Layer dashboard templates admin page: 
list / edit. |
 | `alarm-setup:read` / `alarm-setup:write` | Alarm Setup page: list / edit. |
 | `alarm-rule:read` / `alarm-rule:write` | Alarm Rule catalog: list / edit. |
diff --git a/docs/customization/adding-a-new-layer.md 
b/docs/customization/adding-a-new-layer.md
index f600edc..2a06cd0 100644
--- a/docs/customization/adding-a-new-layer.md
+++ b/docs/customization/adding-a-new-layer.md
@@ -90,7 +90,23 @@ Bundled template changes need a BFF restart (templates are 
loaded once at startu
 
 Each iteration is template + BFF restart. The schema is validated at startup; 
a bad template logs the error and falls back to defaults — check the BFF logs.
 
-### 9. Promote to admin-editable (optional)
+### 9. Add translations (i18n)
+
+The template's English strings — the layer `alias`, any `aliases.*`, `slots`, 
and the widget titles / KPI labels / group titles / tooltips inside 
`dashboards` — are the i18n source. Generate the sibling overlay catalogs so 
the layer renders in every shipped language:
+
+```sh
+pnpm --filter @skywalking-horizon-ui/bff i18n:seed
+```
+
+This walks every bundled template and writes one 
`<your-key>.i18n.<locale>.json` per non-English locale (`de`, `es`, `fr`, `ja`, 
`ko`, `pt`, `zh-CN`), pre-filling shared widget vocabulary from the lexicon. 
Existing translations are preserved — only gaps are added. Fill the 
layer-specific prose you care about in each overlay (anything left blank falls 
back to English at render), then check for drift:
+
+```sh
+pnpm --filter @skywalking-horizon-ui/bff i18n:validate
+```
+
+See [Languages and Translations](i18n.md) for the language × scope coverage, 
the shared lexicon, and how to add a brand-new locale.
+
+### 10. Promote to admin-editable (optional)
 
 Once the template stabilizes:
 
@@ -99,7 +115,7 @@ Once the template stabilizes:
 
 The local bundled file remains the fallback. After you publish, the OAP-stored 
template becomes the runtime copy every Horizon instance reads.
 
-### 10. Add an overview entry (optional)
+### 11. Add an overview entry (optional)
 
 If the new layer belongs in a war-room view:
 
@@ -141,4 +157,5 @@ OAP-side rename means a new enum key. Horizon will see the 
old key go inactive (
 - [Layer Dashboard Templates](layer-templates.md) — field reference.
 - [Menu Structure](menu-structure.md) — how the sidebar composes layers.
 - [Overview Templates](overview-templates.md) — cross-layer dashboards.
+- [Languages and Translations](i18n.md) — translating the template's strings.
 - [Components → Dashboard Widgets](../components/dashboard-widgets.md) — 
widget primitive reference.
diff --git a/docs/customization/i18n.md b/docs/customization/i18n.md
index 520b4cc..0d728a4 100644
--- a/docs/customization/i18n.md
+++ b/docs/customization/i18n.md
@@ -21,6 +21,20 @@ in English first; the other locales are catalog overlays. 
Missing keys
 fall back to English at the leaf, never at the file — a half-translated
 catalog renders strictly better than English-only.
 
+## Coverage by scope
+
+All eight languages are first-class across the surfaces Horizon controls. The 
scope decides **where** the translation resolves:
+
+| Scope | Resolves | Languages |
+|---|---|---|
+| UI chrome — buttons, labels, modals, login, topbar, sidebar | In the browser 
(vue-i18n) | All 8 |
+| Bundled layer-dashboard templates | On the BFF, from sibling overlay 
catalogs | All 8 |
+| Bundled overview templates | On the BFF | All 8 |
+| User-maintained dashboards saved to OAP | On the BFF, from each dashboard's 
embedded `i18n` block | English + whatever the author provides |
+| OAP-supplied data — service / instance / endpoint / alarm names, tags, log 
lines, trace ops | not translated | rendered verbatim |
+
+A missing key in any translated scope falls back to English at the leaf, so a 
partially-translated catalog renders better than English-only.
+
 ## Picking a language
 
 The locale picker lives in the topbar (next to the theme chip) and on
@@ -124,3 +138,6 @@ pnpm --filter @skywalking-horizon-ui/bff i18n:validate
 It rejects catalog keys that no longer match the source template,
 non-string values at translatable paths, and lexicon entries that
 aren't present in the source `en.json` lexicon registry.
+
+When you add a **new layer**, generating its template's translations is part
+of that workflow — see [Adding a New Layer](adding-a-new-layer.md).
diff --git a/docs/customization/layer-templates.md 
b/docs/customization/layer-templates.md
index eb00a03..d35adb3 100644
--- a/docs/customization/layer-templates.md
+++ b/docs/customization/layer-templates.md
@@ -2,9 +2,9 @@
 
 A **layer template** is a single JSON file that describes everything Horizon 
needs to know about one OAP layer: its display name, color, sidebar grouping, 
which sub-tabs to expose, the service-list picker columns, the per-scope widget 
grids, the trace/log/topology routing, and the service-name parsing rule.
 
-There is **one template per layer**, stored under 
`apps/bff/src/bundled_templates/layers/<key>.json` (lowercase filename matches 
the OAP layer enum, e.g. `general.json` for the `GENERAL` layer).
+There is **one template per layer**. Horizon ships a bundled template for 
every supported layer, and an administrator customizes them in the **Layer 
Dashboards** admin page (under *Dashboard setup*) — a visual editor that saves 
a local draft and publishes to OAP with **Check diff & push**. You don't 
hand-edit JSON on the page; the shape documented below is the stored format the 
editor reads and writes, useful for understanding what each control maps to and 
for authoring templates as files.
 
-## Top-level shape
+## Template shape (reference)
 
 ```json
 {
@@ -22,6 +22,7 @@ There is **one template per layer**, stored under 
`apps/bff/src/bundled_template
     "service":   [ ... widgets ... ],
     "instance":  [ ... widgets ... ],
     "endpoint":  [ ... widgets ... ],
+    "dependency":[ ... widgets ... ],
     "topology":  [ ... widgets ... ],
     "trace":     [ ... widgets ... ],
     "logs":      [ ... widgets ... ],
@@ -83,17 +84,21 @@ Per-tab feature toggles. A `false` value hides the tab.
 
 ```json
 "components": {
-  "service":   true,
-  "instance":  true,
-  "endpoint":  true,
-  "topology":  true,
-  "trace":     true,
-  "logs":      false,
-  "profiling": true
+  "service":            true,
+  "instances":          true,
+  "endpoints":          true,
+  "endpointDependency": true,
+  "topology":           true,
+  "traces":             true,
+  "logs":               true,
+  "traceProfiling":     true,
+  "ebpfProfiling":      false,
+  "asyncProfiling":     false,
+  "pprofProfiling":     false
 }
 ```
 
-The landing tab when a layer is clicked is the **first enabled** in the 
priority order `service → instance → endpoint → topology → trace → logs → 
profiling`.
+The keys are the per-layer sub-tabs. `networkProfiling` and `podLogs` are also 
available; any key omitted defaults to enabled. The landing tab when a layer is 
clicked is the **first enabled** in the priority order `service → instances → 
endpoints → endpointDependency → topology → traces → logs → traceProfiling`.
 
 ## `header`
 
diff --git a/docs/customization/overview-templates.md 
b/docs/customization/overview-templates.md
index 24a1cce..6e8be11 100644
--- a/docs/customization/overview-templates.md
+++ b/docs/customization/overview-templates.md
@@ -2,12 +2,12 @@
 
 An **overview template** is a JSON file describing a war-room / cross-cutting 
dashboard composed from MQE-driven widgets on a 12-column grid. Overviews are 
independent of any single layer and are designed for the operator's "is 
everything OK?" pane.
 
-Bundled templates: `apps/bff/src/bundled_templates/overviews/<id>.json`. 
Examples:
+Horizon ships bundled overview templates, and an administrator customizes them 
in the **Overview Templates** admin page (`/admin/overview-templates`, under 
*Dashboard setup*) — a visual editor that saves a local draft and publishes to 
OAP with **Check diff & push**. You don't hand-edit JSON on the page; the shape 
documented below is the stored format the editor reads and writes. Bundled 
examples:
 
-- `services.json` — cross-layer service health + Kubernetes capacity summary.
-- `mesh.json` — Istio data-plane services + pilot activity + Kubernetes.
+- **Service Health** — cross-layer service health + Kubernetes capacity 
summary.
+- **Mesh** — Istio data-plane services + pilot activity + Kubernetes.
 
-## Top-level shape
+## Template shape (reference)
 
 ```json
 {
diff --git a/docs/design-target.md b/docs/design-target.md
index 49fbf83..e9fed63 100644
--- a/docs/design-target.md
+++ b/docs/design-target.md
@@ -23,6 +23,7 @@ Horizon ships dedicated widget primitives for observability 
stacks instead of ge
 - **KpiTileWidget** — compound tile combining a service count with N KPI rows 
(number or progress-bar style).
 - **MetricCompositeWidget** — mixed-style KPI grid (e.g., Kubernetes cluster 
summary: node count + CPU/memory progress bars).
 - **AlarmsWidget** — read-only active-incident rail with a 60-minute window, 
dual-mode (modern `queryAlarms` capability + legacy `getAlarm` fallback).
+- **Topology** — embedded service-map snapshot for the configured layer, 
showing live services and call flows on an overview.
 - **TimeChart** — multi-series line chart with dual y-axis, synced crosshairs 
across all widgets on the same page.
 - **TopList** — top-N sorted list with optional tab switcher for multiple 
expressions.
 - **AlarmsTimeline** — per-minute stacked bar with brush selection for triage.
diff --git a/docs/operate/infra-3d-map.md b/docs/operate/infra-3d-map.md
index cbac6aa..95f21d7 100644
--- a/docs/operate/infra-3d-map.md
+++ b/docs/operate/infra-3d-map.md
@@ -128,8 +128,12 @@ progress live:
 1. **Services** — the service roster and which layers they belong to.
 2. **Templates** — which layers carry a topology.
 3. **Topologies** — each topology-bearing layer's call graph.
-4. **Layout** — placing the cubes.
-5. **Metrics** — the per-service traffic numbers, fetched in batches so
+4. **Hierarchy** — the cross-tier identity links between the different
+   views of the same service. Only services that are new since the last
+   run are fetched; the rest are reused, so a steady deployment costs
+   nothing here on refresh.
+5. **Layout** — placing the cubes.
+6. **Metrics** — the per-service traffic numbers, fetched in batches so
    the cubes light up progressively.
 
 Each step shows its status as the map builds; click a step to open a
@@ -139,33 +143,42 @@ strip re-runs the whole sequence.
 
 ## Configuration
 
-The map is driven by a global configuration that an administrator edits
-at `/admin/3d-map` (linked under **Dashboard setup** in the sidebar).
-The editor is the same dark, dense surface as the rest of Horizon's
-admin pages, with a structured form plus an advanced raw-JSON view.
-
-From it you can:
-
-- **Filter layers** — a global filter, plus a per-tier filter, to choose
-  which layers appear on the map.
-- **Arrange tiers** — rename tiers, reorder them top-to-bottom, and
-  assign each layer to a tier.
+What the map shows is driven by a single configuration that an
+administrator edits in the UI at `/admin/3d-map` (linked under
+**Dashboard setup** in the sidebar). It is a **structured editor** — you
+work with tiers, layers, colors, and metrics through form controls, not
+raw JSON. Horizon ships a bundled default so the map is useful out of the
+box; your edits are kept as a local draft in your browser, and **Check
+diff & push** publishes them to OAP — which is the copy the map then
+renders (falling back to the bundled default if OAP has none).
+
+From the editor you can:
+
+- **Filter layers** — one global layer filter, written as a regex. A
+  layer it excludes is dropped from the map entirely. This is the only
+  filter; everything it admits is then placed on a tier.
+- **Arrange tiers** — rename tiers, reorder them top-to-bottom, and pin
+  each layer to a tier. A layer you don't pin lands on the **failover
+  tier** you nominate, so nothing silently falls off the map.
+- **Group layers** — cluster several related layers (for example the
+  SkyWalking self-observability components) into one labelled block on a
+  tier, while each member keeps its own cube color.
 - **Color layers** — pick each layer's brand color (used for the cube,
   zone, and stamp).
-- **Choose traffic metrics** — pick the throughput metric and unit each
-  layer's cubes display. Topology layers can carry both a server-side and
-  client-side metric (the server side is preferred, with the client side
-  as a fallback); other layers carry a single load metric. The bundled
-  defaults are seeded from each layer's dashboard template, so most
-  layers show a sensible number out of the box.
-- **Style connections** — adjust the color and weight of the in-layer,
-  cross-layer, and hierarchy lines.
-
-Saving takes effect the next time the map is opened. A **Reset to
-bundled** action restores the shipped defaults for review before saving.
-
-The bundled configuration is the read-only baseline; saved changes
-shadow it. Both the map and the editor are gated by access control — any
-signed-in user with read access can view the map, while editing the
-configuration requires the 3D-map write permission (granted to operators
-and admins by default). See [Roles and Permissions](../access-control/rbac.md).
+- **Choose a traffic metric** — for each layer, set the single throughput
+  metric its cubes display: the MQE expression, a display label, and a
+  unit. The bundled defaults are seeded from each layer's dashboard
+  template, so most layers show a sensible number out of the box.
+
+A read-only **Service-map layers** list shows which layers lay their
+cubes out as a call graph — that comes from each layer's template (its
+service-map capability), not from this page.
+
+Pushed changes take effect the next time the map is opened. A **Reset**
+action reloads either the shipped bundled default or OAP's current
+version, so you can start over before saving.
+
+Viewing the map needs read access (`infra-3d:read`, held by the built-in
+viewer role and above); editing and publishing the configuration needs
+`overview:write` (operators and admins by default). See
+[Roles and Permissions](../access-control/rbac.md).
diff --git a/docs/operate/inspect.md b/docs/operate/inspect.md
index 5c9dd4d..6f374c7 100644
--- a/docs/operate/inspect.md
+++ b/docs/operate/inspect.md
@@ -24,7 +24,7 @@ If any of these is missing, the page surfaces a hint banner 
directing the operat
 
 ## Catalog browser
 
-**Endpoint:** `GET 
/inspect/metrics?regex=<pattern>&type=<type>&catalog=<catalog>&mqeQueryable=<bool>`
+**Endpoint:** `GET 
/api/inspect/metrics?regex=<pattern>&type=<type>&catalog=<catalog>&mqeQueryable=<bool>`
 
 Filters:
 
@@ -48,7 +48,7 @@ The list is virtualized — a typical OAP exposes hundreds of 
metrics; scrolling
 
 ## Entity enumerator
 
-**Endpoint:** `GET 
/inspect/entities?metric=<name>&start=<...>&end=<...>&step=<DAY|HOUR|MINUTE>&limit=<n>`
+**Endpoint:** `GET 
/api/inspect/entities?metric=<name>&start=<...>&end=<...>&step=<DAY|HOUR|MINUTE>&limit=<n>`
 
 For a chosen metric, OAP returns the set of entities that have data in the 
window. Useful for:
 
diff --git a/docs/setup/overview.md b/docs/setup/overview.md
index 9abdae4..614de02 100644
--- a/docs/setup/overview.md
+++ b/docs/setup/overview.md
@@ -12,11 +12,11 @@ This page is the shortest path from "no Horizon" to 
"Horizon in front of a runni
 
 ### 1. Unpack Horizon
 
-Unpack the binary tarball and copy the example config:
+Unpack the binary tarball (substitute the release version you downloaded for 
`<version>`) and copy the example config:
 
 ```sh
-tar -xzf apache-skywalking-horizon-ui-0.5.0-bin.tar.gz
-cd apache-skywalking-horizon-ui-0.5.0-bin
+tar -xzf apache-skywalking-horizon-ui-<version>-bin.tar.gz
+cd apache-skywalking-horizon-ui-<version>-bin
 cp horizon.example.yaml horizon.yaml
 ```
 
@@ -100,7 +100,7 @@ docker run -d --name horizon \
   -p 8081:8081 \
   -v "$PWD/horizon.yaml:/app/horizon.yaml:ro" \
   -v horizon-state:/data \
-  ghcr.io/apache/skywalking-horizon-ui:0.5.0
+  ghcr.io/apache/skywalking-horizon-ui:<version>
 ```
 
 See [Container Image](container-image.md) for image tags, Kubernetes YAML, log 
handling, and probes.
diff --git a/docs/setup/rbac.md b/docs/setup/rbac.md
index 963e83b..5120ad0 100644
--- a/docs/setup/rbac.md
+++ b/docs/setup/rbac.md
@@ -31,7 +31,7 @@ rbac:
 
 | Role | Purpose | Grants |
 |---|---|---|
-| `viewer` | Read-only data catalog and public overviews. | `metrics:read`, 
`alarms:read`, `traces:read`, `logs:read`, `topology:read`, `profile:read`, 
`overview:read`. Deliberately not `*:read` so the viewer cannot see rule 
definitions, live-debug sessions, setup screens, or platform internals. |
+| `viewer` | Read-only data catalog and public overviews. | `metrics:read`, 
`alarms:read`, `traces:read`, `logs:read`, `topology:read`, `profile:read`, 
`overview:read`, `infra-3d:read`. Deliberately not `*:read` so the viewer 
cannot see rule definitions, live-debug sessions, setup screens, or platform 
internals. |
 | `maintainer` | Viewer + platform monitoring. | viewer baseline + 
`cluster:read`, `ttl:read`, `config:read`, `inspect:read`. |
 | `operator` | Configures observability. | maintainer baseline + 
`overview:write`, `setup:read/write`, `dashboard:read/write`, 
`alarm-setup:read/write`, `alarm-rule:read/write`, `rule:*` (including 
`rule:write:structural`, `rule:delete`, `rule:debug`), `live-debug:*`, 
`profile:enable`. |
 | `admin` | Unrestricted. | `*`. |
diff --git a/scripts/release-finalize.sh b/scripts/release-finalize.sh
index c160c00..e901818 100755
--- a/scripts/release-finalize.sh
+++ b/scripts/release-finalize.sh
@@ -39,16 +39,16 @@
 #   3. Verify the Docker Hub multi-arch image — CI's publish-image
 #      workflow mirrors the GHCR image to Docker Hub automatically on
 #      every `v*` tag push (apache/skywalking-ui:horizon-<v> and
-#      apache/skywalking-ui:latest). This step just confirms the two
-#      expected tags are present. Falls back to a manual local mirror
-#      (same `docker buildx imagetools create` CI runs) if CI didn't
-#      publish — needs Docker Hub push rights on apache/skywalking-ui.
+#      apache/skywalking-ui:latest). This step only CONFIRMS the two
+#      expected tags are present; publishing is CI's job. There is no
+#      local-push fallback — if the tags are missing, re-run the
+#      publish-image workflow and re-run this script.
 #
 # Usage:  bash scripts/release-finalize.sh
 #
 # The script is idempotent-ish and confirms before every irreversible step
-# (SVN move, SVN delete, gh release, each image push). Nothing destructive
-# happens without a y/N.
+# (SVN move, SVN delete, gh release). Nothing destructive happens without
+# a y/N. The Docker Hub image is published by CI, not here.
 
 set -e -o pipefail
 
@@ -80,7 +80,7 @@ svn_exists() {
 note "Step 1 — Tool + auth preflight"
 
 MISSING=()
-for t in svn gh git docker shasum curl node; do
+for t in svn gh git docker shasum curl; do
     command -v "$t" >/dev/null || MISSING+=("$t")
 done
 if [ ${#MISSING[@]} -gt 0 ]; then
@@ -89,8 +89,8 @@ if [ ${#MISSING[@]} -gt 0 ]; then
 fi
 
 if ! docker buildx version >/dev/null 2>&1; then
-    err "docker buildx is required (Step 5 uses 'imagetools create' to copy"
-    err "the CI-built multi-arch manifest from GHCR to Docker Hub)."
+    err "docker buildx is required (Step 5 uses 'imagetools inspect' to"
+    err "verify the CI-published Docker Hub tags)."
     exit 1
 fi
 
@@ -101,21 +101,6 @@ if ! gh auth status >/dev/null 2>&1; then
 fi
 echo "gh: $(gh auth status 2>&1 | grep -m1 'Logged in' | sed 
's/^[[:space:]]*//')"
 
-# Docker Hub: confirm a stored login. The push itself will 403 if the
-# logged-in account lacks push rights to the apache org — surface the
-# identity now so a wrong account is caught before the long build.
-DOCKER_USER=$(printf 'https://index.docker.io/v1/' | docker-credential-desktop 
get 2>/dev/null \
-    | node -e "let 
s='';process.stdin.on('data',d=>s+=d);process.stdin.on('end',()=>{try{process.stdout.write(JSON.parse(s).Username||'')}catch(e){}})"
 2>/dev/null || true)
-if [ -z "${DOCKER_USER}" ]; then
-    echo "Could not read a Docker Hub login from the credential store."
-    echo "If you are not logged in, run:  docker login"
-    confirm "Continue anyway (the push will fail if not authorized)?" || { 
echo "Aborted."; exit 1; }
-else
-    echo "Docker Hub login: ${DOCKER_USER}"
-    echo "  NOTE: pushing to ${DOCKERHUB_REPO} needs this account to have push 
rights"
-    echo "        in the 'apache' Docker Hub org. The push 403s otherwise."
-fi
-
 # ========================== Step 2: Detect version ==========================
 note "Step 2 — Detect release version"
 
@@ -263,55 +248,31 @@ else
     fi
 fi
 
-# ========================== Step 5: Docker Hub multi-arch image 
==========================
-note "Step 5 — Docker Hub image: ${DOCKERHUB_REPO}"
+# ========================== Step 5: Verify Docker Hub image 
==========================
+note "Step 5 — Verify Docker Hub image: ${DOCKERHUB_REPO}"
 
 # CI (.github/workflows/publish-image.yaml) mirrors the multi-arch image
 # to Docker Hub automatically on every `v*` tag push, so by the time
-# you're finalizing a passed vote this should already be live. We just
-# verify the two expected tags are present.
-#
-# Fallback: if CI didn't publish (workflow failed / secrets missing /
-# tag pushed before this workflow shipped), we fall back to the manual
-# `docker buildx imagetools create` mirror from the GHCR canonical tag
-# — same operation CI does, run locally. That needs Docker Hub push
-# rights on `apache/skywalking-ui`.
+# you're finalizing a passed vote it is already live. This step only
+# VERIFIES the expected tags are present — publishing is CI's job, there
+# is no local-push fallback.
 DH_VERSION_TAG="${DOCKERHUB_REPO}:horizon-${RELEASE_VERSION}"
 DH_LATEST_TAG="${DOCKERHUB_REPO}:latest"
-GHCR_SRC="ghcr.io/apache/skywalking-horizon-ui:${RELEASE_VERSION}"
 
 echo "Expected on Docker Hub:"
 echo "  ${DH_VERSION_TAG}   (immutable, this release)"
 echo "  ${DH_LATEST_TAG}                      (moving — newest Horizon 
release)"
 
 if docker buildx imagetools inspect "${DH_VERSION_TAG}" >/dev/null 2>&1; then
-    echo "✓ ${DH_VERSION_TAG} already on Docker Hub — CI's publish-image 
mirror succeeded."
-    echo "  Verify:  docker buildx imagetools inspect ${DH_VERSION_TAG}"
+    echo "✓ ${DH_VERSION_TAG} is on Docker Hub — CI's publish-image mirror 
succeeded."
+    echo "  Inspect:  docker buildx imagetools inspect ${DH_VERSION_TAG}"
 else
-    echo "✗ ${DH_VERSION_TAG} NOT on Docker Hub yet."
-    echo "  This is the expected outcome only if the publish-image workflow"
-    echo "  failed or didn't run on tag ${TAG}. Check:"
-    echo "    
https://github.com/apache/skywalking-horizon-ui/actions/workflows/publish-image.yaml";
-    if ! docker buildx imagetools inspect "${GHCR_SRC}" >/dev/null 2>&1; then
-        err "Source ${GHCR_SRC} not on GHCR either — CI didn't produce a 
multi-arch"
-        err "image to mirror. Re-run publish-image on ${TAG} from the Actions 
UI"
-        err "and then re-run this script."
-        exit 1
-    fi
-    if confirm "Fall back to a manual local mirror from ${GHCR_SRC}?"; then
-        docker buildx imagetools create \
-            -t "${DH_VERSION_TAG}" \
-            -t "${DH_LATEST_TAG}" \
-            "${GHCR_SRC}"
-        echo "Pushed multi-arch manifest to ${DOCKERHUB_REPO}."
-    else
-        echo "Skipped Docker Hub push — fix CI and re-run, OR run the 
imagetools"
-        echo "create manually:"
-        echo "  docker buildx imagetools create \\"
-        echo "    -t ${DH_VERSION_TAG} \\"
-        echo "    -t ${DH_LATEST_TAG} \\"
-        echo "    ${GHCR_SRC}"
-    fi
+    err "✗ ${DH_VERSION_TAG} is NOT on Docker Hub."
+    err "  CI's publish-image workflow did not mirror tag ${TAG}. The SVN 
promote +"
+    err "  GitHub release above already succeeded; only the image is missing. 
Re-run"
+    err "  the workflow (workflow_dispatch with tag ${TAG}), then re-run this 
script:"
+    err "    
https://github.com/apache/skywalking-horizon-ui/actions/workflows/publish-image.yaml";
+    exit 1
 fi
 
 # ========================== Done ==========================


Reply via email to