feat: complete task management workflow
This commit is contained in:
+38
-9
@@ -1,27 +1,56 @@
|
||||
# API
|
||||
|
||||
Base path: `/api/v1`
|
||||
Base path: `/api/v1`. 除初始化、登录和健康检查外均需 `dodo_session` Cookie。
|
||||
|
||||
## Setup / Auth
|
||||
|
||||
- `GET /setup/status`
|
||||
- `POST /setup/initialize`
|
||||
- `POST /auth/login`
|
||||
- `POST /auth/logout`
|
||||
- `GET /me`
|
||||
|
||||
## Folders
|
||||
- `GET /folders`
|
||||
- `POST /folders`
|
||||
|
||||
- `GET /folders` — 仅返回未删除文件夹
|
||||
- `POST /folders` — 创建文件夹
|
||||
- `PATCH /folders/{folder_id}` — 重命名
|
||||
- `DELETE /folders/{folder_id}` — 软删除;其清单移到根层级
|
||||
|
||||
## Lists
|
||||
- `GET /lists`
|
||||
- `POST /lists`
|
||||
|
||||
- `GET /lists` — 仅返回未删除清单,系统收集箱排首位
|
||||
- `POST /lists` — 创建清单,可指定 `folder_id`
|
||||
- `PATCH /lists/{list_id}` — 重命名;系统收集箱返回 409
|
||||
- `DELETE /lists/{list_id}` — 软删除并将任务移入系统收集箱;系统收集箱返回 409
|
||||
|
||||
## Tags
|
||||
|
||||
标签属于当前用户,可跨清单复用。
|
||||
|
||||
- `GET /tags`
|
||||
- `POST /tags` — `{name, color}`;同一用户名称唯一
|
||||
|
||||
## Tasks
|
||||
- `GET /tasks`
|
||||
- `POST /tasks`
|
||||
- `PATCH /tasks/{task_id}` — 必须携带当前 `version`,冲突返回 409
|
||||
- `DELETE /tasks/{task_id}` — 软删除
|
||||
|
||||
- `GET /tasks?q=&limit=&cursor=` — 顶层未删除任务的游标分页;`q` 匹配标题、描述、标签名和清单名
|
||||
- `POST /tasks` — 创建任务;`parent_id` 只允许指向同清单顶层任务;`tag_ids` 必须属于当前用户
|
||||
- `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`、`tag_ids`、`soft_delete`。所有任务、目标清单和标签在写入前完成归属校验;任一不存在则整批不修改。
|
||||
|
||||
## Recycle bin
|
||||
|
||||
- `GET /trash?limit=&cursor=` — 已删除顶层任务的游标分页
|
||||
- `DELETE /trash/{task_id}` — 永久删除任务及其子任务
|
||||
|
||||
游标是不透明字符串。无效游标返回 422;`limit` 范围为 1–100。
|
||||
|
||||
## Health
|
||||
|
||||
- `GET /health/live`
|
||||
- `GET /health/ready`
|
||||
|
||||
+77
-40
@@ -1,60 +1,97 @@
|
||||
# dodo 数据模型(第一阶段)
|
||||
# dodo 数据模型
|
||||
|
||||
所有业务实体使用 UUIDv7 主键并按 `user_id` 隔离。生产使用 PostgreSQL,测试使用 SQLite;模型保持两者兼容。
|
||||
|
||||
## app_state
|
||||
- key
|
||||
- created_at
|
||||
|
||||
- `key` 主键
|
||||
- `created_at`
|
||||
|
||||
## users
|
||||
- id UUIDv7
|
||||
- username
|
||||
- password_hash
|
||||
- timezone
|
||||
- created_at
|
||||
|
||||
- `id`
|
||||
- `username` 唯一
|
||||
- `password_hash`
|
||||
- `timezone`
|
||||
- `created_at`
|
||||
|
||||
## sessions
|
||||
- id UUIDv7
|
||||
- token_hash
|
||||
- user_id
|
||||
- expires_at
|
||||
- created_at
|
||||
|
||||
- `id`
|
||||
- `token_hash` 唯一
|
||||
- `user_id` → users,级联删除
|
||||
- `expires_at`
|
||||
- `created_at`
|
||||
|
||||
## folders
|
||||
- id UUIDv7
|
||||
- user_id
|
||||
- name
|
||||
- position
|
||||
- created_at
|
||||
|
||||
- `id`
|
||||
- `user_id` → users
|
||||
- `name`
|
||||
- `position`
|
||||
- `created_at`
|
||||
- `deleted_at`,非空表示软删除
|
||||
|
||||
删除文件夹不会删除清单;清单的 `folder_id` 被置空。
|
||||
|
||||
## task_lists
|
||||
- id UUIDv7
|
||||
- user_id
|
||||
- folder_id nullable
|
||||
- name
|
||||
- is_inbox
|
||||
- position
|
||||
- created_at
|
||||
|
||||
- `id`
|
||||
- `user_id` → users
|
||||
- `folder_id` → folders,可空
|
||||
- `name`
|
||||
- `is_inbox`,每个用户初始化时创建一个受保护的系统收集箱
|
||||
- `position`
|
||||
- `created_at`
|
||||
- `deleted_at`,非空表示软删除
|
||||
|
||||
删除普通清单时,其未删除任务原子移动到系统收集箱。系统收集箱不可重命名或删除。
|
||||
|
||||
## tags
|
||||
|
||||
- `id`
|
||||
- `user_id` → users
|
||||
- `name`,同一用户内唯一
|
||||
- `color`
|
||||
- `created_at`
|
||||
|
||||
标签是用户级全局实体,不隶属于清单。
|
||||
|
||||
## task_tags
|
||||
|
||||
- `task_id` → tasks
|
||||
- `tag_id` → tags
|
||||
- `(task_id, tag_id)` 联合主键
|
||||
|
||||
## tasks
|
||||
- id UUIDv7
|
||||
- user_id
|
||||
- list_id
|
||||
- parent_id nullable
|
||||
- title
|
||||
- description
|
||||
- priority (0-3)
|
||||
- completed
|
||||
- due_at nullable
|
||||
- version
|
||||
- position
|
||||
- created_at
|
||||
- updated_at
|
||||
- deleted_at nullable
|
||||
|
||||
- `id`
|
||||
- `user_id` → users
|
||||
- `list_id` → task_lists
|
||||
- `parent_id` → tasks,可空;仅允许一层子任务且必须与父任务同清单
|
||||
- `title`
|
||||
- `description`
|
||||
- `priority`(0–3)
|
||||
- `completed`
|
||||
- `due_at`,可空
|
||||
- `version`,乐观锁版本;单任务更新用 `id + user_id + version` 原子比较更新
|
||||
- `position`
|
||||
- `created_at`
|
||||
- `updated_at`
|
||||
- `deleted_at`,非空表示进入回收站
|
||||
|
||||
顶层任务软删除、恢复或永久删除时同步处理直接子任务。列表与回收站使用 `(created_at, id)` 作为稳定游标排序键。
|
||||
|
||||
## 迁移
|
||||
|
||||
- `0001_initial.py`:已部署的初始模式,不修改
|
||||
- `0002_task_management.py`:新增文件夹/清单软删除列、标签表、任务标签关联表及游标/回收站索引
|
||||
|
||||
## 后续阶段预留
|
||||
|
||||
- task_reminders
|
||||
- task_recurrence_templates
|
||||
- task_recurrence_exceptions
|
||||
- tags / task_tags
|
||||
- habits / habit_logs / habit_reminders
|
||||
- attachments
|
||||
- audit_logs
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
# dodo 产品与技术决策记录
|
||||
|
||||
## 定位
|
||||
|
||||
dodo 是一个纯自托管的 TickTick-like 任务与习惯管理工具。目标不是一比一复刻 TickTick,而是做一个数据归自己、界面温暖紧凑、适合个人长期使用的任务系统。
|
||||
|
||||
## 当前边界
|
||||
|
||||
- 首版只做本地开发验证,不部署。
|
||||
- 首版不做通知渠道:Web Push、Telegram、SMTP 暂不实现。
|
||||
- 首版附件只做本地存储,不实现 S3。
|
||||
- 首版不做番茄钟。
|
||||
- 首版不做自然语言创建任务。
|
||||
|
||||
## 技术栈
|
||||
|
||||
- Monorepo:`frontend/`、`backend/`、`worker/`
|
||||
- 前端:Vue 3 + TypeScript + Vite + Tailwind CSS + Shadcn-vue/Reka UI
|
||||
- 后端:FastAPI + Pydantic v2 + SQLAlchemy 2 Async + Alembic
|
||||
- 数据库:PostgreSQL,主键 UUIDv7,时间统一 UTC,用户配置时区
|
||||
- 后台:独立 Worker + APScheduler
|
||||
- 包管理:uv + pnpm
|
||||
- 交付:单 Docker 镜像,外部 PostgreSQL
|
||||
- 许可证:AGPL-3.0
|
||||
|
||||
## 数据库
|
||||
|
||||
本地开发数据库:
|
||||
|
||||
```text
|
||||
postgresql+asyncpg://postgres:***@10.10.100.99:5433/dodo
|
||||
```
|
||||
|
||||
已从默认 `postgres` 库迁移到独立 `dodo` 库。误建在 `postgres.public` 的 dodo 表已清理。
|
||||
|
||||
## 产品模型
|
||||
|
||||
### 任务
|
||||
|
||||
- 文件夹 → 清单 → 任务
|
||||
- 系统内置收集箱,不允许删除
|
||||
- 任务支持一层子任务
|
||||
- 状态:未完成 / 已完成
|
||||
- 优先级:无 / 低 / 中 / 高
|
||||
- Markdown 描述
|
||||
- 截止日期 + 具体时间
|
||||
- 多提醒设计预留
|
||||
- 全局彩色标签
|
||||
- 删除为软删除,回收站手动清空
|
||||
- 支持创建、修改、完成、恢复、删除操作历史
|
||||
- 并发编辑使用原子乐观锁
|
||||
|
||||
### 重复任务
|
||||
|
||||
- RFC 5545 RRULE
|
||||
- 模板 + 实例
|
||||
- 修改范围:仅本次 / 本次及以后 / 全部
|
||||
- 删除单次保存为例外
|
||||
- 每月 31 日在无 31 日月份跳过
|
||||
- 逾期完成不影响下次计划日期
|
||||
|
||||
### 习惯
|
||||
|
||||
- 完成型 + 数值型
|
||||
- 每天 / 每周 / 每月 / 间隔天数
|
||||
- 数值型当日累计,达标后封顶
|
||||
- 允许补打和修改历史
|
||||
- 支持暂停区间,暂停期不破坏连续记录
|
||||
- 归档后保留历史统计
|
||||
|
||||
## UI 方向
|
||||
|
||||
- 手账生活感
|
||||
- 中高信息密度
|
||||
- 10–12px 中等圆角
|
||||
- 细分割线为主,少量浅底色
|
||||
- 强调色:`#F15A29`
|
||||
- 只做浅色模式
|
||||
- 系统字体栈
|
||||
- 不使用猫猫元素
|
||||
- 轻微动效
|
||||
|
||||
## 页面结构
|
||||
|
||||
- 桌面三栏:左导航 / 中任务列表 / 右任务详情
|
||||
- 手机底部导航
|
||||
- 顶部快速输入,手机悬浮新增按钮
|
||||
- 桌面右侧详情栏,手机底部弹层
|
||||
- 日历默认月视图
|
||||
- 习惯首页:今日习惯列表 + 一周打卡格
|
||||
- 搜索:顶部搜索框 + 全局搜索快捷键
|
||||
|
||||
## 工程质量
|
||||
|
||||
- `/api/v1` API 路径
|
||||
- 统一错误码、可读提示和字段详情
|
||||
- 页面内诊断信息 + Toast
|
||||
- readiness 检查数据库
|
||||
- 首版不提供 Prometheus metrics
|
||||
- 审计日志记录操作人、实体、动作、时间和变更摘要
|
||||
- 手动 JSON 全量导出
|
||||
- 附件默认 20MB,可用环境变量调整
|
||||
- 默认允许常用文档与图片,拒绝危险文件类型
|
||||
|
||||
## 第一阶段验收
|
||||
|
||||
- 可初始化管理员
|
||||
- 可登录
|
||||
- 可创建清单和任务
|
||||
- 后端测试通过
|
||||
- 前端生产构建通过
|
||||
- PostgreSQL 迁移成功
|
||||
- 本地应用可以启动并访问
|
||||
Reference in New Issue
Block a user