# 云笔记 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 触发器),保证中文分词正确。 --- ## v4 多租户账号体系 ### 认证(用户名 + 密码,bcrypt) | 方法 | 路径 | 说明 | |------|------|------| | POST | `/api/auth/register` | 注册 `{username,password,display_name}`;**首个用户自动成为 admin 并接管历史遗留(user_id=0)笔记** | | POST | `/api/auth/login` | 登录 `{username,password}`,写入 `note_token` cookie | | POST | `/api/auth/logout` | 登出 | | GET | `/api/auth/me` | 当前登录用户信息(游客返回 null) | ### 多租户数据隔离 - 每篇笔记归属 `user_id`;所有查询(笔记/分类/标签/回收站/版本/草稿/图谱/FTS 搜索)均按当前用户隔离。 - **前台 `/api`**:登录用户看自己的笔记(前台可★收藏自己的笔记);游客只读所有用户的公开无密码笔记。 - **后台 `/admin/api`**:需登录,每个用户只能管理自己的笔记(越权访问他人笔记返回 404)。 - 旧账号固定密码登录已移除;会话与用户绑定,重启后需重新登录。 ### 安全 - `note_token` 会话 cookie:HttpOnly + SameSite=Lax(防 CSRF),随机 32 字节 token,7 天过期,服务端内存校验绑定用户。 - 密码 bcrypt(cost 10),兼容旧 SHA-256 自动升级。 ### v5 管理员跨租户管理 + 注册开关 - **管理员跨租户管理**:`admin` 角色的用户可读取/修改/删除/恢复/分享任意用户的笔记,树/列表/回收站/分类/标签/图谱/FTS 均显示全平台数据;普通用户仍只能操作自己的数据(越权 404)。 - **注册开关**:管理员可在后台「⚙ 设置」中开启/关闭注册。关闭后 `/api/auth/register` 返回 400「注册功能已关闭」,前台与登录页隐藏「注册」入口,仅已有账号可登录。 - 默认通过环境变量 `REGISTRATION_ENABLED`(默认 `true`)设置,运行时可在后台切换并持久化。 - 接口: | 方法 | 路径 | 说明 | |------|------|------| | GET | `/admin/api/settings/registration` | 获取注册开关状态(管理员) | | PUT | `/admin/api/settings/registration` | 设置注册开关 `{enabled}`(管理员) | | GET | `/api/auth/me` | 返回当前用户角色及 `registration_enabled` |