docs: 更新批量操作与备份恢复说明,新增 ADR-006
- README 补充批量添加/删除、导入前自动备份、归档恢复与 CI 说明 - ADR-006 记录覆盖式操作前快照、id 查重与未保存确认等决策
This commit is contained in:
+56
-11
@@ -13,8 +13,9 @@
|
||||
MVP 固定三列:`todo`(待办)/ `doing`(进行中)/ `done`(已完成)。`status` 使用 TypeScript 字面量联合类型,**不使用 `enum`**(同时满足 `erasableSyntaxOnly` 编译约束)。
|
||||
|
||||
**被否决的方案**
|
||||
- *引入 `columns` 表 + `task.columnId`*:需要额外的列 CRUD、列删除时的任务迁移、列顺序持久化。对单人任务管理而言,收益为零,成本约为原方案的两倍。
|
||||
- *用 `enum` 定义列*:与 `erasableSyntaxOnly: true` 冲突,且 `enum` 在纯类型场景下没有优势。
|
||||
|
||||
- _引入 `columns` 表 + `task.columnId`_:需要额外的列 CRUD、列删除时的任务迁移、列顺序持久化。对单人任务管理而言,收益为零,成本约为原方案的两倍。
|
||||
- _用 `enum` 定义列_:与 `erasableSyntaxOnly: true` 冲突,且 `enum` 在纯类型场景下没有优势。
|
||||
|
||||
**影响**
|
||||
若未来确需自定义列,需一次性迁移 `status` → `columnId`,并在 `schemaVersion` 中登记。
|
||||
@@ -30,8 +31,9 @@ MVP 固定三列:`todo`(待办)/ `doing`(进行中)/ `done`(已完
|
||||
定义 `TaskRepository` 接口(`list / get / create / update / remove / replaceAll`),MVP 只提供 localStorage 实现。UI 与 Store 仅依赖接口,不感知具体实现。
|
||||
|
||||
**被否决的方案**
|
||||
- *直接用 Dexie*:收益是索引查询与大容量,在该规模下用不上;代价是 Pinia 与 DB 双份状态、异步竞态、多标签页同步、测试需引入 `fake-indexeddb`,约多花 1.5 人天。
|
||||
- *直接在组件里读写 localStorage*:数据访问散落各处,无法测试,也无法替换实现。
|
||||
|
||||
- _直接用 Dexie_:收益是索引查询与大容量,在该规模下用不上;代价是 Pinia 与 DB 双份状态、异步竞态、多标签页同步、测试需引入 `fake-indexeddb`,约多花 1.5 人天。
|
||||
- _直接在组件里读写 localStorage_:数据访问散落各处,无法测试,也无法替换实现。
|
||||
|
||||
**影响**
|
||||
数据量增长到万级或需要复杂查询时,新增一个 Dexie 实现并切换注入即可,接口不变。
|
||||
@@ -47,8 +49,9 @@ MVP 固定三列:`todo`(待办)/ `doing`(进行中)/ `done`(已完
|
||||
`dueDate` 类型为 `string | null`,格式固定 `YYYY-MM-DD`,不含时刻与时区信息。「是否逾期」以本地日历日比较得出。
|
||||
|
||||
**被否决的方案**
|
||||
- *存储 ISO 8601 完整时间戳*:需要引入时区处理,且个人看板不需要精确到分钟的截止时间。
|
||||
- *存储 `Date` 对象*:JSON 序列化后仍会退化为字符串,且容易在反序列化时引入时区偏移。
|
||||
|
||||
- _存储 ISO 8601 完整时间戳_:需要引入时区处理,且个人看板不需要精确到分钟的截止时间。
|
||||
- _存储 `Date` 对象_:JSON 序列化后仍会退化为字符串,且容易在反序列化时引入时区偏移。
|
||||
|
||||
**影响**
|
||||
若未来需要提醒功能,应新增独立字段(如 `remindAt`),而不是改变 `dueDate` 的语义。
|
||||
@@ -67,8 +70,9 @@ MVP 固定三列:`todo`(待办)/ `doing`(进行中)/ `done`(已完
|
||||
MVP 为单视图应用:主看板常驻,任务详情使用 Drawer,导入导出与快捷键说明使用 Modal。不引入 `vue-router`。
|
||||
|
||||
**被否决的方案**
|
||||
- *引入 vue-router*:三个「页面」中有两个本质是覆盖层(overlay),用路由表达会让 URL 与状态同步复杂化,且多一个运行时依赖。
|
||||
- *用 URL query 承载筛选状态*:MVP 不做分享与深链需求,暂不需要。
|
||||
|
||||
- _引入 vue-router_:三个「页面」中有两个本质是覆盖层(overlay),用路由表达会让 URL 与状态同步复杂化,且多一个运行时依赖。
|
||||
- _用 URL query 承载筛选状态_:MVP 不做分享与深链需求,暂不需要。
|
||||
|
||||
**影响**
|
||||
若未来增加「今日视图」「统计」等真正的独立页面,再引入路由;届时筛选状态可一并迁移到 query。
|
||||
@@ -95,18 +99,59 @@ ADR-004 决定 MVP 不引入路由,并注明「若未来增加今日视图、
|
||||
以便测试注入 memory history。
|
||||
|
||||
**被否决的方案**
|
||||
- *把今日视图做成一个 Drawer / Modal*:Drawer 适合「聚焦单条记录」(任务详情、备份面板),
|
||||
|
||||
- _把今日视图做成一个 Drawer / Modal_:Drawer 适合「聚焦单条记录」(任务详情、备份面板),
|
||||
不适合承载一个完整的列表视图;而且它无法被收藏或分享,PWA 的 manifest shortcuts 也无处可指。
|
||||
- *在工具栏加一个「今日」筛选按钮*:那只是筛选,不是视图。用户仍然面对三列结构,
|
||||
- _在工具栏加一个「今日」筛选按钮_:那只是筛选,不是视图。用户仍然面对三列结构,
|
||||
还得自己在心里把「逾期」和「进行中」拼起来。
|
||||
- *用 hash 路由避免服务器配置*:URL 会变成 `/#/today`,不美观,且 PWA 的 `start_url`
|
||||
- _用 hash 路由避免服务器配置_:URL 会变成 `/#/today`,不美观,且 PWA 的 `start_url`
|
||||
与 shortcuts 指向带 hash 的地址会让某些平台的安装体验变差。代价是部署时必须配置 SPA 回落 ——
|
||||
这一点已在 README 的部署章节明确写出。
|
||||
|
||||
**影响**
|
||||
|
||||
- **部署要求变化**:服务器必须把未知路径回落到 `index.html`,否则直接访问 `/today` 会 404。
|
||||
README 已给出 Nginx 与 Netlify 的配置。
|
||||
- 今日视图按路由懒加载,不进入首屏包(独立 chunk 约 4KB)。
|
||||
- Service Worker 的 `navigateFallback` 设为 `index.html`,离线时深链 `/today` 同样可用。
|
||||
- 看板原有的筛选状态仍留在 Pinia 中,未迁移到 query —— 目前没有分享带筛选链接的需求,
|
||||
迁移只会增加复杂度。
|
||||
|
||||
---
|
||||
|
||||
## ADR-006 · 覆盖式操作前自动快照,归档任务提供恢复入口
|
||||
|
||||
**背景**
|
||||
|
||||
MVP 有「启动快照 + 手动导出」两道保护,但两个整份覆盖的动作没有退路:导入 JSON 与从快照恢复
|
||||
都会直接替换当前数据。归档功能的设计说明写的是「可随时恢复」,实际只有归档后 5 秒内的 Toast
|
||||
撤销能恢复,界面上找不到入口。另外,详情抽屉不能改状态、未保存的修改点一下遮罩就丢,
|
||||
是日常使用里最高频的两处摩擦。
|
||||
|
||||
**结论**
|
||||
|
||||
1. `importJson` / `restoreSnapshot` 在覆盖前调用 `repository.snapshot(当前数据)`;
|
||||
快照写入失败不阻断主流程。空看板不写,避免产生无意义备份。
|
||||
2. 导入校验增加 id 唯一性检查:严格导入路径直接拒绝并指出重复的两条;
|
||||
宽容读取路径保留先出现的那条,避免重复 id 破坏 `v-for` 与 `findIndex`。
|
||||
3. 详情抽屉增加「状态」三列切换,并展示归档状态与「恢复」入口。
|
||||
4. 详情抽屉维护 dirty 状态:有未保存修改时关闭需要二次确认,不再静默丢弃草稿。
|
||||
5. Toast 自动关闭支持悬停/聚焦暂停,移开后按剩余时间继续;撤销不再「刚要点击就消失」。
|
||||
6. 存储写失败时把 `persistent` 置为 false 并把提示提升到 App 级,两个视图都能看到告警。
|
||||
|
||||
**被否决的方案**
|
||||
|
||||
- _给删除加二次确认弹窗_:与现有「立即删除 + Toast 撤销」的约定冲突,且删除频率高,
|
||||
弹窗会拖慢操作;改为延长撤销的可操作性(暂停计时)成本更低。
|
||||
- _把归档任务从列内排序序列中剥离,让归档后排序仍可用_:需要同时改 `sortOrder` 计算、
|
||||
拖拽下标映射与渲染顺序,收益仅是「已完成列可排序」。当前保留禁用策略,
|
||||
把原因写进工具栏提示(「归档 N 个,列内排序已暂停」),让用户知道为什么拖不动。
|
||||
- _导入后自动生成版本快照_:没有服务端与版本库,快照只是本地兜底,不应膨胀成版本历史。
|
||||
|
||||
**影响**
|
||||
|
||||
- 快照最多占用 4 份全量数据(主数据 + 3 份快照);任务量接近 localStorage 配额时
|
||||
需要清理旧快照或按 ADR-002 迁移到 IndexedDB。
|
||||
- `persistent` 现在会随写入成功/失败翻转,UI 可据此判断「改动是否真的落盘」。
|
||||
- 关闭详情抽屉的默认行为从「直接关闭」变为「有改动先确认」,相关组件测试已同步调整。
|
||||
- 新增 `.gitea/workflows/ci.yml`,把 lint / typecheck / test / build 纳入推送与合并请求检查。
|
||||
|
||||
Reference in New Issue
Block a user