b93c6f1e16
- FTS5中文分词搜索(需-tags=sqlite_fts5) - [[wiki链接]]反向链接+SVG知识图谱 - 自动保存草稿(不触发版本历史) - 标签重命名/合并/删除+使用统计 - 后台编辑实时预览+格式工具栏 - PWA manifest+service worker+移动端适配 - 冒烟测试扩至66例全通过
719 lines
14 KiB
Markdown
719 lines
14 KiB
Markdown
# 云笔记 API 文档
|
||
|
||
## 基础信息
|
||
|
||
- **Base URL**:`http://localhost:8080/api`
|
||
- **认证方式**:Cookie(后台管理接口需要)
|
||
- **默认密码**:`admin123`
|
||
|
||
---
|
||
|
||
## 公开接口
|
||
|
||
公开接口无需认证即可访问(只读)。
|
||
|
||
### 1. 获取笔记列表
|
||
|
||
获取分页的笔记列表。
|
||
|
||
**请求**
|
||
|
||
```
|
||
GET /api/notes
|
||
```
|
||
|
||
**Query 参数**
|
||
|
||
| 参数 | 类型 | 必填 | 说明 | 默认值 |
|
||
|------|------|------|------|--------|
|
||
| page | int | 否 | 页码 | 1 |
|
||
| page_size | int | 否 | 每页数量 | 20 |
|
||
| category | string | 否 | 按分类筛选 | - |
|
||
| tag | string | 否 | 按标签筛选 | - |
|
||
| pinned | bool | 否 | 只看置顶 | - |
|
||
| favorite | bool | 否 | 只看收藏 | - |
|
||
| parent_id | int | 否 | 按父目录筛选 | - |
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "success",
|
||
"data": {
|
||
"items": [
|
||
{
|
||
"id": 1,
|
||
"title": "Go 语言教程",
|
||
"category": "技术",
|
||
"tags": "[\"Go\",\"编程\"]",
|
||
"is_pinned": true,
|
||
"is_favorite": false,
|
||
"is_folder": false,
|
||
"parent_id": 0,
|
||
"sort_order": 0,
|
||
"created_at": "2024-01-15T10:30:00Z",
|
||
"updated_at": "2024-01-15T10:30:00Z"
|
||
}
|
||
],
|
||
"total": 50,
|
||
"page": 1,
|
||
"page_size": 20,
|
||
"total_pages": 3
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 2. 获取单条笔记
|
||
|
||
根据 ID 获取笔记详情。
|
||
|
||
**请求**
|
||
|
||
```
|
||
GET /api/notes/:id
|
||
```
|
||
|
||
**路径参数**
|
||
|
||
| 参数 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| id | int | 笔记 ID |
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "success",
|
||
"data": {
|
||
"id": 1,
|
||
"title": "Go 语言教程",
|
||
"content": "# Go 语言\\n\\nGo 是一门简洁高效的编程语言。",
|
||
"category": "技术",
|
||
"tags": "[\"Go\",\"编程\"]",
|
||
"is_pinned": true,
|
||
"is_favorite": false,
|
||
"is_folder": false,
|
||
"parent_id": 0,
|
||
"created_at": "2024-01-15T10:30:00Z",
|
||
"updated_at": "2024-01-15T10:30:00Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 3. 搜索笔记
|
||
|
||
搜索标题和内容。
|
||
|
||
**请求**
|
||
|
||
```
|
||
GET /api/notes/search
|
||
```
|
||
|
||
**Query 参数**
|
||
|
||
| 参数 | 类型 | 必填 | 说明 | 默认值 |
|
||
|------|------|------|------|--------|
|
||
| q | string | 是 | 搜索关键词 | - |
|
||
| page | int | 否 | 页码 | 1 |
|
||
| page_size | int | 否 | 每页数量 | 20 |
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "success",
|
||
"data": {
|
||
"items": [...],
|
||
"total": 5,
|
||
"page": 1,
|
||
"page_size": 20,
|
||
"total_pages": 1
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 4. 获取分类列表
|
||
|
||
获取所有分类。
|
||
|
||
**请求**
|
||
|
||
```
|
||
GET /api/categories
|
||
```
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "success",
|
||
"data": ["技术", "生活", "工作", "随笔"]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 5. 获取标签列表
|
||
|
||
获取所有标签。
|
||
|
||
**请求**
|
||
|
||
```
|
||
GET /api/tags
|
||
```
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "success",
|
||
"data": ["Go", "Python", "JavaScript", "编程", "笔记"]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 6. 获取树形结构
|
||
|
||
获取目录树形结构(包含目录和笔记)。
|
||
|
||
**请求**
|
||
|
||
```
|
||
GET /api/tree
|
||
```
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "success",
|
||
"data": [
|
||
{
|
||
"id": 1,
|
||
"title": "技术文档",
|
||
"is_folder": true,
|
||
"children": [
|
||
{
|
||
"id": 2,
|
||
"title": "Go 语言教程",
|
||
"is_folder": false
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": 3,
|
||
"title": "生活随笔",
|
||
"is_folder": false
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 管理接口
|
||
|
||
管理接口需要先登录,获取 Cookie 认证。
|
||
|
||
### 7. 登录
|
||
|
||
**请求**
|
||
|
||
```
|
||
POST /admin/login
|
||
```
|
||
|
||
**Body 参数**
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| password | string | 是 | 管理员密码 |
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "登录成功"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 8. 登出
|
||
|
||
**请求**
|
||
|
||
```
|
||
POST /admin/logout
|
||
```
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "已退出登录"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 9. 检查认证状态
|
||
|
||
**请求**
|
||
|
||
```
|
||
GET /admin/auth
|
||
```
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"authenticated": true
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 10. 创建笔记/目录
|
||
|
||
**请求**
|
||
|
||
```
|
||
POST /api/notes
|
||
```
|
||
|
||
**Body 参数**
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| title | string | 是 | 标题 |
|
||
| content | string | 否 | 内容(Markdown) |
|
||
| category | string | 否 | 分类 |
|
||
| tags | string | string | 标签(JSON 数组格式) |
|
||
| is_folder | bool | 否 | 是否为文件夹 |
|
||
| is_pinned | bool | 否 | 是否置顶 |
|
||
| is_favorite | bool | 否 | 是否收藏 |
|
||
| parent_id | int | 否 | 父目录 ID |
|
||
| sort_order | int | 否 | 排序顺序 |
|
||
|
||
**请求示例**
|
||
|
||
```json
|
||
{
|
||
"title": "新建笔记",
|
||
"content": "# 我的笔记\\n\\n这是笔记内容",
|
||
"category": "技术",
|
||
"tags": "[\"笔记\",\"教程\"]",
|
||
"is_folder": false
|
||
}
|
||
```
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "笔记创建成功",
|
||
"data": {
|
||
"id": 10
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 11. 更新笔记/目录
|
||
|
||
**请求**
|
||
|
||
```
|
||
PUT /api/notes/:id
|
||
```
|
||
|
||
**Body 参数**
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| title | string | 否 | 标题 |
|
||
| content | string | 否 | 内容(Markdown) |
|
||
| category | string | 否 | 分类 |
|
||
| tags | string | 否 | 标签 |
|
||
| is_pinned | bool | 否 | 是否置顶 |
|
||
| is_favorite | bool | 否 | 是否收藏 |
|
||
| parent_id | int | 否 | 父目录 ID |
|
||
| sort_order | int | 否 | 排序顺序 |
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "笔记更新成功"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 12. 删除笔记/目录
|
||
|
||
**请求**
|
||
|
||
```
|
||
DELETE /api/notes/:id
|
||
```
|
||
|
||
**说明**:删除目录时会同时删除该目录下的所有子项。
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "笔记删除成功"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 响应状态码
|
||
|
||
| code | 说明 |
|
||
|------|------|
|
||
| 0 | 成功 |
|
||
| 400 | 请求参数错误 |
|
||
| 401 | 未授权(需要登录) |
|
||
| 404 | 笔记不存在 |
|
||
| 500 | 服务器内部错误 |
|
||
|
||
---
|
||
|
||
## 密码保护笔记接口
|
||
|
||
### 访问密码保护的笔记
|
||
|
||
**请求**
|
||
|
||
```
|
||
POST /api/notes/:id/access
|
||
```
|
||
|
||
**Body 参数**
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| password | string | 是 | 笔记访问密码 |
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "访问成功",
|
||
"data": {
|
||
"id": 1,
|
||
"title": "受保护的笔记",
|
||
"content": "# 笔记内容..."
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 图片上传接口
|
||
|
||
### 上传图片
|
||
|
||
**请求**
|
||
|
||
```
|
||
POST /admin/api/upload
|
||
```
|
||
|
||
**说明**:需要登录认证。仅支持 jpg、png、gif、webp、bmp 格式,最大 5MB。
|
||
|
||
**Form 参数**
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| image | file | 是 | 图片文件 |
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "上传成功",
|
||
"data": {
|
||
"url": "/uploads/1234567890_abc123.png"
|
||
}
|
||
}
|
||
```
|
||
|
||
**图片访问**:上传后的图片通过 `/uploads/文件名` 访问。
|
||
|
||
---
|
||
|
||
## 导入导出接口
|
||
|
||
### 导出笔记为 Markdown
|
||
|
||
**请求**
|
||
|
||
```
|
||
GET /admin/api/export/:id
|
||
```
|
||
|
||
**说明**:需要登录认证。导出的文件包含 YAML front matter。
|
||
|
||
**响应**:下载 `.md` 文件,文件名以笔记标题命名。
|
||
|
||
---
|
||
|
||
### 导入 Markdown 文件
|
||
|
||
**请求**
|
||
|
||
```
|
||
POST /admin/api/import
|
||
```
|
||
|
||
**说明**:需要登录认证。仅支持 `.md` 文件。
|
||
|
||
**Form 参数**
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| file | file | 是 | Markdown 文件 |
|
||
|
||
**响应示例**
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "导入成功",
|
||
"data": {
|
||
"id": 15,
|
||
"title": "导入的笔记标题"
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 错误响应示例
|
||
|
||
```json
|
||
{
|
||
"code": 401,
|
||
"message": "请先登录后台管理"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 使用示例
|
||
|
||
### cURL
|
||
|
||
```bash
|
||
# 登录
|
||
curl -X POST http://localhost:8080/admin/login \
|
||
-d "password=admin123" \
|
||
-c cookies.txt
|
||
|
||
# 获取笔记列表
|
||
curl http://localhost:8080/api/notes
|
||
|
||
# 搜索笔记
|
||
curl "http://localhost:8080/api/notes/search?q=Go"
|
||
|
||
# 创建笔记(需要认证)
|
||
curl -X POST http://localhost:8080/api/notes \
|
||
-H "Content-Type: application/json" \
|
||
-b cookies.txt \
|
||
-d '{"title":"新笔记","content":"# 标题\\n\\n内容"}'
|
||
|
||
# 更新笔记(需要认证)
|
||
curl -X PUT http://localhost:8080/api/notes/1 \
|
||
-H "Content-Type: application/json" \
|
||
-b cookies.txt \
|
||
-d '{"title":"更新后的标题"}'
|
||
|
||
# 删除笔记(需要认证)
|
||
curl -X DELETE http://localhost:8080/api/notes/1 -b cookies.txt
|
||
```
|
||
|
||
### JavaScript (Fetch API)
|
||
|
||
```javascript
|
||
// 登录
|
||
await fetch('/admin/login', {
|
||
method: 'POST',
|
||
body: new URLSearchParams({ password: 'admin123' }),
|
||
credentials: 'include'
|
||
});
|
||
|
||
// 获取笔记列表
|
||
const res = await fetch('/api/notes');
|
||
const data = await res.json();
|
||
|
||
// 创建笔记
|
||
await fetch('/api/notes', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ title: '新笔记', content: '# 内容' }),
|
||
credentials: 'include'
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
# 新增功能 API(v2)
|
||
|
||
## 管理接口认证(安全优化)
|
||
|
||
后台管理写操作(创建/更新/删除/回收站/版本/分享/导入导出/上传)统一走 `/admin/api`,
|
||
需登录后携带服务端会话 cookie(随机 token,非固定字符串)。未登录返回 401。
|
||
|
||
## 安全策略调整
|
||
|
||
### 公开接口 `GET /api/notes/:id`
|
||
仅返回 **公开且未设置密码** 的笔记完整内容。带密码或未公开的笔记返回 403(需走密码验证接口),
|
||
防止绕过密码保护直接读取内容。
|
||
|
||
## 回收站(软删除)
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| GET | `/admin/api/trash` | 回收站列表(含已删除的目录和笔记) |
|
||
| POST | `/admin/api/restore/:id` | 恢复笔记/目录(目录连子树一起恢复) |
|
||
| POST | `/admin/api/purge/:id` | 彻底删除(不可恢复,含版本历史) |
|
||
| POST | `/admin/api/empty-trash` | 清空回收站 |
|
||
|
||
删除笔记 `DELETE /admin/api/notes/:id` 现为软删除(进入回收站),目录删除会连带软删除所有子项。
|
||
|
||
## 版本历史
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| GET | `/admin/api/notes/:id/versions` | 获取笔记全部历史版本 |
|
||
| POST | `/admin/api/notes/:id/restore-version` | 恢复指定版本(form: `version_id`) |
|
||
|
||
每次保存(标题或内容变化)自动生成快照。
|
||
|
||
## 分享链接
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| POST | `/admin/api/notes/:id/share` | 创建分享(form: `expire_hours`,0=永久) |
|
||
| POST | `/admin/api/notes/:id/revoke-share` | 撤销分享 |
|
||
| GET | `/api/share/:token` | 公开获取分享笔记 JSON(有密码需带 `?password=`) |
|
||
| GET | `/share/:token` | 分享阅读页(HTML) |
|
||
|
||
## 批量导出
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| GET | `/admin/api/export-all` | 全部笔记导出为 zip(按目录结构 + YAML front matter) |
|
||
|
||
## 图片上传(安全增强)
|
||
|
||
上传会做**内容嗅探**(magic bytes 校验),不仅检查扩展名。伪装成图片的脚本会被拒绝。
|
||
|
||
## 后台管理笔记接口
|
||
|
||
管理端读取/写笔记统一走 `/admin/api/notes`(可访问私有、带密码笔记):
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| POST | `/admin/api/notes` | 创建 |
|
||
| GET | `/admin/api/notes/:id` | 详情(完整内容) |
|
||
| PUT | `/admin/api/notes/:id` | 更新 |
|
||
| DELETE | `/admin/api/notes/:id` | 软删除 |
|
||
|
||
## 前端新增功能
|
||
|
||
- **深色模式**:前台/后台均可切换(🌙/☀️ 按钮),偏好存 localStorage
|
||
- **Mermaid 图表**:前台 Markdown 中 ` ```mermaid ` 代码块渲染为流程图/时序图等
|
||
- **待办清单**:前台渲染 `- [ ]` / `- [x]` 可勾选清单
|
||
- **字数统计**:前台笔记详情显示字数与预估阅读时长
|
||
- **回收站/版本历史/分享**:后台工具栏按钮 + 面板
|
||
|
||
## v3 新增功能(2026-08-11)
|
||
|
||
### FTS5 全文搜索
|
||
|
||
`GET /api/notes/search?q=关键词&page=1` 现使用 **SQLite FTS5 全文索引**,支持中文短词(1~2 字)与英文。
|
||
|
||
- 采用 `unicode61` 分词器 + Go 层对中文做逐字分词(`segmentCJK`),使每个汉字独立成词元,支持短词搜索
|
||
- 索引在创建/更新/标签变更时增量维护,启动时全量重建
|
||
- 搜索结果按 `bm25` 相关度排序,排除已删除笔记与目录
|
||
- FTS 查询失败时自动回退到传统 LIKE 搜索
|
||
- 构建需启用 `-tags=sqlite_fts5`(否则报 `no such module: fts5`)
|
||
|
||
### 双向链接 / 知识图谱
|
||
|
||
支持 `[[笔记标题]]` wiki 链接语法:
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| GET | `/admin/api/notes/:id/backlinks` | 反向链接(谁链接到了该笔记) |
|
||
| GET | `/admin/api/graph` | 知识图谱数据 `{nodes:[{id,title}], edges:[{source,target}]}` |
|
||
|
||
- 后台编辑器支持点击 `[[链接]]` 跳转并高亮
|
||
- 后台工具栏「🕸 知识图谱」以 SVG 图形化展示节点与链接关系
|
||
|
||
### 自动保存草稿
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| POST | `/admin/api/notes/:id/draft` | 保存草稿(body `{content}`),不触发版本历史 |
|
||
| DELETE | `/admin/api/notes/:id/draft` | 清除草稿(保存正文成功后调用) |
|
||
|
||
- 后台编辑器每 8 秒自动保存未落盘内容
|
||
- 打开笔记时若存在未保存草稿会提示恢复
|
||
|
||
### 标签管理
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| GET | `/admin/api/tags/usage` | 标签使用统计 `[{name,count}]` |
|
||
| POST | `/admin/api/tags/rename` | 重命名 `{old_name,new_name}` |
|
||
| POST | `/admin/api/tags/merge` | 合并 `{from,to}`(from 并入 to) |
|
||
| DELETE | `/admin/api/tags` | 删除 `{name}` |
|
||
|
||
- 后台工具栏「🏷 标签管理」图形化操作
|
||
- 重命名/合并/删除会同步更新所有含该标签的笔记及其全文索引
|
||
|
||
### 富文本所见即所得(编辑器增强)
|
||
|
||
- 后台编辑器新增**实时预览**:编辑右侧即时渲染 Markdown
|
||
- 新增**格式工具栏**:加粗/斜体/标题/列表/链接/代码/图片/表格/任务清单
|
||
- 仍以 Markdown 为存储源(保证 FTS/反向链接/导出兼容),预览所见即所得
|
||
|
||
### 移动端 / PWA
|
||
|
||
- 新增 PWA 支持:`/manifest.json`、`/sw.js`、图标 `icon-192.png`/`icon-512.png`
|
||
- 前台页面响应式适配手机(侧栏折叠、字号/按钮优化)
|
||
- 可添加到主屏幕离线使用
|
||
|
||
> 注:FTS5 需用 `-tags=sqlite_fts5` 编译;`note_search` 虚拟表由 Go 代码维护(手动管理而非 SQL 触发器),保证中文分词正确。
|