{"openapi":"3.1.0","info":{"title":"WHRCT22 文章 API","version":"1.1.0","description":"在后台 /admin/keys 创建独立密钥。默认创建草稿，发布或修改已发布文章需要 articles:publish。每个密钥每分钟最多 120 次请求，上传每小时最多 30 次。密钥不可用于管理后台或删除文章。"},"servers":[{"url":"/"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"ArticleInput":{"type":"object","additionalProperties":false,"required":["slug","title"],"properties":{"slug":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","maxLength":100},"title":{"type":"string","maxLength":160},"excerpt":{"type":"string","maxLength":500},"body":{"type":"string","description":"Markdown；不执行 HTML。最多 100000 字符","maxLength":100000},"coverImage":{"type":"string","description":"使用图片上传接口返回的 media.url"},"coverAlt":{"type":"string"},"tags":{"type":"array","maxItems":8,"items":{"type":"string","maxLength":30}},"categoryId":{"type":"string","description":"GET /api/cms/categories 返回的类目 id；空字符串代表未分类。创建时省略为未分类，更新时省略保留原类目。"},"status":{"type":"string","enum":["draft","published"],"default":"draft"}}}}},"paths":{"/api/cms/categories":{"get":{"summary":"获取类目列表，返回 { categories: [{ id, name, revision, createdAt, updatedAt }] }；无需授权。类目管理仅开放给管理员会话。","responses":{"200":{"description":"成功"},"400":{"description":"输入格式有误"},"401":{"description":"密钥无效或过期"},"403":{"description":"缺少对应权限"},"404":{"description":"文章不存在或尚未发布"},"409":{"description":"版本冲突；获取最新 revision 后合并内容再重试"},"429":{"description":"请求过多"},"503":{"description":"存储暂不可用；保留内容后重试"}}}},"/api/cms/articles":{"get":{"summary":"文章列表，按发布时间从新到旧；all=true 按更新时间排序并含草稿，需 articles:read","parameters":[{"in":"query","name":"category","schema":{"type":"string","format":"uuid"},"description":"按类目 id 筛选，在数据库中筛选后再分页；不传时返回所有类目文章"},{"in":"query","name":"all","schema":{"type":"boolean","default":false}},{"in":"query","name":"offset","schema":{"type":"integer","minimum":0,"default":0}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":50,"default":12}}],"responses":{"200":{"description":"成功"},"400":{"description":"输入格式有误"},"401":{"description":"密钥无效或过期"},"403":{"description":"缺少对应权限"},"404":{"description":"文章不存在或尚未发布"},"409":{"description":"版本冲突；获取最新 revision 后合并内容再重试"},"429":{"description":"请求过多"},"503":{"description":"存储暂不可用；保留内容后重试"}}},"post":{"summary":"创建文章；需 articles:write；发布另需 articles:publish","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArticleInput"}}}},"responses":{"200":{"description":"成功"},"201":{"description":"返回 { article }，含 revision 和时间"},"400":{"description":"输入格式有误"},"401":{"description":"密钥无效或过期"},"403":{"description":"缺少对应权限"},"404":{"description":"文章不存在或尚未发布"},"409":{"description":"版本冲突；获取最新 revision 后合并内容再重试"},"429":{"description":"请求过多"},"503":{"description":"存储暂不可用；保留内容后重试"}}}},"/api/cms/articles/{slug}":{"parameters":[{"in":"path","name":"slug","required":true,"schema":{"type":"string"}}],"get":{"summary":"读取 { article }；草稿需 articles:read","responses":{"200":{"description":"成功"},"400":{"description":"输入格式有误"},"401":{"description":"密钥无效或过期"},"403":{"description":"缺少对应权限"},"404":{"description":"文章不存在或尚未发布"},"409":{"description":"版本冲突；获取最新 revision 后合并内容再重试"},"429":{"description":"请求过多"},"503":{"description":"存储暂不可用；保留内容后重试"}}},"put":{"summary":"完整替换文章，slug 不可变；需 articles:write，涉及已发布状态另需 articles:publish","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["slug","title","revision"],"properties":{"slug":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","maxLength":100},"title":{"type":"string","maxLength":160},"excerpt":{"type":"string","maxLength":500},"body":{"type":"string","description":"Markdown；不执行 HTML。最多 100000 字符","maxLength":100000},"coverImage":{"type":"string","description":"使用图片上传接口返回的 media.url"},"coverAlt":{"type":"string"},"tags":{"type":"array","maxItems":8,"items":{"type":"string","maxLength":30}},"categoryId":{"type":"string","description":"GET /api/cms/categories 返回的类目 id；空字符串代表未分类。创建时省略为未分类，更新时省略保留原类目。"},"status":{"type":"string","enum":["draft","published"],"default":"draft"},"revision":{"type":"integer","minimum":1,"description":"上次读取的 article.revision，防止覆盖并发编辑"}}}}}},"responses":{"200":{"description":"成功"},"400":{"description":"输入格式有误"},"401":{"description":"密钥无效或过期"},"403":{"description":"缺少对应权限"},"404":{"description":"文章不存在或尚未发布"},"409":{"description":"版本冲突；获取最新 revision 后合并内容再重试"},"429":{"description":"请求过多"},"503":{"description":"存储暂不可用；保留内容后重试"}}}},"/api/cms/media":{"post":{"summary":"上传图片；需 media:write。JPG/PNG/静态 WebP，最大 3 MB、2400 万像素；转为 WebP 并移除元数据","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"description":"成功"},"201":{"description":"返回 { media: { id,url,name,width,height,size,createdAt }, markdown }"},"400":{"description":"输入格式有误"},"401":{"description":"密钥无效或过期"},"403":{"description":"缺少对应权限"},"404":{"description":"文章不存在或尚未发布"},"409":{"description":"版本冲突；获取最新 revision 后合并内容再重试"},"413":{"description":"文件超过体积限制"},"429":{"description":"请求过多"},"503":{"description":"存储暂不可用；保留内容后重试"}}}}}}