Wang1rrr opened a new issue, #4864: URL: https://github.com/apache/rocketmq-dashboard/issues/4864
### Before Creating the Doc Report - [x] I have searched the [open issues](https://github.com/apache/rocketmq-dashboard/issues) and found no similar issue. ### Which Documentation `docs/api-spec.md` - section 4 "集群管理 Cluster / NameServer / Proxy" and the "接口速查" index. Verified against `rocketmq-studio` @ `4c697f07`. ### What Is Wrong `ProxyController` (`server/src/main/java/org/apache/rocketmq/studio/cluster/proxy/ProxyController.java`) exposes six endpoints under `/api/proxies`. The spec documents exactly one of them, and documents that one incorrectly. | endpoint | controller | 接口速查 | section 4 | | --- | --- | --- | --- | | `GET /api/proxies` | `:43` | missing | missing | | `GET /api/proxies/topology` | `:49` | missing | missing | | `POST /api/proxies/addresses` | `:54` | missing | missing | | `DELETE /api/proxies/addresses` | `:60` | missing | missing | | `POST /api/proxies/config/reload` | `:66` | missing | missing | | `POST /api/proxies/restart` | `:72` | row 17 | 4.11 - contract is wrong | **4.11 does not match the code.** It shows a single-field request body and a `{ success: boolean }` response: - The body is `RestartProxyDTO`, which has **two** `@NotBlank` fields, `clusterId` and `addr`. A caller who follows the spec sends `{"addr": "127.0.0.1:8081"}` and is rejected by bean validation with `400 clusterId is required`. - The response type is `Result<Void>`, so `data` is `null`. There is no `success` field to read. - The endpoint cannot currently succeed at all: `ClusterService.restartProxy` (`:626`) resolves the cluster, checks the address is registered, then unconditionally throws `unsupportedOperation("Proxy restart")` (`:654`) - a `501 Proxy restart is not implemented by the current cluster provider`. The console still shows a success toast (`web/src/pages/cluster/index.tsx:1722`), so the spec is the only place a reader can learn what the call really does. **The five missing endpoints carry behaviour that cannot be guessed from the paths.** Every one of these is a trap for an integrator, and all of it is only discoverable by reading three layers of Java: - **There are two unrelated notions of "proxy".** `GET /api/proxies` returns the *cluster-registered* proxies (`ClusterVO.proxies` via `ClusterService.listProxies`, no probing at all), while `/topology`, `/addresses` and `/config/reload` operate on *Studio's own in-memory address list* (`ProxyAddressService`, seeded with `127.0.0.1:8081`). `GET /api/proxies/topology` takes no `clusterId` and ignores cluster registration entirely - a reader who just called `GET /api/proxies?clusterId=x` will assume the topology is for that cluster. - **Two different status vocabularies for the same concept.** `ProxyVO.status` is `ClusterStatus` (`healthy` / `warning` / `error` / `offline`), while `ProxyTopologyVO.status` is the probe outcome (`UP` / `PARTIAL` / `DOWN`). Nothing says they are different scales. - **The probe is bounded and never fails the request.** One TCP probe per port with a 2 s timeout (`HEALTH_PROBE_TIMEOUT_MILLIS`, `:68`), all probes in parallel on a bounded pool, and a 10 s total budget (`TOPOLOGY_TOTAL_TIMEOUT_MILLIS`, `:77`). Probes that do not finish in time are reported as unreachable, so a rack full of dead proxies yields `DOWN` rows rather than a 5xx or a hung request. - **`remotingPort` is derived, not read.** `deriveRemotingPort` (`:267`) maps `8081 -> 8080` and `8080 -> 8081` and returns `null` for anything else, because the pairing cannot be assumed for custom ports. When it is `null`, `remotingReachable` is hard-`false` and only the gRPC side is probed. `latencyMs` is `-1` whenever gRPC is unreachable. - **Malformed registered addresses vanish.** `buildTopology` (`:174`) skips any address that does not match `host:port` / `[ipv6]:port` with only a server-side log line, so the response can contain fewer rows than the address list. - **Address mutation is validated and audited, and is not persisted.** `addProxyAddr` (`:274`) / `removeProxyAddr` (`:286`) normalise through `normalizeProxyAddr` (`:59` pattern, ports 1-65535, IPv6 literal checked) and raise `400` otherwise. Adding a duplicate is idempotent and does not double-record the audit entry; removing the current address moves `currentProxyAddr` to the first remaining one, or `""` when the list empties; removing an unknown address records a `FAILED` audit row and returns `404`. The whole list lives in a `LinkedHashSet` field, so a Studio restart drops every address an operator added. - **`/config/reload` is the only proxy write that actually reaches a proxy.** It requires the address to be registered under `clusterId` (`:308` -> `ClusterService.requireProxy`, `404` otherwise), then POSTs to `http://{addr}/admin/reloadConfig` (`RELOAD_PATH`, `:65`). Non-2xx and connection failures both surface as `502`, anything else as `500`, and the success and failure paths each record a `RELOAD_PROXY_CONFIG` audit entry. `{"success": true}` is the only non-exception outcome - it never answers `success: false`. ### Suggested Change Rewrite 4.11 against the code (two-field body, `data: null`, 400/404/501 error table, and a sentence saying the provider does not implement restart yet), then add the five missing endpoints as 4.12-4.16 in the format the document already uses - `**Query Parameters:**` / `**Request Body:**` tables, a `**Response data:**` field table, prose for the cross-cutting rules, and `**错误响应:**` tables. The K8s certificate sections move from 4.12-4.15 to 4.17-4.20 so the proxy endpoints stay grouped next to "重启 Proxy"; nothing else in the repository references those numbers by section (`rg -n "4\.1[2-5]" --glob '*.md'` matches only the four headings themselves). Append the five rows to the end of 接口速查 rather than inserting them at row 17, matching how rows 90-98 were appended. Deliberately **not** bundled here, so this stays one coherent change: - `ProxyCompatController` (`/api/proxy/homePage.query`, `/api/proxy/addProxyAddr.do`, `/api/proxy/removeProxyAddr.do`) is also undocumented. It is the v2.1.0 compatibility surface and deserves its own subsection. - 4.4 重启 Broker has the same defect - it documents `{ success: boolean, message: string }` while `ClusterController.restartBroker` (`:89`) returns only `message` and `ClusterService.restartBroker` (`:570`) always throws `501`. ### Are You Willing to Submit a Pull Request? - [x] Yes, I am willing to submit a pull request. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
