diagridio/dev-dashboard

GitHub: diagridio/dev-dashboard

一款面向 Dapr 开发者的本地仪表盘工具,提供应用运行时实时监控、workflow 调试以及引导式 component 和 resiliency 策略 YAML 生成能力。

Stars: 3 | Forks: 0

# Diagrid Dev Dashboard 这是一个为 Dapr 开发者提供的本地仪表盘,它提供了一个实时视图,可以展示正在你的机器上运行的所有 Dapr 实例。此外,它还提供了引导式的构建向导,用于编写 Dapr component 和 resiliency YAML。 ![Dev Dashboard - Applications](https://static.pigsec.cn/wp-content/uploads/repos/cas/8a/8ac65283654e108b408b92cdaa2fdbb4c63451a5540458c4f63af418d4b1063f.png) ![Dev Dashboard - Workflows](https://static.pigsec.cn/wp-content/uploads/repos/cas/e5/e57554ab4c0161f54c760d7905ce2918357c09a3685caea73012a9744dbde146.png) ## 目标 Diagrid Dev Dashboard 是本地 Dapr 开发的得力助手。它可以检查你通过 `dapr run` / `dapr run -f`、Aspire、Docker Compose 或 Dapr Testcontainers(例如通过 `mvn spring-boot:test-run` 和 `dapr-spring-boot-starter-test` 运行的 Spring Boot 应用)启动的应用,并展示关于它们的所有信息——sidecar、workflow、actor、订阅、component、resiliency 策略、配置和日志。 它还可以帮助你编写 Dapr 资源。**Component Builder** 会引导你从完整的 Dapr 目录中选择 component 类型,填写其 metadata 字段,并选择身份验证配置;**Resiliency Builder** 则用于组合 resiliency 策略(timeout、retry、circuit breaker)并将其应用到目标(应用、actor、component)上。这两个向导最后都会提供一个 YAML 预览,你可以将其复制或下载到你的项目中。 ## 安装说明 该仪表盘作为独立二进制文件发布在 GitHub Releases 上。 **安装(单行命令):** *macOS / Linux — 安装到 ~/.local/bin* ``` curl -sSL https://raw.githubusercontent.com/diagridio/dev-dashboard/main/scripts/install.sh | sh ``` *Windows (PowerShell) — 安装到 %LOCALAPPDATA%\Programs\diagrid-dev-dashboard* ``` iwr -useb https://raw.githubusercontent.com/diagridio/dev-dashboard/main/scripts/install.ps1 | iex ``` **如需固定特定版本,请在管道操作前设置 `VERSION`:** *macOS / Linux* ``` curl -sSL https://raw.githubusercontent.com/diagridio/dev-dashboard/main/scripts/install.sh | VERSION=vX.Y.Z sh ``` *Windows* ``` $env:VERSION='vX.Y.Z'; iwr -useb https://raw.githubusercontent.com/diagridio/dev-dashboard/main/scripts/install.ps1 | iex ``` 如果安装目录不在你的 `PATH` 中,脚本会打印出需要添加的 export 行。 **使用 Go 安装 (≥ 1.26):** ``` go install github.com/diagridio/dev-dashboard@latest ``` **手动下载:** 从 [GitHub Releases](https://github.com/diagridio/dev-dashboard/releases) 页面下载适用于你平台的压缩包,解压后,将 `diagrid-dev-dashboard`(或 `diagrid-dev-dashboard.exe`)放到你的 `PATH` 中。使用以下命令进行验证: ``` diagrid-dev-dashboard --version ``` ## 运行仪表盘 ``` # 在默认端口 (9090) 启动并自动打开浏览器 diagrid-dev-dashboard ``` ``` # 在自定义端口启动 diagrid-dev-dashboard --port 8080 ``` ``` # 启用 stderr 诊断日志(服务器启动、应用发现、state-store 连接、日志流、workflow 操作) diagrid-dev-dashboard --verbose ``` 无需额外设置:仪表盘发现正在运行的 Dapr 应用的方式与 `dapr list` 相同,因此任何通过 `dapr run` / `dapr run -f`、Aspire、Docker Compose 或 Dapr Testcontainers 启动的应用都会在一个刷新周期内显示出来。Testcontainers 应用(例如通过 `mvn spring-boot:test-run` 运行的 Spring Boot 应用)无需任何配置:仪表盘会找到由 Testcontainers 管理的 daprd 容器,将其与你的宿主机应用进程配对,甚至通过 sidecar 本身从内存中的 state store 读取 workflow。 在未设置 `--mode`/`DEVDASHBOARD_MODE`(主机使用的默认设置)的情况下,仪表盘会执行上述所有发现源的完整扫描。设置模式会将仪表盘的所有界面——应用、workflow、state store、Control Plane 视图和日志目标——限制为单一来源;过滤器是排他的,从不合并: - `--mode dapr-run` — 仅限宿主机 `dapr run` 进程(Control Plane 显示 `dapr init` 容器)。 - `--mode compose` — 仅限 Docker Compose 容器(Control Plane 显示 compose 运行的 placement/scheduler)。 - `--mode test-containers` — 仅限 Testcontainers 发现(尚无 control-plane 检测)。 - `--mode aspire` — 仅限 Aspire 资源。在由 AppHost 管理的容器内(存在 `DEVDASHBOARD_APP_*` 契约)这是下文描述的容器服务姿态;在普通宿主机上,它会将进程扫描过滤为仅由 Aspire 管理的应用。 `compose` 和 `test-containers` 需要容器运行时(docker 或 podman),如果没有则会在启动时失败。`--bind`(默认为 `127.0.0.1`,在 aspire 容器姿态下为 `0.0.0.0`)与 `--port` 一起控制监听地址。 ## 作为容器运行 (.NET Aspire) 该仪表盘还提供了容器镜像版本,专为通过 [`diagrid-labs/dashboard-aspire`](https://github.com/diagrid-labs/dashboard-aspire) 托管集成嵌入到 [.NET Aspire](https://learn.microsoft.com/dotnet/aspire/) AppHost 中而构建(该集成将根据下文的契约进行重写)。它也可以通过手写的 `docker run` 独立运行。 **镜像:** `ghcr.io/diagridio/dev-dashboard`,带有 `:X.Y.Z` 标签(与二进制发布版本保持一致)和 `:latest` 标签。预发布标签(例如 `v1.5.0-rc.1`)会发布其自己的版本标签,但不会移动 `:latest`。镜像内置了 `DEVDASHBOARD_MODE=aspire`,并在绑定到 `0.0.0.0` 的端口 `8080` 上提供服务。 在 aspire 模式下,发现机制仅限于下文的环境变量契约(没有宿主机进程扫描,也没有 Docker Compose 扫描),并且以下功能被禁用:应用生命周期控制(启动/停止/重启)、control-plane 页面、日志跟踪、自动更新/更新检查以及自动打开浏览器。 **试运行:** ``` docker run --rm -p 8080:8080 \ -e DEVDASHBOARD_APP_COUNT=1 \ -e DEVDASHBOARD_APP_0_ID=myapp \ -e DEVDASHBOARD_APP_0_DAPR_HTTP=http://host.docker.internal:3500 \ ghcr.io/diagridio/dev-dashboard:latest ``` **模式切换:** | Source | Values | Default | |---|---|---| | `--mode` flag / `DEVDASHBOARD_MODE` env | `dapr-run`, `compose`, `test-containers`, `aspire` | 未设置 (完整扫描) | **应用发现** — 每个应用对应一组 `__*` 变量,`i = 0..DEVDASHBOARD_APP_COUNT-1`: | Env var | Required | Meaning | |---|---|---| | `DEVDASHBOARD_APP_COUNT` | 是 | 应用数量(`0` 是合法的:空仪表盘) | | `DEVDASHBOARD_APP__ID` | 是 | Dapr app-id | | `DEVDASHBOARD_APP__DAPR_HTTP` | 是 | daprd HTTP 基础 URL,必须能**从仪表盘容器内**访问(例如 `http://myapp-dapr:3500`) | | `DEVDASHBOARD_APP__NAMESPACE` | 否 | 每个应用各自的 Dapr namespace;默认为 `DEVDASHBOARD_NAMESPACE`。用于**应用范围内的** workflow 操作——获取单个实例的历史记录、经过应用过滤的 workflow 列表/统计信息以及强制删除——因此这些操作会遵循应用自身的 namespace。全范围的 workflow 列表、统计信息和 app-id 下拉菜单(所有应用扫描)仍然使用全局的 `DEVDASHBOARD_NAMESPACE` | | `DEVDASHBOARD_APP__LABEL` | 否 | 显示名称;默认为 app-id。只要它与 app-id 不同,就会显示在应用列表和应用详情页眉中 | 验证在启动时采用快速失败机制:如果 `DEVDASHBOARD_APP_COUNT` 缺失或不是数字,任何必需的单应用变量缺失,或者 `DAPR_HTTP` URL 无法解析,都会退出并报错,指出具体的变量名。 **安全提示:** 在 aspire 模式下,仪表盘会放弃 loopback `Host` 检查(容器通过其 Docker 网络名称或发布的端口进行寻址)。如果没有设置 `DEVDASHBOARD_ALLOWED_HOSTS`,它会接受任何 `Host`,这意味着恶意网页利用 DNS rebinding 可以访问 API,即使该端口仅发布到 localhost。将 `DEVDASHBOARD_ALLOWED_HOSTS` 设置为提供仪表盘服务的主机名即可堵住这个漏洞(loopback 名称始终被允许)。变更请求仍然受到标准化的同源检查保护。该仪表盘是一个本地开发工具——切勿将其公开暴露。 **服务与功能:** | Env var / flag | Default (aspire) | Meaning | |---|---|---| | `DEVDASHBOARD_PORT` / `--port` | `8080` | 监听端口 | | `DEVDASHBOARD_BIND` / `--bind` | `0.0.0.0` | 绑定地址 | | `DEVDASHBOARD_STATESTORE_FILE` / `--statestore` | 未设置 | 挂载的 Dapr state-store component YAML 的路径;启用 Workflows 页面 | | `DEVDASHBOARD_NAMESPACE` / `--namespace` | `default` | 用于 workflow actor key 的默认 Dapr namespace | | `DEVDASHBOARD_RESOURCES_PATH` | `DEVDASHBOARD_STATESTORE_FILE` 的目录 | 用于 Resources 页面的额外 component 目录,由 `os.PathListSeparator` 分隔 | | `DEVDASHBOARD_ALLOWED_HOSTS` | 未设置 (任何主机) | 可选,仅适用于 aspire 模式;`Host` 标头限制为的逗号分隔主机名(始终允许 loopback)。为空表示任何主机。设置它可以堵住上述 DNS rebinding 漏洞 | | `DEVDASHBOARD_MODE` | `aspire` (内置在镜像中) | 见上文的模式切换 | 所有配置的优先级均为 **flag > env > 姿态默认值**。 ## 更新仪表盘 启动时,仪表盘会检查 GitHub 上是否有更新的版本。如果存在新版本,它会在输出的第一行打印一条通知,并且 Web UI 会在 Resources 面板的版本号旁边显示一个 **Update available** 指示器。该检查是尽力而为的:对于源码/开发版本构建会跳过此检查,并且在离线状态下会静默失败。 更新到最新版本(如果已是最新版本则无需操作) ``` diagrid-dev-dashboard update ``` 安装特定版本(可降级或重新安装) ``` diagrid-dev-dashboard update 1.2.0 ``` `update` 会下载适用于你平台的发布归档文件,根据发布版的 `checksums.txt` 验证其 SHA256,并以原子方式替换正在运行的二进制文件。请重启任何正在运行的仪表盘以使用新版本。 ## 故障排除 如果仪表盘未能按预期工作,请使用 `--verbose` 运行,以将诊断日志输出到 stderr: ``` diagrid-dev-dashboard --verbose ``` 日志按 `component=` 分组(值包括:`server`、`discovery`、`workflow`、`registry`、`reconciler`),并使用以下级别:INFO(正常里程碑)、WARN(性能下降但仍可工作,例如 state store 初始化失败)和 ERROR(操作失败,例如服务器无法绑定其端口)。如果不加 `--verbose`,则不会输出任何诊断日志。 ## 用例 开发者使用该仪表盘在本地构建时观察和调试 Dapr 应用: - **查看正在运行的内容** — 所有正在运行的应用/sidecar 的实时表格:app id、健康状态、runtime/语言、app/HTTP/gRPC 端口、daprd + app PID、运行时长以及所属的运行进程。 - **检查应用** — 深入查看单个应用的端口、PID、命令、资源/配置路径、runtime metadata、已启用的功能以及加载的 component。 - **调试 workflow** — 浏览所有应用的 workflow 执行情况,带有状态过滤器和搜索功能,然后打开一个运行实例以查看其**实时事件历史记录**、输入/输出、自定义状态,以及运行时持续跳动的挂钟时间。 - **清理 workflow** — 终止和/或清除单个或批量 workflow,并带有针对卡住/孤立状态的显式 "force delete" 回退机制。 - **查看 actor 和订阅** — 全局页面聚合了所有应用中的活动 actor 类型和 pub/sub 订阅,每个都可以链接回所属的应用。 - **读取 component 和配置** — 只读的 YAML 查看器,丰富了每个 component 是由哪些应用加载的信息;仅存在于 Testcontainers daprd 容器内的 component 也会被提取并显示,并带有以 container- 为前缀的路径。 - **构建 component YAML** — 涵盖整个 Dapr component 目录的引导向导:选择一个类型,填写其 metadata 字段(带有逐字段的文档和默认值),选择身份验证配置,然后复制或下载生成的 YAML。 - **构建 resiliency 策略** — 组合命名的 timeout、retry 和 circuit breaker,将它们应用于目标(应用、actor、component),并以 YAML 格式导出 resiliency spec。 - **管理 workflow state-store 连接** — 在 Components 页面上,最近连接面板(包含 component 文件路径)允许你添加、编辑和断开仪表盘读取 workflow 的 state store。自动检测到的 store 会自动出现;断开连接是持久化的——除非它再次成为活动 store,否则在重启后它仍保持隐藏状态。当前正在读取其 workflow 的 store 无法被移除。手动连接会保存到 `~/.dapr/dev-dashboard/connections.yaml`(模式 `0600`)。当已知多个 store 时,Workflows 页面上的选择器可让你切换浏览的 store。 - **跟踪日志** — 每个应用的 daprd + app 日志实时流式传输 (SSE),带有级别着色、关键字高和跟随开关。 该 UI 专为快速扫描和调试而构建:支持深度链接的视图,一个兼作后端连接指示器的全局自动刷新控制(在后端不可达时暂停数据轮询,并在恢复后恢复轮询),完整的键盘可操作性,以及相关实体之间的交叉导航(应用 → component → "loaded by" 应用等)。 ## 非目标 该仪表盘是一个**本地开发工具**,且仅限于此: - **不适用于 Kubernetes。** 它不打算在 Kubernetes 集群中运行。它像 `dapr list` 一样发现应用——从本地进程表和本地容器 runtime 中发现——这在集群内是没有意义的。 - **不适用于生产环境。** 它不适用于生产、预发布或任何共享/托管环境。它没有身份验证、授权或多用户模型,并且以运行它的用户的权限读取本地文件和 state store。 - **不是 control plane 或部署工具。** 它只在本地观察并帮助你编写 YAML;它不部署应用,也不管理远程的 Dapr 安装。 在你自己的机器上运行它,与你通过 `dapr run`、Aspire、Docker Compose 或 Dapr Testcontainers 启动的应用放在一起。 ## 从源码构建 **前置条件:** Go ≥ 1.26 和 Node.js 20(带有 `npm`)。二进制文件通过 `go:embed` 嵌入了 React SPA,因此 Web 资源 (`web/dist`) 必须在 Go 二进制文件**之前**构建——`make build` 会按正确的顺序执行这两项操作。 **macOS / Linux:** ``` make build # builds web/dist, then the Go binary at bin/diagrid-dev-dashboard ./bin/diagrid-dev-dashboard ``` 等效的手动步骤(如果你没有 `make`): ``` cd web && npm install && npm run build && cd .. go build -o bin/diagrid-dev-dashboard . ./bin/diagrid-dev-dashboard ``` **Windows (PowerShell):** 通常没有 `make` 可用,因此请直接运行以下步骤: ``` cd web; npm install; npm run build; cd .. go build -o bin/diagrid-dev-dashboard.exe . .\bin\diagrid-dev-dashboard.exe ``` 要为子路径挂载进行构建,请在构建之前设置 `DASH_BASE_PATH`(参见[在子路径下挂载](#mounting-under-a-sub-path))。在 Windows 上,即在 `npm run build` 步骤之前设置 `$env:DASH_BASE_PATH='/dashboard/'`。 其他有用的目标:`make test`(Go 单元测试 + web 测试套件)、`make test-go`、`make test-web`、`make test-integration`、`make test-e2e`、`make tidy`。 ### 针对真实的 workflow 应用进行测试 该仪表盘是一个**被动观察者**:它像 `dapr list` 一样发现你的应用,并直接从你的 Dapr **state store** 读取 workflow 数据。你不需要将它指向你的应用——你只需在同一台机器上运行两者即可。 **前置条件:** - 已运行 `dapr init`。这会创建 `~/.dapr/components/statestore.yaml`(一个带有 `actorStateStore: "true"` 的 Redis store)并启动 Redis。这个 `actorStateStore` 就是 Dapr Workflows 持久化保存的地方,也是仪表盘读取的内容。 - 一个 Dapr workflow 应用——例如 [Dapr Workflow 快速入门](https://github.com/dapr/quickstarts/tree/master/workflows),或任何使用 Workflow API 的应用。 **步骤:** 1. 使用 Dapr 运行你的 workflow 应用(在应用所在的目录下): dapr run --app-id order-processor --app-port 6001 -- <你的应用启动命令> # 或者,对于多应用项目: dapr run -f . 2. 触发至少一个 workflow 实例(通过应用的 endpoint / 快速入门流程)。仪表盘仅显示已经存在的状态——空闲的 store 会显示一个空列表。 3. 启动你的源码构建版本: ./bin/diagrid-dev-dashboard # 打开 http://localhost:9090 4. 在 UI 中:**Apps** 表格会显示你的应用(健康状态、端口、PID);**Workflows** 页面会列出从 state store 读取的实例——打开一个以查看其实时事件历史记录、输入/输出、状态和跳动的挂钟时间。你也可以终止/清除实例(带有 force-delete 回退机制)。 **如果 Workflows 页面为空:** 仪表盘会自动检测 `~/.dapr/components` 和正在运行的应用的实时 `--resources-path` 中的 state-store component,然后使用标记为 `actorStateStore: "true"` 的那个(如果回退,则使用第一个检测到的)。请检查: - 如果检测结果有歧义(有多个 store),可以使用 Workflows 页面上的 store 选择器选择一个,或者明确指定: `./bin/diagrid-dev-dashboard --statestore ~/.dapr/components/statestore.yaml`。你也可以通过 Components 页面上的连接管理器手动添加 store。 - Workflow key 是有命名空间的;仪表盘默认使用 `default`。对于其他 namespace,请传入 `--namespace `。 - 只有 **Redis / PostgreSQL / SQLite** state store 可以直接打开。仪表盘无法打开其 store 的应用(例如 `state.in-memory`,或者其 store 位于容器内的 Testcontainers 应用)将**通过其 sidecar 的 gRPC workflow API** 提供服务——这需要 Dapr ≥ 1.17,并且仅在 sidecar 运行时有效。 - 确认应用确实持久化了 workflow(空的 store → 空的列表)。 **Testcontainers 应用**(例如通过 `mvn spring-boot:test-run` 运行的 Java 快速入门)不需要上述任何 store 设置:workflow、component 和应用详情全都来自 Testcontainers 管理的 sidecar 本身。 ## 测试 共有四个测试套件:Go **单元**测试、Go **集成**测试、**Web**(前端)测试,以及一个可选参与的 Go **端到端 (e2e)** 套件。单元测试、集成测试和 Web 测试套件是自包含的——不需要 Docker 或外部服务(集成测试通过 `miniredis` 运行进程内 Redis,并使用临时的 SQLite 数据库)。**端到端 (e2e)** 套件驱动一个真实的 `daprd,并且仅在本地运行——如果未安装 Dapr,它会自动跳过(见下文)。 **前置条件:** Go ≥ 1.26(Go 测试)和带有 `npm` 的 Node.js 20(Web 测试)。 **运行所有测试 (macOS / Linux):** ``` make test # Go unit tests (with -race) + web tests ``` `make test` 会先运行 `make test-go`,然后运行 `make test-web`。它**不会**运行 Go 集成测试——需要单独运行(见下文)。 **Go 单元测试** — 受 `//go:build unit` 控制: ``` make test-go # = go test -tags unit -race ./... # 或者直接: go test -tags unit ./... go test -tags unit -race ./cmd/... # one package, with the race detector ``` (如果安装了 `gotestsum`,`make test-go` 会使用它来获得更好的输出,否则使用普通的 `go test`。) **Go 集成测试** — 受 `//go:build integration` 控制;它们针对进程内 Redis (`miniredis`) 和临时 SQLite DB 运行,测试 state-store 和 workflow 读取路径、解析后的 sidecar `/v1.0/metadata` 以及完整组装的 HTTP 服务器,因此不需要外部服务。它们在 CI 中运行,但不属于 `make test` 的一部分: ``` make test-integration # = go test -tags integration -race ./... # 或者直接: go test -tags integration ./... ``` 一些集成测试使用 golden 文件(`testdata/golden/*`);在有意修改结构后,使用 `-update` 重新生成它们,例如 `go test -tags integration ./pkg/workflow -run Golden -update`。 **Go e2e 测试** — 受 `//go:build e2e` 控制;它们在 `dapr run` 下运行一个真实的 Dapr workflow 应用,并通过仪表盘自身的包读回其状态,与由实时 runtime 生成的状态进行验证。它们需要安装本地 Dapr (`dapr init`)——你的 `PATH` 上有 `dapr` 并且 `PATH` 或 `~/.dapr/bin` 中有 `daprd`——如果找不到 Dapr,它们会**自动跳过**。它们仅在本地运行,不会在 CI 中运行: ``` make test-e2e # = go test -tags e2e ./... ``` **Web 测试** — Vitest: ``` make test-web # = cd web && npm install && npm test (vitest run) # 或者从 web/: cd web npm install npm test # single run npm run test:watch # watch mode ``` **Windows (PowerShell)** — 通常没有 `make` 可用,因此请直接运行命令: ``` go test -tags unit -race ./... go test -tags integration ./... cd web; npm install; npm test; cd .. ``` ## 代码检查 ``` make lint # lint-go (gofmt + go vet) + lint-web (eslint) make lint-go # = gofmt check + go vet -tags unit ./... make lint-web # = cd web && npm install && npm run lint (eslint .) ``` Go 检查(`gofmt`、`go vet`)和 Web `eslint` 会在每次推送和 Pull Request 时在 CI 中运行。 **Pre-commit 钩子(可选):** 安装一个钩子,在每次提交之前只对你暂存的文件进行 Lint 检查: ``` make hooks # symlinks .git/hooks/pre-commit -> scripts/pre-commit ``` 它会对暂存的 Go 文件运行 `gofmt`/`go vet`,对暂存的 `web/` 文件运行 `eslint`。对于单次提交,可以通过 `git commit --no-verify` 绕过它。 ## 发布 因为 `go install` 无法运行 `npm`,所以发布标签提交必须嵌入预构建的 `web/dist`。`scripts/release.sh` 负责处理此问题:它构建 SPA,创建一个**分离的 (detached)** 提交,该提交强制添加 `web/dist`(绕过 `.gitignore`),对其进行标记,然后返回到你的分支——这样标记的提交就为 `go install` 提供了完整的 UI,同时 `main` 分支保持没有构建产物。 **发布版本 (macOS / Linux,或 Windows 上的 Git Bash / WSL —— `release.sh` 是一个 POSIX `sh` 脚本):** 1. 确保处于最新的 `main` 分支上,并且具有干净的工作区。 2. 构建 + 标记发布版本: scripts/release.sh vX.Y.Z 它将构建 SPA,在嵌入 UI 的分离提交上创建标签,并打印推送命令。 3. 推送标签以触发发布工作流: git push origin vX.Y.Z 4. 等待 `release` 工作流完成。它将发布一个 GitHub Release,包含每个平台的一个压缩包 + `checksums.txt`。此后,单行安装命令和 `go install github.com/diagridio/dev-dashboard@vX.Y.Z` 将解析为新版本。 **在标记之前在本地验证(可选,需要 GoReleaser v2):** ``` make release-check # validate .goreleaser.yaml make release-snapshot # build a local snapshot into dist/ without publishing ``` ## 架构 该仪表盘是一个**单一的 Go 二进制文件**,它嵌入了 React SPA,并与你的本地 Dapr sidecar 和 state store 通信。 ``` ┌───────────────────────────────────────────────────────────────┐ │ diagrid-dev-dashboard (single Go binary) │ │ │ │ cmd/ cobra root, flags, serve boot, │ │ connection registry + reconciler │ │ pkg/server chi router + go:embed SPA │ │ pkg/discovery standalone.List() + /v1.0/metadata │ │ pkg/workflow list / history / purge │ │ pkg/statestore client (redis / postgres / sqlite) │ │ pkg/controlplane docker/podman inspect + lifecycle │ │ pkg/metadata component metadata catalog │ │ pkg/resources component + configuration YAML loader │ │ pkg/logs file tail → SSE │ │ web/ React + Vite SPA → dist/ (embedded) │ └───────────────────────────────────────────────────────────────┘ │ HTTP /v1.0/* │ files / TCP │ docker/podman ▼ ▼ ▼ running daprd ~/.dapr, resource paths, control-plane sidecars state store backend containers ``` **组件** - **后端 (Go + `chi`)** — 暴露 REST + JSON API(带有用于日志/流式跟踪的 SSE),并为嵌入的 SPA 提供服务。每个域都位于一个隔离的 `pkg/*` 包中(一个 `service.go` 及其响应类型);HTTP 层位于 `pkg/server` 中,每个域一个文件。没有任何域包依赖于 `cmd/`。 - **前端 (React + TypeScript + Vite)** — 一个构建为静态资产并通过 `go:embed` 嵌入到二进制文件中的单页应用。使用 **TanStack Query** 进行轮询/缓存,使用内部样式化的无头可访问原语,以及自定义的轻量级只读 YAML 高亮显示器(非 Monaco)。客户端 History-API 路由 (`react-router-dom`);Go 服务器对于未知路径回退到 `index.html`,并且支持 base-path。计划实现列表虚拟化,但在 v1 中尚未实现。UI 样式约定(design token、页面剖析、component 类)记录在 [`web/STYLEGUIDE.md`](web/STYLEGUIDE.md) 中。 **关键依赖项和数据源** - **应用发现**重用了 `github.com/dapr/cli/pkg/standalone`(与 `dapr list` 的机制相同)。`standalone.List()` 读取本地进程表,是存在性/端口/PID 的事实来源;每个 sidecar 的 **`/v1.0/metadata`** 调用是数据增强(runtime 版本、component、actor、订阅、扩展的 metadata),并在 sidecar 宕机时优雅降级。每个 sidecar 的 **`/v1.0/healthz`** 检查用于驱动健康徽章——在每次 `/api/apps` 获取期间按需计算(没有单独的后台轮询器),因此其刷新节奏遵循 UI 的自动刷新间隔。第二个扫描器通过检查 compose 标记的容器(来自 daprd argv 的 app id 和端口,从容器 runtime 流式传输的日志)发现运行在 **docker compose** 下的 Dapr 应用。第三个扫描器发现 **Dapr Testcontainers** 会话(带有 `org.testcontainers` 标签的 daprd 容器,例如来自 `dapr-spring-boot-starter-test`):随机发布的 HTTP/gRPC 端口会在每次轮询时重新读取,宿主机应用进程通过应用端口进行配对(真实的 PID、uptime、runtime),并且从容器中提取在测试配置中声明的 component YAML,以便它显示在 Components 页面上。所有来源都被合并,因此一个来源失败绝不会隐藏其他来源。 - **Workflow** 从检测到的 **state store 后端**(Redis / PostgreSQL / SQLite)读取;客户端是根据自动检测到的 component YAML 构建的。当仪表盘无法打开应用的 store 时——Testcontainers 应用(其 store 位于容器内,包括 `state.in-memory`),或者在无法打开任何 store 时的任何应用——workflow 将改为从 **sidecar 的 gRPC workflow API (Dapr ≥ 1.17) 实时读取(按应用)。Purge 在可访问时使用官方的 Dapr workflow API,并以直接进行 state-store key 删除作为显式的强制回退。 - **连接注册表** — 仪表盘可以读取的 state store 在注册表中进行跟踪:自动检测到的 component 引用以及在 UI 中添加的任何连接,持久化到 `~/.dapr/dev-dashboard/connections.yaml`(模式 `0600`)。`pkg/metadata` 目录驱动添加/编辑表单,workflow 后端延迟连接(按需)到选定的 store,并且 `secretKeyRef` metadata 通过本地 secret store(`secretstores.local.file` / `secretstores.local.env`)解析。 - **资源**(component + 配置)从 `~/.dapr` 和从 daprd 参数读取的实时 `--resources-path` 目录加载。 - **日志**从 `~/.dapr/logs/*` 和扩展 metadata 中报告的 `appLogPath`/`daprdLogPath` 中进行跟踪,然后通过 SSE 流式传输到 SPA。 - **Control plane** 通过解析后的容器 runtime(`docker`,否则为 `podman`)进行检查:`dapr_scheduler` / `dapr_placement` 是仪表盘可以启动/重启/停止的自托管容器(仅限于这些白名单名称)。容器日志通过 `docker logs -f` 在 SSE 上流式传输。 - **新闻**(可选)— Resources 侧边栏拉取 Diagrid 产品提要,通过后端自身的 `GET /api/news` endpoint 进行代理和缓存,因此 SPA 永远只与其自身的源通信。 **可移植性** — 所有逻辑都位于 `pkg/*` 域包中,不依赖 `cmd/`,服务器作为 `chi` 子路由器挂载,SPA 是一个嵌入式的 `fs.FS`,因此整个系统以后可以重新挂载到 `diagrid dashboard` 子命令下。 有关完整的架构和扩展指南,请参见 [ARCHITECTURE.md](ARCHITECTURE.md);有关最初的设计原理,请参见 [`docs/superpowers/specs/2026-06-25-dev-dashboard-design.md`](docs/superpowers/specs/2026-06-25-dev-dashboard-design.md)。 ## 贡献 欢迎贡献!请参阅 [CONTRIBUTING.md](CONTRIBUTING.md) 了解如何报告问题、设置开发环境以及提交 Pull Request。所有提交必须根据[开发者原产地证明](https://developercertificate.org/)进行签署(`git commit -s`)。 ## 许可证 版权所有 © Diagrid Inc。根据 [Apache License 2.0](LICENSE) 授权。
标签:Dapr, SOC Prime, 可视化面板, 开发工具, 日志审计, 自动化攻击, 请求拦截, 运维监控