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