# 搜索与标签接口说明（给后端）

前端搜索体验依赖后端两件事：①`/api/posts/search` 做**模糊搜索**；②新增 `/api/tags`
返回完整标签列表。下面是前端目前的调用方式与期望。

---

## 1. 模糊搜索：`GET /api/posts/search`

### 现状
- 前端在用户输入关键字或点击标签时，调用此接口，只负责把 `q` 传过去。
- **匹配方式（模糊 / 精确）完全由后端决定**，前端无法控制。
- 页面提示写明「支持搜索：标题 · 分类 · 标签 · 简介 · 文件类型 · 正文」，因此期望是
  **跨这些字段的模糊匹配**。请确认当前实现；若为精确匹配（`= q`），需改为模糊。

### 查询参数（前端实际会带的）
| 参数 | 必填 | 说明 | 示例 |
|---|---|---|---|
| `q` | 是 | 搜索关键字（已 trim） | `海报` |
| `lang` | 是 | 界面语言 | `zh-CN` / `en` |
| `limit` | 是 | 每页数量 | `20`（标签预览用 `12`） |
| `cursor` | 否 | 分页游标（上一页返回的 `nextCursor`） | |
| `category` | 否 | 分类 slug（在分类页内搜索时） | `tutorial` |
| `type` | 否 | 资源类型过滤 | `image`/`video`/`music`/`pdf`/`ppt`/`text`/`link`/`archive` |
| `sort` | 否 | 排序 | `latest`/`popular`/`recommended` |
| `language` | 否 | 资料源语言过滤 | |

### 期望的匹配规则（模糊）
- 对 `q` 做**部分匹配**（`LIKE %q%` 或全文索引），**大小写不敏感**。
- 匹配字段：**标题、分类名、标签、简介、文件类型、正文**（与页面提示一致）。
- 中文建议用全文索引 / 分词（如 MySQL FULLTEXT、PostgreSQL `pg_trgm`/`tsvector`、或 ES），
  避免仅按整词精确匹配。
- 建议按**相关度排序**（命中标题 > 标签 > 正文…）；无 `sort` 时默认相关度，有 `sort`
  时按指定排序。
- （可选增强）错别字容错、拼音匹配。

### 返回结构（与 `/api/posts` 一致）
```jsonc
{
  "items": [ /* Post[] */ ],
  "nextCursor": "..."   // 还有下一页时返回；没有则省略/为空
}
```
`Post` 关键字段：`id, categoryId, categorySlug, language, text?, attachments[],
isRecommended, publishedAt, updatedAt?, tags?: string[], postType?`。

---

## 2. 标签列表：新增 `GET /api/tags`

### 现状（痛点）
- 「现有标签」目前是前端从**最新 80 条**帖子里现算出来的（取前 12 个高频标签），
  **不完整、也不稳定**——更早的帖子里的标签不会出现。

### 期望
新增接口直接返回**全部标签 + 计数**，前端不再现算。

```
GET /api/tags?lang=zh-CN
```
| 参数 | 必填 | 说明 |
|---|---|---|
| `lang` | 是 | 界面语言（用于本地化标签名，若有） |

返回：
```jsonc
{
  "tags": [
    { "name": "图片", "count": 128 },
    { "name": "教程", "count": 96 }
    // 按 count 降序
  ]
}
```
- 按 `count` 降序；前端会自行截取展示数量。
- 只统计**已发布 / 公开**的帖子。

---

## 验收要点
- [ ] `/api/posts/search?q=部分词` 能返回包含该词的结果（标题/标签/正文等任一命中），
      大小写不敏感。
- [ ] 同一关键字在「搜索框」和「分类内搜索」表现一致。
- [ ] `/api/tags` 返回全量标签（不止最新 80 条里的）。

> 前端已就绪：搜索框/标签都走上面的参数；标签支持再次点击取消。后端按本文件落地后，
> 前端只需把「现有标签」数据源从现算切换到 `/api/tags`（小改动，待接口可用后进行）。
