Herald

配置

Herald 通过一个 TOML 文件管理所有运行时配置。应用启动时读取该文件,不支持热加载——修改配置需要重启进程。

Herald 通过一个 TOML 文件管理所有运行时配置。应用启动时读取该文件,不支持热加载——修改配置需要重启进程。

配置文件加载

启动时按以下顺序决定配置文件路径:

  1. 读取环境变量 HERALD_CONFIG,如果有值则作为文件路径
  2. 未设置则默认读取 config/config.toml

代码入口在 backend/app/src/main.rs

let config_path = env::var("HERALD_CONFIG").unwrap_or("config/config.toml".to_owned());
let config = ApiConfig::load(&config_path)?;

路径可以是相对路径或绝对路径。相对路径基于进程工作目录解析,不是二进制文件所在目录。

环境变量

变量名默认值必填说明
HERALD_CONFIGconfig/config.toml配置文件路径
RUST_LOGserver.log_level 决定tracing 日志级别,优先级高于配置文件中的 log_level

RUST_LOG 在应用启动时由 tracing_subscriber::EnvFilter::try_from_default_env() 读取。如果设置了该环境变量,它会覆盖配置文件中的 log_level。没设置则回退到配置文件的值。

配置文件段

Docker 镜像内置了一份生产配置(backend/config/production.toml)。下表"代码默认值"列是配置文件中省略该字段时代码自动使用的值,"Docker 配置值"列是生产配置中显式设定的值。本地开发按需覆盖即可。

[database]

PostgreSQL 连接池配置。url 是唯一必填项,其余都有内置默认值。

参数类型代码默认值Docker 配置值必填说明
urlstringPostgreSQL 连接字符串
max_connectionsu3210050连接池最大连接数
acquire_timeout_secsu643010从连接池获取连接的超时(秒)
idle_timeout_secsu64600300空闲连接存活时间(秒)
max_lifetime_secsu6418001800单个连接最大生命周期(秒)
connect_timeout_secsu64105建立 TCP 连接的超时(秒)

连接字符串格式:postgresql://用户名:密码@主机:端口/数据库名

Docker 环境中主机名使用容器名(如 dbherald-postgres):

[database]
url = "postgresql://herald:herald@db:5432/herald"

生产环境建议根据实际并发量调整 max_connections。连接池实现基于 SeaORM 的 ConnectOptions

[redis]

参数类型代码默认值Docker 配置值必填说明
urlstringredis://127.0.0.1:6379redis://redis:6379Redis 连接地址

Redis 用于权限检查缓存和 session 存储。Docker 环境中使用容器名作为主机名。

[redis]
url = "redis://redis:6379"

[server]

HTTP 服务器和日志配置。

参数类型代码默认值Docker 配置值必填说明
bind_addressstring0.0.0.0:30000.0.0.0:3000监听地址,格式为 ip:port
log_levelstringinfoinfo日志级别(trace/debug/info/warn/error)
app_envstringproductionproduction运行环境标识

app_env 目前是一个标识字段,代码中不直接用它做分支逻辑。bind_address0.0.0.0 表示监听所有网卡。

[server]
bind_address = "0.0.0.0:3000"
log_level = "info"
app_env = "production"

[frontend]

前端应用相关的配置,主要影响 CORS 和静态文件托管。

参数类型代码默认值Docker 配置值必填说明
urlstringhttp://localhost:5173http://localhost:3000前端应用地址,用于 CORS 白名单
static_dirstring无(不托管)/app/frontend/dist静态文件目录路径,设置后由后端托管 SPA

url 在 Docker 环境中默认为 http://localhost:3000,因为后端在同一端口上同时提供 API 和前端静态文件。部署到域名时改为实际地址(如 https://your-domain.com)。

static_dir 在 Docker 镜像中默认指向 /app/frontend/dist,前端产物在构建时已打包到该路径。

[frontend]
url = "https://your-domain.com"
static_dir = "/app/frontend/dist"

[jwt]

JWT 密钥配置,用于设备码授权(RFC 8628)和第三方 OAuth 登录流程中生成访问令牌。

参数类型默认值(Docker)必填说明
secretstringJWT 签名密钥

Docker 镜像内置了一个占位值 change-me-in-production,部署时必须覆盖为安全的随机字符串。

[jwt]
secret = "your-random-base64-secret-key-here"

生成密钥示例(Linux/macOS):

openssl rand -base64 48

[observability]

OpenTelemetry 可观测性配置。整段缺省(旧配置文件没有 [observability])时也能正常解析,等价于下面的代码默认值——即 metrics 开、traces 关。

