feat: strengthen backup and mobile workflows
ci / gitleaks (push) Successful in 1m19s
ci / docker (push) Successful in 5m48s

This commit is contained in:
2026-09-16 21:12:52 +08:00
parent 6f38190c92
commit 6c234d7d82
64 changed files with 5059 additions and 635 deletions
+55 -39
View File
@@ -1,59 +1,75 @@
# API
Base path: `/api/v1`. 除初始化、登录和健康检查外均需 `dodo_session` Cookie。
Base path: `/api/v1`除初始化、登录和健康检查外,接口均要求 `dodo_session` Cookie;同源写请求使用双提交 CSRF 校验。登录后可访问 `/api/docs``/api/openapi.json`
## Setup / Auth
## 账户与会话
- `GET /setup/status`
- `POST /setup/initialize`
- `POST /auth/login`
- `POST /auth/logout`
- `GET /me`
- `GET /setup/status``POST /setup/initialize`
- `POST /auth/login``POST /auth/logout``POST /auth/change-password`
- `GET/PATCH /me`
- `GET /sessions``DELETE /sessions/{session_id}``DELETE /sessions/others`
- `GET /audit-logs`
## Folders
## 文件夹、清单与任务
- `GET /folders` — 仅返回未删除文件夹
- `POST /folders` — 创建文件夹
- `PATCH /folders/{folder_id}` — 重命名
- `DELETE /folders/{folder_id}` — 软删除;其清单移到根层级
- 文件夹:`GET/POST /folders``PATCH/DELETE /folders/{id}`,以及排序接口
- 清单:`GET/POST /lists``PATCH/DELETE /lists/{id}`,归档恢复、永久删除、移动与排序接口
- 归档清单只标记 `deleted_at`,不会把任务移到收集箱;清单归档期间,其任务在普通列表和详情中不可见,恢复清单后重新出现
- 任务:`GET/POST /tasks``GET/PATCH/DELETE /tasks/{id}``POST /tasks/{id}/restore``DELETE /trash/{id}`
- `GET /tasks``GET /trash` 使用不透明游标;`limit` 为 1100
- `POST /tasks/batch` 支持批量完成、移动、截止时间与软删除;任务写入使用 `version` 乐观锁
- 一层子任务必须与父任务同清单;任务可带日期型或具体时间型截止时间
## Lists
## 重复任务
- `GET /lists` — 仅返回未删除清单,系统收集箱排首位
- `POST /lists` — 创建清单,可指定 `folder_id`
- `PATCH /lists/{list_id}` — 重命名;系统收集箱返回 409
- `DELETE /lists/{list_id}` — 软删除并将任务移入系统收集箱;系统收集箱返回 409
- `GET /tasks/{task_id}/recurrence`
- `POST /recurrences``PATCH/DELETE /recurrences/{id}`
- `POST /recurrences/{id}/complete`
- 支持 RRULE 计划重复与按用户本地完成日期计算的“完成后重复”
## Tasks
## 习惯、倒数日与备忘录
- `GET /tasks?q=&limit=&cursor=` — 顶层未删除任务的游标分页;`q` 匹配标题、描述和清单名
- `POST /tasks` — 创建任务;`parent_id` 只允许指向同清单顶层任务
- `GET /tasks/{task_id}` — 返回任务和一层子任务
- `PATCH /tasks/{task_id}` — 必须携带当前 `version`,原子比较更新;版本冲突返回 409
- `DELETE /tasks/{task_id}` — 软删除任务及其直接子任务
- `POST /tasks/{task_id}/restore` — 恢复任务及其直接子任务
- `POST /tasks/batch` — 原子批量完成、移动、设置截止时间或软删除
- 习惯:创建、列表/周网格、部分更新、排序、归档/恢复/永久删除、日志、暂停和统计
- 倒数日:创建、列表、编辑、置顶、归档/恢复/永久删除;支持公历/农历及周/月/年重复
- 备忘录:游标列表、创建、读取、乐观锁更新、软删除、恢复和归档后永久删除
批量请求字段:`task_ids``completed``list_id``due_at``soft_delete`。所有任务和目标清单在写入前完成归属校验;任一不存在则整批不修改。
## 附件
## Countdowns
- `GET/POST /tasks/{task_id}/attachments`
- `GET/DELETE /attachments/{attachment_id}`
- 文件保存在服务端附件目录;上传受大小与类型限制,访问始终校验当前用户归属
- `GET /countdowns?archived=false` — 查询倒数日;置顶项优先,其余按下一次发生日期排序
- `POST /countdowns` — 创建倒数日、纪念日或生日;支持 `none/weekly/monthly/yearly` 重复
- `PATCH /countdowns/{countdown_id}` — 编辑名称、日期、类型、重复与图标
- `POST /countdowns/{countdown_id}/pin` — 单一置顶,自动取消其他置顶项
- `DELETE /countdowns/{countdown_id}` — 归档
- `POST /countdowns/{countdown_id}/restore` — 恢复归档项
- `DELETE /countdowns/{countdown_id}/purge` — 永久删除已归档项
## 完整备份 ZIP v2
## Recycle bin
### `GET /backup/export.zip`
- `GET /trash?limit=&cursor=` — 已删除顶层任务的游标分页
- `DELETE /trash/{task_id}` — 永久删除任务及其子任务
导出 `dodo-backup` version 2 ZIP。归档包含 `manifest.json`、每类实体的 `data/*.json`、附件元数据和附件原始字节。manifest 声明实体数量及每个条目的 SHA-256。
游标是不透明字符串。无效游标返回 422;`limit` 范围为 1100
实体范围:`folders``lists``tasks``recurrences``recurrence_exceptions``habits``habit_logs``habit_pauses``countdowns``memos``attachments`。会话、密码散列、审计日志及备份内部账本不导出
## Health
### `POST /backup/preflight?mode=merge|replace`
以 multipart 字段 `file` 上传 ZIP。服务端流式暂存,并在返回令牌前验证:ZIP 路径与条目、压缩比/容量、manifest 版本与计数、全部校验和、字段与业务约束、关系拓扑、一层任务树、用户隔离以及附件元数据/字节一致性。
成功返回 `valid`、短期 `preflight_token``backup_id`、归档摘要和各实体数量。预检有每用户待处理数量/容量配额和过期时间;令牌绑定用户、文件摘要和恢复模式。
### `POST /backup/restore`
请求体:
```json
{"preflight_token":"...","mode":"merge"}
```
`merge` 使用持久化 source→target ID/内容摘要账本实现可重试合并;跨用户或同 ID 不同内容冲突会拒绝。`replace` 在事务内替换当前用户业务实体,并通过同文件系统隔离区协调附件删除和失败补偿。令牌单次消费;若数据库已提交但隔离区清理失败,同一令牌仅重试清理,不重复导入。
## 旧格式兼容
- `GET /export``GET /export.csv`:旧版 JSON/UTF-8-BOM CSV v1 轻量导出,不是完整备份
- `POST /restore?mode=merge|replace``POST /restore.csv?mode=merge|replace`:兼容旧 JSON/CSV v1
- 旧格式只覆盖文件夹、清单、任务、重复模板、习惯、倒数日和备忘录;不包含日志、暂停、重复例外和附件字节
## 健康检查
- `GET /health/live`
- `GET /health/ready`