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。


## 目标
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, 可视化面板, 开发工具, 日志审计, 自动化攻击, 请求拦截, 运维监控