参数类型代码默认值Docker 配置值必填说明
service_namestringherald-api未设置上报到 OTLP 的服务名
otlp_endpointstringhttp://localhost:4318未设置OTLP/HTTP 端点;4318 是 OTLP HTTP 标准端口
metrics_export_interval_secsu645未设置metrics 导出周期(秒)
traces_enabledboolfalse未设置是否开启 trace 导出
sqlx_slow_statement_msu64200未设置SQL 慢查询日志阈值(毫秒),超过则记录

两点需要留意:

  • metrics 默认常开:无论 traces_enabled 如何,metrics(OTLP meter provider 加 RED 指标中间件)始终导出到 otlp_endpoint。要让指标被收集,部署侧需要在该端点有可达的 OTLP collector。
  • traces 默认关闭traces_enabled = false 是有意为之,避免 trace 导出的回压影响主线请求。设为 true 才接入 tracing registry,并在进程优雅退出时 flush。

sqlx_slow_statement_ms 控制 sqlx 的慢语句日志:执行时间超过阈值的 SQL 会被记录,用于定位慢查询。

[observability]
service_name = "herald-api"
otlp_endpoint = "http://localhost:4318"
metrics_export_interval_secs = 5
traces_enabled = false
sqlx_slow_statement_ms = 200

production.toml 没有显式设置这一段,所以 Docker 默认走上面的代码 baseline。本地若要接自己的 collector,改 otlp_endpoint 即可。

[custom_domain]

Per-Realm 自定义域名功能的全局配置。ask_key 是反代层 TLS 授权查询端点的共享密钥;cname_target 是租户需要把自定义登录域名 CNAME 到的 Herald 指定 hostname。两者驱动什么见 自定义域名指南

参数类型代码默认值Docker 配置值必填说明
ask_keystring""(空)未设置是(生产)反代层 On-Demand TLS 授权查询的共享密钥(X-Herald-Ask-Key 请求头)。启动时要求非空——启动守卫会拒绝空值。
cname_targetstring""(空)未设置展示给 Realm 管理员的 CNAME 目标 hostname(如 custom.herald.com),在自定义域名配置响应中作为 cnameTarget 返回。

两个字段在解析时均可省略(#[serde(default)]),但 ask_key 在服务端构建路径的启动阶段强制非空。生成随机密钥:

openssl rand -hex 32
[custom_domain]
ask_key = "你的随机共享密钥"
cname_target = "custom.herald.com"

如果不用自定义域名功能,把 ask_key 设为任意非空占位字符串即可满足启动守卫;授权端点仍会拒绝未注册的域名。

用户协议与隐私政策配置

每个 Realm 的用户协议和隐私政策不是写在配置文件里的,而是通过管理后台动态发布。系统初始化时会自动 seed 平台默认模板(中文草稿版,需法务审阅后替换)。

配置入口:以 Realm Admin 登录 → 管理后台 → Settings → Legal。

使用平台默认模板

如果从未发布过自定义版本,该 Realm 自动使用平台默认模板。默认模板更新时,未自定义的 Realm 会触发用户重新同意。

发布自定义版本

在 Legal Tab 的编辑框里填写《用户协议》和/或《隐私政策》的正文,支持多语言(目前为 enzh-CN)。点击发布后,该 Realm 立即切换到自定义版本,版本号递增,已同意的用户下次登录或访问核心功能时会收到重新同意提示。

回退到默认模板

如果 Realm 已经发布了自定义版本,可以点击「回退默认模板」。这不会删除历史自定义版本,而是把当前平台默认模板的内容快照成一个新的自定义版本发布。因此版本号仍然递增,用户仍然需要重新同意。

查看历史版本

Legal Tab 会列出每个协议类型的历史版本,包括版本号、生效日期、来源(默认/自定义)。历史版本用于审计追溯,不能编辑或删除。

RBAC 配置

RBAC 策略不在主配置文件中,而是通过数据库中的 role_policies 表存储。系统初始化时,RealmInitializationService 会为每个 realm 创建默认角色和权限。权限检查由 RedisPermissionChecker 完成,先查 Redis 缓存,缓存 miss 时回源 PostgreSQL。

权限模型使用 resource:action 对(如 product:readdevice:manage),通过 realm_idclient_id 确定作用域。action 有层级关系:manage 覆盖 viewcreatemanage 本身;createview 只覆盖自身。自定义 action(如 admin)只匹配自身,不参与层级。

On this page