docs: v0.2.4 阶段三 文档、示例配置与发布说明

文档与配置同步 v0.3.0 的破坏性变更:

README.md:
- 特性列表更新:管理入口 /dashboard、凭证分离、默认无匿名监控端点
- 环境变量表补充 METRICS_ALLOW_CIDR,并说明未配任何管理凭证时服务拒绝启动
- 端点文档重写:/healthz(匿名且不含字段)、/health(需鉴权)、
  /metrics(默认 404,两种使用方式)、管理页面与安装页对照表
  (含"页面需鉴权为何又能直接打开"的内容协商说明)
- 公网部署安全清单重写:按端点列出真实暴露面,并提醒探针必须指向 /healthz
- 故障排查、架构表、迁移表中的 /admin 引用统一改为 /dashboard

.env.example:新增 METRICS_ALLOW_CIDR 与 admin_key 说明(含 Docker 网段警告)。

两处部署陷阱修复(阶段一给 /health 加鉴权引发的连带问题):
- docker-compose.yml 的 healthcheck 原指向 /health,加鉴权后会一律 401,
  导致容器被判定为 unhealthy → 改为 /healthz
- Dockerfile 的 HEALTHCHECK 同样指向 /health → 改为 /healthz
  (这两处若不改,升级后容器健康状态会持续异常,且现象与鉴权改动看起来无关,排查成本高)

新增 docs/RELEASE_NOTES_v0.3.0.md:可直接用于创建 Release,
含 Breaking Change 清单、新特性、验证方式与实测结果、升级步骤。

docs/IMPLEMENT_v0.3.0.md:
- 按合并后的阶段编号重写实施进度表与阶段标题
  (原「阶段 1 收紧鉴权」与「阶段 2 收口端点」合并为「阶段 1」,后续顺延),
  并说明合并原因:两者只做前者是"有风险无收益"
- 记录本轮实际验证结果

