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

github-actions[bot] pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/dubbo-kubernetes.git


The following commit(s) were added to refs/heads/master by this push:
     new 7d5675a1 Remove redundant design logic (#979)
7d5675a1 is described below

commit 7d5675a141516bc8f96f3f2c49ab309ad140ca0a
Author: mfordjody <[email protected]>
AuthorDate: Fri Jul 24 11:16:16 2026 +0800

    Remove redundant design logic (#979)
---
 dubbod/gui/DESIGN.md                               |  31 +-
 dubbod/gui/resources/data/app.js                   |  42 +--
 dubbod/gui/resources/data/styles.css               |  79 -----
 dubbod/gui/resources/data/topology.js              | 364 ---------------------
 .../charts/addons/grafana/files/manifests.yaml     | 301 -----------------
 .../charts/addons/prometheus/files/manifests.yaml  |  63 ----
 samples/addons/grafana.yaml                        | 301 -----------------
 samples/addons/prometheus.yaml                     |  63 ----
 8 files changed, 11 insertions(+), 1233 deletions(-)

diff --git a/dubbod/gui/DESIGN.md b/dubbod/gui/DESIGN.md
index 30ced4cd..4bab84d3 100644
--- a/dubbod/gui/DESIGN.md
+++ b/dubbod/gui/DESIGN.md
@@ -20,7 +20,6 @@ Log fetches are on demand with `tail` capped at 2000 by the 
backend.
 
 ```
 OBSERVE   Overview        real  api/overview
-          Topology        real  derived from api/overview (config-plane graph)
           Metrics         real  api/metrics (control-plane Prometheus registry)
           Logs            real  api/logs
 MESH      Services        real  overview.services
@@ -29,7 +28,6 @@ MESH      Services        real  overview.services
           Config          real  overview.configKinds (counts only)
 PLANNED   Traffic         gated — no request-level telemetry feed exists
           Events          gated — no Kubernetes events feed exists
-          Alerts          gated — no alerting rule engine exists
 SYSTEM    Runtime         real  overview.server / mesh / version / instance
 ```
 
@@ -49,20 +47,6 @@ renders a capability gate stating exactly which backend feed 
is missing (see §6
 | Registry table | `registries[].{provider,cluster,synced}` |
 | Header cluster / ns / updated | `clusterId`, `namespace`, `updatedAt` |
 
-### Topology page (config-plane graph — honest by construction)
-Nodes and edges are all derivable facts; nothing is invented:
-| Graph element | Source |
-|---|---|
-| Registry nodes | `registries[]` (status = `synced`) |
-| Control-plane node | `instances[]` ready ratio, `counts.xdsConnections`, 
`version` |
-| Gateway nodes | `gatewayInstances[]` ready ratio |
-| Namespace groups + service nodes | `services[]` grouped by `namespace`; 
per-node `registry`, `exposure`, `ports`, `meshExternal` |
-| registry → dubbod edge | sync relationship, styled by `synced` |
-| dubbod → namespace edge | xDS distribution (service count per namespace) |
-| dubbod → gateway edge | provisioning relationship (`managed-by=dubbod`), 
styled by `isReady` |
-| Edge RPS / error rate / latency | **missing capability** — labeled 
"telemetry not connected", never faked |
-| gateway → service routing edges | **missing capability** — needs HTTPRoute 
parentRef/backendRef detail API |
-
 ### Metrics page (all series from `api/metrics`)
 | UI element | Metric family |
 |---|---|
@@ -86,10 +70,10 @@ from `PodLogOptions.Timestamps: true`).
 ## 4. Drill-down model
 
 Global → module → entity drawer. One right-hand drawer component serves every
-entity type (service, gateway, registry, control plane, config kind, topology
-node) so drill-down behaves identically everywhere. Drawer actions only expose
-operations the backend can execute today: fetch logs (dubbod/gateway), open
-metrics, locate in topology, copy hostname/address.
+entity type (service, gateway, registry, control plane, config kind) so
+drill-down behaves identically everywhere. Drawer actions only expose 
operations
+the backend can execute today: fetch logs (dubbod/gateway), open metrics, copy
+hostname/address.
 
 ## 5. Mock mode
 
@@ -103,9 +87,8 @@ marks mock mode; it is never on by default.
 
 | Capability | Blocked UI | Required feed |
 |---|---|---|
-| Request-level telemetry (RPS, error rate, P95/P99 per service/edge) | 
Traffic page; edge metrics in Topology; service KPI columns | metrics ingestion 
from proxyless workloads (e.g. scrape/OTLP) aggregated by service pair |
+| Request-level telemetry (RPS, error rate, P95/P99 per service/edge) | 
Traffic page; service KPI columns | metrics ingestion from proxyless workloads 
(e.g. scrape/OTLP) aggregated by service pair |
 | Kubernetes events | Events page; event timeline in drawers | `api/events` 
backed by an events informer |
-| Alerting | Alerts page; alert badges | rule engine + alert store 
(ack/silence lifecycle) |
 | Historical time series | Metrics page beyond session buffer; time-range 
pickers | TSDB-backed query API (or Prometheus proxy) |
 | Per-resource config listing/spec | Config page rows → resource list & YAML | 
`api/configs?kind=` listing endpoint |
 | Service instance/endpoint listing | Service drawer endpoints tab | 
`api/services/{host}/endpoints` |
@@ -130,5 +113,5 @@ Each gate page states the required feed in these exact 
terms.
   One y-axis per chart; legend + direct labels for multi-series.
 - States implemented everywhere: skeleton (first load), error banner with 
retry,
   empty, capability gate, mock banner. Reduced motion respected.
-- Responsive: nav rail collapses to icons < 1200 px; grids reflow; topology and
-  tables stay usable at 1280×800.
+- Responsive: nav rail collapses to icons < 1200 px; grids and tables stay
+  usable at 1280×800.
diff --git a/dubbod/gui/resources/data/app.js b/dubbod/gui/resources/data/app.js
index 6b494a8e..b3046547 100644
--- a/dubbod/gui/resources/data/app.js
+++ b/dubbod/gui/resources/data/app.js
@@ -24,7 +24,6 @@
  */
 
 import { mockOverview, mockLogs, mockMetrics } from "./mock.js";
-import { Topology } from "./topology.js";
 import {
   Sparkline, TrendChart, BucketBars, BreakdownBars,
   bucketQuantile, fmtNumber, fmtDuration,
@@ -96,9 +95,9 @@ const applyTheme = (mode) => {
 
 const LEGACY_ROUTES = { home: "overview", mesh: "services", meshgateway: 
"gateways", configuration: "config" };
 const ROUTES = [
-  "overview", "topology", "metrics", "logs",
+  "overview", "metrics", "logs",
   "services", "gateways", "registries", "config",
-  "traffic", "events", "alerts", "runtime",
+  "traffic", "events", "runtime",
 ];
 const parseRoute = () => {
   let hash = (location.hash || "").replace(/^#\/?/, "");
@@ -233,8 +232,7 @@ const Drawer = ({ item, onClose, onOpenLogs, navigate }) => 
{
               <span class="chip chip-gate">request metrics n/a</span>
             </div>
             <div class="drawer-actions">
-              <button class="btn" onClick=${() => { onClose(); 
navigate("topology"); }}>Locate in topology</button>
-              <button class="btn btn-ghost" onClick=${() => 
copyText(data.hostname)}>Copy hostname</button>
+              <button class="btn" onClick=${() => 
copyText(data.hostname)}>Copy hostname</button>
             </div>
           `}
 
@@ -246,7 +244,6 @@ const Drawer = ({ item, onClose, onOpenLogs, navigate }) => 
{
             <${Field} label="Replicas" mono>${data.readyReplicas || 0} / 
${data.desiredReplicas || 0} ready</${Field}>
             <div class="drawer-actions">
               <button class="btn" onClick=${() => onOpenLogs({ kind: 
"gateway", name: data.name, namespace: data.namespace })}>View logs</button>
-              <button class="btn btn-ghost" onClick=${() => { onClose(); 
navigate("topology"); }}>Locate in topology</button>
             </div>
           `}
 
@@ -932,7 +929,7 @@ const GATED = {
     title: "Traffic",
     purpose: "Per-service and per-edge request analytics: RPS, success rate, 
error breakdown, latency percentiles, protocol split and drill-down to slow 
calls.",
     missing: "Request-level telemetry from proxyless gRPC workloads — a 
metrics ingestion path (scrape or OTLP) aggregated by service pair. The xds-api 
wire protocol carries no per-request stats today.",
-    wouldShow: ["RPS / error-rate / P95 per service and per edge", 
"traffic-weighted topology edges", "status-code and protocol breakdowns", 
"time-range comparison and anomaly flags"],
+    wouldShow: ["RPS / error-rate / P95 per service and per edge", 
"status-code and protocol breakdowns", "time-range comparison and anomaly 
flags"],
   },
   events: {
     title: "Events",
@@ -940,12 +937,6 @@ const GATED = {
     missing: "An api/events feed backed by a Kubernetes events informer (or an 
internal event store) scoped to mesh resources.",
     wouldShow: ["chronological event stream with severity", "affected-resource 
links into services/gateways", "filters by kind, namespace, and reason"],
   },
-  alerts: {
-    title: "Alerts",
-    purpose: "Active and historical alerts with acknowledge / silence / close 
lifecycle, wired to the metrics that triggered them.",
-    missing: "An alerting rule engine and alert store. Nothing evaluates 
thresholds server-side today; the GUI will not fabricate alert states.",
-    wouldShow: ["severity-grouped active alerts", "ack / silence / close 
actions with audit trail", "links to the triggering metric and topology node"],
-  },
 };
 
 // --- shell 
---------------------------------------------------------------------
@@ -953,7 +944,6 @@ const GATED = {
 const NAV = [
   { group: "Observe", items: [
     { id: "overview", label: "Overview" },
-    { id: "topology", label: "Topology" },
     { id: "metrics", label: "Metrics" },
     { id: "logs", label: "Logs" },
   ]},
@@ -966,7 +956,6 @@ const NAV = [
   { group: "Planned", items: [
     { id: "traffic", label: "Traffic", gated: true },
     { id: "events", label: "Events", gated: true },
-    { id: "alerts", label: "Alerts", gated: true },
   ]},
   { group: "System", items: [
     { id: "runtime", label: "Runtime" },
@@ -976,7 +965,6 @@ const NAV = [
 const NavIcon = ({ id }) => {
   const paths = {
     overview: html`<path d="M3 12h5V3H3zM10 21h5v-9h-5zM17 8h4V3h-4zM3 
21h5v-6H3zM10 9h5V3h-5zM17 21h4V11h-4z"/>`,
-    topology: html`<circle cx="5" cy="12" r="2.5"/><circle cx="19" cy="6" 
r="2.5"/><circle cx="19" cy="18" r="2.5"/><path d="M7.4 11l9.2-4.2M7.4 13l9.2 
4.2" fill="none"/>`,
     metrics: html`<path d="M3 20h18M6 16l4-6 4 3 5-8" fill="none"/>`,
     logs: html`<path d="M4 5h16M4 10h16M4 15h10M4 20h7" fill="none"/>`,
     services: html`<circle cx="12" cy="12" r="8.5" fill="none"/><circle 
cx="12" cy="12" r="3"/>`,
@@ -985,7 +973,6 @@ const NavIcon = ({ id }) => {
     config: html`<circle cx="12" cy="12" r="3" fill="none"/><path d="M12 
2v3M12 19v3M2 12h3M19 12h3M4.9 4.9l2.1 2.1M17 17l2.1 2.1M19.1 4.9L17 7M7 
17l-2.1 2.1" fill="none"/>`,
     traffic: html`<path d="M3 17c4 0 4-10 9-10s5 10 9 10" fill="none"/>`,
     events: html`<circle cx="12" cy="12" r="8.5" fill="none"/><path d="M12 
7v5l3.5 2" fill="none"/>`,
-    alerts: html`<path d="M12 3l9.5 17h-19zM12 10v4M12 17.3v.4" fill="none"/>`,
     runtime: html`<rect x="4" y="4" width="16" height="16" rx="2" 
fill="none"/><path d="M9 9h6v6H9z" fill="none"/>`,
   };
   return html`<svg viewBox="0 0 24 24" class="nav-icon" fill="none" 
stroke="currentColor" stroke-width="1.7" stroke-linecap="round" 
stroke-linejoin="round">${paths[id] || paths.overview}</svg>`;
@@ -1149,27 +1136,6 @@ const App = () => {
 
         <div class="content" key=${route}>
           ${route === "overview" && html`<${OverviewPage} ...${pageProps} />`}
-          ${route === "topology" && html`
-            <div class="page page-flush">
-              <div class="page-head">
-                <div>
-                  <${Eyebrow}>observe / topology</${Eyebrow}>
-                  <h1 class="page-title">Topology</h1>
-                  <div class="page-sub">Configuration-plane relationships as 
of ${updatedAt || "–"} — registries sync into dubbod; dubbod provisions 
gateways and pushes xDS to workloads.</div>
-                </div>
-              </div>
-              <${Topology} data=${data} selectedId=${drawer?.nodeId}
-                onSelect=${(node) => {
-                  const map = {
-                    registry: () => setDrawer({ type: "registry", nodeId: 
node.id, title: node.label, status: node.status, data: node.data }),
-                    gateway: () => setDrawer({ type: "gateway", nodeId: 
node.id, title: node.label, status: node.status, data: node.data }),
-                    service: () => setDrawer({ type: "service", nodeId: 
node.id, title: node.label, status: "unknown", data: node.data }),
-                    controlplane: () => setDrawer({ type: "controlplane", 
nodeId: node.id, title: "dubbod", status: node.status, data: node.data }),
-                  };
-                  map[node.type]?.();
-                }} />
-            </div>
-          `}
           ${route === "metrics" && html`
             <${MetricsPage} history=${history} interval=${metricsInterval} 
setInterval=${setMetricsInterval}
               paused=${metricsPaused} setPaused=${setMetricsPaused} 
error=${metricsError} retry=${pollMetrics} />
diff --git a/dubbod/gui/resources/data/styles.css 
b/dubbod/gui/resources/data/styles.css
index 568d9459..4db4b5bf 100644
--- a/dubbod/gui/resources/data/styles.css
+++ b/dubbod/gui/resources/data/styles.css
@@ -607,85 +607,6 @@ mark { background: var(--warn-soft); color: inherit; 
outline: 1px solid var(--wa
 .hbar-fill { display: block; height: 100%; border-radius: 3px; }
 .hbar-value { flex: none; width: 64px; font-family: var(--mono); font-size: 
11.5px; font-weight: 600; }
 
-/* --- topology (signature) 
------------------------------------------------------------------------ */
-
-.topo { display: flex; flex-direction: column; height: calc(100vh - 230px); 
min-height: 460px; }
-.topo-fullscreen {
-  position: fixed; inset: 0; z-index: 50;
-  height: 100vh; min-height: 0;
-  background: var(--canvas);
-  padding: 12px;
-}
-.topo-toolbar { flex: none; display: flex; gap: 8px; align-items: center; 
margin-bottom: 10px; flex-wrap: wrap; }
-.topo-search { width: 220px; }
-.topo-toolbar-gap { flex: 1; }
-.topo-canvas {
-  flex: 1; position: relative; overflow: hidden;
-  background: var(--surface);
-  background-image: radial-gradient(var(--border) 1px, transparent 1px);
-  background-size: 22px 22px;
-  border: 1px solid var(--border);
-  border-radius: var(--r-md);
-  cursor: grab;
-  touch-action: none;
-}
-.topo-canvas:active { cursor: grabbing; }
-.topo-canvas svg { display: block; }
-
-.topo-band {
-  font-family: var(--mono); font-size: 10px; letter-spacing: 0.18em;
-  fill: var(--ink-3);
-}
-.topo-group { fill: var(--accent-soft); stroke: var(--border-strong); 
stroke-dasharray: 4 4; }
-.topo-group-label { font-family: var(--mono); font-size: 11px; font-weight: 
600; fill: var(--ink-2); }
-.topo-group-count { font-family: var(--mono); font-size: 10px; fill: 
var(--ink-3); }
-
-.topo-node { cursor: pointer; }
-.topo-node-box {
-  fill: var(--surface);
-  stroke: var(--border-strong);
-  transition: stroke var(--speed);
-}
-.topo-node:hover .topo-node-box { stroke: var(--accent); }
-.topo-node.is-selected .topo-node-box { stroke: var(--accent); stroke-width: 
2; }
-.topo-node.status-ok .topo-node-strip { fill: var(--ok); }
-.topo-node.status-warn .topo-node-strip { fill: var(--warn); }
-.topo-node.status-err .topo-node-strip { fill: var(--err); }
-.topo-node.status-unknown .topo-node-strip { fill: var(--unk); opacity: 0.45; }
-.topo-node-label { font-size: 12px; font-weight: 600; fill: var(--ink); }
-.topo-node-sub { font-family: var(--mono); font-size: 9.5px; fill: 
var(--ink-3); }
-.topo-icon {
-  stroke: var(--ink-3); stroke-width: 1.6; fill: none;
-  stroke-linecap: round; stroke-linejoin: round;
-  overflow: visible;
-}
-.topo-node.status-ok .topo-icon { stroke: var(--ok); }
-.topo-node.status-warn .topo-icon { stroke: var(--warn); }
-.topo-node.status-err .topo-icon { stroke: var(--err); }
-
-.topo-edge-line { fill: none; stroke: var(--axis); stroke-width: 1.5; }
-.topo-edge.is-degraded .topo-edge-line { stroke: var(--warn); 
stroke-dasharray: 5 4; }
-.topo-edge-label { font-family: var(--mono); font-size: 9.5px; fill: 
var(--ink-3); }
-.topo-edge.is-degraded .topo-edge-label { fill: var(--warn); }
-
-.topo-more-box { fill: var(--surface-2); stroke: var(--border-strong); 
stroke-dasharray: 3 3; }
-.topo-more { cursor: pointer; }
-.topo-more-label { font-family: var(--mono); font-size: 10.5px; fill: 
var(--ink-2); }
-
-.is-dim { opacity: 0.18; }
-.topo-node.is-hit .topo-node-box { stroke: var(--accent); stroke-width: 2; }
-
-.topo-legend {
-  position: absolute; left: 12px; bottom: 10px;
-  display: flex; gap: 14px; flex-wrap: wrap;
-  font-size: 11px; color: var(--ink-2);
-  background: color-mix(in srgb, var(--surface) 85%, transparent);
-  border: 1px solid var(--border);
-  border-radius: var(--r-sm);
-  padding: 5px 10px;
-}
-.topo-legend > span { display: inline-flex; align-items: center; gap: 6px; }
-
 /* --- responsive 
-----------------------------------------------------------------------------------
 */
 
 @media (max-width: 1360px) {
diff --git a/dubbod/gui/resources/data/topology.js 
b/dubbod/gui/resources/data/topology.js
deleted file mode 100644
index 26e57b32..00000000
--- a/dubbod/gui/resources/data/topology.js
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Config-plane topology — the console's signature view.
- *
- * Every node and edge is a fact from GET api/overview: registries sync into
- * dubbod, dubbod provisions gateways and distributes xDS to namespaces of
- * mesh services. There is no request-level telemetry feed yet, so edges carry
- * relationship + state, never invented traffic numbers.
- */
-
-const html = window.html;
-const { useState, useMemo, useRef, useEffect, useCallback } = window;
-
-const NODE_W = 168;
-const NODE_H = 46;
-const CP_W = 200;
-const CP_H = 92;
-const COL_X = [24, 320, 640];
-const GROUP_PAD = 14;
-const GROUP_HEAD = 30;
-const ROW_GAP = 10;
-const MAX_VISIBLE = 8;
-
-const statusOf = {
-  registry: (r) => (r.synced ? "ok" : "warn"),
-  gateway: (g) => (g.isReady ? "ok" : (g.readyReplicas || 0) === 0 ? "err" : 
"warn"),
-  controlplane: (instances) => {
-    const ready = instances.filter((i) => i.isReady).length;
-    if (instances.length === 0 || ready === 0) return "err";
-    return ready === instances.length ? "ok" : "warn";
-  },
-};
-
-export const buildGraph = (data, { expanded, namespaceFilter }) => {
-  const nodes = [];
-  const edges = [];
-
-  const registries = data.registries || [];
-  const gateways = data.gatewayInstances || [];
-  const instances = data.instances || [];
-  const services = (data.services || []).filter(
-    (s) => !namespaceFilter || s.namespace === namespaceFilter
-  );
-
-  // Column 1: registries then gateways.
-  let y = 56;
-  registries.forEach((r) => {
-    nodes.push({
-      id: `registry:${r.provider}/${r.cluster}`, type: "registry", label: 
r.provider,
-      sub: r.cluster, status: statusOf.registry(r), x: COL_X[0], y, w: NODE_W, 
h: NODE_H, data: r,
-    });
-    y += NODE_H + 18;
-  });
-  y += 40;
-  const gatewayBandY = y;
-  gateways.forEach((g) => {
-    nodes.push({
-      id: `gateway:${g.namespace}/${g.name}`, type: "gateway", label: 
g.gatewayName || g.name,
-      sub: `${g.namespace} · ${g.readyReplicas || 0}/${g.desiredReplicas || 0} 
ready`,
-      status: statusOf.gateway(g), x: COL_X[0], y, w: NODE_W, h: NODE_H, data: 
g,
-    });
-    y += NODE_H + 18;
-  });
-  const col1H = y;
-
-  // Column 3: namespace groups of services.
-  const byNamespace = new Map();
-  services.forEach((s) => {
-    if (!byNamespace.has(s.namespace)) byNamespace.set(s.namespace, []);
-    byNamespace.get(s.namespace).push(s);
-  });
-  let gy = 56;
-  const groups = [];
-  [...byNamespace.entries()].sort((a, b) => 
a[0].localeCompare(b[0])).forEach(([ns, list]) => {
-    const isExpanded = expanded.has(ns);
-    const visible = isExpanded ? list : list.slice(0, MAX_VISIBLE);
-    const hidden = list.length - visible.length;
-    const rows = visible.length + (hidden > 0 || isExpanded ? 1 : 0);
-    const h = GROUP_HEAD + GROUP_PAD + rows * (NODE_H + ROW_GAP);
-    const group = { ns, x: COL_X[2], y: gy, w: NODE_W + GROUP_PAD * 2, h, 
count: list.length };
-    groups.push(group);
-    visible.forEach((s, i) => {
-      nodes.push({
-        id: `service:${s.hostname}`, type: "service", label: s.name || 
s.hostname,
-        sub: s.registry + (s.meshExternal ? " · external" : ""), status: 
"unknown",
-        x: group.x + GROUP_PAD, y: gy + GROUP_HEAD + GROUP_PAD + i * (NODE_H + 
ROW_GAP),
-        w: NODE_W, h: NODE_H, data: s, group: ns,
-      });
-    });
-    if (hidden > 0 || isExpanded) {
-      nodes.push({
-        id: `more:${ns}`, type: "more", label: hidden > 0 ? `+${hidden} more` 
: "collapse",
-        x: group.x + GROUP_PAD, y: gy + GROUP_HEAD + GROUP_PAD + 
visible.length * (NODE_H + ROW_GAP),
-        w: NODE_W, h: 30, group: ns,
-      });
-    }
-    gy += h + 26;
-  });
-  const col3H = gy;
-
-  // Column 2: control plane vertically centered against the taller side.
-  const totalH = Math.max(col1H, col3H, 320);
-  const cp = {
-    id: "controlplane", type: "controlplane", label: "dubbod",
-    sub: `${instances.filter((i) => i.isReady).length}/${instances.length} 
ready · ${data.counts?.xdsConnections ?? 0} xDS conns`,
-    status: statusOf.controlplane(instances),
-    x: COL_X[1], y: totalH / 2 - CP_H / 2, w: CP_W, h: CP_H,
-    data: { instances, version: data.version, namespace: data.namespace },
-  };
-  nodes.push(cp);
-
-  // Edges — all real relationships.
-  nodes.filter((n) => n.type === "registry").forEach((n) => {
-    edges.push({ id: `e:${n.id}`, from: n, to: cp, kind: "sync", ok: 
n.data.synced, label: n.data.synced ? "synced" : "syncing" });
-  });
-  nodes.filter((n) => n.type === "gateway").forEach((n) => {
-    edges.push({ id: `e:${n.id}`, from: cp, to: n, kind: "provision", ok: 
n.data.isReady, label: "provisions" });
-  });
-  groups.forEach((g) => {
-    edges.push({
-      id: `e:ns:${g.ns}`, from: cp, kind: "xds", ok: true, label: `xDS · 
${g.count} svc`,
-      toPoint: { x: g.x, y: g.y + GROUP_HEAD / 2 + 8 }, group: g.ns,
-    });
-  });
-
-  return { nodes, edges, groups, width: COL_X[2] + NODE_W + GROUP_PAD * 2 + 
40, height: totalH + 40, gatewayBandY };
-};
-
-const edgePath = (x1, y1, x2, y2) => {
-  const mx = (x1 + x2) / 2;
-  return `M${x1},${y1} C${mx},${y1} ${mx},${y2} ${x2},${y2}`;
-};
-
-const NodeIcon = ({ type }) => {
-  switch (type) {
-    case "registry":
-      return html`<svg x="9" y="9" width="14" height="14" viewBox="0 0 24 24" 
class="topo-icon"><ellipse cx="12" cy="6" rx="8" ry="3" fill="none"/><path 
d="M4 6v12c0 1.7 3.6 3 8 3s8-1.3 8-3V6" fill="none"/><path d="M4 12c0 1.7 3.6 3 
8 3s8-1.3 8-3" fill="none"/></svg>`;
-    case "controlplane":
-      return html`<svg x="9" y="9" width="14" height="14" viewBox="0 0 24 24" 
class="topo-icon"><polygon points="12 2 2 7 12 12 22 7 12 2" 
fill="none"/><polyline points="2 17 12 22 22 17" fill="none"/><polyline 
points="2 12 12 17 22 12" fill="none"/></svg>`;
-    case "gateway":
-      return html`<svg x="9" y="9" width="14" height="14" viewBox="0 0 24 24" 
class="topo-icon"><path d="M4 21V8l8-5 8 5v13" fill="none"/><path d="M9 
21v-6h6v6" fill="none"/></svg>`;
-    default:
-      return html`<svg x="9" y="9" width="14" height="14" viewBox="0 0 24 24" 
class="topo-icon"><circle cx="12" cy="12" r="9" fill="none"/><circle cx="12" 
cy="12" r="3.5" fill="none"/></svg>`;
-  }
-};
-
-export const Topology = ({ data, onSelect, selectedId }) => {
-  const [transform, setTransform] = useState({ x: 0, y: 0, k: 1 });
-  const [expanded, setExpanded] = useState(new Set());
-  const [namespaceFilter, setNamespaceFilter] = useState("");
-  const [query, setQuery] = useState("");
-  const [fullscreen, setFullscreen] = useState(false);
-  const [dragOffsets, setDragOffsets] = useState(new Map());
-  const containerRef = useRef(null);
-  const gesture = useRef(null);
-
-  const namespaces = useMemo(
-    () => [...new Set((data.services || []).map((s) => s.namespace))].sort(),
-    [data]
-  );
-
-  const graph = useMemo(
-    () => buildGraph(data, { expanded, namespaceFilter }),
-    [data, expanded, namespaceFilter]
-  );
-
-  const offset = (node) => dragOffsets.get(node.id) || { dx: 0, dy: 0 };
-  const nx = (node) => node.x + offset(node).dx;
-  const ny = (node) => node.y + offset(node).dy;
-
-  const matches = (node) => {
-    if (!query) return true;
-    const q = query.toLowerCase();
-    return [node.label, node.sub, node.data?.hostname, node.data?.cluster]
-      .some((v) => v && String(v).toLowerCase().includes(q));
-  };
-
-  const fit = useCallback(() => {
-    const el = containerRef.current;
-    if (!el) return;
-    const k = Math.min(el.clientWidth / graph.width, el.clientHeight / 
graph.height, 1.4);
-    setTransform({
-      x: (el.clientWidth - graph.width * k) / 2,
-      y: Math.max(8, (el.clientHeight - graph.height * k) / 2),
-      k,
-    });
-  }, [graph.width, graph.height]);
-
-  useEffect(() => { fit(); }, [fullscreen, namespaceFilter]);
-  useEffect(() => { fit(); }, []);
-
-  const onWheel = (event) => {
-    event.preventDefault();
-    const el = containerRef.current.getBoundingClientRect();
-    const px = event.clientX - el.left;
-    const py = event.clientY - el.top;
-    setTransform((t) => {
-      const k = Math.min(2.5, Math.max(0.3, t.k * (event.deltaY < 0 ? 1.12 : 
0.89)));
-      return { k, x: px - ((px - t.x) / t.k) * k, y: py - ((py - t.y) / t.k) * 
k };
-    });
-  };
-
-  const onPointerDown = (event, node) => {
-    event.currentTarget.setPointerCapture?.(event.pointerId);
-    gesture.current = {
-      node, startX: event.clientX, startY: event.clientY,
-      base: node ? { ...offset(node) } : { ...transform }, moved: false,
-    };
-  };
-
-  const onPointerMove = (event) => {
-    const g = gesture.current;
-    if (!g) return;
-    const dx = event.clientX - g.startX;
-    const dy = event.clientY - g.startY;
-    if (Math.abs(dx) + Math.abs(dy) > 3) g.moved = true;
-    if (!g.moved) return;
-    if (g.node) {
-      setDragOffsets((prev) => {
-        const next = new Map(prev);
-        next.set(g.node.id, { dx: g.base.dx + dx / transform.k, dy: g.base.dy 
+ dy / transform.k });
-        return next;
-      });
-    } else {
-      setTransform((t) => ({ ...t, x: g.base.x + dx, y: g.base.y + dy }));
-    }
-  };
-
-  const onPointerUp = (event, node) => {
-    const g = gesture.current;
-    gesture.current = null;
-    if (g && !g.moved && node) {
-      if (node.type === "more") {
-        setExpanded((prev) => {
-          const next = new Set(prev);
-          next.has(node.group) ? next.delete(node.group) : 
next.add(node.group);
-          return next;
-        });
-      } else {
-        onSelect?.(node);
-      }
-    }
-  };
-
-  const cp = graph.nodes.find((n) => n.type === "controlplane");
-
-  return html`
-    <div class=${`topo ${fullscreen ? "topo-fullscreen" : ""}`}>
-      <div class="topo-toolbar">
-        <input class="input topo-search" placeholder="Locate node…" 
value=${query} onInput=${(e) => setQuery(e.target.value)} />
-        <select class="input topo-ns" value=${namespaceFilter} onChange=${(e) 
=> setNamespaceFilter(e.target.value)}>
-          <option value="">All namespaces</option>
-          ${namespaces.map((ns) => html`<option key=${ns} 
value=${ns}>${ns}</option>`)}
-        </select>
-        <span class="topo-toolbar-gap" />
-        <span class="chip chip-gate" title="Request-level telemetry is not 
connected; edges show configuration relationships only.">edge telemetry 
n/a</span>
-        <button class="btn btn-ghost" onClick=${() => setTransform((t) => ({ 
...t, k: Math.min(2.5, t.k * 1.2) }))} title="Zoom in">+</button>
-        <button class="btn btn-ghost" onClick=${() => setTransform((t) => ({ 
...t, k: Math.max(0.3, t.k / 1.2) }))} title="Zoom out">−</button>
-        <button class="btn btn-ghost" onClick=${fit} title="Fit to 
view">Fit</button>
-        <button class="btn btn-ghost" onClick=${() => 
setFullscreen(!fullscreen)}>${fullscreen ? "Exit" : "Fullscreen"}</button>
-      </div>
-
-      <div
-        class="topo-canvas"
-        ref=${containerRef}
-        onWheel=${onWheel}
-        onPointerDown=${(e) => { if (e.target === e.currentTarget || 
e.target.tagName === "svg") onPointerDown(e, null); }}
-        onPointerMove=${onPointerMove}
-        onPointerUp=${(e) => onPointerUp(e, null)}
-      >
-        <svg width="100%" height="100%">
-          <g transform=${`translate(${transform.x},${transform.y}) 
scale(${transform.k})`}>
-            <text x=${COL_X[0]} y="30" class="topo-band">REGISTRY PLANE</text>
-            <text x=${COL_X[0]} y=${graph.gatewayBandY - 14} 
class="topo-band">GATEWAY PLANE</text>
-            <text x=${COL_X[1]} y="30" class="topo-band">CONTROL PLANE</text>
-            <text x=${COL_X[2]} y="30" class="topo-band">WORKLOAD PLANE</text>
-
-            ${graph.edges.map((e) => {
-              const from = e.from;
-              const x1 = nx(from) + from.w;
-              const y1 = ny(from) + from.h / 2;
-              const x2 = e.toPoint ? e.toPoint.x : nx(e.to);
-              const y2 = e.toPoint ? e.toPoint.y : ny(e.to) + e.to.h / 2;
-              // Registry edges enter dubbod's left side; others leave its 
right.
-              const flip = e.kind === "sync";
-              const [ax1, ay1, ax2, ay2] = flip
-                ? [nx(from) + from.w, y1, nx(e.to), ny(e.to) + e.to.h / 2]
-                : [x1, y1, x2, y2];
-              const dim = query && !(matches(from) || (e.to && matches(e.to)));
-              return html`
-                <g key=${e.id} class=${`topo-edge ${e.ok ? "" : "is-degraded"} 
${dim ? "is-dim" : ""}`}>
-                  <path d=${edgePath(ax1, ay1, ax2, ay2)} 
class="topo-edge-line" />
-                  <text x=${(ax1 + ax2) / 2} y=${(ay1 + ay2) / 2 - 6} 
class="topo-edge-label" text-anchor="middle">${e.label}</text>
-                </g>
-              `;
-            })}
-
-            ${graph.groups.map((g) => html`
-              <g key=${g.ns} class=${query && ![...graph.nodes].some((n) => 
n.group === g.ns && matches(n)) ? "is-dim" : ""}>
-                <rect x=${g.x} y=${g.y} width=${g.w} height=${g.h} rx="10" 
class="topo-group" />
-                <text x=${g.x + GROUP_PAD} y=${g.y + 20} 
class="topo-group-label">ns/${g.ns}</text>
-                <text x=${g.x + g.w - GROUP_PAD} y=${g.y + 20} 
class="topo-group-count" text-anchor="end">${g.count}</text>
-              </g>
-            `)}
-
-            ${graph.nodes.map((node) => {
-              if (node.type === "more") {
-                return html`
-                  <g key=${node.id} class="topo-more" 
transform=${`translate(${nx(node)},${ny(node)})`}
-                     onPointerDown=${(e) => { e.stopPropagation(); 
onPointerDown(e, node); }}
-                     onPointerMove=${onPointerMove}
-                     onPointerUp=${(e) => { e.stopPropagation(); 
onPointerUp(e, node); }}>
-                    <rect width=${node.w} height=${node.h} rx="6" 
class="topo-more-box" />
-                    <text x=${node.w / 2} y="19" text-anchor="middle" 
class="topo-more-label">${node.label}</text>
-                  </g>
-                `;
-              }
-              const dim = query && !matches(node);
-              const hit = query && matches(node);
-              return html`
-                <g key=${node.id}
-                   class=${`topo-node status-${node.status} ${selectedId === 
node.id ? "is-selected" : ""} ${dim ? "is-dim" : ""} ${hit ? "is-hit" : ""}`}
-                   transform=${`translate(${nx(node)},${ny(node)})`}
-                   onPointerDown=${(e) => { e.stopPropagation(); 
onPointerDown(e, node); }}
-                   onPointerMove=${onPointerMove}
-                   onPointerUp=${(e) => { e.stopPropagation(); onPointerUp(e, 
node); }}>
-                  <rect width=${node.w} height=${node.h} rx="8" 
class="topo-node-box" />
-                  <rect width="3" height=${node.h} rx="1.5" 
class="topo-node-strip" />
-                  <${NodeIcon} type=${node.type} />
-                  <text x="30" y=${node.type === "controlplane" ? 34 : 19} 
class="topo-node-label">${node.label}</text>
-                  ${node.sub && html`<text x="30" y=${node.type === 
"controlplane" ? 52 : 35} class="topo-node-sub">${node.sub}</text>`}
-                  ${node.type === "controlplane" && html`<text x="30" y="72" 
class="topo-node-sub">${(node.data.version || "").split("-")[0]}</text>`}
-                </g>
-              `;
-            })}
-          </g>
-        </svg>
-
-        <div class="topo-legend">
-          <span><span class="dot status-ok" />ready / synced</span>
-          <span><span class="dot status-warn" />degraded / syncing</span>
-          <span><span class="dot status-err" />down</span>
-          <span><span class="dot status-unknown" />no health feed 
(services)</span>
-        </div>
-      </div>
-    </div>
-  `;
-};
diff --git a/manifests/charts/addons/grafana/files/manifests.yaml 
b/manifests/charts/addons/grafana/files/manifests.yaml
index b9a56ef6..98651b8c 100644
--- a/manifests/charts/addons/grafana/files/manifests.yaml
+++ b/manifests/charts/addons/grafana/files/manifests.yaml
@@ -804,307 +804,6 @@ data:
           ],
           "title": "XDS Reject Rate",
           "type": "timeseries"
-        },
-        {
-          "collapsed": false,
-          "gridPos": {
-            "h": 1,
-            "w": 24,
-            "x": 0,
-            "y": 40
-          },
-          "id": 19,
-          "panels": [],
-          "title": "Gateway Traffic",
-          "type": "row"
-        },
-        {
-          "datasource": {
-            "type": "prometheus",
-            "uid": "prometheus"
-          },
-          "fieldConfig": {
-            "defaults": {
-              "custom": {
-                "drawStyle": "line",
-                "fillOpacity": 10,
-                "lineWidth": 1,
-                "showPoints": "never"
-              },
-              "unit": "ops"
-            },
-            "overrides": []
-          },
-          "gridPos": {
-            "h": 8,
-            "w": 8,
-            "x": 0,
-            "y": 41
-          },
-          "id": 20,
-          "options": {
-            "legend": {
-              "calcs": [
-                "lastNotNull"
-              ],
-              "displayMode": "table",
-              "placement": "bottom",
-              "showLegend": true
-            },
-            "tooltip": {
-              "mode": "multi",
-              "sort": "none"
-            }
-          },
-          "targets": [
-            {
-              "expr": "sum by (route, cluster) 
(rate(dxgate_http_route_requests_total[5m]))",
-              "legendFormat": "{{route}} / {{cluster}}",
-              "refId": "A"
-            }
-          ],
-          "title": "HTTP Request Rate",
-          "type": "timeseries"
-        },
-        {
-          "datasource": {
-            "type": "prometheus",
-            "uid": "prometheus"
-          },
-          "fieldConfig": {
-            "defaults": {
-              "custom": {
-                "drawStyle": "line",
-                "fillOpacity": 10,
-                "lineWidth": 1,
-                "showPoints": "never"
-              },
-              "unit": "ops"
-            },
-            "overrides": []
-          },
-          "gridPos": {
-            "h": 8,
-            "w": 8,
-            "x": 8,
-            "y": 41
-          },
-          "id": 21,
-          "options": {
-            "legend": {
-              "calcs": [
-                "lastNotNull"
-              ],
-              "displayMode": "table",
-              "placement": "bottom",
-              "showLegend": true
-            },
-            "tooltip": {
-              "mode": "multi",
-              "sort": "none"
-            }
-          },
-          "targets": [
-            {
-              "expr": "sum by (route, cluster) 
(rate(dxgate_http_route_failures_total[5m]))",
-              "legendFormat": "{{route}} / {{cluster}}",
-              "refId": "A"
-            }
-          ],
-          "title": "HTTP Failure Rate",
-          "type": "timeseries"
-        },
-        {
-          "datasource": {
-            "type": "prometheus",
-            "uid": "prometheus"
-          },
-          "fieldConfig": {
-            "defaults": {
-              "custom": {
-                "drawStyle": "line",
-                "fillOpacity": 10,
-                "lineWidth": 1,
-                "showPoints": "never"
-              },
-              "unit": "ms"
-            },
-            "overrides": []
-          },
-          "gridPos": {
-            "h": 8,
-            "w": 8,
-            "x": 16,
-            "y": 41
-          },
-          "id": 22,
-          "options": {
-            "legend": {
-              "calcs": [
-                "lastNotNull"
-              ],
-              "displayMode": "table",
-              "placement": "bottom",
-              "showLegend": true
-            },
-            "tooltip": {
-              "mode": "multi",
-              "sort": "none"
-            }
-          },
-          "targets": [
-            {
-              "expr": "histogram_quantile(0.95, sum by (le, route, cluster) 
(rate(dxgate_http_route_latency_ms_bucket[5m])))",
-              "legendFormat": "{{route}} / {{cluster}}",
-              "refId": "A"
-            }
-          ],
-          "title": "HTTP Upstream P95",
-          "type": "timeseries"
-        },
-        {
-          "datasource": {
-            "type": "prometheus",
-            "uid": "prometheus"
-          },
-          "fieldConfig": {
-            "defaults": {
-              "custom": {
-                "drawStyle": "line",
-                "fillOpacity": 10,
-                "lineWidth": 1,
-                "showPoints": "never"
-              },
-              "unit": "ms"
-            },
-            "overrides": []
-          },
-          "gridPos": {
-            "h": 8,
-            "w": 8,
-            "x": 0,
-            "y": 49
-          },
-          "id": 23,
-          "options": {
-            "legend": {
-              "calcs": [
-                "lastNotNull"
-              ],
-              "displayMode": "table",
-              "placement": "bottom",
-              "showLegend": true
-            },
-            "tooltip": {
-              "mode": "multi",
-              "sort": "none"
-            }
-          },
-          "targets": [
-            {
-              "expr": "histogram_quantile(0.99, sum by (le, route, cluster) 
(rate(dxgate_http_route_latency_ms_bucket[5m])))",
-              "legendFormat": "{{route}} / {{cluster}}",
-              "refId": "A"
-            }
-          ],
-          "title": "HTTP Upstream P99",
-          "type": "timeseries"
-        },
-        {
-          "datasource": {
-            "type": "prometheus",
-            "uid": "prometheus"
-          },
-          "fieldConfig": {
-            "defaults": {
-              "custom": {
-                "drawStyle": "line",
-                "fillOpacity": 10,
-                "lineWidth": 1,
-                "showPoints": "never"
-              },
-              "unit": "ops"
-            },
-            "overrides": []
-          },
-          "gridPos": {
-            "h": 8,
-            "w": 8,
-            "x": 8,
-            "y": 49
-          },
-          "id": 24,
-          "options": {
-            "legend": {
-              "calcs": [
-                "lastNotNull"
-              ],
-              "displayMode": "table",
-              "placement": "bottom",
-              "showLegend": true
-            },
-            "tooltip": {
-              "mode": "multi",
-              "sort": "none"
-            }
-          },
-          "targets": [
-            {
-              "expr": "sum by (route, cluster, status_code) 
(rate(dxgate_http_route_requests_total{status_code=~\"5..\"}[5m]))",
-              "legendFormat": "{{route}} / {{cluster}} / {{status_code}}",
-              "refId": "A"
-            }
-          ],
-          "title": "HTTP 5xx Rate",
-          "type": "timeseries"
-        },
-        {
-          "datasource": {
-            "type": "prometheus",
-            "uid": "prometheus"
-          },
-          "fieldConfig": {
-            "defaults": {
-              "custom": {
-                "drawStyle": "line",
-                "fillOpacity": 10,
-                "lineWidth": 1,
-                "showPoints": "never"
-              },
-              "unit": "ops"
-            },
-            "overrides": []
-          },
-          "gridPos": {
-            "h": 8,
-            "w": 8,
-            "x": 16,
-            "y": 49
-          },
-          "id": 25,
-          "options": {
-            "legend": {
-              "calcs": [
-                "lastNotNull"
-              ],
-              "displayMode": "table",
-              "placement": "bottom",
-              "showLegend": true
-            },
-            "tooltip": {
-              "mode": "multi",
-              "sort": "none"
-            }
-          },
-          "targets": [
-            {
-              "expr": "sum by (route, cluster, status_code) 
(rate(dxgate_http_route_requests_total{status_code=~\"401|403|429\"}[5m]))",
-              "legendFormat": "{{route}} / {{cluster}} / {{status_code}}",
-              "refId": "A"
-            }
-          ],
-          "title": "Policy Rejection Rate",
-          "type": "timeseries"
         }
       ],
       "refresh": "15s",
diff --git a/manifests/charts/addons/prometheus/files/manifests.yaml 
b/manifests/charts/addons/prometheus/files/manifests.yaml
index 4301ab58..17f1d459 100644
--- a/manifests/charts/addons/prometheus/files/manifests.yaml
+++ b/manifests/charts/addons/prometheus/files/manifests.yaml
@@ -64,9 +64,6 @@ data:
       scrape_interval: 15s
       evaluation_interval: 15s
 
-    rule_files:
-    - /etc/prometheus/rules/*.yaml
-
     scrape_configs:
     - job_name: prometheus
       static_configs:
@@ -106,60 +103,6 @@ data:
         target_label: app
 ---
 apiVersion: v1
-kind: ConfigMap
-metadata:
-  name: prometheus-rules
-  namespace: dubbo-system
-  labels:
-    app.kubernetes.io/name: prometheus
-    app.kubernetes.io/part-of: dubbo-observability
-data:
-  dubbo-alerts.yaml: |
-    groups:
-    - name: dubbo-observability
-      rules:
-      - alert: Dxgate5xxRateHigh
-        expr: sum by (namespace, gateway, route, cluster) 
(rate(dxgate_http_route_requests_total{status_code=~"5.."}[5m])) > 0
-        for: 5m
-        labels:
-          severity: warning
-        annotations:
-          summary: dxgate 5xx responses are increasing
-          description: dxgate is returning 5xx responses for one or more 
Gateway routes.
-      - alert: DxgateP95LatencyHigh
-        expr: histogram_quantile(0.95, sum by (le, namespace, gateway, route, 
cluster) (rate(dxgate_http_route_latency_ms_bucket[5m]))) > 1000
-        for: 10m
-        labels:
-          severity: warning
-        annotations:
-          summary: dxgate P95 latency is above 1s
-          description: Gateway upstream latency is above the sample threshold.
-      - alert: DxgateNotReady
-        expr: up{app="dxgate"} == 0
-        for: 2m
-        labels:
-          severity: critical
-        annotations:
-          summary: dxgate metrics target is down
-          description: Prometheus cannot scrape a dxgate pod or the pod is not 
ready.
-      - alert: DubbodXDSRejects
-        expr: sum(rate(dubbod_total_xds_rejects[5m])) > 0
-        for: 5m
-        labels:
-          severity: warning
-        annotations:
-          summary: xDS rejects are increasing
-          description: One or more data-plane clients rejected xDS resources 
from dubbod.
-      - alert: DubbodSDSError
-        expr: sum(rate(dubbod_sds_certificate_errors_total[5m])) > 0
-        for: 5m
-        labels:
-          severity: warning
-        annotations:
-          summary: SDS certificate errors are increasing
-          description: Workload certificate fetch or delivery is failing.
----
-apiVersion: v1
 kind: Service
 metadata:
   name: prometheus
@@ -230,17 +173,11 @@ spec:
         - name: config
           mountPath: /etc/prometheus
           readOnly: true
-        - name: rules
-          mountPath: /etc/prometheus/rules
-          readOnly: true
         - name: storage
           mountPath: /prometheus
       volumes:
       - name: config
         configMap:
           name: prometheus
-      - name: rules
-        configMap:
-          name: prometheus-rules
       - name: storage
         emptyDir: {}
diff --git a/samples/addons/grafana.yaml b/samples/addons/grafana.yaml
index b9a56ef6..98651b8c 100644
--- a/samples/addons/grafana.yaml
+++ b/samples/addons/grafana.yaml
@@ -804,307 +804,6 @@ data:
           ],
           "title": "XDS Reject Rate",
           "type": "timeseries"
-        },
-        {
-          "collapsed": false,
-          "gridPos": {
-            "h": 1,
-            "w": 24,
-            "x": 0,
-            "y": 40
-          },
-          "id": 19,
-          "panels": [],
-          "title": "Gateway Traffic",
-          "type": "row"
-        },
-        {
-          "datasource": {
-            "type": "prometheus",
-            "uid": "prometheus"
-          },
-          "fieldConfig": {
-            "defaults": {
-              "custom": {
-                "drawStyle": "line",
-                "fillOpacity": 10,
-                "lineWidth": 1,
-                "showPoints": "never"
-              },
-              "unit": "ops"
-            },
-            "overrides": []
-          },
-          "gridPos": {
-            "h": 8,
-            "w": 8,
-            "x": 0,
-            "y": 41
-          },
-          "id": 20,
-          "options": {
-            "legend": {
-              "calcs": [
-                "lastNotNull"
-              ],
-              "displayMode": "table",
-              "placement": "bottom",
-              "showLegend": true
-            },
-            "tooltip": {
-              "mode": "multi",
-              "sort": "none"
-            }
-          },
-          "targets": [
-            {
-              "expr": "sum by (route, cluster) 
(rate(dxgate_http_route_requests_total[5m]))",
-              "legendFormat": "{{route}} / {{cluster}}",
-              "refId": "A"
-            }
-          ],
-          "title": "HTTP Request Rate",
-          "type": "timeseries"
-        },
-        {
-          "datasource": {
-            "type": "prometheus",
-            "uid": "prometheus"
-          },
-          "fieldConfig": {
-            "defaults": {
-              "custom": {
-                "drawStyle": "line",
-                "fillOpacity": 10,
-                "lineWidth": 1,
-                "showPoints": "never"
-              },
-              "unit": "ops"
-            },
-            "overrides": []
-          },
-          "gridPos": {
-            "h": 8,
-            "w": 8,
-            "x": 8,
-            "y": 41
-          },
-          "id": 21,
-          "options": {
-            "legend": {
-              "calcs": [
-                "lastNotNull"
-              ],
-              "displayMode": "table",
-              "placement": "bottom",
-              "showLegend": true
-            },
-            "tooltip": {
-              "mode": "multi",
-              "sort": "none"
-            }
-          },
-          "targets": [
-            {
-              "expr": "sum by (route, cluster) 
(rate(dxgate_http_route_failures_total[5m]))",
-              "legendFormat": "{{route}} / {{cluster}}",
-              "refId": "A"
-            }
-          ],
-          "title": "HTTP Failure Rate",
-          "type": "timeseries"
-        },
-        {
-          "datasource": {
-            "type": "prometheus",
-            "uid": "prometheus"
-          },
-          "fieldConfig": {
-            "defaults": {
-              "custom": {
-                "drawStyle": "line",
-                "fillOpacity": 10,
-                "lineWidth": 1,
-                "showPoints": "never"
-              },
-              "unit": "ms"
-            },
-            "overrides": []
-          },
-          "gridPos": {
-            "h": 8,
-            "w": 8,
-            "x": 16,
-            "y": 41
-          },
-          "id": 22,
-          "options": {
-            "legend": {
-              "calcs": [
-                "lastNotNull"
-              ],
-              "displayMode": "table",
-              "placement": "bottom",
-              "showLegend": true
-            },
-            "tooltip": {
-              "mode": "multi",
-              "sort": "none"
-            }
-          },
-          "targets": [
-            {
-              "expr": "histogram_quantile(0.95, sum by (le, route, cluster) 
(rate(dxgate_http_route_latency_ms_bucket[5m])))",
-              "legendFormat": "{{route}} / {{cluster}}",
-              "refId": "A"
-            }
-          ],
-          "title": "HTTP Upstream P95",
-          "type": "timeseries"
-        },
-        {
-          "datasource": {
-            "type": "prometheus",
-            "uid": "prometheus"
-          },
-          "fieldConfig": {
-            "defaults": {
-              "custom": {
-                "drawStyle": "line",
-                "fillOpacity": 10,
-                "lineWidth": 1,
-                "showPoints": "never"
-              },
-              "unit": "ms"
-            },
-            "overrides": []
-          },
-          "gridPos": {
-            "h": 8,
-            "w": 8,
-            "x": 0,
-            "y": 49
-          },
-          "id": 23,
-          "options": {
-            "legend": {
-              "calcs": [
-                "lastNotNull"
-              ],
-              "displayMode": "table",
-              "placement": "bottom",
-              "showLegend": true
-            },
-            "tooltip": {
-              "mode": "multi",
-              "sort": "none"
-            }
-          },
-          "targets": [
-            {
-              "expr": "histogram_quantile(0.99, sum by (le, route, cluster) 
(rate(dxgate_http_route_latency_ms_bucket[5m])))",
-              "legendFormat": "{{route}} / {{cluster}}",
-              "refId": "A"
-            }
-          ],
-          "title": "HTTP Upstream P99",
-          "type": "timeseries"
-        },
-        {
-          "datasource": {
-            "type": "prometheus",
-            "uid": "prometheus"
-          },
-          "fieldConfig": {
-            "defaults": {
-              "custom": {
-                "drawStyle": "line",
-                "fillOpacity": 10,
-                "lineWidth": 1,
-                "showPoints": "never"
-              },
-              "unit": "ops"
-            },
-            "overrides": []
-          },
-          "gridPos": {
-            "h": 8,
-            "w": 8,
-            "x": 8,
-            "y": 49
-          },
-          "id": 24,
-          "options": {
-            "legend": {
-              "calcs": [
-                "lastNotNull"
-              ],
-              "displayMode": "table",
-              "placement": "bottom",
-              "showLegend": true
-            },
-            "tooltip": {
-              "mode": "multi",
-              "sort": "none"
-            }
-          },
-          "targets": [
-            {
-              "expr": "sum by (route, cluster, status_code) 
(rate(dxgate_http_route_requests_total{status_code=~\"5..\"}[5m]))",
-              "legendFormat": "{{route}} / {{cluster}} / {{status_code}}",
-              "refId": "A"
-            }
-          ],
-          "title": "HTTP 5xx Rate",
-          "type": "timeseries"
-        },
-        {
-          "datasource": {
-            "type": "prometheus",
-            "uid": "prometheus"
-          },
-          "fieldConfig": {
-            "defaults": {
-              "custom": {
-                "drawStyle": "line",
-                "fillOpacity": 10,
-                "lineWidth": 1,
-                "showPoints": "never"
-              },
-              "unit": "ops"
-            },
-            "overrides": []
-          },
-          "gridPos": {
-            "h": 8,
-            "w": 8,
-            "x": 16,
-            "y": 49
-          },
-          "id": 25,
-          "options": {
-            "legend": {
-              "calcs": [
-                "lastNotNull"
-              ],
-              "displayMode": "table",
-              "placement": "bottom",
-              "showLegend": true
-            },
-            "tooltip": {
-              "mode": "multi",
-              "sort": "none"
-            }
-          },
-          "targets": [
-            {
-              "expr": "sum by (route, cluster, status_code) 
(rate(dxgate_http_route_requests_total{status_code=~\"401|403|429\"}[5m]))",
-              "legendFormat": "{{route}} / {{cluster}} / {{status_code}}",
-              "refId": "A"
-            }
-          ],
-          "title": "Policy Rejection Rate",
-          "type": "timeseries"
         }
       ],
       "refresh": "15s",
diff --git a/samples/addons/prometheus.yaml b/samples/addons/prometheus.yaml
index 4301ab58..17f1d459 100644
--- a/samples/addons/prometheus.yaml
+++ b/samples/addons/prometheus.yaml
@@ -64,9 +64,6 @@ data:
       scrape_interval: 15s
       evaluation_interval: 15s
 
-    rule_files:
-    - /etc/prometheus/rules/*.yaml
-
     scrape_configs:
     - job_name: prometheus
       static_configs:
@@ -106,60 +103,6 @@ data:
         target_label: app
 ---
 apiVersion: v1
-kind: ConfigMap
-metadata:
-  name: prometheus-rules
-  namespace: dubbo-system
-  labels:
-    app.kubernetes.io/name: prometheus
-    app.kubernetes.io/part-of: dubbo-observability
-data:
-  dubbo-alerts.yaml: |
-    groups:
-    - name: dubbo-observability
-      rules:
-      - alert: Dxgate5xxRateHigh
-        expr: sum by (namespace, gateway, route, cluster) 
(rate(dxgate_http_route_requests_total{status_code=~"5.."}[5m])) > 0
-        for: 5m
-        labels:
-          severity: warning
-        annotations:
-          summary: dxgate 5xx responses are increasing
-          description: dxgate is returning 5xx responses for one or more 
Gateway routes.
-      - alert: DxgateP95LatencyHigh
-        expr: histogram_quantile(0.95, sum by (le, namespace, gateway, route, 
cluster) (rate(dxgate_http_route_latency_ms_bucket[5m]))) > 1000
-        for: 10m
-        labels:
-          severity: warning
-        annotations:
-          summary: dxgate P95 latency is above 1s
-          description: Gateway upstream latency is above the sample threshold.
-      - alert: DxgateNotReady
-        expr: up{app="dxgate"} == 0
-        for: 2m
-        labels:
-          severity: critical
-        annotations:
-          summary: dxgate metrics target is down
-          description: Prometheus cannot scrape a dxgate pod or the pod is not 
ready.
-      - alert: DubbodXDSRejects
-        expr: sum(rate(dubbod_total_xds_rejects[5m])) > 0
-        for: 5m
-        labels:
-          severity: warning
-        annotations:
-          summary: xDS rejects are increasing
-          description: One or more data-plane clients rejected xDS resources 
from dubbod.
-      - alert: DubbodSDSError
-        expr: sum(rate(dubbod_sds_certificate_errors_total[5m])) > 0
-        for: 5m
-        labels:
-          severity: warning
-        annotations:
-          summary: SDS certificate errors are increasing
-          description: Workload certificate fetch or delivery is failing.
----
-apiVersion: v1
 kind: Service
 metadata:
   name: prometheus
@@ -230,17 +173,11 @@ spec:
         - name: config
           mountPath: /etc/prometheus
           readOnly: true
-        - name: rules
-          mountPath: /etc/prometheus/rules
-          readOnly: true
         - name: storage
           mountPath: /prometheus
       volumes:
       - name: config
         configMap:
           name: prometheus
-      - name: rules
-        configMap:
-          name: prometheus-rules
       - name: storage
         emptyDir: {}

Reply via email to