# 摸鱼论坛 API v1 接口文档

> Base URL: `https://your-domain.com/api/v1`
> 认证方式: JWT Bearer Token
> 响应格式: JSON

---

## 目录

- [认证说明](#认证说明)
- [统一响应格式](#统一响应格式)
- [认证接口](#认证接口-auth)
- [帖子接口](#帖子接口-topics)
- [评论接口](#评论接口-comments)
- [用户接口](#用户接口-users)
- [私信接口](#私信接口-messages)
- [通知接口](#通知接口-notices)
- [版块接口](#版块接口-nodes)
- [搜索接口](#搜索接口-search)
- [上传接口](#上传接口-upload)

---

## 认证说明

大部分接口需要 JWT Token 认证。流程：

1. 调用 `POST /auth/login` 获取 `access_token`
2. 在后续请求的 Header 中携带：`Authorization: Bearer <access_token>`
3. Token 有效期 1 小时，过期后调用 `POST /auth/refresh-token` 刷新

**需要认证的接口**在下方各接口标注中以 🔒 标识。

---

## 统一响应格式

**成功响应：**

```json
{
  "code": 200,
  "message": "success",
  "data": { ... },
  "timestamp": 1693526400
}
```

**错误响应：**

```json
{
  "code": 400,
  "message": "错误描述",
  "data": null,
  "timestamp": 1693526400,
  "errors": { "field": ["具体错误信息"] }
}
```

**常见 HTTP 状态码：**

| 状态码 | 含义 |
|--------|------|
| 200 | 成功 |
| 400 | 参数错误 |
| 401 | 未授权（Token 无效或缺失） |
| 403 | 禁止访问（权限不足/账户被禁/被封禁） |
| 404 | 资源不存在 |
| 429 | 请求过于频繁（限流） |
| 500 | 服务器内部错误 |

---

## 认证接口 (Auth)

### 1. 用户登录

`POST /auth/login` — 无需认证

**请求参数：**

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| username | string | 是 | 用户名 |
| password | string | 是 | 密码 |

**请求示例：**

```json
{
  "username": "admin",
  "password": "your_password"
}
```

**成功响应 (200)：**

```json
{
  "code": 200,
  "message": "登录成功",
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIs...",
    "refresh_token": "eyJhbGciOiJIUzI1NiIs...",
    "expires_in": 3600,
    "token_type": "Bearer",
    "user": {
      "id": 1,
      "username": "admin",
      "email": "admin@example.com",
      "avatar": "https://example.com/avatar/0.png",
      "score": 100,
      "created_at": 1693526400
    }
  }
}
```

**需要两步验证 (403)：**

```json
{
  "code": 403,
  "message": "需要两步验证",
  "data": {
    "requires_2fa": true,
    "partial_token": "eyJhbGciOiJIUzI1NiIs...",
    "expires_in": 300
  }
}
```

**限流：** 用户级 5次/60秒，IP级 10次/60秒

---

### 2. 两步验证（TOTP）

`POST /auth/verify-2fa` — 无需认证

用户登录时返回 `requires_2fa: true` 后，提交 TOTP 验证码完成登录。

**请求参数：**

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| partial_token | string | 是 | 登录时返回的 partial_token |
| code | string | 是 | 6位 TOTP 验证码 |

**成功响应 (200)：** 与登录成功相同，返回完整的 access_token 和 refresh_token。

---

### 3. 用户注册

`POST /auth/register` — 无需认证

**请求参数：**

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| username | string | 是 | 用户名，2-16个字符 |
| email | string | 是 | 邮箱地址 |
| password | string | 是 | 密码，8-64个字符 |
| password_repeat | string | 是 | 确认密码 |
| invite_code | string | 否 | 邀请码（需要时必填） |
| verification_code | string | 否 | 邮箱验证码（开启邮箱验证时必填） |

**请求示例：**

```json
{
  "username": "newuser",
  "email": "user@example.com",
  "password": "secure_password",
  "password_repeat": "secure_password",
  "invite_code": "ABC123",
  "verification_code": "123456"
}
```

**成功响应 (200)：** 与登录成功相同，返回 access_token、refresh_token 和用户信息。

**限流：** 用户级 3次/60秒，IP级 5次/300秒

---

### 4. 发送邮箱验证码

`POST /auth/send-verify-code` — 无需认证

**请求参数：**

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| email | string | 是 | 用于注册的邮箱地址 |

**成功响应 (200)：**

```json
{
  "code": 200,
  "message": "验证码已发送到您的邮箱"
}
```

**限流：** IP级 5次/60秒，同一邮箱 60秒冷却

---

### 5. 刷新 Token

`POST /auth/refresh-token` — 无需认证

**请求参数：**

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| refresh_token | string | 是 | 登录时返回的 refresh_token |

**成功响应 (200)：**

```json
{
  "code": 200,
  "message": "Token刷新成功",
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIs...",
    "expires_in": 3600
  }
}
```

---

### 6. 用户登出

`POST /auth/logout` 🔒

撤销当前 access_token。可选同时撤销 refresh_token。

**请求参数（可选）：**

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| refresh_token | string | 否 | 同时撤销 refresh_token |

**成功响应 (200)：**

```json
{
  "code": 200,
  "message": "登出成功"
}
```

---

### 7. 获取当前用户信息

`GET /auth/profile` 🔒

**成功响应 (200)：**

```json
{
  "code": 200,
  "data": {
    "id": 1,
    "username": "admin",
    "email": "admin@example.com",
    "avatar": "https://example.com/avatar/0.png",
    "score": 100,
    "topic_count": 10,
    "comment_count": 50,
    "fans_count": 5,
    "follow_count": 3,
    "created_at": 1693526400
  }
}
```

---

## 帖子接口 (Topics)

### 8. 获取帖子列表

`GET /topics` — 无需认证

**查询参数：**

| 参数 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| page | int | 否 | 1 | 页码 |
| limit | int | 否 | 20 | 每页数量（最大100） |
| node_id | int | 否 | - | 按版块筛选 |
| sort | string | 否 | hot | 排序：`hot`（热门）、`new`（最新）、`top`（置顶） |

**成功响应 (200)：**

```json
{
  "code": 200,
  "data": {
    "list": [
      {
        "id": 1,
        "title": "帖子标题",
        "content": "帖子内容摘要...",
        "content_summary": "帖子内容摘要...",
        "content_state": "normal",
        "blocked_message": null,
        "user": {
          "id": 1,
          "username": "admin",
          "avatar": "https://example.com/avatar/0.png"
        },
        "node": {
          "id": 1,
          "name": "灌水区",
          "ename": "water"
        },
        "comment_count": 5,
        "view_count": 100,
        "like_count": 10,
        "is_top": false,
        "is_essence": false,
        "created_at": 1693526400,
        "updated_at": 1693526400
      }
    ],
    "pagination": {
      "page": 1,
      "limit": 20,
      "total": 100,
      "total_pages": 5
    }
  }
}
```

---

### 9. 获取帖子详情

`GET /topics/{id}` — 无需认证

**路径参数：**

| 参数 | 类型 | 说明 |
|------|------|------|
| id | int | 帖子ID |

**成功响应 (200)：**

```json
{
  "code": 200,
  "data": {
    "id": 1,
    "title": "帖子标题",
    "content": "完整帖子内容（Markdown）",
    "content_html": "<p>渲染后的 HTML</p>",
    "content_state": "normal",
    "blocked_message": null,
    "block_reason": null,
    "user": {
      "id": 1,
      "username": "admin",
      "avatar": "https://example.com/avatar/0.png",
      "score": 100
    },
    "node": {
      "id": 1,
      "name": "灌水区",
      "ename": "water"
    },
    "comment_count": 5,
    "view_count": 100,
    "like_count": 10,
    "is_liked": false,
    "is_favorited": false,
    "is_top": false,
    "is_essence": false,
    "access_auth": 0,
    "hidden": false,
    "created_at": 1693526400,
    "updated_at": 1693526400
  }
}
```

**错误响应：**
- 403：无权访问（帖子设置了访问权限）
- 404：帖子不存在

---

### 10. 创建帖子

`POST /topics` 🔒

**请求参数：**

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| title | string | 是 | 标题，4-120个字符 |
| content | string | 是 | 内容（Markdown） |
| node_id | int | 是 | 版块ID |
| access_auth | int | 否 | 访问权限：0=公开，1-6=等级，99=私有，默认0 |

**请求示例：**

```json
{
  "title": "这是一篇测试帖子",
  "content": "帖子正文内容，支持 Markdown 格式。",
  "node_id": 1,
  "access_auth": 0
}
```

**成功响应 (200)：**

```json
{
  "code": 200,
  "message": "帖子创建成功",
  "data": {
    "id": 1,
    "title": "这是一篇测试帖子",
    "content": "帖子正文内容...",
    "user_id": 1,
    "node_id": 1,
    "created_at": 1693526400
  }
}
```

**错误响应：**
- 403：账户未激活 / 被禁言 / 积分不足
- 400：参数错误 / 版块不存在

---

### 11. 更新帖子

`PUT /topics/{id}` 🔒

仅帖子作者或管理员可编辑。

**路径参数：**

| 参数 | 类型 | 说明 |
|------|------|------|
| id | int | 帖子ID |

**请求参数（均可选）：**

| 参数 | 类型 | 说明 |
|------|------|------|
| title | string | 新标题 |
| content | string | 新内容 |
| node_id | int | 新版块 |

**成功响应 (200)：**

```json
{
  "code": 200,
  "message": "帖子更新成功",
  "data": {
    "id": 1,
    "title": "更新后的标题",
    "updated_at": 1693527000
  }
}
```

**错误响应：**
- 403：无权编辑 / 帖子已锁定 / 已超过编辑时间限制

---

### 12. 删除帖子

`DELETE /topics/{id}` 🔒

仅帖子作者或管理员可删除（软删除）。

**路径参数：**

| 参数 | 类型 | 说明 |
|------|------|------|
| id | int | 帖子ID |

**成功响应 (200)：**

```json
{
  "code": 200,
  "message": "删除成功"
}
```

---

### 13. 点赞/取消点赞

`POST /topics/{id}/like` 🔒

**路径参数：**

| 参数 | 类型 | 说明 |
|------|------|------|
| id | int | 帖子ID |

**请求参数：**

| 参数 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| type | string | 否 | like | `like` 点赞，`cancel` 取消点赞 |

**成功响应 (200)：**

```json
{
  "code": 200,
  "message": "点赞成功",
  "data": {
    "like_count": 11,
    "is_liked": true
  }
}
```

---

### 14. 收藏/取消收藏

`POST /topics/{id}/favorite` 🔒

**路径参数：**

| 参数 | 类型 | 说明 |
|------|------|------|
| id | int | 帖子ID |

**请求参数：**

| 参数 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| action | string | 否 | favorite | `favorite` 收藏，`unfavorite` 取消收藏 |

**成功响应 (200)：**

```json
{
  "code": 200,
  "message": "收藏成功"
}
```

---

### 15. 投喂鱼丸

`POST /topics/{id}/chicken` 🔒

向帖子或评论投喂鱼丸（每天前4次免费，之后每次消耗1积分）。

**路径参数：**

| 参数 | 类型 | 说明 |
|------|------|------|
| id | int | 帖子ID |

**请求参数：**

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| comment_id | int | 否 | 评论ID（不传则投喂帖子） |

**成功响应 (200)：**

```json
{
  "code": 200,
  "message": "投喂成功，本次免费",
  "data": {
    "chicken_count": 5,
    "is_free": true,
    "today_count": 3
  }
}
```

**错误响应：**
- 400：不能投喂自己 / 已投喂过 / 积分不足

---

## 评论接口 (Comments)

### 16. 获取评论列表

`GET /topics/{topic_id}/comments` — 无需认证

**路径参数：**

| 参数 | 类型 | 说明 |
|------|------|------|
| topic_id | int | 帖子ID |

**查询参数：**

| 参数 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| page | int | 否 | 1 | 页码 |
| limit | int | 否 | 20 | 每页数量（最大100） |
| sort | string | 否 | time | 排序：`time`（时间）、`hot`（热度） |

**成功响应 (200)：**

```json
{
  "code": 200,
  "data": {
    "list": [
      {
        "id": 1,
        "content": "评论内容",
        "content_html": "<p>渲染后的 HTML</p>",
        "content_state": "normal",
        "blocked_message": null,
        "user": {
          "id": 2,
          "username": "user1",
          "avatar": "https://example.com/avatar/1.png"
        },
        "floor": 1,
        "like_count": 3,
        "is_liked": false,
        "created_at": 1693526500
      }
    ],
    "pagination": {
      "page": 1,
      "limit": 20,
      "total": 5,
      "total_pages": 1
    }
  }
}
```

---

### 17. 发表评论

`POST /topics/{topic_id}/comments` 🔒

**路径参数：**

| 参数 | 类型 | 说明 |
|------|------|------|
| topic_id | int | 帖子ID |

**请求参数：**

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| content | string | 是 | 评论内容 |
| parent_id | int | 否 | 回复的评论ID，0为顶层评论 |

**成功响应 (200)：**

```json
{
  "code": 200,
  "message": "评论成功",
  "data": {
    "id": 1,
    "content": "评论内容",
    "user": {
      "id": 1,
      "username": "admin",
      "avatar": "https://example.com/avatar/0.png"
    },
    "floor": 6,
    "created_at": 1693526500
  }
}
```

**错误响应：**
- 403：评论已关闭 / 被禁言 / 积分不足
- 429：提交间隔时间不足

---

### 18. 更新评论

`PUT /comments/{id}` 🔒

仅评论作者或管理员可编辑。

**路径参数：**

| 参数 | 类型 | 说明 |
|------|------|------|
| id | int | 评论ID |

**请求参数：**

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| content | string | 是 | 新内容 |

**成功响应 (200)：**

```json
{
  "code": 200,
  "message": "评论更新成功",
  "data": {
    "id": 1,
    "content": "更新后的评论内容",
    "updated_at": 1693527000
  }
}
```

---

### 19. 删除评论

`DELETE /comments/{id}` 🔒

仅评论作者或管理员可删除。

**路径参数：**

| 参数 | 类型 | 说明 |
|------|------|------|
| id | int | 评论ID |

**成功响应 (200)：**

```json
{
  "code": 200,
  "message": "评论删除成功"
}
```

---

## 用户接口 (Users)

### 20. 获取当前用户资料

`GET /users/me` 🔒

**成功响应 (200)：**

```json
{
  "code": 200,
  "data": {
    "id": 1,
    "username": "admin",
    "email": "admin@example.com",
    "avatar": "https://example.com/avatar/0.png",
    "score": 100,
    "topic_count": 10,
    "comment_count": 50,
    "fans_count": 5,
    "follow_count": 3,
    "website": "https://example.com",
    "about": "个人简介",
    "signature": "个性签名",
    "readme": "自我介绍",
    "created_at": 1693526400
  }
}
```

---

### 21. 更新个人资料

`PUT /users/update-me` 🔒

**请求参数（均可选）：**

| 参数 | 类型 | 最大长度 | 说明 |
|------|------|----------|------|
| website | string | 100 | 个人网站 |
| about | string | 255 | 个人简介 |
| signature | string | 255 | 个性签名 |
| readme | string | 1000 | 自我介绍 |

**成功响应 (200)：**

```json
{
  "code": 200,
  "message": "更新成功"
}
```

---

### 22. 获取用户资料

`GET /users/{id}` — 无需认证

**路径参数：**

| 参数 | 类型 | 说明 |
|------|------|------|
| id | int | 用户ID |

**成功响应 (200)：**

```json
{
  "code": 200,
  "data": {
    "id": 1,
    "username": "admin",
    "avatar": "https://example.com/avatar/0.png",
    "score": 100,
    "topic_count": 10,
    "comment_count": 50,
    "fans_count": 5,
    "follow_count": 3,
    "is_followed": false,
    "created_at": 1693526400
  }
}
```

---

### 23. 获取用户的帖子

`GET /users/{id}/topics` — 无需认证

**路径参数：**

| 参数 | 类型 | 说明 |
|------|------|------|
| id | int | 用户ID |

**查询参数：**

| 参数 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| page | int | 否 | 1 | 页码 |
| limit | int | 否 | 20 | 每页数量（最大100） |

**成功响应 (200)：**

```json
{
  "code": 200,
  "data": {
    "list": [
      {
        "id": 1,
        "title": "帖子标题",
        "node": {
          "id": 1,
          "name": "灌水区",
          "ename": "water"
        },
        "comment_count": 5,
        "view_count": 100,
        "created_at": 1693526400
      }
    ],
    "pagination": {
      "page": 1,
      "limit": 20,
      "total": 10,
      "total_pages": 1
    }
  }
}
```

---

### 24. 获取用户的评论

`GET /users/{id}/comments` — 无需认证

**路径参数：**

| 参数 | 类型 | 说明 |
|------|------|------|
| id | int | 用户ID |

**查询参数：**

| 参数 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| page | int | 否 | 1 | 页码 |
| limit | int | 否 | 20 | 每页数量（最大100） |

**成功响应 (200)：**

```json
{
  "code": 200,
  "data": {
    "list": [
      {
        "id": 1,
        "content": "评论内容摘要",
        "content_state": "normal",
        "topic": {
          "id": 1,
          "title": "帖子标题"
        },
        "floor": 3,
        "created_at": 1693526500
      }
    ],
    "pagination": {
      "page": 1,
      "limit": 20,
      "total": 50,
      "total_pages": 3
    }
  }
}
```

---

### 25. 关注/取消关注

`POST /users/{id}/follow` 🔒

**路径参数：**

| 参数 | 类型 | 说明 |
|------|------|------|
| id | int | 目标用户ID |

**请求参数：**

| 参数 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| action | string | 否 | follow | `follow` 关注，`unfollow` 取消关注 |

**成功响应 (200)：**

```json
{
  "code": 200,
  "message": "关注成功"
}
```

**错误响应：**
- 400：不能关注自己
- 404：用户不存在

---

## 私信接口 (Messages)

### 26. 发送私信

`POST /messages` 🔒

**请求参数：**

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| to | string | 是 | 目标用户ID或用户名 |
| content | string | 是 | 消息内容，最大1000字符 |

**成功响应 (200)：**

```json
{
  "code": 200,
  "message": "发送成功",
  "data": {
    "message_id": 1
  }
}
```

---

### 27. 获取会话列表

`GET /messages` 🔒

**查询参数：**

| 参数 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| limit | int | 否 | 20 | 返回数量（最大100） |

**成功响应 (200)：**

```json
{
  "code": 200,
  "data": {
    "list": [
      {
        "conversation_id": "conv_1_2",
        "user": {
          "id": 2,
          "username": "user1",
          "avatar": "https://example.com/avatar/1.png"
        },
        "last_message": "最后一条消息内容",
        "last_time": 1693526500,
        "has_unread": true
      }
    ]
  }
}
```

---

### 28. 获取会话消息

`GET /messages/{id}` 🔒

**路径参数：**

| 参数 | 类型 | 说明 |
|------|------|------|
| id | string | 会话ID |

**查询参数：**

| 参数 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| limit | int | 否 | 50 | 返回数量（最大100） |
| before_id | int | 否 | 0 | 加载此ID之前的消息（用于分页） |

**成功响应 (200)：**

```json
{
  "code": 200,
  "data": {
    "list": [
      {
        "id": 1,
        "from_id": 1,
        "to_id": 2,
        "content": "消息内容",
        "is_mine": true,
        "created_at": 1693526500
      }
    ]
  }
}
```

**错误响应：**
- 403：无权访问此会话

---

## 通知接口 (Notices)

### 29. 获取未读通知数量

`GET /notifications/count` 🔒

**成功响应 (200)：**

```json
{
  "code": 200,
  "data": {
    "mention": 2,
    "comment": 5,
    "system": 1,
    "message": 3,
    "follow": 0,
    "total": 11
  }
}
```

---

### 30. 获取通知列表

`GET /notices` 🔒

**查询参数：**

| 参数 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| page | int | 否 | 1 | 页码 |
| limit | int | 否 | 20 | 每页数量（最大100） |
| type | string | 否 | all | 筛选：`all`（全部）、`unread`（未读）、`read`（已读） |

**成功响应 (200)：**

```json
{
  "code": 200,
  "data": {
    "list": [
      {
        "id": 1,
        "type": 1,
        "msg": "用户 user1 评论了你的帖子",
        "status": 0,
        "created_at": 1693526500,
        "source": {
          "id": 2,
          "username": "user1",
          "avatar": "https://example.com/avatar/1.png"
        },
        "topic": {
          "id": 1,
          "title": "帖子标题"
        }
      }
    ],
    "pagination": {
      "page": 1,
      "limit": 20,
      "total": 11,
      "total_pages": 1
    }
  }
}
```

---

## 版块接口 (Nodes)

### 31. 获取版块列表

`GET /nodes` — 无需认证

**成功响应 (200)：**

```json
{
  "code": 200,
  "data": [
    {
      "id": 1,
      "name": "灌水区",
      "ename": "water",
      "description": "随便聊聊",
      "topic_count": 100,
      "icon": "https://example.com/icons/water.png"
    },
    {
      "id": 2,
      "name": "技术区",
      "ename": "tech",
      "description": "技术交流",
      "topic_count": 50,
      "icon": "https://example.com/icons/tech.png"
    }
  ]
}
```

---

## 搜索接口 (Search)

### 32. 搜索帖子和用户

`GET /search` — 无需认证

**查询参数：**

| 参数 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| q | string | 是 | - | 搜索关键词（至少2个字符） |
| type | string | 否 | all | 搜索类型：`all`（全部）、`topic`（帖子）、`user`（用户） |
| page | int | 否 | 1 | 页码 |
| limit | int | 否 | 20 | 每页数量（最大100） |

**成功响应 (200)：**

```json
{
  "code": 200,
  "data": {
    "topics": [
      {
        "id": 1,
        "title": "搜索结果标题",
        "user": {
          "id": 1,
          "username": "admin",
          "avatar": "https://example.com/avatar/0.png"
        },
        "node": {
          "id": 1,
          "name": "灌水区",
          "ename": "water"
        },
        "comment_count": 5,
        "created_at": 1693526400,
        "highlight": {
          "title": "搜索结果<strong>关键词</strong>标题"
        }
      }
    ],
    "users": [
      {
        "id": 1,
        "username": "admin",
        "avatar": "https://example.com/avatar/0.png",
        "score": 100
      }
    ],
    "total": 1,
    "engine": "meilisearch"
  }
}
```

---

## 上传接口 (Upload)

### 33. 上传图片

`POST /upload/image` 🔒

**请求格式：** `multipart/form-data`

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| file | file | 是 | 图片文件（支持 jpg/png/gif/webp，最大 5MB） |

**成功响应 (200)：**

```json
{
  "code": 200,
  "message": "上传成功",
  "data": {
    "url": "https://example.com/uploads/2026/09/image.webp",
    "thumb_url": "https://example.com/uploads/2026/09/thumb_image.webp",
    "size": 102400,
    "width": 800,
    "height": 600
  }
}
```

**错误响应：**
- 403：无权上传附件

---

### 34. 上传头像

`POST /upload/avatar` 🔒

**请求格式：** `multipart/form-data`

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| file | file | 是 | 头像图片（最大 5MB） |

**成功响应 (200)：**

```json
{
  "code": 200,
  "message": "头像上传成功",
  "data": {
    "url": "https://example.com/uploads/2026/09/avatar.webp"
  }
}
```

---

## 接口总览

| # | 方法 | 路径 | 认证 | 说明 |
|---|------|------|------|------|
| 1 | POST | /auth/login | 否 | 用户登录 |
| 2 | POST | /auth/verify-2fa | 否 | 两步验证 |
| 3 | POST | /auth/register | 否 | 用户注册 |
| 4 | POST | /auth/send-verify-code | 否 | 发送邮箱验证码 |
| 5 | POST | /auth/refresh-token | 否 | 刷新 Token |
| 6 | POST | /auth/logout | 是 | 用户登出 |
| 7 | GET | /auth/profile | 是 | 获取当前用户信息 |
| 8 | GET | /topics | 否 | 获取帖子列表 |
| 9 | GET | /topics/{id} | 否 | 获取帖子详情 |
| 10 | POST | /topics | 是 | 创建帖子 |
| 11 | PUT | /topics/{id} | 是 | 更新帖子 |
| 12 | DELETE | /topics/{id} | 是 | 删除帖子 |
| 13 | POST | /topics/{id}/like | 是 | 点赞/取消点赞 |
| 14 | POST | /topics/{id}/favorite | 是 | 收藏/取消收藏 |
| 15 | POST | /topics/{id}/chicken | 是 | 投喂鱼丸 |
| 16 | GET | /topics/{topic_id}/comments | 否 | 获取评论列表 |
| 17 | POST | /topics/{topic_id}/comments | 是 | 发表评论 |
| 18 | PUT | /comments/{id} | 是 | 更新评论 |
| 19 | DELETE | /comments/{id} | 是 | 删除评论 |
| 20 | GET | /users/me | 是 | 获取当前用户资料 |
| 21 | PUT | /users/update-me | 是 | 更新个人资料 |
| 22 | GET | /users/{id} | 否 | 获取用户资料 |
| 23 | GET | /users/{id}/topics | 否 | 获取用户的帖子 |
| 24 | GET | /users/{id}/comments | 否 | 获取用户的评论 |
| 25 | POST | /users/{id}/follow | 是 | 关注/取消关注 |
| 26 | POST | /messages | 是 | 发送私信 |
| 27 | GET | /messages | 是 | 获取会话列表 |
| 28 | GET | /messages/{id} | 是 | 获取会话消息 |
| 29 | GET | /notifications/count | 是 | 获取未读通知数量 |
| 30 | GET | /notices | 是 | 获取通知列表 |
| 31 | GET | /nodes | 否 | 获取版块列表 |
| 32 | GET | /search | 否 | 搜索帖子和用户 |
| 33 | POST | /upload/image | 是 | 上传图片 |
| 34 | POST | /upload/avatar | 是 | 上传头像 |

---

## Swagger UI

访问 `/api/v1/doc` 可打开交互式 API 文档（Swagger UI），支持在线调试。

访问 `/api/v1/doc/json` 可获取 OpenAPI JSON 规范文件。