验证:go build / go vet / go test ./... -count=1 全绿。
This commit is contained in:
sun
2026-10-04 01:17:43 +08:00
parent 5113941f44
commit 94b3557c7e
6 changed files with 719 additions and 41 deletions
+140
View File
@@ -0,0 +1,140 @@
# v0.3.0 Release Notes
> 发布日期:待定 · 基线:`develop`
> 主题:**路由鉴权架构升级 · 健康与指标端点收口 · 管理入口统一**
---
## 一句话概括
v0.3.0 把**默认对外的监控面收窄到只有一个匿名存活探针**,
并把**管理凭证与业务调用凭证拆开**,同时把管理入口统一到 `/dashboard`。
业务接口 `/v1/audio/speech` 行为不变。
---
## ⚠️ Breaking Changes(升级前必读)
### 1. 监控端点不再匿名可读
| 端点 | v0.2.x | v0.3.0 |
|---|---|---|
| `/healthz` | 不存在 | **匿名可读**,只回 `200 ok`(不含任何字段) |
| `/health` | 匿名,返回完整健康数据 | **需管理凭证**,否则 401 |
| `/metrics`(根路径) | 匿名 | **默认 404**;需配置 `METRICS_ALLOW_CIDR` 才注册 |
| `/dashboard` | 匿名(服务状态预览页) | **需鉴权**(且已成为管理看板,见第 3 条) |
| `/api/setup/status` | 匿名 | **需管理凭证** |
**你需要做的**:
- **K8s 探针 / Docker HEALTHCHECK** 改指 **`/healthz`**。
继续指向 `/health` 会一律 401 → Pod 反复重启 / 容器被判 unhealthy。
(本仓库的 `docker-compose.yml` 与 `Dockerfile` 已同步修改。)
- **Prometheus** 二选一:
- 改用鉴权版 `/api/admin/metrics`,并在 `scrape_configs` 配
`authorization: { credentials: <管理凭证> }`;
- 或配置 `METRICS_ALLOW_CIDR` 走根路径白名单。
⚠️ Docker 中**不要填 `127.0.0.1/32`**(那是容器自身回环),
请填容器内网网段,例如 `172.16.0.0/12`。
### 2. 未配置管理凭证时服务拒绝启动
`RequireAdmin` 此前在凭证列表为空时**直接放行**(等于管理接口完全裸奔)。
现在该情况返回 401;并且 **normal 模式下若 `admin_key` / `auth_key` /
`OPENAI_TTS_API_KEY` 三者皆为空,服务将 fail-fast 拒绝启动**。
**你需要做的**:升级前确认三者至少配置一个,否则服务起不来。
### 3. 管理入口从 `/admin` 迁至 `/dashboard`
- `/dashboard`、`/dashboard/voices`、`/dashboard/settings` 为新入口
- 详细服务状态页迁至 **`/dashboard/status`**(原 `/dashboard` 是状态预览页)
- `/admin` 及子路径 **301 永久重定向**到对应新路径,书签与脚本请尽快迁移
### 4. 管理 API 正式路径改为 `/api/admin/*`
- 新:`/api/admin/voices`、`/api/admin/settings`(含 `api-key` / `auth-key` / `admin-key`)
- 旧:`/api/voices`、`/api/settings` **仍可用**(**别名**,不是重定向),计划后续版本移除
> 为什么用别名而不是 308:301 会把 `POST`/`PUT`/`PATCH`/`DELETE` 降级成 `GET`
> 且被浏览器永久缓存;308 虽保留方法,但对非浏览器脚本仍是行为变化。
> 别名零往返、零破坏,老脚本完全无感。
---
## ✨ 新特性
### 独立管理凭证 `admin_key`
管理后台登录凭证与业务调用凭证分离。取值优先级:
```
admin_key(DB) → auth_key(DB) → OPENAI_TTS_API_KEY(env)
```
- **不配置**:回退使用 `auth_key`,**行为与 v0.2.x 完全一致**
- **配置后**:业务调用方持有的 `auth_key` **无法访问管理接口**(返回 401)
配置方式:`PUT /api/admin/settings/admin-key`,或在 `/dashboard → 设置` 中操作。
凭证**只写不读** —— `GET /api/admin/settings` 只返回打码值与来源标记。
### 内网 CIDR 白名单 `METRICS_ALLOW_CIDR`
逗号分隔,支持裸 IP 自动补掩码。非白名单来源返回 **404**(而非 403,
避免向扫描者确认端点存在)。未配置时根路径 `/metrics` **完全不注册**。
### 匿名存活探针 `/healthz`
刻意**不返回任何字段**(无版本、无内存、无配置状态、无模式),只回答"进程还在不在"。
运维要细节请走鉴权后的 `/health` 或 `/api/admin/health`。
---
## 🔧 修复
- `RequireAdmin` 空凭证放行(安全缺口,见 Breaking Change 第 2 条)
- `/api/setup/status` 在 normal 模式下仍匿名暴露 `{installed, mode}`
- `docker-compose.yml` / `Dockerfile` 的健康检查端点(随鉴权改动失效)
- 指标写入对空接收者安全(`nil *Counter` / `*Gauge` / `*Histogram` 不再 panic)
- 上游 `HTTPClient` 未初始化时返回错误而非 panic
---
## ✅ 验证方式
```bash
go build ./...
go vet ./...
go test ./... -count=1
```
> 注意:本仓库测试源码**不入库**(`.gitignore` 的 `*_test.go`),
> 干净克隆上 `go test` 只会打印 `no test files`。
> 自动化测试需在开发机(测试文件所在处)执行。
> 发布前请按 [IMPLEMENT_v0.3.0.md](IMPLEMENT_v0.3.0.md) 第 3 节逐条手工回归。
端到端实测结果(真实服务器):
| 检查 | 结果 |
|---|---|
| `/healthz` 匿名 | `200` + 字面量 `ok` |
| `/health` 无凭证 / 带凭证 | `401` / `200` |
| 根 `/metrics` 未配 CIDR | `404`(不注册) |
| `/admin`、`/admin/login`、`/admin/voices`、`/admin/settings` | 全部 `301` 至对应 `/dashboard/*` |
| `/dashboard*` 浏览器请求 / 脚本请求 | `200` 页面外壳 / `401` |
| `/api/admin/*` 与 `/api/*` 别名 | 均 `200`(无 301/308) |
| 配独立 `admin_key` 后业务 key 访问管理接口 | `401` |
| 业务接口 `/v1/audio/speech` | 行为不变 |
---
## 📦 升级步骤
1. 确认已配置 `admin_key` / `auth_key` / `OPENAI_TTS_API_KEY` 至少一个
2. 更新探针指向 `/healthz`
3. 更新 Prometheus 抓取配置(鉴权版或 `METRICS_ALLOW_CIDR`)
4. 替换镜像 / 二进制并重启
5. 访问 `/dashboard` 登录验证;确认旧 `/admin` 书签仍能自动跳转
6. 按需在 `/dashboard → 设置` 配置独立 `admin_key`
**无需数据库迁移** —— 旧的 `tts.db` 可直接复用。