Release 管理 API
管理项目的 Release(对外发布的 API 集合),包括 Release CRUD、别名管理和版本管理。
基础路径
/projects/:projectId/releases认证方式
本模块路由使用 combinedAuth 中间件。未特别标注的端点可使用 JWT、API Key 或 Agent Token;以下四个变更端点仅允许 JWT Bearer Token 或 API Key,Agent Token 会返回 403:
- 更新 Release
- 删除 Release
- 设置别名
- 删除别名
权限说明
未特别标注的端点沿用各路由现有的项目访问检查。上述四个变更端点额外要求调用者拥有 project:write 权限:项目可见但没有写权限时返回 403,项目不存在或调用者不可见时返回 404。
术语说明
| 术语 | 说明 |
|---|---|
| Release | 对外发布的完整 API 集合 |
| Alias | Release 的人类可读别名(如 my-app),用于构建访问 URL |
| Version | Release 的版本快照,支持发布/废弃/下线生命周期 |
| Deployment | 文档的部署版本,可绑定到 Release 端点 |
一、Release 管理
1. 获取项目的 Release
GET /projects/:projectId/releases获取项目关联的 Release 信息。
Path 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
projectId | string | 是 | 项目 ID |
响应 200
{
"release": {
"id": "uuid",
"project_id": "uuid",
"name": "My API",
"alias": "my-api",
"content": { ... },
"created_at": "2026-01-01T00:00:00Z"
}
}如果项目没有 Release,返回 { "release": null }。
错误码
| 状态码 | 说明 |
|---|---|
| 401 | 未认证 |
| 404 | 项目不存在或无权访问 |
| 500 | 操作失败 |
2. 创建 Release
POST /projects/:projectId/releases为项目创建一个新的 Release。
Path 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
projectId | string | 是 | 项目 ID |
Body 参数(JSON)
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
name | string | 是 | Release 名称 |
响应 201
{
"release": { ... }
}错误码
| 状态码 | 说明 |
|---|---|
| 401 | 未认证 |
| 404 | 项目不存在或无权访问 |
| 409 | 别名冲突 |
| 500 | 操作失败 |
3. 更新 Release 内容
PUT /projects/:projectId/releases/:releaseId更新 Release 的配置内容,包括端点配置、鉴权设置等。
认证与权限:仅 JWT/API Key;需要 project:write。Agent Token 或项目可见但缺少写权限时返回 403。
Path 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
projectId | string | 是 | 项目 ID |
releaseId | string | 是 | Release ID |
Body 参数(JSON)
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
content | ReleaseDocumentContent | 是 | Release 配置内容 |
校验规则:
- 关闭鉴权(
requireAuth === false)时,必须指定apiKeyId - 端点级跳过鉴权(
skipAuth === true)时,必须有端点级或全局apiKeyId
响应 200
{
"release": { ... }
}错误码
| 状态码 | 说明 |
|---|---|
| 400 | content 缺失、鉴权配置不合法 |
| 401 | 未认证 |
| 403 | Agent Token,或项目可见但缺少 project:write 权限 |
| 404 | 项目不存在、调用者不可见或 Release 不存在 |
| 409 | 别名冲突 |
| 500 | 操作失败 |
4. 删除 Release
DELETE /projects/:projectId/releases/:releaseId删除指定的 Release。
认证与权限:仅 JWT/API Key;需要 project:write。Agent Token 或项目可见但缺少写权限时返回 403。
Path 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
projectId | string | 是 | 项目 ID |
releaseId | string | 是 | Release ID |
响应 200
{
"success": true
}错误码
| 状态码 | 说明 |
|---|---|
| 401 | 未认证 |
| 403 | Agent Token,或项目可见但缺少 project:write 权限 |
| 404 | 项目不存在、调用者不可见或 Release 不存在 |
| 500 | 操作失败 |
二、别名管理
5. 检查别名可用性
GET /projects/:projectId/releases/check-alias/:alias检查指定别名是否可用。
Path 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
projectId | string | 是 | 项目 ID |
alias | string | 是 | 要检查的别名 |
响应 200
返回别名可用性检查结果。
错误码
| 状态码 | 说明 |
|---|---|
| 401 | 未认证 |
| 404 | 项目不存在或无权访问 |
| 409 | 别名已被占用 |
| 500 | 操作失败 |
6. 设置别名
POST /projects/:projectId/releases/:releaseId/alias为 Release 设置别名。别名用于构建对外访问 URL。
认证与权限:仅 JWT/API Key;需要 project:write。Agent Token 或项目可见但缺少写权限时返回 403。
Path 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
projectId | string | 是 | 项目 ID |
releaseId | string | 是 | Release ID |
Body 参数(JSON)
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
alias | string | 是 | 别名。只允许小写字母、数字和连字符,格式匹配 /^[a-z0-9][a-z0-9-]*[a-z0-9]$/ 或单字符 /^[a-z0-9]$/ |
响应 200
{
"success": true,
"alias": "my-api"
}错误码
| 状态码 | 说明 |
|---|---|
| 400 | alias 缺失或格式不合法 |
| 401 | 未认证 |
| 403 | Agent Token,或项目可见但缺少 project:write 权限 |
| 404 | 项目不存在、调用者不可见或 Release 不存在 |
| 409 | 别名已被其他 Release 占用 |
| 500 | 操作失败 |
7. 删除别名
DELETE /projects/:projectId/releases/:releaseId/alias删除 Release 的别名。
认证与权限:仅 JWT/API Key;需要 project:write。Agent Token 或项目可见但缺少写权限时返回 403。
Path 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
projectId | string | 是 | 项目 ID |
releaseId | string | 是 | Release ID |
响应 200
{
"success": true
}错误码
| 状态码 | 说明 |
|---|---|
| 401 | 未认证 |
| 403 | Agent Token,或项目可见但缺少 project:write 权限 |
| 404 | 项目不存在、调用者不可见或 Release 不存在 |
| 500 | 操作失败 |
三、Deployment 列表
8. 获取 Deployment 列表
GET /projects/:projectId/releases/deployments获取项目下的 Deployment 列表,用于端点绑定选择。
Path 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
projectId | string | 是 | 项目 ID |
响应 200
{
"deployments": [
{
"id": "uuid",
"title": "文档标题",
"version": "1.2",
"documentId": "uuid",
"visibility": "public",
"createdAt": "2026-01-01T00:00:00Z"
}
]
}错误码
| 状态码 | 说明 |
|---|---|
| 401 | 未认证 |
| 404 | 项目不存在或无权访问 |
| 500 | 查询失败 |
四、版本管理
9. 创建版本
POST /projects/:projectId/releases/:releaseId/versions创建版本快照(快照当前 Release 内容)。
Path 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
projectId | string | 是 | 项目 ID |
releaseId | string | 是 | Release ID |
响应 201
{
"version": {
"id": "uuid",
"version": "1.0",
"status": "draft",
"created_at": "2026-01-01T00:00:00Z"
}
}错误码
| 状态码 | 说明 |
|---|---|
| 401 | 未认证 |
| 404 | 项目不存在、无权访问、Release 不存在或 ID 不匹配 |
| 500 | 操作失败 |
10. 列出版本
GET /projects/:projectId/releases/:releaseId/versions获取 Release 的所有版本列表。
Path 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
projectId | string | 是 | 项目 ID |
releaseId | string | 是 | Release ID |
响应 200
{
"versions": [
{
"id": "uuid",
"version": "1.0",
"status": "published",
"published_at": "2026-01-01T00:00:00Z"
}
]
}错误码
| 状态码 | 说明 |
|---|---|
| 401 | 未认证 |
| 404 | 项目不存在、无权访问、Release 不存在或 ID 不匹配 |
| 500 | 操作失败 |
11. 发布版本
POST /projects/:projectId/releases/:releaseId/versions/:versionId/publish校验版本可执行性,生成脱敏 REST/OpenAPI 静态缓存,并以一次原子更新将版本设为已发布。无论 private、unlisted 还是 public 都会生成缓存;文档缓存不会包含内部工作流或字段映射。
输出字段类型的补齐:输出映射的 type 定义上是「从绑定的部署输出继承」。若配置里该字段缺失, 发布时会从绑定源的 variableType 取回来,并把补齐后的配置随本次发布一起落库。 绑定源也给不出类型时返回 400,提示重新选择该字段的输出绑定来源——不会猜一个类型顶上, 猜出来的类型会被固化进对外 API 文档。
Path 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
projectId | string | 是 | 项目 ID |
releaseId | string | 是 | Release ID |
versionId | string | 是 | 版本 ID |
Body 参数(JSON,可选)
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
releaseNotes | string | 否 | 对外发布说明,trim 后最多 4000 字符 |
响应 200
{
"success": true,
"docs": {
"visibility": "public",
"alias": "my-api",
"version": "1.0.0",
"publisher": {
"name": "Example Team",
"slug": "example-team",
"isOfficial": false
}
}
}错误码
| 状态码 | 说明 |
|---|---|
| 400 | 发布前校验不通过:非 draft 状态、alias 无效、releaseNotes 超长、端点绑定/输入输出映射有问题(含输出字段缺类型且无法从绑定源继承) |
| 401 | 未认证 |
| 404 | 项目不存在、无权访问或版本不存在 |
| 500 | 操作失败 |
12. 废弃版本
POST /projects/:projectId/releases/:releaseId/versions/:versionId/deprecate将版本标记为已废弃。仅允许对 published 版本操作 —— 「废弃」的语义前提是它曾经对外可用, 从未发布过的草稿不能被废弃(详见下方「版本状态机」)。
Path 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
projectId | string | 是 | 项目 ID |
releaseId | string | 是 | Release ID |
versionId | string | 是 | 版本 ID |
响应 200
{
"success": true
}错误码
| 状态码 | 说明 |
|---|---|
| 400 | 状态流转非法(如草稿直接废弃、已下线回退),或版本状态被并发修改需重试 |
| 401 | 未认证 |
| 404 | 项目不存在、无权访问或版本不存在 |
| 500 | 操作失败 |
13. 下线版本
POST /projects/:projectId/releases/:releaseId/versions/:versionId/offline将版本设为下线状态。仅允许对 published 或 deprecated 版本操作(详见下方「版本状态机」)。
Path 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
projectId | string | 是 | 项目 ID |
releaseId | string | 是 | Release ID |
versionId | string | 是 | 版本 ID |
响应 200
{
"success": true
}错误码
| 状态码 | 说明 |
|---|---|
| 400 | 状态流转非法(如草稿直接下线、已下线重复下线),或版本状态被并发修改需重试 |
| 401 | 未认证 |
| 404 | 项目不存在、无权访问或版本不存在 |
| 500 | 操作失败 |
版本状态机
版本状态单向流转,不可回退:
draft ──发布──> published ──废弃──> deprecated
│ │
└─────下线───────────┴──> offline| 当前状态 | 允许流转到 | 说明 |
|---|---|---|
draft | published | 只有草稿能发布 |
published | deprecated / offline | 已发布的版本才谈得上废弃或下线 |
deprecated | offline | 废弃后仍可下线 |
offline | 无 | 终态 |
任何不在上表中的流转一律返回 400,并说明当前状态与目标状态。
服务端在读取当前状态与写入新状态之间使用条件更新(CAS):若两者之间状态被并发改动, 更新命中 0 行并返回 400 提示刷新重试,而不会越过状态机。
历史:这套状态机此前只写在代码注释里、实现从未校验,导致生产库出现过 「已废弃但从无发布记录」的版本(草稿被直接标记为废弃)。现由服务层强制。
五、匿名动态文档 API
以下端点无需认证,只返回发布时固化的脱敏文档 DTO。private 与不存在统一返回 404;unlisted 不进入目录但可通过链接访问。
GET /public/release-docs
列出可见性为 public 的最新 Release 文档。支持 query、page、pageSize(最大 50),响应包含 ETag 与短缓存头。
GET /public/release-docs/:alias
返回指定 alias 的最新可访问版本、版本摘要列表、公开 REST 契约、Changelog 和 OpenAPI 内容。
GET /public/release-docs/:alias/versions/:version
返回指定版本。version 支持 latest、v1、v1.2、v1.2.3。历史版本访问受最新发布快照的可见性总闸控制,历史 private 快照不会进入版本列表或被直接读取。
GET /public/release-docs/:alias/versions/:version/openapi.json
下载 OpenAPI 3.0.3 JSON。servers 按当前 API 请求的可信 origin 生成,因此 ETag 按 origin 隔离。
所有公开端点支持 If-None-Match;命中时返回 304。
六、文档站登录访问
文档站登录后通过同源 /docs-api/release-docs/* 读取授权目录和详情。浏览器只发送 HttpOnly wn_docs_session Cookie;nginx 转发到内部路由并注入共享密钥,前端不会把 OAuth access token 放入文档请求头或 URL。
授权目录包含:
- 全部
public文档; - 当前用户可读取项目中的
private与unlisted文档。
项目读取权限与项目页一致:项目所有者、Team Owner、accepted Team member 或显式 project/read grant。site:admin 不自动获得所有项目的私有文档。无权限与不存在统一返回 404。
认证通道的成功和错误响应均使用 Cache-Control: private, no-store 与 Vary: Cookie,不会复用匿名公开端点的 ETag/共享缓存。私有 OpenAPI 的 server origin 只从后端 BACKEND_URL 推导,配置缺失或非法时 fail closed。
早于文档缓存功能发布、且版本内没有
publicDocsCache的历史 Release 不会在读取时动态生成文档。需要重新发布该版本配置后才可在文档站查看。
七、官方团队名单管理
以下端点位于 /admin/site-settings,只接受 JWT,要求 site:admin,并记录 adminAudit:
GET /admin/site-settings/release-docs-official-teamsPUT /admin/site-settings/release-docs-official-teams,Body:{ "teamIds": ["uuid"] }
PUT 校验 UUID 和团队存在性,写后回读,并返回 previousTeamIds/currentTeamIds。误配时由管理员从响应或审计记录恢复旧完整数组。名单变化只影响之后的新发布,不改写历史文档快照。
源码
- 路由:
apps/backend/src/routes/releases.ts - 服务:
apps/backend/src/services/release.ts、release-version.ts、release-public-doc.ts、release-public-doc-store.ts - 类型:
apps/backend/src/types/release.ts - 参考文档:应用发布指南
补充端点
本节补充 plans/need-update-api.md 中尚未覆盖到 docs-site 的接口。端点标题保持严格的 METHOD /path 格式,便于后台文档覆盖率服务识别。
GET /projects/:projectId/releases/:releaseId/debug-logs
获取端点调试日志
认证:JWT Bearer Token、API Key 或 Agent Token(combinedAuth)。 路径参数
| 参数 | 说明 |
|---|---|
projectId | 项目 ID |
releaseId | Release ID |
请求:无请求体。Query 参数用于分页、过滤、搜索或状态筛选;未传时按后端默认排序与分页返回。
响应:成功时返回目标资源详情、状态或配置对象。
常见错误:400 参数非法,401 未认证,403 权限不足,404 资源不存在;服务端或上游异常返回 500。
DELETE /projects/:projectId/releases/:releaseId/debug-logs
清空端点调试日志
认证:JWT Bearer Token、API Key 或 Agent Token(combinedAuth)。 路径参数
| 参数 | 说明 |
|---|---|
projectId | 项目 ID |
releaseId | Release ID |
请求:通常无请求体;删除类接口通过路径参数定位资源,部分接口会执行软删除、释放绑定或撤回流程。
响应:成功时返回 { "success": true } 或等价删除结果;资源不存在、无权限或存在依赖时返回 4xx。
常见错误:400 参数非法,401 未认证,403 权限不足,404 资源不存在;服务端或上游异常返回 500。
PATCH /projects/:projectId/releases/:releaseId/endpoints/:endpointKey/debug
切换端点调试模式
认证:JWT Bearer Token、API Key 或 Agent Token(combinedAuth)。 路径参数
| 参数 | 说明 |
|---|---|
projectId | 项目 ID |
releaseId | Release ID |
endpointKey | Release 端点 key |
请求:请求体为 JSON,传入需要变更的字段;未传字段保持不变。
响应:成功时返回创建或更新后的资源对象,或 { "success": true }。
常见错误:400 参数非法,401 未认证,403 权限不足,404 资源不存在;服务端或上游异常返回 500。
GET /projects/:projectId/releases/documents
可发布文档列表
认证:JWT Bearer Token、API Key 或 Agent Token(combinedAuth)。 路径参数
| 参数 | 说明 |
|---|---|
projectId | 项目 ID |
请求:无请求体。Query 参数用于分页、过滤、搜索或状态筛选;未传时按后端默认排序与分页返回。
响应:成功时返回列表数据,通常包含 items / data / rows 与分页或统计字段。
常见错误:400 参数非法,401 未认证,403 权限不足,404 资源不存在;服务端或上游异常返回 500。
GET /projects/:projectId/releases/documents/:documentId
获取文档发布状态
认证:JWT Bearer Token、API Key 或 Agent Token(combinedAuth)。 路径参数
| 参数 | 说明 |
|---|---|
projectId | 项目 ID |
documentId | 文档 ID |
请求:无请求体。Query 参数用于分页、过滤、搜索或状态筛选;未传时按后端默认排序与分页返回。
响应:成功时返回目标资源详情、状态或配置对象。
常见错误:400 参数非法,401 未认证,403 权限不足,404 资源不存在;服务端或上游异常返回 500。