mach-cms的前台,用vue写的
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

1305 lines
31 KiB

openapi: 3.1.0
info:
title: Mach-CMS API
description: |
Mach-CMS 后端 API 规范。前后端契约文件,任何接口变更必须同步修改此文件。
- 所有业务接口返回统一包装体 `Response<T>`
- 列表查询返回 `PageResult<T>`
- 认证方式:JWT Bearer Token
- 时间格式:ISO-8601(`2024-01-15T08:30:00Z`)
version: 0.3.1
contact:
name: Mach-CMS Team
servers:
- url: http://localhost:8080
description: 本地开发环境
security:
- bearerAuth: []
tags:
- name: Auth
description: 认证与授权
- name: Public
description: 公开接口(无需认证)
- name: Article
description: 文章(前台只读)
- name: ArticleAdmin
description: 文章管理(需 ADMIN/EDITOR)
- name: Tag
description: 标签(前台只读)
- name: TagAdmin
description: 标签管理(需 ADMIN)
- name: Media
description: 媒体文件上传
- name: Search
description: 全文搜索
- name: Comment
description: 评论(前台免登录提交,展示已审核)
- name: CommentAdmin
description: 评论管理(需 ADMIN)
- name: User
description: 用户管理(需 ADMIN)
paths:
# ==================== Public ====================
/api/public/health:
get:
tags: [Public]
summary: 健康检查
security: []
responses:
'200':
description: 服务正常
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseString'
example:
code: 0
message: success
data: UP
# ==================== Auth ====================
/api/auth/register:
post:
tags: [Auth]
summary: 用户注册
security: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/RegisterRequest'
responses:
'200':
description: 注册成功
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseTokenPair'
/api/auth/login:
post:
tags: [Auth]
summary: 用户登录
security: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/LoginRequest'
responses:
'200':
description: 登录成功,返回双 Token
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseTokenPair'
/api/auth/refresh:
post:
tags: [Auth]
summary: 刷新 Access Token
security: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/RefreshTokenRequest'
responses:
'200':
description: 刷新成功
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseTokenPair'
/api/auth/logout:
post:
tags: [Auth]
summary: 退出登录(吊销 Refresh Token)
responses:
'200':
description: 退出成功
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseVoid'
# ==================== Article (Public) ====================
/api/articles:
get:
tags: [Article]
summary: 文章列表(分页)
security: []
parameters:
- name: page
in: query
schema:
type: integer
default: 1
- name: size
in: query
schema:
type: integer
default: 10
maximum: 100
- name: status
in: query
schema:
$ref: '#/components/schemas/ArticleStatus'
default: PUBLISHED
- name: tag
in: query
description: 标签 slug 过滤
schema:
type: string
responses:
'200':
description: 文章列表
content:
application/json:
schema:
$ref: '#/components/schemas/ResponsePageArticleListItem'
/api/articles/popular:
get:
tags: [Article]
summary: 热门文章(按浏览量降序,仅 PUBLISHED)
security: []
parameters:
- name: limit
in: query
schema:
type: integer
default: 5
maximum: 10
minimum: 1
responses:
'200':
description: 热门文章列表
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseListArticleListItem'
/api/articles/{slug}:
get:
tags: [Article]
summary: 文章详情(按 slug)
security: []
parameters:
- name: slug
in: path
required: true
schema:
type: string
responses:
'200':
description: 文章详情
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseArticleDetail'
'404':
description: 文章不存在
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseVoid'
/api/articles/{slug}/meta:
get:
tags: [Article]
summary: 文章 OpenGraph 元数据(分享预览)
security: []
parameters:
- name: slug
in: path
required: true
schema:
type: string
responses:
'200':
description: 元数据(文章不存在时为 null)
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseOpenGraphMeta'
/api/articles/{slug}/star:
post:
tags: [Article]
summary: 点赞文章(已登录)
parameters:
- name: slug
in: path
required: true
schema:
type: string
responses:
'200':
description: 点赞成功
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseVoid'
'401':
description: 未登录
delete:
tags: [Article]
summary: 取消点赞文章(已登录)
parameters:
- name: slug
in: path
required: true
schema:
type: string
responses:
'200':
description: 取消成功
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseVoid'
'401':
description: 未登录
/api/comments/{id}/star:
post:
tags: [Comment]
summary: 点赞评论(已登录)
parameters:
- name: id
in: path
required: true
schema:
type: integer
format: int64
responses:
'200':
description: 点赞成功
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseVoid'
'401':
description: 未登录
delete:
tags: [Comment]
summary: 取消点赞评论(已登录)
parameters:
- name: id
in: path
required: true
schema:
type: integer
format: int64
responses:
'200':
description: 取消成功
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseVoid'
'401':
description: 未登录
# ==================== Comment (Public) ====================
/api/articles/{slug}/comments:
get:
tags: [Comment]
summary: 文章评论列表(仅返回已审核 APPROVED)
security: []
parameters:
- name: slug
in: path
required: true
schema:
type: string
responses:
'200':
description: 评论列表
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseListComment'
post:
tags: [Comment]
summary: 提交评论(免登录,提交后为 PENDING 待审核)
security: []
parameters:
- name: slug
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CommentSubmitRequest'
responses:
'200':
description: 提交成功,返回待审核评论
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseComment'
/api/articles/search:
get:
tags: [Search]
summary: 全文搜索文章
security: []
parameters:
- name: q
in: query
required: true
description: 搜索关键词
schema:
type: string
minLength: 1
maxLength: 100
- name: page
in: query
schema:
type: integer
default: 1
- name: size
in: query
schema:
type: integer
default: 10
maximum: 50
responses:
'200':
description: 搜索结果
content:
application/json:
schema:
$ref: '#/components/schemas/ResponsePageArticleListItem'
# ==================== ArticleAdmin ====================
/api/admin/articles:
post:
tags: [ArticleAdmin]
summary: 创建文章
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ArticleCreateRequest'
responses:
'200':
description: 创建成功
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseArticleDetail'
/api/admin/articles/{id}:
get:
tags: [ArticleAdmin]
summary: 文章详情(按 id,管理端,含草稿/归档等任意状态)
parameters:
- name: id
in: path
required: true
schema:
type: integer
format: int64
responses:
'200':
description: 文章详情
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseArticleDetail'
'404':
description: 文章不存在
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseVoid'
put:
tags: [ArticleAdmin]
summary: 更新文章
parameters:
- name: id
in: path
required: true
schema:
type: integer
format: int64
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ArticleUpdateRequest'
responses:
'200':
description: 更新成功
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseArticleDetail'
delete:
tags: [ArticleAdmin]
summary: 删除文章
parameters:
- name: id
in: path
required: true
schema:
type: integer
format: int64
responses:
'200':
description: 删除成功
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseVoid'
/api/admin/articles/{id}/publish:
patch:
tags: [ArticleAdmin]
summary: 发布文章(状态机:DRAFT → PUBLISHED)
parameters:
- name: id
in: path
required: true
schema:
type: integer
format: int64
responses:
'200':
description: 发布成功
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseArticleDetail'
/api/admin/articles/{id}/archive:
patch:
tags: [ArticleAdmin]
summary: 归档文章
parameters:
- name: id
in: path
required: true
schema:
type: integer
format: int64
responses:
'200':
description: 归档成功
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseArticleDetail'
# ==================== Tag (Public) ====================
/api/tags:
get:
tags: [Tag]
summary: 标签列表(带文章计数)
security: []
responses:
'200':
description: 标签列表
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseListTagWithCount'
# ==================== TagAdmin ====================
/api/admin/tags:
post:
tags: [TagAdmin]
summary: 创建标签
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TagCreateRequest'
responses:
'200':
description: 创建成功
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseTag'
/api/admin/tags/{id}:
put:
tags: [TagAdmin]
summary: 更新标签
parameters:
- name: id
in: path
required: true
schema:
type: integer
format: int64
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TagUpdateRequest'
responses:
'200':
description: 更新成功
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseTag'
delete:
tags: [TagAdmin]
summary: 删除标签
parameters:
- name: id
in: path
required: true
schema:
type: integer
format: int64
responses:
'200':
description: 删除成功
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseVoid'
# ==================== Media ====================
/api/media/upload:
post:
tags: [Media]
summary: 上传文件
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
properties:
file:
type: string
format: binary
description: 文件内容
directory:
type: string
default: images
description: 存储目录
responses:
'200':
description: 上传成功
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseStoredFile'
# ==================== CommentAdmin ====================
/api/admin/comments:
get:
tags: [CommentAdmin]
summary: 待审核评论列表(分页,状态 PENDING)
parameters:
- name: page
in: query
schema:
type: integer
default: 1
- name: size
in: query
schema:
type: integer
default: 20
responses:
'200':
description: 待审核评论列表
content:
application/json:
schema:
$ref: '#/components/schemas/ResponsePageComment'
/api/admin/comments/{id}:
delete:
tags: [CommentAdmin]
summary: 删除评论
parameters:
- name: id
in: path
required: true
schema:
type: integer
format: int64
responses:
'200':
description: 删除成功
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseVoid'
/api/admin/comments/{id}/approve:
patch:
tags: [CommentAdmin]
summary: 审核通过评论(PENDING → APPROVED)
parameters:
- name: id
in: path
required: true
schema:
type: integer
format: int64
responses:
'200':
description: 审核成功
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseComment'
/api/admin/comments/{id}/reject:
patch:
tags: [CommentAdmin]
summary: 驳回评论(PENDING → REJECTED)
parameters:
- name: id
in: path
required: true
schema:
type: integer
format: int64
responses:
'200':
description: 驳回成功
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseComment'
# ==================== User ====================
/api/admin/users:
get:
tags: [User]
summary: 用户列表(分页)
parameters:
- name: page
in: query
schema:
type: integer
default: 1
- name: size
in: query
schema:
type: integer
default: 20
responses:
'200':
description: 用户列表
content:
application/json:
schema:
$ref: '#/components/schemas/ResponsePageUserInfo'
/api/admin/users/{id}/role:
patch:
tags: [User]
summary: 修改用户角色
parameters:
- name: id
in: path
required: true
schema:
type: integer
format: int64
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateRoleRequest'
responses:
'200':
description: 修改成功
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseUserInfo'
/api/admin/users/{id}/status:
patch:
tags: [User]
summary: 启用/禁用用户
parameters:
- name: id
in: path
required: true
schema:
type: integer
format: int64
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateStatusRequest'
responses:
'200':
description: 修改成功
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseUserInfo'
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: |
在请求头中携带 `Authorization: Bearer <access_token>`。
Access Token 有效期 15 分钟,过期后用 Refresh Token 调用 `/api/auth/refresh` 换取新的 Access Token。
schemas:
# ---------- 通用包装体 ----------
Response:
type: object
properties:
code:
type: integer
description: 0 表示成功,非 0 为业务错误码
message:
type: string
data:
description: 业务数据,类型由具体接口决定
required: [code, message]
PageResult:
type: object
properties:
list:
type: array
items: {}
total:
type: integer
format: int64
page:
type: integer
size:
type: integer
totalPages:
type: integer
required: [list, total, page, size, totalPages]
# ---------- 枚举 ----------
ArticleStatus:
type: string
enum: [DRAFT, PUBLISHED, ARCHIVED]
description: |
- DRAFT: 草稿,仅后台可见
- PUBLISHED: 已发布,前台可见
- ARCHIVED: 已归档,前台不可见但保留数据
UserRole:
type: string
enum: [ADMIN, EDITOR, VISITOR]
# ---------- Auth ----------
RegisterRequest:
type: object
properties:
username:
type: string
minLength: 3
maxLength: 50
password:
type: string
minLength: 6
maxLength: 100
email:
type: string
format: email
required: [username, password]
LoginRequest:
type: object
properties:
username:
type: string
password:
type: string
required: [username, password]
RefreshTokenRequest:
type: object
properties:
refreshToken:
type: string
required: [refreshToken]
TokenPair:
type: object
properties:
accessToken:
type: string
refreshToken:
type: string
expiresIn:
type: integer
description: Access Token 有效期(秒)
required: [accessToken, refreshToken, expiresIn]
# ---------- Article ----------
ArticleCreateRequest:
type: object
properties:
title:
type: string
maxLength: 200
summary:
type: string
maxLength: 500
content:
type: string
coverImage:
type: string
description: 封面图 URL
tagIds:
type: array
items:
type: integer
format: int64
required: [title, content]
ArticleUpdateRequest:
type: object
properties:
title:
type: string
maxLength: 200
summary:
type: string
maxLength: 500
content:
type: string
coverImage:
type: string
tagIds:
type: array
items:
type: integer
format: int64
required: [title, content]
ArticleListItem:
type: object
properties:
id:
type: integer
format: int64
title:
type: string
slug:
type: string
summary:
type: string
coverImage:
type: string
status:
$ref: '#/components/schemas/ArticleStatus'
publishedAt:
type: string
format: date-time
createdAt:
type: string
format: date-time
authorName:
type: string
tagNames:
type: array
items:
type: string
starCount:
type: integer
format: int64
description: 点赞数
hasStarred:
type: boolean
nullable: true
description: 当前用户是否已点赞(null 表示未登录)
required: [id, title, slug, status, createdAt, authorName, tagNames, starCount]
ArticleDetail:
type: object
properties:
id:
type: integer
format: int64
title:
type: string
slug:
type: string
summary:
type: string
content:
type: string
coverImage:
type: string
status:
$ref: '#/components/schemas/ArticleStatus'
viewCount:
type: integer
format: int64
publishedAt:
type: string
format: date-time
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
authorName:
type: string
tagNames:
type: array
items:
type: string
starCount:
type: integer
format: int64
description: 点赞数
hasStarred:
type: boolean
nullable: true
description: 当前用户是否已点赞(null 表示未登录)
required: [id, title, slug, content, status, viewCount, createdAt, updatedAt, authorName, tagNames, starCount]
OpenGraphMeta:
type: object
properties:
title:
type: string
description:
type: string
image:
type: string
url:
type: string
type:
type: string
default: article
required: [title, description, url, type]
# ---------- Tag ----------
Tag:
type: object
properties:
id:
type: integer
format: int64
name:
type: string
slug:
type: string
description:
type: string
articleCount:
type: integer
description: 关联文章数量(查询时计算)
createdAt:
type: string
format: date-time
required: [id, name, slug, articleCount, createdAt]
TagCreateRequest:
type: object
properties:
name:
type: string
maxLength: 50
description:
type: string
maxLength: 200
required: [name]
TagUpdateRequest:
type: object
properties:
name:
type: string
maxLength: 50
description:
type: string
maxLength: 200
required: [name]
# ---------- Media ----------
StoredFile:
type: object
properties:
originalName:
type: string
storedPath:
type: string
url:
type: string
thumbnailUrl:
type: string
description: 图片缩略图 URL(非图片为 null)
size:
type: integer
format: int64
contentType:
type: string
required: [originalName, storedPath, url, size]
# ---------- User ----------
UserInfo:
type: object
properties:
id:
type: integer
format: int64
username:
type: string
email:
type: string
avatar:
type: string
role:
$ref: '#/components/schemas/UserRole'
enabled:
type: boolean
createdAt:
type: string
format: date-time
required: [id, username, role, enabled, createdAt]
# ---------- Comment ----------
CommentStatus:
type: string
enum: [PENDING, APPROVED, REJECTED]
description: |
- PENDING: 待审核
- APPROVED: 已通过,前台可见
- REJECTED: 已驳回
CommentSubmitRequest:
type: object
properties:
parentId:
type: integer
format: int64
description: 父评论 ID(回复场景,可空)
authorName:
type: string
maxLength: 100
authorEmail:
type: string
format: email
content:
type: string
maxLength: 2000
required: [authorName, content]
CommentResponse:
type: object
properties:
id:
type: integer
format: int64
articleId:
type: integer
format: int64
parentId:
type: integer
format: int64
authorName:
type: string
authorEmail:
type: string
content:
type: string
status:
$ref: '#/components/schemas/CommentStatus'
createdAt:
type: string
format: date-time
starCount:
type: integer
format: int64
description: 评论点赞数
hasStarred:
type: boolean
nullable: true
description: 当前用户是否已点赞(null 表示未登录)
required: [id, articleId, authorName, content, status, createdAt]
# ---------- User Admin ----------
UpdateRoleRequest:
type: object
properties:
role:
$ref: '#/components/schemas/UserRole'
required: [role]
UpdateStatusRequest:
type: object
properties:
enabled:
type: boolean
required: [enabled]
# ---------- 包装体实例化 ----------
ResponseString:
allOf:
- $ref: '#/components/schemas/Response'
properties:
data:
type: string
ResponseVoid:
allOf:
- $ref: '#/components/schemas/Response'
properties:
data:
type: "null"
ResponseTokenPair:
allOf:
- $ref: '#/components/schemas/Response'
properties:
data:
$ref: '#/components/schemas/TokenPair'
ResponseArticleDetail:
allOf:
- $ref: '#/components/schemas/Response'
properties:
data:
$ref: '#/components/schemas/ArticleDetail'
ResponseOpenGraphMeta:
allOf:
- $ref: '#/components/schemas/Response'
properties:
data:
$ref: '#/components/schemas/OpenGraphMeta'
ResponsePageArticleListItem:
allOf:
- $ref: '#/components/schemas/Response'
properties:
data:
allOf:
- $ref: '#/components/schemas/PageResult'
properties:
list:
type: array
items:
$ref: '#/components/schemas/ArticleListItem'
ResponseListArticleListItem:
allOf:
- $ref: '#/components/schemas/Response'
properties:
data:
type: array
items:
$ref: '#/components/schemas/ArticleListItem'
ResponseTag:
allOf:
- $ref: '#/components/schemas/Response'
properties:
data:
$ref: '#/components/schemas/Tag'
ResponseListTagWithCount:
allOf:
- $ref: '#/components/schemas/Response'
properties:
data:
type: array
items:
$ref: '#/components/schemas/Tag'
ResponseStoredFile:
allOf:
- $ref: '#/components/schemas/Response'
properties:
data:
$ref: '#/components/schemas/StoredFile'
ResponsePageUserInfo:
allOf:
- $ref: '#/components/schemas/Response'
properties:
data:
allOf:
- $ref: '#/components/schemas/PageResult'
properties:
list:
type: array
items:
$ref: '#/components/schemas/UserInfo'
ResponseComment:
allOf:
- $ref: '#/components/schemas/Response'
properties:
data:
$ref: '#/components/schemas/CommentResponse'
ResponseListComment:
allOf:
- $ref: '#/components/schemas/Response'
properties:
data:
type: array
items:
$ref: '#/components/schemas/CommentResponse'
ResponseUserInfo:
allOf:
- $ref: '#/components/schemas/Response'
properties:
data:
$ref: '#/components/schemas/UserInfo'
ResponsePageComment:
allOf:
- $ref: '#/components/schemas/Response'
properties:
data:
allOf:
- $ref: '#/components/schemas/PageResult'
properties:
list:
type: array
items:
$ref: '#/components/schemas/CommentResponse'