docs: 内容系统改用 ID 链接,细化审核状态流转

- 链接格式 slug → /posts/{id}
- 状态重定义: draft/pending/approved/rejected/locked
- 新增 rejected 退回状态(可重提)+ locked 锁定状态(禁止编辑)
- 支持退回+锁定(严重违规/侵权场景)
- 新增解除锁定、提交审核等 API
This commit is contained in:
2026-05-27 18:03:57 +08:00
parent 2528ebd28a
commit fc65872882

View File

@ -12,24 +12,49 @@
|------|------|------| |------|------|------|
| `id` | uint (PK) | 自增主键 | | `id` | uint (PK) | 自增主键 |
| `title` | varchar(200) | 标题,非空 | | `title` | varchar(200) | 标题,非空 |
| `slug` | varchar(200), unique | URL 友好标识,标题自动生成,去重追加数字 |
| `body` | text | Markdown 原文 | | `body` | text | Markdown 原文 |
| `body_html` | text | 渲染后 HTML写时缓存,避免重复解析 | | `body_html` | text | 渲染后 HTML写时缓存 |
| `user_id` | uint (FK → users) | 作者 | | `user_id` | uint (FK → users) | 作者 |
| `status` | varchar(20) | `draft` / `published` / `pending`(审核中)/ `hidden` | | `status` | varchar(20) | `draft` / `pending` / `approved` / `rejected` / `locked` |
| `allow_comment` | bool | 是否允许评论MVP 预留字段 | | `reject_reason` | varchar(500) | 退回理由(管理员填写 |
| `allow_comment` | bool | 是否允许评论MVP 预留) |
| `deleted_at` | gorm.DeletedAt | 软删除 | | `deleted_at` | gorm.DeletedAt | 软删除 |
| `created_at` / `updated_at` | timestamp | | | `created_at` / `updated_at` | timestamp | |
**链接格式**: `/posts/{id}`(如 `/posts/42`
**状态说明**:
| 状态 | 含义 | 公开可见 | 可编辑 |
|------|------|---------|--------|
| `draft` | 草稿,未被审核或审核已关闭 | 否(作者本人可见) | 是 |
| `pending` | 待审,已提交等待管理员操作 | 否 | 否 |
| `approved` | 审核通过,公开发布 | 是 | 是 |
| `rejected` | 退回,审核未通过,可修改后重提 | 否 | 是 |
| `locked` | 锁定,禁止编辑只能删除 | 否 | 否 |
**状态流转**: **状态流转**:
``` ```
draft ──→ pending ──(审核通过)──→ published 创建 → draft ──(提交/审核开启)──→ pending
| ├──(通过)──→ approved ──(撤回)──→ rejected
(管理隐藏)──→ hidden │ │
| ├──(退回)──→ rejected │
(作者删除)──→ deleted_at │ │ │
└──(退回+锁定)──→ locked ←──────┘
←(任意状态锁定)
rejected ──(修改后重提)──→ pending
locked ──(解锁)──→ 回到锁定前状态
任何状态均可软删除(→ deleted_at
``` ```
**锁定场景**:
- **审核退回+锁定**: 严重违规/侵权内容,无修改空间,禁止再次提交
- **审核通过后退回+锁定**: 已发布内容被撤回并禁止再次编辑/提交
- **直接锁定**: 任何时候管理员可锁定任意帖子
--- ---
## 2. 分层结构 ## 2. 分层结构
@ -60,7 +85,6 @@ internal/
```go ```go
type postRepository interface { type postRepository interface {
Create(post *model.Post) error Create(post *model.Post) error
FindBySlug(slug string) (*model.Post, error)
FindByID(id uint) (*model.Post, error) FindByID(id uint) (*model.Post, error)
FindPageable(keyword string, status string, page, pageSize int) ([]model.Post, int64, error) FindPageable(keyword string, status string, page, pageSize int) ([]model.Post, int64, error)
Update(post *model.Post) error Update(post *model.Post) error
@ -73,12 +97,15 @@ type postRepository interface {
```go ```go
type postUseCase interface { type postUseCase interface {
Create(userID uint, title, body string) (*model.Post, error) Create(userID uint, title, body string) (*model.Post, error)
GetBySlug(slug string) (*model.Post, error) GetByID(id uint) (*model.Post, error)
List(keyword string, page, pageSize int) ([]model.Post, int64, error) List(keyword string, page, pageSize int) ([]model.Post, int64, error)
Update(userID, role uint, title, body string) error Update(userID uint, postID uint, title, body string) error
Delete(userID uint, id uint) error Delete(userID uint, postID uint) error
AdminHide(id uint) error SubmitForAudit(postID uint) error // 草稿 → 待审
AdminPublish(id uint) error Approve(postID uint) error // 审核通过
Reject(postID uint, reason string) error // 退回
Lock(postID uint) error // 锁定(禁止编辑)
Unlock(postID uint) error // 解锁
} }
``` ```
@ -92,17 +119,16 @@ type postUseCase interface {
用户提交 → 用户提交 →
1. 鉴权(中间件 authMdw.Required 1. 鉴权(中间件 authMdw.Required
2. 校验标题/正文非空 2. 校验标题/正文非空
3. 生成 unique slug标题 → URL 安全 → 查重追加数字后缀 3. body → body_htmlGoldmark 渲染
4. body → body_htmlGoldmark 渲染) 4. 检查审核开关:
5. 检查审核开关: - 审核关闭 → status = approved直接可见
- IsRegistrationEnabled = false → status = published - 审核开启 → status = pending创建 AuditSubmission
- IsAuditEnabled = true → status = pending创建 AuditSubmission 5. Save → 返回
6. Save → 返回
``` ```
### 列表 ### 列表
- 仅返回 `status = published` - 仅返回 `status = approved`
- keyword 标题模糊搜索 - keyword 标题模糊搜索
- 分页默认 page_size=20 - 分页默认 page_size=20
- 排序: created_at DESC - 排序: created_at DESC
@ -110,16 +136,17 @@ type postUseCase interface {
### 详情 ### 详情
- 通过 slug 查找 - 通过 ID 查找
- 公开: 仅 `published` - 公开: 仅 `approved`
- 作者本人 + admin+: 可预览 `draft` / `pending` - 作者本人 + admin+: 可预览 `draft` / `pending` / `rejected` / `locked`
- 已渲染的 body_html 直接输出(带 XSS 防护) - 已渲染的 body_html 直接输出(带 XSS 防护)
### 编辑 / 删除 ### 编辑 / 删除
- 权限: 作者本人 或 admin+ - 权限: 作者本人 或 admin+
- 编辑: 更新 title / body / body_html重新生成 slug若标题变更 - 状态约束: `pending` / `locked` 禁止编辑
- 删除: 软删除 - `rejected` 状态编辑后自动重置为 `draft`
- 删除: 软删除,任何状态均可
--- ---
@ -129,29 +156,32 @@ type postUseCase interface {
``` ```
GET /posts 列表页 GET /posts 列表页
GET /posts/:slug 详情页 GET /posts/:id 详情页
GET /posts/new 编辑器(需登录) GET /posts/new 编辑器(需登录)
GET /posts/:slug/edit 编辑页(作者/admin GET /posts/:id/edit 编辑页(作者/adminlocked 状态禁止
``` ```
### APIapi ### APIapi
``` ```
POST /api/posts 发帖 POST /api/posts 发帖
PUT /api/posts/:slug 编辑 PUT /api/posts/:id 编辑
DELETE /api/posts/:slug 删除 DELETE /api/posts/:id 删除
POST /api/posts/:id/submit 草稿提交审核
GET /api/posts 列表 JSON GET /api/posts 列表 JSON
GET /api/posts/:slug 详情 JSON GET /api/posts/:id 详情 JSON
GET /api/posts/:slug/preview Markdown 预览 POST /api/posts/preview Markdown 预览
``` ```
### 管理后台admin ### 管理后台admin
``` ```
GET /admin/posts 所有帖子(含草稿/审核中/隐藏 GET /admin/posts 所有帖子(全状态
POST /admin/posts/:slug/hide 隐藏 POST /admin/posts/:id/approve 审核通过
POST /admin/posts/:slug/publish 强制发布 POST /admin/posts/:id/reject 退回(需填写理由)
POST /admin/posts/:slug/restore 恢复软删除 POST /admin/posts/:id/lock 锁定(禁止编辑)
POST /admin/posts/:id/unlock 解锁
POST /admin/posts/:id/restore 恢复软删除
``` ```
--- ---
@ -192,9 +222,18 @@ templates/admin/html/posts/
| 用户角色 | 发帖后状态 | 如何可见 | | 用户角色 | 发帖后状态 | 如何可见 |
|----------|-----------|---------| |----------|-----------|---------|
| user审核开启 | `pending` → AuditSubmission | 审核通过 → published | | user审核开启 | `pending` → AuditSubmission | 审核通过 → approved |
| moderator+ | `published` | 直接可见 | | moderator+ | `approved` | 直接可见 |
| user审核关闭 | `published` | 直接可见 | | user审核关闭 | `approved` | 直接可见 |
**审核操作对应状态变更**:
| 操作 | 状态变更 | 条件 |
|------|---------|------|
| 提交审核 | `draft``pending` | 仅作者本人 |
| 审核通过 | `pending``approved` | admin+ |
| 退回 | `pending`/`approved``rejected` | admin+,需填写理由 |
| 退回+锁定 | `pending`/`approved``locked` | admin+,严重违规/侵权 |
--- ---
@ -202,9 +241,9 @@ templates/admin/html/posts/
侧边栏新增 "内容管理" 入口admin+ 侧边栏新增 "内容管理" 入口admin+
- 全状态列表: 标题 / 作者 / 状态 / 时间 - 全状态列表: 标题 / 作者 / 状态 / 时间 / 退回理由
- 操作: 隐藏 / 强制发布 / 恢复 - 操作: 通过 / 退回 / 锁定 / 解锁 / 恢复
- 状态标签: draft/ pending/ published绿/ hidden(红) - 状态标签: draft/ pending/ approved绿/ rejected/ locked(红)
--- ---